* [PATCH 000 of 8] knfsd: Assorted bugfixes for 2.6.22
@ 2007-05-07 0:35 NeilBrown
2007-05-07 0:35 ` [PATCH 001 of 8] knfsd: Avoid use of unitialised variables on error path when nfs exports NeilBrown
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: NeilBrown @ 2007-05-07 0:35 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, linux-kernel, stable
Following are 8 patches for knfsd and related code that are suitable for
2.6.22.
First two are suitable for -stable: they can cause an oops.
(8 can also cause an oops, but you really need buggy userspace code
running as root, and it is a larger patch than I like to send to -stable).
Other 6 are less significant bug fixes and cleanups.
Thanks,
NeilBrown
[PATCH 001 of 8] knfsd: Avoid use of unitialised variables on error path when nfs exports.
[PATCH 002 of 8] knfsd: rpc: fix server-side wrapping of krb5i replies
[PATCH 003 of 8] knfsd: Fix resource leak resulting in module refcount leak for rpcsec_gss_krb5.ko
[PATCH 004 of 8] knfsd: rpcgss : RPC_GSS_PROC_ DESTROY request will get a bad rpc
[PATCH 005 of 8] knfsd: Simplify a 'while' condition in svcsock.c
[PATCH 006 of 8] knfsd: Trivial makefile cleanup
[PATCH 007 of 8] knfsd: Various nfsd xdr cleanups.
[PATCH 008 of 8] knfsd: Avoid Oops if buggy userspace performs confusing filehandle->dentry mapping.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 001 of 8] knfsd: Avoid use of unitialised variables on error path when nfs exports.
2007-05-07 0:35 [PATCH 000 of 8] knfsd: Assorted bugfixes for 2.6.22 NeilBrown
@ 2007-05-07 0:35 ` NeilBrown
2007-05-07 0:35 ` [PATCH 002 of 8] knfsd: rpc: fix server-side wrapping of krb5i replies NeilBrown
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: NeilBrown @ 2007-05-07 0:35 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, linux-kernel, Neil Brown, stable
We need to zero various parts of 'exp' before any 'goto out', otherwise
when we go to free the contents... we die.
Signed-off-by: Neil Brown <neilb@suse.de>
Cc: stable@kernel.org
### Diffstat output
./fs/nfsd/export.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff .prev/fs/nfsd/export.c ./fs/nfsd/export.c
--- .prev/fs/nfsd/export.c 2007-05-07 10:30:16.000000000 +1000
+++ ./fs/nfsd/export.c 2007-05-07 10:30:28.000000000 +1000
@@ -469,6 +469,13 @@ static int svc_export_parse(struct cache
nd.dentry = NULL;
exp.ex_path = NULL;
+ /* fs locations */
+ exp.ex_fslocs.locations = NULL;
+ exp.ex_fslocs.locations_count = 0;
+ exp.ex_fslocs.migrated = 0;
+
+ exp.ex_uuid = NULL;
+
if (mesg[mlen-1] != '\n')
return -EINVAL;
mesg[mlen-1] = 0;
@@ -509,13 +516,6 @@ static int svc_export_parse(struct cache
if (exp.h.expiry_time == 0)
goto out;
- /* fs locations */
- exp.ex_fslocs.locations = NULL;
- exp.ex_fslocs.locations_count = 0;
- exp.ex_fslocs.migrated = 0;
-
- exp.ex_uuid = NULL;
-
/* flags */
err = get_int(&mesg, &an_int);
if (err == -ENOENT)
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 002 of 8] knfsd: rpc: fix server-side wrapping of krb5i replies
2007-05-07 0:35 [PATCH 000 of 8] knfsd: Assorted bugfixes for 2.6.22 NeilBrown
2007-05-07 0:35 ` [PATCH 001 of 8] knfsd: Avoid use of unitialised variables on error path when nfs exports NeilBrown
@ 2007-05-07 0:35 ` NeilBrown
2007-05-07 0:35 ` [PATCH 003 of 8] knfsd: Fix resource leak resulting in module refcount leak for rpcsec_gss_krb5.ko NeilBrown
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: NeilBrown @ 2007-05-07 0:35 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, linux-kernel, J. Bruce Fields, Neil Brown, stable
It's not necessarily correct to assume that the xdr_buf used to hold the
server's reply must have page data whenever it has tail data.
And there's no need for us to deal with that case separately anyway.
Acked-by: "J. Bruce Fields" <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>
Cc: stable@kernel.org
### Diffstat output
./net/sunrpc/auth_gss/svcauth_gss.c | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff .prev/net/sunrpc/auth_gss/svcauth_gss.c ./net/sunrpc/auth_gss/svcauth_gss.c
--- .prev/net/sunrpc/auth_gss/svcauth_gss.c 2007-05-07 10:30:18.000000000 +1000
+++ ./net/sunrpc/auth_gss/svcauth_gss.c 2007-05-07 10:30:38.000000000 +1000
@@ -1210,13 +1210,7 @@ svcauth_gss_wrap_resp_integ(struct svc_r
if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset,
integ_len))
BUG();
- if (resbuf->page_len == 0
- && resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE
- < PAGE_SIZE) {
- BUG_ON(resbuf->tail[0].iov_len);
- /* Use head for everything */
- resv = &resbuf->head[0];
- } else if (resbuf->tail[0].iov_base == NULL) {
+ if (resbuf->tail[0].iov_base == NULL) {
if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE > PAGE_SIZE)
goto out_err;
resbuf->tail[0].iov_base = resbuf->head[0].iov_base
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 003 of 8] knfsd: Fix resource leak resulting in module refcount leak for rpcsec_gss_krb5.ko
2007-05-07 0:35 [PATCH 000 of 8] knfsd: Assorted bugfixes for 2.6.22 NeilBrown
2007-05-07 0:35 ` [PATCH 001 of 8] knfsd: Avoid use of unitialised variables on error path when nfs exports NeilBrown
2007-05-07 0:35 ` [PATCH 002 of 8] knfsd: rpc: fix server-side wrapping of krb5i replies NeilBrown
@ 2007-05-07 0:35 ` NeilBrown
2007-05-07 0:35 ` [PATCH 004 of 8] knfsd: rpcgss : RPC_GSS_PROC_ DESTROY request will get a bad rpc NeilBrown
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: NeilBrown @ 2007-05-07 0:35 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, linux-kernel, Frank Filz, J. Bruce Fields, Neil Brown
From: Frank Filz <ffilzlnx@us.ibm.com>
I have been investigating a module reference count leak on the server
for rpcsec_gss_krb5.ko. It turns out the problem is a reference count
leak for the security context in net/sunrpc/auth_gss/svcauth_gss.c.
The problem is that gss_write_init_verf() calls gss_svc_searchbyctx()
which does a rsc_lookup() but never releases the reference to the
context. There is another issue that rpc.svcgssd sets an "end of time"
expiration for the context
By adding a cache_put() call in gss_svc_searchbyctx(), and setting an
expiration timeout in the downcall, cache_clean() does clean up the
context and the module reference count now goes to zero after unmount.
I also verified that if the context expires and then the client makes a
new request, a new context is established.
Here is the patch to fix the kernel, I will start a separate thread to
discuss what expiration time should be set by rpc.svcgssd.
Acked-by: "J. Bruce Fields" <bfields@citi.umich.edu>
Signed-off-by: Frank Filz <ffilzlnx@us.ibm.com>
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c
b/net/sunrpc/auth_gss/svcauth_gss.c
index db298b5..eb16e30 100644
Signed-off-by: Neil Brown <neilb@suse.de>
### Diffstat output
./net/sunrpc/auth_gss/svcauth_gss.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff .prev/net/sunrpc/auth_gss/svcauth_gss.c ./net/sunrpc/auth_gss/svcauth_gss.c
--- .prev/net/sunrpc/auth_gss/svcauth_gss.c 2007-05-07 10:30:38.000000000 +1000
+++ ./net/sunrpc/auth_gss/svcauth_gss.c 2007-05-07 10:31:03.000000000 +1000
@@ -938,6 +938,7 @@ static inline int
gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
{
struct rsc *rsci;
+ int rc;
if (rsip->major_status != GSS_S_COMPLETE)
return gss_write_null_verf(rqstp);
@@ -946,7 +947,9 @@ gss_write_init_verf(struct svc_rqst *rqs
rsip->major_status = GSS_S_NO_CONTEXT;
return gss_write_null_verf(rqstp);
}
- return gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
+ rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
+ cache_put(&rsci->h, &rsc_cache);
+ return rc;
}
/*
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 004 of 8] knfsd: rpcgss : RPC_GSS_PROC_ DESTROY request will get a bad rpc
2007-05-07 0:35 [PATCH 000 of 8] knfsd: Assorted bugfixes for 2.6.22 NeilBrown
` (2 preceding siblings ...)
2007-05-07 0:35 ` [PATCH 003 of 8] knfsd: Fix resource leak resulting in module refcount leak for rpcsec_gss_krb5.ko NeilBrown
@ 2007-05-07 0:35 ` NeilBrown
2007-05-07 0:35 ` [PATCH 005 of 8] knfsd: Simplify a 'while' condition in svcsock.c NeilBrown
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: NeilBrown @ 2007-05-07 0:35 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, linux-kernel, J. Bruce Fields, Neil Brown, Wei Yongjun
From: Wei Yongjun <yjwei@cn.fujitsu.com>
If I send a RPC_GSS_PROC_DESTROY message to NFSv4 server, it will reply
with a bad rpc reply which lacks an authentication verifier.
Maybe this patch is needed.
Send/recv packets as following:
send:
RemoteProcedureCall
xid
rpcvers = 2
prog = 100003
vers = 4
proc = 0
cred = AUTH_GSS
version = 1
gss_proc = 3 (RPCSEC_GSS_DESTROY)
service = 1 (RPC_GSS_SVC_NONE)
verf = AUTH_GSS
checksum
reply:
RemoteProcedureReply
xid
msg_type
reply_stat
accepted_reply
Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>
### Diffstat output
./net/sunrpc/auth_gss/svcauth_gss.c | 2 ++
1 file changed, 2 insertions(+)
diff .prev/net/sunrpc/auth_gss/svcauth_gss.c ./net/sunrpc/auth_gss/svcauth_gss.c
--- .prev/net/sunrpc/auth_gss/svcauth_gss.c 2007-05-07 10:31:03.000000000 +1000
+++ ./net/sunrpc/auth_gss/svcauth_gss.c 2007-05-07 10:31:04.000000000 +1000
@@ -1106,6 +1106,8 @@ svcauth_gss_accept(struct svc_rqst *rqst
}
goto complete;
case RPC_GSS_PROC_DESTROY:
+ if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
+ goto auth_err;
set_bit(CACHE_NEGATIVE, &rsci->h.flags);
if (resv->iov_len + 4 > PAGE_SIZE)
goto drop;
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 005 of 8] knfsd: Simplify a 'while' condition in svcsock.c
2007-05-07 0:35 [PATCH 000 of 8] knfsd: Assorted bugfixes for 2.6.22 NeilBrown
` (3 preceding siblings ...)
2007-05-07 0:35 ` [PATCH 004 of 8] knfsd: rpcgss : RPC_GSS_PROC_ DESTROY request will get a bad rpc NeilBrown
@ 2007-05-07 0:35 ` NeilBrown
2007-05-07 0:35 ` [PATCH 006 of 8] knfsd: Trivial makefile cleanup NeilBrown
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: NeilBrown @ 2007-05-07 0:35 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, linux-kernel, Neil Brown
This while loop has an overly complex condition, which performs a
couple of assignments. This hurts readability.
We don't really need a loop at all. We can just return -EAGAIN and
(providing we set SK_DATA), the function will be called again.
So discard the loop, make the complex conditional become a few clear
function calls, and hopefully improve readability.
Signed-off-by: Neil Brown <neilb@suse.de>
### Diffstat output
./net/sunrpc/svcsock.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff .prev/net/sunrpc/svcsock.c ./net/sunrpc/svcsock.c
--- .prev/net/sunrpc/svcsock.c 2007-05-07 10:30:16.000000000 +1000
+++ ./net/sunrpc/svcsock.c 2007-05-07 10:31:04.000000000 +1000
@@ -788,15 +788,20 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
}
clear_bit(SK_DATA, &svsk->sk_flags);
- while ((err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
- 0, 0, MSG_PEEK | MSG_DONTWAIT)) < 0 ||
- (skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
- if (err == -EAGAIN) {
- svc_sock_received(svsk);
- return err;
+ skb = NULL;
+ err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
+ 0, 0, MSG_PEEK | MSG_DONTWAIT);
+ if (err >= 0)
+ skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err);
+
+ if (skb == NULL) {
+ if (err != -EAGAIN) {
+ /* possibly an icmp error */
+ dprintk("svc: recvfrom returned error %d\n", -err);
+ set_bit(SK_DATA, &svsk->sk_flags);
}
- /* possibly an icmp error */
- dprintk("svc: recvfrom returned error %d\n", -err);
+ svc_sock_received(svsk);
+ return -EAGAIN;
}
rqstp->rq_addrlen = sizeof(rqstp->rq_addr);
if (skb->tstamp.tv64 == 0) {
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 006 of 8] knfsd: Trivial makefile cleanup
2007-05-07 0:35 [PATCH 000 of 8] knfsd: Assorted bugfixes for 2.6.22 NeilBrown
` (4 preceding siblings ...)
2007-05-07 0:35 ` [PATCH 005 of 8] knfsd: Simplify a 'while' condition in svcsock.c NeilBrown
@ 2007-05-07 0:35 ` NeilBrown
2007-05-07 0:35 ` [PATCH 007 of 8] knfsd: Various nfsd xdr cleanups NeilBrown
2007-05-07 0:36 ` [PATCH 008 of 8] knfsd: Avoid Oops if buggy userspace performs confusing filehandle->dentry mapping NeilBrown
7 siblings, 0 replies; 9+ messages in thread
From: NeilBrown @ 2007-05-07 0:35 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, linux-kernel, Christoph Hellwig, Neil Brown
From: Christoph Hellwig <hch@lst.de>
kbuild directly interprets <modulename>-y as objects to build into
a module, no need to assign it to the old foo-objs variable.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Neil Brown <neilb@suse.de>
### Diffstat output
./fs/nfsd/Makefile | 1 -
1 file changed, 1 deletion(-)
diff .prev/fs/nfsd/Makefile ./fs/nfsd/Makefile
--- .prev/fs/nfsd/Makefile 2007-05-07 10:30:15.000000000 +1000
+++ ./fs/nfsd/Makefile 2007-05-07 10:31:05.000000000 +1000
@@ -11,4 +11,3 @@ nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs
nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
nfs4acl.o nfs4callback.o nfs4recover.o
-nfsd-objs := $(nfsd-y)
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 007 of 8] knfsd: Various nfsd xdr cleanups.
2007-05-07 0:35 [PATCH 000 of 8] knfsd: Assorted bugfixes for 2.6.22 NeilBrown
` (5 preceding siblings ...)
2007-05-07 0:35 ` [PATCH 006 of 8] knfsd: Trivial makefile cleanup NeilBrown
@ 2007-05-07 0:35 ` NeilBrown
2007-05-07 0:36 ` [PATCH 008 of 8] knfsd: Avoid Oops if buggy userspace performs confusing filehandle->dentry mapping NeilBrown
7 siblings, 0 replies; 9+ messages in thread
From: NeilBrown @ 2007-05-07 0:35 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, linux-kernel, Neil Brown
1/ decode_sattr and decode_sattr3 never return NULL, so remove
several checks for that. ditto for xdr_decode_hyper.
2/ replace some open coded XDR_QUADLEN calls with calls to
XDR_QUADLEN
3/ in decode_writeargs, simply an 'if' to use a single
calculation.
.page_len is the length of that part of the packet that did
not fit in the first page (the head).
So the length of the data part is the remainder of the
head, plus page_len.
3/ other minor cleanups.
Signed-off-by: Neil Brown <neilb@suse.de>
### Diffstat output
./fs/nfsd/nfs3xdr.c | 55 ++++++++++++++++++----------------------------------
./fs/nfsd/nfsxdr.c | 39 +++++++++++++-----------------------
2 files changed, 34 insertions(+), 60 deletions(-)
diff .prev/fs/nfsd/nfs3xdr.c ./fs/nfsd/nfs3xdr.c
--- .prev/fs/nfsd/nfs3xdr.c 2007-05-07 10:30:15.000000000 +1000
+++ ./fs/nfsd/nfs3xdr.c 2007-05-07 10:31:05.000000000 +1000
@@ -239,7 +239,7 @@ static __be32 *
encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
struct dentry *dentry = fhp->fh_dentry;
- if (dentry && dentry->d_inode != NULL) {
+ if (dentry && dentry->d_inode) {
int err;
struct kstat stat;
@@ -300,9 +300,9 @@ int
nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_sattrargs *args)
{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_sattr3(p, &args->attrs)))
+ if (!(p = decode_fh(p, &args->fh)))
return 0;
+ p = decode_sattr3(p, &args->attrs);
if ((args->check_guard = ntohl(*p++)) != 0) {
struct timespec time;
@@ -343,9 +343,9 @@ nfs3svc_decode_readargs(struct svc_rqst
int v,pn;
u32 max_blocksize = svc_max_payload(rqstp);
- if (!(p = decode_fh(p, &args->fh))
- || !(p = xdr_decode_hyper(p, &args->offset)))
+ if (!(p = decode_fh(p, &args->fh)))
return 0;
+ p = xdr_decode_hyper(p, &args->offset);
len = args->count = ntohl(*p++);
@@ -372,9 +372,9 @@ nfs3svc_decode_writeargs(struct svc_rqst
unsigned int len, v, hdr, dlen;
u32 max_blocksize = svc_max_payload(rqstp);
- if (!(p = decode_fh(p, &args->fh))
- || !(p = xdr_decode_hyper(p, &args->offset)))
+ if (!(p = decode_fh(p, &args->fh)))
return 0;
+ p = xdr_decode_hyper(p, &args->offset);
args->count = ntohl(*p++);
args->stable = ntohl(*p++);
@@ -388,29 +388,16 @@ nfs3svc_decode_writeargs(struct svc_rqst
/*
* Check to make sure that we got the right number of
* bytes.
- *
- * If more than one page was used, then compute the length
- * of the data in the request as the total size of the
- * request minus the transport protocol headers minus the
- * RPC protocol headers minus the NFS protocol fields
- * already consumed. If the request fits into a single
- * page, then compete the length of the data as the size
- * of the NFS portion of the request minus the NFS
- * protocol fields already consumed.
*/
hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
- if (rqstp->rq_respages != rqstp->rq_pages + 1) {
- dlen = rqstp->rq_arg.len -
- (PAGE_SIZE - rqstp->rq_arg.head[0].iov_len) - hdr;
- } else {
- dlen = rqstp->rq_arg.head[0].iov_len - hdr;
- }
+ dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
+ - hdr;
/*
* Round the length of the data which was specified up to
* the next multiple of XDR units and then compare that
* against the length which was actually received.
*/
- if (dlen != ((len + 3) & ~0x3))
+ if (dlen != XDR_QUADLEN(len)*4)
return 0;
if (args->count > max_blocksize) {
@@ -442,8 +429,7 @@ nfs3svc_decode_createargs(struct svc_rqs
switch (args->createmode = ntohl(*p++)) {
case NFS3_CREATE_UNCHECKED:
case NFS3_CREATE_GUARDED:
- if (!(p = decode_sattr3(p, &args->attrs)))
- return 0;
+ p = decode_sattr3(p, &args->attrs);
break;
case NFS3_CREATE_EXCLUSIVE:
args->verf = p;
@@ -459,10 +445,10 @@ int
nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_createargs *args)
{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_filename(p, &args->name, &args->len))
- || !(p = decode_sattr3(p, &args->attrs)))
+ if (!(p = decode_fh(p, &args->fh)) ||
+ !(p = decode_filename(p, &args->name, &args->len)))
return 0;
+ p = decode_sattr3(p, &args->attrs);
return xdr_argsize_check(rqstp, p);
}
@@ -476,11 +462,12 @@ nfs3svc_decode_symlinkargs(struct svc_rq
char *old, *new;
struct kvec *vec;
- if (!(p = decode_fh(p, &args->ffh))
- || !(p = decode_filename(p, &args->fname, &args->flen))
- || !(p = decode_sattr3(p, &args->attrs))
+ if (!(p = decode_fh(p, &args->ffh)) ||
+ !(p = decode_filename(p, &args->fname, &args->flen))
)
return 0;
+ p = decode_sattr3(p, &args->attrs);
+
/* now decode the pathname, which might be larger than the first page.
* As we have to check for nul's anyway, we copy it into a new page
* This page appears in the rq_res.pages list, but as pages_len is always
@@ -530,10 +517,8 @@ nfs3svc_decode_mknodargs(struct svc_rqst
args->ftype = ntohl(*p++);
if (args->ftype == NF3BLK || args->ftype == NF3CHR
- || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
- if (!(p = decode_sattr3(p, &args->attrs)))
- return 0;
- }
+ || args->ftype == NF3SOCK || args->ftype == NF3FIFO)
+ p = decode_sattr3(p, &args->attrs);
if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
args->major = ntohl(*p++);
diff .prev/fs/nfsd/nfsxdr.c ./fs/nfsd/nfsxdr.c
--- .prev/fs/nfsd/nfsxdr.c 2007-05-07 10:30:15.000000000 +1000
+++ ./fs/nfsd/nfsxdr.c 2007-05-07 10:31:05.000000000 +1000
@@ -231,9 +231,10 @@ int
nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_sattrargs *args)
{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_sattr(p, &args->attrs)))
+ p = decode_fh(p, &args->fh);
+ if (!p)
return 0;
+ p = decode_sattr(p, &args->attrs);
return xdr_argsize_check(rqstp, p);
}
@@ -303,29 +304,17 @@ nfssvc_decode_writeargs(struct svc_rqst
/*
* Check to make sure that we got the right number of
* bytes.
- *
- * If more than one page was used, then compute the length
- * of the data in the request as the total size of the
- * request minus the transport protocol headers minus the
- * RPC protocol headers minus the NFS protocol fields
- * already consumed. If the request fits into a single
- * page, then compete the length of the data as the size
- * of the NFS portion of the request minus the NFS
- * protocol fields already consumed.
*/
hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
- if (rqstp->rq_respages != rqstp->rq_pages + 1) {
- dlen = rqstp->rq_arg.len -
- (PAGE_SIZE - rqstp->rq_arg.head[0].iov_len) - hdr;
- } else {
- dlen = rqstp->rq_arg.head[0].iov_len - hdr;
- }
+ dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
+ - hdr;
+
/*
* Round the length of the data which was specified up to
* the next multiple of XDR units and then compare that
* against the length which was actually received.
*/
- if (dlen != ((len + 3) & ~0x3))
+ if (dlen != XDR_QUADLEN(len)*4)
return 0;
rqstp->rq_vec[0].iov_base = (void*)p;
@@ -346,10 +335,10 @@ int
nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_createargs *args)
{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_filename(p, &args->name, &args->len))
- || !(p = decode_sattr(p, &args->attrs)))
+ if ( !(p = decode_fh(p, &args->fh))
+ || !(p = decode_filename(p, &args->name, &args->len)))
return 0;
+ p = decode_sattr(p, &args->attrs);
return xdr_argsize_check(rqstp, p);
}
@@ -393,11 +382,11 @@ int
nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_symlinkargs *args)
{
- if (!(p = decode_fh(p, &args->ffh))
- || !(p = decode_filename(p, &args->fname, &args->flen))
- || !(p = decode_pathname(p, &args->tname, &args->tlen))
- || !(p = decode_sattr(p, &args->attrs)))
+ if ( !(p = decode_fh(p, &args->ffh))
+ || !(p = decode_filename(p, &args->fname, &args->flen))
+ || !(p = decode_pathname(p, &args->tname, &args->tlen)))
return 0;
+ p = decode_sattr(p, &args->attrs);
return xdr_argsize_check(rqstp, p);
}
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 008 of 8] knfsd: Avoid Oops if buggy userspace performs confusing filehandle->dentry mapping.
2007-05-07 0:35 [PATCH 000 of 8] knfsd: Assorted bugfixes for 2.6.22 NeilBrown
` (6 preceding siblings ...)
2007-05-07 0:35 ` [PATCH 007 of 8] knfsd: Various nfsd xdr cleanups NeilBrown
@ 2007-05-07 0:36 ` NeilBrown
7 siblings, 0 replies; 9+ messages in thread
From: NeilBrown @ 2007-05-07 0:36 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, linux-kernel, Neil Brown
When a lookup request arrives, nfsd uses information provided by
userspace (mountd) to find the right filesystem.
It then assumes that the same filehandle type as the incoming filehandle
can be used to create an outgoing filehandle.
However if mountd is buggy, or maybe just being creative, the filesystem
may not support that filesystem type, and the kernel could oops, particularly
if 'ex_uuid' is NULL but a FSID_UUID* filehandle type is used.
So add some proper checking that the fsid version/type from the
incoming filehandle is actually supportable, and ignore that information
if it isn't supportable.
Signed-off-by: Neil Brown <neilb@suse.de>
### Diffstat output
./fs/nfsd/nfsfh.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 50 insertions(+), 6 deletions(-)
diff .prev/fs/nfsd/nfsfh.c ./fs/nfsd/nfsfh.c
--- .prev/fs/nfsd/nfsfh.c 2007-05-07 10:30:13.000000000 +1000
+++ ./fs/nfsd/nfsfh.c 2007-05-07 10:31:05.000000000 +1000
@@ -323,7 +323,7 @@ fh_compose(struct svc_fh *fhp, struct sv
*
*/
- u8 version = 1;
+ u8 version;
u8 fsid_type = 0;
struct inode * inode = dentry->d_inode;
struct dentry *parent = dentry->d_parent;
@@ -341,15 +341,59 @@ fh_compose(struct svc_fh *fhp, struct sv
* the reference filehandle (if it is in the same export)
* or the export options.
*/
+ retry:
+ version = 1;
if (ref_fh && ref_fh->fh_export == exp) {
version = ref_fh->fh_handle.fh_version;
- if (version == 0xca)
+ fsid_type = ref_fh->fh_handle.fh_fsid_type;
+
+ if (ref_fh == fhp)
+ fh_put(ref_fh);
+ ref_fh = NULL;
+
+ switch (version) {
+ case 0xca:
fsid_type = FSID_DEV;
- else
- fsid_type = ref_fh->fh_handle.fh_fsid_type;
- /* We know this version/type works for this export
- * so there is no need for further checks.
+ break;
+ case 1:
+ break;
+ default:
+ goto retry;
+ }
+
+ /* Need to check that this type works for this
+ * export point. As the fsid -> filesystem mapping
+ * was guided by user-space, there is no guarantee
+ * that the filesystem actually supports that fsid
+ * type. If it doesn't we loop around again without
+ * ref_fh set.
*/
+ switch(fsid_type) {
+ case FSID_DEV:
+ if (!old_valid_dev(ex_dev))
+ goto retry;
+ /* FALL THROUGH */
+ case FSID_MAJOR_MINOR:
+ case FSID_ENCODE_DEV:
+ if (!(exp->ex_dentry->d_inode->i_sb->s_type->fs_flags
+ & FS_REQUIRES_DEV))
+ goto retry;
+ break;
+ case FSID_NUM:
+ if (! (exp->ex_flags & NFSEXP_FSID))
+ goto retry;
+ break;
+ case FSID_UUID8:
+ case FSID_UUID16:
+ if (!root_export)
+ goto retry;
+ /* fall through */
+ case FSID_UUID4_INUM:
+ case FSID_UUID16_INUM:
+ if (exp->ex_uuid == NULL)
+ goto retry;
+ break;
+ }
} else if (exp->ex_uuid) {
if (fhp->fh_maxsize >= 64) {
if (root_export)
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2007-05-07 0:38 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-05-07 0:35 [PATCH 000 of 8] knfsd: Assorted bugfixes for 2.6.22 NeilBrown
2007-05-07 0:35 ` [PATCH 001 of 8] knfsd: Avoid use of unitialised variables on error path when nfs exports NeilBrown
2007-05-07 0:35 ` [PATCH 002 of 8] knfsd: rpc: fix server-side wrapping of krb5i replies NeilBrown
2007-05-07 0:35 ` [PATCH 003 of 8] knfsd: Fix resource leak resulting in module refcount leak for rpcsec_gss_krb5.ko NeilBrown
2007-05-07 0:35 ` [PATCH 004 of 8] knfsd: rpcgss : RPC_GSS_PROC_ DESTROY request will get a bad rpc NeilBrown
2007-05-07 0:35 ` [PATCH 005 of 8] knfsd: Simplify a 'while' condition in svcsock.c NeilBrown
2007-05-07 0:35 ` [PATCH 006 of 8] knfsd: Trivial makefile cleanup NeilBrown
2007-05-07 0:35 ` [PATCH 007 of 8] knfsd: Various nfsd xdr cleanups NeilBrown
2007-05-07 0:36 ` [PATCH 008 of 8] knfsd: Avoid Oops if buggy userspace performs confusing filehandle->dentry mapping NeilBrown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox