]> Git Repo - linux.git/commitdiff
Merge tag 'nfsd-5.17-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
authorLinus Torvalds <[email protected]>
Wed, 9 Feb 2022 17:56:57 +0000 (09:56 -0800)
committerLinus Torvalds <[email protected]>
Wed, 9 Feb 2022 17:56:57 +0000 (09:56 -0800)
Pull more nfsd fixes from Chuck Lever:
 "Ensure that NFS clients cannot send file size or offset values that
  can cause the NFS server to crash or to return incorrect or surprising
  results.

  In particular, fix how the NFS server handles values larger than
  OFFSET_MAX"

* tag 'nfsd-5.17-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
  NFSD: Deprecate NFS_OFFSET_MAX
  NFSD: Fix offset type in I/O trace points
  NFSD: COMMIT operations must not return NFS?ERR_INVAL
  NFSD: Clamp WRITE offsets
  NFSD: Fix NFSv3 SETATTR/CREATE's handling of large file sizes
  NFSD: Fix ia_size underflow
  NFSD: Fix the behavior of READ near OFFSET_MAX

1  2 
fs/nfsd/nfs3proc.c

diff --combined fs/nfsd/nfs3proc.c
index 8ef53f6726ec8b26b9f027c73785141e86fdb1fe,52ad1972cc33cbfc3073bc5cd3e37cbeb7aea803..936eebd4c56dca2e92e6172cf6d2781e49cb13c5
@@@ -150,13 -150,17 +150,17 @@@ nfsd3_proc_read(struct svc_rqst *rqstp
        unsigned int len;
        int v;
  
-       argp->count = min_t(u32, argp->count, max_blocksize);
        dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
                                SVCFH_fmt(&argp->fh),
                                (unsigned long) argp->count,
                                (unsigned long long) argp->offset);
  
+       argp->count = min_t(u32, argp->count, max_blocksize);
+       if (argp->offset > (u64)OFFSET_MAX)
+               argp->offset = (u64)OFFSET_MAX;
+       if (argp->offset + argp->count > (u64)OFFSET_MAX)
+               argp->count = (u64)OFFSET_MAX - argp->offset;
        v = 0;
        len = argp->count;
        resp->pages = rqstp->rq_next_page;
@@@ -199,6 -203,11 +203,11 @@@ nfsd3_proc_write(struct svc_rqst *rqstp
                                (unsigned long long) argp->offset,
                                argp->stable? " stable" : "");
  
+       resp->status = nfserr_fbig;
+       if (argp->offset > (u64)OFFSET_MAX ||
+           argp->offset + argp->len > (u64)OFFSET_MAX)
+               return rpc_success;
        fh_copy(&resp->fh, &argp->fh);
        resp->committed = argp->stable;
        nvecs = svc_fill_write_vector(rqstp, &argp->payload);
@@@ -434,19 -443,22 +443,19 @@@ nfsd3_proc_link(struct svc_rqst *rqstp
  
  static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
                                     struct nfsd3_readdirres *resp,
 -                                   int count)
 +                                   u32 count)
  {
        struct xdr_buf *buf = &resp->dirlist;
        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));
  
        /* Reserve room for the NULL ptr & eof flag (-2 words) */
        buf->buflen = count - XDR_UNIT * 2;
        buf->pages = rqstp->rq_next_page;
 -      while (count > 0) {
 -              rqstp->rq_next_page++;
 -              count -= PAGE_SIZE;
 -      }
 +      rqstp->rq_next_page += (buf->buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
  
        /* This is xdr_init_encode(), but it assumes that
         * the head kvec has already been consumed. */
        xdr->page_ptr = buf->pages;
        xdr->iov = NULL;
        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;
  }
  
@@@ -651,15 -663,9 +660,9 @@@ nfsd3_proc_commit(struct svc_rqst *rqst
                                argp->count,
                                (unsigned long long) argp->offset);
  
-       if (argp->offset > NFS_OFFSET_MAX) {
-               resp->status = nfserr_inval;
-               goto out;
-       }
        fh_copy(&resp->fh, &argp->fh);
        resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset,
                                   argp->count, resp->verf);
- out:
        return rpc_success;
  }
  
This page took 0.085113 seconds and 4 git commands to generate.