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