diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2017-08-18 17:12:19 +0200 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2017-08-25 00:05:30 +0200 |
commit | fc788f64f1f3eb31e87d4f53bcf1ab76590d5838 (patch) | |
tree | c376a2d770711851ea97fdc6bf62a867986c0a4b /fs/nfsd/nfs4xdr.c | |
parent | nfsd: Fix a memory scribble in the callback channel (diff) | |
download | linux-fc788f64f1f3eb31e87d4f53bcf1ab76590d5838.tar.xz linux-fc788f64f1f3eb31e87d4f53bcf1ab76590d5838.zip |
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 '')
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 6 |
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) argp->p = page_address(argp->pagelist[0]); argp->pagelist++; if (argp->pagelen < PAGE_SIZE) { - argp->end = argp->p + (argp->pagelen>>2); + argp->end = argp->p + XDR_QUADLEN(argp->pagelen); argp->pagelen = 0; } else { argp->end = argp->p + (PAGE_SIZE>>2); @@ -1279,9 +1279,7 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) argp->pagelen -= pages * PAGE_SIZE; len -= pages * PAGE_SIZE; - argp->p = (__be32 *)page_address(argp->pagelist[0]); - argp->pagelist++; - argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE); + next_decode_page(argp); } argp->p += XDR_QUADLEN(len); |