pkeys.h (2912B)
1/* SPDX-License-Identifier: GPL-2.0 */ 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/* Older versions of libc do not not define this */ 28#ifndef SEGV_PKUERR 29#define SEGV_PKUERR 4 30#endif 31 32#define SI_PKEY_OFFSET 0x20 33 34#define __NR_pkey_mprotect 386 35#define __NR_pkey_alloc 384 36#define __NR_pkey_free 385 37 38#define PKEY_BITS_PER_PKEY 2 39#define NR_PKEYS 32 40#define PKEY_BITS_MASK ((1UL << PKEY_BITS_PER_PKEY) - 1) 41 42inline unsigned long pkeyreg_get(void) 43{ 44 return mfspr(SPRN_AMR); 45} 46 47inline void pkeyreg_set(unsigned long amr) 48{ 49 set_amr(amr); 50} 51 52void pkey_set_rights(int pkey, unsigned long rights) 53{ 54 unsigned long amr, shift; 55 56 shift = (NR_PKEYS - pkey - 1) * PKEY_BITS_PER_PKEY; 57 amr = pkeyreg_get(); 58 amr &= ~(PKEY_BITS_MASK << shift); 59 amr |= (rights & PKEY_BITS_MASK) << shift; 60 pkeyreg_set(amr); 61} 62 63int sys_pkey_mprotect(void *addr, size_t len, int prot, int pkey) 64{ 65 return syscall(__NR_pkey_mprotect, addr, len, prot, pkey); 66} 67 68int sys_pkey_alloc(unsigned long flags, unsigned long rights) 69{ 70 return syscall(__NR_pkey_alloc, flags, rights); 71} 72 73int sys_pkey_free(int pkey) 74{ 75 return syscall(__NR_pkey_free, pkey); 76} 77 78int pkeys_unsupported(void) 79{ 80 bool hash_mmu = false; 81 int pkey; 82 83 /* Protection keys are currently supported on Hash MMU only */ 84 FAIL_IF(using_hash_mmu(&hash_mmu)); 85 SKIP_IF(!hash_mmu); 86 87 /* Check if the system call is supported */ 88 pkey = sys_pkey_alloc(0, 0); 89 SKIP_IF(pkey < 0); 90 sys_pkey_free(pkey); 91 92 return 0; 93} 94 95int siginfo_pkey(siginfo_t *si) 96{ 97 /* 98 * In older versions of libc, siginfo_t does not have si_pkey as 99 * a member. 100 */ 101#ifdef si_pkey 102 return si->si_pkey; 103#else 104 return *((int *)(((char *) si) + SI_PKEY_OFFSET)); 105#endif 106} 107 108#define pkey_rights(r) ({ \ 109 static char buf[4] = "rwx"; \ 110 unsigned int amr_bits; \ 111 if ((r) & PKEY_DISABLE_EXECUTE) \ 112 buf[2] = '-'; \ 113 amr_bits = (r) & PKEY_BITS_MASK; \ 114 if (amr_bits & PKEY_DISABLE_WRITE) \ 115 buf[1] = '-'; \ 116 if (amr_bits & PKEY_DISABLE_ACCESS & ~PKEY_DISABLE_WRITE) \ 117 buf[0] = '-'; \ 118 buf; \ 119}) 120 121unsigned long next_pkey_rights(unsigned long rights) 122{ 123 if (rights == PKEY_DISABLE_ACCESS) 124 return PKEY_DISABLE_EXECUTE; 125 else if (rights == (PKEY_DISABLE_ACCESS | PKEY_DISABLE_EXECUTE)) 126 return 0; 127 128 if ((rights & PKEY_BITS_MASK) == 0) 129 rights |= PKEY_DISABLE_WRITE; 130 else if ((rights & PKEY_BITS_MASK) == PKEY_DISABLE_WRITE) 131 rights |= PKEY_DISABLE_ACCESS; 132 133 return rights; 134} 135 136#endif /* _SELFTESTS_POWERPC_PKEYS_H */