diff options
author | Mark Rutland <mark.rutland@arm.com> | 2018-12-07 13:39:26 -0500 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2018-12-13 11:42:46 -0500 |
commit | ec6e822d1a22d0eef1d1fa260dff751dba9a4258 (patch) | |
tree | 709322a7fd3dcaa397913e2fbd46f912d19ec9df | |
parent | 7503197562567b57ec14feb3a9d5400ebc56812f (diff) |
arm64: expose user PAC bit positions via ptrace
When pointer authentication is in use, data/instruction pointers have a
number of PAC bits inserted into them. The number and position of these
bits depends on the configured TCR_ELx.TxSZ and whether tagging is
enabled. ARMv8.3 allows tagging to differ for instruction and data
pointers.
For userspace debuggers to unwind the stack and/or to follow pointer
chains, they need to be able to remove the PAC bits before attempting to
use a pointer.
This patch adds a new structure with masks describing the location of
the PAC bits in userspace instruction and data pointers (i.e. those
addressable via TTBR0), which userspace can query via PTRACE_GETREGSET.
By clearing these bits from pointers (and replacing them with the value
of bit 55), userspace can acquire the PAC-less versions.
This new regset is exposed when the kernel is built with (user) pointer
authentication support, and the address authentication feature is
enabled. Otherwise, the regset is hidden.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Kristina Martsenko <kristina.martsenko@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Ramana Radhakrishnan <ramana.radhakrishnan@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
[will: Fix to use vabits_user instead of VA_BITS and rename macro]
Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r-- | arch/arm64/include/asm/memory.h | 3 | ||||
-rw-r--r-- | arch/arm64/include/asm/pointer_auth.h | 8 | ||||
-rw-r--r-- | arch/arm64/include/asm/processor.h | 2 | ||||
-rw-r--r-- | arch/arm64/include/uapi/asm/ptrace.h | 7 | ||||
-rw-r--r-- | arch/arm64/kernel/ptrace.c | 38 | ||||
-rw-r--r-- | include/uapi/linux/elf.h | 1 |
6 files changed, 57 insertions, 2 deletions
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 6747a3eddeb1..bd749033bc88 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h | |||
@@ -207,6 +207,9 @@ static inline unsigned long kaslr_offset(void) | |||
207 | return kimage_vaddr - KIMAGE_VADDR; | 207 | return kimage_vaddr - KIMAGE_VADDR; |
208 | } | 208 | } |
209 | 209 | ||
210 | /* the actual size of a user virtual address */ | ||
211 | extern u64 vabits_user; | ||
212 | |||
210 | /* | 213 | /* |
211 | * Allow all memory at the discovery stage. We will clip it later. | 214 | * Allow all memory at the discovery stage. We will clip it later. |
212 | */ | 215 | */ |
diff --git a/arch/arm64/include/asm/pointer_auth.h b/arch/arm64/include/asm/pointer_auth.h index 91c4185dda5b..2a22c03c1540 100644 --- a/arch/arm64/include/asm/pointer_auth.h +++ b/arch/arm64/include/asm/pointer_auth.h | |||
@@ -2,9 +2,11 @@ | |||
2 | #ifndef __ASM_POINTER_AUTH_H | 2 | #ifndef __ASM_POINTER_AUTH_H |
3 | #define __ASM_POINTER_AUTH_H | 3 | #define __ASM_POINTER_AUTH_H |
4 | 4 | ||
5 | #include <linux/bitops.h> | ||
5 | #include <linux/random.h> | 6 | #include <linux/random.h> |
6 | 7 | ||
7 | #include <asm/cpufeature.h> | 8 | #include <asm/cpufeature.h> |
9 | #include <asm/memory.h> | ||
8 | #include <asm/sysreg.h> | 10 | #include <asm/sysreg.h> |
9 | 11 | ||
10 | #ifdef CONFIG_ARM64_PTR_AUTH | 12 | #ifdef CONFIG_ARM64_PTR_AUTH |
@@ -61,6 +63,12 @@ static inline void ptrauth_keys_switch(struct ptrauth_keys *keys) | |||
61 | __ptrauth_key_install(APGA, keys->apga); | 63 | __ptrauth_key_install(APGA, keys->apga); |
62 | } | 64 | } |
63 | 65 | ||
66 | /* | ||
67 | * The EL0 pointer bits used by a pointer authentication code. | ||
68 | * This is dependent on TBI0 being enabled, or bits 63:56 would also apply. | ||
69 | */ | ||
70 | #define ptrauth_user_pac_mask() GENMASK(54, vabits_user) | ||
71 | |||
64 | #define ptrauth_thread_init_user(tsk) \ | 72 | #define ptrauth_thread_init_user(tsk) \ |
65 | do { \ | 73 | do { \ |
66 | struct task_struct *__ptiu_tsk = (tsk); \ | 74 | struct task_struct *__ptiu_tsk = (tsk); \ |
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index bbecc6fe3e5b..f4b8e09aff56 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h | |||
@@ -53,8 +53,6 @@ | |||
53 | */ | 53 | */ |
54 | 54 | ||
55 | #define DEFAULT_MAP_WINDOW_64 (UL(1) << VA_BITS) | 55 | #define DEFAULT_MAP_WINDOW_64 (UL(1) << VA_BITS) |
56 | |||
57 | extern u64 vabits_user; | ||
58 | #define TASK_SIZE_64 (UL(1) << vabits_user) | 56 | #define TASK_SIZE_64 (UL(1) << vabits_user) |
59 | 57 | ||
60 | #ifdef CONFIG_COMPAT | 58 | #ifdef CONFIG_COMPAT |
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h index a36227fdb084..c2f249bcd829 100644 --- a/arch/arm64/include/uapi/asm/ptrace.h +++ b/arch/arm64/include/uapi/asm/ptrace.h | |||
@@ -229,6 +229,13 @@ struct user_sve_header { | |||
229 | SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, flags) \ | 229 | SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, flags) \ |
230 | : SVE_PT_FPSIMD_OFFSET + SVE_PT_FPSIMD_SIZE(vq, flags)) | 230 | : SVE_PT_FPSIMD_OFFSET + SVE_PT_FPSIMD_SIZE(vq, flags)) |
231 | 231 | ||
232 | /* pointer authentication masks (NT_ARM_PAC_MASK) */ | ||
233 | |||
234 | struct user_pac_mask { | ||
235 | __u64 data_mask; | ||
236 | __u64 insn_mask; | ||
237 | }; | ||
238 | |||
232 | #endif /* __ASSEMBLY__ */ | 239 | #endif /* __ASSEMBLY__ */ |
233 | 240 | ||
234 | #endif /* _UAPI__ASM_PTRACE_H */ | 241 | #endif /* _UAPI__ASM_PTRACE_H */ |
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 1710a2d01669..9dce33b0e260 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <asm/debug-monitors.h> | 46 | #include <asm/debug-monitors.h> |
47 | #include <asm/fpsimd.h> | 47 | #include <asm/fpsimd.h> |
48 | #include <asm/pgtable.h> | 48 | #include <asm/pgtable.h> |
49 | #include <asm/pointer_auth.h> | ||
49 | #include <asm/stacktrace.h> | 50 | #include <asm/stacktrace.h> |
50 | #include <asm/syscall.h> | 51 | #include <asm/syscall.h> |
51 | #include <asm/traps.h> | 52 | #include <asm/traps.h> |
@@ -956,6 +957,30 @@ out: | |||
956 | 957 | ||
957 | #endif /* CONFIG_ARM64_SVE */ | 958 | #endif /* CONFIG_ARM64_SVE */ |
958 | 959 | ||
960 | #ifdef CONFIG_ARM64_PTR_AUTH | ||
961 | static int pac_mask_get(struct task_struct *target, | ||
962 | const struct user_regset *regset, | ||
963 | unsigned int pos, unsigned int count, | ||
964 | void *kbuf, void __user *ubuf) | ||
965 | { | ||
966 | /* | ||
967 | * The PAC bits can differ across data and instruction pointers | ||
968 | * depending on TCR_EL1.TBID*, which we may make use of in future, so | ||
969 | * we expose separate masks. | ||
970 | */ | ||
971 | unsigned long mask = ptrauth_user_pac_mask(); | ||
972 | struct user_pac_mask uregs = { | ||
973 | .data_mask = mask, | ||
974 | .insn_mask = mask, | ||
975 | }; | ||
976 | |||
977 | if (!system_supports_address_auth()) | ||
978 | return -EINVAL; | ||
979 | |||
980 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &uregs, 0, -1); | ||
981 | } | ||
982 | #endif /* CONFIG_ARM64_PTR_AUTH */ | ||
983 | |||
959 | enum aarch64_regset { | 984 | enum aarch64_regset { |
960 | REGSET_GPR, | 985 | REGSET_GPR, |
961 | REGSET_FPR, | 986 | REGSET_FPR, |
@@ -968,6 +993,9 @@ enum aarch64_regset { | |||
968 | #ifdef CONFIG_ARM64_SVE | 993 | #ifdef CONFIG_ARM64_SVE |
969 | REGSET_SVE, | 994 | REGSET_SVE, |
970 | #endif | 995 | #endif |
996 | #ifdef CONFIG_ARM64_PTR_AUTH | ||
997 | REGSET_PAC_MASK, | ||
998 | #endif | ||
971 | }; | 999 | }; |
972 | 1000 | ||
973 | static const struct user_regset aarch64_regsets[] = { | 1001 | static const struct user_regset aarch64_regsets[] = { |
@@ -1037,6 +1065,16 @@ static const struct user_regset aarch64_regsets[] = { | |||
1037 | .get_size = sve_get_size, | 1065 | .get_size = sve_get_size, |
1038 | }, | 1066 | }, |
1039 | #endif | 1067 | #endif |
1068 | #ifdef CONFIG_ARM64_PTR_AUTH | ||
1069 | [REGSET_PAC_MASK] = { | ||
1070 | .core_note_type = NT_ARM_PAC_MASK, | ||
1071 | .n = sizeof(struct user_pac_mask) / sizeof(u64), | ||
1072 | .size = sizeof(u64), | ||
1073 | .align = sizeof(u64), | ||
1074 | .get = pac_mask_get, | ||
1075 | /* this cannot be set dynamically */ | ||
1076 | }, | ||
1077 | #endif | ||
1040 | }; | 1078 | }; |
1041 | 1079 | ||
1042 | static const struct user_regset_view user_aarch64_view = { | 1080 | static const struct user_regset_view user_aarch64_view = { |
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index c5358e0ae7c5..3f23273d690c 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h | |||
@@ -420,6 +420,7 @@ typedef struct elf64_shdr { | |||
420 | #define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ | 420 | #define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ |
421 | #define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */ | 421 | #define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */ |
422 | #define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension registers */ | 422 | #define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension registers */ |
423 | #define NT_ARM_PAC_MASK 0x406 /* ARM pointer authentication code masks */ | ||
423 | #define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */ | 424 | #define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */ |
424 | #define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */ | 425 | #define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */ |
425 | #define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */ | 426 | #define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */ |