Commit bd23fdba authored by Will Deacon's avatar Will Deacon
Browse files

Merge branch 'for-next/ptrauth' into for-next/core

Allow Pointer Authentication to be configured independently for kernel
and userspace.

* for-next/ptrauth:
  arm64: Conditionally configure PTR_AUTH key of the kernel.
  arm64: Add ARM64_PTR_AUTH_KERNEL config option
parents 2e5d34d2 d053e71a
Loading
Loading
Loading
Loading
+19 −14
Original line number Diff line number Diff line
@@ -1481,12 +1481,6 @@ 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 >= 23301 || (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
	  Pointer authentication (part of the ARMv8.3 Extensions) provides
	  instructions for signing and authenticating pointers against secret
@@ -1498,13 +1492,6 @@ config ARM64_PTR_AUTH
	  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.
@@ -1515,6 +1502,24 @@ config ARM64_PTR_AUTH
	  but with the feature disabled. On such a system, this option should
	  not be selected.

config ARM64_PTR_AUTH_KERNEL
	bool "Use pointer authentication for kernel"
	default y
	depends on ARM64_PTR_AUTH
	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 >= 23301 || (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 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.

	  This feature works with FUNCTION_GRAPH_TRACER option only if
	  DYNAMIC_FTRACE_WITH_REGS is enabled.

@@ -1606,7 +1611,7 @@ config ARM64_BTI_KERNEL
	bool "Use Branch Target Identification for kernel"
	default y
	depends on ARM64_BTI
	depends on ARM64_PTR_AUTH
	depends on ARM64_PTR_AUTH_KERNEL
	depends on CC_HAS_BRANCH_PROT_PAC_RET_BTI
	# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94697
	depends on !CC_IS_GCC || GCC_VERSION >= 100100
+1 −1
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ 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_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
+29 −20
Original line number Diff line number Diff line
@@ -7,19 +7,7 @@
#include <asm/cpufeature.h>
#include <asm/sysreg.h>

#ifdef CONFIG_ARM64_PTR_AUTH
/*
 * thread.keys_user.ap* as offset exceeds the #imm offset range
 * so use the base value of ldp as thread.keys_user and offset as
 * thread.keys_user.ap*.
 */
	.macro __ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3
	mov	\tmp1, #THREAD_KEYS_USER
	add	\tmp1, \tsk, \tmp1
	ldp	\tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APIA]
	msr_s	SYS_APIAKEYLO_EL1, \tmp2
	msr_s	SYS_APIAKEYHI_EL1, \tmp3
	.endm
#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL

	.macro __ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3
	mov	\tmp1, #THREAD_KEYS_KERNEL
@@ -42,6 +30,33 @@ alternative_if ARM64_HAS_ADDRESS_AUTH
alternative_else_nop_endif
	.endm

#else /* CONFIG_ARM64_PTR_AUTH_KERNEL */

	.macro __ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3
	.endm

	.macro ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3
	.endm

	.macro ptrauth_keys_install_kernel tsk, tmp1, tmp2, tmp3
	.endm

#endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */

#ifdef CONFIG_ARM64_PTR_AUTH
/*
 * thread.keys_user.ap* as offset exceeds the #imm offset range
 * so use the base value of ldp as thread.keys_user and offset as
 * thread.keys_user.ap*.
 */
	.macro __ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3
	mov	\tmp1, #THREAD_KEYS_USER
	add	\tmp1, \tsk, \tmp1
	ldp	\tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APIA]
	msr_s	SYS_APIAKEYLO_EL1, \tmp2
	msr_s	SYS_APIAKEYHI_EL1, \tmp3
	.endm

	.macro __ptrauth_keys_init_cpu tsk, tmp1, tmp2, tmp3
	mrs	\tmp1, id_aa64isar1_el1
	ubfx	\tmp1, \tmp1, #ID_AA64ISAR1_APA_SHIFT, #8
@@ -64,17 +79,11 @@ alternative_else_nop_endif
.Lno_addr_auth\@:
	.endm

#else /* CONFIG_ARM64_PTR_AUTH */
#else /* !CONFIG_ARM64_PTR_AUTH */

	.macro ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3
	.endm

	.macro ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3
	.endm

	.macro ptrauth_keys_install_kernel tsk, tmp1, tmp2, tmp3
	.endm

#endif /* CONFIG_ARM64_PTR_AUTH */

#endif /* __ASM_ASM_POINTER_AUTH_H */
+33 −26
Original line number Diff line number Diff line
@@ -31,10 +31,6 @@ struct ptrauth_keys_user {
	struct ptrauth_key apga;
};

struct ptrauth_keys_kernel {
	struct ptrauth_key apia;
};

#define __ptrauth_key_install_nosync(k, v)			\
do {								\
	struct ptrauth_key __pki_v = (v);			\
@@ -42,6 +38,29 @@ do { \
	write_sysreg_s(__pki_v.hi, SYS_ ## k ## KEYHI_EL1);	\
} while (0)

#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL

struct ptrauth_keys_kernel {
	struct ptrauth_key apia;
};

static __always_inline void ptrauth_keys_init_kernel(struct ptrauth_keys_kernel *keys)
{
	if (system_supports_address_auth())
		get_random_bytes(&keys->apia, sizeof(keys->apia));
}

static __always_inline void ptrauth_keys_switch_kernel(struct ptrauth_keys_kernel *keys)
{
	if (!system_supports_address_auth())
		return;

	__ptrauth_key_install_nosync(APIA, keys->apia);
	isb();
}

#endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */

static inline void ptrauth_keys_install_user(struct ptrauth_keys_user *keys)
{
	if (system_supports_address_auth()) {
@@ -69,21 +88,6 @@ static inline void ptrauth_keys_init_user(struct ptrauth_keys_user *keys)
	ptrauth_keys_install_user(keys);
}

static __always_inline void ptrauth_keys_init_kernel(struct ptrauth_keys_kernel *keys)
{
	if (system_supports_address_auth())
		get_random_bytes(&keys->apia, sizeof(keys->apia));
}

static __always_inline void ptrauth_keys_switch_kernel(struct ptrauth_keys_kernel *keys)
{
	if (!system_supports_address_auth())
		return;

	__ptrauth_key_install_nosync(APIA, keys->apia);
	isb();
}

extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg);

extern int ptrauth_set_enabled_keys(struct task_struct *tsk, unsigned long keys,
@@ -121,11 +125,6 @@ static __always_inline void ptrauth_enable(void)
#define ptrauth_thread_switch_user(tsk)                                        \
	ptrauth_keys_install_user(&(tsk)->thread.keys_user)

#define ptrauth_thread_init_kernel(tsk)					\
	ptrauth_keys_init_kernel(&(tsk)->thread.keys_kernel)
#define ptrauth_thread_switch_kernel(tsk)				\
	ptrauth_keys_switch_kernel(&(tsk)->thread.keys_kernel)

#else /* CONFIG_ARM64_PTR_AUTH */
#define ptrauth_enable()
#define ptrauth_prctl_reset_keys(tsk, arg)	(-EINVAL)
@@ -134,11 +133,19 @@ static __always_inline void ptrauth_enable(void)
#define ptrauth_strip_insn_pac(lr)	(lr)
#define ptrauth_suspend_exit()
#define ptrauth_thread_init_user()
#define ptrauth_thread_init_kernel(tsk)
#define ptrauth_thread_switch_user(tsk)
#define ptrauth_thread_switch_kernel(tsk)
#endif /* CONFIG_ARM64_PTR_AUTH */

#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
#define ptrauth_thread_init_kernel(tsk)					\
	ptrauth_keys_init_kernel(&(tsk)->thread.keys_kernel)
#define ptrauth_thread_switch_kernel(tsk)				\
	ptrauth_keys_switch_kernel(&(tsk)->thread.keys_kernel)
#else
#define ptrauth_thread_init_kernel(tsk)
#define ptrauth_thread_switch_kernel(tsk)
#endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */

#define PR_PAC_ENABLED_KEYS_MASK                                               \
	(PR_PAC_APIAKEY | PR_PAC_APIBKEY | PR_PAC_APDAKEY | PR_PAC_APDBKEY)

+2 −0
Original line number Diff line number Diff line
@@ -148,8 +148,10 @@ struct thread_struct {
	struct debug_info	debug;		/* debugging */
#ifdef CONFIG_ARM64_PTR_AUTH
	struct ptrauth_keys_user	keys_user;
#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
	struct ptrauth_keys_kernel	keys_kernel;
#endif
#endif
#ifdef CONFIG_ARM64_MTE
	u64			gcr_user_excl;
#endif
Loading