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

Commit d590fd12 authored by Sami Tolvanen's avatar Sami Tolvanen
Browse files

ANDROID: add support for clang Control Flow Integrity (CFI)



This change adds the CONFIG_CFI_CLANG option, CFI error handling,
and a faster look-up table for cross module CFI checks.

Bug: 67506682
Change-Id: Ic009f0a629b552a0eb16e6d89808c7029e91447d
Signed-off-by: default avatarSami Tolvanen <samitolvanen@google.com>
parent 727e8415
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -829,6 +829,33 @@ export DISABLE_LTO
export LDFINAL_vmlinux LDFLAGS_FINAL_vmlinux
endif

ifdef CONFIG_CFI_CLANG
cfi-clang-flags	+= -fsanitize=cfi
DISABLE_CFI_CLANG := -fno-sanitize=cfi
ifdef CONFIG_MODULES
cfi-clang-flags	+= -fsanitize-cfi-cross-dso
DISABLE_CFI_CLANG += -fno-sanitize-cfi-cross-dso
endif
ifdef CONFIG_CFI_PERMISSIVE
cfi-clang-flags	+= -fsanitize-recover=cfi -fno-sanitize-trap=cfi
endif

# also disable CFI when LTO is disabled
DISABLE_LTO_CLANG += $(DISABLE_CFI_CLANG)
# allow disabling only clang CFI where needed
export DISABLE_CFI_CLANG
endif

ifdef CONFIG_CFI
# cfi-flags are re-tested in prepare-compiler-check
cfi-flags	:= $(cfi-clang-flags)
KBUILD_CFLAGS	+= $(cfi-flags)

DISABLE_CFI	:= $(DISABLE_CFI_CLANG)
DISABLE_LTO	+= $(DISABLE_CFI)
export DISABLE_CFI
endif

# arch Makefile may override CC so keep this after arch Makefile is included
NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
CHECKFLAGS     += $(NOSTDINC_FLAGS)
@@ -1175,6 +1202,11 @@ ifdef stackp-check
	@echo Cannot use CONFIG_CC_STACKPROTECTOR_$(stackp-name): \
                  $(stackp-flag) available but compiler is broken >&2 && exit 1
  endif
endif
ifdef cfi-flags
  ifeq ($(call cc-option, $(cfi-flags)),)
	@echo Cannot use CONFIG_CFI: $(cfi-flags) not supported by compiler >&2 && exit 1
  endif
endif
	@:

+28 −0
Original line number Diff line number Diff line
@@ -645,6 +645,34 @@ config LTO_CLANG

endchoice

config CFI
	bool

config CFI_PERMISSIVE
	bool "Use CFI in permissive mode"
	depends on CFI
	help
	  When selected, Control Flow Integrity (CFI) violations result in a
	  warning instead of a kernel panic. This option is useful for finding
	  CFI violations in drivers during development.

config CFI_CLANG
	bool "Use clang Control Flow Integrity (CFI) (EXPERIMENTAL)"
	depends on LTO_CLANG
	depends on KALLSYMS
	select CFI
	help
	  This option enables clang Control Flow Integrity (CFI), which adds
	  runtime checking for indirect function calls.

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

config HAVE_ARCH_WITHIN_STACK_FRAMES
	bool
	help
+3 −0
Original line number Diff line number Diff line
@@ -67,10 +67,12 @@
 */
#ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
#define TEXT_MAIN .text .text.[0-9a-zA-Z_]*
#define TEXT_CFI_MAIN .text.cfi .text.[0-9a-zA-Z_]*.cfi
#define DATA_MAIN .data .data.[0-9a-zA-Z_]*
#define BSS_MAIN .bss .bss.[0-9a-zA-Z_]*
#else
#define TEXT_MAIN .text
#define TEXT_CFI_MAIN .text.cfi
#define DATA_MAIN .data
#define BSS_MAIN .bss
#endif
@@ -461,6 +463,7 @@
		*(.text.hot TEXT_MAIN .text.fixup .text.unlikely)	\
		*(.text..refcount)					\
		*(.text..ftrace)					\
		*(TEXT_CFI_MAIN) 					\
		*(.ref.text)						\
	MEM_KEEP(init.text)						\
	MEM_KEEP(exit.text)						\

include/linux/cfi.h

0 → 100644
+38 −0
Original line number Diff line number Diff line
#ifndef _LINUX_CFI_H
#define _LINUX_CFI_H

#include <linux/stringify.h>

#ifdef CONFIG_CFI_CLANG
#ifdef CONFIG_MODULES

typedef void (*cfi_check_fn)(uint64_t, void *, void *);

/* Compiler-generated function in each module, and the kernel */
#define CFI_CHECK_FN		__cfi_check
#define CFI_CHECK_FN_NAME	__stringify(CFI_CHECK_FN)

extern void CFI_CHECK_FN(uint64_t, void *, void *);

#ifdef CONFIG_CFI_CLANG_SHADOW
extern void cfi_module_add(struct module *mod, unsigned long min_addr,
	unsigned long max_addr);

extern void cfi_module_remove(struct module *mod, unsigned long min_addr,
	unsigned long max_addr);
#else
static inline void cfi_module_add(struct module *mod, unsigned long min_addr,
	unsigned long max_addr)
{
}

static inline void cfi_module_remove(struct module *mod, unsigned long min_addr,
	unsigned long max_addr)
{
}
#endif /* CONFIG_CFI_CLANG_SHADOW */

#endif /* CONFIG_MODULES */
#endif /* CONFIG_CFI_CLANG */

#endif /* _LINUX_CFI_H */
+2 −0
Original line number Diff line number Diff line
@@ -27,4 +27,6 @@
#define __norecordmcount \
	__attribute__((__section__(".text..ftrace")))
#endif

#define __nocfi		__attribute__((no_sanitize("cfi")))
#endif
Loading