diff --git a/security/security.c b/security/security.c index 70a7ad357bc6ab..b674c5d50a6911 100644 --- a/security/security.c +++ b/security/security.c @@ -28,6 +28,11 @@ #include #include #include +#include +#include +#include +#include + #define MAX_LSM_EVM_XATTR 2 @@ -464,6 +469,45 @@ static int lsm_append(const char *new, char **result) return 0; } +#define LSM_FUNC_DEFAULT(NAME) NAME##_func_default +#define HOOK_STATIC_CALL(HOOK, NUM) static_call_##HOOK##_##NUM +#define HOOK_STATIC_CHECK(HOOK, NUM) static_check_##HOOK##_##NUM + +#define FOR_EACH_HOOK_SLOT(M, ...) \ + M(1, __VA_ARGS__) \ + M(2, __VA_ARGS__) \ + M(3, __VA_ARGS__) + +#define CREATE_STATIC(NUM, NAME) \ + DEFINE_STATIC_CALL(HOOK_STATIC_CALL(NAME, NUM), LSM_FUNC_DEFAULT(NAME)); \ + DEFINE_STATIC_KEY_FALSE(HOOK_STATIC_CHECK(NAME, NUM)); + +// We need a default function that will not be called so that +// static_call can infer the expected type +#define LSM_HOOK(RET, DEFAULT, NAME, ...) \ + noinline RET LSM_FUNC_DEFAULT(NAME)(__VA_ARGS__)\ + { \ + return DEFAULT; \ + } \ + FOR_EACH_HOOK_SLOT(CREATE_STATIC, NAME) +#include +#undef LSM_HOOK +#undef CREATE_STATIC + +#define TRY_TO_ADD(NUM, HOOK, FUNC) \ + if (!static_branch_unlikely(&HOOK_STATIC_CHECK(HOOK, NUM))) { \ + static_call_update(HOOK_STATIC_CALL(HOOK, NUM), FUNC); \ + static_branch_enable(&HOOK_STATIC_CHECK(HOOK, NUM)); \ + break; \ + } + +#define add_static_hook(HOOK, FUNC) \ + do { \ + FOR_EACH_HOOK_SLOT(TRY_TO_ADD, HOOK, FUNC) \ + printk(KERN_ERR "No slot remaining to add LSM hook for "\ + #HOOK "\n"); \ + } while(0) + /** * security_add_hooks - Add a modules hooks to the hook lists. * @hooks: the hooks to add @@ -480,6 +524,12 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count, for (i = 0; i < count; i++) { hooks[i].lsm = lsm; hlist_add_tail_rcu(&hooks[i].list, hooks[i].head); + + #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ + if (&security_hook_heads.NAME == hooks[i].head) \ + add_static_hook(NAME, hooks[i].hook.NAME); + #include + #undef LSM_HOOK } /* @@ -687,6 +737,16 @@ static void __init lsm_early_task(struct task_struct *task) #include #undef LSM_HOOK + +#define TRY_TO_STATIC_CALL_INT(NUM, R, HOOK, ...) \ + if (static_branch_unlikely(&HOOK_STATIC_CHECK(HOOK, NUM))) { \ + R = static_call(HOOK_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ + if (R != 0) \ + break; \ + } + +#define TRY_TO_STATIC_CALL_VOID(NUM, HOOK, ...) \ + static_call_cond(HOOK_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); /* * Hook list operation macros. * @@ -699,22 +759,15 @@ static void __init lsm_early_task(struct task_struct *task) #define call_void_hook(FUNC, ...) \ do { \ - struct security_hook_list *P; \ - \ - hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \ - P->hook.FUNC(__VA_ARGS__); \ + FOR_EACH_HOOK_SLOT(TRY_TO_STATIC_CALL_VOID, \ + FUNC, __VA_ARGS__) \ } while (0) #define call_int_hook(FUNC, IRC, ...) ({ \ int RC = IRC; \ do { \ - struct security_hook_list *P; \ - \ - hlist_for_each_entry(P, &security_hook_heads.FUNC, list) { \ - RC = P->hook.FUNC(__VA_ARGS__); \ - if (RC != 0) \ - break; \ - } \ + FOR_EACH_HOOK_SLOT(TRY_TO_STATIC_CALL_INT, \ + RC, FUNC, __VA_ARGS__) \ } while (0); \ RC; \ })