Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.16 562 lines 13 kB view raw
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. */ 23static volatile sig_atomic_t is_signaled; 24 25/* clang-format off */ 26FIXTURE(scoping_signals) {}; 27/* clang-format on */ 28 29FIXTURE_VARIANT(scoping_signals) 30{ 31 int sig; 32}; 33 34/* clang-format off */ 35FIXTURE_VARIANT_ADD(scoping_signals, sigtrap) { 36 /* clang-format on */ 37 .sig = SIGTRAP, 38}; 39 40/* clang-format off */ 41FIXTURE_VARIANT_ADD(scoping_signals, sigurg) { 42 /* clang-format on */ 43 .sig = SIGURG, 44}; 45 46/* clang-format off */ 47FIXTURE_VARIANT_ADD(scoping_signals, sighup) { 48 /* clang-format on */ 49 .sig = SIGHUP, 50}; 51 52/* clang-format off */ 53FIXTURE_VARIANT_ADD(scoping_signals, sigtstp) { 54 /* clang-format on */ 55 .sig = SIGTSTP, 56}; 57 58FIXTURE_SETUP(scoping_signals) 59{ 60 drop_caps(_metadata); 61 62 is_signaled = 0; 63} 64 65FIXTURE_TEARDOWN(scoping_signals) 66{ 67} 68 69static 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 */ 79TEST_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 */ 154FIXTURE(scoped_domains) {}; 155/* clang-format on */ 156 157#include "scoped_base_variants.h" 158 159FIXTURE_SETUP(scoped_domains) 160{ 161 drop_caps(_metadata); 162} 163 164FIXTURE_TEARDOWN(scoped_domains) 165{ 166} 167 168/* 169 * This test ensures that a scoped process cannot send signal out of 170 * scoped domain. 171 */ 172TEST_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 252enum thread_return { 253 THREAD_INVALID = 0, 254 THREAD_SUCCESS = 1, 255 THREAD_ERROR = 2, 256 THREAD_TEST_FAILED = 3, 257}; 258 259static 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 270TEST(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 295TEST(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 320struct thread_setuid_args { 321 int pipe_read, new_uid; 322}; 323 324void *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 339TEST(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 378const short backlog = 10; 379 380static volatile sig_atomic_t signal_received; 381 382static void handle_sigurg(int sig) 383{ 384 if (sig == SIGURG) 385 signal_received = 1; 386 else 387 signal_received = -1; 388} 389 390static 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 */ 404FIXTURE(fown) {}; 405/* clang-format on */ 406 407enum fown_sandbox { 408 SANDBOX_NONE, 409 SANDBOX_BEFORE_FORK, 410 SANDBOX_BEFORE_SETOWN, 411 SANDBOX_AFTER_SETOWN, 412}; 413 414FIXTURE_VARIANT(fown) 415{ 416 const enum fown_sandbox sandbox_setown; 417}; 418 419/* clang-format off */ 420FIXTURE_VARIANT_ADD(fown, no_sandbox) { 421 /* clang-format on */ 422 .sandbox_setown = SANDBOX_NONE, 423}; 424 425/* clang-format off */ 426FIXTURE_VARIANT_ADD(fown, sandbox_before_fork) { 427 /* clang-format on */ 428 .sandbox_setown = SANDBOX_BEFORE_FORK, 429}; 430 431/* clang-format off */ 432FIXTURE_VARIANT_ADD(fown, sandbox_before_setown) { 433 /* clang-format on */ 434 .sandbox_setown = SANDBOX_BEFORE_SETOWN, 435}; 436 437/* clang-format off */ 438FIXTURE_VARIANT_ADD(fown, sandbox_after_setown) { 439 /* clang-format on */ 440 .sandbox_setown = SANDBOX_AFTER_SETOWN, 441}; 442 443FIXTURE_SETUP(fown) 444{ 445 drop_caps(_metadata); 446} 447 448FIXTURE_TEARDOWN(fown) 449{ 450} 451 452/* 453 * Sending an out of bound message will trigger the SIGURG signal 454 * through file_send_sigiotask. 455 */ 456TEST_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 562TEST_HARNESS_MAIN