Skip to content

Commit

Permalink
Merge tag 'cfi-v5.13-rc1' of git://git.kernel.org/pub/scm/linux/kerne…
Browse files Browse the repository at this point in the history
…l/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
  • Loading branch information
torvalds committed Apr 27, 2021
2 parents 2fbc66c + 9186ad8 commit 57fa236
Show file tree
Hide file tree
Showing 75 changed files with 760 additions and 113 deletions.
17 changes: 17 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
45 changes: 45 additions & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
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 @@ -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
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 @@ -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;
Expand All @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion arch/arm64/kernel/acpi_parking_protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
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 @@ -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;
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_symbol(function_nocfi(__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 @@ -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);
Expand All @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

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));
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);

Expand Down
3 changes: 2 additions & 1 deletion arch/arm64/kernel/smp_spin_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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));

Expand Down
6 changes: 3 additions & 3 deletions arch/arm64/kvm/hyp/nvhe/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions arch/arm64/kvm/vgic/vgic-its.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion arch/arm64/kvm/vgic/vgic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion block/blk-mq-sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion block/blk-mq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion drivers/acpi/nfit/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion drivers/acpi/numa/hmat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions drivers/clk/keystone/sci-clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 5 additions & 2 deletions drivers/firmware/psci/psci.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,9 @@ static int __init psci_features(u32 psci_func_id)
static int psci_suspend_finisher(unsigned long state)
{
u32 power_state = state;
phys_addr_t pa_cpu_resume = __pa_symbol(function_nocfi(cpu_resume));

return psci_ops.cpu_suspend(power_state, __pa_symbol(cpu_resume));
return psci_ops.cpu_suspend(power_state, pa_cpu_resume);
}

int psci_cpu_suspend_enter(u32 state)
Expand All @@ -344,8 +345,10 @@ int psci_cpu_suspend_enter(u32 state)

static int psci_system_suspend(unsigned long unused)
{
phys_addr_t pa_cpu_resume = __pa_symbol(function_nocfi(cpu_resume));

return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND),
__pa_symbol(cpu_resume), 0, 0);
pa_cpu_resume, 0, 0);
}

static int psci_system_suspend_enter(suspend_state_t state)
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/drm_modes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1290,7 +1290,8 @@ EXPORT_SYMBOL(drm_mode_prune_invalid);
* Negative if @lh_a is better than @lh_b, zero if they're equivalent, or
* positive if @lh_b is better than @lh_a.
*/
static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b)
static int drm_mode_compare(void *priv, const struct list_head *lh_a,
const struct list_head *lh_b)
{
struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/i915/gt/intel_engine_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ static const u8 uabi_classes[] = {
[VIDEO_ENHANCEMENT_CLASS] = I915_ENGINE_CLASS_VIDEO_ENHANCE,
};

static int engine_cmp(void *priv, struct list_head *A, struct list_head *B)
static int engine_cmp(void *priv, const struct list_head *A,
const struct list_head *B)
{
const struct intel_engine_cs *a =
container_of((struct rb_node *)A, typeof(*a), uabi_node);
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/gvt/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ struct diff_mmio {

/* Compare two diff_mmio items. */
static int mmio_offset_compare(void *priv,
struct list_head *a, struct list_head *b)
const struct list_head *a, const struct list_head *b)
{
struct diff_mmio *ma;
struct diff_mmio *mb;
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,8 @@ static int igt_ppgtt_shrink_boom(void *arg)
return exercise_ppgtt(arg, shrink_boom);
}

static int sort_holes(void *priv, struct list_head *A, struct list_head *B)
static int sort_holes(void *priv, const struct list_head *A,
const struct list_head *B)
{
struct drm_mm_node *a = list_entry(A, typeof(*a), hole_stack);
struct drm_mm_node *b = list_entry(B, typeof(*b), hole_stack);
Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/radeon/radeon_cs.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,8 +393,8 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
return 0;
}

static int cmp_size_smaller_first(void *priv, struct list_head *a,
struct list_head *b)
static int cmp_size_smaller_first(void *priv, const struct list_head *a,
const struct list_head *b)
{
struct radeon_bo_list *la = list_entry(a, struct radeon_bo_list, tv.head);
struct radeon_bo_list *lb = list_entry(b, struct radeon_bo_list, tv.head);
Expand Down
Loading

0 comments on commit 57fa236

Please sign in to comment.