Security: Improve performance by reusing current->act_as calculations From: David Howells Improve performance of the subjective security patches a little by reusing current->act_as calculations in a few places. Signed-off-by: David Howells --- fs/attr.c | 13 +++++++------ fs/namei.c | 11 +++++++---- fs/posix_acl.c | 9 +++++---- include/linux/fs.h | 4 +++- include/linux/sched.h | 8 +++++++- kernel/sys.c | 3 +-- 6 files changed, 30 insertions(+), 18 deletions(-) diff --git a/fs/attr.c b/fs/attr.c index 117cca7..ba90b9f 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -20,6 +20,7 @@ /* POSIX UID/GID verification for setting inode attributes. */ int inode_change_ok(struct inode *inode, struct iattr *attr) { + struct task_security *act_as = current->act_as; int retval = -EPERM; unsigned int ia_valid = attr->ia_valid; @@ -29,30 +30,30 @@ int inode_change_ok(struct inode *inode, struct iattr *attr) /* Make sure a caller can chown. */ if ((ia_valid & ATTR_UID) && - (current_fsuid() != inode->i_uid || + (act_as->uid != inode->i_uid || attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) goto error; /* Make sure caller can chgrp. */ if ((ia_valid & ATTR_GID) && - (current_fsuid() != inode->i_uid || - (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) && + (act_as->uid != inode->i_uid || + (!__in_group_p(act_as, attr->ia_gid) && attr->ia_gid != inode->i_gid)) && !capable(CAP_CHOWN)) goto error; /* Make sure a caller can chmod. */ if (ia_valid & ATTR_MODE) { - if (!is_owner_or_cap(inode)) + if (!__is_owner_or_cap(act_as, inode)) goto error; /* Also check the setgid bit! */ - if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : + if (!__in_group_p(act_as, (ia_valid & ATTR_GID) ? attr->ia_gid : inode->i_gid) && !capable(CAP_FSETID)) attr->ia_mode &= ~S_ISGID; } /* Check for setting the inode time. */ if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { - if (!is_owner_or_cap(inode)) + if (!__is_owner_or_cap(act_as, inode)) goto error; } fine: diff --git a/fs/namei.c b/fs/namei.c index 495c759..81277fa 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -182,9 +182,10 @@ EXPORT_SYMBOL(putname); int generic_permission(struct inode *inode, int mask, int (*check_acl)(struct inode *inode, int mask)) { + struct task_security *act_as = current->act_as; umode_t mode = inode->i_mode; - if (current_fsuid() == inode->i_uid) + if (act_as->uid == inode->i_uid) mode >>= 6; else { if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { @@ -195,7 +196,7 @@ int generic_permission(struct inode *inode, int mask, return error; } - if (in_group_p(inode->i_gid)) + if (__in_group_p(act_as, inode->i_gid)) mode >>= 3; } @@ -457,14 +458,16 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, static int exec_permission_lite(struct inode *inode, struct nameidata *nd) { + struct task_security *act_as; umode_t mode = inode->i_mode; if (inode->i_op && inode->i_op->permission) return -EAGAIN; - if (current_fsuid() == inode->i_uid) + act_as = current->act_as; + if (act_as->uid == inode->i_uid) mode >>= 6; - else if (in_group_p(inode->i_gid)) + else if (__in_group_p(act_as, inode->i_gid)) mode >>= 3; if (mode & MAY_EXEC) diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 39df95a..623370d 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -211,28 +211,29 @@ int posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want) { const struct posix_acl_entry *pa, *pe, *mask_obj; + struct task_security *act_as = current->act_as; int found = 0; FOREACH_ACL_ENTRY(pa, acl, pe) { switch(pa->e_tag) { case ACL_USER_OBJ: /* (May have been checked already) */ - if (inode->i_uid == current_fsuid()) + if (inode->i_uid == act_as->uid) goto check_perm; break; case ACL_USER: - if (pa->e_id == current_fsuid()) + if (pa->e_id == act_as->uid) goto mask; break; case ACL_GROUP_OBJ: - if (in_group_p(inode->i_gid)) { + if (__in_group_p(act_as, inode->i_gid)) { found = 1; if ((pa->e_perm & want) == want) goto mask; } break; case ACL_GROUP: - if (in_group_p(pa->e_id)) { + if (__in_group_p(act_as, pa->e_id)) { found = 1; if ((pa->e_perm & want) == want) goto mask; diff --git a/include/linux/fs.h b/include/linux/fs.h index d218ef5..cdf3e28 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1064,8 +1064,10 @@ enum { #define put_fs_excl() atomic_dec(¤t->fs_excl) #define has_fs_excl() atomic_read(¤t->fs_excl) +#define __is_owner_or_cap(act_as, inode) \ + (((act_as)->uid == (inode)->i_uid) || capable(CAP_FOWNER)) #define is_owner_or_cap(inode) \ - ((current_fsuid() == (inode)->i_uid) || capable(CAP_FOWNER)) + (__is_owner_or_cap(current->act_as, (inode))) /* not quite ready to be deprecated, but... */ extern void lock_super(struct super_block *); diff --git a/include/linux/sched.h b/include/linux/sched.h index 983b532..f0d645d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1739,7 +1739,13 @@ extern void wake_up_new_task(struct task_struct *tsk, extern void sched_fork(struct task_struct *p, int clone_flags); extern void sched_dead(struct task_struct *p); -extern int in_group_p(gid_t); +extern int __in_group_p(struct task_security *, gid_t); + +static inline int in_group_p(gid_t grp) +{ + return __in_group_p(current->act_as, grp); +} + extern int in_egroup_p(gid_t); extern void proc_caches_init(void); diff --git a/kernel/sys.c b/kernel/sys.c index ec0c251..7bc39f9 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1337,9 +1337,8 @@ asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist) /* * Check whether we're fsgid/egid or in the supplemental group.. */ -int in_group_p(gid_t grp) +int __in_group_p(struct task_security *act_as, gid_t grp) { - struct task_security *act_as = current->act_as; int retval = 1; if (grp != act_as->fsgid) retval = groups_search(act_as->group_info, grp);