Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit afaef01c authored by Alexander Popov's avatar Alexander Popov Committed by Kees Cook
Browse files

x86/entry: Add STACKLEAK erasing the kernel stack at the end of syscalls

The STACKLEAK feature (initially developed by PaX Team) has the following
benefits:

1. Reduces the information that can be revealed through kernel stack leak
   bugs. The idea of erasing the thread stack at the end of syscalls is
   similar to CONFIG_PAGE_POISONING and memzero_explicit() in kernel
   crypto, which all comply with FDP_RIP.2 (Full Residual Information
   Protection) of the Common Criteria standard.

2. Blocks some uninitialized stack variable attacks (e.g. CVE-2017-17712,
   CVE-2010-2963). That kind of bugs should be killed by improving C
   compilers in future, which might take a long time.

This commit introduces the code filling the used part of the kernel
stack with a poison value before returning to userspace. Full
STACKLEAK feature also contains the gcc plugin which comes in a
separate commit.

The STACKLEAK feature is ported from grsecurity/PaX. More information at:
  https://grsecurity.net/
  https://pax.grsecurity.net/



This code is modified from Brad Spengler/PaX Team's code in the last
public patch of grsecurity/PaX based on our understanding of the code.
Changes or omissions from the original code are ours and don't reflect
the original grsecurity/PaX code.

Performance impact:

Hardware: Intel Core i7-4770, 16 GB RAM

Test #1: building the Linux kernel on a single core
        0.91% slowdown

Test #2: hackbench -s 4096 -l 2000 -g 15 -f 25 -P
        4.2% slowdown

So the STACKLEAK description in Kconfig includes: "The tradeoff is the
performance impact: on a single CPU system kernel compilation sees a 1%
slowdown, other systems and workloads may vary and you are advised to
test this feature on your expected workload before deploying it".

Signed-off-by: default avatarAlexander Popov <alex.popov@linux.com>
Acked-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
Acked-by: default avatarIngo Molnar <mingo@kernel.org>
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
parent 57361846
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ ffffffffa0000000 - fffffffffeffffff (1520 MB) module mapping space
[fixmap start]   - ffffffffff5fffff kernel-internal fixmap range
ffffffffff600000 - ffffffffff600fff (=4 kB) legacy vsyscall ABI
ffffffffffe00000 - ffffffffffffffff (=2 MB) unused hole
STACKLEAK_POISON value in this last hole: ffffffffffff4111

Virtual memory map with 5 level page tables:

@@ -50,6 +51,7 @@ ffffffffa0000000 - fffffffffeffffff (1520 MB) module mapping space
[fixmap start]   - ffffffffff5fffff kernel-internal fixmap range
ffffffffff600000 - ffffffffff600fff (=4 kB) legacy vsyscall ABI
ffffffffffe00000 - ffffffffffffffff (=2 MB) unused hole
STACKLEAK_POISON value in this last hole: ffffffffffff4111

Architecture defines a 64-bit virtual address. Implementations can support
less. Currently supported are 48- and 57-bit virtual addresses. Bits 63
+7 −0
Original line number Diff line number Diff line
@@ -419,6 +419,13 @@ config SECCOMP_FILTER

	  See Documentation/userspace-api/seccomp_filter.rst for details.

config HAVE_ARCH_STACKLEAK
	bool
	help
	  An architecture should select this if it has the code which
	  fills the used part of the kernel stack with the STACKLEAK_POISON
	  value before returning from system calls.

config HAVE_STACKPROTECTOR
	bool
	help
+1 −0
Original line number Diff line number Diff line
@@ -127,6 +127,7 @@ config X86
	select HAVE_ARCH_PREL32_RELOCATIONS
	select HAVE_ARCH_SECCOMP_FILTER
	select HAVE_ARCH_THREAD_STRUCT_WHITELIST
	select HAVE_ARCH_STACKLEAK
	select HAVE_ARCH_TRACEHOOK
	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
	select HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD if X86_64
+14 −0
Original line number Diff line number Diff line
@@ -329,8 +329,22 @@ For 32-bit we have the following conventions - kernel is built with

#endif

.macro STACKLEAK_ERASE_NOCLOBBER
#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
	PUSH_AND_CLEAR_REGS
	call stackleak_erase
	POP_REGS
#endif
.endm

#endif /* CONFIG_X86_64 */

.macro STACKLEAK_ERASE
#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
	call stackleak_erase
#endif
.endm

/*
 * This does 'call enter_from_user_mode' unless we can avoid it based on
 * kernel config or using the static jump infrastructure.
+7 −0
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@
#include <asm/frame.h>
#include <asm/nospec-branch.h>

#include "calling.h"

	.section .entry.text, "ax"

/*
@@ -711,6 +713,7 @@ ENTRY(ret_from_fork)
	/* When we fork, we trace the syscall return in the child, too. */
	movl    %esp, %eax
	call    syscall_return_slowpath
	STACKLEAK_ERASE
	jmp     restore_all

	/* kernel thread */
@@ -885,6 +888,8 @@ ENTRY(entry_SYSENTER_32)
	ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \
		    "jmp .Lsyscall_32_done", X86_FEATURE_XENPV

	STACKLEAK_ERASE

/* Opportunistic SYSEXIT */
	TRACE_IRQS_ON			/* User mode traces as IRQs on. */

@@ -996,6 +1001,8 @@ ENTRY(entry_INT80_32)
	call	do_int80_syscall_32
.Lsyscall_32_done:

	STACKLEAK_ERASE

restore_all:
	TRACE_IRQS_IRET
	SWITCH_TO_ENTRY_STACK
Loading