aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs3acl.c
diff options
context:
space:
mode:
authorBen Hutchings <ben@decadent.org.uk>2016-06-22 14:43:35 -0400
committerJ. Bruce Fields <bfields@redhat.com>2016-06-24 12:11:52 -0400
commit999653786df6954a31044528ac3f7a5dadca08f4 (patch)
tree1591ca7fc7acbd0128b33701516f85276ad8ff06 /fs/nfsd/nfs3acl.c
parent485e71e8fb6356c08c7fc6bcce4bf02c9a9a663f (diff)
nfsd: check permissions when setting ACLs
Use set_posix_acl, which includes proper permission checks, instead of calling ->set_acl directly. Without this anyone may be able to grant themselves permissions to a file by setting the ACL. Lock the inode to make the new checks atomic with respect to set_acl. (Also, nfsd was the only caller of set_acl not locking the inode, so I suspect this may fix other races.) This also simplifies the code, and ensures our ACLs are checked by posix_acl_valid. The permission checks and the inode locking were lost with commit 4ac7249e, which changed nfsd to use the set_acl inode operation directly instead of going through xattr handlers. Reported-by: David Sinquin <david@sinquin.eu> [agreunba@redhat.com: use set_posix_acl] Fixes: 4ac7249e Cc: Christoph Hellwig <hch@infradead.org> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs3acl.c')
-rw-r--r--fs/nfsd/nfs3acl.c16
1 files changed, 7 insertions, 9 deletions
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index 01df4cd7c753..0c890347cde3 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -95,22 +95,20 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp,
95 goto out; 95 goto out;
96 96
97 inode = d_inode(fh->fh_dentry); 97 inode = d_inode(fh->fh_dentry);
98 if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) {
99 error = -EOPNOTSUPP;
100 goto out_errno;
101 }
102 98
103 error = fh_want_write(fh); 99 error = fh_want_write(fh);
104 if (error) 100 if (error)
105 goto out_errno; 101 goto out_errno;
106 102
107 error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS); 103 fh_lock(fh);
104
105 error = set_posix_acl(inode, ACL_TYPE_ACCESS, argp->acl_access);
108 if (error) 106 if (error)
109 goto out_drop_write; 107 goto out_drop_lock;
110 error = inode->i_op->set_acl(inode, argp->acl_default, 108 error = set_posix_acl(inode, ACL_TYPE_DEFAULT, argp->acl_default);
111 ACL_TYPE_DEFAULT);
112 109
113out_drop_write: 110out_drop_lock:
111 fh_unlock(fh);
114 fh_drop_write(fh); 112 fh_drop_write(fh);
115out_errno: 113out_errno:
116 nfserr = nfserrno(error); 114 nfserr = nfserrno(error);