diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index ab6cbb944b36566129515cf4aa0ad92b08f0c284..b653345d26f4f48b18ae1223df401310c3da8ee1 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1530,31 +1530,20 @@ menu "ARMv8.3 architectural features" config ARM64_PTR_AUTH bool "Enable support for pointer authentication" - default y - depends on (CC_HAS_SIGN_RETURN_ADDRESS || CC_HAS_BRANCH_PROT_PAC_RET) && AS_HAS_PAC - # Modern compilers insert a .note.gnu.property section note for PAC - # which is only understood by binutils starting with version 2.33.1. - depends on LD_IS_LLD || LD_VERSION >= 233010000 || (CC_IS_GCC && GCC_VERSION < 90100) - depends on !CC_IS_CLANG || AS_HAS_CFI_NEGATE_RA_STATE - depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_REGS) + default n + depends on AS_HAS_PAC help Pointer authentication (part of the ARMv8.3 Extensions) provides - instructions for signing and authenticating pointers against secret - keys, which can be used to mitigate Return Oriented Programming (ROP) - and other attacks. + instructions for signing and authenticating pointers or data fields against + secret keys, which can be used to mitigate Return Oriented Programming (ROP), + Jump Oriented Programming (JOP), Data Oriented Programming (DOP) and other + attacks. This option enables these instructions at EL0 (i.e. for userspace). Choosing this option will cause the kernel to initialise secret keys for each process at exec() time, with these keys being context-switched along with the process. - If the compiler supports the -mbranch-protection or - -msign-return-address flag (e.g. GCC 7 or later), then this option - will also cause the kernel itself to be compiled with return address - protection. In this case, and if the target hardware is known to - support pointer authentication, then CONFIG_STACKPROTECTOR can be - disabled with minimal loss of protection. - The feature is detected at runtime. If the feature is not present in hardware it will not be advertised to userspace/KVM guest nor will it be enabled. @@ -1565,8 +1554,92 @@ config ARM64_PTR_AUTH but with the feature disabled. On such a system, this option should not be selected. - This feature works with FUNCTION_GRAPH_TRACER option only if - DYNAMIC_FTRACE_WITH_REGS is enabled. +config ARM64_PTR_AUTH_USER + bool "Use pointer authentication for user" + default n + depends on ARM64_PTR_AUTH + select ARM64_PTR_AUTH_KERNEL + help + Set the secret keys for the process userspace. This protects against + Return Oriented Programming, Jump Oriented Programming and Data Oriented + Programming attacks in case of userspace bugs. + +config ARM64_PTR_AUTH_KERNEL + bool "Use pointer authentication for kernel" + default n + depends on ARM64_PTR_AUTH + help + Enable ARM64_PTR_AUTH_BACK_CFI to protect against return-oriented + programming attacks. + Enable ARM64_PTR_AUTH_FWD_CFI to protect against jump-oriented + programming attacks. + Enable ARM64_PTR_AUTH_DATA_PTR to protect against (data pointers)-oriented + programming attacks. + Enable ARM64_PTR_AUTH_DATA_FIELD to protect against (data fields)-oriented + programming attacks. + +config ARM64_PTR_AUTH_BACK_CFI + bool "Kernel pointer authentication for backward-edge CFI" + default n + depends on ARM64_PTR_AUTH_KERNEL && (CC_HAS_PAC_BACK_CFI || CC_HAS_SIGN_RETURN_ADDRESS || CC_HAS_BRANCH_PROT_PAC_RET) + depends on LD_IS_LLD || LD_VERSION >= 233010000 || (CC_IS_GCC && GCC_VERSION < 90100) + depends on !CC_IS_CLANG || AS_HAS_CFI_NEGATE_RA_STATE + depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_REGS) + help + If the compiler supports the -mbranch-protection or + -msign-return-address flag (e.g. GCC 7 or later), then this option + will also cause the kernel itself to be compiled with return address + protection. In this case, and if the target hardware is known to + support pointer authentication, then CONFIG_STACKPROTECTOR can be + disabled with minimal loss of protection. + +config ARM64_PTR_AUTH_FWD_CFI + bool "Kernel pointer authentication for forward-edge CFI" + default n + depends on ARM64_PTR_AUTH_KERNEL && CC_HAS_PAC_FWD_CFI + help + This option will cause the kernel itself to be compiled with function pointers + protection. + +config ARM64_PTR_AUTH_FWD_CFI_DEBUG + bool "Debug forward-edge CFI type conflict" + default n + depends on ARM64_PTR_AUTH_KERNEL && CC_HAS_PAC_FWD_CFI + select ARM64_PTR_AUTH_FWD_CFI + help + Print all function address about type conflict. + +config ARM64_PTR_AUTH_DATA_PTR + bool "Kernel pointer authentication for data pointer" + default n + depends on ARM64_PTR_AUTH_KERNEL && CC_HAS_PAC_DATA_PTR + help + This option will cause the kernel itself to be compiled with data pointers + protection. + +config ARM64_PTR_AUTH_DATA_FIELD + bool "Kernel authentication for data field" + default n + depends on ARM64_PTR_AUTH_KERNEL && CC_HAS_PAC_DATA_FIELD + help + This option will cause the kernel itself to be compiled with data fields + protection. + +config ARM64_PTR_AUTH_EXT + def_bool y + depends on (ARM64_PTR_AUTH_BACK_CFI && CC_HAS_PAC_BACK_CFI) || (ARM64_PTR_AUTH_FWD_CFI || ARM64_PTR_AUTH_DATA_PTR || ARM64_PTR_AUTH_DATA_FIELD) + +config CC_HAS_PAC_FWD_CFI + def_bool $(cc-option,-mllvm -FECFI=true) + +config CC_HAS_PAC_BACK_CFI + def_bool $(cc-option,-mllvm -FGBECFI=true) + +config CC_HAS_PAC_DATA_PTR + def_bool $(cc-option,-mllvm -DFIDPP=true) + +config CC_HAS_PAC_DATA_FIELD + def_bool $(cc-option,-mllvm -DFIDPTAG=true) config CC_HAS_BRANCH_PROT_PAC_RET # GCC 9 or later, clang 8 or later diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 485b7dbd4f9e322e3c11d7144a7ea697b8c2c9b3..8f9d0aa0b47986a86c8ebd01808f372fc25272a8 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -70,7 +70,13 @@ endif # 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),y) +ifeq ($(CONFIG_ARM64_PTR_AUTH_BACK_CFI),y) +ifeq ($(CONFIG_CC_HAS_PAC_BACK_CFI),y) +KBUILD_CFLAGS += -mllvm -FGBECFI=true -msign-return-address=none +ifeq ($(CONFIG_ARM64_BTI_KERNEL),y) +branch-prot-flags-$(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI) := -mbranch-protection=bti +endif +else 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 @@ -80,6 +86,26 @@ branch-prot-flags-$(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI) := -mbranch-protectio else branch-prot-flags-$(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET) := -mbranch-protection=pac-ret+leaf endif +endif +endif + +ifeq ($(CONFIG_ARM64_PTR_AUTH_FWD_CFI),y) +KBUILD_CFLAGS += -mllvm -FECFI=true +endif + +ifeq ($(CONFIG_ARM64_PTR_AUTH_DATA_PTR),y) +KBUILD_CFALGS += -mllvm -DFIDPP=true +endif + +ifeq ($(CONFIG_ARM64_PTR_AUTH_DATA_FIELD),y) +KBUILD_CFLAGS += -mllvm -DFIDPTAG=true +endif + +ifeq ($(CONFIG_ARM64_PTR_AUTH_EXT),y) +core-y += $(srctree)/../common_modules/pac/ +LINUXINCLUDE += -I$(srctree)/../common_modules/pac/arm64/include +endif + # -march=armv8.3-a enables the non-nops instructions for PAC, to avoid the # compiler to generate them and consequently to break the single image contract # we pass it only to the assembler. This option is utilized only in case of non @@ -87,7 +113,6 @@ endif ifeq ($(CONFIG_AS_HAS_PAC), y) asm-arch := armv8.3-a endif -endif KBUILD_CFLAGS += $(branch-prot-flags-y) @@ -99,6 +124,10 @@ endif ifdef asm-arch KBUILD_CFLAGS += -Wa,-march=$(asm-arch) \ -DARM64_ASM_ARCH='"$(asm-arch)"' +ifeq ($(CONFIG_AS_HAS_PAC), y) +KBUILD_CFLAGS += -march=$(asm-arch) +KBUILD_AFLAGS += -march=$(asm-arch) +endif endif ifeq ($(CONFIG_SHADOW_CALL_STACK), y) diff --git a/arch/arm64/include/asm/asm_pointer_auth.h b/arch/arm64/include/asm/asm_pointer_auth.h index 52dead2a8640d2ef4acf30a0059e2d2c3413e906..482b05aa17444be80effe92be4e7e831c8470156 100644 --- a/arch/arm64/include/asm/asm_pointer_auth.h +++ b/arch/arm64/include/asm/asm_pointer_auth.h @@ -6,6 +6,9 @@ #include #include #include +#ifdef CONFIG_ARM64_PTR_AUTH_EXT +#include +#endif #ifdef CONFIG_ARM64_PTR_AUTH /* @@ -42,9 +45,15 @@ alternative_else_nop_endif .macro __ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3 mov \tmp1, #THREAD_KEYS_KERNEL add \tmp1, \tsk, \tmp1 +#ifdef CONFIG_ARM64_PTR_AUTH_EXT + ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_KERNEL_KEY_APIB] + msr_s SYS_APIBKEYLO_EL1, \tmp2 + msr_s SYS_APIBKEYLO_EL1, \tmp3 +#else ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_KERNEL_KEY_APIA] msr_s SYS_APIAKEYLO_EL1, \tmp2 msr_s SYS_APIAKEYHI_EL1, \tmp3 +#endif .endm .macro ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3 @@ -69,7 +78,11 @@ alternative_else_nop_endif mrs \tmp2, sctlr_el1 orr \tmp2, \tmp2, \tmp1 msr sctlr_el1, \tmp2 +#ifdef CONFIG_ARM64_PTR_AUTH_EXT + __ptrauth_keys_install_kernel_all \tsk, \tmp1, \tmp2, \tmp3 +#else __ptrauth_keys_install_kernel_nosync \tsk, \tmp1, \tmp2, \tmp3 +#endif isb .Lno_addr_auth\@: .endm diff --git a/arch/arm64/include/asm/pointer_auth.h b/arch/arm64/include/asm/pointer_auth.h index c6b4f0603024332948677b9ec9606d201ac32b28..54b6a10a7158b9ed52b60355625a3b0bed0881c0 100644 --- a/arch/arm64/include/asm/pointer_auth.h +++ b/arch/arm64/include/asm/pointer_auth.h @@ -31,9 +31,22 @@ struct ptrauth_keys_user { }; struct ptrauth_keys_kernel { +#ifdef CONFIG_ARM64_PTR_AUTH_EXT + struct ptrauth_key apib; +#else struct ptrauth_key apia; +#endif }; +#ifdef CONFIG_ARM64_PTR_AUTH_EXT +struct ptrauth_keys_kernel_common { + struct ptrauth_key apia; + struct ptrauth_key apda; + struct ptrauth_key apdb; + struct ptrauth_key apga; +}; +#endif + static inline void ptrauth_keys_init_user(struct ptrauth_keys_user *keys) { if (system_supports_address_auth()) { @@ -57,15 +70,22 @@ do { \ static __always_inline void ptrauth_keys_init_kernel(struct ptrauth_keys_kernel *keys) { if (system_supports_address_auth()) +#ifdef CONFIG_ARM64_PTR_AUTH_EXT + get_random_bytes(&keys->apib, sizeof(keys->apib)); +#else get_random_bytes(&keys->apia, sizeof(keys->apia)); +#endif } static __always_inline void ptrauth_keys_switch_kernel(struct ptrauth_keys_kernel *keys) { if (!system_supports_address_auth()) return; - +#ifdef CONFIG_ARM64_PTR_AUTH_EXT + __ptrauth_key_install_nosync(APIB, keys->apib); +#else __ptrauth_key_install_nosync(APIA, keys->apia); +#endif isb(); } diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 7c546c3487c9fccbc65fc911f6ae8402c9f24c6d..ebecdc40af8ad41f1287ca7ed6c643883c1a9cca 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -148,8 +148,10 @@ struct thread_struct { unsigned long fault_address; /* fault info */ unsigned long fault_code; /* ESR_EL1 value */ struct debug_info debug; /* debugging */ -#ifdef CONFIG_ARM64_PTR_AUTH +#ifdef CONFIG_ARM64_PTR_AUTH_USER struct ptrauth_keys_user keys_user; +#endif +#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL struct ptrauth_keys_kernel keys_kernel; #endif #ifdef CONFIG_ARM64_MTE diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 34ef70877de45abb1e2e9d9a93ce7e54b41df08d..781fa3de00456982ef7d76e171bc5795b2cc9570 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -44,8 +44,10 @@ int main(void) #endif BLANK(); DEFINE(THREAD_CPU_CONTEXT, offsetof(struct task_struct, thread.cpu_context)); -#ifdef CONFIG_ARM64_PTR_AUTH +#ifdef CONFIG_ARM64_PTR_AUTH_USER DEFINE(THREAD_KEYS_USER, offsetof(struct task_struct, thread.keys_user)); +#endif +#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL DEFINE(THREAD_KEYS_KERNEL, offsetof(struct task_struct, thread.keys_kernel)); #endif BLANK(); @@ -137,13 +139,24 @@ int main(void) DEFINE(SDEI_EVENT_INTREGS, offsetof(struct sdei_registered_event, interrupted_regs)); DEFINE(SDEI_EVENT_PRIORITY, offsetof(struct sdei_registered_event, priority)); #endif -#ifdef CONFIG_ARM64_PTR_AUTH +#ifdef CONFIG_ARM64_PTR_AUTH_USER DEFINE(PTRAUTH_USER_KEY_APIA, offsetof(struct ptrauth_keys_user, apia)); DEFINE(PTRAUTH_USER_KEY_APIB, offsetof(struct ptrauth_keys_user, apib)); DEFINE(PTRAUTH_USER_KEY_APDA, offsetof(struct ptrauth_keys_user, apda)); DEFINE(PTRAUTH_USER_KEY_APDB, offsetof(struct ptrauth_keys_user, apdb)); DEFINE(PTRAUTH_USER_KEY_APGA, offsetof(struct ptrauth_keys_user, apga)); - DEFINE(PTRAUTH_KERNEL_KEY_APIA, offsetof(struct ptrauth_keys_kernel, apia)); + BLANK(); +#endif +#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL +#ifdef CONFIG_ARM64_PTR_AUTH_EXT + DEFINE(PTRAUTH_KERNEL_KEY_APIB, offsetof(struct ptrauth_keys_kernel, apib)); + DEFINE(PTRAUTH_KERNEL_KEY_APIA, offsetof(struct ptrauth_keys_kernel_common, apia)); + DEFINE(PTRAUTH_KERNEL_KEY_APDA, offsetof(struct ptrauth_keys_kernel_common, apda)); + DEFINE(PTRAUTH_KERNEL_KEY_APDB, offsetof(struct ptrauth_keys_kernel_common, apdb)); + DEFINE(PTRAUTH_KERNEL_KEY_APGA, offsetof(struct ptrauth_keys_kernel_common, apga)); +#else + DEFINE(PTRAUTH_KERNEL_KEY_APIA, offsetof(struct ptrauth_keys_kernel, apia)); +#endif BLANK(); #endif return 0; diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index d5bc1dbdd2fda84cd1e6e9508c07be5b41fae793..2f53e787447f6e490fac2cb5027fd58ad49654e6 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -28,6 +28,9 @@ #include #include #include +#ifdef CONFIG_ARM64_PTR_AUTH_EXT +#include +#endif /* * Context tracking and irqflag tracing need to instrument transitions between @@ -219,7 +222,11 @@ alternative_else_nop_endif check_mte_async_tcf x22, x23 apply_ssbd 1, x22, x23 +#ifdef CONFIG_ARM64_PTR_AUTH_EXT + ptrauth_keys_install_kernel_all tsk, x20, x22, x23 +#else ptrauth_keys_install_kernel tsk, x20, x22, x23 +#endif scs_load tsk, x20 .else diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index f9119eea735e242ff628f248ee6f0e3e497b2d76..444db57d6d7a98d11484660be53ec00b669af3d6 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -420,6 +420,9 @@ SYM_FUNC_START_LOCAL(__primary_switched) adr_l x5, init_task msr sp_el0, x5 // Save thread_info +#ifdef CONFIG_ARM64_PTR_AUTH_EXT + bl ptrauth_kernel_keys_init +#endif #ifdef CONFIG_ARM64_PTR_AUTH __ptrauth_keys_init_cpu x5, x6, x7, x8 #endif diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index e46df0a2d4f9d200bee7ccaf3528431eca45206a..5f04f0502f0c354dc80c4b75f49d78c4b20f7a17 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -25,6 +25,35 @@ xconfig: $(obj)/qconf gconfig: $(obj)/gconf $(Q)$< $(silent) $(Kconfig) +PHONY += scriptconfig iscriptconfig kmenuconfig guiconfig dumpvarsconfig + +PYTHONCMD ?= python +kpython := PYTHONPATH=$(srctree)/Kconfiglib:$$PYTHONPATH $(PYTHONCMD) + +ifneq ($(filter scriptconfig,$(MAKECMDGOALS)),) +ifndef SCRIPT +$(error Use "make scriptconfig SCRIPT= [SCRIPT_ARG=]") +endif +endif + +scriptconfig: + $(Q)$(kpython) $(SCRIPT) $(Kconfig) $(if $(SCRIPT_ARG),"$(SCRIPT_ARG)") + +iscriptconfig: + $(Q)$(kpython) -i -c \ + "import kconfiglib; \ + kconf = kconfiglib.Kconfig('$(Kconfig)'); \ + print('A Kconfig instance \'kconf\' for the architecture $(ARCH) has been created.')" + +kmenuconfig: + $(Q)$(kpython) $(srctree)/Kconfiglib/menuconfig.py $(Kconfig) + +guiconfig: + $(Q)$(kpython) $(srctree)/Kconfiglib/guiconfig.py $(Kconfig) + +dumpvarsconfig: + $(Q)$(kpython) $(srctree)/Kconfiglib/examples/dumpvars.py $(Kconfig) + menuconfig: $(obj)/mconf $(Q)$< $(silent) $(Kconfig)