linux/arch/arm64/kernel/pointer_auth.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3#include <linux/compat.h>
   4#include <linux/errno.h>
   5#include <linux/prctl.h>
   6#include <linux/random.h>
   7#include <linux/sched.h>
   8#include <asm/cpufeature.h>
   9#include <asm/pointer_auth.h>
  10
  11int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg)
  12{
  13        struct ptrauth_keys_user *keys = &tsk->thread.keys_user;
  14        unsigned long addr_key_mask = PR_PAC_APIAKEY | PR_PAC_APIBKEY |
  15                                      PR_PAC_APDAKEY | PR_PAC_APDBKEY;
  16        unsigned long key_mask = addr_key_mask | PR_PAC_APGAKEY;
  17
  18        if (!system_supports_address_auth() && !system_supports_generic_auth())
  19                return -EINVAL;
  20
  21        if (is_compat_thread(task_thread_info(tsk)))
  22                return -EINVAL;
  23
  24        if (!arg) {
  25                ptrauth_keys_init_user(keys);
  26                return 0;
  27        }
  28
  29        if (arg & ~key_mask)
  30                return -EINVAL;
  31
  32        if (((arg & addr_key_mask) && !system_supports_address_auth()) ||
  33            ((arg & PR_PAC_APGAKEY) && !system_supports_generic_auth()))
  34                return -EINVAL;
  35
  36        if (arg & PR_PAC_APIAKEY)
  37                get_random_bytes(&keys->apia, sizeof(keys->apia));
  38        if (arg & PR_PAC_APIBKEY)
  39                get_random_bytes(&keys->apib, sizeof(keys->apib));
  40        if (arg & PR_PAC_APDAKEY)
  41                get_random_bytes(&keys->apda, sizeof(keys->apda));
  42        if (arg & PR_PAC_APDBKEY)
  43                get_random_bytes(&keys->apdb, sizeof(keys->apdb));
  44        if (arg & PR_PAC_APGAKEY)
  45                get_random_bytes(&keys->apga, sizeof(keys->apga));
  46        ptrauth_keys_install_user(keys);
  47
  48        return 0;
  49}
  50
  51static u64 arg_to_enxx_mask(unsigned long arg)
  52{
  53        u64 sctlr_enxx_mask = 0;
  54
  55        WARN_ON(arg & ~PR_PAC_ENABLED_KEYS_MASK);
  56        if (arg & PR_PAC_APIAKEY)
  57                sctlr_enxx_mask |= SCTLR_ELx_ENIA;
  58        if (arg & PR_PAC_APIBKEY)
  59                sctlr_enxx_mask |= SCTLR_ELx_ENIB;
  60        if (arg & PR_PAC_APDAKEY)
  61                sctlr_enxx_mask |= SCTLR_ELx_ENDA;
  62        if (arg & PR_PAC_APDBKEY)
  63                sctlr_enxx_mask |= SCTLR_ELx_ENDB;
  64        return sctlr_enxx_mask;
  65}
  66
  67int ptrauth_set_enabled_keys(struct task_struct *tsk, unsigned long keys,
  68                             unsigned long enabled)
  69{
  70        u64 sctlr = tsk->thread.sctlr_user;
  71
  72        if (!system_supports_address_auth())
  73                return -EINVAL;
  74
  75        if (is_compat_thread(task_thread_info(tsk)))
  76                return -EINVAL;
  77
  78        if ((keys & ~PR_PAC_ENABLED_KEYS_MASK) || (enabled & ~keys))
  79                return -EINVAL;
  80
  81        sctlr &= ~arg_to_enxx_mask(keys);
  82        sctlr |= arg_to_enxx_mask(enabled);
  83        if (tsk == current)
  84                set_task_sctlr_el1(sctlr);
  85        else
  86                tsk->thread.sctlr_user = sctlr;
  87
  88        return 0;
  89}
  90
  91int ptrauth_get_enabled_keys(struct task_struct *tsk)
  92{
  93        int retval = 0;
  94
  95        if (!system_supports_address_auth())
  96                return -EINVAL;
  97
  98        if (is_compat_thread(task_thread_info(tsk)))
  99                return -EINVAL;
 100
 101        if (tsk->thread.sctlr_user & SCTLR_ELx_ENIA)
 102                retval |= PR_PAC_APIAKEY;
 103        if (tsk->thread.sctlr_user & SCTLR_ELx_ENIB)
 104                retval |= PR_PAC_APIBKEY;
 105        if (tsk->thread.sctlr_user & SCTLR_ELx_ENDA)
 106                retval |= PR_PAC_APDAKEY;
 107        if (tsk->thread.sctlr_user & SCTLR_ELx_ENDB)
 108                retval |= PR_PAC_APDBKEY;
 109
 110        return retval;
 111}
 112