hardening updates for v5.18-rc1

- Add arm64 Shadow Call Stack support for GCC 12 (Dan Li)
 - Avoid memset with stack offset randomization under Clang (Marco Elver)
 - Clean up stackleak plugin to play nice with .noinstr (Kees Cook)
 - Check stack depth for greater usercopy hardening coverage (Kees Cook)
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEEpcP2jyKd1g9yPm4TiXL039xtwCYFAmI4kXMWHGtlZXNjb29r
 QGNocm9taXVtLm9yZwAKCRCJcvTf3G3AJhBoD/wJFr0s13Cvsbibuk7PLAPJlQe9
 QBMolrrS9+JNoqdIMiILrmthCPnDBkBNrU/YvfkIyGQOO2RGxrtZVzLhyHKCDg6u
 iIkNG9S5D12ucEdqqLWdZxyBZcQuR6Rf//lGvtx8ps+jYy8fDwRekurJIb3kWl5u
 qB0O0PFd+RjGgvtm+Fh8h0FiBMxbKfPXI+s7W2rCfcwe+w5Z24YD1eoCHmnQJYcu
 Mnuk7cHsx2TFms4UqUK1Z/0EBpCKNEEX4s0z/nrfu8dRTPvLqLgbGpcmXTkik9PN
 BucIxgdRqqYbTyGvhsDhpEUVfmFcQzdPmuMnnnUc8BiXy9EqGqSfjMEzutuf+RS7
 0i4LWoDW2LYMUixqDLAMdLpwdC2Ca7hP62kE4vNVqW3jBty+jhPBVO6ddhHO14nd
 q6m+CQz0SVTIyrLI4N+TNg/EIj2DpBpAhs49QWDOL/ZqP0ewYk8Ef8pXKgJo2jJC
 aAs+18pdpoVCEs1fztzjuWZT77iTmziYhb2BOMnT4yBcAdifi7eW6l0pYsgfxoJ/
 WC/MmTWt08/IHBk09d8GbFdoP8byDUgzmzUUoskJJH2JA7475xM6qhI2J627Lpth
 baEv3UT8JWBBX+koU2wxhxKgscIvbNjJjpEGNt2YuBBeQ4lrlijsFzQjmu62gZDL
 LG0XOVV97/1V9uJ2CA==
 =yaWZ
 -----END PGP SIGNATURE-----

Merge tag 'hardening-v5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull kernel hardening updates from Kees Cook:

 - Add arm64 Shadow Call Stack support for GCC 12 (Dan Li)

 - Avoid memset with stack offset randomization under Clang (Marco
   Elver)

 - Clean up stackleak plugin to play nice with .noinstr (Kees Cook)

 - Check stack depth for greater usercopy hardening coverage (Kees Cook)

* tag 'hardening-v5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  arm64: Add gcc Shadow Call Stack support
  m68k: Implement "current_stack_pointer"
  xtensa: Implement "current_stack_pointer"
  usercopy: Check valid lifetime via stack depth
  stack: Constrain and fix stack offset randomization with Clang builds
  stack: Introduce CONFIG_RANDOMIZE_KSTACK_OFFSET
  gcc-plugins/stackleak: Ignore .noinstr.text and .entry.text
  gcc-plugins/stackleak: Exactly match strings instead of prefixes
  gcc-plugins/stackleak: Provide verbose mode
This commit is contained in:
Linus Torvalds 2022-03-21 19:32:04 -07:00
commit 2142b7f0c6
21 changed files with 139 additions and 31 deletions

View File

@ -599,21 +599,22 @@ config STACKPROTECTOR_STRONG
config ARCH_SUPPORTS_SHADOW_CALL_STACK config ARCH_SUPPORTS_SHADOW_CALL_STACK
bool bool
help help
An architecture should select this if it supports Clang's Shadow An architecture should select this if it supports the compiler's
Call Stack and implements runtime support for shadow stack Shadow Call Stack and implements runtime support for shadow stack
switching. switching.
config SHADOW_CALL_STACK config SHADOW_CALL_STACK
bool "Clang Shadow Call Stack" bool "Shadow Call Stack"
depends on CC_IS_CLANG && ARCH_SUPPORTS_SHADOW_CALL_STACK depends on ARCH_SUPPORTS_SHADOW_CALL_STACK
depends on DYNAMIC_FTRACE_WITH_REGS || !FUNCTION_GRAPH_TRACER depends on DYNAMIC_FTRACE_WITH_REGS || !FUNCTION_GRAPH_TRACER
help help
This option enables Clang's Shadow Call Stack, which uses a This option enables the compiler's Shadow Call Stack, which
shadow stack to protect function return addresses from being uses a shadow stack to protect function return addresses from
overwritten by an attacker. More information can be found in being overwritten by an attacker. More information can be found
Clang's documentation: in the compiler's documentation:
https://clang.llvm.org/docs/ShadowCallStack.html - Clang: https://clang.llvm.org/docs/ShadowCallStack.html
- GCC: https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#Instrumentation-Options
Note that security guarantees in the kernel differ from the Note that security guarantees in the kernel differ from the
ones documented for user space. The kernel must store addresses ones documented for user space. The kernel must store addresses
@ -1159,16 +1160,30 @@ config HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
to the compiler, so it will attempt to add canary checks regardless to the compiler, so it will attempt to add canary checks regardless
of the static branch state. of the static branch state.
config RANDOMIZE_KSTACK_OFFSET_DEFAULT config RANDOMIZE_KSTACK_OFFSET
bool "Randomize kernel stack offset on syscall entry" bool "Support for randomizing kernel stack offset on syscall entry" if EXPERT
default y
depends on HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET depends on HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
depends on INIT_STACK_NONE || !CC_IS_CLANG || CLANG_VERSION >= 140000
help help
The kernel stack offset can be randomized (after pt_regs) by The kernel stack offset can be randomized (after pt_regs) by
roughly 5 bits of entropy, frustrating memory corruption roughly 5 bits of entropy, frustrating memory corruption
attacks that depend on stack address determinism or attacks that depend on stack address determinism or
cross-syscall address exposures. This feature is controlled cross-syscall address exposures.
by kernel boot param "randomize_kstack_offset=on/off", and this
config chooses the default boot state. The feature is controlled via the "randomize_kstack_offset=on/off"
kernel boot param, and if turned off has zero overhead due to its use
of static branches (see JUMP_LABEL).
If unsure, say Y.
config RANDOMIZE_KSTACK_OFFSET_DEFAULT
bool "Default state of kernel stack offset randomization"
depends on RANDOMIZE_KSTACK_OFFSET
help
Kernel stack offset randomization is controlled by kernel boot param
"randomize_kstack_offset=on/off", and this config chooses the default
boot state.
config ARCH_OPTIONAL_KERNEL_RWX config ARCH_OPTIONAL_KERNEL_RWX
def_bool n def_bool n

View File

@ -5,6 +5,7 @@ config ARM
select ARCH_32BIT_OFF_T select ARCH_32BIT_OFF_T
select ARCH_CORRECT_STACKTRACE_ON_KRETPROBE if HAVE_KRETPROBES && FRAME_POINTER && !ARM_UNWIND select ARCH_CORRECT_STACKTRACE_ON_KRETPROBE if HAVE_KRETPROBES && FRAME_POINTER && !ARM_UNWIND
select ARCH_HAS_BINFMT_FLAT select ARCH_HAS_BINFMT_FLAT
select ARCH_HAS_CURRENT_STACK_POINTER
select ARCH_HAS_DEBUG_VIRTUAL if MMU select ARCH_HAS_DEBUG_VIRTUAL if MMU
select ARCH_HAS_DMA_WRITE_COMBINE if !ARM_DMA_MEM_BUFFERABLE select ARCH_HAS_DMA_WRITE_COMBINE if !ARM_DMA_MEM_BUFFERABLE
select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_ELF_RANDOMIZE

View File

@ -19,6 +19,7 @@ config ARM64
select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2 select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
select ARCH_HAS_CACHE_LINE_SIZE select ARCH_HAS_CACHE_LINE_SIZE
select ARCH_HAS_CURRENT_STACK_POINTER
select ARCH_HAS_DEBUG_VIRTUAL select ARCH_HAS_DEBUG_VIRTUAL
select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DEBUG_VM_PGTABLE
select ARCH_HAS_DMA_PREP_COHERENT select ARCH_HAS_DMA_PREP_COHERENT
@ -1257,7 +1258,7 @@ config HW_PERF_EVENTS
def_bool y def_bool y
depends on ARM_PMU depends on ARM_PMU
# Supported by clang >= 7.0 # Supported by clang >= 7.0 or GCC >= 12.0.0
config CC_HAVE_SHADOW_CALL_STACK config CC_HAVE_SHADOW_CALL_STACK
def_bool $(cc-option, -fsanitize=shadow-call-stack -ffixed-x18) def_bool $(cc-option, -fsanitize=shadow-call-stack -ffixed-x18)

View File

@ -4,6 +4,7 @@ config M68K
default y default y
select ARCH_32BIT_OFF_T select ARCH_32BIT_OFF_T
select ARCH_HAS_BINFMT_FLAT select ARCH_HAS_BINFMT_FLAT
select ARCH_HAS_CURRENT_STACK_POINTER
select ARCH_HAS_DMA_PREP_COHERENT if HAS_DMA && MMU && !COLDFIRE select ARCH_HAS_DMA_PREP_COHERENT if HAS_DMA && MMU && !COLDFIRE
select ARCH_HAS_SYNC_DMA_FOR_DEVICE if HAS_DMA select ARCH_HAS_SYNC_DMA_FOR_DEVICE if HAS_DMA
select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS

View File

@ -24,6 +24,8 @@ static inline struct task_struct *get_current(void)
#define current get_current() #define current get_current()
#endif /* CONFNIG_MMU */ #endif /* CONFIG_MMU */
register unsigned long current_stack_pointer __asm__("sp");
#endif /* !(_M68K_CURRENT_H) */ #endif /* !(_M68K_CURRENT_H) */

View File

@ -108,6 +108,7 @@ config PPC
select ARCH_ENABLE_MEMORY_HOTPLUG select ARCH_ENABLE_MEMORY_HOTPLUG
select ARCH_ENABLE_MEMORY_HOTREMOVE select ARCH_ENABLE_MEMORY_HOTREMOVE
select ARCH_HAS_COPY_MC if PPC64 select ARCH_HAS_COPY_MC if PPC64
select ARCH_HAS_CURRENT_STACK_POINTER
select ARCH_HAS_DEBUG_VIRTUAL select ARCH_HAS_DEBUG_VIRTUAL
select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DEBUG_VM_PGTABLE
select ARCH_HAS_DEBUG_WX if STRICT_KERNEL_RWX select ARCH_HAS_DEBUG_WX if STRICT_KERNEL_RWX

View File

@ -60,6 +60,7 @@ config S390
select ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM select ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM
select ARCH_ENABLE_MEMORY_HOTREMOVE select ARCH_ENABLE_MEMORY_HOTREMOVE
select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2 select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
select ARCH_HAS_CURRENT_STACK_POINTER
select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DEBUG_VM_PGTABLE
select ARCH_HAS_DEBUG_WX select ARCH_HAS_DEBUG_WX
select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_DEVMEM_IS_ALLOWED

View File

@ -7,6 +7,7 @@ config SUPERH
select ARCH_HAVE_CUSTOM_GPIO_H select ARCH_HAVE_CUSTOM_GPIO_H
select ARCH_HAVE_NMI_SAFE_CMPXCHG if (GUSA_RB || CPU_SH4A) select ARCH_HAVE_NMI_SAFE_CMPXCHG if (GUSA_RB || CPU_SH4A)
select ARCH_HAS_BINFMT_FLAT if !MMU select ARCH_HAS_BINFMT_FLAT if !MMU
select ARCH_HAS_CURRENT_STACK_POINTER
select ARCH_HAS_GIGANTIC_PAGE select ARCH_HAS_GIGANTIC_PAGE
select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_PTE_SPECIAL

View File

@ -69,6 +69,7 @@ config X86
select ARCH_ENABLE_THP_MIGRATION if X86_64 && TRANSPARENT_HUGEPAGE select ARCH_ENABLE_THP_MIGRATION if X86_64 && TRANSPARENT_HUGEPAGE
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
select ARCH_HAS_CACHE_LINE_SIZE select ARCH_HAS_CACHE_LINE_SIZE
select ARCH_HAS_CURRENT_STACK_POINTER
select ARCH_HAS_DEBUG_VIRTUAL select ARCH_HAS_DEBUG_VIRTUAL
select ARCH_HAS_DEBUG_VM_PGTABLE if !X86_PAE select ARCH_HAS_DEBUG_VM_PGTABLE if !X86_PAE
select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_DEVMEM_IS_ALLOWED

View File

@ -3,6 +3,7 @@ config XTENSA
def_bool y def_bool y
select ARCH_32BIT_OFF_T select ARCH_32BIT_OFF_T
select ARCH_HAS_BINFMT_FLAT if !MMU select ARCH_HAS_BINFMT_FLAT if !MMU
select ARCH_HAS_CURRENT_STACK_POINTER
select ARCH_HAS_DMA_PREP_COHERENT if MMU select ARCH_HAS_DMA_PREP_COHERENT if MMU
select ARCH_HAS_SYNC_DMA_FOR_CPU if MMU select ARCH_HAS_SYNC_DMA_FOR_CPU if MMU
select ARCH_HAS_SYNC_DMA_FOR_DEVICE if MMU select ARCH_HAS_SYNC_DMA_FOR_DEVICE if MMU

View File

@ -26,6 +26,8 @@ static inline struct task_struct *get_current(void)
#define current get_current() #define current get_current()
register unsigned long current_stack_pointer __asm__("a1");
#else #else
#define GET_CURRENT(reg,sp) \ #define GET_CURRENT(reg,sp) \

View File

@ -19,14 +19,14 @@ struct stackframe {
static __always_inline unsigned long *stack_pointer(struct task_struct *task) static __always_inline unsigned long *stack_pointer(struct task_struct *task)
{ {
unsigned long *sp; unsigned long sp;
if (!task || task == current) if (!task || task == current)
__asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp)); sp = current_stack_pointer;
else else
sp = (unsigned long *)task->thread.sp; sp = task->thread.sp;
return sp; return (unsigned long *)sp;
} }
void walk_stackframe(unsigned long *sp, void walk_stackframe(unsigned long *sp,

View File

@ -36,9 +36,8 @@ asmlinkage void do_IRQ(int hwirq, struct pt_regs *regs)
#ifdef CONFIG_DEBUG_STACKOVERFLOW #ifdef CONFIG_DEBUG_STACKOVERFLOW
/* Debugging check for stack overflow: is there less than 1KB free? */ /* Debugging check for stack overflow: is there less than 1KB free? */
{ {
unsigned long sp; unsigned long sp = current_stack_pointer;
__asm__ __volatile__ ("mov %0, a1\n" : "=a" (sp));
sp &= THREAD_SIZE - 1; sp &= THREAD_SIZE - 1;
if (unlikely(sp < (sizeof(thread_info) + 1024))) if (unlikely(sp < (sizeof(thread_info) + 1024)))

View File

@ -97,6 +97,10 @@
#define KASAN_ABI_VERSION 4 #define KASAN_ABI_VERSION 4
#endif #endif
#ifdef CONFIG_SHADOW_CALL_STACK
#define __noscs __attribute__((__no_sanitize__("shadow-call-stack")))
#endif
#if __has_attribute(__no_sanitize_address__) #if __has_attribute(__no_sanitize_address__)
#define __no_sanitize_address __attribute__((no_sanitize_address)) #define __no_sanitize_address __attribute__((no_sanitize_address))
#else #else

View File

@ -2,6 +2,7 @@
#ifndef _LINUX_RANDOMIZE_KSTACK_H #ifndef _LINUX_RANDOMIZE_KSTACK_H
#define _LINUX_RANDOMIZE_KSTACK_H #define _LINUX_RANDOMIZE_KSTACK_H
#ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/jump_label.h> #include <linux/jump_label.h>
#include <linux/percpu-defs.h> #include <linux/percpu-defs.h>
@ -16,8 +17,20 @@ DECLARE_PER_CPU(u32, kstack_offset);
* alignment. Also, since this use is being explicitly masked to a max of * 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 * 10 bits, stack-clash style attacks are unlikely. For more details see
* "VLAs" in Documentation/process/deprecated.rst * "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 * 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 * "VLA" from being unbounded (see above). 10 bits leaves enough room for
@ -36,7 +49,7 @@ void *__builtin_alloca(size_t size);
if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \ if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \
&randomize_kstack_offset)) { \ &randomize_kstack_offset)) { \
u32 offset = raw_cpu_read(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. */ \ /* Keep allocation even after "ptr" loses scope. */ \
asm volatile("" :: "r"(ptr) : "memory"); \ asm volatile("" :: "r"(ptr) : "memory"); \
} \ } \
@ -50,5 +63,9 @@ void *__builtin_alloca(size_t size);
raw_cpu_write(kstack_offset, offset); \ raw_cpu_write(kstack_offset, offset); \
} \ } \
} while (0) } while (0)
#else /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
#define add_random_kstack_offset() do { } while (0)
#define choose_random_kstack_offset(rand) do { } while (0)
#endif /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
#endif #endif

View File

@ -853,7 +853,7 @@ static void __init mm_init(void)
pti_init(); pti_init();
} }
#ifdef CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET #ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
DEFINE_STATIC_KEY_MAYBE_RO(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, DEFINE_STATIC_KEY_MAYBE_RO(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
randomize_kstack_offset); randomize_kstack_offset);
DEFINE_PER_CPU(u32, kstack_offset); DEFINE_PER_CPU(u32, kstack_offset);

View File

@ -744,6 +744,15 @@ config IDLE_PAGE_TRACKING
config ARCH_HAS_CACHE_LINE_SIZE config ARCH_HAS_CACHE_LINE_SIZE
bool bool
config ARCH_HAS_CURRENT_STACK_POINTER
bool
help
In support of HARDENED_USERCOPY performing stack variable lifetime
checking, an architecture-agnostic way to find the stack pointer
is needed. Once an architecture defines an unsigned long global
register alias named "current_stack_pointer", this config can be
selected.
config ARCH_HAS_PTE_DEVMAP config ARCH_HAS_PTE_DEVMAP
bool bool

View File

@ -29,7 +29,7 @@
* Returns: * Returns:
* NOT_STACK: not at all on the stack * NOT_STACK: not at all on the stack
* GOOD_FRAME: fully within a valid stack frame * GOOD_FRAME: fully within a valid stack frame
* GOOD_STACK: fully on the stack (when can't do frame-checking) * GOOD_STACK: within the current stack (when can't frame-check exactly)
* BAD_STACK: error condition (invalid stack position or bad stack frame) * BAD_STACK: error condition (invalid stack position or bad stack frame)
*/ */
static noinline int check_stack_object(const void *obj, unsigned long len) static noinline int check_stack_object(const void *obj, unsigned long len)
@ -55,6 +55,17 @@ static noinline int check_stack_object(const void *obj, unsigned long len)
if (ret) if (ret)
return ret; return ret;
/* Finally, check stack depth if possible. */
#ifdef CONFIG_ARCH_HAS_CURRENT_STACK_POINTER
if (IS_ENABLED(CONFIG_STACK_GROWSUP)) {
if ((void *)current_stack_pointer < obj + len)
return BAD_STACK;
} else {
if (obj < (void *)current_stack_pointer)
return BAD_STACK;
}
#endif
return GOOD_STACK; return GOOD_STACK;
} }
@ -280,7 +291,15 @@ void __check_object_size(const void *ptr, unsigned long n, bool to_user)
*/ */
return; return;
default: default:
usercopy_abort("process stack", NULL, to_user, 0, n); usercopy_abort("process stack", NULL, to_user,
#ifdef CONFIG_ARCH_HAS_CURRENT_STACK_POINTER
IS_ENABLED(CONFIG_STACK_GROWSUP) ?
ptr - (void *)current_stack_pointer :
(void *)current_stack_pointer - ptr,
#else
0,
#endif
n);
} }
/* Check for bad heap object. */ /* Check for bad heap object. */

View File

@ -37,6 +37,8 @@ gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \
+= -fplugin-arg-stackleak_plugin-track-min-size=$(CONFIG_STACKLEAK_TRACK_MIN_SIZE) += -fplugin-arg-stackleak_plugin-track-min-size=$(CONFIG_STACKLEAK_TRACK_MIN_SIZE)
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \ gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \
+= -fplugin-arg-stackleak_plugin-arch=$(SRCARCH) += -fplugin-arg-stackleak_plugin-arch=$(SRCARCH)
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK_VERBOSE) \
+= -fplugin-arg-stackleak_plugin-verbose
ifdef CONFIG_GCC_PLUGIN_STACKLEAK ifdef CONFIG_GCC_PLUGIN_STACKLEAK
DISABLE_STACKLEAK_PLUGIN += -fplugin-arg-stackleak_plugin-disable DISABLE_STACKLEAK_PLUGIN += -fplugin-arg-stackleak_plugin-disable
endif endif

View File

@ -429,6 +429,23 @@ static unsigned int stackleak_cleanup_execute(void)
return 0; return 0;
} }
/*
* STRING_CST may or may not be NUL terminated:
* https://gcc.gnu.org/onlinedocs/gccint/Constant-expressions.html
*/
static inline bool string_equal(tree node, const char *string, int length)
{
if (TREE_STRING_LENGTH(node) < length)
return false;
if (TREE_STRING_LENGTH(node) > length + 1)
return false;
if (TREE_STRING_LENGTH(node) == length + 1 &&
TREE_STRING_POINTER(node)[length] != '\0')
return false;
return !memcmp(TREE_STRING_POINTER(node), string, length);
}
#define STRING_EQUAL(node, str) string_equal(node, str, strlen(str))
static bool stackleak_gate(void) static bool stackleak_gate(void)
{ {
tree section; tree section;
@ -438,13 +455,17 @@ static bool stackleak_gate(void)
if (section && TREE_VALUE(section)) { if (section && TREE_VALUE(section)) {
section = TREE_VALUE(TREE_VALUE(section)); section = TREE_VALUE(TREE_VALUE(section));
if (!strncmp(TREE_STRING_POINTER(section), ".init.text", 10)) if (STRING_EQUAL(section, ".init.text"))
return false; return false;
if (!strncmp(TREE_STRING_POINTER(section), ".devinit.text", 13)) if (STRING_EQUAL(section, ".devinit.text"))
return false; return false;
if (!strncmp(TREE_STRING_POINTER(section), ".cpuinit.text", 13)) if (STRING_EQUAL(section, ".cpuinit.text"))
return false; return false;
if (!strncmp(TREE_STRING_POINTER(section), ".meminit.text", 13)) if (STRING_EQUAL(section, ".meminit.text"))
return false;
if (STRING_EQUAL(section, ".noinstr.text"))
return false;
if (STRING_EQUAL(section, ".entry.text"))
return false; return false;
} }

View File

@ -174,6 +174,16 @@ config GCC_PLUGIN_STACKLEAK
* https://grsecurity.net/ * https://grsecurity.net/
* https://pax.grsecurity.net/ * https://pax.grsecurity.net/
config GCC_PLUGIN_STACKLEAK_VERBOSE
bool "Report stack depth analysis instrumentation" if EXPERT
depends on GCC_PLUGIN_STACKLEAK
depends on !COMPILE_TEST # too noisy
help
This option will cause a warning to be printed each time the
stackleak plugin finds a function it thinks needs to be
instrumented. This is useful for comparing coverage between
builds.
config STACKLEAK_TRACK_MIN_SIZE config STACKLEAK_TRACK_MIN_SIZE
int "Minimum stack frame size of functions tracked by STACKLEAK" int "Minimum stack frame size of functions tracked by STACKLEAK"
default 100 default 100