mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-06 13:23:18 +00:00
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:
commit
2142b7f0c6
43
arch/Kconfig
43
arch/Kconfig
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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) */
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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) \
|
||||||
|
@ -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,
|
||||||
|
@ -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)))
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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. */
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user