Skip to content

Commit 57fa236

Browse files
committed
Merge tag 'cfi-v5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
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
2 parents 2fbc66c + 9186ad8 commit 57fa236

75 files changed

Lines changed: 760 additions & 113 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Makefile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,23 @@ KBUILD_AFLAGS += -fno-lto
924924
export CC_FLAGS_LTO
925925
endif
926926

927+
ifdef CONFIG_CFI_CLANG
928+
CC_FLAGS_CFI := -fsanitize=cfi \
929+
-fsanitize-cfi-cross-dso \
930+
-fno-sanitize-cfi-canonical-jump-tables \
931+
-fno-sanitize-trap=cfi \
932+
-fno-sanitize-blacklist
933+
934+
ifdef CONFIG_CFI_PERMISSIVE
935+
CC_FLAGS_CFI += -fsanitize-recover=cfi
936+
endif
937+
938+
# If LTO flags are filtered out, we must also filter out CFI.
939+
CC_FLAGS_LTO += $(CC_FLAGS_CFI)
940+
KBUILD_CFLAGS += $(CC_FLAGS_CFI)
941+
export CC_FLAGS_CFI
942+
endif
943+
927944
ifdef CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B
928945
KBUILD_CFLAGS += -falign-functions=32
929946
endif

arch/Kconfig

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,51 @@ config LTO_CLANG_THIN
692692
If unsure, say Y.
693693
endchoice
694694

695+
config ARCH_SUPPORTS_CFI_CLANG
696+
bool
697+
help
698+
An architecture should select this option if it can support Clang's
699+
Control-Flow Integrity (CFI) checking.
700+
701+
config CFI_CLANG
702+
bool "Use Clang's Control Flow Integrity (CFI)"
703+
depends on LTO_CLANG && ARCH_SUPPORTS_CFI_CLANG
704+
# Clang >= 12:
705+
# - https://bugs.llvm.org/show_bug.cgi?id=46258
706+
# - https://bugs.llvm.org/show_bug.cgi?id=47479
707+
depends on CLANG_VERSION >= 120000
708+
select KALLSYMS
709+
help
710+
This option enables Clang’s forward-edge Control Flow Integrity
711+
(CFI) checking, where the compiler injects a runtime check to each
712+
indirect function call to ensure the target is a valid function with
713+
the correct static type. This restricts possible call targets and
714+
makes it more difficult for an attacker to exploit bugs that allow
715+
the modification of stored function pointers. More information can be
716+
found from Clang's documentation:
717+
718+
https://clang.llvm.org/docs/ControlFlowIntegrity.html
719+
720+
config CFI_CLANG_SHADOW
721+
bool "Use CFI shadow to speed up cross-module checks"
722+
default y
723+
depends on CFI_CLANG && MODULES
724+
help
725+
If you select this option, the kernel builds a fast look-up table of
726+
CFI check functions in loaded modules to reduce performance overhead.
727+
728+
If unsure, say Y.
729+
730+
config CFI_PERMISSIVE
731+
bool "Use CFI in permissive mode"
732+
depends on CFI_CLANG
733+
help
734+
When selected, Control Flow Integrity (CFI) violations result in a
735+
warning instead of a kernel panic. This option should only be used
736+
for finding indirect call type mismatches during development.
737+
738+
If unsure, say N.
739+
695740
config HAVE_ARCH_WITHIN_STACK_FRAMES
696741
bool
697742
help

arch/arm64/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ config ARM64
7575
select ARCH_SUPPORTS_SHADOW_CALL_STACK if CC_HAVE_SHADOW_CALL_STACK
7676
select ARCH_SUPPORTS_LTO_CLANG if CPU_LITTLE_ENDIAN
7777
select ARCH_SUPPORTS_LTO_CLANG_THIN
78+
select ARCH_SUPPORTS_CFI_CLANG
7879
select ARCH_SUPPORTS_ATOMIC_RMW
7980
select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 && (GCC_VERSION >= 50000 || CC_IS_CLANG)
8081
select ARCH_SUPPORTS_NUMA_BALANCING

arch/arm64/include/asm/memory.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,22 @@ static inline void *phys_to_virt(phys_addr_t x)
323323
#define virt_to_pfn(x) __phys_to_pfn(__virt_to_phys((unsigned long)(x)))
324324
#define sym_to_pfn(x) __phys_to_pfn(__pa_symbol(x))
325325

326+
#ifdef CONFIG_CFI_CLANG
327+
/*
328+
* With CONFIG_CFI_CLANG, the compiler replaces function address
329+
* references with the address of the function's CFI jump table
330+
* entry. The function_nocfi macro always returns the address of the
331+
* actual function instead.
332+
*/
333+
#define function_nocfi(x) ({ \
334+
void *addr; \
335+
asm("adrp %0, " __stringify(x) "\n\t" \
336+
"add %0, %0, :lo12:" __stringify(x) \
337+
: "=r" (addr)); \
338+
addr; \
339+
})
340+
#endif
341+
326342
/*
327343
* virt_to_page(x) convert a _valid_ virtual address to struct page *
328344
* virt_addr_valid(x) indicates whether a virtual address is valid

arch/arm64/include/asm/mmu_context.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ static inline void cpu_install_idmap(void)
119119
* Atomically replaces the active TTBR1_EL1 PGD with a new VA-compatible PGD,
120120
* avoiding the possibility of conflicting TLB entries being allocated.
121121
*/
122-
static inline void cpu_replace_ttbr1(pgd_t *pgdp)
122+
static inline void __nocfi cpu_replace_ttbr1(pgd_t *pgdp)
123123
{
124124
typedef void (ttbr_replace_func)(phys_addr_t);
125125
extern ttbr_replace_func idmap_cpu_replace_ttbr1;
@@ -140,7 +140,7 @@ static inline void cpu_replace_ttbr1(pgd_t *pgdp)
140140
ttbr1 |= TTBR_CNP_BIT;
141141
}
142142

143-
replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1);
143+
replace_phys = (void *)__pa_symbol(function_nocfi(idmap_cpu_replace_ttbr1));
144144

145145
cpu_install_idmap();
146146
replace_phys(ttbr1);

arch/arm64/kernel/acpi_parking_protocol.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ static int acpi_parking_protocol_cpu_boot(unsigned int cpu)
9999
* that read this address need to convert this address to the
100100
* Boot-Loader's endianness before jumping.
101101
*/
102-
writeq_relaxed(__pa_symbol(secondary_entry), &mailbox->entry_point);
102+
writeq_relaxed(__pa_symbol(function_nocfi(secondary_entry)),
103+
&mailbox->entry_point);
103104
writel_relaxed(cpu_entry->gic_cpu_id, &mailbox->cpu_id);
104105

105106
arch_send_wakeup_ipi_mask(cpumask_of(cpu));

arch/arm64/kernel/alternative.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ static void clean_dcache_range_nopatch(u64 start, u64 end)
133133
} while (cur += d_size, cur < end);
134134
}
135135

136-
static void __apply_alternatives(void *alt_region, bool is_module,
137-
unsigned long *feature_mask)
136+
static void __nocfi __apply_alternatives(void *alt_region, bool is_module,
137+
unsigned long *feature_mask)
138138
{
139139
struct alt_instr *alt;
140140
struct alt_region *region = alt_region;

arch/arm64/kernel/cpu-reset.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@
1313
void __cpu_soft_restart(unsigned long el2_switch, unsigned long entry,
1414
unsigned long arg0, unsigned long arg1, unsigned long arg2);
1515

16-
static inline void __noreturn cpu_soft_restart(unsigned long entry,
17-
unsigned long arg0,
18-
unsigned long arg1,
19-
unsigned long arg2)
16+
static inline void __noreturn __nocfi cpu_soft_restart(unsigned long entry,
17+
unsigned long arg0,
18+
unsigned long arg1,
19+
unsigned long arg2)
2020
{
2121
typeof(__cpu_soft_restart) *restart;
2222

2323
unsigned long el2_switch = !is_kernel_in_hyp_mode() &&
2424
is_hyp_mode_available();
25-
restart = (void *)__pa_symbol(__cpu_soft_restart);
25+
restart = (void *)__pa_symbol(function_nocfi(__cpu_soft_restart));
2626

2727
cpu_install_idmap();
2828
restart(el2_switch, entry, arg0, arg1, arg2);

arch/arm64/kernel/cpufeature.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,7 +1451,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
14511451
}
14521452

14531453
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
1454-
static void
1454+
static void __nocfi
14551455
kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
14561456
{
14571457
typedef void (kpti_remap_fn)(int, int, phys_addr_t);
@@ -1468,7 +1468,7 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
14681468
if (arm64_use_ng_mappings)
14691469
return;
14701470

1471-
remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
1471+
remap_fn = (void *)__pa_symbol(function_nocfi(idmap_kpti_install_ng_mappings));
14721472

14731473
cpu_install_idmap();
14741474
remap_fn(cpu, num_online_cpus(), __pa_symbol(swapper_pg_dir));

arch/arm64/kernel/ftrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
5555
unsigned long pc;
5656
u32 new;
5757

58-
pc = (unsigned long)&ftrace_call;
58+
pc = (unsigned long)function_nocfi(ftrace_call);
5959
new = aarch64_insn_gen_branch_imm(pc, (unsigned long)func,
6060
AARCH64_INSN_BRANCH_LINK);
6161

0 commit comments

Comments
 (0)