x86/entry: Enable random_kstack_offset support
authorKees Cook <keescook@chromium.org>
Thu, 1 Apr 2021 23:23:45 +0000 (16:23 -0700)
committerThomas Gleixner <tglx@linutronix.de>
Thu, 8 Apr 2021 12:05:20 +0000 (14:05 +0200)
Allow for a randomized stack offset on a per-syscall basis, with roughly
5-6 bits of entropy, depending on compiler and word size. Since the
method of offsetting uses macros, this cannot live in the common entry
code (the stack offset needs to be retained for the life of the syscall,
which means it needs to happen at the actual entry point).

Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20210401232347.2791257-5-keescook@chromium.org
arch/x86/Kconfig
arch/x86/entry/common.c
arch/x86/include/asm/entry-common.h

index 2792879d398ee41fa0d4858815b33e18664297ae..4b4ad8ec10d2f20e4ecac19b82063d231c4a6011 100644 (file)
@@ -165,6 +165,7 @@ config X86
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD if X86_64
        select HAVE_ARCH_USERFAULTFD_WP         if X86_64 && USERFAULTFD
        select HAVE_ARCH_VMAP_STACK             if X86_64
+       select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
        select HAVE_ARCH_WITHIN_STACK_FRAMES
        select HAVE_ASM_MODVERSIONS
        select HAVE_CMPXCHG_DOUBLE
index 4efd39aacb9f28366f3bbafb17f59a3ec181cbed..7b2542b13ebd9683748677df37604adb911c4b40 100644 (file)
@@ -38,6 +38,7 @@
 #ifdef CONFIG_X86_64
 __visible noinstr void do_syscall_64(unsigned long nr, struct pt_regs *regs)
 {
+       add_random_kstack_offset();
        nr = syscall_enter_from_user_mode(regs, nr);
 
        instrumentation_begin();
@@ -83,6 +84,7 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
 {
        unsigned int nr = syscall_32_enter(regs);
 
+       add_random_kstack_offset();
        /*
         * Subtlety here: if ptrace pokes something larger than 2^32-1 into
         * orig_ax, the unsigned int return value truncates it.  This may
@@ -102,6 +104,7 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
        unsigned int nr = syscall_32_enter(regs);
        int res;
 
+       add_random_kstack_offset();
        /*
         * This cannot use syscall_enter_from_user_mode() as it has to
         * fetch EBP before invoking any of the syscall entry work
index 2b87b191b3b8470cf80ad8d5004a7baf4ab4d6da..14ebd21965691d17ea763e5f62494cf780946cae 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef _ASM_X86_ENTRY_COMMON_H
 #define _ASM_X86_ENTRY_COMMON_H
 
+#include <linux/randomize_kstack.h>
 #include <linux/user-return-notifier.h>
 
 #include <asm/nospec-branch.h>
@@ -70,6 +71,21 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
         */
        current_thread_info()->status &= ~(TS_COMPAT | TS_I386_REGS_POKED);
 #endif
+
+       /*
+        * Ultimately, this value will get limited by KSTACK_OFFSET_MAX(),
+        * but not enough for x86 stack utilization comfort. To keep
+        * reasonable stack head room, reduce the maximum offset to 8 bits.
+        *
+        * The actual entropy will be further reduced by the compiler when
+        * applying stack alignment constraints (see cc_stack_align4/8 in
+        * arch/x86/Makefile), which will remove the 3 (x86_64) or 2 (ia32)
+        * low bits from any entropy chosen here.
+        *
+        * Therefore, final stack offset entropy will be 5 (x86_64) or
+        * 6 (ia32) bits.
+        */
+       choose_random_kstack_offset(rdtsc() & 0xFF);
 }
 #define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare