xref: /linux/tools/testing/selftests/landlock/scoped_signal_test.c (revision 566ab427f827b0256d3e8ce0235d088e6a9c28bd)
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 static int thread_pipe[2];
253 
254 enum thread_return {
255 	THREAD_INVALID = 0,
256 	THREAD_SUCCESS = 1,
257 	THREAD_ERROR = 2,
258 };
259 
260 void *thread_func(void *arg)
261 {
262 	char buf;
263 
264 	if (read(thread_pipe[0], &buf, 1) != 1)
265 		return (void *)THREAD_ERROR;
266 
267 	return (void *)THREAD_SUCCESS;
268 }
269 
270 TEST(signal_scoping_threads)
271 {
272 	pthread_t no_sandbox_thread, scoped_thread;
273 	enum thread_return ret = THREAD_INVALID;
274 
275 	drop_caps(_metadata);
276 	ASSERT_EQ(0, pipe2(thread_pipe, O_CLOEXEC));
277 
278 	ASSERT_EQ(0,
279 		  pthread_create(&no_sandbox_thread, NULL, thread_func, NULL));
280 
281 	/* Restricts the domain after creating the first thread. */
282 	create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL);
283 
284 	ASSERT_EQ(EPERM, pthread_kill(no_sandbox_thread, 0));
285 	ASSERT_EQ(1, write(thread_pipe[1], ".", 1));
286 
287 	ASSERT_EQ(0, pthread_create(&scoped_thread, NULL, thread_func, NULL));
288 	ASSERT_EQ(0, pthread_kill(scoped_thread, 0));
289 	ASSERT_EQ(1, write(thread_pipe[1], ".", 1));
290 
291 	EXPECT_EQ(0, pthread_join(no_sandbox_thread, (void **)&ret));
292 	EXPECT_EQ(THREAD_SUCCESS, ret);
293 	EXPECT_EQ(0, pthread_join(scoped_thread, (void **)&ret));
294 	EXPECT_EQ(THREAD_SUCCESS, ret);
295 
296 	EXPECT_EQ(0, close(thread_pipe[0]));
297 	EXPECT_EQ(0, close(thread_pipe[1]));
298 }
299 
300 const short backlog = 10;
301 
302 static volatile sig_atomic_t signal_received;
303 
304 static void handle_sigurg(int sig)
305 {
306 	if (sig == SIGURG)
307 		signal_received = 1;
308 	else
309 		signal_received = -1;
310 }
311 
312 static int setup_signal_handler(int signal)
313 {
314 	struct sigaction sa = {
315 		.sa_handler = handle_sigurg,
316 	};
317 
318 	if (sigemptyset(&sa.sa_mask))
319 		return -1;
320 
321 	sa.sa_flags = SA_SIGINFO | SA_RESTART;
322 	return sigaction(SIGURG, &sa, NULL);
323 }
324 
325 /* clang-format off */
326 FIXTURE(fown) {};
327 /* clang-format on */
328 
329 enum fown_sandbox {
330 	SANDBOX_NONE,
331 	SANDBOX_BEFORE_FORK,
332 	SANDBOX_BEFORE_SETOWN,
333 	SANDBOX_AFTER_SETOWN,
334 };
335 
336 FIXTURE_VARIANT(fown)
337 {
338 	const enum fown_sandbox sandbox_setown;
339 };
340 
341 /* clang-format off */
342 FIXTURE_VARIANT_ADD(fown, no_sandbox) {
343 	/* clang-format on */
344 	.sandbox_setown = SANDBOX_NONE,
345 };
346 
347 /* clang-format off */
348 FIXTURE_VARIANT_ADD(fown, sandbox_before_fork) {
349 	/* clang-format on */
350 	.sandbox_setown = SANDBOX_BEFORE_FORK,
351 };
352 
353 /* clang-format off */
354 FIXTURE_VARIANT_ADD(fown, sandbox_before_setown) {
355 	/* clang-format on */
356 	.sandbox_setown = SANDBOX_BEFORE_SETOWN,
357 };
358 
359 /* clang-format off */
360 FIXTURE_VARIANT_ADD(fown, sandbox_after_setown) {
361 	/* clang-format on */
362 	.sandbox_setown = SANDBOX_AFTER_SETOWN,
363 };
364 
365 FIXTURE_SETUP(fown)
366 {
367 	drop_caps(_metadata);
368 }
369 
370 FIXTURE_TEARDOWN(fown)
371 {
372 }
373 
374 /*
375  * Sending an out of bound message will trigger the SIGURG signal
376  * through file_send_sigiotask.
377  */
378 TEST_F(fown, sigurg_socket)
379 {
380 	int server_socket, recv_socket;
381 	struct service_fixture server_address;
382 	char buffer_parent;
383 	int status;
384 	int pipe_parent[2], pipe_child[2];
385 	pid_t child;
386 
387 	memset(&server_address, 0, sizeof(server_address));
388 	set_unix_address(&server_address, 0);
389 
390 	ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
391 	ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
392 
393 	if (variant->sandbox_setown == SANDBOX_BEFORE_FORK)
394 		create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL);
395 
396 	child = fork();
397 	ASSERT_LE(0, child);
398 	if (child == 0) {
399 		int client_socket;
400 		char buffer_child;
401 
402 		EXPECT_EQ(0, close(pipe_parent[1]));
403 		EXPECT_EQ(0, close(pipe_child[0]));
404 
405 		ASSERT_EQ(0, setup_signal_handler(SIGURG));
406 		client_socket = socket(AF_UNIX, SOCK_STREAM, 0);
407 		ASSERT_LE(0, client_socket);
408 
409 		/* Waits for the parent to listen. */
410 		ASSERT_EQ(1, read(pipe_parent[0], &buffer_child, 1));
411 		ASSERT_EQ(0, connect(client_socket, &server_address.unix_addr,
412 				     server_address.unix_addr_len));
413 
414 		/*
415 		 * Waits for the parent to accept the connection, sandbox
416 		 * itself, and call fcntl(2).
417 		 */
418 		ASSERT_EQ(1, read(pipe_parent[0], &buffer_child, 1));
419 		/* May signal itself. */
420 		ASSERT_EQ(1, send(client_socket, ".", 1, MSG_OOB));
421 		EXPECT_EQ(0, close(client_socket));
422 		ASSERT_EQ(1, write(pipe_child[1], ".", 1));
423 		EXPECT_EQ(0, close(pipe_child[1]));
424 
425 		/* Waits for the message to be received. */
426 		ASSERT_EQ(1, read(pipe_parent[0], &buffer_child, 1));
427 		EXPECT_EQ(0, close(pipe_parent[0]));
428 
429 		if (variant->sandbox_setown == SANDBOX_BEFORE_SETOWN) {
430 			ASSERT_EQ(0, signal_received);
431 		} else {
432 			/*
433 			 * A signal is only received if fcntl(F_SETOWN) was
434 			 * called before any sandboxing or if the signal
435 			 * receiver is in the same domain.
436 			 */
437 			ASSERT_EQ(1, signal_received);
438 		}
439 		_exit(_metadata->exit_code);
440 		return;
441 	}
442 	EXPECT_EQ(0, close(pipe_parent[0]));
443 	EXPECT_EQ(0, close(pipe_child[1]));
444 
445 	server_socket = socket(AF_UNIX, SOCK_STREAM, 0);
446 	ASSERT_LE(0, server_socket);
447 	ASSERT_EQ(0, bind(server_socket, &server_address.unix_addr,
448 			  server_address.unix_addr_len));
449 	ASSERT_EQ(0, listen(server_socket, backlog));
450 	ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
451 
452 	recv_socket = accept(server_socket, NULL, NULL);
453 	ASSERT_LE(0, recv_socket);
454 
455 	if (variant->sandbox_setown == SANDBOX_BEFORE_SETOWN)
456 		create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL);
457 
458 	/*
459 	 * Sets the child to receive SIGURG for MSG_OOB.  This uncommon use is
460 	 * a valid attack scenario which also simplifies this test.
461 	 */
462 	ASSERT_EQ(0, fcntl(recv_socket, F_SETOWN, child));
463 
464 	if (variant->sandbox_setown == SANDBOX_AFTER_SETOWN)
465 		create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL);
466 
467 	ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
468 
469 	/* Waits for the child to send MSG_OOB. */
470 	ASSERT_EQ(1, read(pipe_child[0], &buffer_parent, 1));
471 	EXPECT_EQ(0, close(pipe_child[0]));
472 	ASSERT_EQ(1, recv(recv_socket, &buffer_parent, 1, MSG_OOB));
473 	EXPECT_EQ(0, close(recv_socket));
474 	EXPECT_EQ(0, close(server_socket));
475 	ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
476 	EXPECT_EQ(0, close(pipe_parent[1]));
477 
478 	ASSERT_EQ(child, waitpid(child, &status, 0));
479 	if (WIFSIGNALED(status) || !WIFEXITED(status) ||
480 	    WEXITSTATUS(status) != EXIT_SUCCESS)
481 		_metadata->exit_code = KSFT_FAIL;
482 }
483 
484 TEST_HARNESS_MAIN
485