diff options
author | Ben Hutchings <ben@decadent.org.uk> | 2016-06-22 14:43:35 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2016-06-24 12:11:52 -0400 |
commit | 999653786df6954a31044528ac3f7a5dadca08f4 (patch) | |
tree | 1591ca7fc7acbd0128b33701516f85276ad8ff06 /fs | |
parent | 485e71e8fb6356c08c7fc6bcce4bf02c9a9a663f (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.c | 20 | ||||
-rw-r--r-- | fs/nfsd/nfs3acl.c | 16 | ||||
-rw-r--r-- | fs/nfsd/nfs4acl.c | 16 |
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; |
134 | out_drop_write: | 133 | out_drop_lock: |
134 | fh_unlock(fh); | ||
135 | fh_drop_write(fh); | 135 | fh_drop_write(fh); |
136 | out_errno: | 136 | out_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 | ||
113 | out_drop_write: | 110 | out_drop_lock: |
111 | fh_unlock(fh); | ||
114 | fh_drop_write(fh); | 112 | fh_drop_write(fh); |
115 | out_errno: | 113 | out_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 | ||
794 | out_release: | 792 | out_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); |
797 | out_nfserr: | 797 | out_nfserr: |