[PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls

KP Singh kpsingh at kernel.org
Sat Jun 17 15:09:36 UTC 2023


On Fri, Jun 16, 2023 at 3:05 AM Casey Schaufler <casey at schaufler-ca.com> wrote:
>
> On 6/15/2023 5:04 PM, KP Singh wrote:
> > LSM hooks are currently invoked from a linked list as indirect calls
> > which are invoked using retpolines as a mitigation for speculative
> > attacks (Branch History / Target injection) and add extra overhead which
> > is especially bad in kernel hot paths:
> >
> > security_file_ioctl:
> >    0xffffffff814f0320 <+0>:   endbr64
> >    0xffffffff814f0324 <+4>:   push   %rbp
> >    0xffffffff814f0325 <+5>:   push   %r15
> >    0xffffffff814f0327 <+7>:   push   %r14
> >    0xffffffff814f0329 <+9>:   push   %rbx
> >    0xffffffff814f032a <+10>:  mov    %rdx,%rbx
> >    0xffffffff814f032d <+13>:  mov    %esi,%ebp
> >    0xffffffff814f032f <+15>:  mov    %rdi,%r14
> >    0xffffffff814f0332 <+18>:  mov    $0xffffffff834a7030,%r15
> >    0xffffffff814f0339 <+25>:  mov    (%r15),%r15
> >    0xffffffff814f033c <+28>:  test   %r15,%r15
> >    0xffffffff814f033f <+31>:  je     0xffffffff814f0358 <security_file_ioctl+56>
> >    0xffffffff814f0341 <+33>:  mov    0x18(%r15),%r11
> >    0xffffffff814f0345 <+37>:  mov    %r14,%rdi
> >    0xffffffff814f0348 <+40>:  mov    %ebp,%esi
> >    0xffffffff814f034a <+42>:  mov    %rbx,%rdx
> >
> >    0xffffffff814f034d <+45>:  call   0xffffffff81f742e0 <__x86_indirect_thunk_array+352>
> >                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >
> >     Indirect calls that use retpolines leading to overhead, not just due
> >     to extra instruction but also branch misses.
> >
> >    0xffffffff814f0352 <+50>:  test   %eax,%eax
> >    0xffffffff814f0354 <+52>:  je     0xffffffff814f0339 <security_file_ioctl+25>
> >    0xffffffff814f0356 <+54>:  jmp    0xffffffff814f035a <security_file_ioctl+58>
> >    0xffffffff814f0358 <+56>:  xor    %eax,%eax
> >    0xffffffff814f035a <+58>:  pop    %rbx
> >    0xffffffff814f035b <+59>:  pop    %r14
> >    0xffffffff814f035d <+61>:  pop    %r15
> >    0xffffffff814f035f <+63>:  pop    %rbp
> >    0xffffffff814f0360 <+64>:  jmp    0xffffffff81f747c4 <__x86_return_thunk>
> >
> > The indirect calls are not really needed as one knows the addresses of
> > enabled LSM callbacks at boot time and only the order can possibly
> > change at boot time with the lsm= kernel command line parameter.
> >
> > An array of static calls is defined per LSM hook and the static calls
> > are updated at boot time once the order has been determined.
> >
> > A static key guards whether an LSM static call is enabled or not,
> > without this static key, for LSM hooks that return an int, the presence
> > of the hook that returns a default value can create side-effects which
> > has resulted in bugs [1].
> >
> > With the hook now exposed as a static call, one can see that the
> > retpolines are no longer there and the LSM callbacks are invoked
> > directly:
> >
> > security_file_ioctl:
> >    0xffffffff818f0ca0 <+0>:   endbr64
> >    0xffffffff818f0ca4 <+4>:   nopl   0x0(%rax,%rax,1)
> >    0xffffffff818f0ca9 <+9>:   push   %rbp
> >    0xffffffff818f0caa <+10>:  push   %r14
> >    0xffffffff818f0cac <+12>:  push   %rbx
> >    0xffffffff818f0cad <+13>:  mov    %rdx,%rbx
> >    0xffffffff818f0cb0 <+16>:  mov    %esi,%ebp
> >    0xffffffff818f0cb2 <+18>:  mov    %rdi,%r14
> >    0xffffffff818f0cb5 <+21>:  jmp    0xffffffff818f0cc7 <security_file_ioctl+39>
> >                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >    Static key enabled for SELinux
> >
> >    0xffffffff818f0cb7 <+23>:  jmp    0xffffffff818f0cde <security_file_ioctl+62>
> >                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >
> >    Static key enabled for BPF LSM. This is something that is changed to
> >    default to false to avoid the existing side effect issues of BPF LSM
> >    [1] in a subsequent patch.
> >
> >    0xffffffff818f0cb9 <+25>:  xor    %eax,%eax
> >    0xffffffff818f0cbb <+27>:  xchg   %ax,%ax
> >    0xffffffff818f0cbd <+29>:  pop    %rbx
> >    0xffffffff818f0cbe <+30>:  pop    %r14
> >    0xffffffff818f0cc0 <+32>:  pop    %rbp
> >    0xffffffff818f0cc1 <+33>:  cs jmp 0xffffffff82c00000 <__x86_return_thunk>
> >    0xffffffff818f0cc7 <+39>:  endbr64
> >    0xffffffff818f0ccb <+43>:  mov    %r14,%rdi
> >    0xffffffff818f0cce <+46>:  mov    %ebp,%esi
> >    0xffffffff818f0cd0 <+48>:  mov    %rbx,%rdx
> >    0xffffffff818f0cd3 <+51>:  call   0xffffffff81903230 <selinux_file_ioctl>
> >                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >    Direct call to SELinux.
> >
> >    0xffffffff818f0cd8 <+56>:  test   %eax,%eax
> >    0xffffffff818f0cda <+58>:  jne    0xffffffff818f0cbd <security_file_ioctl+29>
> >    0xffffffff818f0cdc <+60>:  jmp    0xffffffff818f0cb7 <security_file_ioctl+23>
> >    0xffffffff818f0cde <+62>:  endbr64
> >    0xffffffff818f0ce2 <+66>:  mov    %r14,%rdi
> >    0xffffffff818f0ce5 <+69>:  mov    %ebp,%esi
> >    0xffffffff818f0ce7 <+71>:  mov    %rbx,%rdx
> >    0xffffffff818f0cea <+74>:  call   0xffffffff8141e220 <bpf_lsm_file_ioctl>
> >                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >    Direct call to BPF LSM.
> >
> >    0xffffffff818f0cef <+79>:  test   %eax,%eax
> >    0xffffffff818f0cf1 <+81>:  jne    0xffffffff818f0cbd <security_file_ioctl+29>
> >    0xffffffff818f0cf3 <+83>:  jmp    0xffffffff818f0cb9 <security_file_ioctl+25>
> >    0xffffffff818f0cf5 <+85>:  endbr64
> >    0xffffffff818f0cf9 <+89>:  mov    %r14,%rdi
> >    0xffffffff818f0cfc <+92>:  mov    %ebp,%esi
> >    0xffffffff818f0cfe <+94>:  mov    %rbx,%rdx
> >    0xffffffff818f0d01 <+97>:  pop    %rbx
> >    0xffffffff818f0d02 <+98>:  pop    %r14
> >    0xffffffff818f0d04 <+100>: pop    %rbp
> >    0xffffffff818f0d05 <+101>: ret
> >    0xffffffff818f0d06 <+102>: int3
> >    0xffffffff818f0d07 <+103>: int3
> >    0xffffffff818f0d08 <+104>: int3
> >    0xffffffff818f0d09 <+105>: int3
> >
> > While this patch uses static_branch_unlikely indicating that an LSM hook
> > is likely to be not present, a subsequent makes it configurable. In most
> > cases this is still a better choice as even when an LSM with one hook is
> > added, empty slots are created for all LSM hooks (especially when many
> > LSMs that do not initialize most hooks are present on the system).
>
> You could avoid this (I think - some of the macro processing is gnarley)
> by keeping the existing list creation in place. You could then create

The arrays / slots need to be created at compile time, the list
creation happens dynamically / at runtime.

> your arrays based on the number of entries for each hook. The original

The only other option is source code parsing to look at the
LSM_HOOK_INIT and then generating a per hook count, but that gets very
ugly and fragile to implement. Unfortunately, there is no way to avoid
the gnarly macros.

- KP

> list could then be discarded. No empty slots.
>
> On the other hand, I may be missing something obvious.
>
> >
> > There are some hooks that don't use the call_int_hook and
> > call_void_hook. These hooks are updated to use a new macro called
> > security_for_each_hook where the lsm_callback is directly invoked as an
> > indirect call. Currently, there are no performance sensitive hooks that
> > use the security_for_each_hook macro. However, if, some performance
> > sensitive hooks are discovered, these can be updated to use static calls
> > with loop unrolling as well using a custom macro.
> >
> > [1] https://lore.kernel.org/linux-security-module/20220609234601.2026362-1-kpsingh@kernel.org/
> >
> > Signed-off-by: KP Singh <kpsingh at kernel.org>
> > ---
> >  include/linux/lsm_hooks.h |  70 ++++++++++++--
> >  security/security.c       | 193 +++++++++++++++++++++++++-------------
> >  2 files changed, 188 insertions(+), 75 deletions(-)
> >
> > diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> > index ab2b2fafa4a4..069da0fa617a 100644
> > --- a/include/linux/lsm_hooks.h
> > +++ b/include/linux/lsm_hooks.h
> > @@ -28,26 +28,77 @@
> >  #include <linux/security.h>
> >  #include <linux/init.h>
> >  #include <linux/rculist.h>
> > +#include <linux/static_call.h>
> > +#include <linux/unroll.h>
> > +#include <linux/jump_label.h>
> > +#include <linux/lsm_count.h>
> > +
> > +#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
> > +
> > +/*
> > + * Identifier for the LSM static calls.
> > + * HOOK is an LSM hook as defined in linux/lsm_hookdefs.h
> > + * IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT
> > + */
> > +#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX
> > +
> > +/*
> > + * Call the macro M for each LSM hook MAX_LSM_COUNT times.
> > + */
> > +#define LSM_LOOP_UNROLL(M, ...)              \
> > +do {                                         \
> > +     UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)   \
> > +} while (0)
> > +
> > +#define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)
> >
> >  union security_list_options {
> >       #define LSM_HOOK(RET, DEFAULT, NAME, ...) RET (*NAME)(__VA_ARGS__);
> >       #include "lsm_hook_defs.h"
> >       #undef LSM_HOOK
> > +     void *lsm_callback;
> >  };
> >
> > -struct security_hook_heads {
> > -     #define LSM_HOOK(RET, DEFAULT, NAME, ...) struct hlist_head NAME;
> > -     #include "lsm_hook_defs.h"
> > +/*
> > + * @key: static call key as defined by STATIC_CALL_KEY
> > + * @trampoline: static call trampoline as defined by STATIC_CALL_TRAMP
> > + * @hl: The security_hook_list as initialized by the owning LSM.
> > + * @active: Enabled when the static call has an LSM hook associated.
> > + */
> > +struct lsm_static_call {
> > +     struct static_call_key *key;
> > +     void *trampoline;
> > +     struct security_hook_list *hl;
> > +     /* this needs to be true or false based on what the key defaults to */
> > +     struct static_key_false *active;
> > +};
> > +
> > +/*
> > + * Table of the static calls for each LSM hook.
> > + * Once the LSMs are initialized, their callbacks will be copied to these
> > + * tables such that the calls are filled backwards (from last to first).
> > + * This way, we can jump directly to the first used static call, and execute
> > + * all of them after. This essentially makes the entry point
> > + * dynamic to adapt the number of static calls to the number of callbacks.
> > + */
> > +struct lsm_static_calls_table {
> > +     #define LSM_HOOK(RET, DEFAULT, NAME, ...) \
> > +             struct lsm_static_call NAME[MAX_LSM_COUNT];
> > +     #include <linux/lsm_hook_defs.h>
> >       #undef LSM_HOOK
> >  } __randomize_layout;
> >
> >  /*
> >   * Security module hook list structure.
> >   * For use with generic list macros for common operations.
> > + *
> > + * struct security_hook_list - Contents of a cacheable, mappable object.
> > + * @scalls: The beginning of the array of static calls assigned to this hook.
> > + * @hook: The callback for the hook.
> > + * @lsm: The name of the lsm that owns this hook.
> >   */
> >  struct security_hook_list {
> > -     struct hlist_node               list;
> > -     struct hlist_head               *head;
> > +     struct lsm_static_call  *scalls;
> >       union security_list_options     hook;
> >       const char                      *lsm;
> >  } __randomize_layout;
> > @@ -77,10 +128,12 @@ struct lsm_blob_sizes {
> >   * care of the common case and reduces the amount of
> >   * text involved.
> >   */
> > -#define LSM_HOOK_INIT(HEAD, HOOK) \
> > -     { .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }
> > +#define LSM_HOOK_INIT(NAME, CALLBACK)                        \
> > +     {                                               \
> > +             .scalls = static_calls_table.NAME,      \
> > +             .hook = { .NAME = CALLBACK }            \
> > +     }
> >
> > -extern struct security_hook_heads security_hook_heads;
> >  extern char *lsm_names;
> >
> >  extern void security_add_hooks(struct security_hook_list *hooks, int count,
> > @@ -118,5 +171,6 @@ extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
> >               __aligned(sizeof(unsigned long))
> >
> >  extern int lsm_inode_alloc(struct inode *inode);
> > +extern struct lsm_static_calls_table static_calls_table __ro_after_init;
> >
> >  #endif /* ! __LINUX_LSM_HOOKS_H */
> > diff --git a/security/security.c b/security/security.c
> > index b720424ca37d..9ae7c0ec5cac 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -30,6 +30,8 @@
> >  #include <linux/string.h>
> >  #include <linux/msg.h>
> >  #include <net/flow.h>
> > +#include <linux/static_call.h>
> > +#include <linux/jump_label.h>
> >
> >  #define MAX_LSM_EVM_XATTR    2
> >
> > @@ -75,7 +77,6 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
> >       [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
> >  };
> >
> > -struct security_hook_heads security_hook_heads __ro_after_init;
> >  static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
> >
> >  static struct kmem_cache *lsm_file_cache;
> > @@ -94,6 +95,43 @@ static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
> >  static __initdata struct lsm_info **ordered_lsms;
> >  static __initdata struct lsm_info *exclusive;
> >
> > +/*
> > + * Define static calls and static keys for each LSM hook.
> > + */
> > +
> > +#define DEFINE_LSM_STATIC_CALL(NUM, NAME, RET, ...)                  \
> > +     DEFINE_STATIC_CALL_NULL(LSM_STATIC_CALL(NAME, NUM),             \
> > +                             *((RET(*)(__VA_ARGS__))NULL));          \
> > +     DEFINE_STATIC_KEY_FALSE(SECURITY_HOOK_ACTIVE_KEY(NAME, NUM));
> > +
> > +#define LSM_HOOK(RET, DEFAULT, NAME, ...)                            \
> > +     LSM_DEFINE_UNROLL(DEFINE_LSM_STATIC_CALL, NAME, RET, __VA_ARGS__)
> > +#include <linux/lsm_hook_defs.h>
> > +#undef LSM_HOOK
> > +#undef DEFINE_LSM_STATIC_CALL
> > +
> > +/*
> > + * Initialise a table of static calls for each LSM hook.
> > + * DEFINE_STATIC_CALL_NULL invocation above generates a key (STATIC_CALL_KEY)
> > + * and a trampoline (STATIC_CALL_TRAMP) which are used to call
> > + * __static_call_update when updating the static call.
> > + */
> > +struct lsm_static_calls_table static_calls_table __ro_after_init = {
> > +#define INIT_LSM_STATIC_CALL(NUM, NAME)                                      \
> > +     (struct lsm_static_call) {                                      \
> > +             .key = &STATIC_CALL_KEY(LSM_STATIC_CALL(NAME, NUM)),    \
> > +             .trampoline = &STATIC_CALL_TRAMP(LSM_STATIC_CALL(NAME, NUM)),\
> > +             .active = &SECURITY_HOOK_ACTIVE_KEY(NAME, NUM),         \
> > +     },
> > +#define LSM_HOOK(RET, DEFAULT, NAME, ...)                            \
> > +     .NAME = {                                                       \
> > +             LSM_DEFINE_UNROLL(INIT_LSM_STATIC_CALL, NAME)           \
> > +     },
> > +#include <linux/lsm_hook_defs.h>
> > +#undef LSM_HOOK
> > +#undef INIT_LSM_STATIC_CALL
> > +};
> > +
> >  static __initdata bool debug;
> >  #define init_debug(...)                                              \
> >       do {                                                    \
> > @@ -154,7 +192,7 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> >       if (exists_ordered_lsm(lsm))
> >               return;
> >
> > -     if (WARN(last_lsm == LSM_COUNT, "%s: out of LSM slots!?\n", from))
> > +     if (WARN(last_lsm == LSM_COUNT, "%s: out of LSM static calls!?\n", from))
> >               return;
> >
> >       /* Enable this LSM, if it is not already set. */
> > @@ -325,6 +363,25 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> >       kfree(sep);
> >  }
> >
> > +static void __init lsm_static_call_init(struct security_hook_list *hl)
> > +{
> > +     struct lsm_static_call *scall = hl->scalls;
> > +     int i;
> > +
> > +     for (i = 0; i < MAX_LSM_COUNT; i++) {
> > +             /* Update the first static call that is not used yet */
> > +             if (!scall->hl) {
> > +                     __static_call_update(scall->key, scall->trampoline,
> > +                                          hl->hook.lsm_callback);
> > +                     scall->hl = hl;
> > +                     static_branch_enable(scall->active);
> > +                     return;
> > +             }
> > +             scall++;
> > +     }
> > +     panic("%s - Ran out of static slots.\n", __func__);
> > +}
> > +
> >  static void __init lsm_early_cred(struct cred *cred);
> >  static void __init lsm_early_task(struct task_struct *task);
> >
> > @@ -403,11 +460,6 @@ int __init early_security_init(void)
> >  {
> >       struct lsm_info *lsm;
> >
> > -#define LSM_HOOK(RET, DEFAULT, NAME, ...) \
> > -     INIT_HLIST_HEAD(&security_hook_heads.NAME);
> > -#include "linux/lsm_hook_defs.h"
> > -#undef LSM_HOOK
> > -
> >       for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> >               if (!lsm->enabled)
> >                       lsm->enabled = &lsm_enabled_true;
> > @@ -523,7 +575,7 @@ 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);
> > +             lsm_static_call_init(&hooks[i]);
> >       }
> >
> >       /*
> > @@ -761,29 +813,41 @@ static int lsm_superblock_alloc(struct super_block *sb)
> >   * call_int_hook:
> >   *   This is a hook that returns a value.
> >   */
> > +#define __CALL_STATIC_VOID(NUM, HOOK, ...)                                \
> > +do {                                                                      \
> > +     if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) {    \
> > +             static_call(LSM_STATIC_CALL(HOOK, NUM))(__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__);              \
> > +#define call_void_hook(FUNC, ...)                                 \
> > +     do {                                                      \
> > +             LSM_LOOP_UNROLL(__CALL_STATIC_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;                          \
> > -             }                                               \
> > -     } while (0);                                            \
> > -     RC;                                                     \
> > +#define __CALL_STATIC_INT(NUM, R, HOOK, LABEL, ...)                       \
> > +do {                                                                      \
> > +     if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) {  \
> > +             R = static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__);    \
> > +             if (R != 0)                                                  \
> > +                     goto LABEL;                                          \
> > +     }                                                                    \
> > +} while (0);
> > +
> > +#define call_int_hook(FUNC, IRC, ...)                                        \
> > +({                                                                   \
> > +     __label__ out;                                                  \
> > +     int RC = IRC;                                                   \
> > +     LSM_LOOP_UNROLL(__CALL_STATIC_INT, RC, FUNC, out, __VA_ARGS__); \
> > +out:                                                                 \
> > +     RC;                                                             \
> >  })
> >
> > +#define security_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))
> > +
>
> As this is a macro that is only used in this file I would much
> prefer you not use the "security_" prefix. I think for_each_hook()
> or even lsm_for_each_hook() would be preferable.
>
> >  /* Security operations */
> >
> >  /**
> > @@ -1019,7 +1083,7 @@ int security_settime64(const struct timespec64 *ts, const struct timezone *tz)
> >   */
> >  int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
> >  {
> > -     struct security_hook_list *hp;
> > +     struct lsm_static_call *scall;
> >       int cap_sys_admin = 1;
> >       int rc;
> >
> > @@ -1030,8 +1094,8 @@ 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.
> >        */
> > -     hlist_for_each_entry(hp, &security_hook_heads.vm_enough_memory, list) {
> > -             rc = hp->hook.vm_enough_memory(mm, pages);
> > +     security_for_each_hook(scall, vm_enough_memory) {
> > +             rc = scall->hl->hook.vm_enough_memory(mm, pages);
> >               if (rc <= 0) {
> >                       cap_sys_admin = 0;
> >                       break;
> > @@ -1169,13 +1233,12 @@ 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 security_hook_list *hp;
> > +     struct lsm_static_call *scall;
> >       int trc;
> >       int rc = -ENOPARAM;
> >
> > -     hlist_for_each_entry(hp, &security_hook_heads.fs_context_parse_param,
> > -                          list) {
> > -             trc = hp->hook.fs_context_parse_param(fc, param);
> > +     security_for_each_hook(scall, fs_context_parse_param) {
> > +             trc = scall->hl->hook.fs_context_parse_param(fc, param);
> >               if (trc == 0)
> >                       rc = 0;
> >               else if (trc != -ENOPARAM)
> > @@ -1538,19 +1601,19 @@ int security_dentry_init_security(struct dentry *dentry, int mode,
> >                                 const char **xattr_name, void **ctx,
> >                                 u32 *ctxlen)
> >  {
> > -     struct security_hook_list *hp;
> > +     struct lsm_static_call *scall;
> >       int rc;
> >
> >       /*
> >        * Only one module will provide a security context.
> >        */
> > -     hlist_for_each_entry(hp, &security_hook_heads.dentry_init_security,
> > -                          list) {
> > -             rc = hp->hook.dentry_init_security(dentry, mode, name,
> > +     security_for_each_hook(scall, dentry_init_security) {
> > +             rc = scall->hl->hook.dentry_init_security(dentry, mode, name,
> >                                                  xattr_name, ctx, ctxlen);
> >               if (rc != LSM_RET_DEFAULT(dentry_init_security))
> >                       return rc;
> >       }
> > +
> >       return LSM_RET_DEFAULT(dentry_init_security);
> >  }
> >  EXPORT_SYMBOL(security_dentry_init_security);
> > @@ -2366,7 +2429,7 @@ int security_inode_getsecurity(struct mnt_idmap *idmap,
> >                              struct inode *inode, const char *name,
> >                              void **buffer, bool alloc)
> >  {
> > -     struct security_hook_list *hp;
> > +     struct lsm_static_call *scall;
> >       int rc;
> >
> >       if (unlikely(IS_PRIVATE(inode)))
> > @@ -2374,9 +2437,8 @@ int security_inode_getsecurity(struct mnt_idmap *idmap,
> >       /*
> >        * Only one module will provide an attribute with a given name.
> >        */
> > -     hlist_for_each_entry(hp, &security_hook_heads.inode_getsecurity, list) {
> > -             rc = hp->hook.inode_getsecurity(idmap, inode, name, buffer,
> > -                                             alloc);
> > +     security_for_each_hook(scall, inode_getsecurity) {
> > +             rc = scall->hl->hook.inode_getsecurity(idmap, inode, name, buffer, alloc);
> >               if (rc != LSM_RET_DEFAULT(inode_getsecurity))
> >                       return rc;
> >       }
> > @@ -2401,7 +2463,7 @@ int security_inode_getsecurity(struct mnt_idmap *idmap,
> >  int security_inode_setsecurity(struct inode *inode, const char *name,
> >                              const void *value, size_t size, int flags)
> >  {
> > -     struct security_hook_list *hp;
> > +     struct lsm_static_call *scall;
> >       int rc;
> >
> >       if (unlikely(IS_PRIVATE(inode)))
> > @@ -2409,9 +2471,8 @@ int security_inode_setsecurity(struct inode *inode, const char *name,
> >       /*
> >        * Only one module will provide an attribute with a given name.
> >        */
> > -     hlist_for_each_entry(hp, &security_hook_heads.inode_setsecurity, list) {
> > -             rc = hp->hook.inode_setsecurity(inode, name, value, size,
> > -                                             flags);
> > +     security_for_each_hook(scall, inode_setsecurity) {
> > +             rc = scall->hl->hook.inode_setsecurity(inode, name, value, size, flags);
> >               if (rc != LSM_RET_DEFAULT(inode_setsecurity))
> >                       return rc;
> >       }
> > @@ -2485,7 +2546,7 @@ EXPORT_SYMBOL(security_inode_copy_up);
> >   */
> >  int security_inode_copy_up_xattr(const char *name)
> >  {
> > -     struct security_hook_list *hp;
> > +     struct lsm_static_call *scall;
> >       int rc;
> >
> >       /*
> > @@ -2493,9 +2554,8 @@ int security_inode_copy_up_xattr(const char *name)
> >        * xattr), -EOPNOTSUPP if it does not know anything about the xattr or
> >        * any other error code in case of an error.
> >        */
> > -     hlist_for_each_entry(hp,
> > -                          &security_hook_heads.inode_copy_up_xattr, list) {
> > -             rc = hp->hook.inode_copy_up_xattr(name);
> > +     security_for_each_hook(scall, inode_copy_up_xattr) {
> > +             rc = scall->hl->hook.inode_copy_up_xattr(name);
> >               if (rc != LSM_RET_DEFAULT(inode_copy_up_xattr))
> >                       return rc;
> >       }
> > @@ -3375,10 +3435,10 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
> >  {
> >       int thisrc;
> >       int rc = LSM_RET_DEFAULT(task_prctl);
> > -     struct security_hook_list *hp;
> > +     struct lsm_static_call *scall;
> >
> > -     hlist_for_each_entry(hp, &security_hook_heads.task_prctl, list) {
> > -             thisrc = hp->hook.task_prctl(option, arg2, arg3, arg4, arg5);
> > +     security_for_each_hook(scall, task_prctl) {
> > +             thisrc = scall->hl->hook.task_prctl(option, arg2, arg3, arg4, arg5);
> >               if (thisrc != LSM_RET_DEFAULT(task_prctl)) {
> >                       rc = thisrc;
> >                       if (thisrc != 0)
> > @@ -3775,12 +3835,12 @@ EXPORT_SYMBOL(security_d_instantiate);
> >  int security_getprocattr(struct task_struct *p, const char *lsm,
> >                        const char *name, char **value)
> >  {
> > -     struct security_hook_list *hp;
> > +     struct lsm_static_call *scall;
> >
> > -     hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
> > -             if (lsm != NULL && strcmp(lsm, hp->lsm))
> > +     security_for_each_hook(scall, getprocattr) {
> > +             if (lsm != NULL && strcmp(lsm, scall->hl->lsm))
> >                       continue;
> > -             return hp->hook.getprocattr(p, name, value);
> > +             return scall->hl->hook.getprocattr(p, name, value);
> >       }
> >       return LSM_RET_DEFAULT(getprocattr);
> >  }
> > @@ -3800,12 +3860,12 @@ int security_getprocattr(struct task_struct *p, const char *lsm,
> >  int security_setprocattr(const char *lsm, const char *name, void *value,
> >                        size_t size)
> >  {
> > -     struct security_hook_list *hp;
> > +     struct lsm_static_call *scall;
> >
> > -     hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
> > -             if (lsm != NULL && strcmp(lsm, hp->lsm))
> > +     security_for_each_hook(scall, setprocattr) {
> > +             if (lsm != NULL && strcmp(lsm, scall->hl->lsm))
> >                       continue;
> > -             return hp->hook.setprocattr(name, value, size);
> > +             return scall->hl->hook.setprocattr(name, value, size);
> >       }
> >       return LSM_RET_DEFAULT(setprocattr);
> >  }
> > @@ -3857,15 +3917,15 @@ EXPORT_SYMBOL(security_ismaclabel);
> >   */
> >  int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> >  {
> > -     struct security_hook_list *hp;
> > +     struct lsm_static_call *scall;
> >       int rc;
> >
> >       /*
> >        * Currently, only one LSM can implement secid_to_secctx (i.e this
> >        * LSM hook is not "stackable").
> >        */
> > -     hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) {
> > -             rc = hp->hook.secid_to_secctx(secid, secdata, seclen);
> > +     security_for_each_hook(scall, secid_to_secctx) {
> > +             rc = scall->hl->hook.secid_to_secctx(secid, secdata, seclen);
> >               if (rc != LSM_RET_DEFAULT(secid_to_secctx))
> >                       return rc;
> >       }
> > @@ -4901,7 +4961,7 @@ int security_xfrm_state_pol_flow_match(struct xfrm_state *x,
> >                                      struct xfrm_policy *xp,
> >                                      const struct flowi_common *flic)
> >  {
> > -     struct security_hook_list *hp;
> > +     struct lsm_static_call *scall;
> >       int rc = LSM_RET_DEFAULT(xfrm_state_pol_flow_match);
> >
> >       /*
> > @@ -4913,9 +4973,8 @@ int security_xfrm_state_pol_flow_match(struct xfrm_state *x,
> >        * For speed optimization, we explicitly break the loop rather than
> >        * using the macro
> >        */
> > -     hlist_for_each_entry(hp, &security_hook_heads.xfrm_state_pol_flow_match,
> > -                          list) {
> > -             rc = hp->hook.xfrm_state_pol_flow_match(x, xp, flic);
> > +     security_for_each_hook(scall, xfrm_state_pol_flow_match) {
> > +             rc = scall->hl->hook.xfrm_state_pol_flow_match(x, xp, flic);
> >               break;
> >       }
> >       return rc;



More information about the Linux-security-module-archive mailing list