diff options
-rw-r--r-- | fs/namei.c | 72 |
1 files changed, 38 insertions, 34 deletions
diff --git a/fs/namei.c b/fs/namei.c index 4ad2b781a65..e04f15ae4b0 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -303,6 +303,44 @@ int inode_permission(struct inode *inode, int mask) return security_inode_permission(inode, mask); } +/** + * exec_permission - check for right to do lookups in a given directory + * @inode: inode to check permission on + * @flags: IPERM_FLAG_ flags. + * + * Short-cut version of inode_permission(), for calling on directories + * during pathname resolution. Combines parts of inode_permission() + * and generic_permission(), and tests ONLY for MAY_EXEC permission. + * + * If appropriate, check DAC only. If not appropriate, or + * short-cut DAC fails, then call ->permission() to do more + * complete permission check. + */ +static inline int exec_permission(struct inode *inode, unsigned int flags) +{ + int ret; + struct user_namespace *ns = inode_userns(inode); + + if (inode->i_op->permission) { + ret = inode->i_op->permission(inode, MAY_EXEC, flags); + if (likely(!ret)) + goto ok; + } else { + ret = acl_permission_check(inode, MAY_EXEC, flags, + inode->i_op->check_acl); + if (likely(!ret)) + goto ok; + if (ret != -EACCES) + return ret; + if (ns_capable(ns, CAP_DAC_OVERRIDE) || + ns_capable(ns, CAP_DAC_READ_SEARCH)) + goto ok; + } + return ret; +ok: + return security_inode_exec_permission(inode, flags); +} + /* * get_write_access() gets write permission for a file. * put_write_access() releases this write permission. @@ -551,40 +589,6 @@ static int complete_walk(struct nameidata *nd) return status; } -/* - * Short-cut version of permission(), for calling on directories - * during pathname resolution. Combines parts of permission() - * and generic_permission(), and tests ONLY for MAY_EXEC permission. - * - * If appropriate, check DAC only. If not appropriate, or - * short-cut DAC fails, then call ->permission() to do more - * complete permission check. - */ -static inline int exec_permission(struct inode *inode, unsigned int flags) -{ - int ret; - struct user_namespace *ns = inode_userns(inode); - - if (inode->i_op->permission) { - ret = inode->i_op->permission(inode, MAY_EXEC, flags); - if (likely(!ret)) - goto ok; - } else { - ret = acl_permission_check(inode, MAY_EXEC, flags, - inode->i_op->check_acl); - if (likely(!ret)) - goto ok; - if (ret != -EACCES) - return ret; - if (ns_capable(ns, CAP_DAC_OVERRIDE) || - ns_capable(ns, CAP_DAC_READ_SEARCH)) - goto ok; - } - return ret; -ok: - return security_inode_exec_permission(inode, flags); -} - static __always_inline void set_root(struct nameidata *nd) { if (!nd->root.mnt) |