1*baa489faSSeongJae Park /* SPDX-License-Identifier: GPL-2.0 */
2*baa489faSSeongJae Park #ifndef _PKEYS_HELPER_H
3*baa489faSSeongJae Park #define _PKEYS_HELPER_H
4*baa489faSSeongJae Park #define _GNU_SOURCE
5*baa489faSSeongJae Park #include <string.h>
6*baa489faSSeongJae Park #include <stdarg.h>
7*baa489faSSeongJae Park #include <stdio.h>
8*baa489faSSeongJae Park #include <stdint.h>
9*baa489faSSeongJae Park #include <stdbool.h>
10*baa489faSSeongJae Park #include <signal.h>
11*baa489faSSeongJae Park #include <assert.h>
12*baa489faSSeongJae Park #include <stdlib.h>
13*baa489faSSeongJae Park #include <ucontext.h>
14*baa489faSSeongJae Park #include <sys/mman.h>
15*baa489faSSeongJae Park 
16*baa489faSSeongJae Park #include "../kselftest.h"
17*baa489faSSeongJae Park 
18*baa489faSSeongJae Park /* Define some kernel-like types */
19*baa489faSSeongJae Park #define  u8 __u8
20*baa489faSSeongJae Park #define u16 __u16
21*baa489faSSeongJae Park #define u32 __u32
22*baa489faSSeongJae Park #define u64 __u64
23*baa489faSSeongJae Park 
24*baa489faSSeongJae Park #define PTR_ERR_ENOTSUP ((void *)-ENOTSUP)
25*baa489faSSeongJae Park 
26*baa489faSSeongJae Park #ifndef DEBUG_LEVEL
27*baa489faSSeongJae Park #define DEBUG_LEVEL 0
28*baa489faSSeongJae Park #endif
29*baa489faSSeongJae Park #define DPRINT_IN_SIGNAL_BUF_SIZE 4096
30*baa489faSSeongJae Park extern int dprint_in_signal;
31*baa489faSSeongJae Park extern char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
32*baa489faSSeongJae Park 
33*baa489faSSeongJae Park extern int test_nr;
34*baa489faSSeongJae Park extern int iteration_nr;
35*baa489faSSeongJae Park 
36*baa489faSSeongJae Park #ifdef __GNUC__
37*baa489faSSeongJae Park __attribute__((format(printf, 1, 2)))
38*baa489faSSeongJae Park #endif
sigsafe_printf(const char * format,...)39*baa489faSSeongJae Park static inline void sigsafe_printf(const char *format, ...)
40*baa489faSSeongJae Park {
41*baa489faSSeongJae Park 	va_list ap;
42*baa489faSSeongJae Park 
43*baa489faSSeongJae Park 	if (!dprint_in_signal) {
44*baa489faSSeongJae Park 		va_start(ap, format);
45*baa489faSSeongJae Park 		vprintf(format, ap);
46*baa489faSSeongJae Park 		va_end(ap);
47*baa489faSSeongJae Park 	} else {
48*baa489faSSeongJae Park 		int ret;
49*baa489faSSeongJae Park 		/*
50*baa489faSSeongJae Park 		 * No printf() functions are signal-safe.
51*baa489faSSeongJae Park 		 * They deadlock easily. Write the format
52*baa489faSSeongJae Park 		 * string to get some output, even if
53*baa489faSSeongJae Park 		 * incomplete.
54*baa489faSSeongJae Park 		 */
55*baa489faSSeongJae Park 		ret = write(1, format, strlen(format));
56*baa489faSSeongJae Park 		if (ret < 0)
57*baa489faSSeongJae Park 			exit(1);
58*baa489faSSeongJae Park 	}
59*baa489faSSeongJae Park }
60*baa489faSSeongJae Park #define dprintf_level(level, args...) do {	\
61*baa489faSSeongJae Park 	if (level <= DEBUG_LEVEL)		\
62*baa489faSSeongJae Park 		sigsafe_printf(args);		\
63*baa489faSSeongJae Park } while (0)
64*baa489faSSeongJae Park #define dprintf0(args...) dprintf_level(0, args)
65*baa489faSSeongJae Park #define dprintf1(args...) dprintf_level(1, args)
66*baa489faSSeongJae Park #define dprintf2(args...) dprintf_level(2, args)
67*baa489faSSeongJae Park #define dprintf3(args...) dprintf_level(3, args)
68*baa489faSSeongJae Park #define dprintf4(args...) dprintf_level(4, args)
69*baa489faSSeongJae Park 
70*baa489faSSeongJae Park extern void abort_hooks(void);
71*baa489faSSeongJae Park #define pkey_assert(condition) do {		\
72*baa489faSSeongJae Park 	if (!(condition)) {			\
73*baa489faSSeongJae Park 		dprintf0("assert() at %s::%d test_nr: %d iteration: %d\n", \
74*baa489faSSeongJae Park 				__FILE__, __LINE__,	\
75*baa489faSSeongJae Park 				test_nr, iteration_nr);	\
76*baa489faSSeongJae Park 		dprintf0("errno at assert: %d", errno);	\
77*baa489faSSeongJae Park 		abort_hooks();			\
78*baa489faSSeongJae Park 		exit(__LINE__);			\
79*baa489faSSeongJae Park 	}					\
80*baa489faSSeongJae Park } while (0)
81*baa489faSSeongJae Park 
82*baa489faSSeongJae Park __attribute__((noinline)) int read_ptr(int *ptr);
83*baa489faSSeongJae Park void expected_pkey_fault(int pkey);
84*baa489faSSeongJae Park int sys_pkey_alloc(unsigned long flags, unsigned long init_val);
85*baa489faSSeongJae Park int sys_pkey_free(unsigned long pkey);
86*baa489faSSeongJae Park int mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
87*baa489faSSeongJae Park 		unsigned long pkey);
88*baa489faSSeongJae Park void record_pkey_malloc(void *ptr, long size, int prot);
89*baa489faSSeongJae Park 
90*baa489faSSeongJae Park #if defined(__i386__) || defined(__x86_64__) /* arch */
91*baa489faSSeongJae Park #include "pkey-x86.h"
92*baa489faSSeongJae Park #elif defined(__powerpc64__) /* arch */
93*baa489faSSeongJae Park #include "pkey-powerpc.h"
94*baa489faSSeongJae Park #else /* arch */
95*baa489faSSeongJae Park #error Architecture not supported
96*baa489faSSeongJae Park #endif /* arch */
97*baa489faSSeongJae Park 
98*baa489faSSeongJae Park #define PKEY_MASK	(PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)
99*baa489faSSeongJae Park 
set_pkey_bits(u64 reg,int pkey,u64 flags)100*baa489faSSeongJae Park static inline u64 set_pkey_bits(u64 reg, int pkey, u64 flags)
101*baa489faSSeongJae Park {
102*baa489faSSeongJae Park 	u32 shift = pkey_bit_position(pkey);
103*baa489faSSeongJae Park 	/* mask out bits from pkey in old value */
104*baa489faSSeongJae Park 	reg &= ~((u64)PKEY_MASK << shift);
105*baa489faSSeongJae Park 	/* OR in new bits for pkey */
106*baa489faSSeongJae Park 	reg |= (flags & PKEY_MASK) << shift;
107*baa489faSSeongJae Park 	return reg;
108*baa489faSSeongJae Park }
109*baa489faSSeongJae Park 
get_pkey_bits(u64 reg,int pkey)110*baa489faSSeongJae Park static inline u64 get_pkey_bits(u64 reg, int pkey)
111*baa489faSSeongJae Park {
112*baa489faSSeongJae Park 	u32 shift = pkey_bit_position(pkey);
113*baa489faSSeongJae Park 	/*
114*baa489faSSeongJae Park 	 * shift down the relevant bits to the lowest two, then
115*baa489faSSeongJae Park 	 * mask off all the other higher bits
116*baa489faSSeongJae Park 	 */
117*baa489faSSeongJae Park 	return ((reg >> shift) & PKEY_MASK);
118*baa489faSSeongJae Park }
119*baa489faSSeongJae Park 
120*baa489faSSeongJae Park extern u64 shadow_pkey_reg;
121*baa489faSSeongJae Park 
_read_pkey_reg(int line)122*baa489faSSeongJae Park static inline u64 _read_pkey_reg(int line)
123*baa489faSSeongJae Park {
124*baa489faSSeongJae Park 	u64 pkey_reg = __read_pkey_reg();
125*baa489faSSeongJae Park 
126*baa489faSSeongJae Park 	dprintf4("read_pkey_reg(line=%d) pkey_reg: %016llx"
127*baa489faSSeongJae Park 			" shadow: %016llx\n",
128*baa489faSSeongJae Park 			line, pkey_reg, shadow_pkey_reg);
129*baa489faSSeongJae Park 	assert(pkey_reg == shadow_pkey_reg);
130*baa489faSSeongJae Park 
131*baa489faSSeongJae Park 	return pkey_reg;
132*baa489faSSeongJae Park }
133*baa489faSSeongJae Park 
134*baa489faSSeongJae Park #define read_pkey_reg() _read_pkey_reg(__LINE__)
135*baa489faSSeongJae Park 
write_pkey_reg(u64 pkey_reg)136*baa489faSSeongJae Park static inline void write_pkey_reg(u64 pkey_reg)
137*baa489faSSeongJae Park {
138*baa489faSSeongJae Park 	dprintf4("%s() changing %016llx to %016llx\n", __func__,
139*baa489faSSeongJae Park 			__read_pkey_reg(), pkey_reg);
140*baa489faSSeongJae Park 	/* will do the shadow check for us: */
141*baa489faSSeongJae Park 	read_pkey_reg();
142*baa489faSSeongJae Park 	__write_pkey_reg(pkey_reg);
143*baa489faSSeongJae Park 	shadow_pkey_reg = pkey_reg;
144*baa489faSSeongJae Park 	dprintf4("%s(%016llx) pkey_reg: %016llx\n", __func__,
145*baa489faSSeongJae Park 			pkey_reg, __read_pkey_reg());
146*baa489faSSeongJae Park }
147*baa489faSSeongJae Park 
148*baa489faSSeongJae Park /*
149*baa489faSSeongJae Park  * These are technically racy. since something could
150*baa489faSSeongJae Park  * change PKEY register between the read and the write.
151*baa489faSSeongJae Park  */
__pkey_access_allow(int pkey,int do_allow)152*baa489faSSeongJae Park static inline void __pkey_access_allow(int pkey, int do_allow)
153*baa489faSSeongJae Park {
154*baa489faSSeongJae Park 	u64 pkey_reg = read_pkey_reg();
155*baa489faSSeongJae Park 	int bit = pkey * 2;
156*baa489faSSeongJae Park 
157*baa489faSSeongJae Park 	if (do_allow)
158*baa489faSSeongJae Park 		pkey_reg &= (1<<bit);
159*baa489faSSeongJae Park 	else
160*baa489faSSeongJae Park 		pkey_reg |= (1<<bit);
161*baa489faSSeongJae Park 
162*baa489faSSeongJae Park 	dprintf4("pkey_reg now: %016llx\n", read_pkey_reg());
163*baa489faSSeongJae Park 	write_pkey_reg(pkey_reg);
164*baa489faSSeongJae Park }
165*baa489faSSeongJae Park 
__pkey_write_allow(int pkey,int do_allow_write)166*baa489faSSeongJae Park static inline void __pkey_write_allow(int pkey, int do_allow_write)
167*baa489faSSeongJae Park {
168*baa489faSSeongJae Park 	u64 pkey_reg = read_pkey_reg();
169*baa489faSSeongJae Park 	int bit = pkey * 2 + 1;
170*baa489faSSeongJae Park 
171*baa489faSSeongJae Park 	if (do_allow_write)
172*baa489faSSeongJae Park 		pkey_reg &= (1<<bit);
173*baa489faSSeongJae Park 	else
174*baa489faSSeongJae Park 		pkey_reg |= (1<<bit);
175*baa489faSSeongJae Park 
176*baa489faSSeongJae Park 	write_pkey_reg(pkey_reg);
177*baa489faSSeongJae Park 	dprintf4("pkey_reg now: %016llx\n", read_pkey_reg());
178*baa489faSSeongJae Park }
179*baa489faSSeongJae Park 
180*baa489faSSeongJae Park #define ALIGN_UP(x, align_to)	(((x) + ((align_to)-1)) & ~((align_to)-1))
181*baa489faSSeongJae Park #define ALIGN_DOWN(x, align_to) ((x) & ~((align_to)-1))
182*baa489faSSeongJae Park #define ALIGN_PTR_UP(p, ptr_align_to)	\
183*baa489faSSeongJae Park 	((typeof(p))ALIGN_UP((unsigned long)(p), ptr_align_to))
184*baa489faSSeongJae Park #define ALIGN_PTR_DOWN(p, ptr_align_to)	\
185*baa489faSSeongJae Park 	((typeof(p))ALIGN_DOWN((unsigned long)(p), ptr_align_to))
186*baa489faSSeongJae Park #define __stringify_1(x...)     #x
187*baa489faSSeongJae Park #define __stringify(x...)       __stringify_1(x)
188*baa489faSSeongJae Park 
siginfo_get_pkey_ptr(siginfo_t * si)189*baa489faSSeongJae Park static inline u32 *siginfo_get_pkey_ptr(siginfo_t *si)
190*baa489faSSeongJae Park {
191*baa489faSSeongJae Park #ifdef si_pkey
192*baa489faSSeongJae Park 	return &si->si_pkey;
193*baa489faSSeongJae Park #else
194*baa489faSSeongJae Park 	return (u32 *)(((u8 *)si) + si_pkey_offset);
195*baa489faSSeongJae Park #endif
196*baa489faSSeongJae Park }
197*baa489faSSeongJae Park 
kernel_has_pkeys(void)198*baa489faSSeongJae Park static inline int kernel_has_pkeys(void)
199*baa489faSSeongJae Park {
200*baa489faSSeongJae Park 	/* try allocating a key and see if it succeeds */
201*baa489faSSeongJae Park 	int ret = sys_pkey_alloc(0, 0);
202*baa489faSSeongJae Park 	if (ret <= 0) {
203*baa489faSSeongJae Park 		return 0;
204*baa489faSSeongJae Park 	}
205*baa489faSSeongJae Park 	sys_pkey_free(ret);
206*baa489faSSeongJae Park 	return 1;
207*baa489faSSeongJae Park }
208*baa489faSSeongJae Park 
is_pkeys_supported(void)209*baa489faSSeongJae Park static inline int is_pkeys_supported(void)
210*baa489faSSeongJae Park {
211*baa489faSSeongJae Park 	/* check if the cpu supports pkeys */
212*baa489faSSeongJae Park 	if (!cpu_has_pkeys()) {
213*baa489faSSeongJae Park 		dprintf1("SKIP: %s: no CPU support\n", __func__);
214*baa489faSSeongJae Park 		return 0;
215*baa489faSSeongJae Park 	}
216*baa489faSSeongJae Park 
217*baa489faSSeongJae Park 	/* check if the kernel supports pkeys */
218*baa489faSSeongJae Park 	if (!kernel_has_pkeys()) {
219*baa489faSSeongJae Park 		dprintf1("SKIP: %s: no kernel support\n", __func__);
220*baa489faSSeongJae Park 		return 0;
221*baa489faSSeongJae Park 	}
222*baa489faSSeongJae Park 
223*baa489faSSeongJae Park 	return 1;
224*baa489faSSeongJae Park }
225*baa489faSSeongJae Park 
226*baa489faSSeongJae Park #endif /* _PKEYS_HELPER_H */
227