* [PATCH v2 0/5] Reduce overhead of LSMs with static calls
@ 2023-06-16 0:04 KP Singh
2023-06-16 0:04 ` [PATCH v2 1/5] kernel: Add helper macros for loop unrolling KP Singh
` (4 more replies)
0 siblings, 5 replies; 21+ messages in thread
From: KP Singh @ 2023-06-16 0:04 UTC (permalink / raw)
To: linux-security-module, bpf
Cc: paul, keescook, casey, song, daniel, ast, jannh
# Background
LSM hooks (callbacks) are currently invoked as indirect function calls. These
callbacks are registered into a linked list at boot time as the order of the
LSMs can be configured on the kernel command line with the "lsm=" command line
parameter.
Indirect function calls have a high overhead due to retpoline mitigation for
various speculative execution attacks.
Retpolines remain relevant even with newer generation CPUs as recently
discovered speculative attacks, like Spectre BHB need Retpolines to mitigate
against branch history injection and still need to be used in combination with
newer mitigation features like eIBRS.
This overhead is especially significant for the "bpf" LSM which allows the user
to implement LSM functionality with eBPF program. In order to facilitate this
the "bpf" LSM provides a default callback for all LSM hooks. When enabled,
the "bpf" LSM incurs an unnecessary / avoidable indirect call. This is
especially bad in OS hot paths (e.g. in the networking stack).
This overhead prevents the adoption of bpf LSM on performance critical
systems, and also, in general, slows down all LSMs.
Since we know the address of the enabled LSM callbacks at compile time and only
the order is determined at boot time, the LSM framework can allocate static
calls for each of the possible LSM callbacks and these calls can be updated once
the order is determined at boot.
This series is a respin of the RFC proposed by Paul Renauld (renauld@google.com)
and Brendan Jackman (jackmanb@google.com) [1]
# Performance improvement
With this patch-set some syscalls with lots of LSM hooks in their path
benefitted at an average of ~3% and I/O and Pipe based system calls benefitting
the most.
Here are the results of the relevant Unixbench system benchmarks with BPF LSM
and SELinux enabled with default policies enabled with and without these
patches.
Benchmark Delta(%): (+ is better)
===============================================================================
Execl Throughput +1.9356
File Write 1024 bufsize 2000 maxblocks +6.5953
Pipe Throughput +9.5499
Pipe-based Context Switching +3.0209
Process Creation +2.3246
Shell Scripts (1 concurrent) +1.4975
System Call Overhead +2.7815
System Benchmarks Index Score (Partial Only): +3.4859
In the best case, some syscalls like eventfd_create benefitted to about ~10%.
The full analysis can be viewed at https://kpsingh.ch/lsm-perf
[1] https://lore.kernel.org/linux-security-module/20200820164753.3256899-1-jackmanb@chromium.org/
# BPF LSM Side effects
Patch 4 of the series also addresses the issues with the side effects of the
default value return values of the BPF LSM callbacks and also removes the
overheads associated with them making it deployable at hyperscale.
# v1 -> v2 (based on linux-next, next-20230614)
- Incorporated suggestions from Kees
- Changed the way MAX_LSMs are counted from a binary based generator to a clever header.
- Add CONFIG_SECURITY_HOOK_LIKELY to configure the likelihood of LSM hooks.
(Note on avaialability: I won't be able to reply / rev the series for the next couple of weeks)
KP Singh (5):
kernel: Add helper macros for loop unrolling
security: Count the LSMs enabled at compile time
security: Replace indirect LSM hook calls with static calls
bpf: Only enable BPF LSM hooks when an LSM program is attached
security: Add CONFIG_SECURITY_HOOK_LIKELY
include/linux/bpf.h | 1 +
include/linux/bpf_lsm.h | 5 +
include/linux/lsm_count.h | 131 +++++++++++++++++++++++++
include/linux/lsm_hooks.h | 81 ++++++++++++++--
include/linux/unroll.h | 36 +++++++
kernel/bpf/trampoline.c | 29 +++++-
security/Kconfig | 11 +++
security/bpf/hooks.c | 25 ++++-
security/security.c | 197 +++++++++++++++++++++++++-------------
9 files changed, 438 insertions(+), 78 deletions(-)
create mode 100644 include/linux/lsm_count.h
create mode 100644 include/linux/unroll.h
--
2.41.0.162.gfafddb0af9-goog
^ permalink raw reply [flat|nested] 21+ messages in thread* [PATCH v2 1/5] kernel: Add helper macros for loop unrolling 2023-06-16 0:04 [PATCH v2 0/5] Reduce overhead of LSMs with static calls KP Singh @ 2023-06-16 0:04 ` KP Singh 2023-06-16 0:04 ` [PATCH v2 2/5] security: Count the LSMs enabled at compile time KP Singh ` (3 subsequent siblings) 4 siblings, 0 replies; 21+ messages in thread From: KP Singh @ 2023-06-16 0:04 UTC (permalink / raw) To: linux-security-module, bpf Cc: paul, keescook, casey, song, daniel, ast, jannh, KP Singh This helps in easily initializing blocks of code (e.g. static calls and keys). UNROLL(N, MACRO, __VA_ARGS__) calls MACRO N times with the first argument as the index of the iteration. This allows string pasting to create unique tokens for variable names, function calls etc. As an example: #include <linux/unroll.h> #define MACRO(N, a, b) \ int add_##N(int a, int b) \ { \ return a + b + N; \ } UNROLL(2, MACRO, x, y) expands to: int add_0(int x, int y) { return x + y + 0; } int add_1(int x, int y) { return x + y + 1; } Signed-off-by: KP Singh <kpsingh@kernel.org> --- include/linux/unroll.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 include/linux/unroll.h diff --git a/include/linux/unroll.h b/include/linux/unroll.h new file mode 100644 index 000000000000..5c5deac49d43 --- /dev/null +++ b/include/linux/unroll.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (C) 2023 Google LLC. + */ + +#ifndef __UNROLL_H +#define __UNROLL_H + +#include <linux/kernel.h> + +#define UNROLL(N, MACRO, args...) CONCATENATE(__UNROLL_, N)(MACRO, args) + +#define __UNROLL_0(MACRO, args...) +#define __UNROLL_1(MACRO, args...) __UNROLL_0(MACRO, args) MACRO(0, args) +#define __UNROLL_2(MACRO, args...) __UNROLL_1(MACRO, args) MACRO(1, args) +#define __UNROLL_3(MACRO, args...) __UNROLL_2(MACRO, args) MACRO(2, args) +#define __UNROLL_4(MACRO, args...) __UNROLL_3(MACRO, args) MACRO(3, args) +#define __UNROLL_5(MACRO, args...) __UNROLL_4(MACRO, args) MACRO(4, args) +#define __UNROLL_6(MACRO, args...) __UNROLL_5(MACRO, args) MACRO(5, args) +#define __UNROLL_7(MACRO, args...) __UNROLL_6(MACRO, args) MACRO(6, args) +#define __UNROLL_8(MACRO, args...) __UNROLL_7(MACRO, args) MACRO(7, args) +#define __UNROLL_9(MACRO, args...) __UNROLL_8(MACRO, args) MACRO(8, args) +#define __UNROLL_10(MACRO, args...) __UNROLL_9(MACRO, args) MACRO(9, args) +#define __UNROLL_11(MACRO, args...) __UNROLL_10(MACRO, args) MACRO(10, args) +#define __UNROLL_12(MACRO, args...) __UNROLL_11(MACRO, args) MACRO(11, args) +#define __UNROLL_13(MACRO, args...) __UNROLL_12(MACRO, args) MACRO(12, args) +#define __UNROLL_14(MACRO, args...) __UNROLL_13(MACRO, args) MACRO(13, args) +#define __UNROLL_15(MACRO, args...) __UNROLL_14(MACRO, args) MACRO(14, args) +#define __UNROLL_16(MACRO, args...) __UNROLL_15(MACRO, args) MACRO(15, args) +#define __UNROLL_17(MACRO, args...) __UNROLL_16(MACRO, args) MACRO(16, args) +#define __UNROLL_18(MACRO, args...) __UNROLL_17(MACRO, args) MACRO(17, args) +#define __UNROLL_19(MACRO, args...) __UNROLL_18(MACRO, args) MACRO(18, args) +#define __UNROLL_20(MACRO, args...) __UNROLL_19(MACRO, args) MACRO(19, args) + +#endif /* __UNROLL_H */ -- 2.41.0.162.gfafddb0af9-goog ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 2/5] security: Count the LSMs enabled at compile time 2023-06-16 0:04 [PATCH v2 0/5] Reduce overhead of LSMs with static calls KP Singh 2023-06-16 0:04 ` [PATCH v2 1/5] kernel: Add helper macros for loop unrolling KP Singh @ 2023-06-16 0:04 ` KP Singh 2023-06-16 0:38 ` Casey Schaufler 2023-06-16 0:04 ` [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls KP Singh ` (2 subsequent siblings) 4 siblings, 1 reply; 21+ messages in thread From: KP Singh @ 2023-06-16 0:04 UTC (permalink / raw) To: linux-security-module, bpf Cc: paul, keescook, casey, song, daniel, ast, jannh, Kui-Feng Lee, KP Singh These macros are a clever trick to determine a count of the number of LSMs that are enabled in the config to ascertain the maximum number of static calls that need to be configured per LSM hook. Without this one would need to generate static calls for (number of possible LSMs * number of LSM hooks) which ends up being quite wasteful especially when some LSMs are not compiled into the kernel. Suggested-by: Kui-Feng Lee <sinquersw@gmail.com> Signed-off-by: KP Singh <kpsingh@kernel.org> --- include/linux/lsm_count.h | 131 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 include/linux/lsm_count.h diff --git a/include/linux/lsm_count.h b/include/linux/lsm_count.h new file mode 100644 index 000000000000..818f62ffa723 --- /dev/null +++ b/include/linux/lsm_count.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (C) 2023 Google LLC. + */ + +#ifndef __LINUX_LSM_COUNT_H +#define __LINUX_LSM_COUNT_H + +#include <linux/kconfig.h> + +/* + * Macros to count the number of LSMs enabled in the kernel at compile time. + */ + +#define __LSM_COUNT_15(x, y...) 15 +#define __LSM_COUNT_14(x, y...) 14 +#define __LSM_COUNT_13(x, y...) 13 +#define __LSM_COUNT_12(x, y...) 12 +#define __LSM_COUNT_11(x, y...) 11 +#define __LSM_COUNT_10(x, y...) 10 +#define __LSM_COUNT_9(x, y...) 9 +#define __LSM_COUNT_8(x, y...) 8 +#define __LSM_COUNT_7(x, y...) 7 +#define __LSM_COUNT_6(x, y...) 6 +#define __LSM_COUNT_5(x, y...) 5 +#define __LSM_COUNT_4(x, y...) 4 +#define __LSM_COUNT_3(x, y...) 3 +#define __LSM_COUNT_2(x, y...) 2 +#define __LSM_COUNT_1(x, y...) 1 +#define __LSM_COUNT_0(x, y...) 0 + +#define __LSM_COUNT1_15(x, y...) __LSM_COUNT ## x ## _15(y) +#define __LSM_COUNT1_14(x, y...) __LSM_COUNT ## x ## _14(y) +#define __LSM_COUNT1_13(x, y...) __LSM_COUNT ## x ## _13(y) +#define __LSM_COUNT1_12(x, y...) __LSM_COUNT ## x ## _12(y) +#define __LSM_COUNT1_10(x, y...) __LSM_COUNT ## x ## _11(y) +#define __LSM_COUNT1_9(x, y...) __LSM_COUNT ## x ## _10(y) +#define __LSM_COUNT1_8(x, y...) __LSM_COUNT ## x ## _9(y) +#define __LSM_COUNT1_7(x, y...) __LSM_COUNT ## x ## _8(y) +#define __LSM_COUNT1_6(x, y...) __LSM_COUNT ## x ## _7(y) +#define __LSM_COUNT1_5(x, y...) __LSM_COUNT ## x ## _6(y) +#define __LSM_COUNT1_4(x, y...) __LSM_COUNT ## x ## _5(y) +#define __LSM_COUNT1_3(x, y...) __LSM_COUNT ## x ## _4(y) +#define __LSM_COUNT1_2(x, y...) __LSM_COUNT ## x ## _3(y) +#define __LSM_COUNT1_1(x, y...) __LSM_COUNT ## x ## _2(y) +#define __LSM_COUNT1_0(x, y...) __LSM_COUNT ## x ## _1(y) +#define __LSM_COUNT(x, y...) __LSM_COUNT ## x ## _0(y) + +#define __LSM_COUNT_EXPAND(x...) __LSM_COUNT(x) + +#if IS_ENABLED(CONFIG_SECURITY) +#define CAPABILITIES_ENABLED 1, +#else +#define CAPABILITIES_ENABLED +#endif + +#if IS_ENABLED(CONFIG_SECURITY_SELINUX) +#define SELINUX_ENABLED 1, +#else +#define SELINUX_ENABLED +#endif + +#if IS_ENABLED(CONFIG_SECURITY_SMACK) +#define SMACK_ENABLED 1, +#else +#define SMACK_ENABLED +#endif + +#if IS_ENABLED(CONFIG_SECURITY_APPARMOR) +#define APPARMOR_ENABLED 1, +#else +#define APPARMOR_ENABLED +#endif + +#if IS_ENABLED(CONFIG_SECURITY_TOMOYO) +#define TOMOYO_ENABLED 1, +#else +#define TOMOYO_ENABLED +#endif + +#if IS_ENABLED(CONFIG_SECURITY_YAMA) +#define YAMA_ENABLED 1, +#else +#define YAMA_ENABLED +#endif + +#if IS_ENABLED(CONFIG_SECURITY_LOADPIN) +#define LOADPIN_ENABLED 1, +#else +#define LOADPIN_ENABLED +#endif + +#if IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) +#define LOCKDOWN_ENABLED 1, +#else +#define LOCKDOWN_ENABLED +#endif + +#if IS_ENABLED(CONFIG_BPF_LSM) +#define BPF_LSM_ENABLED 1, +#else +#define BPF_LSM_ENABLED +#endif + +#if IS_ENABLED(CONFIG_BPF_LSM) +#define BPF_LSM_ENABLED 1, +#else +#define BPF_LSM_ENABLED +#endif + +#if IS_ENABLED(CONFIG_SECURITY_LANDLOCK) +#define LANDLOCK_ENABLED 1, +#else +#define LANDLOCK_ENABLED +#endif + +#define MAX_LSM_COUNT \ + __LSM_COUNT_EXPAND( \ + CAPABILITIES_ENABLED \ + SELINUX_ENABLED \ + SMACK_ENABLED \ + APPARMOR_ENABLED \ + TOMOYO_ENABLED \ + YAMA_ENABLED \ + LOADPIN_ENABLED \ + LOCKDOWN_ENABLED \ + BPF_LSM_ENABLED \ + LANDLOCK_ENABLED) + +#endif /* __LINUX_LSM_COUNT_H */ -- 2.41.0.162.gfafddb0af9-goog ^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/5] security: Count the LSMs enabled at compile time 2023-06-16 0:04 ` [PATCH v2 2/5] security: Count the LSMs enabled at compile time KP Singh @ 2023-06-16 0:38 ` Casey Schaufler 2023-06-16 22:27 ` Andrii Nakryiko 0 siblings, 1 reply; 21+ messages in thread From: Casey Schaufler @ 2023-06-16 0:38 UTC (permalink / raw) To: KP Singh, linux-security-module, bpf Cc: paul, keescook, song, daniel, ast, jannh, Kui-Feng Lee, Casey Schaufler On 6/15/2023 5:04 PM, KP Singh wrote: > These macros are a clever trick to determine a count of the number of > LSMs that are enabled in the config to ascertain the maximum number of > static calls that need to be configured per LSM hook. > > Without this one would need to generate static calls for (number of > possible LSMs * number of LSM hooks) which ends up being quite wasteful > especially when some LSMs are not compiled into the kernel. > > Suggested-by: Kui-Feng Lee <sinquersw@gmail.com> > Signed-off-by: KP Singh <kpsingh@kernel.org> > --- > include/linux/lsm_count.h | 131 ++++++++++++++++++++++++++++++++++++++ > 1 file changed, 131 insertions(+) > create mode 100644 include/linux/lsm_count.h > > diff --git a/include/linux/lsm_count.h b/include/linux/lsm_count.h > new file mode 100644 > index 000000000000..818f62ffa723 > --- /dev/null > +++ b/include/linux/lsm_count.h > @@ -0,0 +1,131 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > + > +/* > + * Copyright (C) 2023 Google LLC. > + */ > + > +#ifndef __LINUX_LSM_COUNT_H > +#define __LINUX_LSM_COUNT_H > + > +#include <linux/kconfig.h> > + > +/* > + * Macros to count the number of LSMs enabled in the kernel at compile time. > + */ > + > +#define __LSM_COUNT_15(x, y...) 15 > +#define __LSM_COUNT_14(x, y...) 14 > +#define __LSM_COUNT_13(x, y...) 13 > +#define __LSM_COUNT_12(x, y...) 12 > +#define __LSM_COUNT_11(x, y...) 11 > +#define __LSM_COUNT_10(x, y...) 10 > +#define __LSM_COUNT_9(x, y...) 9 > +#define __LSM_COUNT_8(x, y...) 8 > +#define __LSM_COUNT_7(x, y...) 7 > +#define __LSM_COUNT_6(x, y...) 6 > +#define __LSM_COUNT_5(x, y...) 5 > +#define __LSM_COUNT_4(x, y...) 4 > +#define __LSM_COUNT_3(x, y...) 3 > +#define __LSM_COUNT_2(x, y...) 2 > +#define __LSM_COUNT_1(x, y...) 1 > +#define __LSM_COUNT_0(x, y...) 0 > + > +#define __LSM_COUNT1_15(x, y...) __LSM_COUNT ## x ## _15(y) > +#define __LSM_COUNT1_14(x, y...) __LSM_COUNT ## x ## _14(y) > +#define __LSM_COUNT1_13(x, y...) __LSM_COUNT ## x ## _13(y) > +#define __LSM_COUNT1_12(x, y...) __LSM_COUNT ## x ## _12(y) > +#define __LSM_COUNT1_10(x, y...) __LSM_COUNT ## x ## _11(y) > +#define __LSM_COUNT1_9(x, y...) __LSM_COUNT ## x ## _10(y) > +#define __LSM_COUNT1_8(x, y...) __LSM_COUNT ## x ## _9(y) > +#define __LSM_COUNT1_7(x, y...) __LSM_COUNT ## x ## _8(y) > +#define __LSM_COUNT1_6(x, y...) __LSM_COUNT ## x ## _7(y) > +#define __LSM_COUNT1_5(x, y...) __LSM_COUNT ## x ## _6(y) > +#define __LSM_COUNT1_4(x, y...) __LSM_COUNT ## x ## _5(y) > +#define __LSM_COUNT1_3(x, y...) __LSM_COUNT ## x ## _4(y) > +#define __LSM_COUNT1_2(x, y...) __LSM_COUNT ## x ## _3(y) > +#define __LSM_COUNT1_1(x, y...) __LSM_COUNT ## x ## _2(y) > +#define __LSM_COUNT1_0(x, y...) __LSM_COUNT ## x ## _1(y) > +#define __LSM_COUNT(x, y...) __LSM_COUNT ## x ## _0(y) > + > +#define __LSM_COUNT_EXPAND(x...) __LSM_COUNT(x) > + > +#if IS_ENABLED(CONFIG_SECURITY) > +#define CAPABILITIES_ENABLED 1, > +#else > +#define CAPABILITIES_ENABLED > +#endif > + > +#if IS_ENABLED(CONFIG_SECURITY_SELINUX) > +#define SELINUX_ENABLED 1, > +#else > +#define SELINUX_ENABLED > +#endif > + > +#if IS_ENABLED(CONFIG_SECURITY_SMACK) > +#define SMACK_ENABLED 1, > +#else > +#define SMACK_ENABLED > +#endif > + > +#if IS_ENABLED(CONFIG_SECURITY_APPARMOR) > +#define APPARMOR_ENABLED 1, > +#else > +#define APPARMOR_ENABLED > +#endif > + > +#if IS_ENABLED(CONFIG_SECURITY_TOMOYO) > +#define TOMOYO_ENABLED 1, > +#else > +#define TOMOYO_ENABLED > +#endif > + > +#if IS_ENABLED(CONFIG_SECURITY_YAMA) > +#define YAMA_ENABLED 1, > +#else > +#define YAMA_ENABLED > +#endif > + > +#if IS_ENABLED(CONFIG_SECURITY_LOADPIN) > +#define LOADPIN_ENABLED 1, > +#else > +#define LOADPIN_ENABLED > +#endif > + > +#if IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) > +#define LOCKDOWN_ENABLED 1, > +#else > +#define LOCKDOWN_ENABLED > +#endif > + > +#if IS_ENABLED(CONFIG_BPF_LSM) > +#define BPF_LSM_ENABLED 1, > +#else > +#define BPF_LSM_ENABLED > +#endif > + > +#if IS_ENABLED(CONFIG_BPF_LSM) > +#define BPF_LSM_ENABLED 1, > +#else > +#define BPF_LSM_ENABLED > +#endif > + > +#if IS_ENABLED(CONFIG_SECURITY_LANDLOCK) > +#define LANDLOCK_ENABLED 1, > +#else > +#define LANDLOCK_ENABLED > +#endif > + > +#define MAX_LSM_COUNT \ > + __LSM_COUNT_EXPAND( \ > + CAPABILITIES_ENABLED \ > + SELINUX_ENABLED \ > + SMACK_ENABLED \ > + APPARMOR_ENABLED \ > + TOMOYO_ENABLED \ > + YAMA_ENABLED \ > + LOADPIN_ENABLED \ > + LOCKDOWN_ENABLED \ > + BPF_LSM_ENABLED \ > + LANDLOCK_ENABLED) > + Wouldn't the following be simpler? It's from my LSM syscall patchset. It certainly takes up fewer lines and would be easier to maintain than the set of macros you've proposed. +#define LSM_COUNT ( \ + (IS_ENABLED(CONFIG_SECURITY) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_SECURITY_SELINUX) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_SECURITY_SMACK) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_SECURITY_TOMOYO) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_IMA) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_SECURITY_APPARMOR) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_SECURITY_YAMA) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_SECURITY_LOADPIN) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_SECURITY_SAFESETID) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0)) > +#endif /* __LINUX_LSM_COUNT_H */ ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/5] security: Count the LSMs enabled at compile time 2023-06-16 0:38 ` Casey Schaufler @ 2023-06-16 22:27 ` Andrii Nakryiko 2023-09-16 0:54 ` KP Singh 0 siblings, 1 reply; 21+ messages in thread From: Andrii Nakryiko @ 2023-06-16 22:27 UTC (permalink / raw) To: Casey Schaufler Cc: KP Singh, linux-security-module, bpf, paul, keescook, song, daniel, ast, jannh, Kui-Feng Lee On Thu, Jun 15, 2023 at 5:38 PM Casey Schaufler <casey@schaufler-ca.com> wrote: > > On 6/15/2023 5:04 PM, KP Singh wrote: > > These macros are a clever trick to determine a count of the number of > > LSMs that are enabled in the config to ascertain the maximum number of > > static calls that need to be configured per LSM hook. > > > > Without this one would need to generate static calls for (number of > > possible LSMs * number of LSM hooks) which ends up being quite wasteful > > especially when some LSMs are not compiled into the kernel. > > > > Suggested-by: Kui-Feng Lee <sinquersw@gmail.com> > > Signed-off-by: KP Singh <kpsingh@kernel.org> > > --- > > include/linux/lsm_count.h | 131 ++++++++++++++++++++++++++++++++++++++ > > 1 file changed, 131 insertions(+) > > create mode 100644 include/linux/lsm_count.h > > > > diff --git a/include/linux/lsm_count.h b/include/linux/lsm_count.h > > new file mode 100644 > > index 000000000000..818f62ffa723 > > --- /dev/null > > +++ b/include/linux/lsm_count.h > > @@ -0,0 +1,131 @@ > > +/* SPDX-License-Identifier: GPL-2.0 */ > > + > > +/* > > + * Copyright (C) 2023 Google LLC. > > + */ > > + > > +#ifndef __LINUX_LSM_COUNT_H > > +#define __LINUX_LSM_COUNT_H > > + > > +#include <linux/kconfig.h> > > + > > +/* > > + * Macros to count the number of LSMs enabled in the kernel at compile time. > > + */ > > + > > +#define __LSM_COUNT_15(x, y...) 15 > > +#define __LSM_COUNT_14(x, y...) 14 > > +#define __LSM_COUNT_13(x, y...) 13 > > +#define __LSM_COUNT_12(x, y...) 12 > > +#define __LSM_COUNT_11(x, y...) 11 > > +#define __LSM_COUNT_10(x, y...) 10 > > +#define __LSM_COUNT_9(x, y...) 9 > > +#define __LSM_COUNT_8(x, y...) 8 > > +#define __LSM_COUNT_7(x, y...) 7 > > +#define __LSM_COUNT_6(x, y...) 6 > > +#define __LSM_COUNT_5(x, y...) 5 > > +#define __LSM_COUNT_4(x, y...) 4 > > +#define __LSM_COUNT_3(x, y...) 3 > > +#define __LSM_COUNT_2(x, y...) 2 > > +#define __LSM_COUNT_1(x, y...) 1 > > +#define __LSM_COUNT_0(x, y...) 0 > > + > > +#define __LSM_COUNT1_15(x, y...) __LSM_COUNT ## x ## _15(y) > > +#define __LSM_COUNT1_14(x, y...) __LSM_COUNT ## x ## _14(y) > > +#define __LSM_COUNT1_13(x, y...) __LSM_COUNT ## x ## _13(y) > > +#define __LSM_COUNT1_12(x, y...) __LSM_COUNT ## x ## _12(y) > > +#define __LSM_COUNT1_10(x, y...) __LSM_COUNT ## x ## _11(y) > > +#define __LSM_COUNT1_9(x, y...) __LSM_COUNT ## x ## _10(y) > > +#define __LSM_COUNT1_8(x, y...) __LSM_COUNT ## x ## _9(y) > > +#define __LSM_COUNT1_7(x, y...) __LSM_COUNT ## x ## _8(y) > > +#define __LSM_COUNT1_6(x, y...) __LSM_COUNT ## x ## _7(y) > > +#define __LSM_COUNT1_5(x, y...) __LSM_COUNT ## x ## _6(y) > > +#define __LSM_COUNT1_4(x, y...) __LSM_COUNT ## x ## _5(y) > > +#define __LSM_COUNT1_3(x, y...) __LSM_COUNT ## x ## _4(y) > > +#define __LSM_COUNT1_2(x, y...) __LSM_COUNT ## x ## _3(y) > > +#define __LSM_COUNT1_1(x, y...) __LSM_COUNT ## x ## _2(y) > > +#define __LSM_COUNT1_0(x, y...) __LSM_COUNT ## x ## _1(y) > > +#define __LSM_COUNT(x, y...) __LSM_COUNT ## x ## _0(y) > > + > > +#define __LSM_COUNT_EXPAND(x...) __LSM_COUNT(x) > > + > > +#if IS_ENABLED(CONFIG_SECURITY) > > +#define CAPABILITIES_ENABLED 1, > > +#else > > +#define CAPABILITIES_ENABLED > > +#endif > > + > > +#if IS_ENABLED(CONFIG_SECURITY_SELINUX) > > +#define SELINUX_ENABLED 1, > > +#else > > +#define SELINUX_ENABLED > > +#endif > > + > > +#if IS_ENABLED(CONFIG_SECURITY_SMACK) > > +#define SMACK_ENABLED 1, > > +#else > > +#define SMACK_ENABLED > > +#endif > > + > > +#if IS_ENABLED(CONFIG_SECURITY_APPARMOR) > > +#define APPARMOR_ENABLED 1, > > +#else > > +#define APPARMOR_ENABLED > > +#endif > > + > > +#if IS_ENABLED(CONFIG_SECURITY_TOMOYO) > > +#define TOMOYO_ENABLED 1, > > +#else > > +#define TOMOYO_ENABLED > > +#endif > > + > > +#if IS_ENABLED(CONFIG_SECURITY_YAMA) > > +#define YAMA_ENABLED 1, > > +#else > > +#define YAMA_ENABLED > > +#endif > > + > > +#if IS_ENABLED(CONFIG_SECURITY_LOADPIN) > > +#define LOADPIN_ENABLED 1, > > +#else > > +#define LOADPIN_ENABLED > > +#endif > > + > > +#if IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) > > +#define LOCKDOWN_ENABLED 1, > > +#else > > +#define LOCKDOWN_ENABLED > > +#endif > > + > > +#if IS_ENABLED(CONFIG_BPF_LSM) > > +#define BPF_LSM_ENABLED 1, > > +#else > > +#define BPF_LSM_ENABLED > > +#endif > > + > > +#if IS_ENABLED(CONFIG_BPF_LSM) > > +#define BPF_LSM_ENABLED 1, > > +#else > > +#define BPF_LSM_ENABLED > > +#endif duplicate that redefined BPF_LSM_ENABLED unnecessarily > > + > > +#if IS_ENABLED(CONFIG_SECURITY_LANDLOCK) > > +#define LANDLOCK_ENABLED 1, > > +#else > > +#define LANDLOCK_ENABLED > > +#endif > > + > > +#define MAX_LSM_COUNT \ > > + __LSM_COUNT_EXPAND( \ > > + CAPABILITIES_ENABLED \ > > + SELINUX_ENABLED \ > > + SMACK_ENABLED \ > > + APPARMOR_ENABLED \ > > + TOMOYO_ENABLED \ > > + YAMA_ENABLED \ > > + LOADPIN_ENABLED \ > > + LOCKDOWN_ENABLED \ > > + BPF_LSM_ENABLED \ > > + LANDLOCK_ENABLED) > > + > > Wouldn't the following be simpler? It's from my LSM syscall patchset. Of course it would be, but unfortunately it doesn't work with the UNROLL() macro. This MAX_LSM_COUNT has to evaluate a compile-time integer *literal* (not any sort of expression), so that UNROLL(N,...) can do its magic. KP, this __LSM_COUNT_EXPAND() is actually doing exactly what already existing COUNT_ARGS() macro from linux/kernel.h does, which is implemented way more succinctly: #define __COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _n, X...) _n #define COUNT_ARGS(X...) __COUNT_ARGS(, ##X, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) The only problem is that: #define ___COUNT_ARGS(args...) COUNT_ARGS(args) #define MAX_LSM_COUNT \ ___COUNT_ARGS( \ CAPABILITIES_ENABLED \ SELINUX_ENABLED \ SMACK_ENABLED \ APPARMOR_ENABLED \ TOMOYO_ENABLED \ YAMA_ENABLED \ LOADPIN_ENABLED \ LOCKDOWN_ENABLED \ BPF_LSM_ENABLED \ LANDLOCK_ENABLED) overcounts by one, because of that trailing command within each XXX_ENABLED definition. But still, instead of a multi-line __LSM_COUNT{,1}_N set of macros, it might be better to use the COUNT_ARGS trick, but just account for those trailing commas? E.g., maybe just do a COUNT_COMMAS() macro which will adjust all the return values by 1 down, except when there is no comma (still 0). It's pretty minor in the grand scheme of things, but just something for you to be aware of. > It certainly takes up fewer lines and would be easier to maintain > than the set of macros you've proposed. > > +#define LSM_COUNT ( \ > + (IS_ENABLED(CONFIG_SECURITY) ? 1 : 0) + \ > + (IS_ENABLED(CONFIG_SECURITY_SELINUX) ? 1 : 0) + \ > + (IS_ENABLED(CONFIG_SECURITY_SMACK) ? 1 : 0) + \ > + (IS_ENABLED(CONFIG_SECURITY_TOMOYO) ? 1 : 0) + \ > + (IS_ENABLED(CONFIG_IMA) ? 1 : 0) + \ > + (IS_ENABLED(CONFIG_SECURITY_APPARMOR) ? 1 : 0) + \ > + (IS_ENABLED(CONFIG_SECURITY_YAMA) ? 1 : 0) + \ > + (IS_ENABLED(CONFIG_SECURITY_LOADPIN) ? 1 : 0) + \ > + (IS_ENABLED(CONFIG_SECURITY_SAFESETID) ? 1 : 0) + \ > + (IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \ > + (IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \ > + (IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0)) > > > > +#endif /* __LINUX_LSM_COUNT_H */ > ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/5] security: Count the LSMs enabled at compile time 2023-06-16 22:27 ` Andrii Nakryiko @ 2023-09-16 0:54 ` KP Singh 0 siblings, 0 replies; 21+ messages in thread From: KP Singh @ 2023-09-16 0:54 UTC (permalink / raw) To: Andrii Nakryiko Cc: Casey Schaufler, linux-security-module, bpf, paul, keescook, song, daniel, ast, jannh, Kui-Feng Lee On Sat, Jun 17, 2023 at 12:27 AM Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote: > > On Thu, Jun 15, 2023 at 5:38 PM Casey Schaufler <casey@schaufler-ca.com> wrote: > > > > On 6/15/2023 5:04 PM, KP Singh wrote: > > > These macros are a clever trick to determine a count of the number of > > > LSMs that are enabled in the config to ascertain the maximum number of > > > static calls that need to be configured per LSM hook. > > > > > > Without this one would need to generate static calls for (number of > > > possible LSMs * number of LSM hooks) which ends up being quite wasteful > > > especially when some LSMs are not compiled into the kernel. > > > > > > Suggested-by: Kui-Feng Lee <sinquersw@gmail.com> > > > Signed-off-by: KP Singh <kpsingh@kernel.org> > > > --- > > > include/linux/lsm_count.h | 131 ++++++++++++++++++++++++++++++++++++++ > > > 1 file changed, 131 insertions(+) > > > create mode 100644 include/linux/lsm_count.h > > > > > > diff --git a/include/linux/lsm_count.h b/include/linux/lsm_count.h > > > new file mode 100644 > > > index 000000000000..818f62ffa723 > > > --- /dev/null > > > +++ b/include/linux/lsm_count.h > > > @@ -0,0 +1,131 @@ > > > +/* SPDX-License-Identifier: GPL-2.0 */ > > > + > > > +/* > > > + * Copyright (C) 2023 Google LLC. > > > + */ > > > + > > > +#ifndef __LINUX_LSM_COUNT_H > > > +#define __LINUX_LSM_COUNT_H > > > + > > > +#include <linux/kconfig.h> > > > + > > > +/* > > > + * Macros to count the number of LSMs enabled in the kernel at compile time. > > > + */ > > > + > > > +#define __LSM_COUNT_15(x, y...) 15 > > > +#define __LSM_COUNT_14(x, y...) 14 > > > +#define __LSM_COUNT_13(x, y...) 13 > > > +#define __LSM_COUNT_12(x, y...) 12 > > > +#define __LSM_COUNT_11(x, y...) 11 > > > +#define __LSM_COUNT_10(x, y...) 10 > > > +#define __LSM_COUNT_9(x, y...) 9 > > > +#define __LSM_COUNT_8(x, y...) 8 > > > +#define __LSM_COUNT_7(x, y...) 7 > > > +#define __LSM_COUNT_6(x, y...) 6 > > > +#define __LSM_COUNT_5(x, y...) 5 > > > +#define __LSM_COUNT_4(x, y...) 4 > > > +#define __LSM_COUNT_3(x, y...) 3 > > > +#define __LSM_COUNT_2(x, y...) 2 > > > +#define __LSM_COUNT_1(x, y...) 1 > > > +#define __LSM_COUNT_0(x, y...) 0 > > > + > > > +#define __LSM_COUNT1_15(x, y...) __LSM_COUNT ## x ## _15(y) > > > +#define __LSM_COUNT1_14(x, y...) __LSM_COUNT ## x ## _14(y) > > > +#define __LSM_COUNT1_13(x, y...) __LSM_COUNT ## x ## _13(y) > > > +#define __LSM_COUNT1_12(x, y...) __LSM_COUNT ## x ## _12(y) > > > +#define __LSM_COUNT1_10(x, y...) __LSM_COUNT ## x ## _11(y) > > > +#define __LSM_COUNT1_9(x, y...) __LSM_COUNT ## x ## _10(y) > > > +#define __LSM_COUNT1_8(x, y...) __LSM_COUNT ## x ## _9(y) > > > +#define __LSM_COUNT1_7(x, y...) __LSM_COUNT ## x ## _8(y) > > > +#define __LSM_COUNT1_6(x, y...) __LSM_COUNT ## x ## _7(y) > > > +#define __LSM_COUNT1_5(x, y...) __LSM_COUNT ## x ## _6(y) > > > +#define __LSM_COUNT1_4(x, y...) __LSM_COUNT ## x ## _5(y) > > > +#define __LSM_COUNT1_3(x, y...) __LSM_COUNT ## x ## _4(y) > > > +#define __LSM_COUNT1_2(x, y...) __LSM_COUNT ## x ## _3(y) > > > +#define __LSM_COUNT1_1(x, y...) __LSM_COUNT ## x ## _2(y) > > > +#define __LSM_COUNT1_0(x, y...) __LSM_COUNT ## x ## _1(y) > > > +#define __LSM_COUNT(x, y...) __LSM_COUNT ## x ## _0(y) > > > + > > > +#define __LSM_COUNT_EXPAND(x...) __LSM_COUNT(x) > > > + > > > +#if IS_ENABLED(CONFIG_SECURITY) > > > +#define CAPABILITIES_ENABLED 1, > > > +#else > > > +#define CAPABILITIES_ENABLED > > > +#endif > > > + > > > +#if IS_ENABLED(CONFIG_SECURITY_SELINUX) > > > +#define SELINUX_ENABLED 1, > > > +#else > > > +#define SELINUX_ENABLED > > > +#endif > > > + > > > +#if IS_ENABLED(CONFIG_SECURITY_SMACK) > > > +#define SMACK_ENABLED 1, > > > +#else > > > +#define SMACK_ENABLED > > > +#endif > > > + > > > +#if IS_ENABLED(CONFIG_SECURITY_APPARMOR) > > > +#define APPARMOR_ENABLED 1, > > > +#else > > > +#define APPARMOR_ENABLED > > > +#endif > > > + > > > +#if IS_ENABLED(CONFIG_SECURITY_TOMOYO) > > > +#define TOMOYO_ENABLED 1, > > > +#else > > > +#define TOMOYO_ENABLED > > > +#endif > > > + > > > +#if IS_ENABLED(CONFIG_SECURITY_YAMA) > > > +#define YAMA_ENABLED 1, > > > +#else > > > +#define YAMA_ENABLED > > > +#endif > > > + > > > +#if IS_ENABLED(CONFIG_SECURITY_LOADPIN) > > > +#define LOADPIN_ENABLED 1, > > > +#else > > > +#define LOADPIN_ENABLED > > > +#endif > > > + > > > +#if IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) > > > +#define LOCKDOWN_ENABLED 1, > > > +#else > > > +#define LOCKDOWN_ENABLED > > > +#endif > > > + > > > +#if IS_ENABLED(CONFIG_BPF_LSM) > > > +#define BPF_LSM_ENABLED 1, > > > +#else > > > +#define BPF_LSM_ENABLED > > > +#endif > > > + > > > +#if IS_ENABLED(CONFIG_BPF_LSM) > > > +#define BPF_LSM_ENABLED 1, > > > +#else > > > +#define BPF_LSM_ENABLED > > > +#endif > > duplicate that redefined BPF_LSM_ENABLED unnecessarily > > > > + > > > +#if IS_ENABLED(CONFIG_SECURITY_LANDLOCK) > > > +#define LANDLOCK_ENABLED 1, > > > +#else > > > +#define LANDLOCK_ENABLED > > > +#endif > > > + > > > +#define MAX_LSM_COUNT \ > > > + __LSM_COUNT_EXPAND( \ > > > + CAPABILITIES_ENABLED \ > > > + SELINUX_ENABLED \ > > > + SMACK_ENABLED \ > > > + APPARMOR_ENABLED \ > > > + TOMOYO_ENABLED \ > > > + YAMA_ENABLED \ > > > + LOADPIN_ENABLED \ > > > + LOCKDOWN_ENABLED \ > > > + BPF_LSM_ENABLED \ > > > + LANDLOCK_ENABLED) > > > + > > > > Wouldn't the following be simpler? It's from my LSM syscall patchset. > > Of course it would be, but unfortunately it doesn't work with the > UNROLL() macro. This MAX_LSM_COUNT has to evaluate a compile-time > integer *literal* (not any sort of expression), so that UNROLL(N,...) > can do its magic. > > > KP, this __LSM_COUNT_EXPAND() is actually doing exactly what already > existing COUNT_ARGS() macro from linux/kernel.h does, which is > implemented way more succinctly: > > #define __COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, > _12, _n, X...) _n > #define COUNT_ARGS(X...) __COUNT_ARGS(, ##X, 12, 11, 10, 9, 8, 7, 6, > 5, 4, 3, 2, 1, 0) > > > The only problem is that: > > #define ___COUNT_ARGS(args...) COUNT_ARGS(args) > #define MAX_LSM_COUNT \ > ___COUNT_ARGS( \ > CAPABILITIES_ENABLED \ > SELINUX_ENABLED \ > SMACK_ENABLED \ > APPARMOR_ENABLED \ > TOMOYO_ENABLED \ > YAMA_ENABLED \ > LOADPIN_ENABLED \ > LOCKDOWN_ENABLED \ > BPF_LSM_ENABLED \ > LANDLOCK_ENABLED) > > overcounts by one, because of that trailing command within each > XXX_ENABLED definition. > > > But still, instead of a multi-line __LSM_COUNT{,1}_N set of macros, it > might be better to use the COUNT_ARGS trick, but just account for > those trailing commas? E.g., maybe just do a COUNT_COMMAS() macro > which will adjust all the return values by 1 down, except when there > is no comma (still 0). > > It's pretty minor in the grand scheme of things, but just something > for you to be aware of. I am back and revving this up again (after a hiatus due to health stuff and then ramping back at work). Apologies for the radio silence here. I agree, Also if you notice CAPABILITIES_ENABLED is kinda bogus, and CONFIG_SECURITY is used as a proxy, overcounting by 1 is actually what I need. So, thanks, this makes it much simpler. ^^ (I realized I had replied the above to Andrii and not replied back to the list). > > > > It certainly takes up fewer lines and would be easier to maintain > > than the set of macros you've proposed. > > > > +#define LSM_COUNT ( \ > > + (IS_ENABLED(CONFIG_SECURITY) ? 1 : 0) + \ > > + (IS_ENABLED(CONFIG_SECURITY_SELINUX) ? 1 : 0) + \ > > + (IS_ENABLED(CONFIG_SECURITY_SMACK) ? 1 : 0) + \ > > + (IS_ENABLED(CONFIG_SECURITY_TOMOYO) ? 1 : 0) + \ > > + (IS_ENABLED(CONFIG_IMA) ? 1 : 0) + \ > > + (IS_ENABLED(CONFIG_SECURITY_APPARMOR) ? 1 : 0) + \ > > + (IS_ENABLED(CONFIG_SECURITY_YAMA) ? 1 : 0) + \ > > + (IS_ENABLED(CONFIG_SECURITY_LOADPIN) ? 1 : 0) + \ > > + (IS_ENABLED(CONFIG_SECURITY_SAFESETID) ? 1 : 0) + \ > > + (IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \ > > + (IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \ > > + (IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0)) > > > > > > > +#endif /* __LINUX_LSM_COUNT_H */ > > ^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls 2023-06-16 0:04 [PATCH v2 0/5] Reduce overhead of LSMs with static calls KP Singh 2023-06-16 0:04 ` [PATCH v2 1/5] kernel: Add helper macros for loop unrolling KP Singh 2023-06-16 0:04 ` [PATCH v2 2/5] security: Count the LSMs enabled at compile time KP Singh @ 2023-06-16 0:04 ` KP Singh 2023-06-16 1:05 ` Casey Schaufler ` (3 more replies) 2023-06-16 0:04 ` [PATCH v2 4/5] bpf: Only enable BPF LSM hooks when an LSM program is attached KP Singh 2023-06-16 0:04 ` [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY KP Singh 4 siblings, 4 replies; 21+ messages in thread From: KP Singh @ 2023-06-16 0:04 UTC (permalink / raw) To: linux-security-module, bpf Cc: paul, keescook, casey, song, daniel, ast, jannh, KP Singh 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). 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@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)) + /* 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; -- 2.41.0.162.gfafddb0af9-goog ^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls 2023-06-16 0:04 ` [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls KP Singh @ 2023-06-16 1:05 ` Casey Schaufler 2023-06-17 15:09 ` KP Singh 2023-06-16 3:41 ` kernel test robot ` (2 subsequent siblings) 3 siblings, 1 reply; 21+ messages in thread From: Casey Schaufler @ 2023-06-16 1:05 UTC (permalink / raw) To: KP Singh, linux-security-module, bpf Cc: paul, keescook, song, daniel, ast, jannh, Casey Schaufler 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 your arrays based on the number of entries for each hook. The original 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@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; ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls 2023-06-16 1:05 ` Casey Schaufler @ 2023-06-17 15:09 ` KP Singh 0 siblings, 0 replies; 21+ messages in thread From: KP Singh @ 2023-06-17 15:09 UTC (permalink / raw) To: Casey Schaufler Cc: linux-security-module, bpf, paul, keescook, song, daniel, ast, jannh On Fri, Jun 16, 2023 at 3:05 AM Casey Schaufler <casey@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@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; ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls 2023-06-16 0:04 ` [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls KP Singh 2023-06-16 1:05 ` Casey Schaufler @ 2023-06-16 3:41 ` kernel test robot 2023-06-16 21:09 ` kernel test robot 2023-06-20 21:53 ` Kees Cook 3 siblings, 0 replies; 21+ messages in thread From: kernel test robot @ 2023-06-16 3:41 UTC (permalink / raw) To: KP Singh, linux-security-module, bpf Cc: oe-kbuild-all, paul, keescook, casey, song, daniel, ast, jannh, KP Singh Hi KP, kernel test robot noticed the following build errors: [auto build test ERROR on next-20230615] [also build test ERROR on v6.4-rc6] [cannot apply to bpf-next/master bpf/master pcmoore-selinux/next linus/master v6.4-rc6 v6.4-rc5 v6.4-rc4] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/KP-Singh/kernel-Add-helper-macros-for-loop-unrolling/20230616-080708 base: next-20230615 patch link: https://lore.kernel.org/r/20230616000441.3677441-4-kpsingh%40kernel.org patch subject: [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls config: m68k-randconfig-r001-20230615 (https://download.01.org/0day-ci/archive/20230616/202306161110.9jeDpzVN-lkp@intel.com/config) compiler: m68k-linux-gcc (GCC) 12.3.0 reproduce (this is a W=1 build): mkdir -p ~/bin wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross git checkout next-20230615 b4 shazam https://lore.kernel.org/r/20230616000441.3677441-4-kpsingh@kernel.org # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=m68k olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202306161110.9jeDpzVN-lkp@intel.com/ All errors (new ones prefixed by >>): >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x20): undefined reference to `__SCT__lsm_static_call_binder_set_context_mgr_0' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x30): undefined reference to `__SCT__lsm_static_call_binder_set_context_mgr_1' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x40): undefined reference to `__SCT__lsm_static_call_binder_transaction_0' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x50): undefined reference to `__SCT__lsm_static_call_binder_transaction_1' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x60): undefined reference to `__SCT__lsm_static_call_binder_transfer_binder_0' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x70): undefined reference to `__SCT__lsm_static_call_binder_transfer_binder_1' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x80): undefined reference to `__SCT__lsm_static_call_binder_transfer_file_0' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x90): undefined reference to `__SCT__lsm_static_call_binder_transfer_file_1' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0xa0): undefined reference to `__SCT__lsm_static_call_ptrace_access_check_0' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0xb0): undefined reference to `__SCT__lsm_static_call_ptrace_access_check_1' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0xc0): undefined reference to `__SCT__lsm_static_call_ptrace_traceme_0' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0xd0): undefined reference to `__SCT__lsm_static_call_ptrace_traceme_1' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0xe0): undefined reference to `__SCT__lsm_static_call_capget_0' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0xf0): undefined reference to `__SCT__lsm_static_call_capget_1' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x100): undefined reference to `__SCT__lsm_static_call_capset_0' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x110): undefined reference to `__SCT__lsm_static_call_capset_1' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x120): undefined reference to `__SCT__lsm_static_call_capable_0' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x130): undefined reference to `__SCT__lsm_static_call_capable_1' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x140): undefined reference to `__SCT__lsm_static_call_quotactl_0' >> m68k-linux-ld: security/security.o:(.data..ro_after_init+0x150): undefined reference to `__SCT__lsm_static_call_quotactl_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x160): undefined reference to `__SCT__lsm_static_call_quota_on_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x170): undefined reference to `__SCT__lsm_static_call_quota_on_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x180): undefined reference to `__SCT__lsm_static_call_syslog_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x190): undefined reference to `__SCT__lsm_static_call_syslog_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x1a0): undefined reference to `__SCT__lsm_static_call_settime_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x1b0): undefined reference to `__SCT__lsm_static_call_settime_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x1c0): undefined reference to `__SCT__lsm_static_call_vm_enough_memory_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x1d0): undefined reference to `__SCT__lsm_static_call_vm_enough_memory_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x1e0): undefined reference to `__SCT__lsm_static_call_bprm_creds_for_exec_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x1f0): undefined reference to `__SCT__lsm_static_call_bprm_creds_for_exec_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x200): undefined reference to `__SCT__lsm_static_call_bprm_creds_from_file_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x210): undefined reference to `__SCT__lsm_static_call_bprm_creds_from_file_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x220): undefined reference to `__SCT__lsm_static_call_bprm_check_security_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x230): undefined reference to `__SCT__lsm_static_call_bprm_check_security_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x240): undefined reference to `__SCT__lsm_static_call_bprm_committing_creds_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x250): undefined reference to `__SCT__lsm_static_call_bprm_committing_creds_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x260): undefined reference to `__SCT__lsm_static_call_bprm_committed_creds_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x270): undefined reference to `__SCT__lsm_static_call_bprm_committed_creds_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x280): undefined reference to `__SCT__lsm_static_call_fs_context_dup_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x290): undefined reference to `__SCT__lsm_static_call_fs_context_dup_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x2a0): undefined reference to `__SCT__lsm_static_call_fs_context_parse_param_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x2b0): undefined reference to `__SCT__lsm_static_call_fs_context_parse_param_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x2c0): undefined reference to `__SCT__lsm_static_call_sb_alloc_security_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x2d0): undefined reference to `__SCT__lsm_static_call_sb_alloc_security_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x2e0): undefined reference to `__SCT__lsm_static_call_sb_delete_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x2f0): undefined reference to `__SCT__lsm_static_call_sb_delete_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x300): undefined reference to `__SCT__lsm_static_call_sb_free_security_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x310): undefined reference to `__SCT__lsm_static_call_sb_free_security_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x320): undefined reference to `__SCT__lsm_static_call_sb_free_mnt_opts_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x330): undefined reference to `__SCT__lsm_static_call_sb_free_mnt_opts_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x340): undefined reference to `__SCT__lsm_static_call_sb_eat_lsm_opts_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x350): undefined reference to `__SCT__lsm_static_call_sb_eat_lsm_opts_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x360): undefined reference to `__SCT__lsm_static_call_sb_mnt_opts_compat_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x370): undefined reference to `__SCT__lsm_static_call_sb_mnt_opts_compat_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x380): undefined reference to `__SCT__lsm_static_call_sb_remount_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x390): undefined reference to `__SCT__lsm_static_call_sb_remount_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x3a0): undefined reference to `__SCT__lsm_static_call_sb_kern_mount_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x3b0): undefined reference to `__SCT__lsm_static_call_sb_kern_mount_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x3c0): undefined reference to `__SCT__lsm_static_call_sb_show_options_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x3d0): undefined reference to `__SCT__lsm_static_call_sb_show_options_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x3e0): undefined reference to `__SCT__lsm_static_call_sb_statfs_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x3f0): undefined reference to `__SCT__lsm_static_call_sb_statfs_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x400): undefined reference to `__SCT__lsm_static_call_sb_mount_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x410): undefined reference to `__SCT__lsm_static_call_sb_mount_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x420): undefined reference to `__SCT__lsm_static_call_sb_umount_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x430): undefined reference to `__SCT__lsm_static_call_sb_umount_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x440): undefined reference to `__SCT__lsm_static_call_sb_pivotroot_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x450): undefined reference to `__SCT__lsm_static_call_sb_pivotroot_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x460): undefined reference to `__SCT__lsm_static_call_sb_set_mnt_opts_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x470): undefined reference to `__SCT__lsm_static_call_sb_set_mnt_opts_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x480): undefined reference to `__SCT__lsm_static_call_sb_clone_mnt_opts_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x490): undefined reference to `__SCT__lsm_static_call_sb_clone_mnt_opts_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x4a0): undefined reference to `__SCT__lsm_static_call_move_mount_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x4b0): undefined reference to `__SCT__lsm_static_call_move_mount_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x4c0): undefined reference to `__SCT__lsm_static_call_dentry_init_security_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x4d0): undefined reference to `__SCT__lsm_static_call_dentry_init_security_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x4e0): undefined reference to `__SCT__lsm_static_call_dentry_create_files_as_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x4f0): undefined reference to `__SCT__lsm_static_call_dentry_create_files_as_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x500): undefined reference to `__SCT__lsm_static_call_path_unlink_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x510): undefined reference to `__SCT__lsm_static_call_path_unlink_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x520): undefined reference to `__SCT__lsm_static_call_path_mkdir_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x530): undefined reference to `__SCT__lsm_static_call_path_mkdir_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x540): undefined reference to `__SCT__lsm_static_call_path_rmdir_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x550): undefined reference to `__SCT__lsm_static_call_path_rmdir_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x560): undefined reference to `__SCT__lsm_static_call_path_mknod_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x570): undefined reference to `__SCT__lsm_static_call_path_mknod_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x580): undefined reference to `__SCT__lsm_static_call_path_truncate_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x590): undefined reference to `__SCT__lsm_static_call_path_truncate_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x5a0): undefined reference to `__SCT__lsm_static_call_path_symlink_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x5b0): undefined reference to `__SCT__lsm_static_call_path_symlink_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x5c0): undefined reference to `__SCT__lsm_static_call_path_link_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x5d0): undefined reference to `__SCT__lsm_static_call_path_link_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x5e0): undefined reference to `__SCT__lsm_static_call_path_rename_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x5f0): undefined reference to `__SCT__lsm_static_call_path_rename_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x600): undefined reference to `__SCT__lsm_static_call_path_chmod_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x610): undefined reference to `__SCT__lsm_static_call_path_chmod_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x620): undefined reference to `__SCT__lsm_static_call_path_chown_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x630): undefined reference to `__SCT__lsm_static_call_path_chown_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x640): undefined reference to `__SCT__lsm_static_call_path_chroot_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x650): undefined reference to `__SCT__lsm_static_call_path_chroot_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x660): undefined reference to `__SCT__lsm_static_call_path_notify_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x670): undefined reference to `__SCT__lsm_static_call_path_notify_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x680): undefined reference to `__SCT__lsm_static_call_inode_alloc_security_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x690): undefined reference to `__SCT__lsm_static_call_inode_alloc_security_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x6a0): undefined reference to `__SCT__lsm_static_call_inode_free_security_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x6b0): undefined reference to `__SCT__lsm_static_call_inode_free_security_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x6c0): undefined reference to `__SCT__lsm_static_call_inode_init_security_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x6d0): undefined reference to `__SCT__lsm_static_call_inode_init_security_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x6e0): undefined reference to `__SCT__lsm_static_call_inode_init_security_anon_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x6f0): undefined reference to `__SCT__lsm_static_call_inode_init_security_anon_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x700): undefined reference to `__SCT__lsm_static_call_inode_create_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x710): undefined reference to `__SCT__lsm_static_call_inode_create_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x720): undefined reference to `__SCT__lsm_static_call_inode_link_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x730): undefined reference to `__SCT__lsm_static_call_inode_link_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x740): undefined reference to `__SCT__lsm_static_call_inode_unlink_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x750): undefined reference to `__SCT__lsm_static_call_inode_unlink_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x760): undefined reference to `__SCT__lsm_static_call_inode_symlink_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x770): undefined reference to `__SCT__lsm_static_call_inode_symlink_1' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x780): undefined reference to `__SCT__lsm_static_call_inode_mkdir_0' m68k-linux-ld: security/security.o:(.data..ro_after_init+0x790): undefined reference to `__SCT__lsm_static_call_inode_mkdir_1' -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls 2023-06-16 0:04 ` [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls KP Singh 2023-06-16 1:05 ` Casey Schaufler 2023-06-16 3:41 ` kernel test robot @ 2023-06-16 21:09 ` kernel test robot 2023-06-17 15:39 ` KP Singh 2023-06-20 21:53 ` Kees Cook 3 siblings, 1 reply; 21+ messages in thread From: kernel test robot @ 2023-06-16 21:09 UTC (permalink / raw) To: KP Singh, linux-security-module, bpf Cc: oe-kbuild-all, paul, keescook, casey, song, daniel, ast, jannh, KP Singh Hi KP, kernel test robot noticed the following build errors: [auto build test ERROR on next-20230615] [also build test ERROR on v6.4-rc6] [cannot apply to bpf-next/master bpf/master pcmoore-selinux/next linus/master v6.4-rc6 v6.4-rc5 v6.4-rc4] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/KP-Singh/kernel-Add-helper-macros-for-loop-unrolling/20230616-080708 base: next-20230615 patch link: https://lore.kernel.org/r/20230616000441.3677441-4-kpsingh%40kernel.org patch subject: [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls config: s390-defconfig (https://download.01.org/0day-ci/archive/20230617/202306170414.br6e1YPW-lkp@intel.com/config) compiler: s390-linux-gcc (GCC) 12.3.0 reproduce: (https://download.01.org/0day-ci/archive/20230617/202306170414.br6e1YPW-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202306170414.br6e1YPW-lkp@intel.com/ All errors (new ones prefixed by >>): >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x28): undefined reference to `__SCT__lsm_static_call_binder_set_context_mgr_0' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x48): undefined reference to `__SCT__lsm_static_call_binder_set_context_mgr_1' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x68): undefined reference to `__SCT__lsm_static_call_binder_set_context_mgr_2' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x88): undefined reference to `__SCT__lsm_static_call_binder_set_context_mgr_3' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0xa8): undefined reference to `__SCT__lsm_static_call_binder_set_context_mgr_4' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0xc8): undefined reference to `__SCT__lsm_static_call_binder_transaction_0' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0xe8): undefined reference to `__SCT__lsm_static_call_binder_transaction_1' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x108): undefined reference to `__SCT__lsm_static_call_binder_transaction_2' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x128): undefined reference to `__SCT__lsm_static_call_binder_transaction_3' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x148): undefined reference to `__SCT__lsm_static_call_binder_transaction_4' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x168): undefined reference to `__SCT__lsm_static_call_binder_transfer_binder_0' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x188): undefined reference to `__SCT__lsm_static_call_binder_transfer_binder_1' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x1a8): undefined reference to `__SCT__lsm_static_call_binder_transfer_binder_2' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x1c8): undefined reference to `__SCT__lsm_static_call_binder_transfer_binder_3' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x1e8): undefined reference to `__SCT__lsm_static_call_binder_transfer_binder_4' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x208): undefined reference to `__SCT__lsm_static_call_binder_transfer_file_0' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x228): undefined reference to `__SCT__lsm_static_call_binder_transfer_file_1' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x248): undefined reference to `__SCT__lsm_static_call_binder_transfer_file_2' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x268): undefined reference to `__SCT__lsm_static_call_binder_transfer_file_3' >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x288): undefined reference to `__SCT__lsm_static_call_binder_transfer_file_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0x2a8): undefined reference to `__SCT__lsm_static_call_ptrace_access_check_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0x2c8): undefined reference to `__SCT__lsm_static_call_ptrace_access_check_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0x2e8): undefined reference to `__SCT__lsm_static_call_ptrace_access_check_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0x308): undefined reference to `__SCT__lsm_static_call_ptrace_access_check_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0x328): undefined reference to `__SCT__lsm_static_call_ptrace_access_check_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0x348): undefined reference to `__SCT__lsm_static_call_ptrace_traceme_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0x368): undefined reference to `__SCT__lsm_static_call_ptrace_traceme_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0x388): undefined reference to `__SCT__lsm_static_call_ptrace_traceme_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0x3a8): undefined reference to `__SCT__lsm_static_call_ptrace_traceme_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0x3c8): undefined reference to `__SCT__lsm_static_call_ptrace_traceme_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0x3e8): undefined reference to `__SCT__lsm_static_call_capget_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0x408): undefined reference to `__SCT__lsm_static_call_capget_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0x428): undefined reference to `__SCT__lsm_static_call_capget_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0x448): undefined reference to `__SCT__lsm_static_call_capget_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0x468): undefined reference to `__SCT__lsm_static_call_capget_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0x488): undefined reference to `__SCT__lsm_static_call_capset_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0x4a8): undefined reference to `__SCT__lsm_static_call_capset_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0x4c8): undefined reference to `__SCT__lsm_static_call_capset_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0x4e8): undefined reference to `__SCT__lsm_static_call_capset_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0x508): undefined reference to `__SCT__lsm_static_call_capset_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0x528): undefined reference to `__SCT__lsm_static_call_capable_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0x548): undefined reference to `__SCT__lsm_static_call_capable_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0x568): undefined reference to `__SCT__lsm_static_call_capable_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0x588): undefined reference to `__SCT__lsm_static_call_capable_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0x5a8): undefined reference to `__SCT__lsm_static_call_capable_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0x5c8): undefined reference to `__SCT__lsm_static_call_quotactl_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0x5e8): undefined reference to `__SCT__lsm_static_call_quotactl_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0x608): undefined reference to `__SCT__lsm_static_call_quotactl_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0x628): undefined reference to `__SCT__lsm_static_call_quotactl_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0x648): undefined reference to `__SCT__lsm_static_call_quotactl_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0x668): undefined reference to `__SCT__lsm_static_call_quota_on_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0x688): undefined reference to `__SCT__lsm_static_call_quota_on_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0x6a8): undefined reference to `__SCT__lsm_static_call_quota_on_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0x6c8): undefined reference to `__SCT__lsm_static_call_quota_on_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0x6e8): undefined reference to `__SCT__lsm_static_call_quota_on_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0x708): undefined reference to `__SCT__lsm_static_call_syslog_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0x728): undefined reference to `__SCT__lsm_static_call_syslog_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0x748): undefined reference to `__SCT__lsm_static_call_syslog_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0x768): undefined reference to `__SCT__lsm_static_call_syslog_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0x788): undefined reference to `__SCT__lsm_static_call_syslog_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0x7a8): undefined reference to `__SCT__lsm_static_call_settime_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0x7c8): undefined reference to `__SCT__lsm_static_call_settime_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0x7e8): undefined reference to `__SCT__lsm_static_call_settime_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0x808): undefined reference to `__SCT__lsm_static_call_settime_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0x828): undefined reference to `__SCT__lsm_static_call_settime_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0x848): undefined reference to `__SCT__lsm_static_call_vm_enough_memory_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0x868): undefined reference to `__SCT__lsm_static_call_vm_enough_memory_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0x888): undefined reference to `__SCT__lsm_static_call_vm_enough_memory_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0x8a8): undefined reference to `__SCT__lsm_static_call_vm_enough_memory_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0x8c8): undefined reference to `__SCT__lsm_static_call_vm_enough_memory_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0x8e8): undefined reference to `__SCT__lsm_static_call_bprm_creds_for_exec_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0x908): undefined reference to `__SCT__lsm_static_call_bprm_creds_for_exec_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0x928): undefined reference to `__SCT__lsm_static_call_bprm_creds_for_exec_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0x948): undefined reference to `__SCT__lsm_static_call_bprm_creds_for_exec_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0x968): undefined reference to `__SCT__lsm_static_call_bprm_creds_for_exec_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0x988): undefined reference to `__SCT__lsm_static_call_bprm_creds_from_file_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0x9a8): undefined reference to `__SCT__lsm_static_call_bprm_creds_from_file_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0x9c8): undefined reference to `__SCT__lsm_static_call_bprm_creds_from_file_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0x9e8): undefined reference to `__SCT__lsm_static_call_bprm_creds_from_file_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0xa08): undefined reference to `__SCT__lsm_static_call_bprm_creds_from_file_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0xa28): undefined reference to `__SCT__lsm_static_call_bprm_check_security_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0xa48): undefined reference to `__SCT__lsm_static_call_bprm_check_security_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0xa68): undefined reference to `__SCT__lsm_static_call_bprm_check_security_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0xa88): undefined reference to `__SCT__lsm_static_call_bprm_check_security_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0xaa8): undefined reference to `__SCT__lsm_static_call_bprm_check_security_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0xac8): undefined reference to `__SCT__lsm_static_call_bprm_committing_creds_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0xae8): undefined reference to `__SCT__lsm_static_call_bprm_committing_creds_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0xb08): undefined reference to `__SCT__lsm_static_call_bprm_committing_creds_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0xb28): undefined reference to `__SCT__lsm_static_call_bprm_committing_creds_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0xb48): undefined reference to `__SCT__lsm_static_call_bprm_committing_creds_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0xb68): undefined reference to `__SCT__lsm_static_call_bprm_committed_creds_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0xb88): undefined reference to `__SCT__lsm_static_call_bprm_committed_creds_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0xba8): undefined reference to `__SCT__lsm_static_call_bprm_committed_creds_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0xbc8): undefined reference to `__SCT__lsm_static_call_bprm_committed_creds_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0xbe8): undefined reference to `__SCT__lsm_static_call_bprm_committed_creds_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0xc08): undefined reference to `__SCT__lsm_static_call_fs_context_dup_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0xc28): undefined reference to `__SCT__lsm_static_call_fs_context_dup_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0xc48): undefined reference to `__SCT__lsm_static_call_fs_context_dup_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0xc68): undefined reference to `__SCT__lsm_static_call_fs_context_dup_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0xc88): undefined reference to `__SCT__lsm_static_call_fs_context_dup_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0xca8): undefined reference to `__SCT__lsm_static_call_fs_context_parse_param_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0xcc8): undefined reference to `__SCT__lsm_static_call_fs_context_parse_param_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0xce8): undefined reference to `__SCT__lsm_static_call_fs_context_parse_param_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0xd08): undefined reference to `__SCT__lsm_static_call_fs_context_parse_param_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0xd28): undefined reference to `__SCT__lsm_static_call_fs_context_parse_param_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0xd48): undefined reference to `__SCT__lsm_static_call_sb_alloc_security_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0xd68): undefined reference to `__SCT__lsm_static_call_sb_alloc_security_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0xd88): undefined reference to `__SCT__lsm_static_call_sb_alloc_security_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0xda8): undefined reference to `__SCT__lsm_static_call_sb_alloc_security_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0xdc8): undefined reference to `__SCT__lsm_static_call_sb_alloc_security_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0xde8): undefined reference to `__SCT__lsm_static_call_sb_delete_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0xe08): undefined reference to `__SCT__lsm_static_call_sb_delete_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0xe28): undefined reference to `__SCT__lsm_static_call_sb_delete_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0xe48): undefined reference to `__SCT__lsm_static_call_sb_delete_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0xe68): undefined reference to `__SCT__lsm_static_call_sb_delete_4' s390-linux-ld: security/security.o:(.data..ro_after_init+0xe88): undefined reference to `__SCT__lsm_static_call_sb_free_security_0' s390-linux-ld: security/security.o:(.data..ro_after_init+0xea8): undefined reference to `__SCT__lsm_static_call_sb_free_security_1' s390-linux-ld: security/security.o:(.data..ro_after_init+0xec8): undefined reference to `__SCT__lsm_static_call_sb_free_security_2' s390-linux-ld: security/security.o:(.data..ro_after_init+0xee8): undefined reference to `__SCT__lsm_static_call_sb_free_security_3' s390-linux-ld: security/security.o:(.data..ro_after_init+0xf08): undefined reference to `__SCT__lsm_static_call_sb_free_security_4' -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls 2023-06-16 21:09 ` kernel test robot @ 2023-06-17 15:39 ` KP Singh 0 siblings, 0 replies; 21+ messages in thread From: KP Singh @ 2023-06-17 15:39 UTC (permalink / raw) To: kernel test robot Cc: linux-security-module, bpf, oe-kbuild-all, paul, keescook, casey, song, daniel, ast, jannh On Fri, Jun 16, 2023 at 11:10 PM kernel test robot <lkp@intel.com> wrote: > > Hi KP, > > kernel test robot noticed the following build errors: > > [auto build test ERROR on next-20230615] > [also build test ERROR on v6.4-rc6] > [cannot apply to bpf-next/master bpf/master pcmoore-selinux/next linus/master v6.4-rc6 v6.4-rc5 v6.4-rc4] > [If your patch is applied to the wrong git tree, kindly drop us a note. > And when submitting patch, we suggest to use '--base' as documented in > https://git-scm.com/docs/git-format-patch#_base_tree_information] > > url: https://github.com/intel-lab-lkp/linux/commits/KP-Singh/kernel-Add-helper-macros-for-loop-unrolling/20230616-080708 > base: next-20230615 > patch link: https://lore.kernel.org/r/20230616000441.3677441-4-kpsingh%40kernel.org > patch subject: [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls > config: s390-defconfig (https://download.01.org/0day-ci/archive/20230617/202306170414.br6e1YPW-lkp@intel.com/config) > compiler: s390-linux-gcc (GCC) 12.3.0 > reproduce: (https://download.01.org/0day-ci/archive/20230617/202306170414.br6e1YPW-lkp@intel.com/reproduce) > > If you fix the issue in a separate patch/commit (i.e. not just a new version of > the same patch/commit), kindly add following tags > | Reported-by: kernel test robot <lkp@intel.com> > | Closes: https://lore.kernel.org/oe-kbuild-all/202306170414.br6e1YPW-lkp@intel.com/ > > All errors (new ones prefixed by >>): > > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x28): undefined reference to `__SCT__lsm_static_call_binder_set_context_mgr_0' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x48): undefined reference to `__SCT__lsm_static_call_binder_set_context_mgr_1' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x68): undefined reference to `__SCT__lsm_static_call_binder_set_context_mgr_2' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x88): undefined reference to `__SCT__lsm_static_call_binder_set_context_mgr_3' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0xa8): undefined reference to `__SCT__lsm_static_call_binder_set_context_mgr_4' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0xc8): undefined reference to `__SCT__lsm_static_call_binder_transaction_0' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0xe8): undefined reference to `__SCT__lsm_static_call_binder_transaction_1' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x108): undefined reference to `__SCT__lsm_static_call_binder_transaction_2' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x128): undefined reference to `__SCT__lsm_static_call_binder_transaction_3' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x148): undefined reference to `__SCT__lsm_static_call_binder_transaction_4' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x168): undefined reference to `__SCT__lsm_static_call_binder_transfer_binder_0' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x188): undefined reference to `__SCT__lsm_static_call_binder_transfer_binder_1' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x1a8): undefined reference to `__SCT__lsm_static_call_binder_transfer_binder_2' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x1c8): undefined reference to `__SCT__lsm_static_call_binder_transfer_binder_3' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x1e8): undefined reference to `__SCT__lsm_static_call_binder_transfer_binder_4' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x208): undefined reference to `__SCT__lsm_static_call_binder_transfer_file_0' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x228): undefined reference to `__SCT__lsm_static_call_binder_transfer_file_1' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x248): undefined reference to `__SCT__lsm_static_call_binder_transfer_file_2' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x268): undefined reference to `__SCT__lsm_static_call_binder_transfer_file_3' > >> s390-linux-ld: security/security.o:(.data..ro_after_init+0x288): undefined reference to `__SCT__lsm_static_call_binder_transfer_file_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x2a8): undefined reference to `__SCT__lsm_static_call_ptrace_access_check_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x2c8): undefined reference to `__SCT__lsm_static_call_ptrace_access_check_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x2e8): undefined reference to `__SCT__lsm_static_call_ptrace_access_check_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x308): undefined reference to `__SCT__lsm_static_call_ptrace_access_check_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x328): undefined reference to `__SCT__lsm_static_call_ptrace_access_check_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x348): undefined reference to `__SCT__lsm_static_call_ptrace_traceme_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x368): undefined reference to `__SCT__lsm_static_call_ptrace_traceme_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x388): undefined reference to `__SCT__lsm_static_call_ptrace_traceme_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x3a8): undefined reference to `__SCT__lsm_static_call_ptrace_traceme_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x3c8): undefined reference to `__SCT__lsm_static_call_ptrace_traceme_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x3e8): undefined reference to `__SCT__lsm_static_call_capget_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x408): undefined reference to `__SCT__lsm_static_call_capget_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x428): undefined reference to `__SCT__lsm_static_call_capget_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x448): undefined reference to `__SCT__lsm_static_call_capget_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x468): undefined reference to `__SCT__lsm_static_call_capget_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x488): undefined reference to `__SCT__lsm_static_call_capset_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x4a8): undefined reference to `__SCT__lsm_static_call_capset_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x4c8): undefined reference to `__SCT__lsm_static_call_capset_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x4e8): undefined reference to `__SCT__lsm_static_call_capset_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x508): undefined reference to `__SCT__lsm_static_call_capset_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x528): undefined reference to `__SCT__lsm_static_call_capable_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x548): undefined reference to `__SCT__lsm_static_call_capable_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x568): undefined reference to `__SCT__lsm_static_call_capable_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x588): undefined reference to `__SCT__lsm_static_call_capable_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x5a8): undefined reference to `__SCT__lsm_static_call_capable_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x5c8): undefined reference to `__SCT__lsm_static_call_quotactl_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x5e8): undefined reference to `__SCT__lsm_static_call_quotactl_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x608): undefined reference to `__SCT__lsm_static_call_quotactl_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x628): undefined reference to `__SCT__lsm_static_call_quotactl_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x648): undefined reference to `__SCT__lsm_static_call_quotactl_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x668): undefined reference to `__SCT__lsm_static_call_quota_on_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x688): undefined reference to `__SCT__lsm_static_call_quota_on_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x6a8): undefined reference to `__SCT__lsm_static_call_quota_on_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x6c8): undefined reference to `__SCT__lsm_static_call_quota_on_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x6e8): undefined reference to `__SCT__lsm_static_call_quota_on_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x708): undefined reference to `__SCT__lsm_static_call_syslog_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x728): undefined reference to `__SCT__lsm_static_call_syslog_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x748): undefined reference to `__SCT__lsm_static_call_syslog_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x768): undefined reference to `__SCT__lsm_static_call_syslog_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x788): undefined reference to `__SCT__lsm_static_call_syslog_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x7a8): undefined reference to `__SCT__lsm_static_call_settime_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x7c8): undefined reference to `__SCT__lsm_static_call_settime_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x7e8): undefined reference to `__SCT__lsm_static_call_settime_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x808): undefined reference to `__SCT__lsm_static_call_settime_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x828): undefined reference to `__SCT__lsm_static_call_settime_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x848): undefined reference to `__SCT__lsm_static_call_vm_enough_memory_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x868): undefined reference to `__SCT__lsm_static_call_vm_enough_memory_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x888): undefined reference to `__SCT__lsm_static_call_vm_enough_memory_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x8a8): undefined reference to `__SCT__lsm_static_call_vm_enough_memory_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x8c8): undefined reference to `__SCT__lsm_static_call_vm_enough_memory_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x8e8): undefined reference to `__SCT__lsm_static_call_bprm_creds_for_exec_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x908): undefined reference to `__SCT__lsm_static_call_bprm_creds_for_exec_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x928): undefined reference to `__SCT__lsm_static_call_bprm_creds_for_exec_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x948): undefined reference to `__SCT__lsm_static_call_bprm_creds_for_exec_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x968): undefined reference to `__SCT__lsm_static_call_bprm_creds_for_exec_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x988): undefined reference to `__SCT__lsm_static_call_bprm_creds_from_file_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x9a8): undefined reference to `__SCT__lsm_static_call_bprm_creds_from_file_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x9c8): undefined reference to `__SCT__lsm_static_call_bprm_creds_from_file_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0x9e8): undefined reference to `__SCT__lsm_static_call_bprm_creds_from_file_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xa08): undefined reference to `__SCT__lsm_static_call_bprm_creds_from_file_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xa28): undefined reference to `__SCT__lsm_static_call_bprm_check_security_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xa48): undefined reference to `__SCT__lsm_static_call_bprm_check_security_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xa68): undefined reference to `__SCT__lsm_static_call_bprm_check_security_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xa88): undefined reference to `__SCT__lsm_static_call_bprm_check_security_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xaa8): undefined reference to `__SCT__lsm_static_call_bprm_check_security_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xac8): undefined reference to `__SCT__lsm_static_call_bprm_committing_creds_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xae8): undefined reference to `__SCT__lsm_static_call_bprm_committing_creds_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xb08): undefined reference to `__SCT__lsm_static_call_bprm_committing_creds_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xb28): undefined reference to `__SCT__lsm_static_call_bprm_committing_creds_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xb48): undefined reference to `__SCT__lsm_static_call_bprm_committing_creds_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xb68): undefined reference to `__SCT__lsm_static_call_bprm_committed_creds_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xb88): undefined reference to `__SCT__lsm_static_call_bprm_committed_creds_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xba8): undefined reference to `__SCT__lsm_static_call_bprm_committed_creds_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xbc8): undefined reference to `__SCT__lsm_static_call_bprm_committed_creds_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xbe8): undefined reference to `__SCT__lsm_static_call_bprm_committed_creds_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xc08): undefined reference to `__SCT__lsm_static_call_fs_context_dup_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xc28): undefined reference to `__SCT__lsm_static_call_fs_context_dup_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xc48): undefined reference to `__SCT__lsm_static_call_fs_context_dup_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xc68): undefined reference to `__SCT__lsm_static_call_fs_context_dup_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xc88): undefined reference to `__SCT__lsm_static_call_fs_context_dup_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xca8): undefined reference to `__SCT__lsm_static_call_fs_context_parse_param_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xcc8): undefined reference to `__SCT__lsm_static_call_fs_context_parse_param_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xce8): undefined reference to `__SCT__lsm_static_call_fs_context_parse_param_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xd08): undefined reference to `__SCT__lsm_static_call_fs_context_parse_param_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xd28): undefined reference to `__SCT__lsm_static_call_fs_context_parse_param_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xd48): undefined reference to `__SCT__lsm_static_call_sb_alloc_security_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xd68): undefined reference to `__SCT__lsm_static_call_sb_alloc_security_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xd88): undefined reference to `__SCT__lsm_static_call_sb_alloc_security_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xda8): undefined reference to `__SCT__lsm_static_call_sb_alloc_security_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xdc8): undefined reference to `__SCT__lsm_static_call_sb_alloc_security_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xde8): undefined reference to `__SCT__lsm_static_call_sb_delete_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xe08): undefined reference to `__SCT__lsm_static_call_sb_delete_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xe28): undefined reference to `__SCT__lsm_static_call_sb_delete_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xe48): undefined reference to `__SCT__lsm_static_call_sb_delete_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xe68): undefined reference to `__SCT__lsm_static_call_sb_delete_4' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xe88): undefined reference to `__SCT__lsm_static_call_sb_free_security_0' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xea8): undefined reference to `__SCT__lsm_static_call_sb_free_security_1' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xec8): undefined reference to `__SCT__lsm_static_call_sb_free_security_2' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xee8): undefined reference to `__SCT__lsm_static_call_sb_free_security_3' > s390-linux-ld: security/security.o:(.data..ro_after_init+0xf08): undefined reference to `__SCT__lsm_static_call_sb_free_security_4' > We ended up leaking the STATIC_CALL_TRAMP (__SCT__) which is not used on architectures that don't have static call support. A simple change fixes this: diff --git a/security/security.c b/security/security.c index da80a8918e7d..f6ea028dbc7e 100644 --- a/security/security.c +++ b/security/security.c @@ -95,6 +95,14 @@ static __initconst const char *const builtin_lsm_order = CONFIG_LSM; static __initdata struct lsm_info **ordered_lsms; static __initdata struct lsm_info *exclusive; + +#ifdef CONFIG_HAVE_STATIC_CALL +#define LSM_HOOK_TRAMP(NAME, NUM) \ + &STATIC_CALL_TRAMP(LSM_STATIC_CALL(NAME, NUM)) +#else +#define LSM_HOOK_TRAMP(NAME, NUM) NULL +#endif + /* * Define static calls and static keys for each LSM hook. */ @@ -123,7 +131,7 @@ 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)),\ + .trampoline = LSM_HOOK_TRAMP(NAME, NUM), \ .active = &SECURITY_HOOK_ACTIVE_KEY(NAME, NUM), \ }, #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ The trampoline is not used as the static call just ends up being an indirect call. I will fix this in the next revision. > -- > 0-DAY CI Kernel Test Service > https://github.com/intel/lkp-tests/wiki ^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls 2023-06-16 0:04 ` [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls KP Singh ` (2 preceding siblings ...) 2023-06-16 21:09 ` kernel test robot @ 2023-06-20 21:53 ` Kees Cook 3 siblings, 0 replies; 21+ messages in thread From: Kees Cook @ 2023-06-20 21:53 UTC (permalink / raw) To: KP Singh Cc: linux-security-module, bpf, paul, casey, song, daniel, ast, jannh On Fri, Jun 16, 2023 at 02:04:39AM +0200, 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: Overall, I find this a much cleaner patch compared to the v1 -- thanks for cleaning up how the loops are replaced. I'm looking forward to v3 (with the build fixes and other comments addressed), as I think the performance benefit this series provides is significant. Thanks! -Kees -- Kees Cook ^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 4/5] bpf: Only enable BPF LSM hooks when an LSM program is attached 2023-06-16 0:04 [PATCH v2 0/5] Reduce overhead of LSMs with static calls KP Singh ` (2 preceding siblings ...) 2023-06-16 0:04 ` [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls KP Singh @ 2023-06-16 0:04 ` KP Singh 2023-06-16 0:04 ` [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY KP Singh 4 siblings, 0 replies; 21+ messages in thread From: KP Singh @ 2023-06-16 0:04 UTC (permalink / raw) To: linux-security-module, bpf Cc: paul, keescook, casey, song, daniel, ast, jannh, KP Singh BPF LSM hooks have side-effects (even when a default value is returned), as some hooks end up behaving differently due to the very presence of the hook. The static keys guarding the BPF LSM hooks are disabled by default and enabled only when a BPF program is attached implementing the hook logic. This avoids the issue of the side-effects and also the minor overhead associated with the empty callback. security_file_ioctl: 0xffffffff818f0e30 <+0>: endbr64 0xffffffff818f0e34 <+4>: nopl 0x0(%rax,%rax,1) 0xffffffff818f0e39 <+9>: push %rbp 0xffffffff818f0e3a <+10>: push %r14 0xffffffff818f0e3c <+12>: push %rbx 0xffffffff818f0e3d <+13>: mov %rdx,%rbx 0xffffffff818f0e40 <+16>: mov %esi,%ebp 0xffffffff818f0e42 <+18>: mov %rdi,%r14 0xffffffff818f0e45 <+21>: jmp 0xffffffff818f0e57 <security_file_ioctl+39> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Static key enabled for SELinux 0xffffffff818f0e47 <+23>: xchg %ax,%ax ^^^^^^^^^^^^^^ Static key disabled for BPF. This gets patched when a BPF LSM program is attached 0xffffffff818f0e49 <+25>: xor %eax,%eax 0xffffffff818f0e4b <+27>: xchg %ax,%ax 0xffffffff818f0e4d <+29>: pop %rbx 0xffffffff818f0e4e <+30>: pop %r14 0xffffffff818f0e50 <+32>: pop %rbp 0xffffffff818f0e51 <+33>: cs jmp 0xffffffff82c00000 <__x86_return_thunk> 0xffffffff818f0e57 <+39>: endbr64 0xffffffff818f0e5b <+43>: mov %r14,%rdi 0xffffffff818f0e5e <+46>: mov %ebp,%esi 0xffffffff818f0e60 <+48>: mov %rbx,%rdx 0xffffffff818f0e63 <+51>: call 0xffffffff819033c0 <selinux_file_ioctl> 0xffffffff818f0e68 <+56>: test %eax,%eax 0xffffffff818f0e6a <+58>: jne 0xffffffff818f0e4d <security_file_ioctl+29> 0xffffffff818f0e6c <+60>: jmp 0xffffffff818f0e47 <security_file_ioctl+23> 0xffffffff818f0e6e <+62>: endbr64 0xffffffff818f0e72 <+66>: mov %r14,%rdi 0xffffffff818f0e75 <+69>: mov %ebp,%esi 0xffffffff818f0e77 <+71>: mov %rbx,%rdx 0xffffffff818f0e7a <+74>: call 0xffffffff8141e3b0 <bpf_lsm_file_ioctl> 0xffffffff818f0e7f <+79>: test %eax,%eax 0xffffffff818f0e81 <+81>: jne 0xffffffff818f0e4d <security_file_ioctl+29> 0xffffffff818f0e83 <+83>: jmp 0xffffffff818f0e49 <security_file_ioctl+25> 0xffffffff818f0e85 <+85>: endbr64 0xffffffff818f0e89 <+89>: mov %r14,%rdi 0xffffffff818f0e8c <+92>: mov %ebp,%esi 0xffffffff818f0e8e <+94>: mov %rbx,%rdx 0xffffffff818f0e91 <+97>: pop %rbx 0xffffffff818f0e92 <+98>: pop %r14 0xffffffff818f0e94 <+100>: pop %rbp 0xffffffff818f0e95 <+101>: ret Signed-off-by: KP Singh <kpsingh@kernel.org> --- include/linux/bpf.h | 1 + include/linux/bpf_lsm.h | 5 +++++ include/linux/lsm_hooks.h | 13 ++++++++++++- kernel/bpf/trampoline.c | 29 +++++++++++++++++++++++++++-- security/bpf/hooks.c | 25 ++++++++++++++++++++++++- security/security.c | 3 ++- 6 files changed, 71 insertions(+), 5 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index f58895830ada..d288b65836c4 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1134,6 +1134,7 @@ struct bpf_attach_target_info { struct module *tgt_mod; const char *tgt_name; const struct btf_type *tgt_type; + bool is_lsm_target; }; #define BPF_DISPATCHER_MAX 48 /* Fits in 2048B */ diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h index 1de7ece5d36d..5bbc31ac948c 100644 --- a/include/linux/bpf_lsm.h +++ b/include/linux/bpf_lsm.h @@ -29,6 +29,7 @@ int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog, bool bpf_lsm_is_sleepable_hook(u32 btf_id); bool bpf_lsm_is_trusted(const struct bpf_prog *prog); +void bpf_lsm_toggle_hook(void *addr, bool value); static inline struct bpf_storage_blob *bpf_inode( const struct inode *inode) @@ -78,6 +79,10 @@ static inline void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog, { } +static inline void bpf_lsm_toggle_hook(void *addr, bool value) +{ +} + #endif /* CONFIG_BPF_LSM */ #endif /* _LINUX_BPF_LSM_H */ diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 069da0fa617a..96fa610ce443 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -96,11 +96,14 @@ struct lsm_static_calls_table { * @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. + * @default_state: The state of the LSM hook when initialized. If set to false, + * the static key guarding the hook will be set to disabled. */ struct security_hook_list { struct lsm_static_call *scalls; union security_list_options hook; const char *lsm; + bool default_state; } __randomize_layout; /* @@ -131,7 +134,15 @@ struct lsm_blob_sizes { #define LSM_HOOK_INIT(NAME, CALLBACK) \ { \ .scalls = static_calls_table.NAME, \ - .hook = { .NAME = CALLBACK } \ + .hook = { .NAME = CALLBACK }, \ + .default_state = true \ + } + +#define LSM_HOOK_INIT_DISABLED(NAME, CALLBACK) \ + { \ + .scalls = static_calls_table.NAME, \ + .hook = { .NAME = CALLBACK }, \ + .default_state = false \ } extern char *lsm_names; diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index 78acf28d4873..5b17cd7aab30 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -13,6 +13,7 @@ #include <linux/bpf_verifier.h> #include <linux/bpf_lsm.h> #include <linux/delay.h> +#include <linux/bpf_lsm.h> /* dummy _ops. The verifier will operate on target program's ops. */ const struct bpf_verifier_ops bpf_extension_verifier_ops = { @@ -514,7 +515,7 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_tr { enum bpf_tramp_prog_type kind; struct bpf_tramp_link *link_exiting; - int err = 0; + int err = 0, num_lsm_progs = 0; int cnt = 0, i; kind = bpf_attach_type_to_tramp(link->link.prog); @@ -545,8 +546,14 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_tr continue; /* prog already linked */ return -EBUSY; + + if (link_exiting->link.prog->type == BPF_PROG_TYPE_LSM) + num_lsm_progs++; } + if (!num_lsm_progs && link->link.prog->type == BPF_PROG_TYPE_LSM) + bpf_lsm_toggle_hook(tr->func.addr, true); + hlist_add_head(&link->tramp_hlist, &tr->progs_hlist[kind]); tr->progs_cnt[kind]++; err = bpf_trampoline_update(tr, true /* lock_direct_mutex */); @@ -569,8 +576,10 @@ int bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_trampoline static int __bpf_trampoline_unlink_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr) { + struct bpf_tramp_link *link_exiting; enum bpf_tramp_prog_type kind; - int err; + bool lsm_link_found = false; + int err, num_lsm_progs = 0; kind = bpf_attach_type_to_tramp(link->link.prog); if (kind == BPF_TRAMP_REPLACE) { @@ -580,8 +589,24 @@ static int __bpf_trampoline_unlink_prog(struct bpf_tramp_link *link, struct bpf_ tr->extension_prog = NULL; return err; } + + if (link->link.prog->type == BPF_PROG_TYPE_LSM) { + hlist_for_each_entry(link_exiting, &tr->progs_hlist[kind], + tramp_hlist) { + if (link_exiting->link.prog->type == BPF_PROG_TYPE_LSM) + num_lsm_progs++; + + if (link_exiting->link.prog == link->link.prog) + lsm_link_found = true; + } + } + hlist_del_init(&link->tramp_hlist); tr->progs_cnt[kind]--; + + if (lsm_link_found && num_lsm_progs == 1) + bpf_lsm_toggle_hook(tr->func.addr, false); + return bpf_trampoline_update(tr, true /* lock_direct_mutex */); } diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c index cfaf1d0e6a5f..1957244196d0 100644 --- a/security/bpf/hooks.c +++ b/security/bpf/hooks.c @@ -8,7 +8,7 @@ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = { #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ - LSM_HOOK_INIT(NAME, bpf_lsm_##NAME), + LSM_HOOK_INIT_DISABLED(NAME, bpf_lsm_##NAME), #include <linux/lsm_hook_defs.h> #undef LSM_HOOK LSM_HOOK_INIT(inode_free_security, bpf_inode_storage_free), @@ -32,3 +32,26 @@ DEFINE_LSM(bpf) = { .init = bpf_lsm_init, .blobs = &bpf_lsm_blob_sizes }; + +void bpf_lsm_toggle_hook(void *addr, bool value) +{ + struct lsm_static_call *scalls; + struct security_hook_list *h; + int i, j; + + for (i = 0; i < ARRAY_SIZE(bpf_lsm_hooks); i++) { + h = &bpf_lsm_hooks[i]; + scalls = h->scalls; + if (h->hook.lsm_callback == addr) + continue; + + for (j = 0; j < MAX_LSM_COUNT; j++) { + if (scalls[j].hl != h) + continue; + if (value) + static_branch_enable(scalls[j].active); + else + static_branch_disable(scalls[j].active); + } + } +} diff --git a/security/security.c b/security/security.c index 9ae7c0ec5cac..4aec25949212 100644 --- a/security/security.c +++ b/security/security.c @@ -374,7 +374,8 @@ static void __init lsm_static_call_init(struct security_hook_list *hl) __static_call_update(scall->key, scall->trampoline, hl->hook.lsm_callback); scall->hl = hl; - static_branch_enable(scall->active); + if (hl->default_state) + static_branch_enable(scall->active); return; } scall++; -- 2.41.0.162.gfafddb0af9-goog ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY 2023-06-16 0:04 [PATCH v2 0/5] Reduce overhead of LSMs with static calls KP Singh ` (3 preceding siblings ...) 2023-06-16 0:04 ` [PATCH v2 4/5] bpf: Only enable BPF LSM hooks when an LSM program is attached KP Singh @ 2023-06-16 0:04 ` KP Singh 2023-06-16 1:14 ` Casey Schaufler ` (2 more replies) 4 siblings, 3 replies; 21+ messages in thread From: KP Singh @ 2023-06-16 0:04 UTC (permalink / raw) To: linux-security-module, bpf Cc: paul, keescook, casey, song, daniel, ast, jannh, KP Singh This config influences the nature of the static key that guards the static call for LSM hooks. When enabled, it indicates that an LSM static call slot is more likely to be initialized. When disabled, it optimizes for the case when static call slot is more likely to be not initialized. When a major LSM like (SELinux, AppArmor, Smack etc) is active on a system the system would benefit from enabling the config. However there are other cases which would benefit from the config being disabled (e.g. a system with a BPF LSM with no hooks enabled by default, or an LSM like loadpin / yama). Ultimately, there is no one-size fits all solution. with CONFIG_SECURITY_HOOK_LIKELY enabled, the inactive / uninitialized case is penalized with a direct jmp (still better than an indirect jmp): function security_file_ioctl: 0xffffffff818f0c80 <+0>: endbr64 0xffffffff818f0c84 <+4>: nopl 0x0(%rax,%rax,1) 0xffffffff818f0c89 <+9>: push %rbp 0xffffffff818f0c8a <+10>: push %r14 0xffffffff818f0c8c <+12>: push %rbx 0xffffffff818f0c8d <+13>: mov %rdx,%rbx 0xffffffff818f0c90 <+16>: mov %esi,%ebp 0xffffffff818f0c92 <+18>: mov %rdi,%r14 0xffffffff818f0c95 <+21>: jmp 0xffffffff818f0ca8 <security_file_ioctl+40> jump to skip the inactive BPF LSM hook. 0xffffffff818f0c97 <+23>: mov %r14,%rdi 0xffffffff818f0c9a <+26>: mov %ebp,%esi 0xffffffff818f0c9c <+28>: mov %rbx,%rdx 0xffffffff818f0c9f <+31>: call 0xffffffff8141e3b0 <bpf_lsm_file_ioctl> 0xffffffff818f0ca4 <+36>: test %eax,%eax 0xffffffff818f0ca6 <+38>: jne 0xffffffff818f0cbf <security_file_ioctl+63> 0xffffffff818f0ca8 <+40>: endbr64 0xffffffff818f0cac <+44>: jmp 0xffffffff818f0ccd <security_file_ioctl+77> jump to skip the empty slot. 0xffffffff818f0cae <+46>: mov %r14,%rdi 0xffffffff818f0cb1 <+49>: mov %ebp,%esi 0xffffffff818f0cb3 <+51>: mov %rbx,%rdx 0xffffffff818f0cb6 <+54>: nopl 0x0(%rax,%rax,1) ^^^^^^^^^^^^^^^^^^^^^^^ Empty slot 0xffffffff818f0cbb <+59>: test %eax,%eax 0xffffffff818f0cbd <+61>: je 0xffffffff818f0ccd <security_file_ioctl+77> 0xffffffff818f0cbf <+63>: endbr64 0xffffffff818f0cc3 <+67>: pop %rbx 0xffffffff818f0cc4 <+68>: pop %r14 0xffffffff818f0cc6 <+70>: pop %rbp 0xffffffff818f0cc7 <+71>: cs jmp 0xffffffff82c00000 <__x86_return_thunk> 0xffffffff818f0ccd <+77>: endbr64 0xffffffff818f0cd1 <+81>: xor %eax,%eax 0xffffffff818f0cd3 <+83>: jmp 0xffffffff818f0cbf <security_file_ioctl+63> 0xffffffff818f0cd5 <+85>: mov %r14,%rdi 0xffffffff818f0cd8 <+88>: mov %ebp,%esi 0xffffffff818f0cda <+90>: mov %rbx,%rdx 0xffffffff818f0cdd <+93>: pop %rbx 0xffffffff818f0cde <+94>: pop %r14 0xffffffff818f0ce0 <+96>: pop %rbp 0xffffffff818f0ce1 <+97>: ret When the config is disabled, the case optimizes the scenario above. security_file_ioctl: 0xffffffff818f0e30 <+0>: endbr64 0xffffffff818f0e34 <+4>: nopl 0x0(%rax,%rax,1) 0xffffffff818f0e39 <+9>: push %rbp 0xffffffff818f0e3a <+10>: push %r14 0xffffffff818f0e3c <+12>: push %rbx 0xffffffff818f0e3d <+13>: mov %rdx,%rbx 0xffffffff818f0e40 <+16>: mov %esi,%ebp 0xffffffff818f0e42 <+18>: mov %rdi,%r14 0xffffffff818f0e45 <+21>: xchg %ax,%ax 0xffffffff818f0e47 <+23>: xchg %ax,%ax The static keys in their disabled state do not create jumps leading to faster code. 0xffffffff818f0e49 <+25>: xor %eax,%eax 0xffffffff818f0e4b <+27>: xchg %ax,%ax 0xffffffff818f0e4d <+29>: pop %rbx 0xffffffff818f0e4e <+30>: pop %r14 0xffffffff818f0e50 <+32>: pop %rbp 0xffffffff818f0e51 <+33>: cs jmp 0xffffffff82c00000 <__x86_return_thunk> 0xffffffff818f0e57 <+39>: endbr64 0xffffffff818f0e5b <+43>: mov %r14,%rdi 0xffffffff818f0e5e <+46>: mov %ebp,%esi 0xffffffff818f0e60 <+48>: mov %rbx,%rdx 0xffffffff818f0e63 <+51>: call 0xffffffff8141e3b0 <bpf_lsm_file_ioctl> 0xffffffff818f0e68 <+56>: test %eax,%eax 0xffffffff818f0e6a <+58>: jne 0xffffffff818f0e4d <security_file_ioctl+29> 0xffffffff818f0e6c <+60>: jmp 0xffffffff818f0e47 <security_file_ioctl+23> 0xffffffff818f0e6e <+62>: endbr64 0xffffffff818f0e72 <+66>: mov %r14,%rdi 0xffffffff818f0e75 <+69>: mov %ebp,%esi 0xffffffff818f0e77 <+71>: mov %rbx,%rdx 0xffffffff818f0e7a <+74>: nopl 0x0(%rax,%rax,1) 0xffffffff818f0e7f <+79>: test %eax,%eax 0xffffffff818f0e81 <+81>: jne 0xffffffff818f0e4d <security_file_ioctl+29> 0xffffffff818f0e83 <+83>: jmp 0xffffffff818f0e49 <security_file_ioctl+25> 0xffffffff818f0e85 <+85>: endbr64 0xffffffff818f0e89 <+89>: mov %r14,%rdi 0xffffffff818f0e8c <+92>: mov %ebp,%esi 0xffffffff818f0e8e <+94>: mov %rbx,%rdx 0xffffffff818f0e91 <+97>: pop %rbx 0xffffffff818f0e92 <+98>: pop %r14 0xffffffff818f0e94 <+100>: pop %rbp 0xffffffff818f0e95 <+101>: ret Signed-off-by: KP Singh <kpsingh@kernel.org> --- security/Kconfig | 11 +++++++++++ security/security.c | 13 ++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/security/Kconfig b/security/Kconfig index 52c9af08ad35..bd2a0dff991a 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -32,6 +32,17 @@ config SECURITY If you are unsure how to answer this question, answer N. +config SECURITY_HOOK_LIKELY + bool "LSM hooks are likely to be initialized" + depends on SECURITY + default y + help + This controls the behaviour of the static keys that guard LSM hooks. + If LSM hooks are likely to be initialized by LSMs, then one gets + better performance by enabling this option. However, if the system is + using an LSM where hooks are much likely to be disabled, one gets + better performance by disabling this config. + config SECURITYFS bool "Enable the securityfs filesystem" help diff --git a/security/security.c b/security/security.c index 4aec25949212..da80a8918e7d 100644 --- a/security/security.c +++ b/security/security.c @@ -99,9 +99,9 @@ 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 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, ...) \ @@ -110,6 +110,9 @@ static __initdata struct lsm_info *exclusive; #undef LSM_HOOK #undef DEFINE_LSM_STATIC_CALL +#define security_hook_active(n, h) \ + static_branch_maybe(CONFIG_SECURITY_HOOK_LIKELY, &SECURITY_HOOK_ACTIVE_KEY(h, n)) + /* * Initialise a table of static calls for each LSM hook. * DEFINE_STATIC_CALL_NULL invocation above generates a key (STATIC_CALL_KEY) @@ -816,7 +819,7 @@ static int lsm_superblock_alloc(struct super_block *sb) */ #define __CALL_STATIC_VOID(NUM, HOOK, ...) \ do { \ - if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ + if (security_hook_active(NUM, HOOK)) { \ static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ } \ } while (0); @@ -828,7 +831,7 @@ do { \ #define __CALL_STATIC_INT(NUM, R, HOOK, LABEL, ...) \ do { \ - if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ + if (security_hook_active(NUM, HOOK)) { \ R = static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ if (R != 0) \ goto LABEL; \ -- 2.41.0.162.gfafddb0af9-goog ^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY 2023-06-16 0:04 ` [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY KP Singh @ 2023-06-16 1:14 ` Casey Schaufler 2023-06-17 15:11 ` KP Singh 2023-06-20 20:58 ` Kees Cook 2023-09-18 13:55 ` Paul Moore 2 siblings, 1 reply; 21+ messages in thread From: Casey Schaufler @ 2023-06-16 1:14 UTC (permalink / raw) To: KP Singh, linux-security-module, bpf Cc: paul, keescook, song, daniel, ast, jannh, Casey Schaufler On 6/15/2023 5:04 PM, KP Singh wrote: > This config influences the nature of the static key that guards the > static call for LSM hooks. > > When enabled, it indicates that an LSM static call slot is more likely > to be initialized. When disabled, it optimizes for the case when static > call slot is more likely to be not initialized. > > When a major LSM like (SELinux, AppArmor, Smack etc) is active on a > system the system would benefit from enabling the config. However there > are other cases which would benefit from the config being disabled > (e.g. a system with a BPF LSM with no hooks enabled by default, or an > LSM like loadpin / yama). Ultimately, there is no one-size fits all > solution. > > with CONFIG_SECURITY_HOOK_LIKELY enabled, the inactive / > uninitialized case is penalized with a direct jmp (still better than > an indirect jmp): > > function security_file_ioctl: > 0xffffffff818f0c80 <+0>: endbr64 > 0xffffffff818f0c84 <+4>: nopl 0x0(%rax,%rax,1) > 0xffffffff818f0c89 <+9>: push %rbp > 0xffffffff818f0c8a <+10>: push %r14 > 0xffffffff818f0c8c <+12>: push %rbx > 0xffffffff818f0c8d <+13>: mov %rdx,%rbx > 0xffffffff818f0c90 <+16>: mov %esi,%ebp > 0xffffffff818f0c92 <+18>: mov %rdi,%r14 > 0xffffffff818f0c95 <+21>: jmp 0xffffffff818f0ca8 <security_file_ioctl+40> > > jump to skip the inactive BPF LSM hook. > > 0xffffffff818f0c97 <+23>: mov %r14,%rdi > 0xffffffff818f0c9a <+26>: mov %ebp,%esi > 0xffffffff818f0c9c <+28>: mov %rbx,%rdx > 0xffffffff818f0c9f <+31>: call 0xffffffff8141e3b0 <bpf_lsm_file_ioctl> > 0xffffffff818f0ca4 <+36>: test %eax,%eax > 0xffffffff818f0ca6 <+38>: jne 0xffffffff818f0cbf <security_file_ioctl+63> > 0xffffffff818f0ca8 <+40>: endbr64 > 0xffffffff818f0cac <+44>: jmp 0xffffffff818f0ccd <security_file_ioctl+77> > > jump to skip the empty slot. > > 0xffffffff818f0cae <+46>: mov %r14,%rdi > 0xffffffff818f0cb1 <+49>: mov %ebp,%esi > 0xffffffff818f0cb3 <+51>: mov %rbx,%rdx > 0xffffffff818f0cb6 <+54>: nopl 0x0(%rax,%rax,1) > ^^^^^^^^^^^^^^^^^^^^^^^ > Empty slot > > 0xffffffff818f0cbb <+59>: test %eax,%eax > 0xffffffff818f0cbd <+61>: je 0xffffffff818f0ccd <security_file_ioctl+77> > 0xffffffff818f0cbf <+63>: endbr64 > 0xffffffff818f0cc3 <+67>: pop %rbx > 0xffffffff818f0cc4 <+68>: pop %r14 > 0xffffffff818f0cc6 <+70>: pop %rbp > 0xffffffff818f0cc7 <+71>: cs jmp 0xffffffff82c00000 <__x86_return_thunk> > 0xffffffff818f0ccd <+77>: endbr64 > 0xffffffff818f0cd1 <+81>: xor %eax,%eax > 0xffffffff818f0cd3 <+83>: jmp 0xffffffff818f0cbf <security_file_ioctl+63> > 0xffffffff818f0cd5 <+85>: mov %r14,%rdi > 0xffffffff818f0cd8 <+88>: mov %ebp,%esi > 0xffffffff818f0cda <+90>: mov %rbx,%rdx > 0xffffffff818f0cdd <+93>: pop %rbx > 0xffffffff818f0cde <+94>: pop %r14 > 0xffffffff818f0ce0 <+96>: pop %rbp > 0xffffffff818f0ce1 <+97>: ret > > When the config is disabled, the case optimizes the scenario above. > > security_file_ioctl: > 0xffffffff818f0e30 <+0>: endbr64 > 0xffffffff818f0e34 <+4>: nopl 0x0(%rax,%rax,1) > 0xffffffff818f0e39 <+9>: push %rbp > 0xffffffff818f0e3a <+10>: push %r14 > 0xffffffff818f0e3c <+12>: push %rbx > 0xffffffff818f0e3d <+13>: mov %rdx,%rbx > 0xffffffff818f0e40 <+16>: mov %esi,%ebp > 0xffffffff818f0e42 <+18>: mov %rdi,%r14 > 0xffffffff818f0e45 <+21>: xchg %ax,%ax > 0xffffffff818f0e47 <+23>: xchg %ax,%ax > > The static keys in their disabled state do not create jumps leading > to faster code. > > 0xffffffff818f0e49 <+25>: xor %eax,%eax > 0xffffffff818f0e4b <+27>: xchg %ax,%ax > 0xffffffff818f0e4d <+29>: pop %rbx > 0xffffffff818f0e4e <+30>: pop %r14 > 0xffffffff818f0e50 <+32>: pop %rbp > 0xffffffff818f0e51 <+33>: cs jmp 0xffffffff82c00000 <__x86_return_thunk> > 0xffffffff818f0e57 <+39>: endbr64 > 0xffffffff818f0e5b <+43>: mov %r14,%rdi > 0xffffffff818f0e5e <+46>: mov %ebp,%esi > 0xffffffff818f0e60 <+48>: mov %rbx,%rdx > 0xffffffff818f0e63 <+51>: call 0xffffffff8141e3b0 <bpf_lsm_file_ioctl> > 0xffffffff818f0e68 <+56>: test %eax,%eax > 0xffffffff818f0e6a <+58>: jne 0xffffffff818f0e4d <security_file_ioctl+29> > 0xffffffff818f0e6c <+60>: jmp 0xffffffff818f0e47 <security_file_ioctl+23> > 0xffffffff818f0e6e <+62>: endbr64 > 0xffffffff818f0e72 <+66>: mov %r14,%rdi > 0xffffffff818f0e75 <+69>: mov %ebp,%esi > 0xffffffff818f0e77 <+71>: mov %rbx,%rdx > 0xffffffff818f0e7a <+74>: nopl 0x0(%rax,%rax,1) > 0xffffffff818f0e7f <+79>: test %eax,%eax > 0xffffffff818f0e81 <+81>: jne 0xffffffff818f0e4d <security_file_ioctl+29> > 0xffffffff818f0e83 <+83>: jmp 0xffffffff818f0e49 <security_file_ioctl+25> > 0xffffffff818f0e85 <+85>: endbr64 > 0xffffffff818f0e89 <+89>: mov %r14,%rdi > 0xffffffff818f0e8c <+92>: mov %ebp,%esi > 0xffffffff818f0e8e <+94>: mov %rbx,%rdx > 0xffffffff818f0e91 <+97>: pop %rbx > 0xffffffff818f0e92 <+98>: pop %r14 > 0xffffffff818f0e94 <+100>: pop %rbp > 0xffffffff818f0e95 <+101>: ret > > Signed-off-by: KP Singh <kpsingh@kernel.org> > --- > security/Kconfig | 11 +++++++++++ > security/security.c | 13 ++++++++----- > 2 files changed, 19 insertions(+), 5 deletions(-) > > diff --git a/security/Kconfig b/security/Kconfig > index 52c9af08ad35..bd2a0dff991a 100644 > --- a/security/Kconfig > +++ b/security/Kconfig > @@ -32,6 +32,17 @@ config SECURITY > > If you are unsure how to answer this question, answer N. > > +config SECURITY_HOOK_LIKELY > + bool "LSM hooks are likely to be initialized" > + depends on SECURITY > + default y > + help > + This controls the behaviour of the static keys that guard LSM hooks. > + If LSM hooks are likely to be initialized by LSMs, then one gets > + better performance by enabling this option. However, if the system is > + using an LSM where hooks are much likely to be disabled, one gets > + better performance by disabling this config. > + > config SECURITYFS > bool "Enable the securityfs filesystem" > help > diff --git a/security/security.c b/security/security.c > index 4aec25949212..da80a8918e7d 100644 > --- a/security/security.c > +++ b/security/security.c > @@ -99,9 +99,9 @@ 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 DEFINE_LSM_STATIC_CALL(NUM, NAME, RET, ...) \ > + DEFINE_STATIC_CALL_NULL(LSM_STATIC_CALL(NAME, NUM), \ > + *((RET(*)(__VA_ARGS__))NULL)); \ This is just a cosmetic change, right? Please fix it in the original patch when you respin, not here. I spent way to long trying to figure out why you had to make a change. > DEFINE_STATIC_KEY_FALSE(SECURITY_HOOK_ACTIVE_KEY(NAME, NUM)); > > #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ > @@ -110,6 +110,9 @@ static __initdata struct lsm_info *exclusive; > #undef LSM_HOOK > #undef DEFINE_LSM_STATIC_CALL > > +#define security_hook_active(n, h) \ > + static_branch_maybe(CONFIG_SECURITY_HOOK_LIKELY, &SECURITY_HOOK_ACTIVE_KEY(h, n)) > + Please don't use the security_ prefix here. It's a local macro, use hook_active() or, if you must, lsm_hook_active(). > /* > * Initialise a table of static calls for each LSM hook. > * DEFINE_STATIC_CALL_NULL invocation above generates a key (STATIC_CALL_KEY) > @@ -816,7 +819,7 @@ static int lsm_superblock_alloc(struct super_block *sb) > */ > #define __CALL_STATIC_VOID(NUM, HOOK, ...) \ > do { \ > - if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ > + if (security_hook_active(NUM, HOOK)) { \ > static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ > } \ > } while (0); > @@ -828,7 +831,7 @@ do { \ > > #define __CALL_STATIC_INT(NUM, R, HOOK, LABEL, ...) \ > do { \ > - if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ > + if (security_hook_active(NUM, HOOK)) { \ > R = static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ > if (R != 0) \ > goto LABEL; \ ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY 2023-06-16 1:14 ` Casey Schaufler @ 2023-06-17 15:11 ` KP Singh 0 siblings, 0 replies; 21+ messages in thread From: KP Singh @ 2023-06-17 15:11 UTC (permalink / raw) To: Casey Schaufler Cc: linux-security-module, bpf, paul, keescook, song, daniel, ast, jannh On Fri, Jun 16, 2023 at 3:15 AM Casey Schaufler <casey@schaufler-ca.com> wrote: > > On 6/15/2023 5:04 PM, KP Singh wrote: > > This config influences the nature of the static key that guards the > > static call for LSM hooks. > > > > When enabled, it indicates that an LSM static call slot is more likely > > to be initialized. When disabled, it optimizes for the case when static > > call slot is more likely to be not initialized. > > > > When a major LSM like (SELinux, AppArmor, Smack etc) is active on a > > system the system would benefit from enabling the config. However there > > are other cases which would benefit from the config being disabled > > (e.g. a system with a BPF LSM with no hooks enabled by default, or an > > LSM like loadpin / yama). Ultimately, there is no one-size fits all > > solution. > > > > with CONFIG_SECURITY_HOOK_LIKELY enabled, the inactive / > > uninitialized case is penalized with a direct jmp (still better than > > an indirect jmp): > > > > function security_file_ioctl: > > 0xffffffff818f0c80 <+0>: endbr64 > > 0xffffffff818f0c84 <+4>: nopl 0x0(%rax,%rax,1) > > 0xffffffff818f0c89 <+9>: push %rbp > > 0xffffffff818f0c8a <+10>: push %r14 > > 0xffffffff818f0c8c <+12>: push %rbx > > 0xffffffff818f0c8d <+13>: mov %rdx,%rbx > > 0xffffffff818f0c90 <+16>: mov %esi,%ebp > > 0xffffffff818f0c92 <+18>: mov %rdi,%r14 > > 0xffffffff818f0c95 <+21>: jmp 0xffffffff818f0ca8 <security_file_ioctl+40> > > > > jump to skip the inactive BPF LSM hook. > > > > 0xffffffff818f0c97 <+23>: mov %r14,%rdi > > 0xffffffff818f0c9a <+26>: mov %ebp,%esi > > 0xffffffff818f0c9c <+28>: mov %rbx,%rdx > > 0xffffffff818f0c9f <+31>: call 0xffffffff8141e3b0 <bpf_lsm_file_ioctl> > > 0xffffffff818f0ca4 <+36>: test %eax,%eax > > 0xffffffff818f0ca6 <+38>: jne 0xffffffff818f0cbf <security_file_ioctl+63> > > 0xffffffff818f0ca8 <+40>: endbr64 > > 0xffffffff818f0cac <+44>: jmp 0xffffffff818f0ccd <security_file_ioctl+77> > > > > jump to skip the empty slot. > > > > 0xffffffff818f0cae <+46>: mov %r14,%rdi > > 0xffffffff818f0cb1 <+49>: mov %ebp,%esi > > 0xffffffff818f0cb3 <+51>: mov %rbx,%rdx > > 0xffffffff818f0cb6 <+54>: nopl 0x0(%rax,%rax,1) > > ^^^^^^^^^^^^^^^^^^^^^^^ > > Empty slot > > > > 0xffffffff818f0cbb <+59>: test %eax,%eax > > 0xffffffff818f0cbd <+61>: je 0xffffffff818f0ccd <security_file_ioctl+77> > > 0xffffffff818f0cbf <+63>: endbr64 > > 0xffffffff818f0cc3 <+67>: pop %rbx > > 0xffffffff818f0cc4 <+68>: pop %r14 > > 0xffffffff818f0cc6 <+70>: pop %rbp > > 0xffffffff818f0cc7 <+71>: cs jmp 0xffffffff82c00000 <__x86_return_thunk> > > 0xffffffff818f0ccd <+77>: endbr64 > > 0xffffffff818f0cd1 <+81>: xor %eax,%eax > > 0xffffffff818f0cd3 <+83>: jmp 0xffffffff818f0cbf <security_file_ioctl+63> > > 0xffffffff818f0cd5 <+85>: mov %r14,%rdi > > 0xffffffff818f0cd8 <+88>: mov %ebp,%esi > > 0xffffffff818f0cda <+90>: mov %rbx,%rdx > > 0xffffffff818f0cdd <+93>: pop %rbx > > 0xffffffff818f0cde <+94>: pop %r14 > > 0xffffffff818f0ce0 <+96>: pop %rbp > > 0xffffffff818f0ce1 <+97>: ret > > > > When the config is disabled, the case optimizes the scenario above. > > > > security_file_ioctl: > > 0xffffffff818f0e30 <+0>: endbr64 > > 0xffffffff818f0e34 <+4>: nopl 0x0(%rax,%rax,1) > > 0xffffffff818f0e39 <+9>: push %rbp > > 0xffffffff818f0e3a <+10>: push %r14 > > 0xffffffff818f0e3c <+12>: push %rbx > > 0xffffffff818f0e3d <+13>: mov %rdx,%rbx > > 0xffffffff818f0e40 <+16>: mov %esi,%ebp > > 0xffffffff818f0e42 <+18>: mov %rdi,%r14 > > 0xffffffff818f0e45 <+21>: xchg %ax,%ax > > 0xffffffff818f0e47 <+23>: xchg %ax,%ax > > > > The static keys in their disabled state do not create jumps leading > > to faster code. > > > > 0xffffffff818f0e49 <+25>: xor %eax,%eax > > 0xffffffff818f0e4b <+27>: xchg %ax,%ax > > 0xffffffff818f0e4d <+29>: pop %rbx > > 0xffffffff818f0e4e <+30>: pop %r14 > > 0xffffffff818f0e50 <+32>: pop %rbp > > 0xffffffff818f0e51 <+33>: cs jmp 0xffffffff82c00000 <__x86_return_thunk> > > 0xffffffff818f0e57 <+39>: endbr64 > > 0xffffffff818f0e5b <+43>: mov %r14,%rdi > > 0xffffffff818f0e5e <+46>: mov %ebp,%esi > > 0xffffffff818f0e60 <+48>: mov %rbx,%rdx > > 0xffffffff818f0e63 <+51>: call 0xffffffff8141e3b0 <bpf_lsm_file_ioctl> > > 0xffffffff818f0e68 <+56>: test %eax,%eax > > 0xffffffff818f0e6a <+58>: jne 0xffffffff818f0e4d <security_file_ioctl+29> > > 0xffffffff818f0e6c <+60>: jmp 0xffffffff818f0e47 <security_file_ioctl+23> > > 0xffffffff818f0e6e <+62>: endbr64 > > 0xffffffff818f0e72 <+66>: mov %r14,%rdi > > 0xffffffff818f0e75 <+69>: mov %ebp,%esi > > 0xffffffff818f0e77 <+71>: mov %rbx,%rdx > > 0xffffffff818f0e7a <+74>: nopl 0x0(%rax,%rax,1) > > 0xffffffff818f0e7f <+79>: test %eax,%eax > > 0xffffffff818f0e81 <+81>: jne 0xffffffff818f0e4d <security_file_ioctl+29> > > 0xffffffff818f0e83 <+83>: jmp 0xffffffff818f0e49 <security_file_ioctl+25> > > 0xffffffff818f0e85 <+85>: endbr64 > > 0xffffffff818f0e89 <+89>: mov %r14,%rdi > > 0xffffffff818f0e8c <+92>: mov %ebp,%esi > > 0xffffffff818f0e8e <+94>: mov %rbx,%rdx > > 0xffffffff818f0e91 <+97>: pop %rbx > > 0xffffffff818f0e92 <+98>: pop %r14 > > 0xffffffff818f0e94 <+100>: pop %rbp > > 0xffffffff818f0e95 <+101>: ret > > > > Signed-off-by: KP Singh <kpsingh@kernel.org> > > --- > > security/Kconfig | 11 +++++++++++ > > security/security.c | 13 ++++++++----- > > 2 files changed, 19 insertions(+), 5 deletions(-) > > > > diff --git a/security/Kconfig b/security/Kconfig > > index 52c9af08ad35..bd2a0dff991a 100644 > > --- a/security/Kconfig > > +++ b/security/Kconfig > > @@ -32,6 +32,17 @@ config SECURITY > > > > If you are unsure how to answer this question, answer N. > > > > +config SECURITY_HOOK_LIKELY > > + bool "LSM hooks are likely to be initialized" > > + depends on SECURITY > > + default y > > + help > > + This controls the behaviour of the static keys that guard LSM hooks. > > + If LSM hooks are likely to be initialized by LSMs, then one gets > > + better performance by enabling this option. However, if the system is > > + using an LSM where hooks are much likely to be disabled, one gets > > + better performance by disabling this config. > > + > > config SECURITYFS > > bool "Enable the securityfs filesystem" > > help > > diff --git a/security/security.c b/security/security.c > > index 4aec25949212..da80a8918e7d 100644 > > --- a/security/security.c > > +++ b/security/security.c > > @@ -99,9 +99,9 @@ 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 DEFINE_LSM_STATIC_CALL(NUM, NAME, RET, ...) \ > > + DEFINE_STATIC_CALL_NULL(LSM_STATIC_CALL(NAME, NUM), \ > > + *((RET(*)(__VA_ARGS__))NULL)); \ > > This is just a cosmetic change, right? Please fix it in the original > patch when you respin, not here. I spent way to long trying to figure out > why you had to make a change. Sorry about this, I will fix it when I respin. > > > DEFINE_STATIC_KEY_FALSE(SECURITY_HOOK_ACTIVE_KEY(NAME, NUM)); > > > > #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ > > @@ -110,6 +110,9 @@ static __initdata struct lsm_info *exclusive; > > #undef LSM_HOOK > > #undef DEFINE_LSM_STATIC_CALL > > > > +#define security_hook_active(n, h) \ > > + static_branch_maybe(CONFIG_SECURITY_HOOK_LIKELY, &SECURITY_HOOK_ACTIVE_KEY(h, n)) > > + > > Please don't use the security_ prefix here. It's a local macro, use hook_active() > or, if you must, lsm_hook_active(). Ack, will use lsm_hook_active. > > > /* > > * Initialise a table of static calls for each LSM hook. > > * DEFINE_STATIC_CALL_NULL invocation above generates a key (STATIC_CALL_KEY) > > @@ -816,7 +819,7 @@ static int lsm_superblock_alloc(struct super_block *sb) > > */ > > #define __CALL_STATIC_VOID(NUM, HOOK, ...) \ > > do { \ > > - if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ > > + if (security_hook_active(NUM, HOOK)) { \ > > static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ > > } \ > > } while (0); > > @@ -828,7 +831,7 @@ do { \ > > > > #define __CALL_STATIC_INT(NUM, R, HOOK, LABEL, ...) \ > > do { \ > > - if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ > > + if (security_hook_active(NUM, HOOK)) { \ > > R = static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ > > if (R != 0) \ > > goto LABEL; \ ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY 2023-06-16 0:04 ` [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY KP Singh 2023-06-16 1:14 ` Casey Schaufler @ 2023-06-20 20:58 ` Kees Cook 2023-09-18 13:27 ` KP Singh 2023-09-18 13:55 ` Paul Moore 2 siblings, 1 reply; 21+ messages in thread From: Kees Cook @ 2023-06-20 20:58 UTC (permalink / raw) To: KP Singh Cc: linux-security-module, bpf, paul, casey, song, daniel, ast, jannh On Fri, Jun 16, 2023 at 02:04:41AM +0200, KP Singh wrote: > [...] > @@ -110,6 +110,9 @@ static __initdata struct lsm_info *exclusive; > #undef LSM_HOOK > #undef DEFINE_LSM_STATIC_CALL > > +#define security_hook_active(n, h) \ > + static_branch_maybe(CONFIG_SECURITY_HOOK_LIKELY, &SECURITY_HOOK_ACTIVE_KEY(h, n)) > + > /* > * Initialise a table of static calls for each LSM hook. > * DEFINE_STATIC_CALL_NULL invocation above generates a key (STATIC_CALL_KEY) > @@ -816,7 +819,7 @@ static int lsm_superblock_alloc(struct super_block *sb) > */ > #define __CALL_STATIC_VOID(NUM, HOOK, ...) \ > do { \ > - if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ > + if (security_hook_active(NUM, HOOK)) { \ > static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ > } \ > } while (0); > @@ -828,7 +831,7 @@ do { \ > > #define __CALL_STATIC_INT(NUM, R, HOOK, LABEL, ...) \ > do { \ > - if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ > + if (security_hook_active(NUM, HOOK)) { \ > R = static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ > if (R != 0) \ > goto LABEL; \ I actually think I'd prefer there be no macro wrapping static_branch_maybe(), just for reading it more easily. i.e. people reading this code are going to expect the static_branch/static_call code patterns, and seeing "security_hook_active" only slows them down in understanding it. I don't think it's _that_ ugly to have it all typed out. e.g.: if (static_branch_maybe(CONFIG_SECURITY_HOOK_LIKELY, \ &SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM)) { \ R = static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ if (R != 0) \ goto LABEL; \ -- Kees Cook ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY 2023-06-20 20:58 ` Kees Cook @ 2023-09-18 13:27 ` KP Singh 0 siblings, 0 replies; 21+ messages in thread From: KP Singh @ 2023-09-18 13:27 UTC (permalink / raw) To: Kees Cook Cc: linux-security-module, bpf, paul, casey, song, daniel, ast, jannh On Tue, Jun 20, 2023 at 10:59 PM Kees Cook <keescook@chromium.org> wrote: > > On Fri, Jun 16, 2023 at 02:04:41AM +0200, KP Singh wrote: > > [...] > > @@ -110,6 +110,9 @@ static __initdata struct lsm_info *exclusive; > > #undef LSM_HOOK > > #undef DEFINE_LSM_STATIC_CALL > > > > +#define security_hook_active(n, h) \ > > + static_branch_maybe(CONFIG_SECURITY_HOOK_LIKELY, &SECURITY_HOOK_ACTIVE_KEY(h, n)) > > + > > /* > > * Initialise a table of static calls for each LSM hook. > > * DEFINE_STATIC_CALL_NULL invocation above generates a key (STATIC_CALL_KEY) > > @@ -816,7 +819,7 @@ static int lsm_superblock_alloc(struct super_block *sb) > > */ > > #define __CALL_STATIC_VOID(NUM, HOOK, ...) \ > > do { \ > > - if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ > > + if (security_hook_active(NUM, HOOK)) { \ > > static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ > > } \ > > } while (0); > > @@ -828,7 +831,7 @@ do { \ > > > > #define __CALL_STATIC_INT(NUM, R, HOOK, LABEL, ...) \ > > do { \ > > - if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ > > + if (security_hook_active(NUM, HOOK)) { \ > > R = static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ > > if (R != 0) \ > > goto LABEL; \ > > I actually think I'd prefer there be no macro wrapping > static_branch_maybe(), just for reading it more easily. i.e. people > reading this code are going to expect the static_branch/static_call code > patterns, and seeing "security_hook_active" only slows them down in > understanding it. I don't think it's _that_ ugly to have it all typed > out. e.g.: Done and agreed, especially given that this is behind a macro anyways. > > if (static_branch_maybe(CONFIG_SECURITY_HOOK_LIKELY, \ > &SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM)) { \ > R = static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ > if (R != 0) \ > goto LABEL; \ > > > > -- > Kees Cook ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY 2023-06-16 0:04 ` [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY KP Singh 2023-06-16 1:14 ` Casey Schaufler 2023-06-20 20:58 ` Kees Cook @ 2023-09-18 13:55 ` Paul Moore 2023-09-18 16:28 ` KP Singh 2 siblings, 1 reply; 21+ messages in thread From: Paul Moore @ 2023-09-18 13:55 UTC (permalink / raw) To: KP Singh Cc: linux-security-module, bpf, keescook, casey, song, daniel, ast, jannh On Thu, Jun 15, 2023 at 8:05 PM KP Singh <kpsingh@kernel.org> wrote: > > This config influences the nature of the static key that guards the > static call for LSM hooks. No further comment on the rest of this patch series yet, this just happened to bubble to the top of my inbox and I wanted to comment quickly - I'm not in favor of adding a Kconfig option for something like this. If you have an extremely well defined use case then you can probably do the work to figure out the "correct" value for the tunable, but for a general purpose kernel build that will have different LSMs active, a variety of different BPF LSM hook implementations at different times, etc. there is little hope to getting this right. No thank you. -- paul-moore.com ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY 2023-09-18 13:55 ` Paul Moore @ 2023-09-18 16:28 ` KP Singh 0 siblings, 0 replies; 21+ messages in thread From: KP Singh @ 2023-09-18 16:28 UTC (permalink / raw) To: Paul Moore Cc: linux-security-module, bpf, keescook, casey, song, daniel, ast, jannh On Mon, Sep 18, 2023 at 3:56 PM Paul Moore <paul@paul-moore.com> wrote: > > On Thu, Jun 15, 2023 at 8:05 PM KP Singh <kpsingh@kernel.org> wrote: > > > > This config influences the nature of the static key that guards the > > static call for LSM hooks. > > No further comment on the rest of this patch series yet, this just > happened to bubble to the top of my inbox and I wanted to comment > quickly - I'm not in favor of adding a Kconfig option for something I understand, I will send the v3 with the patch for reference and we can drop it, if that's the consensus. > like this. If you have an extremely well defined use case then you > can probably do the work to figure out the "correct" value for the > tunable, but for a general purpose kernel build that will have > different LSMs active, a variety of different BPF LSM hook > implementations at different times, etc. there is little hope to > getting this right. No thank you. > > -- > paul-moore.com ^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2023-09-18 17:07 UTC | newest] Thread overview: 21+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-06-16 0:04 [PATCH v2 0/5] Reduce overhead of LSMs with static calls KP Singh 2023-06-16 0:04 ` [PATCH v2 1/5] kernel: Add helper macros for loop unrolling KP Singh 2023-06-16 0:04 ` [PATCH v2 2/5] security: Count the LSMs enabled at compile time KP Singh 2023-06-16 0:38 ` Casey Schaufler 2023-06-16 22:27 ` Andrii Nakryiko 2023-09-16 0:54 ` KP Singh 2023-06-16 0:04 ` [PATCH v2 3/5] security: Replace indirect LSM hook calls with static calls KP Singh 2023-06-16 1:05 ` Casey Schaufler 2023-06-17 15:09 ` KP Singh 2023-06-16 3:41 ` kernel test robot 2023-06-16 21:09 ` kernel test robot 2023-06-17 15:39 ` KP Singh 2023-06-20 21:53 ` Kees Cook 2023-06-16 0:04 ` [PATCH v2 4/5] bpf: Only enable BPF LSM hooks when an LSM program is attached KP Singh 2023-06-16 0:04 ` [PATCH v2 5/5] security: Add CONFIG_SECURITY_HOOK_LIKELY KP Singh 2023-06-16 1:14 ` Casey Schaufler 2023-06-17 15:11 ` KP Singh 2023-06-20 20:58 ` Kees Cook 2023-09-18 13:27 ` KP Singh 2023-09-18 13:55 ` Paul Moore 2023-09-18 16:28 ` KP Singh
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).