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 | 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 | */ |
| @@ -2,9 +2,11 @@ · 1 unmodified line | |||
| 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) · 50 unmodified lines | |||
| 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); \ |
| @@ -53,8 +53,6 @@ · 52 unmodified lines | |||
| 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 |
| @@ -229,6 +229,13 @@ struct user_sve_header { · 228 unmodified lines | |||
| 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 */ |
| @@ -46,6 +46,7 @@ · 45 unmodified lines | |||
| 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: · 904 unmodified lines | |||
| 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 { · 6 unmodified lines | |||
| 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[] = { · 63 unmodified lines | |||
| 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 = { |
| @@ -420,6 +420,7 @@ typedef struct elf64_shdr { · 419 unmodified lines | |||
| 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 */ |