aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2011-01-07 01:49:58 -0500
committerNick Piggin <npiggin@kernel.dk>2011-01-07 01:50:29 -0500
commitb74c79e99389cd79b31fcc08f82c24e492e63c7e (patch)
tree763c6b412517306670bc625e90035f2d16bb739f /fs/namei.c
parent34286d6662308d82aed891852d04c7c3a2649b16 (diff)
fs: provide rcu-walk aware permission i_ops
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c75
1 files changed, 29 insertions, 46 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 6e275363e89d..4e957bf744ae 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -169,8 +169,8 @@ EXPORT_SYMBOL(putname);
169/* 169/*
170 * This does basic POSIX ACL permission checking 170 * This does basic POSIX ACL permission checking
171 */ 171 */
172static inline int __acl_permission_check(struct inode *inode, int mask, 172static int acl_permission_check(struct inode *inode, int mask, unsigned int flags,
173 int (*check_acl)(struct inode *inode, int mask), int rcu) 173 int (*check_acl)(struct inode *inode, int mask, unsigned int flags))
174{ 174{
175 umode_t mode = inode->i_mode; 175 umode_t mode = inode->i_mode;
176 176
@@ -180,13 +180,9 @@ static inline int __acl_permission_check(struct inode *inode, int mask,
180 mode >>= 6; 180 mode >>= 6;
181 else { 181 else {
182 if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { 182 if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {
183 if (rcu) { 183 int error = check_acl(inode, mask, flags);
184 return -ECHILD; 184 if (error != -EAGAIN)
185 } else { 185 return error;
186 int error = check_acl(inode, mask);
187 if (error != -EAGAIN)
188 return error;
189 }
190 } 186 }
191 187
192 if (in_group_p(inode->i_gid)) 188 if (in_group_p(inode->i_gid))
@@ -201,32 +197,31 @@ static inline int __acl_permission_check(struct inode *inode, int mask,
201 return -EACCES; 197 return -EACCES;
202} 198}
203 199
204static inline int acl_permission_check(struct inode *inode, int mask,
205 int (*check_acl)(struct inode *inode, int mask))
206{
207 return __acl_permission_check(inode, mask, check_acl, 0);
208}
209
210/** 200/**
211 * generic_permission - check for access rights on a Posix-like filesystem 201 * generic_permission - check for access rights on a Posix-like filesystem
212 * @inode: inode to check access rights for 202 * @inode: inode to check access rights for
213 * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) 203 * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
214 * @check_acl: optional callback to check for Posix ACLs 204 * @check_acl: optional callback to check for Posix ACLs
205 * @flags IPERM_FLAG_ flags.
215 * 206 *
216 * Used to check for read/write/execute permissions on a file. 207 * Used to check for read/write/execute permissions on a file.
217 * We use "fsuid" for this, letting us set arbitrary permissions 208 * We use "fsuid" for this, letting us set arbitrary permissions
218 * for filesystem access without changing the "normal" uids which 209 * for filesystem access without changing the "normal" uids which
219 * are used for other things.. 210 * are used for other things.
211 *
212 * generic_permission is rcu-walk aware. It returns -ECHILD in case an rcu-walk
213 * request cannot be satisfied (eg. requires blocking or too much complexity).
214 * It would then be called again in ref-walk mode.
220 */ 215 */
221int generic_permission(struct inode *inode, int mask, 216int generic_permission(struct inode *inode, int mask, unsigned int flags,
222 int (*check_acl)(struct inode *inode, int mask)) 217 int (*check_acl)(struct inode *inode, int mask, unsigned int flags))
223{ 218{
224 int ret; 219 int ret;
225 220
226 /* 221 /*
227 * Do the basic POSIX ACL permission checks. 222 * Do the basic POSIX ACL permission checks.
228 */ 223 */
229 ret = acl_permission_check(inode, mask, check_acl); 224 ret = acl_permission_check(inode, mask, flags, check_acl);
230 if (ret != -EACCES) 225 if (ret != -EACCES)
231 return ret; 226 return ret;
232 227
@@ -281,9 +276,10 @@ int inode_permission(struct inode *inode, int mask)
281 } 276 }
282 277
283 if (inode->i_op->permission) 278 if (inode->i_op->permission)
284 retval = inode->i_op->permission(inode, mask); 279 retval = inode->i_op->permission(inode, mask, 0);
285 else 280 else
286 retval = generic_permission(inode, mask, inode->i_op->check_acl); 281 retval = generic_permission(inode, mask, 0,
282 inode->i_op->check_acl);
287 283
288 if (retval) 284 if (retval)
289 return retval; 285 return retval;
@@ -668,22 +664,19 @@ force_reval_path(struct path *path, struct nameidata *nd)
668 * short-cut DAC fails, then call ->permission() to do more 664 * short-cut DAC fails, then call ->permission() to do more
669 * complete permission check. 665 * complete permission check.
670 */ 666 */
671static inline int __exec_permission(struct inode *inode, int rcu) 667static inline int exec_permission(struct inode *inode, unsigned int flags)
672{ 668{
673 int ret; 669 int ret;
674 670
675 if (inode->i_op->permission) { 671 if (inode->i_op->permission) {
676 if (rcu) 672 ret = inode->i_op->permission(inode, MAY_EXEC, flags);
677 return -ECHILD; 673 } else {
678 ret = inode->i_op->permission(inode, MAY_EXEC); 674 ret = acl_permission_check(inode, MAY_EXEC, flags,
679 if (!ret) 675 inode->i_op->check_acl);
680 goto ok;
681 return ret;
682 } 676 }
683 ret = __acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl, rcu); 677 if (likely(!ret))
684 if (!ret)
685 goto ok; 678 goto ok;
686 if (rcu && ret == -ECHILD) 679 if (ret == -ECHILD)
687 return ret; 680 return ret;
688 681
689 if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH)) 682 if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH))
@@ -691,17 +684,7 @@ static inline int __exec_permission(struct inode *inode, int rcu)
691 684
692 return ret; 685 return ret;
693ok: 686ok:
694 return security_inode_exec_permission(inode, rcu); 687 return security_inode_exec_permission(inode, flags);
695}
696
697static int exec_permission(struct inode *inode)
698{
699 return __exec_permission(inode, 0);
700}
701
702static int exec_permission_rcu(struct inode *inode)
703{
704 return __exec_permission(inode, 1);
705} 688}
706 689
707static __always_inline void set_root(struct nameidata *nd) 690static __always_inline void set_root(struct nameidata *nd)
@@ -1165,7 +1148,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
1165 1148
1166 nd->flags |= LOOKUP_CONTINUE; 1149 nd->flags |= LOOKUP_CONTINUE;
1167 if (nd->flags & LOOKUP_RCU) { 1150 if (nd->flags & LOOKUP_RCU) {
1168 err = exec_permission_rcu(nd->inode); 1151 err = exec_permission(nd->inode, IPERM_FLAG_RCU);
1169 if (err == -ECHILD) { 1152 if (err == -ECHILD) {
1170 if (nameidata_drop_rcu(nd)) 1153 if (nameidata_drop_rcu(nd))
1171 return -ECHILD; 1154 return -ECHILD;
@@ -1173,7 +1156,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
1173 } 1156 }
1174 } else { 1157 } else {
1175exec_again: 1158exec_again:
1176 err = exec_permission(nd->inode); 1159 err = exec_permission(nd->inode, 0);
1177 } 1160 }
1178 if (err) 1161 if (err)
1179 break; 1162 break;
@@ -1620,7 +1603,7 @@ static struct dentry *__lookup_hash(struct qstr *name,
1620 struct dentry *dentry; 1603 struct dentry *dentry;
1621 int err; 1604 int err;
1622 1605
1623 err = exec_permission(inode); 1606 err = exec_permission(inode, 0);
1624 if (err) 1607 if (err)
1625 return ERR_PTR(err); 1608 return ERR_PTR(err);
1626 1609