aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKristina Martsenko <kristina.martsenko@arm.com>2019-01-30 07:02:44 -0500
committerCatalin Marinas <catalin.marinas@arm.com>2019-02-01 08:56:58 -0500
commitd0a060be573bfbf8753a15dca35497db5e968bb0 (patch)
tree3b584b617217dfcb32ef5b092fc9eed47182e29a
parente2a2e56e40822ab78e304198387f61314af7d7ce (diff)
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.) Reviewed-by: Dave Martin <Dave.Martin@arm.com> Signed-off-by: Kristina Martsenko <kristina.martsenko@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r--Documentation/arm64/pointer-authentication.txt5
-rw-r--r--arch/arm64/include/uapi/asm/ptrace.h13
-rw-r--r--arch/arm64/kernel/ptrace.c147
-rw-r--r--include/uapi/linux/elf.h2
4 files changed, 167 insertions, 0 deletions
diff --git a/Documentation/arm64/pointer-authentication.txt b/Documentation/arm64/pointer-authentication.txt
index a25cd21290e9..5baca42ba146 100644
--- a/Documentation/arm64/pointer-authentication.txt
+++ b/Documentation/arm64/pointer-authentication.txt
@@ -78,6 +78,11 @@ bits can vary between the two. Note that the masks apply to TTBR0
78addresses, and are not valid to apply to TTBR1 addresses (e.g. kernel 78addresses, and are not valid to apply to TTBR1 addresses (e.g. kernel
79pointers). 79pointers).
80 80
81Additionally, when CONFIG_CHECKPOINT_RESTORE is also set, the kernel
82will expose the NT_ARM_PACA_KEYS and NT_ARM_PACG_KEYS regsets (struct
83user_pac_address_keys and struct user_pac_generic_keys). These can be
84used to get and set the keys for a thread.
85
81 86
82Virtualization 87Virtualization
83-------------- 88--------------
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index 28d77c9ed531..d78623acb649 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -233,6 +233,19 @@ struct user_pac_mask {
233 __u64 insn_mask; 233 __u64 insn_mask;
234}; 234};
235 235
236/* pointer authentication keys (NT_ARM_PACA_KEYS, NT_ARM_PACG_KEYS) */
237
238struct user_pac_address_keys {
239 __uint128_t apiakey;
240 __uint128_t apibkey;
241 __uint128_t apdakey;
242 __uint128_t apdbkey;
243};
244
245struct user_pac_generic_keys {
246 __uint128_t apgakey;
247};
248
236#endif /* __ASSEMBLY__ */ 249#endif /* __ASSEMBLY__ */
237 250
238#endif /* _UAPI__ASM_PTRACE_H */ 251#endif /* _UAPI__ASM_PTRACE_H */
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 9dce33b0e260..a86413be5a2d 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -979,6 +979,131 @@ static int pac_mask_get(struct task_struct *target,
979 979
980 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &uregs, 0, -1); 980 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &uregs, 0, -1);
981} 981}
982
983#ifdef CONFIG_CHECKPOINT_RESTORE
984static __uint128_t pac_key_to_user(const struct ptrauth_key *key)
985{
986 return (__uint128_t)key->hi << 64 | key->lo;
987}
988
989static 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
999static 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
1008static 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
1017static 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
1034static 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
1056static 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
1062static 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
1068static 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
1085static 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 */
982#endif /* CONFIG_ARM64_PTR_AUTH */ 1107#endif /* CONFIG_ARM64_PTR_AUTH */
983 1108
984enum aarch64_regset { 1109enum aarch64_regset {
@@ -995,6 +1120,10 @@ enum aarch64_regset {
995#endif 1120#endif
996#ifdef CONFIG_ARM64_PTR_AUTH 1121#ifdef CONFIG_ARM64_PTR_AUTH
997 REGSET_PAC_MASK, 1122 REGSET_PAC_MASK,
1123#ifdef CONFIG_CHECKPOINT_RESTORE
1124 REGSET_PACA_KEYS,
1125 REGSET_PACG_KEYS,
1126#endif
998#endif 1127#endif
999}; 1128};
1000 1129
@@ -1074,6 +1203,24 @@ static const struct user_regset aarch64_regsets[] = {
1074 .get = pac_mask_get, 1203 .get = pac_mask_get,
1075 /* this cannot be set dynamically */ 1204 /* this cannot be set dynamically */
1076 }, 1205 },
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
1077#endif 1224#endif
1078}; 1225};
1079 1226
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index e4d6ddd93567..34c02e4290fe 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -421,6 +421,8 @@ typedef struct elf64_shdr {
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_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 */
424#define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */ 426#define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */
425#define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */ 427#define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */
426#define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */ 428#define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */