diff options
Diffstat (limited to 'security/security.c')
-rw-r--r-- | security/security.c | 146 |
1 files changed, 74 insertions, 72 deletions
diff --git a/security/security.c b/security/security.c index 39ffe949e509a5..f99d57f7c94429 100644 --- a/security/security.c +++ b/security/security.c @@ -945,10 +945,41 @@ out: \ RC; \ }) -#define lsm_for_each_hook(scall, NAME) \ - for (scall = static_calls_table.NAME; \ - scall - static_calls_table.NAME < MAX_LSM_COUNT; scall++) \ - if (static_key_enabled(&scall->active->key)) +/** + * Can be used in the context passed to lsm_for_each_hook to get the lsmid of the + * current hook + */ +#define current_lsmid() _hook_lsmid + +#define __CALL_HOOK(NUM, HOOK, RC, BODY_BEFORE, BODY_AFTER, ...) \ +do { \ + int _hook_lsmid; \ + \ + if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ + _hook_lsmid = static_calls_table.HOOK[NUM].hl->lsmid->id; \ + BODY_BEFORE \ + RC = static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ + BODY_AFTER \ + } \ +} while (0); + +#define lsm_for_each_hook(HOOK, RC, BODY, ...) \ + LSM_LOOP_UNROLL(__CALL_HOOK, HOOK, RC, ;, BODY, __VA_ARGS__) + +#define call_hook_with_lsmid(HOOK, LSMID, ...) \ +({ \ + __label__ out; \ + int RC = LSM_RET_DEFAULT(HOOK); \ + \ + LSM_LOOP_UNROLL(__CALL_HOOK, HOOK, RC, { \ + if (current_lsmid() != LSMID) \ + continue; \ + }, { \ + goto out; \ + }, __VA_ARGS__); \ +out: \ + RC; \ +}) /* Security operations */ @@ -1184,7 +1215,6 @@ int security_settime64(const struct timespec64 *ts, const struct timezone *tz) */ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) { - struct lsm_static_call *scall; int cap_sys_admin = 1; int rc; @@ -1195,13 +1225,16 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) * agree that it should be set it will. If any module * thinks it should not be set it won't. */ - lsm_for_each_hook(scall, vm_enough_memory) { - rc = scall->hl->hook.vm_enough_memory(mm, pages); - if (rc <= 0) { - cap_sys_admin = 0; - break; - } - } + + lsm_for_each_hook(vm_enough_memory, rc, + { + if (rc <= 0) { + cap_sys_admin = 0; + break; + } + }, + mm, pages); + return __vm_enough_memory(mm, pages, cap_sys_admin); } @@ -1343,17 +1376,16 @@ int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc) int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) { - struct lsm_static_call *scall; - int trc; + int trc = LSM_RET_DEFAULT(fs_context_parse_param); int rc = -ENOPARAM; - lsm_for_each_hook(scall, fs_context_parse_param) { - trc = scall->hl->hook.fs_context_parse_param(fc, param); + lsm_for_each_hook(fs_context_parse_param, trc, { if (trc == 0) rc = 0; else if (trc != -ENOPARAM) return trc; - } + }, fc, param); + return rc; } @@ -1578,15 +1610,13 @@ int security_sb_set_mnt_opts(struct super_block *sb, unsigned long kern_flags, unsigned long *set_kern_flags) { - struct lsm_static_call *scall; int rc = mnt_opts ? -EOPNOTSUPP : LSM_RET_DEFAULT(sb_set_mnt_opts); - lsm_for_each_hook(scall, sb_set_mnt_opts) { - rc = scall->hl->hook.sb_set_mnt_opts(sb, mnt_opts, kern_flags, - set_kern_flags); + lsm_for_each_hook(sb_set_mnt_opts, rc, { if (rc != LSM_RET_DEFAULT(sb_set_mnt_opts)) break; - } + }, sb, mnt_opts, kern_flags, set_kern_flags); + return rc; } EXPORT_SYMBOL(security_sb_set_mnt_opts); @@ -1777,7 +1807,6 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, const initxattrs initxattrs, void *fs_data) { - struct lsm_static_call *scall; struct xattr *new_xattrs = NULL; int ret = -EOPNOTSUPP, xattr_count = 0; @@ -1795,18 +1824,17 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, return -ENOMEM; } - lsm_for_each_hook(scall, inode_init_security) { - ret = scall->hl->hook.inode_init_security(inode, dir, qstr, new_xattrs, - &xattr_count); - if (ret && ret != -EOPNOTSUPP) - goto out; + lsm_for_each_hook(inode_init_security, ret, { /* * As documented in lsm_hooks.h, -EOPNOTSUPP in this context * means that the LSM is not willing to provide an xattr, not * that it wants to signal an error. Thus, continue to invoke * the remaining LSMs. */ - } + if (ret && ret != -EOPNOTSUPP) + goto out; + }, + inode, dir, qstr, new_xattrs, &xattr_count); /* If initxattrs() is NULL, xattr_count is zero, skip the call. */ if (!xattr_count) @@ -3601,16 +3629,15 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, { int thisrc; int rc = LSM_RET_DEFAULT(task_prctl); - struct lsm_static_call *scall; - lsm_for_each_hook(scall, task_prctl) { - thisrc = scall->hl->hook.task_prctl(option, arg2, arg3, arg4, arg5); + lsm_for_each_hook(task_prctl, thisrc, { if (thisrc != LSM_RET_DEFAULT(task_prctl)) { rc = thisrc; if (thisrc != 0) break; } - } + }, option, arg2, arg3, arg4, arg5); + return rc; } @@ -3991,6 +4018,9 @@ EXPORT_SYMBOL(security_d_instantiate); * Please keep this in sync with it's counterpart in security/lsm_syscalls.c */ +#define call_getselfattr(RC, BODY_BEFORE, BODY_AFTER, ...) \ + LSM_LOOP_UNROLL(__CALL_HOOK, getselfattr, RC, BODY_BEFORE, BODY_AFTER, __VA_ARGS__) + /** * security_getselfattr - Read an LSM attribute of the current process. * @attr: which attribute to return @@ -4010,7 +4040,6 @@ EXPORT_SYMBOL(security_d_instantiate); int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx, u32 __user *size, u32 flags) { - struct lsm_static_call *scall; struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, }; u8 __user *base = (u8 __user *)uctx; u32 entrysize; @@ -4048,13 +4077,14 @@ int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx, * In the usual case gather all the data from the LSMs. * In the single case only get the data from the LSM specified. */ - lsm_for_each_hook(scall, getselfattr) { - if (single && lctx.id != scall->hl->lsmid->id) + + call_getselfattr(rc, { + if (single && lctx.id != current_lsmid()) continue; entrysize = left; if (base) uctx = (struct lsm_ctx __user *)(base + total); - rc = scall->hl->hook.getselfattr(attr, uctx, &entrysize, flags); + }, { if (rc == -EOPNOTSUPP) { rc = 0; continue; @@ -4072,7 +4102,8 @@ int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx, count += rc; if (single) break; - } + }, attr, uctx, &entrysize, flags); + if (put_user(total, size)) return -EFAULT; if (toobig) @@ -4103,9 +4134,8 @@ int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx, int security_setselfattr(unsigned int attr, struct lsm_ctx __user *uctx, u32 size, u32 flags) { - struct lsm_static_call *scall; struct lsm_ctx *lctx; - int rc = LSM_RET_DEFAULT(setselfattr); + int rc; u64 required_len; if (flags) @@ -4126,11 +4156,7 @@ int security_setselfattr(unsigned int attr, struct lsm_ctx __user *uctx, goto free_out; } - lsm_for_each_hook(scall, setselfattr) - if ((scall->hl->lsmid->id) == lctx->id) { - rc = scall->hl->hook.setselfattr(attr, lctx, size, flags); - break; - } + rc = call_hook_with_lsmid(setselfattr, lctx->id, attr, lctx, size, flags); free_out: kfree(lctx); @@ -4151,14 +4177,7 @@ free_out: int security_getprocattr(struct task_struct *p, int lsmid, const char *name, char **value) { - struct lsm_static_call *scall; - - lsm_for_each_hook(scall, getprocattr) { - if (lsmid != 0 && lsmid != scall->hl->lsmid->id) - continue; - return scall->hl->hook.getprocattr(p, name, value); - } - return LSM_RET_DEFAULT(getprocattr); + return call_hook_with_lsmid(getprocattr, lsmid, p, name, value); } /** @@ -4175,14 +4194,7 @@ int security_getprocattr(struct task_struct *p, int lsmid, const char *name, */ int security_setprocattr(int lsmid, const char *name, void *value, size_t size) { - struct lsm_static_call *scall; - - lsm_for_each_hook(scall, setprocattr) { - if (lsmid != 0 && lsmid != scall->hl->lsmid->id) - continue; - return scall->hl->hook.setprocattr(name, value, size); - } - return LSM_RET_DEFAULT(setprocattr); + return call_hook_with_lsmid(setprocattr, lsmid, name, value, size); } /** @@ -5267,23 +5279,13 @@ int security_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, const struct flowi_common *flic) { - struct lsm_static_call *scall; - int rc = LSM_RET_DEFAULT(xfrm_state_pol_flow_match); - /* * Since this function is expected to return 0 or 1, the judgment * becomes difficult if multiple LSMs supply this call. Fortunately, * we can use the first LSM's judgment because currently only SELinux * supplies this call. - * - * For speed optimization, we explicitly break the loop rather than - * using the macro */ - lsm_for_each_hook(scall, xfrm_state_pol_flow_match) { - rc = scall->hl->hook.xfrm_state_pol_flow_match(x, xp, flic); - break; - } - return rc; + return call_int_hook(xfrm_state_pol_flow_match, x, xp, flic); } /** |