nfsd4: bug in read_buf

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.

Cc: stable@kernel.org
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>

authored by Neil Brown and committed by J. Bruce Fields 2bc3c117 0d0fb0f9

+4 -4
+4 -4
fs/nfsd/nfs4xdr.c
··· 161 161 argp->p = page_address(argp->pagelist[0]); 162 162 argp->pagelist++; 163 163 if (argp->pagelen < PAGE_SIZE) { 164 - argp->end = p + (argp->pagelen>>2); 164 + argp->end = argp->p + (argp->pagelen>>2); 165 165 argp->pagelen = 0; 166 166 } else { 167 - argp->end = p + (PAGE_SIZE>>2); 167 + argp->end = argp->p + (PAGE_SIZE>>2); 168 168 argp->pagelen -= PAGE_SIZE; 169 169 } 170 170 memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); ··· 1426 1426 argp->p = page_address(argp->pagelist[0]); 1427 1427 argp->pagelist++; 1428 1428 if (argp->pagelen < PAGE_SIZE) { 1429 - argp->end = p + (argp->pagelen>>2); 1429 + argp->end = argp->p + (argp->pagelen>>2); 1430 1430 argp->pagelen = 0; 1431 1431 } else { 1432 - argp->end = p + (PAGE_SIZE>>2); 1432 + argp->end = argp->p + (PAGE_SIZE>>2); 1433 1433 argp->pagelen -= PAGE_SIZE; 1434 1434 } 1435 1435 }