1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Tests Memory Protection Keys (see Documentation/core-api/protection-keys.rst)
4  *
5  * The testcases in this file exercise various flows related to signal handling,
6  * using an alternate signal stack, with the default pkey (pkey 0) disabled.
7  *
8  * Compile with:
9  * gcc -mxsave      -o pkey_sighandler_tests -O2 -g -std=gnu99 -pthread -Wall pkey_sighandler_tests.c -I../../../../tools/include -lrt -ldl -lm
10  * gcc -mxsave -m32 -o pkey_sighandler_tests -O2 -g -std=gnu99 -pthread -Wall pkey_sighandler_tests.c -I../../../../tools/include -lrt -ldl -lm
11  */
12 #define _GNU_SOURCE
13 #define __SANE_USERSPACE_TYPES__
14 #include <linux/mman.h>
15 #include <errno.h>
16 #include <sys/syscall.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <stdint.h>
20 #include <stdbool.h>
21 #include <signal.h>
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <sys/mman.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <pthread.h>
29 #include <limits.h>
30 
31 #include "pkey-helpers.h"
32 
33 #define STACK_SIZE PTHREAD_STACK_MIN
34 
35 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
36 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
37 static siginfo_t siginfo = {0};
38 
39 /*
40  * We need to use inline assembly instead of glibc's syscall because glibc's
41  * syscall will attempt to access the PLT in order to call a library function
42  * which is protected by MPK 0 which we don't have access to.
43  */
44 static inline __always_inline
syscall_raw(long n,long a1,long a2,long a3,long a4,long a5,long a6)45 long syscall_raw(long n, long a1, long a2, long a3, long a4, long a5, long a6)
46 {
47 	unsigned long ret;
48 #ifdef __x86_64__
49 	register long r10 asm("r10") = a4;
50 	register long r8 asm("r8") = a5;
51 	register long r9 asm("r9") = a6;
52 	asm volatile ("syscall"
53 		      : "=a"(ret)
54 		      : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10), "r"(r8), "r"(r9)
55 		      : "rcx", "r11", "memory");
56 #elif defined __i386__
57 	asm volatile ("int $0x80"
58 		      : "=a"(ret)
59 		      : "a"(n), "b"(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5)
60 		      : "memory");
61 #elif defined __aarch64__
62 	register long x0 asm("x0") = a1;
63 	register long x1 asm("x1") = a2;
64 	register long x2 asm("x2") = a3;
65 	register long x3 asm("x3") = a4;
66 	register long x4 asm("x4") = a5;
67 	register long x5 asm("x5") = a6;
68 	register long x8 asm("x8") = n;
69 	asm volatile ("svc #0"
70 		      : "=r"(x0)
71 		      : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5), "r"(x8)
72 		      : "memory");
73 	ret = x0;
74 #else
75 # error syscall_raw() not implemented
76 #endif
77 	return ret;
78 }
79 
clone_raw(unsigned long flags,void * stack,int * parent_tid,int * child_tid)80 static inline long clone_raw(unsigned long flags, void *stack,
81 			     int *parent_tid, int *child_tid)
82 {
83 	long a1 = flags;
84 	long a2 = (long)stack;
85 	long a3 = (long)parent_tid;
86 #if defined(__x86_64__) || defined(__i386)
87 	long a4 = (long)child_tid;
88 	long a5 = 0;
89 #elif defined(__aarch64__)
90 	long a4 = 0;
91 	long a5 = (long)child_tid;
92 #else
93 # error clone_raw() not implemented
94 #endif
95 
96 	return syscall_raw(SYS_clone, a1, a2, a3, a4, a5, 0);
97 }
98 
99 /*
100  * Returns the most restrictive pkey register value that can be used by the
101  * tests.
102  */
pkey_reg_restrictive_default(void)103 static inline u64 pkey_reg_restrictive_default(void)
104 {
105 	/*
106 	 * Disallow everything except execution on pkey 0, so that each caller
107 	 * doesn't need to enable it explicitly (the selftest code runs with
108 	 * its code mapped with pkey 0).
109 	 */
110 	return set_pkey_bits(PKEY_REG_ALLOW_NONE, 0, PKEY_DISABLE_ACCESS);
111 }
112 
sigsegv_handler(int signo,siginfo_t * info,void * ucontext)113 static void sigsegv_handler(int signo, siginfo_t *info, void *ucontext)
114 {
115 	pthread_mutex_lock(&mutex);
116 
117 	memcpy(&siginfo, info, sizeof(siginfo_t));
118 
119 	pthread_cond_signal(&cond);
120 	pthread_mutex_unlock(&mutex);
121 
122 	syscall_raw(SYS_exit, 0, 0, 0, 0, 0, 0);
123 }
124 
sigusr1_handler(int signo,siginfo_t * info,void * ucontext)125 static void sigusr1_handler(int signo, siginfo_t *info, void *ucontext)
126 {
127 	pthread_mutex_lock(&mutex);
128 
129 	memcpy(&siginfo, info, sizeof(siginfo_t));
130 
131 	pthread_cond_signal(&cond);
132 	pthread_mutex_unlock(&mutex);
133 }
134 
sigusr2_handler(int signo,siginfo_t * info,void * ucontext)135 static void sigusr2_handler(int signo, siginfo_t *info, void *ucontext)
136 {
137 	/*
138 	 * pkru should be the init_pkru value which enabled MPK 0 so
139 	 * we can use library functions.
140 	 */
141 	printf("%s invoked.\n", __func__);
142 }
143 
raise_sigusr2(void)144 static void raise_sigusr2(void)
145 {
146 	pid_t tid = 0;
147 
148 	tid = syscall_raw(SYS_gettid, 0, 0, 0, 0, 0, 0);
149 
150 	syscall_raw(SYS_tkill, tid, SIGUSR2, 0, 0, 0, 0);
151 
152 	/*
153 	 * We should return from the signal handler here and be able to
154 	 * return to the interrupted thread.
155 	 */
156 }
157 
thread_segv_with_pkey0_disabled(void * ptr)158 static void *thread_segv_with_pkey0_disabled(void *ptr)
159 {
160 	/* Disable MPK 0 (and all others too) */
161 	__write_pkey_reg(pkey_reg_restrictive_default());
162 
163 	/* Segfault (with SEGV_MAPERR) */
164 	*(volatile int *)NULL = 1;
165 	return NULL;
166 }
167 
thread_segv_pkuerr_stack(void * ptr)168 static void *thread_segv_pkuerr_stack(void *ptr)
169 {
170 	/* Disable MPK 0 (and all others too) */
171 	__write_pkey_reg(pkey_reg_restrictive_default());
172 
173 	/* After we disable MPK 0, we can't access the stack to return */
174 	return NULL;
175 }
176 
thread_segv_maperr_ptr(void * ptr)177 static void *thread_segv_maperr_ptr(void *ptr)
178 {
179 	stack_t *stack = ptr;
180 	u64 pkey_reg;
181 
182 	/*
183 	 * Setup alternate signal stack, which should be pkey_mprotect()ed by
184 	 * MPK 0. The thread's stack cannot be used for signals because it is
185 	 * not accessible by the default init_pkru value of 0x55555554.
186 	 */
187 	syscall_raw(SYS_sigaltstack, (long)stack, 0, 0, 0, 0, 0);
188 
189 	/* Disable MPK 0.  Only MPK 1 is enabled. */
190 	pkey_reg = pkey_reg_restrictive_default();
191 	pkey_reg = set_pkey_bits(pkey_reg, 1, PKEY_UNRESTRICTED);
192 	__write_pkey_reg(pkey_reg);
193 
194 	/* Segfault */
195 	*(volatile int *)NULL = 1;
196 	syscall_raw(SYS_exit, 0, 0, 0, 0, 0, 0);
197 	return NULL;
198 }
199 
200 /*
201  * Verify that the sigsegv handler is invoked when pkey 0 is disabled.
202  * Note that the new thread stack and the alternate signal stack is
203  * protected by MPK 0.
204  */
test_sigsegv_handler_with_pkey0_disabled(void)205 static void test_sigsegv_handler_with_pkey0_disabled(void)
206 {
207 	struct sigaction sa;
208 	pthread_attr_t attr;
209 	pthread_t thr;
210 
211 	sa.sa_flags = SA_SIGINFO;
212 
213 	sa.sa_sigaction = sigsegv_handler;
214 	sigemptyset(&sa.sa_mask);
215 	if (sigaction(SIGSEGV, &sa, NULL) == -1) {
216 		perror("sigaction");
217 		exit(EXIT_FAILURE);
218 	}
219 
220 	memset(&siginfo, 0, sizeof(siginfo));
221 
222 	pthread_attr_init(&attr);
223 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
224 
225 	pthread_create(&thr, &attr, thread_segv_with_pkey0_disabled, NULL);
226 
227 	pthread_mutex_lock(&mutex);
228 	while (siginfo.si_signo == 0)
229 		pthread_cond_wait(&cond, &mutex);
230 	pthread_mutex_unlock(&mutex);
231 
232 	ksft_test_result(siginfo.si_signo == SIGSEGV &&
233 			 siginfo.si_code == SEGV_MAPERR &&
234 			 siginfo.si_addr == NULL,
235 			 "%s\n", __func__);
236 }
237 
238 /*
239  * Verify that the sigsegv handler is invoked when pkey 0 is disabled.
240  * Note that the new thread stack and the alternate signal stack is
241  * protected by MPK 0, which renders them inaccessible when MPK 0
242  * is disabled. So just the return from the thread should cause a
243  * segfault with SEGV_PKUERR.
244  */
test_sigsegv_handler_cannot_access_stack(void)245 static void test_sigsegv_handler_cannot_access_stack(void)
246 {
247 	struct sigaction sa;
248 	pthread_attr_t attr;
249 	pthread_t thr;
250 
251 	sa.sa_flags = SA_SIGINFO;
252 
253 	sa.sa_sigaction = sigsegv_handler;
254 	sigemptyset(&sa.sa_mask);
255 	if (sigaction(SIGSEGV, &sa, NULL) == -1) {
256 		perror("sigaction");
257 		exit(EXIT_FAILURE);
258 	}
259 
260 	memset(&siginfo, 0, sizeof(siginfo));
261 
262 	pthread_attr_init(&attr);
263 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
264 
265 	pthread_create(&thr, &attr, thread_segv_pkuerr_stack, NULL);
266 
267 	pthread_mutex_lock(&mutex);
268 	while (siginfo.si_signo == 0)
269 		pthread_cond_wait(&cond, &mutex);
270 	pthread_mutex_unlock(&mutex);
271 
272 	ksft_test_result(siginfo.si_signo == SIGSEGV &&
273 			 siginfo.si_code == SEGV_PKUERR,
274 			 "%s\n", __func__);
275 }
276 
277 /*
278  * Verify that the sigsegv handler that uses an alternate signal stack
279  * is correctly invoked for a thread which uses a non-zero MPK to protect
280  * its own stack, and disables all other MPKs (including 0).
281  */
test_sigsegv_handler_with_different_pkey_for_stack(void)282 static void test_sigsegv_handler_with_different_pkey_for_stack(void)
283 {
284 	struct sigaction sa;
285 	static stack_t sigstack;
286 	void *stack;
287 	int pkey;
288 	int parent_pid = 0;
289 	int child_pid = 0;
290 	u64 pkey_reg;
291 
292 	sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
293 
294 	sa.sa_sigaction = sigsegv_handler;
295 
296 	sigemptyset(&sa.sa_mask);
297 	if (sigaction(SIGSEGV, &sa, NULL) == -1) {
298 		perror("sigaction");
299 		exit(EXIT_FAILURE);
300 	}
301 
302 	stack = mmap(0, STACK_SIZE, PROT_READ | PROT_WRITE,
303 		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
304 
305 	assert(stack != MAP_FAILED);
306 
307 	/* Allow access to MPK 0 and MPK 1 */
308 	pkey_reg = pkey_reg_restrictive_default();
309 	pkey_reg = set_pkey_bits(pkey_reg, 0, PKEY_UNRESTRICTED);
310 	pkey_reg = set_pkey_bits(pkey_reg, 1, PKEY_UNRESTRICTED);
311 	__write_pkey_reg(pkey_reg);
312 
313 	/* Protect the new stack with MPK 1 */
314 	pkey = sys_pkey_alloc(0, 0);
315 	sys_mprotect_pkey(stack, STACK_SIZE, PROT_READ | PROT_WRITE, pkey);
316 
317 	/* Set up alternate signal stack that will use the default MPK */
318 	sigstack.ss_sp = mmap(0, STACK_SIZE, PROT_READ | PROT_WRITE,
319 			      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
320 	sigstack.ss_flags = 0;
321 	sigstack.ss_size = STACK_SIZE;
322 
323 	memset(&siginfo, 0, sizeof(siginfo));
324 
325 	/* Use clone to avoid newer glibcs using rseq on new threads */
326 	long ret = clone_raw(CLONE_VM | CLONE_FS | CLONE_FILES |
327 			     CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM |
328 			     CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID |
329 			     CLONE_DETACHED,
330 			     stack + STACK_SIZE,
331 			     &parent_pid,
332 			     &child_pid);
333 
334 	if (ret < 0) {
335 		errno = -ret;
336 		perror("clone");
337 	} else if (ret == 0) {
338 		thread_segv_maperr_ptr(&sigstack);
339 		syscall_raw(SYS_exit, 0, 0, 0, 0, 0, 0);
340 	}
341 
342 	pthread_mutex_lock(&mutex);
343 	while (siginfo.si_signo == 0)
344 		pthread_cond_wait(&cond, &mutex);
345 	pthread_mutex_unlock(&mutex);
346 
347 	ksft_test_result(siginfo.si_signo == SIGSEGV &&
348 			 siginfo.si_code == SEGV_MAPERR &&
349 			 siginfo.si_addr == NULL,
350 			 "%s\n", __func__);
351 }
352 
353 /*
354  * Verify that the PKRU value set by the application is correctly
355  * restored upon return from signal handling.
356  */
test_pkru_preserved_after_sigusr1(void)357 static void test_pkru_preserved_after_sigusr1(void)
358 {
359 	struct sigaction sa;
360 	u64 pkey_reg;
361 
362 	/* Allow access to MPK 0 and an arbitrary set of keys */
363 	pkey_reg = pkey_reg_restrictive_default();
364 	pkey_reg = set_pkey_bits(pkey_reg, 0, PKEY_UNRESTRICTED);
365 	pkey_reg = set_pkey_bits(pkey_reg, 3, PKEY_UNRESTRICTED);
366 	pkey_reg = set_pkey_bits(pkey_reg, 7, PKEY_UNRESTRICTED);
367 
368 	sa.sa_flags = SA_SIGINFO;
369 
370 	sa.sa_sigaction = sigusr1_handler;
371 	sigemptyset(&sa.sa_mask);
372 	if (sigaction(SIGUSR1, &sa, NULL) == -1) {
373 		perror("sigaction");
374 		exit(EXIT_FAILURE);
375 	}
376 
377 	memset(&siginfo, 0, sizeof(siginfo));
378 
379 	__write_pkey_reg(pkey_reg);
380 
381 	raise(SIGUSR1);
382 
383 	pthread_mutex_lock(&mutex);
384 	while (siginfo.si_signo == 0)
385 		pthread_cond_wait(&cond, &mutex);
386 	pthread_mutex_unlock(&mutex);
387 
388 	/* Ensure the pkru value is the same after returning from signal. */
389 	ksft_test_result(pkey_reg == __read_pkey_reg() &&
390 			 siginfo.si_signo == SIGUSR1,
391 			 "%s\n", __func__);
392 }
393 
thread_sigusr2_self(void * ptr)394 static noinline void *thread_sigusr2_self(void *ptr)
395 {
396 	/*
397 	 * A const char array like "Resuming after SIGUSR2" won't be stored on
398 	 * the stack and the code could access it via an offset from the program
399 	 * counter. This makes sure it's on the function's stack frame.
400 	 */
401 	char str[] = {'R', 'e', 's', 'u', 'm', 'i', 'n', 'g', ' ',
402 		'a', 'f', 't', 'e', 'r', ' ',
403 		'S', 'I', 'G', 'U', 'S', 'R', '2',
404 		'.', '.', '.', '\n', '\0'};
405 	stack_t *stack = ptr;
406 	u64 pkey_reg;
407 
408 	/*
409 	 * Setup alternate signal stack, which should be pkey_mprotect()ed by
410 	 * MPK 0. The thread's stack cannot be used for signals because it is
411 	 * not accessible by the default init_pkru value of 0x55555554.
412 	 */
413 	syscall(SYS_sigaltstack, (long)stack, 0, 0, 0, 0, 0);
414 
415 	/* Disable MPK 0.  Only MPK 2 is enabled. */
416 	pkey_reg = pkey_reg_restrictive_default();
417 	pkey_reg = set_pkey_bits(pkey_reg, 2, PKEY_UNRESTRICTED);
418 	__write_pkey_reg(pkey_reg);
419 
420 	raise_sigusr2();
421 
422 	/* Do something, to show the thread resumed execution after the signal */
423 	syscall_raw(SYS_write, 1, (long) str, sizeof(str) - 1, 0, 0, 0);
424 
425 	/*
426 	 * We can't return to test_pkru_sigreturn because it
427 	 * will attempt to use a %rbp value which is on the stack
428 	 * of the main thread.
429 	 */
430 	syscall_raw(SYS_exit, 0, 0, 0, 0, 0, 0);
431 	return NULL;
432 }
433 
434 /*
435  * Verify that sigreturn is able to restore altstack even if the thread had
436  * disabled pkey 0.
437  */
test_pkru_sigreturn(void)438 static void test_pkru_sigreturn(void)
439 {
440 	struct sigaction sa = {0};
441 	static stack_t sigstack;
442 	void *stack;
443 	int pkey;
444 	int parent_pid = 0;
445 	int child_pid = 0;
446 	u64 pkey_reg;
447 
448 	sa.sa_handler = SIG_DFL;
449 	sa.sa_flags = 0;
450 	sigemptyset(&sa.sa_mask);
451 
452 	/*
453 	 * For this testcase, we do not want to handle SIGSEGV. Reset handler
454 	 * to default so that the application can crash if it receives SIGSEGV.
455 	 */
456 	if (sigaction(SIGSEGV, &sa, NULL) == -1) {
457 		perror("sigaction");
458 		exit(EXIT_FAILURE);
459 	}
460 
461 	sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
462 	sa.sa_sigaction = sigusr2_handler;
463 	sigemptyset(&sa.sa_mask);
464 
465 	if (sigaction(SIGUSR2, &sa, NULL) == -1) {
466 		perror("sigaction");
467 		exit(EXIT_FAILURE);
468 	}
469 
470 	stack = mmap(0, STACK_SIZE, PROT_READ | PROT_WRITE,
471 		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
472 
473 	assert(stack != MAP_FAILED);
474 
475 	/*
476 	 * Allow access to MPK 0 and MPK 2. The child thread (to be created
477 	 * later in this flow) will have its stack protected by MPK 2, whereas
478 	 * the current thread's stack is protected by the default MPK 0. Hence
479 	 * both need to be enabled.
480 	 */
481 	pkey_reg = pkey_reg_restrictive_default();
482 	pkey_reg = set_pkey_bits(pkey_reg, 0, PKEY_UNRESTRICTED);
483 	pkey_reg = set_pkey_bits(pkey_reg, 2, PKEY_UNRESTRICTED);
484 	__write_pkey_reg(pkey_reg);
485 
486 	/* Protect the stack with MPK 2 */
487 	pkey = sys_pkey_alloc(0, 0);
488 	sys_mprotect_pkey(stack, STACK_SIZE, PROT_READ | PROT_WRITE, pkey);
489 
490 	/* Set up alternate signal stack that will use the default MPK */
491 	sigstack.ss_sp = mmap(0, STACK_SIZE, PROT_READ | PROT_WRITE,
492 			      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
493 	sigstack.ss_flags = 0;
494 	sigstack.ss_size = STACK_SIZE;
495 
496 	/* Use clone to avoid newer glibcs using rseq on new threads */
497 	long ret = clone_raw(CLONE_VM | CLONE_FS | CLONE_FILES |
498 			     CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM |
499 			     CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID |
500 			     CLONE_DETACHED,
501 			     stack + STACK_SIZE,
502 			     &parent_pid,
503 			     &child_pid);
504 
505 	if (ret < 0) {
506 		errno = -ret;
507 		perror("clone");
508 	}  else if (ret == 0) {
509 		thread_sigusr2_self(&sigstack);
510 		syscall_raw(SYS_exit, 0, 0, 0, 0, 0, 0);
511 	}
512 
513 	child_pid =  ret;
514 	/* Check that thread exited */
515 	do {
516 		sched_yield();
517 		ret = syscall_raw(SYS_tkill, child_pid, 0, 0, 0, 0, 0);
518 	} while (ret != -ESRCH && ret != -EINVAL);
519 
520 	ksft_test_result_pass("%s\n", __func__);
521 }
522 
523 static void (*pkey_tests[])(void) = {
524 	test_sigsegv_handler_with_pkey0_disabled,
525 	test_sigsegv_handler_cannot_access_stack,
526 	test_sigsegv_handler_with_different_pkey_for_stack,
527 	test_pkru_preserved_after_sigusr1,
528 	test_pkru_sigreturn
529 };
530 
main(int argc,char * argv[])531 int main(int argc, char *argv[])
532 {
533 	int i;
534 
535 	ksft_print_header();
536 	ksft_set_plan(ARRAY_SIZE(pkey_tests));
537 
538 	if (!is_pkeys_supported())
539 		ksft_exit_skip("pkeys not supported\n");
540 
541 	for (i = 0; i < ARRAY_SIZE(pkey_tests); i++)
542 		(*pkey_tests[i])();
543 
544 	ksft_finished();
545 	return 0;
546 }
547