Skip to content
This repository has been archived by the owner on Nov 21, 2022. It is now read-only.

Commit

Permalink
Merge branch 'clang-cfi' of https://github.com/samitolvanen/linux int…
Browse files Browse the repository at this point in the history
…o next

* 'clang-cfi' of https://github.com/samitolvanen/linux:
  security: fix the key_permission LSM hook function type
  x86/entry: disable CFI for run_on_irqstack_cond
  x86: kprobes: mark optprobe_template_func global
  x86: map CFI jump tables in pti_clone_entry_text
  x86, module: Ignore __typeid__ relocations
  x86, relocs: Ignore __typeid__ relocations
  x86/alternatives: Use C int3 selftest but disable KASAN
  x86/extable: Do not mark exception callback as CFI
  arm64: disable BTI with CFI_CLANG
  arm64: kvm: disable CFI
  arm64: add __nocfi to __apply_alternatives
  arm64: add __pa_function
  arm64: add __nocfi to functions that jump to a physical address
  lib/list_sort: fix function type mismatches
  bpf: disable CFI in dispatcher functions
  kallsyms: cfi: strip hashes from static functions
  workqueue: cfi: disable callback pointer check with modules
  objtool: cfi: ignore CFI jump tables
  export: cfi: fix ksymtab addresses
  module: cfi: ensure __cfi_check alignment
  cfi: add __cficanonical and fix PREL32 relocations
  add support for Clang's Control Flow Integrity (CFI)
  x86, build: allow LTO_CLANG and THINLTO to be selected
  x86, relocs: Ignore L4_PAGE_OFFSET relocations
  x86, ftrace: disable recordmcount for ftrace_make_nop
  x86, vdso: disable LTO only for vDSO
  arm64: allow LTO_CLANG and THINLTO to be selected
  arm64: vdso: disable LTO
  arm64: export CC_USING_PATCHABLE_FUNCTION_ENTRY
  drivers/misc/lkdtm: disable LTO for rodata.o
  efi/libstub: disable LTO
  scripts/mod: disable LTO for empty.c
  modpost: lto: strip .lto from module names
  pci: lto: fix PREL32 relocations
  init: lto: fix PREL32 relocations
  init: lto: ensure initcall ordering
  kbuild: lto: remove duplicate dependencies from .mod files
  kbuild: lto: merge module sections
  kbuild: lto: limit inlining
  kbuild: lto: fix stack validation
  kbuild: lto: fix recordmcount
  kbuild: lto: fix module versioning
  kbuild: add support for Clang LTO
  recordmcount: support >64k sections
  objtool: use sh_info to find the base for .rela sections

Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
  • Loading branch information
nathanchance committed Jun 18, 2020
2 parents ce2cc8e + 219dfdc commit ca5d2ee
Show file tree
Hide file tree
Showing 66 changed files with 1,546 additions and 108 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
*.so.dbg
*.su
*.symtypes
*.symversions
*.tab.[ch]
*.tar
*.xz
Expand Down
44 changes: 42 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ KBUILD_AFLAGS += $(CC_FLAGS_USING)
ifdef CONFIG_DYNAMIC_FTRACE
ifdef CONFIG_HAVE_C_RECORDMCOUNT
BUILD_C_RECORDMCOUNT := y
export BUILD_C_RECORDMCOUNT
export BUILD_C_RECORDMCOUNT RECORDMCOUNT_WARN
endif
endif
endif
Expand All @@ -895,6 +895,45 @@ KBUILD_CFLAGS += $(CC_FLAGS_SCS)
export CC_FLAGS_SCS
endif

ifdef CONFIG_LTO_CLANG
ifdef CONFIG_THINLTO
CC_FLAGS_LTO_CLANG := -flto=thin $(call cc-option, -fsplit-lto-unit)
KBUILD_LDFLAGS += --thinlto-cache-dir=.thinlto-cache
else
CC_FLAGS_LTO_CLANG := -flto
endif
CC_FLAGS_LTO_CLANG += -fvisibility=default

# Limit inlining across translation units to reduce binary size
LD_FLAGS_LTO_CLANG := -mllvm -import-instr-limit=5
KBUILD_LDFLAGS += $(LD_FLAGS_LTO_CLANG)

KBUILD_LDS_MODULE += scripts/module-lto.lds
endif

ifdef CONFIG_LTO
CC_FLAGS_LTO := $(CC_FLAGS_LTO_CLANG)
KBUILD_CFLAGS += $(CC_FLAGS_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-blacklist

ifdef CONFIG_CFI_PERMISSIVE
CC_FLAGS_CFI += -fsanitize-recover=cfi \
-fno-sanitize-trap=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

# arch Makefile may override CC so keep this after arch Makefile is included
NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)

Expand Down Expand Up @@ -1794,7 +1833,8 @@ clean: $(clean-dirs)
-o -name '.tmp_*.o.*' \
-o -name '*.c.[012]*.*' \
-o -name '*.ll' \
-o -name '*.gcno' \) -type f -print | xargs rm -f
-o -name '*.gcno' \
-o -name '*.*.symversions' \) -type f -print | xargs rm -f

# Generate tags for editors
# ---------------------------------------------------------------------------
Expand Down
88 changes: 88 additions & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,94 @@ config SHADOW_CALL_STACK
reading and writing arbitrary memory may be able to locate them
and hijack control flow by modifying the stacks.

config LTO
bool

config ARCH_SUPPORTS_LTO_CLANG
bool
help
An architecture should select this option if it supports:
- compiling with Clang,
- compiling inline assembly with Clang's integrated assembler,
- and linking with LLD.

config ARCH_SUPPORTS_THINLTO
bool
help
An architecture should select this option if it supports Clang's
ThinLTO.

config THINLTO
bool "Clang ThinLTO"
depends on LTO_CLANG && ARCH_SUPPORTS_THINLTO
default y
help
This option enables Clang's ThinLTO, which allows for parallel
optimization and faster incremental compiles. More information
can be found from Clang's documentation:

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

choice
prompt "Link Time Optimization (LTO)"
default LTO_NONE
help
This option enables Link Time Optimization (LTO), which allows the
compiler to optimize binaries globally.

If unsure, select LTO_NONE.

config LTO_NONE
bool "None"

config LTO_CLANG
bool "Clang's Link Time Optimization (EXPERIMENTAL)"
depends on CC_IS_CLANG && CLANG_VERSION >= 110000 && LD_IS_LLD
depends on $(success,$(NM) --help | head -n 1 | grep -qi llvm)
depends on $(success,$(AR) --help | head -n 1 | grep -qi llvm)
depends on ARCH_SUPPORTS_LTO_CLANG
depends on !FTRACE_MCOUNT_RECORD || HAVE_C_RECORDMCOUNT
depends on !KASAN
select LTO
help
This option enables Clang's Link Time Optimization (LTO), which
allows the compiler to optimize the kernel globally. If you enable
this option, the compiler generates LLVM bitcode instead of ELF
object files, and the actual compilation from bitcode happens at
the LTO link step, which may take several minutes depending on the
kernel configuration. More information can be found from LLVM's
documentation:

https://llvm.org/docs/LinkTimeOptimization.html

To select this option, you also need to use LLVM tools to handle
the bitcode by passing LLVM=1 to make.

endchoice

config CFI_CLANG
bool "Use Clang's Control Flow Integrity (CFI)"
depends on LTO_CLANG && KALLSYMS
help
This option enables Clang's 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 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 is useful for finding
CFI violations during development.

config HAVE_ARCH_WITHIN_STACK_FRAMES
bool
help
Expand Down
3 changes: 3 additions & 0 deletions arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ config ARM64
select ARCH_USE_SYM_ANNOTATIONS
select ARCH_SUPPORTS_MEMORY_FAILURE
select ARCH_SUPPORTS_SHADOW_CALL_STACK if CC_HAVE_SHADOW_CALL_STACK
select ARCH_SUPPORTS_LTO_CLANG
select ARCH_SUPPORTS_THINLTO
select ARCH_SUPPORTS_ATOMIC_RMW
select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 && (GCC_VERSION >= 50000 || CC_IS_CLANG)
select ARCH_SUPPORTS_NUMA_BALANCING
Expand Down Expand Up @@ -1634,6 +1636,7 @@ config ARM64_BTI_KERNEL
depends on !CC_IS_CLANG || CLANG_VERSION >= 100001
depends on !(CC_IS_CLANG && GCOV_KERNEL)
depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_REGS)
depends on !CFI_CLANG
help
Build the kernel with Branch Target Identification annotations
and enable enforcement of this for kernel code. When this option
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ endif
ifeq ($(CONFIG_DYNAMIC_FTRACE_WITH_REGS),y)
KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
CC_FLAGS_FTRACE := -fpatchable-function-entry=2
export CC_USING_PATCHABLE_FUNCTION_ENTRY := 1
endif

# Default value
Expand Down
16 changes: 16 additions & 0 deletions arch/arm64/include/asm/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,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))

/*
* With non-canonical CFI jump tables, the compiler replaces function
* address references with the address of the function's CFI jump
* table entry. This results in __pa_symbol(function) returning the
* physical address of the jump table entry, which can lead to address
* space confusion since the jump table points to the function's
* virtual address. Therefore, use inline assembly to ensure we are
* always taking the address of the actual function.
*/
#define __pa_function(x) ({ \
unsigned long addr; \
asm("adrp %0, " __stringify(x) "\n\t" \
"add %0, %0, :lo12:" __stringify(x) : "=r" (addr)); \
__pa_symbol(addr); \
})

/*
* virt_to_page(x) convert a _valid_ virtual address to struct page *
* virt_addr_valid(x) indicates whether a virtual address is valid
Expand Down
4 changes: 2 additions & 2 deletions arch/arm64/include/asm/mmu_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,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;
Expand All @@ -158,7 +158,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_function(idmap_cpu_replace_ttbr1);

cpu_install_idmap();
replace_phys(ttbr1);
Expand Down
4 changes: 2 additions & 2 deletions arch/arm64/kernel/alternative.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ static void clean_dcache_range_nopatch(u64 start, u64 end)
} while (cur += d_size, cur < end);
}

static void __apply_alternatives(void *alt_region, bool is_module,
unsigned long *feature_mask)
static void __nocfi __apply_alternatives(void *alt_region, bool is_module,
unsigned long *feature_mask)
{
struct alt_instr *alt;
struct alt_region *region = alt_region;
Expand Down
10 changes: 5 additions & 5 deletions arch/arm64/kernel/cpu-reset.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
void __cpu_soft_restart(unsigned long el2_switch, unsigned long entry,
unsigned long arg0, unsigned long arg1, unsigned long arg2);

static inline void __noreturn cpu_soft_restart(unsigned long entry,
unsigned long arg0,
unsigned long arg1,
unsigned long arg2)
static inline void __noreturn __nocfi cpu_soft_restart(unsigned long entry,
unsigned long arg0,
unsigned long arg1,
unsigned long arg2)
{
typeof(__cpu_soft_restart) *restart;

unsigned long el2_switch = !is_kernel_in_hyp_mode() &&
is_hyp_mode_available();
restart = (void *)__pa_symbol(__cpu_soft_restart);
restart = (void *)__pa_function(__cpu_soft_restart);

cpu_install_idmap();
restart(el2_switch, entry, arg0, arg1, arg2);
Expand Down
4 changes: 2 additions & 2 deletions arch/arm64/kernel/cpufeature.c
Original file line number Diff line number Diff line change
Expand Up @@ -1343,7 +1343,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
}

#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
static void
static void __nocfi
kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
{
typedef void (kpti_remap_fn)(int, int, phys_addr_t);
Expand All @@ -1360,7 +1360,7 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
if (arm64_use_ng_mappings)
return;

remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
remap_fn = (void *)__pa_function(idmap_kpti_install_ng_mappings);

cpu_install_idmap();
remap_fn(cpu, num_online_cpus(), __pa_symbol(swapper_pg_dir));
Expand Down
3 changes: 2 additions & 1 deletion arch/arm64/kernel/psci.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ static int __init cpu_psci_cpu_prepare(unsigned int cpu)

static int cpu_psci_cpu_boot(unsigned int cpu)
{
int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa_symbol(secondary_entry));
int err = psci_ops.cpu_on(cpu_logical_map(cpu),
__pa_function(secondary_entry));
if (err)
pr_err("failed to boot CPU%d (%d)\n", cpu, err);

Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/kernel/smp_spin_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ static int smp_spin_table_cpu_prepare(unsigned int cpu)
* boot-loader's endianess before jumping. This is mandated by
* the boot protocol.
*/
writeq_relaxed(__pa_symbol(secondary_holding_pen), release_addr);
writeq_relaxed(__pa_function(secondary_holding_pen), release_addr);
__flush_dcache_area((__force void *)release_addr,
sizeof(*release_addr));

Expand Down
4 changes: 2 additions & 2 deletions arch/arm64/kernel/vdso/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ ldflags-y := -shared -nostdlib -soname=linux-vdso.so.1 --hash-style=sysv \
ccflags-y := -fno-common -fno-builtin -fno-stack-protector -ffixed-x18
ccflags-y += -DDISABLE_BRANCH_PROFILING

CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) -Os $(CC_FLAGS_SCS)
KBUILD_CFLAGS += $(DISABLE_LTO)
CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) -Os $(CC_FLAGS_SCS) \
$(CC_FLAGS_LTO)
KASAN_SANITIZE := n
UBSAN_SANITIZE := n
OBJECT_FILES_NON_STANDARD := y
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/kvm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#

ccflags-y += -I $(srctree)/$(src)
CFLAGS_REMOVE_debug.o += $(CC_FLAGS_CFI)

KVM=../../../virt/kvm

Expand Down
3 changes: 3 additions & 0 deletions arch/arm64/kvm/hyp/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ GCOV_PROFILE := n
KASAN_SANITIZE := n
UBSAN_SANITIZE := n
KCOV_INSTRUMENT := n

# Disable CFI for the files in this directory
KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_CFI), $(KBUILD_CFLAGS))
2 changes: 2 additions & 0 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ config X86
select ARCH_SUPPORTS_ACPI
select ARCH_SUPPORTS_ATOMIC_RMW
select ARCH_SUPPORTS_NUMA_BALANCING if X86_64
select ARCH_SUPPORTS_LTO_CLANG if X86_64
select ARCH_SUPPORTS_THINLTO if X86_64
select ARCH_USE_BUILTIN_BSWAP
select ARCH_USE_QUEUED_RWLOCKS
select ARCH_USE_QUEUED_SPINLOCKS
Expand Down
5 changes: 5 additions & 0 deletions arch/x86/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ ifdef CONFIG_X86_64
KBUILD_LDFLAGS += $(call ld-option, -z max-page-size=0x200000)
endif

ifdef CONFIG_LTO_CLANG
KBUILD_LDFLAGS += -plugin-opt=-code-model=kernel \
-plugin-opt=-stack-alignment=$(if $(CONFIG_X86_32),4,8)
endif

# Workaround for a gcc prelease that unfortunately was shipped in a suse release
KBUILD_CFLAGS += -Wno-sign-compare
#
Expand Down
5 changes: 2 additions & 3 deletions arch/x86/entry/vdso/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ ARCH_REL_TYPE_ABS := R_X86_64_JUMP_SLOT|R_X86_64_GLOB_DAT|R_X86_64_RELATIVE|
ARCH_REL_TYPE_ABS += R_386_GLOB_DAT|R_386_JMP_SLOT|R_386_RELATIVE
include $(srctree)/lib/vdso/Makefile

KBUILD_CFLAGS += $(DISABLE_LTO)

# Sanitizer runtimes are unavailable and cannot be linked here.
KASAN_SANITIZE := n
UBSAN_SANITIZE := n
Expand Down Expand Up @@ -92,7 +90,7 @@ ifneq ($(RETPOLINE_VDSO_CFLAGS),)
endif
endif

$(vobjs): KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS) $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS)) $(CFL)
$(vobjs): KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO) $(GCC_PLUGINS_CFLAGS) $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS)) $(CFL)

#
# vDSO code runs in userspace and -pg doesn't help with profiling anyway.
Expand Down Expand Up @@ -150,6 +148,7 @@ KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 := $(filter-out $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 := $(filter-out $(CC_FLAGS_LTO),$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic
KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector)
KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls)
Expand Down
1 change: 1 addition & 0 deletions arch/x86/include/asm/irq_stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ static __always_inline bool irq_needs_irq_stack(struct pt_regs *regs)
return !user_mode(regs) && !irqstack_active();
}

__nocfi
static __always_inline void run_on_irqstack_cond(void *func, void *arg,
struct pt_regs *regs)
{
Expand Down
1 change: 1 addition & 0 deletions arch/x86/include/asm/sections.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <asm/extable.h>

extern char __brk_base[], __brk_limit[];
extern char __cfi_jt_start[], __cfi_jt_end[];
extern char __end_rodata_aligned[];

#if defined(CONFIG_X86_64)
Expand Down
Loading

0 comments on commit ca5d2ee

Please sign in to comment.