mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
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
This commit is contained in:
commit
57fa2369ab
75 files changed
+760
-113
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -99,7 +99,8 @@ static int acpi_parking_protocol_cpu_boot(unsigned int cpu)
|
||||
* that read this address need to convert this address to the
|
||||
* Boot-Loader's endianness before jumping.
|
||||
*/
|
||||
writeq_relaxed(__pa_symbol(secondary_entry), &mailbox->entry_point);
|
||||
writeq_relaxed(__pa_symbol(function_nocfi(secondary_entry)),
|
||||
&mailbox->entry_point);
|
||||
writel_relaxed(cpu_entry->gic_cpu_id, &mailbox->cpu_id);
|
||||
|
||||
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
|
||||
|
||||
@@ -133,8 +133,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;
|
||||
|
||||
@@ -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_symbol(function_nocfi(__cpu_soft_restart));
|
||||
|
||||
cpu_install_idmap();
|
||||
restart(el2_switch, entry, arg0, arg1, arg2);
|
||||
|
||||
@@ -1451,7 +1451,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);
|
||||
@@ -1468,7 +1468,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_symbol(function_nocfi(idmap_kpti_install_ng_mappings));
|
||||
|
||||
cpu_install_idmap();
|
||||
remap_fn(cpu, num_online_cpus(), __pa_symbol(swapper_pg_dir));
|
||||
|
||||
@@ -55,7 +55,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
|
||||
unsigned long pc;
|
||||
u32 new;
|
||||
|
||||
pc = (unsigned long)&ftrace_call;
|
||||
pc = (unsigned long)function_nocfi(ftrace_call);
|
||||
new = aarch64_insn_gen_branch_imm(pc, (unsigned long)func,
|
||||
AARCH64_INSN_BRANCH_LINK);
|
||||
|
||||
|
||||
@@ -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));
|
||||
phys_addr_t pa_secondary_entry = __pa_symbol(function_nocfi(secondary_entry));
|
||||
int err = psci_ops.cpu_on(cpu_logical_map(cpu), pa_secondary_entry);
|
||||
if (err)
|
||||
pr_err("failed to boot CPU%d (%d)\n", cpu, err);
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ static int smp_spin_table_cpu_init(unsigned int cpu)
|
||||
static int smp_spin_table_cpu_prepare(unsigned int cpu)
|
||||
{
|
||||
__le64 __iomem *release_addr;
|
||||
phys_addr_t pa_holding_pen = __pa_symbol(function_nocfi(secondary_holding_pen));
|
||||
|
||||
if (!cpu_release_addr[cpu])
|
||||
return -ENODEV;
|
||||
@@ -88,7 +89,7 @@ static int smp_spin_table_cpu_prepare(unsigned int cpu)
|
||||
* boot-loader's endianness before jumping. This is mandated by
|
||||
* the boot protocol.
|
||||
*/
|
||||
writeq_relaxed(__pa_symbol(secondary_holding_pen), release_addr);
|
||||
writeq_relaxed(pa_holding_pen, release_addr);
|
||||
__flush_dcache_area((__force void *)release_addr,
|
||||
sizeof(*release_addr));
|
||||
|
||||
|
||||
@@ -75,9 +75,9 @@ quiet_cmd_hyprel = HYPREL $@
|
||||
quiet_cmd_hypcopy = HYPCOPY $@
|
||||
cmd_hypcopy = $(OBJCOPY) --prefix-symbols=__kvm_nvhe_ $< $@
|
||||
|
||||
# Remove ftrace and Shadow Call Stack CFLAGS.
|
||||
# This is equivalent to the 'notrace' and '__noscs' annotations.
|
||||
KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS), $(KBUILD_CFLAGS))
|
||||
# Remove ftrace, Shadow Call Stack, and CFI CFLAGS.
|
||||
# This is equivalent to the 'notrace', '__noscs', and '__nocfi' annotations.
|
||||
KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) $(CC_FLAGS_CFI), $(KBUILD_CFLAGS))
|
||||
|
||||
# KVM nVHE code is run at a different exception code with a different map, so
|
||||
# compiler instrumentation that inserts callbacks or checks into the code may
|
||||
|
||||
@@ -2190,8 +2190,8 @@ static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int vgic_its_ite_cmp(void *priv, struct list_head *a,
|
||||
struct list_head *b)
|
||||
static int vgic_its_ite_cmp(void *priv, const struct list_head *a,
|
||||
const struct list_head *b)
|
||||
{
|
||||
struct its_ite *itea = container_of(a, struct its_ite, ite_list);
|
||||
struct its_ite *iteb = container_of(b, struct its_ite, ite_list);
|
||||
@@ -2329,8 +2329,8 @@ static int vgic_its_restore_dte(struct vgic_its *its, u32 id,
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int vgic_its_device_cmp(void *priv, struct list_head *a,
|
||||
struct list_head *b)
|
||||
static int vgic_its_device_cmp(void *priv, const struct list_head *a,
|
||||
const struct list_head *b)
|
||||
{
|
||||
struct its_device *deva = container_of(a, struct its_device, dev_list);
|
||||
struct its_device *devb = container_of(b, struct its_device, dev_list);
|
||||
|
||||
@@ -255,7 +255,8 @@ static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
|
||||
* Return negative if "a" sorts before "b", 0 to preserve order, and positive
|
||||
* to sort "b" before "a".
|
||||
*/
|
||||
static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
|
||||
static int vgic_irq_cmp(void *priv, const struct list_head *a,
|
||||
const struct list_head *b)
|
||||
{
|
||||
struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list);
|
||||
struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list);
|
||||
|
||||
@@ -75,7 +75,8 @@ void blk_mq_sched_restart(struct blk_mq_hw_ctx *hctx)
|
||||
blk_mq_run_hw_queue(hctx, true);
|
||||
}
|
||||
|
||||
static int sched_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
|
||||
static int sched_rq_cmp(void *priv, const struct list_head *a,
|
||||
const struct list_head *b)
|
||||
{
|
||||
struct request *rqa = container_of(a, struct request, queuelist);
|
||||
struct request *rqb = container_of(b, struct request, queuelist);
|
||||
|
||||
+2
-1
@@ -1895,7 +1895,8 @@ void blk_mq_insert_requests(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
|
||||
spin_unlock(&ctx->lock);
|
||||
}
|
||||
|
||||
static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
|
||||
static int plug_rq_cmp(void *priv, const struct list_head *a,
|
||||
const struct list_head *b)
|
||||
{
|
||||
struct request *rqa = container_of(a, struct request, queuelist);
|
||||
struct request *rqb = container_of(b, struct request, queuelist);
|
||||
|
||||
@@ -1195,7 +1195,8 @@ static int __nfit_mem_init(struct acpi_nfit_desc *acpi_desc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfit_mem_cmp(void *priv, struct list_head *_a, struct list_head *_b)
|
||||
static int nfit_mem_cmp(void *priv, const struct list_head *_a,
|
||||
const struct list_head *_b)
|
||||
{
|
||||
struct nfit_mem *a = container_of(_a, typeof(*a), list);
|
||||
struct nfit_mem *b = container_of(_b, typeof(*b), list);
|
||||
|
||||
@@ -558,7 +558,8 @@ static bool hmat_update_best(u8 type, u32 value, u32 *best)
|
||||
return updated;
|
||||
}
|
||||
|
||||
static int initiator_cmp(void *priv, struct list_head *a, struct list_head *b)
|
||||
static int initiator_cmp(void *priv, const struct list_head *a,
|
||||
const struct list_head *b)
|
||||
{
|
||||
struct memory_initiator *ia;
|
||||
struct memory_initiator *ib;
|
||||
|
||||
@@ -503,8 +503,8 @@ static int ti_sci_scan_clocks_from_fw(struct sci_clk_provider *provider)
|
||||
|
||||
#else
|
||||
|
||||
static int _cmp_sci_clk_list(void *priv, struct list_head *a,
|
||||
struct list_head *b)
|
||||
static int _cmp_sci_clk_list(void *priv, const struct list_head *a,
|
||||
const struct list_head *b)
|
||||
{
|
||||
struct sci_clk *ca = container_of(a, struct sci_clk, node);
|
||||
struct sci_clk *cb = container_of(b, struct sci_clk, node);
|
||||
|
||||
Loaded 20 of 75 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user