linux/arch/arm64/Makefile
Mark Rutland c68cf5285e arm64: pauth: don't sign leaf functions
Currently, when CONFIG_ARM64_PTR_AUTH_KERNEL=y (and
CONFIG_UNWIND_PATCH_PAC_INTO_SCS=n), we enable pointer authentication
for all functions, including leaf functions. This isn't necessary, and
is unfortunate for a few reasons:

* Any PACIASP instruction is implicitly a `BTI C` landing pad, and
  forcing the addition of a PACIASP in every function introduces a
  larger set of BTI gadgets than is necessary.

* The PACIASP and AUTIASP instructions make leaf functions larger than
  necessary, bloating the kernel Image. For a defconfig v6.2-rc3 kernel,
  this appears to add ~64KiB relative to not signing leaf functions,
  which is unfortunate but not entirely onerous.

* The PACIASP and AUTIASP instructions potentially make leaf functions
  more expensive in terms of performance and/or power. For many trivial
  leaf functions, this is clearly unnecessary, e.g.

  | <arch_local_save_flags>:
  |        d503233f        paciasp
  |        d53b4220        mrs     x0, daif
  |        d50323bf        autiasp
  |        d65f03c0        ret

  | <calibration_delay_done>:
  |        d503233f        paciasp
  |        d50323bf        autiasp
  |        d65f03c0        ret
  |        d503201f        nop

* When CONFIG_UNWIND_PATCH_PAC_INTO_SCS=y we disable pointer
  authentication for leaf functions, so clearly this is not functionally
  necessary, indicates we have an inconsistent threat model, and
  convolutes the Makefile logic.

We've used pointer authentication in leaf functions since the
introduction of in-kernel pointer authentication in commit:

  74afda4016a7437e ("arm64: compile the kernel with ptrauth return address signing")

... but at the time we had no rationale for signing leaf functions.

Subsequently, we considered avoiding signing leaf functions:

  https://lore.kernel.org/linux-arm-kernel/1586856741-26839-1-git-send-email-amit.kachhap@arm.com/
  https://lore.kernel.org/linux-arm-kernel/1588149371-20310-1-git-send-email-amit.kachhap@arm.com/

... however at the time we didn't have an abundance of reasons to avoid
signing leaf functions as above (e.g. the BTI case), we had no hardware
to make performance measurements, and it was reasoned that this gave
some level of protection against a limited set of code-reuse gadgets
which would fall through to a RET. We documented this in commit:

  717b938e22f8dbf0 ("arm64: Document why we enable PAC support for leaf functions")

Notably, this was before we supported any forward-edge CFI scheme (e.g.
Arm BTI, or Clang CFI/kCFI), which would prevent jumping into the middle
of a function.

In addition, even with signing forced for leaf functions, AUTIASP may be
placed before a number of instructions which might constitute such a
gadget, e.g.

| <user_regs_reset_single_step>:
|        f9400022        ldr     x2, [x1]
|        d503233f        paciasp
|        d50323bf        autiasp
|        f9408401        ldr     x1, [x0, #264]
|        720b005f        tst     w2, #0x200000
|        b26b0022        orr     x2, x1, #0x200000
|        926af821        and     x1, x1, #0xffffffffffdfffff
|        9a820021        csel    x1, x1, x2, eq  // eq = none
|        f9008401        str     x1, [x0, #264]
|        d65f03c0        ret

| <fpsimd_cpu_dead>:
|        2a0003e3        mov     w3, w0
|        9000ff42        adrp    x2, ffff800009ffd000 <xen_dynamic_chip+0x48>
|        9120e042        add     x2, x2, #0x838
|        52800000        mov     w0, #0x0                        // #0
|        d503233f        paciasp
|        f000d041        adrp    x1, ffff800009a20000 <this_cpu_vector>
|        d50323bf        autiasp
|        9102c021        add     x1, x1, #0xb0
|        f8635842        ldr     x2, [x2, w3, uxtw #3]
|        f821685f        str     xzr, [x2, x1]
|        d65f03c0        ret
|        d503201f        nop

So generally, trying to use AUTIASP to detect such gadgetization is not
robust, and this is dealt with far better by forward-edge CFI (which is
designed to prevent such cases). We should bite the bullet and stop
pretending that AUTIASP is a mitigation for such forward-edge
gadgetization.

For the above reasons, this patch has the kernel consistently sign
non-leaf functions and avoid signing leaf functions.

Considering a defconfig v6.2-rc3 kernel built with LLVM 15.0.6:

* The vmlinux is ~43KiB smaller:

  | [mark@lakrids:~/src/linux]% ls -al vmlinux-*
  | -rwxr-xr-x 1 mark mark 338547808 Jan 25 17:17 vmlinux-after
  | -rwxr-xr-x 1 mark mark 338591472 Jan 25 17:22 vmlinux-before

* The resulting Image is 64KiB smaller:

  | [mark@lakrids:~/src/linux]% ls -al Image-*
  | -rwxr-xr-x 1 mark mark 32702976 Jan 25 17:17 Image-after
  | -rwxr-xr-x 1 mark mark 32768512 Jan 25 17:22 Image-before

* There are ~400 fewer BTI gadgets:

  | [mark@lakrids:~/src/linux]% usekorg 12.1.0 aarch64-linux-objdump -d vmlinux-before 2> /dev/null | grep -ow 'paciasp\|bti\sc\?' | sort | uniq -c
  |    1219 bti     c
  |   61982 paciasp

  | [mark@lakrids:~/src/linux]% usekorg 12.1.0 aarch64-linux-objdump -d vmlinux-after 2> /dev/null | grep -ow 'paciasp\|bti\sc\?' | sort | uniq -c
  |   10099 bti     c
  |   52699 paciasp

  Which is +8880 BTIs, and -9283 PACIASPs, for -403 unnecessary BTI
  gadgets. While this is small relative to the total, distinguishing the
  two cases will make it easier to analyse and reduce this set further
  in future.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Mark Brown <broonie@kernel.org>
Cc: Amit Daniel Kachhap <amit.kachhap@arm.com>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20230131105809.991288-3-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2023-01-31 16:03:37 +00:00

214 lines
6.9 KiB
Makefile

#
# arch/arm64/Makefile
#
# This file is included by the global makefile so that you can add your own
# architecture-specific flags and dependencies.
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
# Copyright (C) 1995-2001 by Russell King
LDFLAGS_vmlinux :=--no-undefined -X
ifeq ($(CONFIG_RELOCATABLE), y)
# Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour
# for relative relocs, since this leads to better Image compression
# with the relocation offsets always being zero.
LDFLAGS_vmlinux += -shared -Bsymbolic -z notext \
$(call ld-option, --no-apply-dynamic-relocs)
endif
ifeq ($(CONFIG_ARM64_ERRATUM_843419),y)
ifeq ($(CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419),y)
LDFLAGS_vmlinux += --fix-cortex-a53-843419
endif
endif
cc_has_k_constraint := $(call try-run,echo \
'int main(void) { \
asm volatile("and w0, w0, %w0" :: "K" (4294967295)); \
return 0; \
}' | $(CC) -S -x c -o "$$TMP" -,,-DCONFIG_CC_HAS_K_CONSTRAINT=1)
ifeq ($(CONFIG_BROKEN_GAS_INST),y)
$(warning Detected assembler with broken .inst; disassembly will be unreliable)
endif
KBUILD_CFLAGS += -mgeneral-regs-only \
$(compat_vdso) $(cc_has_k_constraint)
KBUILD_CFLAGS += $(call cc-disable-warning, psabi)
KBUILD_AFLAGS += $(compat_vdso)
KBUILD_CFLAGS += $(call cc-option,-mabi=lp64)
KBUILD_AFLAGS += $(call cc-option,-mabi=lp64)
# Avoid generating .eh_frame* sections.
ifneq ($(CONFIG_UNWIND_TABLES),y)
KBUILD_CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
KBUILD_AFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
else
KBUILD_CFLAGS += -fasynchronous-unwind-tables
KBUILD_AFLAGS += -fasynchronous-unwind-tables
endif
ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
prepare: stack_protector_prepare
stack_protector_prepare: prepare0
$(eval KBUILD_CFLAGS += -mstack-protector-guard=sysreg \
-mstack-protector-guard-reg=sp_el0 \
-mstack-protector-guard-offset=$(shell \
awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}' \
include/generated/asm-offsets.h))
endif
ifeq ($(CONFIG_ARM64_BTI_KERNEL),y)
KBUILD_CFLAGS += -mbranch-protection=pac-ret+bti
else ifeq ($(CONFIG_ARM64_PTR_AUTH_KERNEL),y)
ifeq ($(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET),y)
KBUILD_CFLAGS += -mbranch-protection=pac-ret
else
KBUILD_CFLAGS += -msign-return-address=non-leaf
endif
else
KBUILD_CFLAGS += $(call cc-option,-mbranch-protection=none)
endif
# Tell the assembler to support instructions from the latest target
# architecture.
#
# For non-integrated assemblers we'll pass this on the command line, and for
# integrated assemblers we'll define ARM64_ASM_ARCH and ARM64_ASM_PREAMBLE for
# inline usage.
#
# We cannot pass the same arch flag to the compiler as this would allow it to
# freely generate instructions which are not supported by earlier architecture
# versions, which would prevent a single kernel image from working on earlier
# hardware.
ifeq ($(CONFIG_AS_HAS_ARMV8_5), y)
asm-arch := armv8.5-a
else ifeq ($(CONFIG_AS_HAS_ARMV8_4), y)
asm-arch := armv8.4-a
else ifeq ($(CONFIG_AS_HAS_ARMV8_3), y)
asm-arch := armv8.3-a
else ifeq ($(CONFIG_AS_HAS_ARMV8_2), y)
asm-arch := armv8.2-a
endif
ifdef asm-arch
KBUILD_CFLAGS += -Wa,-march=$(asm-arch) \
-DARM64_ASM_ARCH='"$(asm-arch)"'
endif
ifeq ($(CONFIG_SHADOW_CALL_STACK), y)
KBUILD_CFLAGS += -ffixed-x18
endif
ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
KBUILD_CPPFLAGS += -mbig-endian
CHECKFLAGS += -D__AARCH64EB__
# Prefer the baremetal ELF build target, but not all toolchains include
# it so fall back to the standard linux version if needed.
KBUILD_LDFLAGS += -EB $(call ld-option, -maarch64elfb, -maarch64linuxb -z norelro)
UTS_MACHINE := aarch64_be
else
KBUILD_CPPFLAGS += -mlittle-endian
CHECKFLAGS += -D__AARCH64EL__
# Same as above, prefer ELF but fall back to linux target if needed.
KBUILD_LDFLAGS += -EL $(call ld-option, -maarch64elf, -maarch64linux -z norelro)
UTS_MACHINE := aarch64
endif
ifeq ($(CONFIG_LD_IS_LLD), y)
KBUILD_LDFLAGS += -z norelro
endif
CHECKFLAGS += -D__aarch64__
ifeq ($(CONFIG_DYNAMIC_FTRACE_WITH_ARGS),y)
KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
CC_FLAGS_FTRACE := -fpatchable-function-entry=2
endif
ifeq ($(CONFIG_KASAN_SW_TAGS), y)
KASAN_SHADOW_SCALE_SHIFT := 4
else ifeq ($(CONFIG_KASAN_GENERIC), y)
KASAN_SHADOW_SCALE_SHIFT := 3
endif
KBUILD_CFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)
KBUILD_CPPFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)
KBUILD_AFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)
libs-y := arch/arm64/lib/ $(libs-y)
libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
# Default target when executing plain make
boot := arch/arm64/boot
ifeq ($(CONFIG_EFI_ZBOOT),)
KBUILD_IMAGE := $(boot)/Image.gz
else
KBUILD_IMAGE := $(boot)/vmlinuz.efi
endif
all: $(notdir $(KBUILD_IMAGE))
Image vmlinuz.efi: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
Image.%: Image
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
install: KBUILD_IMAGE := $(boot)/Image
install zinstall:
$(call cmd,install)
PHONY += vdso_install
vdso_install:
$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@
$(if $(CONFIG_COMPAT_VDSO), \
$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 $@)
archprepare:
$(Q)$(MAKE) $(build)=arch/arm64/tools kapi
ifeq ($(CONFIG_ARM64_ERRATUM_843419),y)
ifneq ($(CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419),y)
@echo "warning: ld does not support --fix-cortex-a53-843419; kernel may be susceptible to erratum" >&2
endif
endif
ifeq ($(CONFIG_ARM64_USE_LSE_ATOMICS),y)
ifneq ($(CONFIG_ARM64_LSE_ATOMICS),y)
@echo "warning: LSE atomics not supported by binutils" >&2
endif
endif
ifeq ($(KBUILD_EXTMOD),)
# We need to generate vdso-offsets.h before compiling certain files in kernel/.
# In order to do that, we should use the archprepare target, but we can't since
# asm-offsets.h is included in some files used to generate vdso-offsets.h, and
# asm-offsets.h is built in prepare0, for which archprepare is a dependency.
# Therefore we need to generate the header after prepare0 has been made, hence
# this hack.
prepare: vdso_prepare
vdso_prepare: prepare0
$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso \
include/generated/vdso-offsets.h arch/arm64/kernel/vdso/vdso.so
ifdef CONFIG_COMPAT_VDSO
$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 \
include/generated/vdso32-offsets.h arch/arm64/kernel/vdso32/vdso.so
endif
endif
define archhelp
echo '* Image.gz - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)'
echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
echo ' install - Install uncompressed kernel'
echo ' zinstall - Install compressed kernel'
echo ' Install using (your) ~/bin/installkernel or'
echo ' (distribution) /sbin/installkernel or'
echo ' install to $$(INSTALL_PATH) and run lilo'
endef