diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index c9cf46e0c0405d190ab2c19175fa15f0ac30e289..2ac8f5912dfa8ca0a54e10a3d31076f8210aaeb1 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -154,18 +154,23 @@ nfsd3_proc_read(struct svc_rqst *rqstp) struct nfsd3_readres *resp = rqstp->rq_resp; __be32 nfserr; u32 max_blocksize = svc_max_payload(rqstp); - unsigned long cnt = min(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; + /* Obtain buffer pointer for payload. * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof) * + 1 (xdr opaque byte count) = 26 */ - resp->count = cnt; + resp->count = argp->count; svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); fh_copy(&resp->fh, &argp->fh); @@ -175,7 +180,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp) &resp->count); if (nfserr == 0) { struct inode *inode = d_inode(resp->fh.fh_dentry); - resp->eof = nfsd_eof_on_read(cnt, resp->count, argp->offset, + resp->eof = nfsd_eof_on_read(resp->count, resp->count, argp->offset, inode->i_size); } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 1c3e6de6bcba9cee69874586a8b2cf78f72cbc85..8bb0b6d2ea4e579f76658d3aa897509f02c71a3f 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -760,12 +760,16 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, __be32 status; read->rd_filp = NULL; - if (read->rd_offset >= OFFSET_MAX) - return nfserr_inval; trace_nfsd_read_start(rqstp, &cstate->current_fh, read->rd_offset, read->rd_length); + read->rd_length = min_t(u32, read->rd_length, svc_max_payload(rqstp)); + if (read->rd_offset > (u64)OFFSET_MAX) + read->rd_offset = (u64)OFFSET_MAX; + if (read->rd_offset + read->rd_length > (u64)OFFSET_MAX) + read->rd_length = (u64)OFFSET_MAX - read->rd_offset; + /* * If we do a zero copy read, then a client will see read data * that reflects the state of the file *after* performing the diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index db0beefe65ec2c0613c4348dd09aabcaa039314c..7dae38d210417a2a787ebe2162290be3377017e4 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3595,11 +3595,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, } xdr_commit_encode(xdr); - maxcount = svc_max_payload(resp->rqstp); - maxcount = min_t(unsigned long, maxcount, + maxcount = min_t(unsigned long, read->rd_length, (xdr->buf->buflen - xdr->buf->len)); - maxcount = min_t(unsigned long, maxcount, read->rd_length); - if (read->rd_tmp_file) ra = nfsd_init_raparms(file);