1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Landlock tests - Signal Scoping 4 * 5 * Copyright © 2024 Tahera Fahimi <fahimitahera@gmail.com> 6 */ 7 8 #define _GNU_SOURCE 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <linux/landlock.h> 12 #include <pthread.h> 13 #include <signal.h> 14 #include <sys/prctl.h> 15 #include <sys/types.h> 16 #include <sys/wait.h> 17 #include <unistd.h> 18 19 #include "common.h" 20 #include "scoped_common.h" 21 22 /* This variable is used for handling several signals. */ 23 static volatile sig_atomic_t is_signaled; 24 25 /* clang-format off */ 26 FIXTURE(scoping_signals) {}; 27 /* clang-format on */ 28 29 FIXTURE_VARIANT(scoping_signals) 30 { 31 int sig; 32 }; 33 34 /* clang-format off */ 35 FIXTURE_VARIANT_ADD(scoping_signals, sigtrap) { 36 /* clang-format on */ 37 .sig = SIGTRAP, 38 }; 39 40 /* clang-format off */ 41 FIXTURE_VARIANT_ADD(scoping_signals, sigurg) { 42 /* clang-format on */ 43 .sig = SIGURG, 44 }; 45 46 /* clang-format off */ 47 FIXTURE_VARIANT_ADD(scoping_signals, sighup) { 48 /* clang-format on */ 49 .sig = SIGHUP, 50 }; 51 52 /* clang-format off */ 53 FIXTURE_VARIANT_ADD(scoping_signals, sigtstp) { 54 /* clang-format on */ 55 .sig = SIGTSTP, 56 }; 57 58 FIXTURE_SETUP(scoping_signals) 59 { 60 drop_caps(_metadata); 61 62 is_signaled = 0; 63 } 64 65 FIXTURE_TEARDOWN(scoping_signals) 66 { 67 } 68 69 static void scope_signal_handler(int sig, siginfo_t *info, void *ucontext) 70 { 71 if (sig == SIGTRAP || sig == SIGURG || sig == SIGHUP || sig == SIGTSTP) 72 is_signaled = 1; 73 } 74 75 /* 76 * In this test, a child process sends a signal to parent before and 77 * after getting scoped. 78 */ 79 TEST_F(scoping_signals, send_sig_to_parent) 80 { 81 int pipe_parent[2]; 82 int status; 83 pid_t child; 84 pid_t parent = getpid(); 85 struct sigaction action = { 86 .sa_sigaction = scope_signal_handler, 87 .sa_flags = SA_SIGINFO, 88 89 }; 90 91 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC)); 92 ASSERT_LE(0, sigaction(variant->sig, &action, NULL)); 93 94 /* The process should not have already been signaled. */ 95 EXPECT_EQ(0, is_signaled); 96 97 child = fork(); 98 ASSERT_LE(0, child); 99 if (child == 0) { 100 char buf_child; 101 int err; 102 103 EXPECT_EQ(0, close(pipe_parent[1])); 104 105 /* 106 * The child process can send signal to parent when 107 * domain is not scoped. 108 */ 109 err = kill(parent, variant->sig); 110 ASSERT_EQ(0, err); 111 ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1)); 112 EXPECT_EQ(0, close(pipe_parent[0])); 113 114 create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL); 115 116 /* 117 * The child process cannot send signal to the parent 118 * anymore. 119 */ 120 err = kill(parent, variant->sig); 121 ASSERT_EQ(-1, err); 122 ASSERT_EQ(EPERM, errno); 123 124 /* 125 * No matter of the domain, a process should be able to 126 * send a signal to itself. 127 */ 128 ASSERT_EQ(0, is_signaled); 129 ASSERT_EQ(0, raise(variant->sig)); 130 ASSERT_EQ(1, is_signaled); 131 132 _exit(_metadata->exit_code); 133 return; 134 } 135 EXPECT_EQ(0, close(pipe_parent[0])); 136 137 /* Waits for a first signal to be received, without race condition. */ 138 while (!is_signaled && !usleep(1)) 139 ; 140 ASSERT_EQ(1, is_signaled); 141 ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); 142 EXPECT_EQ(0, close(pipe_parent[1])); 143 is_signaled = 0; 144 145 ASSERT_EQ(child, waitpid(child, &status, 0)); 146 if (WIFSIGNALED(status) || !WIFEXITED(status) || 147 WEXITSTATUS(status) != EXIT_SUCCESS) 148 _metadata->exit_code = KSFT_FAIL; 149 150 EXPECT_EQ(0, is_signaled); 151 } 152 153 /* clang-format off */ 154 FIXTURE(scoped_domains) {}; 155 /* clang-format on */ 156 157 #include "scoped_base_variants.h" 158 159 FIXTURE_SETUP(scoped_domains) 160 { 161 drop_caps(_metadata); 162 } 163 164 FIXTURE_TEARDOWN(scoped_domains) 165 { 166 } 167 168 /* 169 * This test ensures that a scoped process cannot send signal out of 170 * scoped domain. 171 */ 172 TEST_F(scoped_domains, check_access_signal) 173 { 174 pid_t child; 175 pid_t parent = getpid(); 176 int status; 177 bool can_signal_child, can_signal_parent; 178 int pipe_parent[2], pipe_child[2]; 179 char buf_parent; 180 int err; 181 182 can_signal_parent = !variant->domain_child; 183 can_signal_child = !variant->domain_parent; 184 185 if (variant->domain_both) 186 create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL); 187 188 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC)); 189 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC)); 190 191 child = fork(); 192 ASSERT_LE(0, child); 193 if (child == 0) { 194 char buf_child; 195 196 EXPECT_EQ(0, close(pipe_child[0])); 197 EXPECT_EQ(0, close(pipe_parent[1])); 198 199 if (variant->domain_child) 200 create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL); 201 202 ASSERT_EQ(1, write(pipe_child[1], ".", 1)); 203 EXPECT_EQ(0, close(pipe_child[1])); 204 205 /* Waits for the parent to send signals. */ 206 ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1)); 207 EXPECT_EQ(0, close(pipe_parent[0])); 208 209 err = kill(parent, 0); 210 if (can_signal_parent) { 211 ASSERT_EQ(0, err); 212 } else { 213 ASSERT_EQ(-1, err); 214 ASSERT_EQ(EPERM, errno); 215 } 216 /* 217 * No matter of the domain, a process should be able to 218 * send a signal to itself. 219 */ 220 ASSERT_EQ(0, raise(0)); 221 222 _exit(_metadata->exit_code); 223 return; 224 } 225 EXPECT_EQ(0, close(pipe_parent[0])); 226 EXPECT_EQ(0, close(pipe_child[1])); 227 228 if (variant->domain_parent) 229 create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL); 230 231 ASSERT_EQ(1, read(pipe_child[0], &buf_parent, 1)); 232 EXPECT_EQ(0, close(pipe_child[0])); 233 234 err = kill(child, 0); 235 if (can_signal_child) { 236 ASSERT_EQ(0, err); 237 } else { 238 ASSERT_EQ(-1, err); 239 ASSERT_EQ(EPERM, errno); 240 } 241 ASSERT_EQ(0, raise(0)); 242 243 ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); 244 EXPECT_EQ(0, close(pipe_parent[1])); 245 ASSERT_EQ(child, waitpid(child, &status, 0)); 246 247 if (WIFSIGNALED(status) || !WIFEXITED(status) || 248 WEXITSTATUS(status) != EXIT_SUCCESS) 249 _metadata->exit_code = KSFT_FAIL; 250 } 251 252 enum thread_return { 253 THREAD_INVALID = 0, 254 THREAD_SUCCESS = 1, 255 THREAD_ERROR = 2, 256 THREAD_TEST_FAILED = 3, 257 }; 258 259 static void *thread_sync(void *arg) 260 { 261 const int pipe_read = *(int *)arg; 262 char buf; 263 264 if (read(pipe_read, &buf, 1) != 1) 265 return (void *)THREAD_ERROR; 266 267 return (void *)THREAD_SUCCESS; 268 } 269 270 TEST(signal_scoping_thread_before) 271 { 272 pthread_t no_sandbox_thread; 273 enum thread_return ret = THREAD_INVALID; 274 int thread_pipe[2]; 275 276 drop_caps(_metadata); 277 ASSERT_EQ(0, pipe2(thread_pipe, O_CLOEXEC)); 278 279 ASSERT_EQ(0, pthread_create(&no_sandbox_thread, NULL, thread_sync, 280 &thread_pipe[0])); 281 282 /* Enforces restriction after creating the thread. */ 283 create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL); 284 285 EXPECT_EQ(0, pthread_kill(no_sandbox_thread, 0)); 286 EXPECT_EQ(1, write(thread_pipe[1], ".", 1)); 287 288 EXPECT_EQ(0, pthread_join(no_sandbox_thread, (void **)&ret)); 289 EXPECT_EQ(THREAD_SUCCESS, ret); 290 291 EXPECT_EQ(0, close(thread_pipe[0])); 292 EXPECT_EQ(0, close(thread_pipe[1])); 293 } 294 295 TEST(signal_scoping_thread_after) 296 { 297 pthread_t scoped_thread; 298 enum thread_return ret = THREAD_INVALID; 299 int thread_pipe[2]; 300 301 drop_caps(_metadata); 302 ASSERT_EQ(0, pipe2(thread_pipe, O_CLOEXEC)); 303 304 /* Enforces restriction before creating the thread. */ 305 create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL); 306 307 ASSERT_EQ(0, pthread_create(&scoped_thread, NULL, thread_sync, 308 &thread_pipe[0])); 309 310 EXPECT_EQ(0, pthread_kill(scoped_thread, 0)); 311 EXPECT_EQ(1, write(thread_pipe[1], ".", 1)); 312 313 EXPECT_EQ(0, pthread_join(scoped_thread, (void **)&ret)); 314 EXPECT_EQ(THREAD_SUCCESS, ret); 315 316 EXPECT_EQ(0, close(thread_pipe[0])); 317 EXPECT_EQ(0, close(thread_pipe[1])); 318 } 319 320 struct thread_setuid_args { 321 int pipe_read, new_uid; 322 }; 323 324 void *thread_setuid(void *ptr) 325 { 326 const struct thread_setuid_args *arg = ptr; 327 char buf; 328 329 if (read(arg->pipe_read, &buf, 1) != 1) 330 return (void *)THREAD_ERROR; 331 332 /* libc's setuid() should update all thread's credentials. */ 333 if (getuid() != arg->new_uid) 334 return (void *)THREAD_TEST_FAILED; 335 336 return (void *)THREAD_SUCCESS; 337 } 338 339 TEST(signal_scoping_thread_setuid) 340 { 341 struct thread_setuid_args arg; 342 pthread_t no_sandbox_thread; 343 enum thread_return ret = THREAD_INVALID; 344 int pipe_parent[2]; 345 int prev_uid; 346 347 disable_caps(_metadata); 348 349 /* This test does not need to be run as root. */ 350 prev_uid = getuid(); 351 arg.new_uid = prev_uid + 1; 352 EXPECT_LT(0, arg.new_uid); 353 354 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC)); 355 arg.pipe_read = pipe_parent[0]; 356 357 /* Capabilities must be set before creating a new thread. */ 358 set_cap(_metadata, CAP_SETUID); 359 ASSERT_EQ(0, pthread_create(&no_sandbox_thread, NULL, thread_setuid, 360 &arg)); 361 362 /* Enforces restriction after creating the thread. */ 363 create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL); 364 365 EXPECT_NE(arg.new_uid, getuid()); 366 EXPECT_EQ(0, setuid(arg.new_uid)); 367 EXPECT_EQ(arg.new_uid, getuid()); 368 EXPECT_EQ(1, write(pipe_parent[1], ".", 1)); 369 370 EXPECT_EQ(0, pthread_join(no_sandbox_thread, (void **)&ret)); 371 EXPECT_EQ(THREAD_SUCCESS, ret); 372 373 clear_cap(_metadata, CAP_SETUID); 374 EXPECT_EQ(0, close(pipe_parent[0])); 375 EXPECT_EQ(0, close(pipe_parent[1])); 376 } 377 378 const short backlog = 10; 379 380 static volatile sig_atomic_t signal_received; 381 382 static void handle_sigurg(int sig) 383 { 384 if (sig == SIGURG) 385 signal_received = 1; 386 else 387 signal_received = -1; 388 } 389 390 static int setup_signal_handler(int signal) 391 { 392 struct sigaction sa = { 393 .sa_handler = handle_sigurg, 394 }; 395 396 if (sigemptyset(&sa.sa_mask)) 397 return -1; 398 399 sa.sa_flags = SA_SIGINFO | SA_RESTART; 400 return sigaction(SIGURG, &sa, NULL); 401 } 402 403 /* clang-format off */ 404 FIXTURE(fown) {}; 405 /* clang-format on */ 406 407 enum fown_sandbox { 408 SANDBOX_NONE, 409 SANDBOX_BEFORE_FORK, 410 SANDBOX_BEFORE_SETOWN, 411 SANDBOX_AFTER_SETOWN, 412 }; 413 414 FIXTURE_VARIANT(fown) 415 { 416 const enum fown_sandbox sandbox_setown; 417 }; 418 419 /* clang-format off */ 420 FIXTURE_VARIANT_ADD(fown, no_sandbox) { 421 /* clang-format on */ 422 .sandbox_setown = SANDBOX_NONE, 423 }; 424 425 /* clang-format off */ 426 FIXTURE_VARIANT_ADD(fown, sandbox_before_fork) { 427 /* clang-format on */ 428 .sandbox_setown = SANDBOX_BEFORE_FORK, 429 }; 430 431 /* clang-format off */ 432 FIXTURE_VARIANT_ADD(fown, sandbox_before_setown) { 433 /* clang-format on */ 434 .sandbox_setown = SANDBOX_BEFORE_SETOWN, 435 }; 436 437 /* clang-format off */ 438 FIXTURE_VARIANT_ADD(fown, sandbox_after_setown) { 439 /* clang-format on */ 440 .sandbox_setown = SANDBOX_AFTER_SETOWN, 441 }; 442 443 FIXTURE_SETUP(fown) 444 { 445 drop_caps(_metadata); 446 } 447 448 FIXTURE_TEARDOWN(fown) 449 { 450 } 451 452 /* 453 * Sending an out of bound message will trigger the SIGURG signal 454 * through file_send_sigiotask. 455 */ 456 TEST_F(fown, sigurg_socket) 457 { 458 int server_socket, recv_socket; 459 struct service_fixture server_address; 460 char buffer_parent; 461 int status; 462 int pipe_parent[2], pipe_child[2]; 463 pid_t child; 464 465 memset(&server_address, 0, sizeof(server_address)); 466 set_unix_address(&server_address, 0); 467 468 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC)); 469 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC)); 470 471 if (variant->sandbox_setown == SANDBOX_BEFORE_FORK) 472 create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL); 473 474 child = fork(); 475 ASSERT_LE(0, child); 476 if (child == 0) { 477 int client_socket; 478 char buffer_child; 479 480 EXPECT_EQ(0, close(pipe_parent[1])); 481 EXPECT_EQ(0, close(pipe_child[0])); 482 483 ASSERT_EQ(0, setup_signal_handler(SIGURG)); 484 client_socket = socket(AF_UNIX, SOCK_STREAM, 0); 485 ASSERT_LE(0, client_socket); 486 487 /* Waits for the parent to listen. */ 488 ASSERT_EQ(1, read(pipe_parent[0], &buffer_child, 1)); 489 ASSERT_EQ(0, connect(client_socket, &server_address.unix_addr, 490 server_address.unix_addr_len)); 491 492 /* 493 * Waits for the parent to accept the connection, sandbox 494 * itself, and call fcntl(2). 495 */ 496 ASSERT_EQ(1, read(pipe_parent[0], &buffer_child, 1)); 497 /* May signal itself. */ 498 ASSERT_EQ(1, send(client_socket, ".", 1, MSG_OOB)); 499 EXPECT_EQ(0, close(client_socket)); 500 ASSERT_EQ(1, write(pipe_child[1], ".", 1)); 501 EXPECT_EQ(0, close(pipe_child[1])); 502 503 /* Waits for the message to be received. */ 504 ASSERT_EQ(1, read(pipe_parent[0], &buffer_child, 1)); 505 EXPECT_EQ(0, close(pipe_parent[0])); 506 507 if (variant->sandbox_setown == SANDBOX_BEFORE_SETOWN) { 508 ASSERT_EQ(0, signal_received); 509 } else { 510 /* 511 * A signal is only received if fcntl(F_SETOWN) was 512 * called before any sandboxing or if the signal 513 * receiver is in the same domain. 514 */ 515 ASSERT_EQ(1, signal_received); 516 } 517 _exit(_metadata->exit_code); 518 return; 519 } 520 EXPECT_EQ(0, close(pipe_parent[0])); 521 EXPECT_EQ(0, close(pipe_child[1])); 522 523 server_socket = socket(AF_UNIX, SOCK_STREAM, 0); 524 ASSERT_LE(0, server_socket); 525 ASSERT_EQ(0, bind(server_socket, &server_address.unix_addr, 526 server_address.unix_addr_len)); 527 ASSERT_EQ(0, listen(server_socket, backlog)); 528 ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); 529 530 recv_socket = accept(server_socket, NULL, NULL); 531 ASSERT_LE(0, recv_socket); 532 533 if (variant->sandbox_setown == SANDBOX_BEFORE_SETOWN) 534 create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL); 535 536 /* 537 * Sets the child to receive SIGURG for MSG_OOB. This uncommon use is 538 * a valid attack scenario which also simplifies this test. 539 */ 540 ASSERT_EQ(0, fcntl(recv_socket, F_SETOWN, child)); 541 542 if (variant->sandbox_setown == SANDBOX_AFTER_SETOWN) 543 create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL); 544 545 ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); 546 547 /* Waits for the child to send MSG_OOB. */ 548 ASSERT_EQ(1, read(pipe_child[0], &buffer_parent, 1)); 549 EXPECT_EQ(0, close(pipe_child[0])); 550 ASSERT_EQ(1, recv(recv_socket, &buffer_parent, 1, MSG_OOB)); 551 EXPECT_EQ(0, close(recv_socket)); 552 EXPECT_EQ(0, close(server_socket)); 553 ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); 554 EXPECT_EQ(0, close(pipe_parent[1])); 555 556 ASSERT_EQ(child, waitpid(child, &status, 0)); 557 if (WIFSIGNALED(status) || !WIFEXITED(status) || 558 WEXITSTATUS(status) != EXIT_SUCCESS) 559 _metadata->exit_code = KSFT_FAIL; 560 } 561 562 TEST_HARNESS_MAIN 563