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