arm64: add ptrace regsets for ptrauth key management
authorKristina Martsenko <kristina.martsenko@arm.com>
Wed, 30 Jan 2019 12:02:44 +0000 (12:02 +0000)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 1 Feb 2019 13:56:58 +0000 (13:56 +0000)
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>
Documentation/arm64/pointer-authentication.txt
arch/arm64/include/uapi/asm/ptrace.h
arch/arm64/kernel/ptrace.c
include/uapi/linux/elf.h

index a25cd21290e900aec89165f3f9368c8d0a61081b..5baca42ba146dd56c6c3e1ca433173290fe9ef5c 100644 (file)
@@ -78,6 +78,11 @@ bits can vary between the two. Note that the masks apply to TTBR0
 addresses, and are not valid to apply to TTBR1 addresses (e.g. kernel
 pointers).
 
+Additionally, when CONFIG_CHECKPOINT_RESTORE is also set, the kernel
+will expose the NT_ARM_PACA_KEYS and NT_ARM_PACG_KEYS regsets (struct
+user_pac_address_keys and struct user_pac_generic_keys). These can be
+used to get and set the keys for a thread.
+
 
 Virtualization
 --------------
index 28d77c9ed53110b89a2751c921931087dc453f96..d78623acb6491e6ef4ae64a365c22e29bd5cefe2 100644 (file)
@@ -233,6 +233,19 @@ struct user_pac_mask {
        __u64           insn_mask;
 };
 
+/* pointer authentication keys (NT_ARM_PACA_KEYS, NT_ARM_PACG_KEYS) */
+
+struct user_pac_address_keys {
+       __uint128_t     apiakey;
+       __uint128_t     apibkey;
+       __uint128_t     apdakey;
+       __uint128_t     apdbkey;
+};
+
+struct user_pac_generic_keys {
+       __uint128_t     apgakey;
+};
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI__ASM_PTRACE_H */
index 9dce33b0e26042b4d70e8a1ae35c0b1f39195e05..a86413be5a2d0ca246cf656d1ae6be2faf3ba993 100644 (file)
@@ -979,6 +979,131 @@ static int pac_mask_get(struct task_struct *target,
 
        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &uregs, 0, -1);
 }
+
+#ifdef CONFIG_CHECKPOINT_RESTORE
+static __uint128_t pac_key_to_user(const struct ptrauth_key *key)
+{
+       return (__uint128_t)key->hi << 64 | key->lo;
+}
+
+static struct ptrauth_key pac_key_from_user(__uint128_t ukey)
+{
+       struct ptrauth_key key = {
+               .lo = (unsigned long)ukey,
+               .hi = (unsigned long)(ukey >> 64),
+       };
+
+       return key;
+}
+
+static void pac_address_keys_to_user(struct user_pac_address_keys *ukeys,
+                                    const struct ptrauth_keys *keys)
+{
+       ukeys->apiakey = pac_key_to_user(&keys->apia);
+       ukeys->apibkey = pac_key_to_user(&keys->apib);
+       ukeys->apdakey = pac_key_to_user(&keys->apda);
+       ukeys->apdbkey = pac_key_to_user(&keys->apdb);
+}
+
+static void pac_address_keys_from_user(struct ptrauth_keys *keys,
+                                      const struct user_pac_address_keys *ukeys)
+{
+       keys->apia = pac_key_from_user(ukeys->apiakey);
+       keys->apib = pac_key_from_user(ukeys->apibkey);
+       keys->apda = pac_key_from_user(ukeys->apdakey);
+       keys->apdb = pac_key_from_user(ukeys->apdbkey);
+}
+
+static int pac_address_keys_get(struct task_struct *target,
+                               const struct user_regset *regset,
+                               unsigned int pos, unsigned int count,
+                               void *kbuf, void __user *ubuf)
+{
+       struct ptrauth_keys *keys = &target->thread.keys_user;
+       struct user_pac_address_keys user_keys;
+
+       if (!system_supports_address_auth())
+               return -EINVAL;
+
+       pac_address_keys_to_user(&user_keys, keys);
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                  &user_keys, 0, -1);
+}
+
+static int pac_address_keys_set(struct task_struct *target,
+                               const struct user_regset *regset,
+                               unsigned int pos, unsigned int count,
+                               const void *kbuf, const void __user *ubuf)
+{
+       struct ptrauth_keys *keys = &target->thread.keys_user;
+       struct user_pac_address_keys user_keys;
+       int ret;
+
+       if (!system_supports_address_auth())
+               return -EINVAL;
+
+       pac_address_keys_to_user(&user_keys, keys);
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &user_keys, 0, -1);
+       if (ret)
+               return ret;
+       pac_address_keys_from_user(keys, &user_keys);
+
+       return 0;
+}
+
+static void pac_generic_keys_to_user(struct user_pac_generic_keys *ukeys,
+                                    const struct ptrauth_keys *keys)
+{
+       ukeys->apgakey = pac_key_to_user(&keys->apga);
+}
+
+static void pac_generic_keys_from_user(struct ptrauth_keys *keys,
+                                      const struct user_pac_generic_keys *ukeys)
+{
+       keys->apga = pac_key_from_user(ukeys->apgakey);
+}
+
+static int pac_generic_keys_get(struct task_struct *target,
+                               const struct user_regset *regset,
+                               unsigned int pos, unsigned int count,
+                               void *kbuf, void __user *ubuf)
+{
+       struct ptrauth_keys *keys = &target->thread.keys_user;
+       struct user_pac_generic_keys user_keys;
+
+       if (!system_supports_generic_auth())
+               return -EINVAL;
+
+       pac_generic_keys_to_user(&user_keys, keys);
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                  &user_keys, 0, -1);
+}
+
+static int pac_generic_keys_set(struct task_struct *target,
+                               const struct user_regset *regset,
+                               unsigned int pos, unsigned int count,
+                               const void *kbuf, const void __user *ubuf)
+{
+       struct ptrauth_keys *keys = &target->thread.keys_user;
+       struct user_pac_generic_keys user_keys;
+       int ret;
+
+       if (!system_supports_generic_auth())
+               return -EINVAL;
+
+       pac_generic_keys_to_user(&user_keys, keys);
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &user_keys, 0, -1);
+       if (ret)
+               return ret;
+       pac_generic_keys_from_user(keys, &user_keys);
+
+       return 0;
+}
+#endif /* CONFIG_CHECKPOINT_RESTORE */
 #endif /* CONFIG_ARM64_PTR_AUTH */
 
 enum aarch64_regset {
@@ -995,6 +1120,10 @@ enum aarch64_regset {
 #endif
 #ifdef CONFIG_ARM64_PTR_AUTH
        REGSET_PAC_MASK,
+#ifdef CONFIG_CHECKPOINT_RESTORE
+       REGSET_PACA_KEYS,
+       REGSET_PACG_KEYS,
+#endif
 #endif
 };
 
@@ -1074,6 +1203,24 @@ static const struct user_regset aarch64_regsets[] = {
                .get = pac_mask_get,
                /* this cannot be set dynamically */
        },
+#ifdef CONFIG_CHECKPOINT_RESTORE
+       [REGSET_PACA_KEYS] = {
+               .core_note_type = NT_ARM_PACA_KEYS,
+               .n = sizeof(struct user_pac_address_keys) / sizeof(__uint128_t),
+               .size = sizeof(__uint128_t),
+               .align = sizeof(__uint128_t),
+               .get = pac_address_keys_get,
+               .set = pac_address_keys_set,
+       },
+       [REGSET_PACG_KEYS] = {
+               .core_note_type = NT_ARM_PACG_KEYS,
+               .n = sizeof(struct user_pac_generic_keys) / sizeof(__uint128_t),
+               .size = sizeof(__uint128_t),
+               .align = sizeof(__uint128_t),
+               .get = pac_generic_keys_get,
+               .set = pac_generic_keys_set,
+       },
+#endif
 #endif
 };
 
index e4d6ddd93567c67c6230253632debfb42afcd8d6..34c02e4290fe5b7970b432052ddbd0beb8943f8a 100644 (file)
@@ -421,6 +421,8 @@ typedef struct elf64_shdr {
 #define NT_ARM_SYSTEM_CALL     0x404   /* ARM system call number */
 #define NT_ARM_SVE     0x405           /* ARM Scalable Vector Extension registers */
 #define NT_ARM_PAC_MASK                0x406   /* ARM pointer authentication code masks */
+#define NT_ARM_PACA_KEYS       0x407   /* ARM pointer authentication address keys */
+#define NT_ARM_PACG_KEYS       0x408   /* ARM pointer authentication generic key */
 #define NT_ARC_V2      0x600           /* ARCv2 accumulator/extra registers */
 #define NT_VMCOREDD    0x700           /* Vmcore Device Dump Note */
 #define NT_MIPS_DSP    0x800           /* MIPS DSP ASE registers */