aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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
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')
-rw-r--r--fs/nfsd/nfs2acl.c20
-rw-r--r--fs/nfsd/nfs3acl.c16
-rw-r--r--fs/nfsd/nfs4acl.c16
3 files changed, 25 insertions, 27 deletions
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 1580ea6fd64d..d08cd88155c7 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -104,22 +104,21 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
104 goto out; 104 goto out;
105 105
106 inode = d_inode(fh->fh_dentry); 106 inode = d_inode(fh->fh_dentry);
107 if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) {
108 error = -EOPNOTSUPP;
109 goto out_errno;
110 }
111 107
112 error = fh_want_write(fh); 108 error = fh_want_write(fh);
113 if (error) 109 if (error)
114 goto out_errno; 110 goto out_errno;
115 111
116 error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS); 112 fh_lock(fh);
113
114 error = set_posix_acl(inode, ACL_TYPE_ACCESS, argp->acl_access);
117 if (error) 115 if (error)
118 goto out_drop_write; 116 goto out_drop_lock;
119 error = inode->i_op->set_acl(inode, argp->acl_default, 117 error = set_posix_acl(inode, ACL_TYPE_DEFAULT, argp->acl_default);
120 ACL_TYPE_DEFAULT);
121 if (error) 118 if (error)
122 goto out_drop_write; 119 goto out_drop_lock;
120
121 fh_unlock(fh);
123 122
124 fh_drop_write(fh); 123 fh_drop_write(fh);
125 124
@@ -131,7 +130,8 @@ out:
131 posix_acl_release(argp->acl_access); 130 posix_acl_release(argp->acl_access);
132 posix_acl_release(argp->acl_default); 131 posix_acl_release(argp->acl_default);
133 return nfserr; 132 return nfserr;
134out_drop_write: 133out_drop_lock:
134 fh_unlock(fh);
135 fh_drop_write(fh); 135 fh_drop_write(fh);
136out_errno: 136out_errno:
137 nfserr = nfserrno(error); 137 nfserr = nfserrno(error);
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);
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index 6adabd6049b7..71292a0d6f09 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -770,9 +770,6 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
770 dentry = fhp->fh_dentry; 770 dentry = fhp->fh_dentry;
771 inode = d_inode(dentry); 771 inode = d_inode(dentry);
772 772
773 if (!inode->i_op->set_acl || !IS_POSIXACL(inode))
774 return nfserr_attrnotsupp;
775
776 if (S_ISDIR(inode->i_mode)) 773 if (S_ISDIR(inode->i_mode))
777 flags = NFS4_ACL_DIR; 774 flags = NFS4_ACL_DIR;
778 775
@@ -782,16 +779,19 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
782 if (host_error < 0) 779 if (host_error < 0)
783 goto out_nfserr; 780 goto out_nfserr;
784 781
785 host_error = inode->i_op->set_acl(inode, pacl, ACL_TYPE_ACCESS); 782 fh_lock(fhp);
783
784 host_error = set_posix_acl(inode, ACL_TYPE_ACCESS, pacl);
786 if (host_error < 0) 785 if (host_error < 0)
787 goto out_release; 786 goto out_drop_lock;
788 787
789 if (S_ISDIR(inode->i_mode)) { 788 if (S_ISDIR(inode->i_mode)) {
790 host_error = inode->i_op->set_acl(inode, dpacl, 789 host_error = set_posix_acl(inode, ACL_TYPE_DEFAULT, dpacl);
791 ACL_TYPE_DEFAULT);
792 } 790 }
793 791
794out_release: 792out_drop_lock:
793 fh_unlock(fhp);
794
795 posix_acl_release(pacl); 795 posix_acl_release(pacl);
796 posix_acl_release(dpacl); 796 posix_acl_release(dpacl);
797out_nfserr: 797out_nfserr: