brintos

brintos / linux-shallow public Read only

0
0
Text · 2.8 KiB · 51729d9 Raw
137 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2/*3 * Copyright 2020, Sandipan Das, IBM Corp.4 */5 6#ifndef _SELFTESTS_POWERPC_PKEYS_H7#define _SELFTESTS_POWERPC_PKEYS_H8 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_ACCESS19#define PKEY_DISABLE_ACCESS	0x320 21#undef PKEY_DISABLE_WRITE22#define PKEY_DISABLE_WRITE	0x223 24#undef PKEY_DISABLE_EXECUTE25#define PKEY_DISABLE_EXECUTE	0x426 27/* Older versions of libc do not define this */28#ifndef SEGV_PKUERR29#define SEGV_PKUERR	430#endif31 32#define SI_PKEY_OFFSET	0x2033 34#define __NR_pkey_mprotect	38635#define __NR_pkey_alloc		38436#define __NR_pkey_free		38537 38#define PKEY_BITS_PER_PKEY	239#define NR_PKEYS		3240#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 as99	 * a member.100	 */101#ifdef si_pkey102	return si->si_pkey;103#else104	return *((int *)(((char *) si) + SI_PKEY_OFFSET));105#endif106}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 */137