Commit 5dbdc4c5 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 1c3e979b 53b1119a
...@@ -438,22 +438,19 @@ nfsd3_proc_link(struct svc_rqst *rqstp) ...@@ -438,22 +438,19 @@ nfsd3_proc_link(struct svc_rqst *rqstp)
static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp, static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
struct nfsd3_readdirres *resp, struct nfsd3_readdirres *resp,
int count) u32 count)
{ {
struct xdr_buf *buf = &resp->dirlist; struct xdr_buf *buf = &resp->dirlist;
struct xdr_stream *xdr = &resp->xdr; struct xdr_stream *xdr = &resp->xdr;
count = min_t(u32, count, svc_max_payload(rqstp)); count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp));
memset(buf, 0, sizeof(*buf)); memset(buf, 0, sizeof(*buf));
/* Reserve room for the NULL ptr & eof flag (-2 words) */ /* Reserve room for the NULL ptr & eof flag (-2 words) */
buf->buflen = count - XDR_UNIT * 2; buf->buflen = count - XDR_UNIT * 2;
buf->pages = rqstp->rq_next_page; buf->pages = rqstp->rq_next_page;
while (count > 0) { rqstp->rq_next_page += (buf->buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
rqstp->rq_next_page++;
count -= PAGE_SIZE;
}
/* This is xdr_init_encode(), but it assumes that /* This is xdr_init_encode(), but it assumes that
* the head kvec has already been consumed. */ * the head kvec has already been consumed. */
...@@ -462,7 +459,7 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp, ...@@ -462,7 +459,7 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
xdr->page_ptr = buf->pages; xdr->page_ptr = buf->pages;
xdr->iov = NULL; xdr->iov = NULL;
xdr->p = page_address(*buf->pages); xdr->p = page_address(*buf->pages);
xdr->end = xdr->p + (PAGE_SIZE >> 2); xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE);
xdr->rqst = NULL; xdr->rqst = NULL;
} }
......
...@@ -556,17 +556,17 @@ nfsd_proc_rmdir(struct svc_rqst *rqstp) ...@@ -556,17 +556,17 @@ nfsd_proc_rmdir(struct svc_rqst *rqstp)
static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp,
struct nfsd_readdirres *resp, struct nfsd_readdirres *resp,
int count) u32 count)
{ {
struct xdr_buf *buf = &resp->dirlist; struct xdr_buf *buf = &resp->dirlist;
struct xdr_stream *xdr = &resp->xdr; struct xdr_stream *xdr = &resp->xdr;
count = min_t(u32, count, PAGE_SIZE); count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp));
memset(buf, 0, sizeof(*buf)); memset(buf, 0, sizeof(*buf));
/* Reserve room for the NULL ptr & eof flag (-2 words) */ /* Reserve room for the NULL ptr & eof flag (-2 words) */
buf->buflen = count - sizeof(__be32) * 2; buf->buflen = count - XDR_UNIT * 2;
buf->pages = rqstp->rq_next_page; buf->pages = rqstp->rq_next_page;
rqstp->rq_next_page++; rqstp->rq_next_page++;
...@@ -577,7 +577,7 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, ...@@ -577,7 +577,7 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp,
xdr->page_ptr = buf->pages; xdr->page_ptr = buf->pages;
xdr->iov = NULL; xdr->iov = NULL;
xdr->p = page_address(*buf->pages); xdr->p = page_address(*buf->pages);
xdr->end = xdr->p + (PAGE_SIZE >> 2); xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE);
xdr->rqst = NULL; xdr->rqst = NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment