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 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 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 */ 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 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 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