* [PATCH v2 2/2] stack: Constrain and fix stack offset randomization with Clang builds
2022-01-31 9:05 [PATCH v2 1/2] stack: Introduce CONFIG_RANDOMIZE_KSTACK_OFFSET Marco Elver
@ 2022-01-31 9:05 ` Marco Elver
2022-01-31 21:15 ` Kees Cook
2022-01-31 21:14 ` [PATCH v2 1/2] stack: Introduce CONFIG_RANDOMIZE_KSTACK_OFFSET Kees Cook
` (2 subsequent siblings)
3 siblings, 1 reply; 7+ messages in thread
From: Marco Elver @ 2022-01-31 9:05 UTC (permalink / raw)
To: elver, Thomas Gleixner, Kees Cook
Cc: Peter Zijlstra, Ingo Molnar, Elena Reshetova, Nathan Chancellor,
Nick Desaulniers, Alexander Potapenko, llvm, kasan-dev,
linux-kernel
All supported versions of Clang perform auto-init of __builtin_alloca()
when stack auto-init is on (CONFIG_INIT_STACK_ALL_{ZERO,PATTERN}).
add_random_kstack_offset() uses __builtin_alloca() to add a stack
offset. This means, when CONFIG_INIT_STACK_ALL_{ZERO,PATTERN} is
enabled, add_random_kstack_offset() will auto-init that unused portion
of the stack used to add an offset.
There are several problems with this:
1. These offsets can be as large as 1023 bytes. Performing
memset() on them isn't exactly cheap, and this is done on
every syscall entry.
2. Architectures adding add_random_kstack_offset() to syscall
entry implemented in C require them to be 'noinstr' (e.g. see
x86 and s390). The potential problem here is that a call to
memset may occur, which is not noinstr.
A x86_64 defconfig kernel with Clang 11 and CONFIG_VMLINUX_VALIDATION shows:
| vmlinux.o: warning: objtool: do_syscall_64()+0x9d: call to memset() leaves .noinstr.text section
| vmlinux.o: warning: objtool: do_int80_syscall_32()+0xab: call to memset() leaves .noinstr.text section
| vmlinux.o: warning: objtool: __do_fast_syscall_32()+0xe2: call to memset() leaves .noinstr.text section
| vmlinux.o: warning: objtool: fixup_bad_iret()+0x2f: call to memset() leaves .noinstr.text section
Clang 14 (unreleased) will introduce a way to skip alloca initialization
via __builtin_alloca_uninitialized() (https://reviews.llvm.org/D115440).
Constrain RANDOMIZE_KSTACK_OFFSET to only be enabled if no stack
auto-init is enabled, the compiler is GCC, or Clang is version 14+. Use
__builtin_alloca_uninitialized() if the compiler provides it, as is done
by Clang 14.
Link: https://lkml.kernel.org/r/YbHTKUjEejZCLyhX@elver.google.com
Fixes: 39218ff4c625 ("stack: Optionally randomize kernel stack offset each syscall")
Signed-off-by: Marco Elver <elver@google.com>
Reviewed-by: Nathan Chancellor <nathan@kernel.org>
---
v2:
* Update comment to point out which compilers initialize allocas.
---
arch/Kconfig | 1 +
include/linux/randomize_kstack.h | 16 ++++++++++++++--
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/arch/Kconfig b/arch/Kconfig
index 2cde48d9b77c..c5b50bfe31c1 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -1163,6 +1163,7 @@ config RANDOMIZE_KSTACK_OFFSET
bool "Support for randomizing kernel stack offset on syscall entry" if EXPERT
default y
depends on HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
+ depends on INIT_STACK_NONE || !CC_IS_CLANG || CLANG_VERSION >= 140000
help
The kernel stack offset can be randomized (after pt_regs) by
roughly 5 bits of entropy, frustrating memory corruption
diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kstack.h
index 91f1b990a3c3..1468caf001c0 100644
--- a/include/linux/randomize_kstack.h
+++ b/include/linux/randomize_kstack.h
@@ -17,8 +17,20 @@ DECLARE_PER_CPU(u32, kstack_offset);
* alignment. Also, since this use is being explicitly masked to a max of
* 10 bits, stack-clash style attacks are unlikely. For more details see
* "VLAs" in Documentation/process/deprecated.rst
+ *
+ * The normal __builtin_alloca() is initialized with INIT_STACK_ALL (currently
+ * only with Clang and not GCC). Initializing the unused area on each syscall
+ * entry is expensive, and generating an implicit call to memset() may also be
+ * problematic (such as in noinstr functions). Therefore, if the compiler
+ * supports it (which it should if it initializes allocas), always use the
+ * "uninitialized" variant of the builtin.
*/
-void *__builtin_alloca(size_t size);
+#if __has_builtin(__builtin_alloca_uninitialized)
+#define __kstack_alloca __builtin_alloca_uninitialized
+#else
+#define __kstack_alloca __builtin_alloca
+#endif
+
/*
* Use, at most, 10 bits of entropy. We explicitly cap this to keep the
* "VLA" from being unbounded (see above). 10 bits leaves enough room for
@@ -37,7 +49,7 @@ void *__builtin_alloca(size_t size);
if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \
&randomize_kstack_offset)) { \
u32 offset = raw_cpu_read(kstack_offset); \
- u8 *ptr = __builtin_alloca(KSTACK_OFFSET_MAX(offset)); \
+ u8 *ptr = __kstack_alloca(KSTACK_OFFSET_MAX(offset)); \
/* Keep allocation even after "ptr" loses scope. */ \
asm volatile("" :: "r"(ptr) : "memory"); \
} \
--
2.35.0.rc2.247.g8bbb082509-goog
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v2 2/2] stack: Constrain and fix stack offset randomization with Clang builds
2022-01-31 9:05 ` [PATCH v2 2/2] stack: Constrain and fix stack offset randomization with Clang builds Marco Elver
@ 2022-01-31 21:15 ` Kees Cook
2022-02-01 11:18 ` Marco Elver
0 siblings, 1 reply; 7+ messages in thread
From: Kees Cook @ 2022-01-31 21:15 UTC (permalink / raw)
To: Marco Elver
Cc: Thomas Gleixner, Peter Zijlstra, Ingo Molnar, Elena Reshetova,
Nathan Chancellor, Nick Desaulniers, Alexander Potapenko, llvm,
kasan-dev, linux-kernel
On Mon, Jan 31, 2022 at 10:05:21AM +0100, Marco Elver wrote:
> All supported versions of Clang perform auto-init of __builtin_alloca()
> when stack auto-init is on (CONFIG_INIT_STACK_ALL_{ZERO,PATTERN}).
>
> add_random_kstack_offset() uses __builtin_alloca() to add a stack
> offset. This means, when CONFIG_INIT_STACK_ALL_{ZERO,PATTERN} is
> enabled, add_random_kstack_offset() will auto-init that unused portion
> of the stack used to add an offset.
>
> There are several problems with this:
>
> 1. These offsets can be as large as 1023 bytes. Performing
> memset() on them isn't exactly cheap, and this is done on
> every syscall entry.
>
> 2. Architectures adding add_random_kstack_offset() to syscall
> entry implemented in C require them to be 'noinstr' (e.g. see
> x86 and s390). The potential problem here is that a call to
> memset may occur, which is not noinstr.
>
> A x86_64 defconfig kernel with Clang 11 and CONFIG_VMLINUX_VALIDATION shows:
>
> | vmlinux.o: warning: objtool: do_syscall_64()+0x9d: call to memset() leaves .noinstr.text section
> | vmlinux.o: warning: objtool: do_int80_syscall_32()+0xab: call to memset() leaves .noinstr.text section
> | vmlinux.o: warning: objtool: __do_fast_syscall_32()+0xe2: call to memset() leaves .noinstr.text section
> | vmlinux.o: warning: objtool: fixup_bad_iret()+0x2f: call to memset() leaves .noinstr.text section
>
> Clang 14 (unreleased) will introduce a way to skip alloca initialization
> via __builtin_alloca_uninitialized() (https://reviews.llvm.org/D115440).
>
> Constrain RANDOMIZE_KSTACK_OFFSET to only be enabled if no stack
> auto-init is enabled, the compiler is GCC, or Clang is version 14+. Use
> __builtin_alloca_uninitialized() if the compiler provides it, as is done
> by Clang 14.
>
> Link: https://lkml.kernel.org/r/YbHTKUjEejZCLyhX@elver.google.com
> Fixes: 39218ff4c625 ("stack: Optionally randomize kernel stack offset each syscall")
> Signed-off-by: Marco Elver <elver@google.com>
Thanks for the tweaks; this looks good to me now.
Acked-by: Kees Cook <keescook@chromium.org>
--
Kees Cook
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH v2 2/2] stack: Constrain and fix stack offset randomization with Clang builds
2022-01-31 21:15 ` Kees Cook
@ 2022-02-01 11:18 ` Marco Elver
0 siblings, 0 replies; 7+ messages in thread
From: Marco Elver @ 2022-02-01 11:18 UTC (permalink / raw)
To: Kees Cook
Cc: Thomas Gleixner, Peter Zijlstra, Ingo Molnar, Elena Reshetova,
Nathan Chancellor, Nick Desaulniers, Alexander Potapenko, llvm,
kasan-dev, linux-kernel
On Mon, 31 Jan 2022 at 22:15, Kees Cook <keescook@chromium.org> wrote:
> On Mon, Jan 31, 2022 at 10:05:21AM +0100, Marco Elver wrote:
> > All supported versions of Clang perform auto-init of __builtin_alloca()
> > when stack auto-init is on (CONFIG_INIT_STACK_ALL_{ZERO,PATTERN}).
> >
> > add_random_kstack_offset() uses __builtin_alloca() to add a stack
> > offset. This means, when CONFIG_INIT_STACK_ALL_{ZERO,PATTERN} is
> > enabled, add_random_kstack_offset() will auto-init that unused portion
> > of the stack used to add an offset.
> >
> > There are several problems with this:
> >
> > 1. These offsets can be as large as 1023 bytes. Performing
> > memset() on them isn't exactly cheap, and this is done on
> > every syscall entry.
> >
> > 2. Architectures adding add_random_kstack_offset() to syscall
> > entry implemented in C require them to be 'noinstr' (e.g. see
> > x86 and s390). The potential problem here is that a call to
> > memset may occur, which is not noinstr.
> >
> > A x86_64 defconfig kernel with Clang 11 and CONFIG_VMLINUX_VALIDATION shows:
> >
> > | vmlinux.o: warning: objtool: do_syscall_64()+0x9d: call to memset() leaves .noinstr.text section
> > | vmlinux.o: warning: objtool: do_int80_syscall_32()+0xab: call to memset() leaves .noinstr.text section
> > | vmlinux.o: warning: objtool: __do_fast_syscall_32()+0xe2: call to memset() leaves .noinstr.text section
> > | vmlinux.o: warning: objtool: fixup_bad_iret()+0x2f: call to memset() leaves .noinstr.text section
> >
> > Clang 14 (unreleased) will introduce a way to skip alloca initialization
> > via __builtin_alloca_uninitialized() (https://reviews.llvm.org/D115440).
> >
> > Constrain RANDOMIZE_KSTACK_OFFSET to only be enabled if no stack
> > auto-init is enabled, the compiler is GCC, or Clang is version 14+. Use
> > __builtin_alloca_uninitialized() if the compiler provides it, as is done
> > by Clang 14.
> >
> > Link: https://lkml.kernel.org/r/YbHTKUjEejZCLyhX@elver.google.com
> > Fixes: 39218ff4c625 ("stack: Optionally randomize kernel stack offset each syscall")
> > Signed-off-by: Marco Elver <elver@google.com>
>
> Thanks for the tweaks; this looks good to me now.
>
> Acked-by: Kees Cook <keescook@chromium.org>
Kees, which tree do randomize_kstack changes go through these days?
I've seen previous patches went through -tip via Thomas.
Thanks,
-- Marco
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] stack: Introduce CONFIG_RANDOMIZE_KSTACK_OFFSET
2022-01-31 9:05 [PATCH v2 1/2] stack: Introduce CONFIG_RANDOMIZE_KSTACK_OFFSET Marco Elver
2022-01-31 9:05 ` [PATCH v2 2/2] stack: Constrain and fix stack offset randomization with Clang builds Marco Elver
@ 2022-01-31 21:14 ` Kees Cook
2022-02-01 10:34 ` Peter Zijlstra
2022-02-14 19:14 ` Kees Cook
3 siblings, 0 replies; 7+ messages in thread
From: Kees Cook @ 2022-01-31 21:14 UTC (permalink / raw)
To: Marco Elver
Cc: Thomas Gleixner, Peter Zijlstra, Ingo Molnar, Elena Reshetova,
Nathan Chancellor, Nick Desaulniers, Alexander Potapenko, llvm,
kasan-dev, linux-kernel
On Mon, Jan 31, 2022 at 10:05:20AM +0100, Marco Elver wrote:
> The randomize_kstack_offset feature is unconditionally compiled in when
> the architecture supports it.
>
> To add constraints on compiler versions, we require a dedicated Kconfig
> variable. Therefore, introduce RANDOMIZE_KSTACK_OFFSET.
>
> Furthermore, this option is now also configurable by EXPERT kernels:
> while the feature is supposed to have zero performance overhead when
> disabled, due to its use of static branches, there are few cases where
> giving a distribution the option to disable the feature entirely makes
> sense. For example, in very resource constrained environments, which
> would never enable the feature to begin with, in which case the
> additional kernel code size increase would be redundant.
>
> Signed-off-by: Marco Elver <elver@google.com>
Acked-by: Kees Cook <keescook@chromium.org>
--
Kees Cook
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] stack: Introduce CONFIG_RANDOMIZE_KSTACK_OFFSET
2022-01-31 9:05 [PATCH v2 1/2] stack: Introduce CONFIG_RANDOMIZE_KSTACK_OFFSET Marco Elver
2022-01-31 9:05 ` [PATCH v2 2/2] stack: Constrain and fix stack offset randomization with Clang builds Marco Elver
2022-01-31 21:14 ` [PATCH v2 1/2] stack: Introduce CONFIG_RANDOMIZE_KSTACK_OFFSET Kees Cook
@ 2022-02-01 10:34 ` Peter Zijlstra
2022-02-14 19:14 ` Kees Cook
3 siblings, 0 replies; 7+ messages in thread
From: Peter Zijlstra @ 2022-02-01 10:34 UTC (permalink / raw)
To: Marco Elver
Cc: Thomas Gleixner, Kees Cook, Ingo Molnar, Elena Reshetova,
Nathan Chancellor, Nick Desaulniers, Alexander Potapenko, llvm,
kasan-dev, linux-kernel
On Mon, Jan 31, 2022 at 10:05:20AM +0100, Marco Elver wrote:
> The randomize_kstack_offset feature is unconditionally compiled in when
> the architecture supports it.
>
> To add constraints on compiler versions, we require a dedicated Kconfig
> variable. Therefore, introduce RANDOMIZE_KSTACK_OFFSET.
>
> Furthermore, this option is now also configurable by EXPERT kernels:
> while the feature is supposed to have zero performance overhead when
> disabled, due to its use of static branches, there are few cases where
> giving a distribution the option to disable the feature entirely makes
> sense. For example, in very resource constrained environments, which
> would never enable the feature to begin with, in which case the
> additional kernel code size increase would be redundant.
>
> Signed-off-by: Marco Elver <elver@google.com>
> Reviewed-by: Nathan Chancellor <nathan@kernel.org>
For both patches:
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] stack: Introduce CONFIG_RANDOMIZE_KSTACK_OFFSET
2022-01-31 9:05 [PATCH v2 1/2] stack: Introduce CONFIG_RANDOMIZE_KSTACK_OFFSET Marco Elver
` (2 preceding siblings ...)
2022-02-01 10:34 ` Peter Zijlstra
@ 2022-02-14 19:14 ` Kees Cook
3 siblings, 0 replies; 7+ messages in thread
From: Kees Cook @ 2022-02-14 19:14 UTC (permalink / raw)
To: Marco Elver, Thomas Gleixner
Cc: Kees Cook, Alexander Potapenko, Nathan Chancellor, kasan-dev,
Peter Zijlstra, Ingo Molnar, linux-kernel, Elena Reshetova,
Nick Desaulniers, llvm
On Mon, 31 Jan 2022 10:05:20 +0100, Marco Elver wrote:
> The randomize_kstack_offset feature is unconditionally compiled in when
> the architecture supports it.
>
> To add constraints on compiler versions, we require a dedicated Kconfig
> variable. Therefore, introduce RANDOMIZE_KSTACK_OFFSET.
>
> Furthermore, this option is now also configurable by EXPERT kernels:
> while the feature is supposed to have zero performance overhead when
> disabled, due to its use of static branches, there are few cases where
> giving a distribution the option to disable the feature entirely makes
> sense. For example, in very resource constrained environments, which
> would never enable the feature to begin with, in which case the
> additional kernel code size increase would be redundant.
>
> [...]
Applied to for-next/hardening, thanks!
[1/2] stack: Introduce CONFIG_RANDOMIZE_KSTACK_OFFSET
https://git.kernel.org/kees/c/8cb37a5974a4
[2/2] stack: Constrain and fix stack offset randomization with Clang builds
https://git.kernel.org/kees/c/efa90c11f62e
--
Kees Cook
^ permalink raw reply [flat|nested] 7+ messages in thread