diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2017-08-18 11:12:19 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2017-08-24 18:05:30 -0400 |
commit | fc788f64f1f3eb31e87d4f53bcf1ab76590d5838 (patch) | |
tree | c376a2d770711851ea97fdc6bf62a867986c0a4b /fs/nfsd | |
parent | eff793687792d3eed594d147aceef2000fb9ca3d (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.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) | |||
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 | ||