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.
Unified · Split
| @@ -207,6 +207,9 @@ static inline unsigned long kaslr_offset(void) · 206 unmodified lines | ||
| 207 | 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 | 214 | * Allow all memory at the discovery stage. We will clip it later. |
| 212 | 215 | */ |
| @@ -2,9 +2,11 @@ · 1 unmodified line | ||
| 2 | 2 | #ifndef __ASM_POINTER_AUTH_H |
| 3 | 3 | #define __ASM_POINTER_AUTH_H |
| 4 | 4 | |
| 5 | +#include <linux/bitops.h> | |
| 5 | 6 | #include <linux/random.h> |
| 6 | 7 | |
| 7 | 8 | #include <asm/cpufeature.h> |
| 9 | +#include <asm/memory.h> | |
| 8 | 10 | #include <asm/sysreg.h> |
| 9 | 11 | |
| 10 | 12 | #ifdef CONFIG_ARM64_PTR_AUTH |
| @@ -61,6 +63,12 @@ static inline void ptrauth_keys_switch(struct ptrauth_keys *keys) · 50 unmodified lines | ||
| 61 | 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 | 72 | #define ptrauth_thread_init_user(tsk) \ |
| 65 | 73 | do { \ |
| 66 | 74 | struct task_struct *__ptiu_tsk = (tsk); \ |
| @@ -53,8 +53,6 @@ · 52 unmodified lines | ||
| 53 | 53 | */ |
| 54 | 54 | |
| 55 | 55 | #define DEFAULT_MAP_WINDOW_64 (UL(1) << VA_BITS) |
| 56 | − | |
| 57 | −extern u64 vabits_user; | |
| 58 | 56 | #define TASK_SIZE_64 (UL(1) << vabits_user) |
| 59 | 57 | |
| 60 | 58 | #ifdef CONFIG_COMPAT |
| @@ -229,6 +229,13 @@ struct user_sve_header { · 228 unmodified lines | ||
| 229 | 229 | SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, flags) \ |
| 230 | 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 | 239 | #endif /* __ASSEMBLY__ */ |
| 233 | 240 | |
| 234 | 241 | #endif /* _UAPI__ASM_PTRACE_H */ |
| @@ -46,6 +46,7 @@ · 45 unmodified lines | ||
| 46 | 46 | #include <asm/debug-monitors.h> |
| 47 | 47 | #include <asm/fpsimd.h> |
| 48 | 48 | #include <asm/pgtable.h> |
| 49 | +#include <asm/pointer_auth.h> | |
| 49 | 50 | #include <asm/stacktrace.h> |
| 50 | 51 | #include <asm/syscall.h> |
| 51 | 52 | #include <asm/traps.h> |
| @@ -956,6 +957,30 @@ out: · 904 unmodified lines | ||
| 956 | 957 | |
| 957 | 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 | 984 | enum aarch64_regset { |
| 960 | 985 | REGSET_GPR, |
| 961 | 986 | REGSET_FPR, |
| @@ -968,6 +993,9 @@ enum aarch64_regset { · 6 unmodified lines | ||
| 968 | 993 | #ifdef CONFIG_ARM64_SVE |
| 969 | 994 | REGSET_SVE, |
| 970 | 995 | #endif |
| 996 | +#ifdef CONFIG_ARM64_PTR_AUTH | |
| 997 | + REGSET_PAC_MASK, | |
| 998 | +#endif | |
| 971 | 999 | }; |
| 972 | 1000 | |
| 973 | 1001 | static const struct user_regset aarch64_regsets[] = { |
| @@ -1037,6 +1065,16 @@ static const struct user_regset aarch64_regsets[] = { · 63 unmodified lines | ||
| 1037 | 1065 | .get_size = sve_get_size, |
| 1038 | 1066 | }, |
| 1039 | 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 | 1080 | static const struct user_regset_view user_aarch64_view = { |
| @@ -420,6 +420,7 @@ typedef struct elf64_shdr { · 419 unmodified lines | ||
| 420 | 420 | #define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ |
| 421 | 421 | #define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */ |
| 422 | 422 | #define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension registers */ |
| 423 | +#define NT_ARM_PAC_MASK 0x406 /* ARM pointer authentication code masks */ | |
| 423 | 424 | #define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */ |
| 424 | 425 | #define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */ |
| 425 | 426 | #define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */ |