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