History

arm64: add ptrace regsets for ptrauth key management

Add two new ptrace regsets, which can be used to request and change the pointer authentication keys of a thread. NT_ARM_PACA_KEYS gives access to the instruction/data address keys, and NT_ARM_PACG_KEYS to the generic authentication key. The keys are also part of the core dump file of the process. The regsets are only exposed if the kernel is compiled with CONFIG_CHECKPOINT_RESTORE=y, as the only intended use case is checkpointing and restoring processes that are using pointer authentication. (This can be changed later if there are other use cases.)

Kristina Martsenko committed 7 years ago

Commit d0a060b1 parent e2a2e564 files · +167 −0Browse files

Unified · Split

4 files
  1. Documentation/arm64/pointer-authentication.txt +5 −0
  2. arch/arm64/include/uapi/asm/ptrace.h +13 −0
  3. arch/arm64/kernel/ptrace.c +147 −0
  4. include/uapi/linux/elf.h +2 −0
Documentation/arm64/pointer-authentication.txt+5−0
@@ -78,6 +78,11 @@ bits can vary between the two. Note that the masks apply to TTBR0 · 77 unmodified lines
7878 addresses, and are not valid to apply to TTBR1 addresses (e.g. kernel
7979 pointers).
8080
81+Additionally, when CONFIG_CHECKPOINT_RESTORE is also set, the kernel
82+will expose the NT_ARM_PACA_KEYS and NT_ARM_PACG_KEYS regsets (struct
83+user_pac_address_keys and struct user_pac_generic_keys). These can be
84+used to get and set the keys for a thread.
85+
8186
8287 Virtualization
8388 --------------
arch/arm64/include/uapi/asm/ptrace.h+13−0
@@ -233,6 +233,19 @@ struct user_pac_mask { · 232 unmodified lines
233233 __u64 insn_mask;
234234 };
235235
236+/* pointer authentication keys (NT_ARM_PACA_KEYS, NT_ARM_PACG_KEYS) */
237+
238+struct user_pac_address_keys {
239+ __uint128_t apiakey;
240+ __uint128_t apibkey;
241+ __uint128_t apdakey;
242+ __uint128_t apdbkey;
243+};
244+
245+struct user_pac_generic_keys {
246+ __uint128_t apgakey;
247+};
248+
236249 #endif /* __ASSEMBLY__ */
237250
238251 #endif /* _UAPI__ASM_PTRACE_H */
arch/arm64/kernel/ptrace.c+147−0
@@ -979,6 +979,131 @@ static int pac_mask_get(struct task_struct *target, · 978 unmodified lines
979979
980980 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &uregs, 0, -1);
981981 }
982+
983+#ifdef CONFIG_CHECKPOINT_RESTORE
984+static __uint128_t pac_key_to_user(const struct ptrauth_key *key)
985+{
986+ return (__uint128_t)key->hi << 64 | key->lo;
987+}
988+
989+static struct ptrauth_key pac_key_from_user(__uint128_t ukey)
990+{
991+ struct ptrauth_key key = {
992+ .lo = (unsigned long)ukey,
993+ .hi = (unsigned long)(ukey >> 64),
994+ };
995+
996+ return key;
997+}
998+
999+static void pac_address_keys_to_user(struct user_pac_address_keys *ukeys,
1000+ const struct ptrauth_keys *keys)
1001+{
1002+ ukeys->apiakey = pac_key_to_user(&keys->apia);
1003+ ukeys->apibkey = pac_key_to_user(&keys->apib);
1004+ ukeys->apdakey = pac_key_to_user(&keys->apda);
1005+ ukeys->apdbkey = pac_key_to_user(&keys->apdb);
1006+}
1007+
1008+static void pac_address_keys_from_user(struct ptrauth_keys *keys,
1009+ const struct user_pac_address_keys *ukeys)
1010+{
1011+ keys->apia = pac_key_from_user(ukeys->apiakey);
1012+ keys->apib = pac_key_from_user(ukeys->apibkey);
1013+ keys->apda = pac_key_from_user(ukeys->apdakey);
1014+ keys->apdb = pac_key_from_user(ukeys->apdbkey);
1015+}
1016+
1017+static int pac_address_keys_get(struct task_struct *target,
1018+ const struct user_regset *regset,
1019+ unsigned int pos, unsigned int count,
1020+ void *kbuf, void __user *ubuf)
1021+{
1022+ struct ptrauth_keys *keys = &target->thread.keys_user;
1023+ struct user_pac_address_keys user_keys;
1024+
1025+ if (!system_supports_address_auth())
1026+ return -EINVAL;
1027+
1028+ pac_address_keys_to_user(&user_keys, keys);
1029+
1030+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
1031+ &user_keys, 0, -1);
1032+}
1033+
1034+static int pac_address_keys_set(struct task_struct *target,
1035+ const struct user_regset *regset,
1036+ unsigned int pos, unsigned int count,
1037+ const void *kbuf, const void __user *ubuf)
1038+{
1039+ struct ptrauth_keys *keys = &target->thread.keys_user;
1040+ struct user_pac_address_keys user_keys;
1041+ int ret;
1042+
1043+ if (!system_supports_address_auth())
1044+ return -EINVAL;
1045+
1046+ pac_address_keys_to_user(&user_keys, keys);
1047+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
1048+ &user_keys, 0, -1);
1049+ if (ret)
1050+ return ret;
1051+ pac_address_keys_from_user(keys, &user_keys);
1052+
1053+ return 0;
1054+}
1055+
1056+static void pac_generic_keys_to_user(struct user_pac_generic_keys *ukeys,
1057+ const struct ptrauth_keys *keys)
1058+{
1059+ ukeys->apgakey = pac_key_to_user(&keys->apga);
1060+}
1061+
1062+static void pac_generic_keys_from_user(struct ptrauth_keys *keys,
1063+ const struct user_pac_generic_keys *ukeys)
1064+{
1065+ keys->apga = pac_key_from_user(ukeys->apgakey);
1066+}
1067+
1068+static int pac_generic_keys_get(struct task_struct *target,
1069+ const struct user_regset *regset,
1070+ unsigned int pos, unsigned int count,
1071+ void *kbuf, void __user *ubuf)
1072+{
1073+ struct ptrauth_keys *keys = &target->thread.keys_user;
1074+ struct user_pac_generic_keys user_keys;
1075+
1076+ if (!system_supports_generic_auth())
1077+ return -EINVAL;
1078+
1079+ pac_generic_keys_to_user(&user_keys, keys);
1080+
1081+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
1082+ &user_keys, 0, -1);
1083+}
1084+
1085+static int pac_generic_keys_set(struct task_struct *target,
1086+ const struct user_regset *regset,
1087+ unsigned int pos, unsigned int count,
1088+ const void *kbuf, const void __user *ubuf)
1089+{
1090+ struct ptrauth_keys *keys = &target->thread.keys_user;
1091+ struct user_pac_generic_keys user_keys;
1092+ int ret;
1093+
1094+ if (!system_supports_generic_auth())
1095+ return -EINVAL;
1096+
1097+ pac_generic_keys_to_user(&user_keys, keys);
1098+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
1099+ &user_keys, 0, -1);
1100+ if (ret)
1101+ return ret;
1102+ pac_generic_keys_from_user(keys, &user_keys);
1103+
1104+ return 0;
1105+}
1106+#endif /* CONFIG_CHECKPOINT_RESTORE */
9821107 #endif /* CONFIG_ARM64_PTR_AUTH */
9831108
9841109 enum aarch64_regset {
@@ -995,6 +1120,10 @@ enum aarch64_regset { · 10 unmodified lines
9951120 #endif
9961121 #ifdef CONFIG_ARM64_PTR_AUTH
9971122 REGSET_PAC_MASK,
1123+#ifdef CONFIG_CHECKPOINT_RESTORE
1124+ REGSET_PACA_KEYS,
1125+ REGSET_PACG_KEYS,
1126+#endif
9981127 #endif
9991128 };
10001129
@@ -1074,6 +1203,24 @@ static const struct user_regset aarch64_regsets[] = { · 73 unmodified lines
10741203 .get = pac_mask_get,
10751204 /* this cannot be set dynamically */
10761205 },
1206+#ifdef CONFIG_CHECKPOINT_RESTORE
1207+ [REGSET_PACA_KEYS] = {
1208+ .core_note_type = NT_ARM_PACA_KEYS,
1209+ .n = sizeof(struct user_pac_address_keys) / sizeof(__uint128_t),
1210+ .size = sizeof(__uint128_t),
1211+ .align = sizeof(__uint128_t),
1212+ .get = pac_address_keys_get,
1213+ .set = pac_address_keys_set,
1214+ },
1215+ [REGSET_PACG_KEYS] = {
1216+ .core_note_type = NT_ARM_PACG_KEYS,
1217+ .n = sizeof(struct user_pac_generic_keys) / sizeof(__uint128_t),
1218+ .size = sizeof(__uint128_t),
1219+ .align = sizeof(__uint128_t),
1220+ .get = pac_generic_keys_get,
1221+ .set = pac_generic_keys_set,
1222+ },
1223+#endif
10771224 #endif
10781225 };
10791226
include/uapi/linux/elf.h+2−0
@@ -421,6 +421,8 @@ typedef struct elf64_shdr { · 420 unmodified lines
421421 #define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
422422 #define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension registers */
423423 #define NT_ARM_PAC_MASK 0x406 /* ARM pointer authentication code masks */
424+#define NT_ARM_PACA_KEYS 0x407 /* ARM pointer authentication address keys */
425+#define NT_ARM_PACG_KEYS 0x408 /* ARM pointer authentication generic key */
424426 #define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */
425427 #define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */
426428 #define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */