Commit 57fa2369 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull CFI on arm64 support from Kees Cook:
 "This builds on last cycle's LTO work, and allows the arm64 kernels to
  be built with Clang's Control Flow Integrity feature. This feature has
  happily lived in Android kernels for almost 3 years[1], so I'm excited
  to have it ready for upstream.

  The wide diffstat is mainly due to the treewide fixing of mismatched
  list_sort prototypes. Other things in core kernel are to address
  various CFI corner cases. The largest code portion is the CFI runtime
  implementation itself (which will be shared by all architectures
  implementing support for CFI). The arm64 pieces are Acked by arm64
  maintainers rather than coming through the arm64 tree since carrying
  this tree over there was going to be awkward.

  CFI support for x86 is still under development, but is pretty close.
  There are a handful of corner cases on x86 that need some improvements
  to Clang and objtool, but otherwise works well.

  Summary:

   - Clean up list_sort prototypes (Sami Tolvanen)

   - Introduce CONFIG_CFI_CLANG for arm64 (Sami Tolvanen)"

* tag 'cfi-v5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  arm64: allow CONFIG_CFI_CLANG to be selected
  KVM: arm64: Disable CFI for nVHE
  arm64: ftrace: use function_nocfi for ftrace_call
  arm64: add __nocfi to __apply_alternatives
  arm64: add __nocfi to functions that jump to a physical address
  arm64: use function_nocfi with __pa_symbol
  arm64: implement function_nocfi
  psci: use function_nocfi for cpu_resume
  lkdtm: use function_nocfi
  treewide: Change list_sort to use const pointers
  bpf: disable CFI in dispatcher functions
  kallsyms: strip ThinLTO hashes from static functions
  kthread: use WARN_ON_FUNCTION_MISMATCH
  workqueue: use WARN_ON_FUNCTION_MISMATCH
  module: ensure __cfi_check alignment
  mm: add generic function_nocfi macro
  cfi: add __cficanonical
  add support for Clang CFI
parents 2fbc66c7 9186ad8e
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -924,6 +924,23 @@ KBUILD_AFLAGS += -fno-lto
export CC_FLAGS_LTO
endif

ifdef CONFIG_CFI_CLANG
CC_FLAGS_CFI	:= -fsanitize=cfi \
		   -fsanitize-cfi-cross-dso \
		   -fno-sanitize-cfi-canonical-jump-tables \
		   -fno-sanitize-trap=cfi \
		   -fno-sanitize-blacklist

ifdef CONFIG_CFI_PERMISSIVE
CC_FLAGS_CFI	+= -fsanitize-recover=cfi
endif

# If LTO flags are filtered out, we must also filter out CFI.
CC_FLAGS_LTO	+= $(CC_FLAGS_CFI)
KBUILD_CFLAGS	+= $(CC_FLAGS_CFI)
export CC_FLAGS_CFI
endif

ifdef CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B
KBUILD_CFLAGS += -falign-functions=32
endif
+45 −0
Original line number Diff line number Diff line
@@ -692,6 +692,51 @@ config LTO_CLANG_THIN
	  If unsure, say Y.
endchoice

config ARCH_SUPPORTS_CFI_CLANG
	bool
	help
	  An architecture should select this option if it can support Clang's
	  Control-Flow Integrity (CFI) checking.

config CFI_CLANG
	bool "Use Clang's Control Flow Integrity (CFI)"
	depends on LTO_CLANG && ARCH_SUPPORTS_CFI_CLANG
	# Clang >= 12:
	# - https://bugs.llvm.org/show_bug.cgi?id=46258
	# - https://bugs.llvm.org/show_bug.cgi?id=47479
	depends on CLANG_VERSION >= 120000
	select KALLSYMS
	help
	  This option enables Clang’s forward-edge Control Flow Integrity
	  (CFI) checking, where the compiler injects a runtime check to each
	  indirect function call to ensure the target is a valid function with
	  the correct static type. This restricts possible call targets and
	  makes it more difficult for an attacker to exploit bugs that allow
	  the modification of stored function pointers. More information can be
	  found from Clang's documentation:

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

config CFI_CLANG_SHADOW
	bool "Use CFI shadow to speed up cross-module checks"
	default y
	depends on CFI_CLANG && MODULES
	help
	  If you select this option, the kernel builds a fast look-up table of
	  CFI check functions in loaded modules to reduce performance overhead.

	  If unsure, say Y.

config CFI_PERMISSIVE
	bool "Use CFI in permissive mode"
	depends on CFI_CLANG
	help
	  When selected, Control Flow Integrity (CFI) violations result in a
	  warning instead of a kernel panic. This option should only be used
	  for finding indirect call type mismatches during development.

	  If unsure, say N.

config HAVE_ARCH_WITHIN_STACK_FRAMES
	bool
	help
+1 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ config ARM64
	select ARCH_SUPPORTS_SHADOW_CALL_STACK if CC_HAVE_SHADOW_CALL_STACK
	select ARCH_SUPPORTS_LTO_CLANG if CPU_LITTLE_ENDIAN
	select ARCH_SUPPORTS_LTO_CLANG_THIN
	select ARCH_SUPPORTS_CFI_CLANG
	select ARCH_SUPPORTS_ATOMIC_RMW
	select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 && (GCC_VERSION >= 50000 || CC_IS_CLANG)
	select ARCH_SUPPORTS_NUMA_BALANCING
+16 −0
Original line number Diff line number Diff line
@@ -323,6 +323,22 @@ static inline void *phys_to_virt(phys_addr_t x)
#define virt_to_pfn(x)		__phys_to_pfn(__virt_to_phys((unsigned long)(x)))
#define sym_to_pfn(x)		__phys_to_pfn(__pa_symbol(x))

#ifdef CONFIG_CFI_CLANG
/*
 * With CONFIG_CFI_CLANG, the compiler replaces function address
 * references with the address of the function's CFI jump table
 * entry. The function_nocfi macro always returns the address of the
 * actual function instead.
 */
#define function_nocfi(x) ({						\
	void *addr;							\
	asm("adrp %0, " __stringify(x) "\n\t"				\
	    "add  %0, %0, :lo12:" __stringify(x)			\
	    : "=r" (addr));						\
	addr;								\
})
#endif

/*
 *  virt_to_page(x)	convert a _valid_ virtual address to struct page *
 *  virt_addr_valid(x)	indicates whether a virtual address is valid
+2 −2
Original line number Diff line number Diff line
@@ -119,7 +119,7 @@ static inline void cpu_install_idmap(void)
 * Atomically replaces the active TTBR1_EL1 PGD with a new VA-compatible PGD,
 * avoiding the possibility of conflicting TLB entries being allocated.
 */
static inline void cpu_replace_ttbr1(pgd_t *pgdp)
static inline void __nocfi cpu_replace_ttbr1(pgd_t *pgdp)
{
	typedef void (ttbr_replace_func)(phys_addr_t);
	extern ttbr_replace_func idmap_cpu_replace_ttbr1;
@@ -140,7 +140,7 @@ static inline void cpu_replace_ttbr1(pgd_t *pgdp)
		ttbr1 |= TTBR_CNP_BIT;
	}

	replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1);
	replace_phys = (void *)__pa_symbol(function_nocfi(idmap_cpu_replace_ttbr1));

	cpu_install_idmap();
	replace_phys(ttbr1);
Loading