diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-08-28 14:51:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-08 14:07:44 -0400 |
commit | 5909ccaa300a4a834ffa275327af4df0b9cb5295 (patch) | |
tree | b4e402a2a544be7c59bccd4b4533787f2f19e7bc | |
parent | cb9179ead0aa0e3b7b4087cdba59baf16bbeef6d (diff) |
Make 'check_acl()' a first-class filesystem op
This is stage one in flattening out the callchains for the common
permission testing. Rather than have most filesystem implement their
own inode->i_op->permission function that just calls back down to the
VFS layers 'generic_permission()' with the per-filesystem ACL checking
function, the filesystem can just expose its 'check_acl' function
directly, and let the VFS layer do everything for it.
This is all just preparatory - no filesystem actually enables this yet.
Reviewed-by: James Morris <jmorris@namei.org>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/namei.c | 62 | ||||
-rw-r--r-- | include/linux/fs.h | 1 |
2 files changed, 36 insertions, 27 deletions
diff --git a/fs/namei.c b/fs/namei.c index e645e3070360..ed27bb205b7e 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -169,19 +169,10 @@ void putname(const char *name) | |||
169 | EXPORT_SYMBOL(putname); | 169 | EXPORT_SYMBOL(putname); |
170 | #endif | 170 | #endif |
171 | 171 | ||
172 | 172 | /* | |
173 | /** | 173 | * This does basic POSIX ACL permission checking |
174 | * generic_permission - check for access rights on a Posix-like filesystem | ||
175 | * @inode: inode to check access rights for | ||
176 | * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) | ||
177 | * @check_acl: optional callback to check for Posix ACLs | ||
178 | * | ||
179 | * Used to check for read/write/execute permissions on a file. | ||
180 | * We use "fsuid" for this, letting us set arbitrary permissions | ||
181 | * for filesystem access without changing the "normal" uids which | ||
182 | * are used for other things.. | ||
183 | */ | 174 | */ |
184 | int generic_permission(struct inode *inode, int mask, | 175 | static int acl_permission_check(struct inode *inode, int mask, |
185 | int (*check_acl)(struct inode *inode, int mask)) | 176 | int (*check_acl)(struct inode *inode, int mask)) |
186 | { | 177 | { |
187 | umode_t mode = inode->i_mode; | 178 | umode_t mode = inode->i_mode; |
@@ -193,9 +184,7 @@ int generic_permission(struct inode *inode, int mask, | |||
193 | else { | 184 | else { |
194 | if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { | 185 | if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { |
195 | int error = check_acl(inode, mask); | 186 | int error = check_acl(inode, mask); |
196 | if (error == -EACCES) | 187 | if (error != -EAGAIN) |
197 | goto check_capabilities; | ||
198 | else if (error != -EAGAIN) | ||
199 | return error; | 188 | return error; |
200 | } | 189 | } |
201 | 190 | ||
@@ -208,8 +197,32 @@ int generic_permission(struct inode *inode, int mask, | |||
208 | */ | 197 | */ |
209 | if ((mask & ~mode) == 0) | 198 | if ((mask & ~mode) == 0) |
210 | return 0; | 199 | return 0; |
200 | return -EACCES; | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * generic_permission - check for access rights on a Posix-like filesystem | ||
205 | * @inode: inode to check access rights for | ||
206 | * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) | ||
207 | * @check_acl: optional callback to check for Posix ACLs | ||
208 | * | ||
209 | * Used to check for read/write/execute permissions on a file. | ||
210 | * We use "fsuid" for this, letting us set arbitrary permissions | ||
211 | * for filesystem access without changing the "normal" uids which | ||
212 | * are used for other things.. | ||
213 | */ | ||
214 | int generic_permission(struct inode *inode, int mask, | ||
215 | int (*check_acl)(struct inode *inode, int mask)) | ||
216 | { | ||
217 | int ret; | ||
218 | |||
219 | /* | ||
220 | * Do the basic POSIX ACL permission checks. | ||
221 | */ | ||
222 | ret = acl_permission_check(inode, mask, check_acl); | ||
223 | if (ret != -EACCES) | ||
224 | return ret; | ||
211 | 225 | ||
212 | check_capabilities: | ||
213 | /* | 226 | /* |
214 | * Read/write DACs are always overridable. | 227 | * Read/write DACs are always overridable. |
215 | * Executable DACs are overridable if at least one exec bit is set. | 228 | * Executable DACs are overridable if at least one exec bit is set. |
@@ -262,7 +275,7 @@ int inode_permission(struct inode *inode, int mask) | |||
262 | if (inode->i_op->permission) | 275 | if (inode->i_op->permission) |
263 | retval = inode->i_op->permission(inode, mask); | 276 | retval = inode->i_op->permission(inode, mask); |
264 | else | 277 | else |
265 | retval = generic_permission(inode, mask, NULL); | 278 | retval = generic_permission(inode, mask, inode->i_op->check_acl); |
266 | 279 | ||
267 | if (retval) | 280 | if (retval) |
268 | return retval; | 281 | return retval; |
@@ -432,27 +445,22 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, | |||
432 | */ | 445 | */ |
433 | static int exec_permission_lite(struct inode *inode) | 446 | static int exec_permission_lite(struct inode *inode) |
434 | { | 447 | { |
435 | umode_t mode = inode->i_mode; | 448 | int ret; |
436 | 449 | ||
437 | if (inode->i_op->permission) { | 450 | if (inode->i_op->permission) { |
438 | int ret = inode->i_op->permission(inode, MAY_EXEC); | 451 | ret = inode->i_op->permission(inode, MAY_EXEC); |
439 | if (!ret) | 452 | if (!ret) |
440 | goto ok; | 453 | goto ok; |
441 | return ret; | 454 | return ret; |
442 | } | 455 | } |
443 | 456 | ret = acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl); | |
444 | if (current_fsuid() == inode->i_uid) | 457 | if (!ret) |
445 | mode >>= 6; | ||
446 | else if (in_group_p(inode->i_gid)) | ||
447 | mode >>= 3; | ||
448 | |||
449 | if (mode & MAY_EXEC) | ||
450 | goto ok; | 458 | goto ok; |
451 | 459 | ||
452 | if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH)) | 460 | if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH)) |
453 | goto ok; | 461 | goto ok; |
454 | 462 | ||
455 | return -EACCES; | 463 | return ret; |
456 | ok: | 464 | ok: |
457 | return security_inode_permission(inode, MAY_EXEC); | 465 | return security_inode_permission(inode, MAY_EXEC); |
458 | } | 466 | } |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 73e9b643e455..c1f993515f51 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1528,6 +1528,7 @@ struct inode_operations { | |||
1528 | void (*put_link) (struct dentry *, struct nameidata *, void *); | 1528 | void (*put_link) (struct dentry *, struct nameidata *, void *); |
1529 | void (*truncate) (struct inode *); | 1529 | void (*truncate) (struct inode *); |
1530 | int (*permission) (struct inode *, int); | 1530 | int (*permission) (struct inode *, int); |
1531 | int (*check_acl)(struct inode *, int); | ||
1531 | int (*setattr) (struct dentry *, struct iattr *); | 1532 | int (*setattr) (struct dentry *, struct iattr *); |
1532 | int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); | 1533 | int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); |
1533 | int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); | 1534 | int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); |