Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'nfsd-5.16-3' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux

Pull nfsd fix from Chuck Lever:
"Address a buffer overrun reported by Anatoly Trosinenko"

* tag 'nfsd-5.16-3' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
NFSD: Fix READDIR buffer overflow

+8 -11
+4 -7
fs/nfsd/nfs3proc.c
··· 438 438 439 439 static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp, 440 440 struct nfsd3_readdirres *resp, 441 - int count) 441 + u32 count) 442 442 { 443 443 struct xdr_buf *buf = &resp->dirlist; 444 444 struct xdr_stream *xdr = &resp->xdr; 445 445 446 - count = min_t(u32, count, svc_max_payload(rqstp)); 446 + count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp)); 447 447 448 448 memset(buf, 0, sizeof(*buf)); 449 449 450 450 /* Reserve room for the NULL ptr & eof flag (-2 words) */ 451 451 buf->buflen = count - XDR_UNIT * 2; 452 452 buf->pages = rqstp->rq_next_page; 453 - while (count > 0) { 454 - rqstp->rq_next_page++; 455 - count -= PAGE_SIZE; 456 - } 453 + rqstp->rq_next_page += (buf->buflen + PAGE_SIZE - 1) >> PAGE_SHIFT; 457 454 458 455 /* This is xdr_init_encode(), but it assumes that 459 456 * the head kvec has already been consumed. */ ··· 459 462 xdr->page_ptr = buf->pages; 460 463 xdr->iov = NULL; 461 464 xdr->p = page_address(*buf->pages); 462 - xdr->end = xdr->p + (PAGE_SIZE >> 2); 465 + xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE); 463 466 xdr->rqst = NULL; 464 467 } 465 468
+4 -4
fs/nfsd/nfsproc.c
··· 556 556 557 557 static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, 558 558 struct nfsd_readdirres *resp, 559 - int count) 559 + u32 count) 560 560 { 561 561 struct xdr_buf *buf = &resp->dirlist; 562 562 struct xdr_stream *xdr = &resp->xdr; 563 563 564 - count = min_t(u32, count, PAGE_SIZE); 564 + count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp)); 565 565 566 566 memset(buf, 0, sizeof(*buf)); 567 567 568 568 /* Reserve room for the NULL ptr & eof flag (-2 words) */ 569 - buf->buflen = count - sizeof(__be32) * 2; 569 + buf->buflen = count - XDR_UNIT * 2; 570 570 buf->pages = rqstp->rq_next_page; 571 571 rqstp->rq_next_page++; 572 572 ··· 577 577 xdr->page_ptr = buf->pages; 578 578 xdr->iov = NULL; 579 579 xdr->p = page_address(*buf->pages); 580 - xdr->end = xdr->p + (PAGE_SIZE >> 2); 580 + xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE); 581 581 xdr->rqst = NULL; 582 582 } 583 583