diff options
Diffstat (limited to 'fs/nfsd/nfs3proc.c')
| -rw-r--r-- | fs/nfsd/nfs3proc.c | 36 | 
1 files changed, 16 insertions, 20 deletions
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 4418517f6f12..936eebd4c56d 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -150,13 +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,18 +203,19 @@ 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); -	if (!nvecs) { -		resp->status = nfserr_io; -		goto out; -	} +  	resp->status = nfsd_write(rqstp, &resp->fh, argp->offset,  				  rqstp->rq_vec, nvecs, &cnt,  				  resp->committed, resp->verf);  	resp->count = cnt; -out:  	return rpc_success;  } @@ -438,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. */ @@ -462,7 +464,7 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,  	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;  } @@ -658,15 +660,9 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)  				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;  }  | 
