Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  * Copyright 2020, Sandipan Das, IBM Corp.
0004  */
0005 
0006 #ifndef _SELFTESTS_POWERPC_PKEYS_H
0007 #define _SELFTESTS_POWERPC_PKEYS_H
0008 
0009 #include <sys/mman.h>
0010 
0011 #include "reg.h"
0012 #include "utils.h"
0013 
0014 /*
0015  * Older versions of libc use the Intel-specific access rights.
0016  * Hence, override the definitions as they might be incorrect.
0017  */
0018 #undef PKEY_DISABLE_ACCESS
0019 #define PKEY_DISABLE_ACCESS 0x3
0020 
0021 #undef PKEY_DISABLE_WRITE
0022 #define PKEY_DISABLE_WRITE  0x2
0023 
0024 #undef PKEY_DISABLE_EXECUTE
0025 #define PKEY_DISABLE_EXECUTE    0x4
0026 
0027 /* Older versions of libc do not not define this */
0028 #ifndef SEGV_PKUERR
0029 #define SEGV_PKUERR 4
0030 #endif
0031 
0032 #define SI_PKEY_OFFSET  0x20
0033 
0034 #define __NR_pkey_mprotect  386
0035 #define __NR_pkey_alloc     384
0036 #define __NR_pkey_free      385
0037 
0038 #define PKEY_BITS_PER_PKEY  2
0039 #define NR_PKEYS        32
0040 #define PKEY_BITS_MASK      ((1UL << PKEY_BITS_PER_PKEY) - 1)
0041 
0042 inline unsigned long pkeyreg_get(void)
0043 {
0044     return mfspr(SPRN_AMR);
0045 }
0046 
0047 inline void pkeyreg_set(unsigned long amr)
0048 {
0049     set_amr(amr);
0050 }
0051 
0052 void pkey_set_rights(int pkey, unsigned long rights)
0053 {
0054     unsigned long amr, shift;
0055 
0056     shift = (NR_PKEYS - pkey - 1) * PKEY_BITS_PER_PKEY;
0057     amr = pkeyreg_get();
0058     amr &= ~(PKEY_BITS_MASK << shift);
0059     amr |= (rights & PKEY_BITS_MASK) << shift;
0060     pkeyreg_set(amr);
0061 }
0062 
0063 int sys_pkey_mprotect(void *addr, size_t len, int prot, int pkey)
0064 {
0065     return syscall(__NR_pkey_mprotect, addr, len, prot, pkey);
0066 }
0067 
0068 int sys_pkey_alloc(unsigned long flags, unsigned long rights)
0069 {
0070     return syscall(__NR_pkey_alloc, flags, rights);
0071 }
0072 
0073 int sys_pkey_free(int pkey)
0074 {
0075     return syscall(__NR_pkey_free, pkey);
0076 }
0077 
0078 int pkeys_unsupported(void)
0079 {
0080     bool hash_mmu = false;
0081     int pkey;
0082 
0083     /* Protection keys are currently supported on Hash MMU only */
0084     FAIL_IF(using_hash_mmu(&hash_mmu));
0085     SKIP_IF(!hash_mmu);
0086 
0087     /* Check if the system call is supported */
0088     pkey = sys_pkey_alloc(0, 0);
0089     SKIP_IF(pkey < 0);
0090     sys_pkey_free(pkey);
0091 
0092     return 0;
0093 }
0094 
0095 int siginfo_pkey(siginfo_t *si)
0096 {
0097     /*
0098      * In older versions of libc, siginfo_t does not have si_pkey as
0099      * a member.
0100      */
0101 #ifdef si_pkey
0102     return si->si_pkey;
0103 #else
0104     return *((int *)(((char *) si) + SI_PKEY_OFFSET));
0105 #endif
0106 }
0107 
0108 #define pkey_rights(r) ({                       \
0109     static char buf[4] = "rwx";                 \
0110     unsigned int amr_bits;                      \
0111     if ((r) & PKEY_DISABLE_EXECUTE)                 \
0112         buf[2] = '-';                       \
0113     amr_bits = (r) & PKEY_BITS_MASK;                \
0114     if (amr_bits & PKEY_DISABLE_WRITE)              \
0115         buf[1] = '-';                       \
0116     if (amr_bits & PKEY_DISABLE_ACCESS & ~PKEY_DISABLE_WRITE)   \
0117         buf[0] = '-';                       \
0118     buf;                                \
0119 })
0120 
0121 unsigned long next_pkey_rights(unsigned long rights)
0122 {
0123     if (rights == PKEY_DISABLE_ACCESS)
0124         return PKEY_DISABLE_EXECUTE;
0125     else if (rights == (PKEY_DISABLE_ACCESS | PKEY_DISABLE_EXECUTE))
0126         return 0;
0127 
0128     if ((rights & PKEY_BITS_MASK) == 0)
0129         rights |= PKEY_DISABLE_WRITE;
0130     else if ((rights & PKEY_BITS_MASK) == PKEY_DISABLE_WRITE)
0131         rights |= PKEY_DISABLE_ACCESS;
0132 
0133     return rights;
0134 }
0135 
0136 #endif /* _SELFTESTS_POWERPC_PKEYS_H */