summaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2017-08-18 11:12:19 -0400
committerJ. Bruce Fields <bfields@redhat.com>2017-08-24 18:05:30 -0400
commitfc788f64f1f3eb31e87d4f53bcf1ab76590d5838 (patch)
treec376a2d770711851ea97fdc6bf62a867986c0a4b /fs/nfsd
parenteff793687792d3eed594d147aceef2000fb9ca3d (diff)
nfsd: Limit end of page list when decoding NFSv4 WRITE
When processing an NFSv4 WRITE operation, argp->end should never point past the end of the data in the final page of the page list. Otherwise, nfsd4_decode_compound can walk into uninitialized memory. More critical, nfsd4_decode_write is failing to increment argp->pagelen when it increments argp->pagelist. This can cause later xdr decoders to assume more data is available than really is, which can cause server crashes on malformed requests. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4xdr.c6
1 files changed, 2 insertions, 4 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 20fbcab97753..5f940d2a136b 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -144,7 +144,7 @@ static void next_decode_page(struct nfsd4_compoundargs *argp)
144 argp->p = page_address(argp->pagelist[0]); 144 argp->p = page_address(argp->pagelist[0]);
145 argp->pagelist++; 145 argp->pagelist++;
146 if (argp->pagelen < PAGE_SIZE) { 146 if (argp->pagelen < PAGE_SIZE) {
147 argp->end = argp->p + (argp->pagelen>>2); 147 argp->end = argp->p + XDR_QUADLEN(argp->pagelen);
148 argp->pagelen = 0; 148 argp->pagelen = 0;
149 } else { 149 } else {
150 argp->end = argp->p + (PAGE_SIZE>>2); 150 argp->end = argp->p + (PAGE_SIZE>>2);
@@ -1279,9 +1279,7 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
1279 argp->pagelen -= pages * PAGE_SIZE; 1279 argp->pagelen -= pages * PAGE_SIZE;
1280 len -= pages * PAGE_SIZE; 1280 len -= pages * PAGE_SIZE;
1281 1281
1282 argp->p = (__be32 *)page_address(argp->pagelist[0]); 1282 next_decode_page(argp);
1283 argp->pagelist++;
1284 argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE);
1285 } 1283 }
1286 argp->p += XDR_QUADLEN(len); 1284 argp->p += XDR_QUADLEN(len);
1287 1285