1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Landlock tests - Signal Scoping
4 *
5 * Copyright © 2024 Tahera Fahimi <[email protected]>
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 */
FIXTURE(scoping_signals)26 FIXTURE(scoping_signals) {};
27 /* clang-format on */
28
FIXTURE_VARIANT(scoping_signals)29 FIXTURE_VARIANT(scoping_signals)
30 {
31 int sig;
32 };
33
34 /* clang-format off */
FIXTURE_VARIANT_ADD(scoping_signals,sigtrap)35 FIXTURE_VARIANT_ADD(scoping_signals, sigtrap) {
36 /* clang-format on */
37 .sig = SIGTRAP,
38 };
39
40 /* clang-format off */
FIXTURE_VARIANT_ADD(scoping_signals,sigurg)41 FIXTURE_VARIANT_ADD(scoping_signals, sigurg) {
42 /* clang-format on */
43 .sig = SIGURG,
44 };
45
46 /* clang-format off */
FIXTURE_VARIANT_ADD(scoping_signals,sighup)47 FIXTURE_VARIANT_ADD(scoping_signals, sighup) {
48 /* clang-format on */
49 .sig = SIGHUP,
50 };
51
52 /* clang-format off */
FIXTURE_VARIANT_ADD(scoping_signals,sigtstp)53 FIXTURE_VARIANT_ADD(scoping_signals, sigtstp) {
54 /* clang-format on */
55 .sig = SIGTSTP,
56 };
57
FIXTURE_SETUP(scoping_signals)58 FIXTURE_SETUP(scoping_signals)
59 {
60 drop_caps(_metadata);
61
62 is_signaled = 0;
63 }
64
FIXTURE_TEARDOWN(scoping_signals)65 FIXTURE_TEARDOWN(scoping_signals)
66 {
67 }
68
scope_signal_handler(int sig,siginfo_t * info,void * ucontext)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 */
TEST_F(scoping_signals,send_sig_to_parent)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 */
FIXTURE(scoped_domains)154 FIXTURE(scoped_domains) {};
155 /* clang-format on */
156
157 #include "scoped_base_variants.h"
158
FIXTURE_SETUP(scoped_domains)159 FIXTURE_SETUP(scoped_domains)
160 {
161 drop_caps(_metadata);
162 }
163
FIXTURE_TEARDOWN(scoped_domains)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 */
TEST_F(scoped_domains,check_access_signal)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
thread_sync(void * arg)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
TEST(signal_scoping_thread_before)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
TEST(signal_scoping_thread_after)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
thread_setuid(void * ptr)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
TEST(signal_scoping_thread_setuid)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
handle_sigurg(int sig)382 static void handle_sigurg(int sig)
383 {
384 if (sig == SIGURG)
385 signal_received = 1;
386 else
387 signal_received = -1;
388 }
389
setup_signal_handler(int signal)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 */
FIXTURE(fown)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
FIXTURE_VARIANT(fown)414 FIXTURE_VARIANT(fown)
415 {
416 const enum fown_sandbox sandbox_setown;
417 };
418
419 /* clang-format off */
FIXTURE_VARIANT_ADD(fown,no_sandbox)420 FIXTURE_VARIANT_ADD(fown, no_sandbox) {
421 /* clang-format on */
422 .sandbox_setown = SANDBOX_NONE,
423 };
424
425 /* clang-format off */
FIXTURE_VARIANT_ADD(fown,sandbox_before_fork)426 FIXTURE_VARIANT_ADD(fown, sandbox_before_fork) {
427 /* clang-format on */
428 .sandbox_setown = SANDBOX_BEFORE_FORK,
429 };
430
431 /* clang-format off */
FIXTURE_VARIANT_ADD(fown,sandbox_before_setown)432 FIXTURE_VARIANT_ADD(fown, sandbox_before_setown) {
433 /* clang-format on */
434 .sandbox_setown = SANDBOX_BEFORE_SETOWN,
435 };
436
437 /* clang-format off */
FIXTURE_VARIANT_ADD(fown,sandbox_after_setown)438 FIXTURE_VARIANT_ADD(fown, sandbox_after_setown) {
439 /* clang-format on */
440 .sandbox_setown = SANDBOX_AFTER_SETOWN,
441 };
442
FIXTURE_SETUP(fown)443 FIXTURE_SETUP(fown)
444 {
445 drop_caps(_metadata);
446 }
447
FIXTURE_TEARDOWN(fown)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 */
TEST_F(fown,sigurg_socket)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