[PATCH 2/2] arm64: pauth: don't sign leaf functions
Ard Biesheuvel
ardb at kernel.org
Thu Jan 26 00:40:33 PST 2023
On Wed, 25 Jan 2023 at 19:22, Mark Rutland <mark.rutland at arm.com> wrote:
>
> 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 leave functions since the
leaf
> 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 buller and stop
bullet
> pretending that AUTIASP is a mitigation for such forward-edge
> gadgetisation.
>
Nit: this has an 's' whereas the previous occurrence had a 'z'
> 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 at 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 at 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 at 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 at 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 relatively 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 at arm.com>
> Cc: Amit Daniel Kachhap <amit.kachhap at arm.com>
> Cc: Ard Biesheuvel <ardb at kernel.org>
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: Mark Brown <broonie at kernel.org>
> Cc: Will Deacon <will at kernel.org>
Reviewed-by: Ard Biesheuvel <ardb at kernel.org>
> ---
> arch/arm64/Makefile | 28 ++++++++--------------------
> 1 file changed, 8 insertions(+), 20 deletions(-)
>
> diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
> index e176eb76345b5..ab1f12b4f339a 100644
> --- a/arch/arm64/Makefile
> +++ b/arch/arm64/Makefile
> @@ -63,30 +63,18 @@ stack_protector_prepare: prepare0
> include/generated/asm-offsets.h))
> endif
>
> -# Ensure that if the compiler supports branch protection we default it
> -# off, this will be overridden if we are using branch protection.
> -branch-prot-flags-y += $(call cc-option,-mbranch-protection=none)
> -
> -ifeq ($(CONFIG_ARM64_PTR_AUTH_KERNEL),y)
> -branch-prot-flags-$(CONFIG_CC_HAS_SIGN_RETURN_ADDRESS) := -msign-return-address=all
> -# We enable additional protection for leaf functions as there is some
> -# narrow potential for ROP protection benefits and no substantial
> -# performance impact has been observed.
> -PACRET-y := pac-ret+leaf
> -
> -# Using a shadow call stack in leaf functions is too costly, so avoid PAC there
> -# as well when we may be patching PAC into SCS
> -PACRET-$(CONFIG_UNWIND_PATCH_PAC_INTO_SCS) := pac-ret
> -
> ifeq ($(CONFIG_ARM64_BTI_KERNEL),y)
> -branch-prot-flags-$(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI) := -mbranch-protection=$(PACRET-y)+bti
> + 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
> -branch-prot-flags-$(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET) := -mbranch-protection=$(PACRET-y)
> -endif
> + KBUILD_CFLAGS += $(call cc-option,-mbranch-protection=none)
> endif
>
> -KBUILD_CFLAGS += $(branch-prot-flags-y)
> -
> # Tell the assembler to support instructions from the latest target
> # architecture.
> #
> --
> 2.30.2
>
More information about the linux-arm-kernel
mailing list