diff options
Diffstat (limited to 'fs/nfs')
| -rw-r--r-- | fs/nfs/file.c | 4 | ||||
| -rw-r--r-- | fs/nfs/inode.c | 2 | ||||
| -rw-r--r-- | fs/nfs/nfs3proc.c | 2 | ||||
| -rw-r--r-- | fs/nfs/nfs4file.c | 4 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 55 | ||||
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 17 | ||||
| -rw-r--r-- | fs/nfs/super.c | 2 | 
7 files changed, 42 insertions, 44 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 75d6d0a3d32..6a7fcab7ecb 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -287,10 +287,12 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)  	struct inode *inode = file->f_path.dentry->d_inode;  	ret = filemap_write_and_wait_range(inode->i_mapping, start, end); +	if (ret != 0) +		goto out;  	mutex_lock(&inode->i_mutex);  	ret = nfs_file_fsync_commit(file, start, end, datasync);  	mutex_unlock(&inode->i_mutex); - +out:  	return ret;  } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index c6e895f0fbf..9b47610338f 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -154,7 +154,7 @@ static void nfs_zap_caches_locked(struct inode *inode)  	nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);  	nfsi->attrtimeo_timestamp = jiffies; -	memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); +	memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf));  	if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))  		nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;  	else diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index d6b3b5f2d77..69322096c32 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -643,7 +643,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,  		  u64 cookie, struct page **pages, unsigned int count, int plus)  {  	struct inode		*dir = dentry->d_inode; -	__be32			*verf = NFS_COOKIEVERF(dir); +	__be32			*verf = NFS_I(dir)->cookieverf;  	struct nfs3_readdirargs	arg = {  		.fh		= NFS_FH(dir),  		.cookie		= cookie, diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index acb65e7887f..eb5eb8eef4d 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -96,13 +96,15 @@ nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)  	struct inode *inode = file->f_path.dentry->d_inode;  	ret = filemap_write_and_wait_range(inode->i_mapping, start, end); +	if (ret != 0) +		goto out;  	mutex_lock(&inode->i_mutex);  	ret = nfs_file_fsync_commit(file, start, end, datasync);  	if (!ret && !datasync)  		/* application has asked for meta-data sync */  		ret = pnfs_layoutcommit_inode(inode, true);  	mutex_unlock(&inode->i_mutex); - +out:  	return ret;  } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 635274140b1..1e50326d00d 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3215,11 +3215,11 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,  			dentry->d_parent->d_name.name,  			dentry->d_name.name,  			(unsigned long long)cookie); -	nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); +	nfs4_setup_readdir(cookie, NFS_I(dir)->cookieverf, dentry, &args);  	res.pgbase = args.pgbase;  	status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);  	if (status >= 0) { -		memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); +		memcpy(NFS_I(dir)->cookieverf, res.verifier.data, NFS4_VERIFIER_SIZE);  		status += args.pgbase;  	} @@ -3653,11 +3653,11 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server)  		&& (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);  } -/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that - * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on +/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that + * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_SIZE) bytes on   * the stack.   */ -#define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) +#define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)  static int buf_to_pages_noslab(const void *buf, size_t buflen,  		struct page **pages, unsigned int *pgbase) @@ -3668,7 +3668,7 @@ static int buf_to_pages_noslab(const void *buf, size_t buflen,  	spages = pages;  	do { -		len = min_t(size_t, PAGE_CACHE_SIZE, buflen); +		len = min_t(size_t, PAGE_SIZE, buflen);  		newpage = alloc_page(GFP_KERNEL);  		if (newpage == NULL) @@ -3739,7 +3739,7 @@ static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size  	struct nfs4_cached_acl *acl;  	size_t buflen = sizeof(*acl) + acl_len; -	if (pages && buflen <= PAGE_SIZE) { +	if (buflen <= PAGE_SIZE) {  		acl = kmalloc(buflen, GFP_KERNEL);  		if (acl == NULL)  			goto out; @@ -3782,17 +3782,15 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu  		.rpc_argp = &args,  		.rpc_resp = &res,  	}; -	int ret = -ENOMEM, npages, i; -	size_t acl_len = 0; +	unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE); +	int ret = -ENOMEM, i; -	npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;  	/* As long as we're doing a round trip to the server anyway,  	 * let's be prepared for a page of acl data. */  	if (npages == 0)  		npages = 1; - -	/* Add an extra page to handle the bitmap returned */ -	npages++; +	if (npages > ARRAY_SIZE(pages)) +		return -ERANGE;  	for (i = 0; i < npages; i++) {  		pages[i] = alloc_page(GFP_KERNEL); @@ -3808,11 +3806,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu  	args.acl_len = npages * PAGE_SIZE;  	args.acl_pgbase = 0; -	/* Let decode_getfacl know not to fail if the ACL data is larger than -	 * the page we send as a guess */ -	if (buf == NULL) -		res.acl_flags |= NFS4_ACL_LEN_REQUEST; -  	dprintk("%s  buf %p buflen %zu npages %d args.acl_len %zu\n",  		__func__, buf, buflen, npages, args.acl_len);  	ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), @@ -3820,20 +3813,19 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu  	if (ret)  		goto out_free; -	acl_len = res.acl_len; -	if (acl_len > args.acl_len) -		nfs4_write_cached_acl(inode, NULL, 0, acl_len); -	else -		nfs4_write_cached_acl(inode, pages, res.acl_data_offset, -				      acl_len); -	if (buf) { +	/* Handle the case where the passed-in buffer is too short */ +	if (res.acl_flags & NFS4_ACL_TRUNC) { +		/* Did the user only issue a request for the acl length? */ +		if (buf == NULL) +			goto out_ok;  		ret = -ERANGE; -		if (acl_len > buflen) -			goto out_free; -		_copy_from_pages(buf, pages, res.acl_data_offset, -				acl_len); +		goto out_free;  	} -	ret = acl_len; +	nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len); +	if (buf) +		_copy_from_pages(buf, pages, res.acl_data_offset, res.acl_len); +out_ok: +	ret = res.acl_len;  out_free:  	for (i = 0; i < npages; i++)  		if (pages[i]) @@ -3891,10 +3883,13 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl  		.rpc_argp	= &arg,  		.rpc_resp	= &res,  	}; +	unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);  	int ret, i;  	if (!nfs4_server_supports_acls(server))  		return -EOPNOTSUPP; +	if (npages > ARRAY_SIZE(pages)) +		return -ERANGE;  	i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);  	if (i < 0)  		return i; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1bfbd67c556..8dba6bd4855 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -5072,18 +5072,14 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,  		 * are stored with the acl data to handle the problem of  		 * variable length bitmaps.*/  		res->acl_data_offset = xdr_stream_pos(xdr) - pg_offset; - -		/* We ignore &savep and don't do consistency checks on -		 * the attr length.  Let userspace figure it out.... */  		res->acl_len = attrlen; -		if (attrlen > (xdr->nwords << 2)) { -			if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { -				/* getxattr interface called with a NULL buf */ -				goto out; -			} + +		/* Check for receive buffer overflow */ +		if (res->acl_len > (xdr->nwords << 2) || +		    res->acl_len + res->acl_data_offset > xdr->buf->page_len) { +			res->acl_flags |= NFS4_ACL_TRUNC;  			dprintk("NFS: acl reply: attrlen %u > page_len %u\n",  					attrlen, xdr->nwords << 2); -			return -EINVAL;  		}  	} else  		status = -EOPNOTSUPP; @@ -6229,7 +6225,8 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,  	status = decode_open(xdr, res);  	if (status)  		goto out; -	if (decode_getfh(xdr, &res->fh) != 0) +	status = decode_getfh(xdr, &res->fh); +	if (status)  		goto out;  	decode_getfattr(xdr, res->f_attr, res->server);  out: diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 239aff7338e..b8eda700584 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1867,6 +1867,7 @@ static int nfs23_validate_mount_data(void *options,  		memcpy(sap, &data->addr, sizeof(data->addr));  		args->nfs_server.addrlen = sizeof(data->addr); +		args->nfs_server.port = ntohs(data->addr.sin_port);  		if (!nfs_verify_server_address(sap))  			goto out_no_address; @@ -2564,6 +2565,7 @@ static int nfs4_validate_mount_data(void *options,  			return -EFAULT;  		if (!nfs_verify_server_address(sap))  			goto out_no_address; +		args->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);  		if (data->auth_flavourlen) {  			if (data->auth_flavourlen > 1)  |