diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/asm-generic/bug.h | 16 | ||||
-rw-r--r-- | include/asm-generic/vmlinux.lds.h | 20 | ||||
-rw-r--r-- | include/linux/bpf.h | 4 | ||||
-rw-r--r-- | include/linux/cfi.h | 41 | ||||
-rw-r--r-- | include/linux/compiler-clang.h | 3 | ||||
-rw-r--r-- | include/linux/compiler_types.h | 8 | ||||
-rw-r--r-- | include/linux/init.h | 6 | ||||
-rw-r--r-- | include/linux/list_sort.h | 7 | ||||
-rw-r--r-- | include/linux/mm.h | 10 | ||||
-rw-r--r-- | include/linux/module.h | 13 | ||||
-rw-r--r-- | include/linux/pci.h | 4 |
11 files changed, 119 insertions, 13 deletions
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h index 76a10e0dca9f..b402494883b6 100644 --- a/include/asm-generic/bug.h +++ b/include/asm-generic/bug.h @@ -241,6 +241,22 @@ void __warn(const char *file, int line, void *caller, unsigned taint, # define WARN_ON_SMP(x) ({0;}) #endif +/* + * WARN_ON_FUNCTION_MISMATCH() warns if a value doesn't match a + * function address, and can be useful for catching issues with + * callback functions, for example. + * + * With CONFIG_CFI_CLANG, the warning is disabled because the + * compiler replaces function addresses taken in C code with + * local jump table addresses, which breaks cross-module function + * address equality. + */ +#if defined(CONFIG_CFI_CLANG) && defined(CONFIG_MODULES) +# define WARN_ON_FUNCTION_MISMATCH(x, fn) ({ 0; }) +#else +# define WARN_ON_FUNCTION_MISMATCH(x, fn) WARN_ON_ONCE((x) != (fn)) +#endif + #endif /* __ASSEMBLY__ */ #endif diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 0331d5d49551..40a9c101565e 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -544,6 +544,22 @@ . = ALIGN((align)); \ __end_rodata = .; + +/* + * .text..L.cfi.jumptable.* contain Control-Flow Integrity (CFI) + * jump table entries. + */ +#ifdef CONFIG_CFI_CLANG +#define TEXT_CFI_JT \ + . = ALIGN(PMD_SIZE); \ + __cfi_jt_start = .; \ + *(.text..L.cfi.jumptable .text..L.cfi.jumptable.*) \ + . = ALIGN(PMD_SIZE); \ + __cfi_jt_end = .; +#else +#define TEXT_CFI_JT +#endif + /* * Non-instrumentable text section */ @@ -570,6 +586,7 @@ NOINSTR_TEXT \ *(.text..refcount) \ *(.ref.text) \ + TEXT_CFI_JT \ MEM_KEEP(init.text*) \ MEM_KEEP(exit.text*) \ @@ -974,7 +991,8 @@ * keep any .init_array.* sections. * https://bugs.llvm.org/show_bug.cgi?id=46478 */ -#if defined(CONFIG_GCOV_KERNEL) || defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KCSAN) +#if defined(CONFIG_GCOV_KERNEL) || defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KCSAN) || \ + defined(CONFIG_CFI_CLANG) # ifdef CONFIG_CONSTRUCTORS # define SANITIZER_DISCARDS \ *(.eh_frame) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index fdac0534ce79..00597b0c719c 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -652,7 +652,7 @@ struct bpf_dispatcher { struct bpf_ksym ksym; }; -static __always_inline unsigned int bpf_dispatcher_nop_func( +static __always_inline __nocfi unsigned int bpf_dispatcher_nop_func( const void *ctx, const struct bpf_insn *insnsi, unsigned int (*bpf_func)(const void *, @@ -680,7 +680,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr); } #define DEFINE_BPF_DISPATCHER(name) \ - noinline unsigned int bpf_dispatcher_##name##_func( \ + noinline __nocfi unsigned int bpf_dispatcher_##name##_func( \ const void *ctx, \ const struct bpf_insn *insnsi, \ unsigned int (*bpf_func)(const void *, \ diff --git a/include/linux/cfi.h b/include/linux/cfi.h new file mode 100644 index 000000000000..879744aaa6e0 --- /dev/null +++ b/include/linux/cfi.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Clang Control Flow Integrity (CFI) support. + * + * Copyright (C) 2021 Google LLC + */ +#ifndef _LINUX_CFI_H +#define _LINUX_CFI_H + +#ifdef CONFIG_CFI_CLANG +typedef void (*cfi_check_fn)(uint64_t id, void *ptr, void *diag); + +/* Compiler-generated function in each module, and the kernel */ +extern void __cfi_check(uint64_t id, void *ptr, void *diag); + +/* + * Force the compiler to generate a CFI jump table entry for a function + * and store the jump table address to __cfi_jt_<function>. + */ +#define __CFI_ADDRESSABLE(fn, __attr) \ + const void *__cfi_jt_ ## fn __visible __attr = (void *)&fn + +#ifdef CONFIG_CFI_CLANG_SHADOW + +extern void cfi_module_add(struct module *mod, unsigned long base_addr); +extern void cfi_module_remove(struct module *mod, unsigned long base_addr); + +#else + +static inline void cfi_module_add(struct module *mod, unsigned long base_addr) {} +static inline void cfi_module_remove(struct module *mod, unsigned long base_addr) {} + +#endif /* CONFIG_CFI_CLANG_SHADOW */ + +#else /* !CONFIG_CFI_CLANG */ + +#define __CFI_ADDRESSABLE(fn, __attr) + +#endif /* CONFIG_CFI_CLANG */ + +#endif /* _LINUX_CFI_H */ diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index d217c382b02d..adbe76b203e2 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -61,3 +61,6 @@ #if __has_feature(shadow_call_stack) # define __noscs __attribute__((__no_sanitize__("shadow-call-stack"))) #endif + +#define __nocfi __attribute__((__no_sanitize__("cfi"))) +#define __cficanonical __attribute__((__cfi_canonical_jump_table__)) diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index e5dd5a4ae946..d29bda7f6ebd 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -242,6 +242,14 @@ struct ftrace_likely_data { # define __noscs #endif +#ifndef __nocfi +# define __nocfi +#endif + +#ifndef __cficanonical +# define __cficanonical +#endif + #ifndef asm_volatile_goto #define asm_volatile_goto(x...) asm goto(x) #endif diff --git a/include/linux/init.h b/include/linux/init.h index 31f54de58429..045ad1650ed1 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -47,7 +47,7 @@ /* These are for everybody (although not all archs will actually discard it in modules) */ -#define __init __section(".init.text") __cold __latent_entropy __noinitretpoline +#define __init __section(".init.text") __cold __latent_entropy __noinitretpoline __nocfi #define __initdata __section(".init.data") #define __initconst __section(".init.rodata") #define __exitdata __section(".exit.data") @@ -220,8 +220,8 @@ extern bool initcall_debug; __initcall_name(initstub, __iid, id) #define __define_initcall_stub(__stub, fn) \ - int __init __stub(void); \ - int __init __stub(void) \ + int __init __cficanonical __stub(void); \ + int __init __cficanonical __stub(void) \ { \ return fn(); \ } \ diff --git a/include/linux/list_sort.h b/include/linux/list_sort.h index 20f178c24e9d..453105f74e05 100644 --- a/include/linux/list_sort.h +++ b/include/linux/list_sort.h @@ -6,8 +6,9 @@ struct list_head; +typedef int __attribute__((nonnull(2,3))) (*list_cmp_func_t)(void *, + const struct list_head *, const struct list_head *); + __attribute__((nonnull(2,3))) -void list_sort(void *priv, struct list_head *head, - int (*cmp)(void *priv, struct list_head *a, - struct list_head *b)); +void list_sort(void *priv, struct list_head *head, list_cmp_func_t cmp); #endif diff --git a/include/linux/mm.h b/include/linux/mm.h index 616dcaf08d99..06094627f1c1 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -125,6 +125,16 @@ extern int mmap_rnd_compat_bits __read_mostly; #endif /* + * With CONFIG_CFI_CLANG, the compiler replaces function addresses in + * instrumented C code with jump table addresses. Architectures that + * support CFI can define this macro to return the actual function address + * when needed. + */ +#ifndef function_nocfi +#define function_nocfi(x) (x) +#endif + +/* * To prevent common memory management code establishing * a zero page mapping on a read fault. * This macro should be defined within <asm/pgtable.h>. diff --git a/include/linux/module.h b/include/linux/module.h index da4b6fbe8ebe..8100bb477d86 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -26,6 +26,7 @@ #include <linux/tracepoint-defs.h> #include <linux/srcu.h> #include <linux/static_call_types.h> +#include <linux/cfi.h> #include <linux/percpu.h> #include <asm/module.h> @@ -128,13 +129,17 @@ extern void cleanup_module(void); #define module_init(initfn) \ static inline initcall_t __maybe_unused __inittest(void) \ { return initfn; } \ - int init_module(void) __copy(initfn) __attribute__((alias(#initfn))); + int init_module(void) __copy(initfn) \ + __attribute__((alias(#initfn))); \ + __CFI_ADDRESSABLE(init_module, __initdata); /* This is only required if you want to be unloadable. */ #define module_exit(exitfn) \ static inline exitcall_t __maybe_unused __exittest(void) \ { return exitfn; } \ - void cleanup_module(void) __copy(exitfn) __attribute__((alias(#exitfn))); + void cleanup_module(void) __copy(exitfn) \ + __attribute__((alias(#exitfn))); \ + __CFI_ADDRESSABLE(cleanup_module, __exitdata); #endif @@ -376,6 +381,10 @@ struct module { const s32 *crcs; unsigned int num_syms; +#ifdef CONFIG_CFI_CLANG + cfi_check_fn cfi_check; +#endif + /* Kernel parameters. */ #ifdef CONFIG_SYSFS struct mutex param_lock; diff --git a/include/linux/pci.h b/include/linux/pci.h index 86c799c97b77..39684b72db91 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1944,8 +1944,8 @@ enum pci_fixup_pass { #ifdef CONFIG_LTO_CLANG #define __DECLARE_PCI_FIXUP_SECTION(sec, name, vendor, device, class, \ class_shift, hook, stub) \ - void stub(struct pci_dev *dev); \ - void stub(struct pci_dev *dev) \ + void __cficanonical stub(struct pci_dev *dev); \ + void __cficanonical stub(struct pci_dev *dev) \ { \ hook(dev); \ } \ |