Commit 75031975 authored by Mark Rutland's avatar Mark Rutland Committed by Will Deacon

arm64: add basic pointer authentication support

This patch adds basic support for pointer authentication, allowing
userspace to make use of APIAKey, APIBKey, APDAKey, APDBKey, and
APGAKey. The kernel maintains key values for each process (shared by all
threads within), which are initialised to random values at exec() time.

The ID_AA64ISAR1_EL1.{APA,API,GPA,GPI} fields are exposed to userspace,
to describe that pointer authentication instructions are available and
that the kernel is managing the keys. Two new hwcaps are added for the
same reason: PACA (for address authentication) and PACG (for generic
authentication).
Reviewed-by: default avatarRichard Henderson <richard.henderson@linaro.org>
Signed-off-by: default avatarMark Rutland <mark.rutland@arm.com>
Signed-off-by: default avatarKristina Martsenko <kristina.martsenko@arm.com>
Tested-by: default avatarAdam Wallis <awallis@codeaurora.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Ramana Radhakrishnan <ramana.radhakrishnan@arm.com>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
[will: Fix sizeof() usage and unroll address key initialisation]
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent 6984eb47
// SPDX-License-Identifier: GPL-2.0
#ifndef __ASM_POINTER_AUTH_H
#define __ASM_POINTER_AUTH_H
#include <linux/random.h>
#include <asm/cpufeature.h>
#include <asm/sysreg.h>
#ifdef CONFIG_ARM64_PTR_AUTH
/*
* Each key is a 128-bit quantity which is split across a pair of 64-bit
* registers (Lo and Hi).
*/
struct ptrauth_key {
unsigned long lo, hi;
};
/*
* We give each process its own keys, which are shared by all threads. The keys
* are inherited upon fork(), and reinitialised upon exec*().
*/
struct ptrauth_keys {
struct ptrauth_key apia;
struct ptrauth_key apib;
struct ptrauth_key apda;
struct ptrauth_key apdb;
struct ptrauth_key apga;
};
static inline void ptrauth_keys_init(struct ptrauth_keys *keys)
{
if (system_supports_address_auth()) {
get_random_bytes(&keys->apia, sizeof(keys->apia));
get_random_bytes(&keys->apib, sizeof(keys->apib));
get_random_bytes(&keys->apda, sizeof(keys->apda));
get_random_bytes(&keys->apdb, sizeof(keys->apdb));
}
if (system_supports_generic_auth())
get_random_bytes(&keys->apga, sizeof(keys->apga));
}
#define __ptrauth_key_install(k, v) \
do { \
struct ptrauth_key __pki_v = (v); \
write_sysreg_s(__pki_v.lo, SYS_ ## k ## KEYLO_EL1); \
write_sysreg_s(__pki_v.hi, SYS_ ## k ## KEYHI_EL1); \
} while (0)
static inline void ptrauth_keys_switch(struct ptrauth_keys *keys)
{
if (system_supports_address_auth()) {
__ptrauth_key_install(APIA, keys->apia);
__ptrauth_key_install(APIB, keys->apib);
__ptrauth_key_install(APDA, keys->apda);
__ptrauth_key_install(APDB, keys->apdb);
}
if (system_supports_generic_auth())
__ptrauth_key_install(APGA, keys->apga);
}
#define ptrauth_thread_init_user(tsk) \
do { \
struct task_struct *__ptiu_tsk = (tsk); \
ptrauth_keys_init(&__ptiu_tsk->thread_info.keys_user); \
ptrauth_keys_switch(&__ptiu_tsk->thread_info.keys_user); \
} while (0)
#define ptrauth_thread_switch(tsk) \
ptrauth_keys_switch(&(tsk)->thread_info.keys_user)
#else /* CONFIG_ARM64_PTR_AUTH */
#define ptrauth_thread_init_user(tsk)
#define ptrauth_thread_switch(tsk)
#endif /* CONFIG_ARM64_PTR_AUTH */
#endif /* __ASM_POINTER_AUTH_H */
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
struct task_struct; struct task_struct;
#include <asm/memory.h> #include <asm/memory.h>
#include <asm/pointer_auth.h>
#include <asm/stack_pointer.h> #include <asm/stack_pointer.h>
#include <asm/types.h> #include <asm/types.h>
...@@ -54,6 +55,9 @@ struct thread_info { ...@@ -54,6 +55,9 @@ struct thread_info {
#endif #endif
} preempt; } preempt;
}; };
#ifdef CONFIG_ARM64_PTR_AUTH
struct ptrauth_keys keys_user;
#endif
}; };
#define thread_saved_pc(tsk) \ #define thread_saved_pc(tsk) \
......
...@@ -50,5 +50,7 @@ ...@@ -50,5 +50,7 @@
#define HWCAP_FLAGM (1 << 27) #define HWCAP_FLAGM (1 << 27)
#define HWCAP_SSBS (1 << 28) #define HWCAP_SSBS (1 << 28)
#define HWCAP_SB (1 << 29) #define HWCAP_SB (1 << 29)
#define HWCAP_PACA (1 << 30)
#define HWCAP_PACG (1UL << 31)
#endif /* _UAPI__ASM_HWCAP_H */ #endif /* _UAPI__ASM_HWCAP_H */
...@@ -1191,6 +1191,12 @@ static void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused) ...@@ -1191,6 +1191,12 @@ static void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused)
#endif /* CONFIG_ARM64_RAS_EXTN */ #endif /* CONFIG_ARM64_RAS_EXTN */
#ifdef CONFIG_ARM64_PTR_AUTH #ifdef CONFIG_ARM64_PTR_AUTH
static void cpu_enable_address_auth(struct arm64_cpu_capabilities const *cap)
{
sysreg_clear_set(sctlr_el1, 0, SCTLR_ELx_ENIA | SCTLR_ELx_ENIB |
SCTLR_ELx_ENDA | SCTLR_ELx_ENDB);
}
static bool has_address_auth(const struct arm64_cpu_capabilities *entry, static bool has_address_auth(const struct arm64_cpu_capabilities *entry,
int __unused) int __unused)
{ {
...@@ -1478,6 +1484,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = { ...@@ -1478,6 +1484,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
.capability = ARM64_HAS_ADDRESS_AUTH, .capability = ARM64_HAS_ADDRESS_AUTH,
.type = ARM64_CPUCAP_SYSTEM_FEATURE, .type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = has_address_auth, .matches = has_address_auth,
.cpu_enable = cpu_enable_address_auth,
}, },
{ {
.desc = "Generic authentication (architected algorithm)", .desc = "Generic authentication (architected algorithm)",
...@@ -1552,6 +1559,12 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = { ...@@ -1552,6 +1559,12 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, ID_AA64PFR0_SVE, CAP_HWCAP, HWCAP_SVE), HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, ID_AA64PFR0_SVE, CAP_HWCAP, HWCAP_SVE),
#endif #endif
HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_SSBS_SHIFT, FTR_UNSIGNED, ID_AA64PFR1_SSBS_PSTATE_INSNS, CAP_HWCAP, HWCAP_SSBS), HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_SSBS_SHIFT, FTR_UNSIGNED, ID_AA64PFR1_SSBS_PSTATE_INSNS, CAP_HWCAP, HWCAP_SSBS),
#ifdef CONFIG_ARM64_PTR_AUTH
{ .desc = "HWCAP_PACA", .type = ARM64_CPUCAP_SYSTEM_FEATURE, .matches = has_address_auth,
.hwcap_type = CAP_HWCAP, .hwcap = HWCAP_PACA },
{ .desc = "HWCAP_PACG", .type = ARM64_CPUCAP_SYSTEM_FEATURE, .matches = has_generic_auth,
.hwcap_type = CAP_HWCAP, .hwcap = HWCAP_PACG },
#endif
{}, {},
}; };
......
...@@ -83,6 +83,8 @@ static const char *const hwcap_str[] = { ...@@ -83,6 +83,8 @@ static const char *const hwcap_str[] = {
"flagm", "flagm",
"ssbs", "ssbs",
"sb", "sb",
"paca",
"pacg",
NULL NULL
}; };
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include <asm/fpsimd.h> #include <asm/fpsimd.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/pointer_auth.h>
#include <asm/stacktrace.h> #include <asm/stacktrace.h>
#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK) #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK)
...@@ -429,6 +430,7 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev, ...@@ -429,6 +430,7 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
contextidr_thread_switch(next); contextidr_thread_switch(next);
entry_task_switch(next); entry_task_switch(next);
uao_thread_switch(next); uao_thread_switch(next);
ptrauth_thread_switch(next);
/* /*
* Complete any pending TLB or cache maintenance on this CPU in case * Complete any pending TLB or cache maintenance on this CPU in case
...@@ -496,4 +498,6 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) ...@@ -496,4 +498,6 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
void arch_setup_new_exec(void) void arch_setup_new_exec(void)
{ {
current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0; current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0;
ptrauth_thread_init_user(current);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment