GIT: unionfs2-2.6.27.y: nfsd4: bug in read_buf

Erez Zadok ezk at fsl.cs.sunysb.edu
Thu Aug 12 23:15:22 EDT 2010


commit dc116e1abdbfe4afc934e62c42f1963806469e6b
Author: Neil Brown <neilb at suse.de>
Date:   Tue Apr 20 12:16:52 2010 +1000

    nfsd4: bug in read_buf
    
    commit 2bc3c1179c781b359d4f2f3439cb3df72afc17fc upstream.
    
    When read_buf is called to move over to the next page in the pagelist
    of an NFSv4 request, it sets argp->end to essentially a random
    number, certainly not an address within the page which argp->p now
    points to.  So subsequent calls to READ_BUF will think there is much
    more than a page of spare space (the cast to u32 ensures an unsigned
    comparison) so we can expect to fall off the end of the second
    page.
    
    We never encountered thsi in testing because typically the only
    operations which use more than two pages are write-like operations,
    which have their own decoding logic.  Something like a getattr after a
    write may cross a page boundary, but it would be very unusual for it to
    cross another boundary after that.
    
    Signed-off-by: J. Bruce Fields <bfields at citi.umich.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index abffc90..6203c81 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -179,10 +179,10 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
 	argp->p = page_address(argp->pagelist[0]);
 	argp->pagelist++;
 	if (argp->pagelen < PAGE_SIZE) {
-		argp->end = p + (argp->pagelen>>2);
+		argp->end = argp->p + (argp->pagelen>>2);
 		argp->pagelen = 0;
 	} else {
-		argp->end = p + (PAGE_SIZE>>2);
+		argp->end = argp->p + (PAGE_SIZE>>2);
 		argp->pagelen -= PAGE_SIZE;
 	}
 	memcpy(((char*)p)+avail, argp->p, (nbytes - avail));
@@ -1115,10 +1115,10 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
 			argp->p = page_address(argp->pagelist[0]);
 			argp->pagelist++;
 			if (argp->pagelen < PAGE_SIZE) {
-				argp->end = p + (argp->pagelen>>2);
+				argp->end = argp->p + (argp->pagelen>>2);
 				argp->pagelen = 0;
 			} else {
-				argp->end = p + (PAGE_SIZE>>2);
+				argp->end = argp->p + (PAGE_SIZE>>2);
 				argp->pagelen -= PAGE_SIZE;
 			}
 		}


More information about the unionfs-cvs mailing list