[PATCH v4 00/17] add support for Clang's Shadow Call Stack

Sami Tolvanen
2019-11-01T22:12:17Z

This patch series adds support for Clang's Shadow Call Stack
(SCS) mitigation, which uses a separately allocated shadow stack
to protect against return address overwrites. More information
can be found here:

https://clang.llvm.org/docs/ShadowCallStack.html

SCS provides better protection against traditional buffer
overflows than CONFIG_STACKPROTECTOR_*, but it should be noted
that SCS security guarantees in the kernel differ from the ones
documented for user space. The kernel must store addresses of
shadow stacks used by other tasks and interrupt handlers in
memory, which means an attacker capable reading and writing
arbitrary memory may be able to locate them and hijack control
flow by modifying shadow stacks that are not currently in use.

SCS is currently supported only on arm64, where the compiler
requires the x18 register to be reserved for holding the current
task's shadow stack pointer. Because of this, the series includes
patches from Ard to remove x18 usage from assembly code.

With -fsanitize=shadow-call-stack, the compiler injects
instructions to all non-leaf C functions to store the return
address to the shadow stack, and unconditionally load it again
before returning. As a result, SCS is currently incompatible
with features that rely on modifying function return addresses
to alter control flow, such as function graph tracing and
kretprobes, although it may be possible to later change these
features to modify the shadow stack instead. A copy of the return
address is still kept in the kernel stack for compatibility with
stack unwinding, for example.

SCS has a minimal performance overhead, but allocating
shadow stacks increases kernel memory usage. The feature is
therefore mostly useful on hardware that lacks support for PAC
instructions.

Changes in v4:
- Fixed authorship for Ard's patches
- Added missing commit messages
- Commented code that clears SCS from thread_info
- Added a comment about SCS_END_MAGIC being non-canonical

Changes in v3:
- Switched to filter-out for removing SCS flags in Makefiles
- Changed the __noscs attribute to use __no_sanitize__("...")
instead of no_sanitize("...")
- Cleaned up inline function definitions and moved task_scs()
into a macro
- Cleaned up scs_free() and scs_magic()
- Moved SCS initialization into dup_task_struct() and removed
the now unused scs_task_init()
- Added comments to __scs_base() and scs_task_reset() to better
document design choices
- Changed copy_page to make the offset and bias explicit

Changes in v2:
- Changed Ard's KVM patch to use x29 instead of x18 for the
guest context, which makes restore_callee_saved_regs cleaner
- Updated help text (and commit messages) to point out
differences in security properties compared to user space SCS
- Cleaned up config options: removed the ROP protection choice,
replaced the CC_IS_CLANG dependency with an arch-specific
cc-option test, and moved disabling of incompatible config
options to an arch-specific Kconfig
- Added CC_FLAGS_SCS, which are filtered out where needed
instead of using DISABLE_SCS
- Added a __has_feature guard around __noscs for older clang
versions

Ard Biesheuvel (3):
arm64/lib: copy_page: avoid x18 register in assembler code
arm64: kvm: stop treating register x18 as caller save
arm64: kernel: avoid x18 __cpu_soft_restart

Sami Tolvanen (14):
arm64: mm: avoid x18 in idmap_kpti_install_ng_mappings
add support for Clang's Shadow Call Stack (SCS)
scs: add accounting
scs: add support for stack usage debugging
kprobes: fix compilation without CONFIG_KRETPROBES
arm64: kprobes: fix kprobes without CONFIG_KRETPROBES
arm64: disable kretprobes with SCS
arm64: disable function graph tracing with SCS
arm64: reserve x18 from general allocation with SCS
arm64: preserve x18 when CPU is suspended
arm64: efi: restore x18 if it was corrupted
arm64: vdso: disable Shadow Call Stack
arm64: disable SCS for hypervisor code
arm64: implement Shadow Call Stack

Makefile | 6 +
arch/Kconfig | 33 ++++
arch/arm64/Kconfig | 9 +-
arch/arm64/Makefile | 4 +
arch/arm64/include/asm/scs.h | 37 +++++
arch/arm64/include/asm/stacktrace.h | 4 +
arch/arm64/include/asm/suspend.h | 2 +-
arch/arm64/include/asm/thread_info.h | 3 +
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/asm-offsets.c | 3 +
arch/arm64/kernel/cpu-reset.S | 4 +-
arch/arm64/kernel/efi-rt-wrapper.S | 7 +-
arch/arm64/kernel/entry.S | 28 ++++
arch/arm64/kernel/head.S | 9 ++
arch/arm64/kernel/irq.c | 2 +
arch/arm64/kernel/probes/kprobes.c | 2 +
arch/arm64/kernel/process.c | 2 +
arch/arm64/kernel/scs.c | 39 +++++
arch/arm64/kernel/smp.c | 4 +
arch/arm64/kernel/vdso/Makefile | 2 +-
arch/arm64/kvm/hyp/Makefile | 3 +
arch/arm64/kvm/hyp/entry.S | 41 +++--
arch/arm64/lib/copy_page.S | 38 ++---
arch/arm64/mm/proc.S | 73 +++++----
drivers/base/node.c | 6 +
fs/proc/meminfo.c | 4 +
include/linux/compiler-clang.h | 6 +
include/linux/compiler_types.h | 4 +
include/linux/mmzone.h | 3 +
include/linux/scs.h | 57 +++++++
init/init_task.c | 8 +
kernel/Makefile | 1 +
kernel/fork.c | 9 ++
kernel/kprobes.c | 38 ++---
kernel/sched/core.c | 2 +
kernel/sched/sched.h | 1 +
kernel/scs.c | 227 +++++++++++++++++++++++++++
mm/page_alloc.c | 6 +
mm/vmstat.c | 3 +
39 files changed, 634 insertions(+), 97 deletions(-)
create mode 100644 arch/arm64/include/asm/scs.h
create mode 100644 arch/arm64/kernel/scs.c
create mode 100644 include/linux/scs.h
create mode 100644 kernel/scs.c

base-commit: 0dbe6cb8f7e05bc9611602ef45980a6c57b245a3
--
2.24.0.rc1.363.gb1bccd3e3d-goog