From e002a4774d11d8c598e8c783dbadafde747415f0 Mon Sep 17 00:00:00 2001 From: Paul Renauld Date: Fri, 10 Jul 2020 10:32:33 +0200 Subject: [PATCH 1/5] create keys and add to static list --- security/security.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/security/security.c b/security/security.c index 70a7ad357bc6ab..b7cdbacc931f0d 100644 --- a/security/security.c +++ b/security/security.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) "LSM: " fmt +#ifndef DEBUG_NO_IMPORT #include #include #include @@ -28,6 +29,10 @@ #include #include #include +#include +#include +#include +#endif #define MAX_LSM_EVM_XATTR 2 @@ -464,6 +469,47 @@ 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 LSM_HOOK(RET, DEFAULT, NAME, ...) \ +noinline RET LSM_FUNC_DEFAULT(NAME)(__VA_ARGS__) \ +{ \ + return DEFAULT; \ +} +#include +#undef LSM_HOOK + +#define CREATE_STATIC(NAME, NUM) \ + DEFINE_STATIC_CALL(HOOK_STATIC_CALL(NAME, NUM), LSM_FUNC_DEFAULT(NAME));\ + DEFINE_STATIC_KEY_FALSE(HOOK_STATIC_CHECK(NAME, NUM)); + + +#define LSM_HOOK(RET, DEFAULT, NAME, ...) \ + CREATE_STATIC(NAME, 1) \ + CREATE_STATIC(NAME, 2) \ + CREATE_STATIC(NAME, 3) +#include +#undef LSM_HOOK +#undef CREATE_STATIC + +#define TRY_TO_ADD(HOOK, FUNC, NUM) \ + 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 { \ + TRY_TO_ADD(HOOK, FUNC, 1) \ + TRY_TO_ADD(HOOK, FUNC, 2) \ + TRY_TO_ADD(HOOK, FUNC, 3) \ + printk(KERN_ERR "No slot remaining to add LSM hook for " "\n"); \ + } while(0) + + /** * security_add_hooks - Add a modules hooks to the hook lists. * @hooks: the hooks to add @@ -480,6 +526,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 } /* From 7a0e6b7a13a4b282ae7e847cfbdd4112b9308c8b Mon Sep 17 00:00:00 2001 From: Paul Renauld Date: Fri, 10 Jul 2020 12:05:44 +0200 Subject: [PATCH 2/5] minimum working poc --- security/security.c | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/security/security.c b/security/security.c index b7cdbacc931f0d..a899a2bfc2a2dc 100644 --- a/security/security.c +++ b/security/security.c @@ -495,7 +495,7 @@ noinline RET LSM_FUNC_DEFAULT(NAME)(__VA_ARGS__) \ #undef CREATE_STATIC #define TRY_TO_ADD(HOOK, FUNC, NUM) \ - if (static_branch_unlikely(&HOOK_STATIC_CHECK(HOOK, NUM))) { \ + 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; \ @@ -506,7 +506,7 @@ noinline RET LSM_FUNC_DEFAULT(NAME)(__VA_ARGS__) \ TRY_TO_ADD(HOOK, FUNC, 1) \ TRY_TO_ADD(HOOK, FUNC, 2) \ TRY_TO_ADD(HOOK, FUNC, 3) \ - printk(KERN_ERR "No slot remaining to add LSM hook for " "\n"); \ + printk(KERN_ERR "No slot remaining to add LSM hook for " #HOOK "\n"); \ } while(0) @@ -526,6 +526,8 @@ 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); + // if (&security_hook_heads.file_permission == hooks[i].head) + // ADD_STATIC_HOOK(file_permission, hooks[i].hook.file_permission); #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ if (&security_hook_heads.NAME == hooks[i].head) \ @@ -739,6 +741,14 @@ static void __init lsm_early_task(struct task_struct *task) #include #undef LSM_HOOK + +#define TRY_TO_STATIC_CALL(R, HOOK, NUM, ...) \ + if (static_branch_unlikely(&HOOK_STATIC_CHECK(HOOK, NUM))) { \ + R = static_call(HOOK_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ + if (R != 0) \ + break; \ + } + /* * Hook list operation macros. * @@ -751,25 +761,32 @@ 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__); \ + static_call_cond(HOOK_STATIC_CALL(FUNC, 1))(__VA_ARGS__); \ + static_call_cond(HOOK_STATIC_CALL(FUNC, 2))(__VA_ARGS__); \ + static_call_cond(HOOK_STATIC_CALL(FUNC, 3))(__VA_ARGS__); \ } while (0) + // struct security_hook_list *P; \ + // \ + // hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \ + // P->hook.FUNC(__VA_ARGS__); \ + #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; \ - } \ + TRY_TO_STATIC_CALL(RC, FUNC, 1, __VA_ARGS__) \ + TRY_TO_STATIC_CALL(RC, FUNC, 2, __VA_ARGS__) \ + TRY_TO_STATIC_CALL(RC, FUNC, 3, __VA_ARGS__) \ } while (0); \ RC; \ }) + // 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; \ + // } \ /* Security operations */ From f990d59c827442cb6a98f5678a7c5596f4983e44 Mon Sep 17 00:00:00 2001 From: Paul Renauld Date: Mon, 13 Jul 2020 11:54:12 +0200 Subject: [PATCH 3/5] wip --- security/security.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/security/security.c b/security/security.c index a899a2bfc2a2dc..f85aa8fc9673f4 100644 --- a/security/security.c +++ b/security/security.c @@ -526,8 +526,6 @@ 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); - // if (&security_hook_heads.file_permission == hooks[i].head) - // ADD_STATIC_HOOK(file_permission, hooks[i].hook.file_permission); #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ if (&security_hook_heads.NAME == hooks[i].head) \ @@ -761,15 +759,20 @@ static void __init lsm_early_task(struct task_struct *task) #define call_void_hook(FUNC, ...) \ do { \ - static_call_cond(HOOK_STATIC_CALL(FUNC, 1))(__VA_ARGS__); \ - static_call_cond(HOOK_STATIC_CALL(FUNC, 2))(__VA_ARGS__); \ - static_call_cond(HOOK_STATIC_CALL(FUNC, 3))(__VA_ARGS__); \ + static_call_cond(HOOK_STATIC_CALL(FUNC, 1))(__VA_ARGS__); \ + static_call_cond(HOOK_STATIC_CALL(FUNC, 2))(__VA_ARGS__); \ + static_call_cond(HOOK_STATIC_CALL(FUNC, 3))(__VA_ARGS__); \ + } while (0) + + +// #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__); \ } while (0) - // struct security_hook_list *P; \ - // \ - // hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \ - // P->hook.FUNC(__VA_ARGS__); \ #define call_int_hook(FUNC, IRC, ...) ({ \ int RC = IRC; \ @@ -780,13 +783,20 @@ static void __init lsm_early_task(struct task_struct *task) } while (0); \ RC; \ }) - // 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; \ - // } \ + +// #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; \ + } \ + } while (0); \ + RC; \ +}) /* Security operations */ From ea2ba0cf772cb848a6c835d32eca148721e26c19 Mon Sep 17 00:00:00 2001 From: Paul Renauld Date: Mon, 13 Jul 2020 12:00:31 +0200 Subject: [PATCH 4/5] cleanup --- security/security.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/security/security.c b/security/security.c index f85aa8fc9673f4..f1278ce5da4fcc 100644 --- a/security/security.c +++ b/security/security.c @@ -10,7 +10,6 @@ #define pr_fmt(fmt) "LSM: " fmt -#ifndef DEBUG_NO_IMPORT #include #include #include @@ -32,7 +31,6 @@ #include #include #include -#endif #define MAX_LSM_EVM_XATTR 2 @@ -485,7 +483,6 @@ noinline RET LSM_FUNC_DEFAULT(NAME)(__VA_ARGS__) \ DEFINE_STATIC_CALL(HOOK_STATIC_CALL(NAME, NUM), LSM_FUNC_DEFAULT(NAME));\ DEFINE_STATIC_KEY_FALSE(HOOK_STATIC_CHECK(NAME, NUM)); - #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ CREATE_STATIC(NAME, 1) \ CREATE_STATIC(NAME, 2) \ @@ -509,7 +506,6 @@ noinline RET LSM_FUNC_DEFAULT(NAME)(__VA_ARGS__) \ 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 @@ -764,7 +760,6 @@ static void __init lsm_early_task(struct task_struct *task) static_call_cond(HOOK_STATIC_CALL(FUNC, 3))(__VA_ARGS__); \ } while (0) - // #define call_void_hook(FUNC, ...) \ do { \ struct security_hook_list *P; \ @@ -773,7 +768,6 @@ static void __init lsm_early_task(struct task_struct *task) P->hook.FUNC(__VA_ARGS__); \ } while (0) - #define call_int_hook(FUNC, IRC, ...) ({ \ int RC = IRC; \ do { \ From 71e7e3a5f68b17a54c1e7a6a1e720785527b880d Mon Sep 17 00:00:00 2001 From: Paul Renauld Date: Tue, 14 Jul 2020 14:35:47 +0200 Subject: [PATCH 5/5] for-loop like --- security/security.c | 78 +++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/security/security.c b/security/security.c index f1278ce5da4fcc..b674c5d50a6911 100644 --- a/security/security.c +++ b/security/security.c @@ -31,6 +31,8 @@ #include #include #include +#include + #define MAX_LSM_EVM_XATTR 2 @@ -471,39 +473,39 @@ static int lsm_append(const char *new, char **result) #define HOOK_STATIC_CALL(HOOK, NUM) static_call_##HOOK##_##NUM #define HOOK_STATIC_CHECK(HOOK, NUM) static_check_##HOOK##_##NUM -#define LSM_HOOK(RET, DEFAULT, NAME, ...) \ -noinline RET LSM_FUNC_DEFAULT(NAME)(__VA_ARGS__) \ -{ \ - return DEFAULT; \ -} -#include -#undef LSM_HOOK +#define FOR_EACH_HOOK_SLOT(M, ...) \ + M(1, __VA_ARGS__) \ + M(2, __VA_ARGS__) \ + M(3, __VA_ARGS__) -#define CREATE_STATIC(NAME, NUM) \ - DEFINE_STATIC_CALL(HOOK_STATIC_CALL(NAME, NUM), LSM_FUNC_DEFAULT(NAME));\ +#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)); -#define LSM_HOOK(RET, DEFAULT, NAME, ...) \ - CREATE_STATIC(NAME, 1) \ - CREATE_STATIC(NAME, 2) \ - CREATE_STATIC(NAME, 3) +// 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(HOOK, FUNC, NUM) \ +#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) \ +#define add_static_hook(HOOK, FUNC) \ do { \ - TRY_TO_ADD(HOOK, FUNC, 1) \ - TRY_TO_ADD(HOOK, FUNC, 2) \ - TRY_TO_ADD(HOOK, FUNC, 3) \ - printk(KERN_ERR "No slot remaining to add LSM hook for " #HOOK "\n"); \ + FOR_EACH_HOOK_SLOT(TRY_TO_ADD, HOOK, FUNC) \ + printk(KERN_ERR "No slot remaining to add LSM hook for "\ + #HOOK "\n"); \ } while(0) /** @@ -525,7 +527,7 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count, #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ if (&security_hook_heads.NAME == hooks[i].head) \ - ADD_STATIC_HOOK(NAME, hooks[i].hook.NAME); + add_static_hook(NAME, hooks[i].hook.NAME); #include #undef LSM_HOOK } @@ -736,13 +738,15 @@ static void __init lsm_early_task(struct task_struct *task) #undef LSM_HOOK -#define TRY_TO_STATIC_CALL(R, HOOK, NUM, ...) \ +#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. * @@ -755,39 +759,15 @@ static void __init lsm_early_task(struct task_struct *task) #define call_void_hook(FUNC, ...) \ do { \ - static_call_cond(HOOK_STATIC_CALL(FUNC, 1))(__VA_ARGS__); \ - static_call_cond(HOOK_STATIC_CALL(FUNC, 2))(__VA_ARGS__); \ - static_call_cond(HOOK_STATIC_CALL(FUNC, 3))(__VA_ARGS__); \ - } while (0) - -// #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 { \ - TRY_TO_STATIC_CALL(RC, FUNC, 1, __VA_ARGS__) \ - TRY_TO_STATIC_CALL(RC, FUNC, 2, __VA_ARGS__) \ - TRY_TO_STATIC_CALL(RC, FUNC, 3, __VA_ARGS__) \ - } while (0); \ - RC; \ -}) - -// #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; \ })