aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs3xdr.c
diff options
context:
space:
mode:
authorPeter Staubach <staubach@redhat.com>2007-05-09 05:34:48 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-09 15:30:54 -0400
commitf34b95689d2ce001c157b1604289ff240b4bdee0 (patch)
treee249e166e3c66656ad1b5ac895da6e4c207830e1 /fs/nfsd/nfs3xdr.c
parent8842c9655b2b7f0e8e6c50a773b649e5d8a57678 (diff)
The NFSv2/NFSv3 server does not handle zero length WRITE requests correctly
The NFSv2 and NFSv3 servers do not handle WRITE requests for 0 bytes correctly. The specifications indicate that the server should accept the request, but it should mostly turn into a no-op. Currently, the server will return an XDR decode error, which it should not. Attached is a patch which addresses this issue. It also adds some boundary checking to ensure that the request contains as much data as was requested to be written. It also correctly handles an NFSv3 request which requests to write more data than the server has stated that it is prepared to handle. Previously, there was some support which looked like it should work, but wasn't quite right. Signed-off-by: Peter Staubach <staubach@redhat.com> Acked-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/nfsd/nfs3xdr.c')
-rw-r--r--fs/nfsd/nfs3xdr.c48
1 files changed, 38 insertions, 10 deletions
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 7e4bb0af24d7..43fb360784b7 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -369,7 +369,7 @@ int
369nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, 369nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
370 struct nfsd3_writeargs *args) 370 struct nfsd3_writeargs *args)
371{ 371{
372 unsigned int len, v, hdr; 372 unsigned int len, v, hdr, dlen;
373 u32 max_blocksize = svc_max_payload(rqstp); 373 u32 max_blocksize = svc_max_payload(rqstp);
374 374
375 if (!(p = decode_fh(p, &args->fh)) 375 if (!(p = decode_fh(p, &args->fh))
@@ -379,18 +379,47 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
379 args->count = ntohl(*p++); 379 args->count = ntohl(*p++);
380 args->stable = ntohl(*p++); 380 args->stable = ntohl(*p++);
381 len = args->len = ntohl(*p++); 381 len = args->len = ntohl(*p++);
382 /*
383 * The count must equal the amount of data passed.
384 */
385 if (args->count != args->len)
386 return 0;
382 387
388 /*
389 * Check to make sure that we got the right number of
390 * bytes.
391 *
392 * If more than one page was used, then compute the length
393 * of the data in the request as the total size of the
394 * request minus the transport protocol headers minus the
395 * RPC protocol headers minus the NFS protocol fields
396 * already consumed. If the request fits into a single
397 * page, then compete the length of the data as the size
398 * of the NFS portion of the request minus the NFS
399 * protocol fields already consumed.
400 */
383 hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; 401 hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
384 if (rqstp->rq_arg.len < hdr || 402 if (rqstp->rq_respages != rqstp->rq_pages + 1) {
385 rqstp->rq_arg.len - hdr < len) 403 dlen = rqstp->rq_arg.len -
404 (PAGE_SIZE - rqstp->rq_arg.head[0].iov_len) - hdr;
405 } else {
406 dlen = rqstp->rq_arg.head[0].iov_len - hdr;
407 }
408 /*
409 * Round the length of the data which was specified up to
410 * the next multiple of XDR units and then compare that
411 * against the length which was actually received.
412 */
413 if (dlen != ((len + 3) & ~0x3))
386 return 0; 414 return 0;
387 415
416 if (args->count > max_blocksize) {
417 args->count = max_blocksize;
418 len = args->len = max_blocksize;
419 }
388 rqstp->rq_vec[0].iov_base = (void*)p; 420 rqstp->rq_vec[0].iov_base = (void*)p;
389 rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; 421 rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
390 422 v = 0;
391 if (len > max_blocksize)
392 len = max_blocksize;
393 v= 0;
394 while (len > rqstp->rq_vec[v].iov_len) { 423 while (len > rqstp->rq_vec[v].iov_len) {
395 len -= rqstp->rq_vec[v].iov_len; 424 len -= rqstp->rq_vec[v].iov_len;
396 v++; 425 v++;
@@ -398,9 +427,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
398 rqstp->rq_vec[v].iov_len = PAGE_SIZE; 427 rqstp->rq_vec[v].iov_len = PAGE_SIZE;
399 } 428 }
400 rqstp->rq_vec[v].iov_len = len; 429 rqstp->rq_vec[v].iov_len = len;
401 args->vlen = v+1; 430 args->vlen = v + 1;
402 431 return 1;
403 return args->count == args->len && rqstp->rq_vec[0].iov_len > 0;
404} 432}
405 433
406int 434int