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