| 1 |
|
| 2 | |
| 3 | * Copyright 2020, Sandipan Das, IBM Corp.
|
| 4 |
|
| 5 |
|
| 6 | #ifndef _SELFTESTS_POWERPC_PKEYS_H
|
| 7 | #define _SELFTESTS_POWERPC_PKEYS_H
|
| 8 |
|
| 9 | #include <sys/mman.h>
|
| 10 |
|
| 11 | #include "reg.h"
|
| 12 | #include "utils.h"
|
| 13 |
|
| 14 | |
| 15 | * Older versions of libc use the Intel-specific access rights.
|
| 16 | * Hence, override the definitions as they might be incorrect.
|
| 17 |
|
| 18 | #undef PKEY_DISABLE_ACCESS
|
| 19 | #define PKEY_DISABLE_ACCESS 0x3
|
| 20 |
|
| 21 | #undef PKEY_DISABLE_WRITE
|
| 22 | #define PKEY_DISABLE_WRITE 0x2
|
| 23 |
|
| 24 | #undef PKEY_DISABLE_EXECUTE
|
| 25 | #define PKEY_DISABLE_EXECUTE 0x4
|
| 26 |
|
| 27 | #undef PKEY_UNRESTRICTED
|
| 28 | #define PKEY_UNRESTRICTED 0x0
|
| 29 |
|
| 30 |
|
| 31 | #ifndef SEGV_PKUERR
|
| 32 | #define SEGV_PKUERR 4
|
| 33 | #endif
|
| 34 |
|
| 35 | #define SI_PKEY_OFFSET 0x20
|
| 36 |
|
| 37 | #define __NR_pkey_mprotect 386
|
| 38 | #define __NR_pkey_alloc 384
|
| 39 | #define __NR_pkey_free 385
|
| 40 |
|
| 41 | #ifndef NT_PPC_PKEY
|
| 42 | #define NT_PPC_PKEY 0x110
|
| 43 | #endif
|
| 44 |
|
| 45 | #define PKEY_BITS_PER_PKEY 2
|
| 46 | #define NR_PKEYS 32
|
| 47 | #define PKEY_BITS_MASK ((1UL << PKEY_BITS_PER_PKEY) - 1)
|
| 48 |
|
| 49 | #define AMR_BITS_PER_PKEY 2
|
| 50 | #define PKEY_REG_BITS (sizeof(u64) * 8)
|
| 51 | #define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey + 1) * AMR_BITS_PER_PKEY))
|
| 52 |
|
| 53 | inline unsigned long pkeyreg_get(void)
|
| 54 | {
|
| 55 | return mfspr(SPRN_AMR);
|
| 56 | }
|
| 57 |
|
| 58 | inline void pkeyreg_set(unsigned long amr)
|
| 59 | {
|
| 60 | set_amr(amr);
|
| 61 | }
|
| 62 |
|
| 63 | void pkey_set_rights(int pkey, unsigned long rights)
|
| 64 | {
|
| 65 | unsigned long amr, shift;
|
| 66 |
|
| 67 | shift = (NR_PKEYS - pkey - 1) * PKEY_BITS_PER_PKEY;
|
| 68 | amr = pkeyreg_get();
|
| 69 | amr &= ~(PKEY_BITS_MASK << shift);
|
| 70 | amr |= (rights & PKEY_BITS_MASK) << shift;
|
| 71 | pkeyreg_set(amr);
|
| 72 | }
|
| 73 |
|
| 74 | int sys_pkey_mprotect(void *addr, size_t len, int prot, int pkey)
|
| 75 | {
|
| 76 | return syscall(__NR_pkey_mprotect, addr, len, prot, pkey);
|
| 77 | }
|
| 78 |
|
| 79 | int sys_pkey_alloc(unsigned long flags, unsigned long rights)
|
| 80 | {
|
| 81 | return syscall(__NR_pkey_alloc, flags, rights);
|
| 82 | }
|
| 83 |
|
| 84 | int sys_pkey_free(int pkey)
|
| 85 | {
|
| 86 | return syscall(__NR_pkey_free, pkey);
|
| 87 | }
|
| 88 |
|
| 89 | int pkeys_unsupported(void)
|
| 90 | {
|
| 91 | bool hash_mmu = false;
|
| 92 | int pkey;
|
| 93 |
|
| 94 |
|
| 95 | FAIL_IF(using_hash_mmu(&hash_mmu));
|
| 96 | SKIP_IF(!hash_mmu);
|
| 97 |
|
| 98 |
|
| 99 | pkey = sys_pkey_alloc(0, PKEY_UNRESTRICTED);
|
| 100 | SKIP_IF(pkey < 0);
|
| 101 | sys_pkey_free(pkey);
|
| 102 |
|
| 103 | return 0;
|
| 104 | }
|
| 105 |
|
| 106 | int siginfo_pkey(siginfo_t *si)
|
| 107 | {
|
| 108 | |
| 109 | * In older versions of libc, siginfo_t does not have si_pkey as
|
| 110 | * a member.
|
| 111 |
|
| 112 | #ifdef si_pkey
|
| 113 | return si->si_pkey;
|
| 114 | #else
|
| 115 | return *((int *)(((char *) si) + SI_PKEY_OFFSET));
|
| 116 | #endif
|
| 117 | }
|
| 118 |
|
| 119 | #define pkey_rights(r) ({ \
|
| 120 | static char buf[4] = "rwx"; \
|
| 121 | unsigned int amr_bits; \
|
| 122 | if ((r) & PKEY_DISABLE_EXECUTE) \
|
| 123 | buf[2] = '-'; \
|
| 124 | amr_bits = (r) & PKEY_BITS_MASK; \
|
| 125 | if (amr_bits & PKEY_DISABLE_WRITE) \
|
| 126 | buf[1] = '-'; \
|
| 127 | if (amr_bits & PKEY_DISABLE_ACCESS & ~PKEY_DISABLE_WRITE) \
|
| 128 | buf[0] = '-'; \
|
| 129 | buf; \
|
| 130 | })
|
| 131 |
|
| 132 | unsigned long next_pkey_rights(unsigned long rights)
|
| 133 | {
|
| 134 | if (rights == PKEY_DISABLE_ACCESS)
|
| 135 | return PKEY_DISABLE_EXECUTE;
|
| 136 | else if (rights == (PKEY_DISABLE_ACCESS | PKEY_DISABLE_EXECUTE))
|
| 137 | return 0;
|
| 138 |
|
| 139 | if ((rights & PKEY_BITS_MASK) == 0)
|
| 140 | rights |= PKEY_DISABLE_WRITE;
|
| 141 | else if ((rights & PKEY_BITS_MASK) == PKEY_DISABLE_WRITE)
|
| 142 | rights |= PKEY_DISABLE_ACCESS;
|
| 143 |
|
| 144 | return rights;
|
| 145 | }
|
| 146 |
|
| 147 | #endif
|