1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Landlock tests - Abstract UNIX socket
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 <sched.h>
13 #include <signal.h>
14 #include <stddef.h>
15 #include <sys/mount.h>
16 #include <sys/prctl.h>
17 #include <sys/socket.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <sys/un.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
23
24 #include "audit.h"
25 #include "common.h"
26 #include "scoped_common.h"
27 #include "trace.h"
28
29 #define TRACE_TASK "scoped_abstract"
30
31 /* Number of pending connections queue to be hold. */
32 const short backlog = 10;
33
create_fs_domain(struct __test_metadata * const _metadata)34 static void create_fs_domain(struct __test_metadata *const _metadata)
35 {
36 int ruleset_fd;
37 struct landlock_ruleset_attr ruleset_attr = {
38 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR,
39 };
40
41 ruleset_fd =
42 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
43 EXPECT_LE(0, ruleset_fd)
44 {
45 TH_LOG("Failed to create a ruleset: %s", strerror(errno));
46 }
47 EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
48 EXPECT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
49 EXPECT_EQ(0, close(ruleset_fd));
50 }
51
FIXTURE(scoped_domains)52 FIXTURE(scoped_domains)
53 {
54 struct service_fixture stream_address, dgram_address;
55 };
56
57 #include "scoped_base_variants.h"
58
FIXTURE_SETUP(scoped_domains)59 FIXTURE_SETUP(scoped_domains)
60 {
61 drop_caps(_metadata);
62
63 memset(&self->stream_address, 0, sizeof(self->stream_address));
64 memset(&self->dgram_address, 0, sizeof(self->dgram_address));
65 set_unix_address(&self->stream_address, 0);
66 set_unix_address(&self->dgram_address, 1);
67 }
68
FIXTURE_TEARDOWN(scoped_domains)69 FIXTURE_TEARDOWN(scoped_domains)
70 {
71 }
72
73 /*
74 * Test unix_stream_connect() and unix_may_send() for a child connecting to its
75 * parent, when they have scoped domain or no domain.
76 */
TEST_F(scoped_domains,connect_to_parent)77 TEST_F(scoped_domains, connect_to_parent)
78 {
79 pid_t child;
80 bool can_connect_to_parent;
81 int status;
82 int pipe_parent[2];
83 int stream_server, dgram_server;
84
85 /*
86 * can_connect_to_parent is true if a child process can connect to its
87 * parent process. This depends on the child process not being isolated
88 * from the parent with a dedicated Landlock domain.
89 */
90 can_connect_to_parent = !variant->domain_child;
91
92 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
93 if (variant->domain_both) {
94 create_scoped_domain(_metadata,
95 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
96 if (!__test_passed(_metadata))
97 return;
98 }
99
100 child = fork();
101 ASSERT_LE(0, child);
102 if (child == 0) {
103 int err;
104 int stream_client, dgram_client;
105 char buf_child;
106
107 EXPECT_EQ(0, close(pipe_parent[1]));
108 if (variant->domain_child)
109 create_scoped_domain(
110 _metadata, LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
111
112 stream_client = socket(AF_UNIX, SOCK_STREAM, 0);
113 ASSERT_LE(0, stream_client);
114 dgram_client = socket(AF_UNIX, SOCK_DGRAM, 0);
115 ASSERT_LE(0, dgram_client);
116
117 /* Waits for the server. */
118 ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
119
120 err = connect(stream_client, &self->stream_address.unix_addr,
121 self->stream_address.unix_addr_len);
122 if (can_connect_to_parent) {
123 EXPECT_EQ(0, err);
124 } else {
125 EXPECT_EQ(-1, err);
126 EXPECT_EQ(EPERM, errno);
127 }
128 EXPECT_EQ(0, close(stream_client));
129
130 err = connect(dgram_client, &self->dgram_address.unix_addr,
131 self->dgram_address.unix_addr_len);
132 if (can_connect_to_parent) {
133 EXPECT_EQ(0, err);
134 } else {
135 EXPECT_EQ(-1, err);
136 EXPECT_EQ(EPERM, errno);
137 }
138 EXPECT_EQ(0, close(dgram_client));
139 _exit(_metadata->exit_code);
140 return;
141 }
142 EXPECT_EQ(0, close(pipe_parent[0]));
143 if (variant->domain_parent)
144 create_scoped_domain(_metadata,
145 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
146
147 stream_server = socket(AF_UNIX, SOCK_STREAM, 0);
148 ASSERT_LE(0, stream_server);
149 dgram_server = socket(AF_UNIX, SOCK_DGRAM, 0);
150 ASSERT_LE(0, dgram_server);
151 ASSERT_EQ(0, bind(stream_server, &self->stream_address.unix_addr,
152 self->stream_address.unix_addr_len));
153 ASSERT_EQ(0, bind(dgram_server, &self->dgram_address.unix_addr,
154 self->dgram_address.unix_addr_len));
155 ASSERT_EQ(0, listen(stream_server, backlog));
156
157 /* Signals to child that the parent is listening. */
158 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
159
160 ASSERT_EQ(child, waitpid(child, &status, 0));
161 EXPECT_EQ(0, close(stream_server));
162 EXPECT_EQ(0, close(dgram_server));
163
164 if (WIFSIGNALED(status) || !WIFEXITED(status) ||
165 WEXITSTATUS(status) != EXIT_SUCCESS)
166 _metadata->exit_code = KSFT_FAIL;
167 }
168
169 /*
170 * Test unix_stream_connect() and unix_may_send() for a parent connecting to
171 * its child, when they have scoped domain or no domain.
172 */
TEST_F(scoped_domains,connect_to_child)173 TEST_F(scoped_domains, connect_to_child)
174 {
175 pid_t child;
176 bool can_connect_to_child;
177 int err_stream, err_dgram, errno_stream, errno_dgram, status;
178 int pipe_child[2], pipe_parent[2];
179 char buf;
180 int stream_client, dgram_client;
181
182 /*
183 * can_connect_to_child is true if a parent process can connect to its
184 * child process. The parent process is not isolated from the child
185 * with a dedicated Landlock domain.
186 */
187 can_connect_to_child = !variant->domain_parent;
188
189 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
190 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
191 if (variant->domain_both) {
192 create_scoped_domain(_metadata,
193 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
194 if (!__test_passed(_metadata))
195 return;
196 }
197
198 child = fork();
199 ASSERT_LE(0, child);
200 if (child == 0) {
201 int stream_server, dgram_server;
202
203 EXPECT_EQ(0, close(pipe_parent[1]));
204 EXPECT_EQ(0, close(pipe_child[0]));
205 if (variant->domain_child)
206 create_scoped_domain(
207 _metadata, LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
208
209 /* Waits for the parent to be in a domain, if any. */
210 ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));
211
212 stream_server = socket(AF_UNIX, SOCK_STREAM, 0);
213 ASSERT_LE(0, stream_server);
214 dgram_server = socket(AF_UNIX, SOCK_DGRAM, 0);
215 ASSERT_LE(0, dgram_server);
216 ASSERT_EQ(0,
217 bind(stream_server, &self->stream_address.unix_addr,
218 self->stream_address.unix_addr_len));
219 ASSERT_EQ(0, bind(dgram_server, &self->dgram_address.unix_addr,
220 self->dgram_address.unix_addr_len));
221 ASSERT_EQ(0, listen(stream_server, backlog));
222
223 /* Signals to the parent that child is listening. */
224 ASSERT_EQ(1, write(pipe_child[1], ".", 1));
225
226 /* Waits to connect. */
227 ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));
228 EXPECT_EQ(0, close(stream_server));
229 EXPECT_EQ(0, close(dgram_server));
230 _exit(_metadata->exit_code);
231 return;
232 }
233 EXPECT_EQ(0, close(pipe_child[1]));
234 EXPECT_EQ(0, close(pipe_parent[0]));
235
236 if (variant->domain_parent)
237 create_scoped_domain(_metadata,
238 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
239
240 /* Signals that the parent is in a domain, if any. */
241 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
242
243 stream_client = socket(AF_UNIX, SOCK_STREAM, 0);
244 ASSERT_LE(0, stream_client);
245 dgram_client = socket(AF_UNIX, SOCK_DGRAM, 0);
246 ASSERT_LE(0, dgram_client);
247
248 /* Waits for the child to listen */
249 ASSERT_EQ(1, read(pipe_child[0], &buf, 1));
250 err_stream = connect(stream_client, &self->stream_address.unix_addr,
251 self->stream_address.unix_addr_len);
252 errno_stream = errno;
253 err_dgram = connect(dgram_client, &self->dgram_address.unix_addr,
254 self->dgram_address.unix_addr_len);
255 errno_dgram = errno;
256 if (can_connect_to_child) {
257 EXPECT_EQ(0, err_stream);
258 EXPECT_EQ(0, err_dgram);
259 } else {
260 EXPECT_EQ(-1, err_stream);
261 EXPECT_EQ(-1, err_dgram);
262 EXPECT_EQ(EPERM, errno_stream);
263 EXPECT_EQ(EPERM, errno_dgram);
264 }
265 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
266 EXPECT_EQ(0, close(stream_client));
267 EXPECT_EQ(0, close(dgram_client));
268
269 ASSERT_EQ(child, waitpid(child, &status, 0));
270 if (WIFSIGNALED(status) || !WIFEXITED(status) ||
271 WEXITSTATUS(status) != EXIT_SUCCESS)
272 _metadata->exit_code = KSFT_FAIL;
273 }
274
FIXTURE(scoped_audit)275 FIXTURE(scoped_audit)
276 {
277 struct service_fixture dgram_address;
278 struct audit_filter audit_filter;
279 int audit_fd;
280 };
281
FIXTURE_SETUP(scoped_audit)282 FIXTURE_SETUP(scoped_audit)
283 {
284 disable_caps(_metadata);
285
286 memset(&self->dgram_address, 0, sizeof(self->dgram_address));
287 set_unix_address(&self->dgram_address, 1);
288
289 set_cap(_metadata, CAP_AUDIT_CONTROL);
290 self->audit_fd = audit_init_with_exe_filter(&self->audit_filter);
291 EXPECT_LE(0, self->audit_fd);
292 drop_caps(_metadata);
293 }
294
FIXTURE_TEARDOWN_PARENT(scoped_audit)295 FIXTURE_TEARDOWN_PARENT(scoped_audit)
296 {
297 EXPECT_EQ(0, audit_cleanup(-1, NULL));
298 }
299
FIXTURE_VARIANT(scoped_audit)300 FIXTURE_VARIANT(scoped_audit)
301 {
302 const __u64 scoped;
303 const __u64 quiet_scoped;
304 };
305
306 /* clang-format off */
FIXTURE_VARIANT_ADD(scoped_audit,no_quiet)307 FIXTURE_VARIANT_ADD(scoped_audit, no_quiet)
308 {
309 /* clang-format on */
310 .scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
311 .quiet_scoped = 0,
312 };
313
314 /* clang-format off */
FIXTURE_VARIANT_ADD(scoped_audit,quiet_abstract_socket)315 FIXTURE_VARIANT_ADD(scoped_audit, quiet_abstract_socket)
316 {
317 /* clang-format on */
318 .scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
319 .quiet_scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
320 };
321
322 /* clang-format off */
FIXTURE_VARIANT_ADD(scoped_audit,quiet_abstract_socket_2)323 FIXTURE_VARIANT_ADD(scoped_audit, quiet_abstract_socket_2)
324 {
325 /* clang-format on */
326 .scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET | LANDLOCK_SCOPE_SIGNAL,
327 .quiet_scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
328 LANDLOCK_SCOPE_SIGNAL,
329 };
330
331 /* clang-format off */
FIXTURE_VARIANT_ADD(scoped_audit,quiet_unrelated)332 FIXTURE_VARIANT_ADD(scoped_audit, quiet_unrelated)
333 {
334 /* clang-format on */
335 .scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET | LANDLOCK_SCOPE_SIGNAL,
336 .quiet_scoped = LANDLOCK_SCOPE_SIGNAL,
337 };
338
339 /* python -c 'print(b"\0selftests-landlock-abstract-unix-".hex().upper())' */
340 #define ABSTRACT_SOCKET_PATH_PREFIX \
341 "0073656C6674657374732D6C616E646C6F636B2D61627374726163742D756E69782D"
342
343 /*
344 * Simpler version of scoped_domains.connect_to_child, but with audit tests.
345 */
TEST_F(scoped_audit,connect_to_child)346 TEST_F(scoped_audit, connect_to_child)
347 {
348 pid_t child;
349 int err_dgram, status;
350 int pipe_child[2], pipe_parent[2];
351 char buf;
352 int dgram_client;
353 struct audit_records records;
354 int ruleset_fd;
355 const struct landlock_ruleset_attr ruleset_attr = {
356 .scoped = variant->scoped,
357 .quiet_scoped = variant->quiet_scoped,
358 };
359 bool should_audit =
360 !(variant->quiet_scoped & LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
361
362 /* Makes sure there is no superfluous logged records. */
363 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
364 EXPECT_EQ(0, records.access);
365 EXPECT_EQ(0, records.domain);
366
367 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
368 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
369
370 child = fork();
371 ASSERT_LE(0, child);
372 if (child == 0) {
373 int dgram_server;
374
375 EXPECT_EQ(0, close(pipe_parent[1]));
376 EXPECT_EQ(0, close(pipe_child[0]));
377
378 /* Waits for the parent to be in a domain. */
379 ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));
380
381 dgram_server = socket(AF_UNIX, SOCK_DGRAM, 0);
382 ASSERT_LE(0, dgram_server);
383 ASSERT_EQ(0, bind(dgram_server, &self->dgram_address.unix_addr,
384 self->dgram_address.unix_addr_len));
385
386 /* Signals to the parent that child is listening. */
387 ASSERT_EQ(1, write(pipe_child[1], ".", 1));
388
389 /* Waits to connect. */
390 ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));
391 EXPECT_EQ(0, close(dgram_server));
392 _exit(_metadata->exit_code);
393 return;
394 }
395 EXPECT_EQ(0, close(pipe_child[1]));
396 EXPECT_EQ(0, close(pipe_parent[0]));
397
398 ruleset_fd =
399 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
400 ASSERT_LE(0, ruleset_fd)
401 {
402 TH_LOG("Failed to create a ruleset: %s", strerror(errno));
403 }
404 enforce_ruleset(_metadata, ruleset_fd);
405 EXPECT_EQ(0, close(ruleset_fd));
406
407 /* Signals that the parent is in a domain, if any. */
408 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
409
410 dgram_client = socket(AF_UNIX, SOCK_DGRAM, 0);
411 ASSERT_LE(0, dgram_client);
412
413 /* Waits for the child to listen */
414 ASSERT_EQ(1, read(pipe_child[0], &buf, 1));
415 err_dgram = connect(dgram_client, &self->dgram_address.unix_addr,
416 self->dgram_address.unix_addr_len);
417 EXPECT_EQ(-1, err_dgram);
418 EXPECT_EQ(EPERM, errno);
419
420 if (should_audit) {
421 EXPECT_EQ(
422 0,
423 audit_match_record(
424 self->audit_fd, AUDIT_LANDLOCK_ACCESS,
425 REGEX_LANDLOCK_PREFIX
426 " blockers=scope\\.abstract_unix_socket path=" ABSTRACT_SOCKET_PATH_PREFIX
427 "[0-9A-F]\\+$",
428 NULL));
429 }
430
431 /* No other logs */
432 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
433 EXPECT_EQ(0, records.access);
434
435 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
436 EXPECT_EQ(0, close(dgram_client));
437
438 ASSERT_EQ(child, waitpid(child, &status, 0));
439 if (WIFSIGNALED(status) || !WIFEXITED(status) ||
440 WEXITSTATUS(status) != EXIT_SUCCESS)
441 _metadata->exit_code = KSFT_FAIL;
442 }
443
FIXTURE(scoped_vs_unscoped)444 FIXTURE(scoped_vs_unscoped)
445 {
446 struct service_fixture parent_stream_address, parent_dgram_address,
447 child_stream_address, child_dgram_address;
448 };
449
450 #include "scoped_multiple_domain_variants.h"
451
FIXTURE_SETUP(scoped_vs_unscoped)452 FIXTURE_SETUP(scoped_vs_unscoped)
453 {
454 drop_caps(_metadata);
455
456 memset(&self->parent_stream_address, 0,
457 sizeof(self->parent_stream_address));
458 set_unix_address(&self->parent_stream_address, 0);
459 memset(&self->parent_dgram_address, 0,
460 sizeof(self->parent_dgram_address));
461 set_unix_address(&self->parent_dgram_address, 1);
462 memset(&self->child_stream_address, 0,
463 sizeof(self->child_stream_address));
464 set_unix_address(&self->child_stream_address, 2);
465 memset(&self->child_dgram_address, 0,
466 sizeof(self->child_dgram_address));
467 set_unix_address(&self->child_dgram_address, 3);
468 }
469
FIXTURE_TEARDOWN(scoped_vs_unscoped)470 FIXTURE_TEARDOWN(scoped_vs_unscoped)
471 {
472 }
473
474 /*
475 * Test unix_stream_connect and unix_may_send for parent, child and
476 * grand child processes when they can have scoped or non-scoped domains.
477 */
TEST_F(scoped_vs_unscoped,unix_scoping)478 TEST_F(scoped_vs_unscoped, unix_scoping)
479 {
480 pid_t child;
481 int status;
482 bool can_connect_to_parent, can_connect_to_child;
483 int pipe_parent[2];
484 int stream_server_parent, dgram_server_parent;
485
486 can_connect_to_child = (variant->domain_grand_child != SCOPE_SANDBOX);
487 can_connect_to_parent = (can_connect_to_child &&
488 (variant->domain_children != SCOPE_SANDBOX));
489
490 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
491
492 if (variant->domain_all == OTHER_SANDBOX)
493 create_fs_domain(_metadata);
494 else if (variant->domain_all == SCOPE_SANDBOX)
495 create_scoped_domain(_metadata,
496 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
497
498 child = fork();
499 ASSERT_LE(0, child);
500 if (child == 0) {
501 int stream_server_child, dgram_server_child;
502 int pipe_child[2];
503 pid_t grand_child;
504
505 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
506
507 if (variant->domain_children == OTHER_SANDBOX)
508 create_fs_domain(_metadata);
509 else if (variant->domain_children == SCOPE_SANDBOX)
510 create_scoped_domain(
511 _metadata, LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
512
513 grand_child = fork();
514 ASSERT_LE(0, grand_child);
515 if (grand_child == 0) {
516 char buf;
517 int stream_err, dgram_err, stream_errno, dgram_errno;
518 int stream_client, dgram_client;
519
520 EXPECT_EQ(0, close(pipe_parent[1]));
521 EXPECT_EQ(0, close(pipe_child[1]));
522
523 if (variant->domain_grand_child == OTHER_SANDBOX)
524 create_fs_domain(_metadata);
525 else if (variant->domain_grand_child == SCOPE_SANDBOX)
526 create_scoped_domain(
527 _metadata,
528 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
529
530 stream_client = socket(AF_UNIX, SOCK_STREAM, 0);
531 ASSERT_LE(0, stream_client);
532 dgram_client = socket(AF_UNIX, SOCK_DGRAM, 0);
533 ASSERT_LE(0, dgram_client);
534
535 ASSERT_EQ(1, read(pipe_child[0], &buf, 1));
536 stream_err = connect(
537 stream_client,
538 &self->child_stream_address.unix_addr,
539 self->child_stream_address.unix_addr_len);
540 stream_errno = errno;
541 dgram_err = connect(
542 dgram_client,
543 &self->child_dgram_address.unix_addr,
544 self->child_dgram_address.unix_addr_len);
545 dgram_errno = errno;
546 if (can_connect_to_child) {
547 EXPECT_EQ(0, stream_err);
548 EXPECT_EQ(0, dgram_err);
549 } else {
550 EXPECT_EQ(-1, stream_err);
551 EXPECT_EQ(-1, dgram_err);
552 EXPECT_EQ(EPERM, stream_errno);
553 EXPECT_EQ(EPERM, dgram_errno);
554 }
555
556 EXPECT_EQ(0, close(stream_client));
557 stream_client = socket(AF_UNIX, SOCK_STREAM, 0);
558 ASSERT_LE(0, stream_client);
559 /* Datagram sockets can "reconnect". */
560
561 ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));
562 stream_err = connect(
563 stream_client,
564 &self->parent_stream_address.unix_addr,
565 self->parent_stream_address.unix_addr_len);
566 stream_errno = errno;
567 dgram_err = connect(
568 dgram_client,
569 &self->parent_dgram_address.unix_addr,
570 self->parent_dgram_address.unix_addr_len);
571 dgram_errno = errno;
572 if (can_connect_to_parent) {
573 EXPECT_EQ(0, stream_err);
574 EXPECT_EQ(0, dgram_err);
575 } else {
576 EXPECT_EQ(-1, stream_err);
577 EXPECT_EQ(-1, dgram_err);
578 EXPECT_EQ(EPERM, stream_errno);
579 EXPECT_EQ(EPERM, dgram_errno);
580 }
581 EXPECT_EQ(0, close(stream_client));
582 EXPECT_EQ(0, close(dgram_client));
583
584 _exit(_metadata->exit_code);
585 return;
586 }
587 EXPECT_EQ(0, close(pipe_child[0]));
588 if (variant->domain_child == OTHER_SANDBOX)
589 create_fs_domain(_metadata);
590 else if (variant->domain_child == SCOPE_SANDBOX)
591 create_scoped_domain(
592 _metadata, LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
593
594 stream_server_child = socket(AF_UNIX, SOCK_STREAM, 0);
595 ASSERT_LE(0, stream_server_child);
596 dgram_server_child = socket(AF_UNIX, SOCK_DGRAM, 0);
597 ASSERT_LE(0, dgram_server_child);
598
599 ASSERT_EQ(0, bind(stream_server_child,
600 &self->child_stream_address.unix_addr,
601 self->child_stream_address.unix_addr_len));
602 ASSERT_EQ(0, bind(dgram_server_child,
603 &self->child_dgram_address.unix_addr,
604 self->child_dgram_address.unix_addr_len));
605 ASSERT_EQ(0, listen(stream_server_child, backlog));
606
607 ASSERT_EQ(1, write(pipe_child[1], ".", 1));
608 ASSERT_EQ(grand_child, waitpid(grand_child, &status, 0));
609 EXPECT_EQ(0, close(stream_server_child));
610 EXPECT_EQ(0, close(dgram_server_child));
611 return;
612 }
613 EXPECT_EQ(0, close(pipe_parent[0]));
614
615 if (variant->domain_parent == OTHER_SANDBOX)
616 create_fs_domain(_metadata);
617 else if (variant->domain_parent == SCOPE_SANDBOX)
618 create_scoped_domain(_metadata,
619 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
620
621 stream_server_parent = socket(AF_UNIX, SOCK_STREAM, 0);
622 ASSERT_LE(0, stream_server_parent);
623 dgram_server_parent = socket(AF_UNIX, SOCK_DGRAM, 0);
624 ASSERT_LE(0, dgram_server_parent);
625 ASSERT_EQ(0, bind(stream_server_parent,
626 &self->parent_stream_address.unix_addr,
627 self->parent_stream_address.unix_addr_len));
628 ASSERT_EQ(0, bind(dgram_server_parent,
629 &self->parent_dgram_address.unix_addr,
630 self->parent_dgram_address.unix_addr_len));
631
632 ASSERT_EQ(0, listen(stream_server_parent, backlog));
633
634 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
635 ASSERT_EQ(child, waitpid(child, &status, 0));
636 EXPECT_EQ(0, close(stream_server_parent));
637 EXPECT_EQ(0, close(dgram_server_parent));
638
639 if (WIFSIGNALED(status) || !WIFEXITED(status) ||
640 WEXITSTATUS(status) != EXIT_SUCCESS)
641 _metadata->exit_code = KSFT_FAIL;
642 }
643
FIXTURE(outside_socket)644 FIXTURE(outside_socket)
645 {
646 struct service_fixture address, transit_address;
647 };
648
FIXTURE_VARIANT(outside_socket)649 FIXTURE_VARIANT(outside_socket)
650 {
651 const bool child_socket;
652 const int type;
653 };
654
655 /* clang-format off */
FIXTURE_VARIANT_ADD(outside_socket,allow_dgram_child)656 FIXTURE_VARIANT_ADD(outside_socket, allow_dgram_child) {
657 /* clang-format on */
658 .child_socket = true,
659 .type = SOCK_DGRAM,
660 };
661
662 /* clang-format off */
FIXTURE_VARIANT_ADD(outside_socket,deny_dgram_server)663 FIXTURE_VARIANT_ADD(outside_socket, deny_dgram_server) {
664 /* clang-format on */
665 .child_socket = false,
666 .type = SOCK_DGRAM,
667 };
668
669 /* clang-format off */
FIXTURE_VARIANT_ADD(outside_socket,allow_stream_child)670 FIXTURE_VARIANT_ADD(outside_socket, allow_stream_child) {
671 /* clang-format on */
672 .child_socket = true,
673 .type = SOCK_STREAM,
674 };
675
676 /* clang-format off */
FIXTURE_VARIANT_ADD(outside_socket,deny_stream_server)677 FIXTURE_VARIANT_ADD(outside_socket, deny_stream_server) {
678 /* clang-format on */
679 .child_socket = false,
680 .type = SOCK_STREAM,
681 };
682
FIXTURE_SETUP(outside_socket)683 FIXTURE_SETUP(outside_socket)
684 {
685 drop_caps(_metadata);
686
687 memset(&self->transit_address, 0, sizeof(self->transit_address));
688 set_unix_address(&self->transit_address, 0);
689 memset(&self->address, 0, sizeof(self->address));
690 set_unix_address(&self->address, 1);
691 }
692
FIXTURE_TEARDOWN(outside_socket)693 FIXTURE_TEARDOWN(outside_socket)
694 {
695 }
696
697 /*
698 * Test unix_stream_connect and unix_may_send for parent and child processes
699 * when connecting socket has different domain than the process using it.
700 */
TEST_F(outside_socket,socket_with_different_domain)701 TEST_F(outside_socket, socket_with_different_domain)
702 {
703 pid_t child;
704 int err, status;
705 int pipe_child[2], pipe_parent[2];
706 char buf_parent;
707 int server_socket;
708
709 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
710 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
711
712 child = fork();
713 ASSERT_LE(0, child);
714 if (child == 0) {
715 int client_socket;
716 char buf_child;
717
718 EXPECT_EQ(0, close(pipe_parent[1]));
719 EXPECT_EQ(0, close(pipe_child[0]));
720
721 /* Client always has a domain. */
722 create_scoped_domain(_metadata,
723 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
724
725 if (variant->child_socket) {
726 int data_socket, passed_socket, stream_server;
727
728 passed_socket = socket(AF_UNIX, variant->type, 0);
729 ASSERT_LE(0, passed_socket);
730 stream_server = socket(AF_UNIX, SOCK_STREAM, 0);
731 ASSERT_LE(0, stream_server);
732 ASSERT_EQ(0, bind(stream_server,
733 &self->transit_address.unix_addr,
734 self->transit_address.unix_addr_len));
735 ASSERT_EQ(0, listen(stream_server, backlog));
736 ASSERT_EQ(1, write(pipe_child[1], ".", 1));
737 data_socket = accept(stream_server, NULL, NULL);
738 ASSERT_LE(0, data_socket);
739 ASSERT_EQ(0, send_fd(data_socket, passed_socket));
740 EXPECT_EQ(0, close(passed_socket));
741 EXPECT_EQ(0, close(stream_server));
742 }
743
744 client_socket = socket(AF_UNIX, variant->type, 0);
745 ASSERT_LE(0, client_socket);
746
747 /* Waits for parent signal for connection. */
748 ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
749 err = connect(client_socket, &self->address.unix_addr,
750 self->address.unix_addr_len);
751 if (variant->child_socket) {
752 EXPECT_EQ(0, err);
753 } else {
754 EXPECT_EQ(-1, err);
755 EXPECT_EQ(EPERM, errno);
756 }
757 EXPECT_EQ(0, close(client_socket));
758 _exit(_metadata->exit_code);
759 return;
760 }
761 EXPECT_EQ(0, close(pipe_child[1]));
762 EXPECT_EQ(0, close(pipe_parent[0]));
763
764 if (variant->child_socket) {
765 int client_child = socket(AF_UNIX, SOCK_STREAM, 0);
766
767 ASSERT_LE(0, client_child);
768 ASSERT_EQ(1, read(pipe_child[0], &buf_parent, 1));
769 ASSERT_EQ(0, connect(client_child,
770 &self->transit_address.unix_addr,
771 self->transit_address.unix_addr_len));
772 server_socket = recv_fd(client_child);
773 EXPECT_EQ(0, close(client_child));
774 } else {
775 server_socket = socket(AF_UNIX, variant->type, 0);
776 }
777 ASSERT_LE(0, server_socket);
778
779 /* Server always has a domain. */
780 create_scoped_domain(_metadata, LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
781
782 ASSERT_EQ(0, bind(server_socket, &self->address.unix_addr,
783 self->address.unix_addr_len));
784 if (variant->type == SOCK_STREAM)
785 ASSERT_EQ(0, listen(server_socket, backlog));
786
787 /* Signals to child that the parent is listening. */
788 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
789
790 ASSERT_EQ(child, waitpid(child, &status, 0));
791 EXPECT_EQ(0, close(server_socket));
792
793 if (WIFSIGNALED(status) || !WIFEXITED(status) ||
794 WEXITSTATUS(status) != EXIT_SUCCESS)
795 _metadata->exit_code = KSFT_FAIL;
796 }
797
798 static const char stream_path[] = TMP_DIR "/stream.sock";
799 static const char dgram_path[] = TMP_DIR "/dgram.sock";
800
801 /* clang-format off */
FIXTURE(various_address_sockets)802 FIXTURE(various_address_sockets) {};
803 /* clang-format on */
804
FIXTURE_VARIANT(various_address_sockets)805 FIXTURE_VARIANT(various_address_sockets)
806 {
807 const int domain;
808 };
809
810 /* clang-format off */
FIXTURE_VARIANT_ADD(various_address_sockets,pathname_socket_scoped_domain)811 FIXTURE_VARIANT_ADD(various_address_sockets, pathname_socket_scoped_domain) {
812 /* clang-format on */
813 .domain = SCOPE_SANDBOX,
814 };
815
816 /* clang-format off */
FIXTURE_VARIANT_ADD(various_address_sockets,pathname_socket_other_domain)817 FIXTURE_VARIANT_ADD(various_address_sockets, pathname_socket_other_domain) {
818 /* clang-format on */
819 .domain = OTHER_SANDBOX,
820 };
821
822 /* clang-format off */
FIXTURE_VARIANT_ADD(various_address_sockets,pathname_socket_no_domain)823 FIXTURE_VARIANT_ADD(various_address_sockets, pathname_socket_no_domain) {
824 /* clang-format on */
825 .domain = NO_SANDBOX,
826 };
827
FIXTURE_SETUP(various_address_sockets)828 FIXTURE_SETUP(various_address_sockets)
829 {
830 drop_caps(_metadata);
831
832 umask(0077);
833 ASSERT_EQ(0, mkdir(TMP_DIR, 0700));
834 }
835
FIXTURE_TEARDOWN(various_address_sockets)836 FIXTURE_TEARDOWN(various_address_sockets)
837 {
838 EXPECT_EQ(0, unlink(stream_path));
839 EXPECT_EQ(0, unlink(dgram_path));
840 EXPECT_EQ(0, rmdir(TMP_DIR));
841 }
842
TEST_F(various_address_sockets,scoped_pathname_sockets)843 TEST_F(various_address_sockets, scoped_pathname_sockets)
844 {
845 pid_t child;
846 int status;
847 char buf_child, buf_parent;
848 int pipe_parent[2];
849 int unnamed_sockets[2];
850 int stream_pathname_socket, dgram_pathname_socket,
851 stream_abstract_socket, dgram_abstract_socket, data_socket;
852 struct service_fixture stream_abstract_addr, dgram_abstract_addr;
853 struct sockaddr_un stream_pathname_addr = {
854 .sun_family = AF_UNIX,
855 };
856 struct sockaddr_un dgram_pathname_addr = {
857 .sun_family = AF_UNIX,
858 };
859
860 /* Pathname address. */
861 snprintf(stream_pathname_addr.sun_path,
862 sizeof(stream_pathname_addr.sun_path), "%s", stream_path);
863 snprintf(dgram_pathname_addr.sun_path,
864 sizeof(dgram_pathname_addr.sun_path), "%s", dgram_path);
865
866 /* Abstract address. */
867 memset(&stream_abstract_addr, 0, sizeof(stream_abstract_addr));
868 set_unix_address(&stream_abstract_addr, 0);
869 memset(&dgram_abstract_addr, 0, sizeof(dgram_abstract_addr));
870 set_unix_address(&dgram_abstract_addr, 1);
871
872 /* Unnamed address for datagram socket. */
873 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_DGRAM, 0, unnamed_sockets));
874
875 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
876
877 child = fork();
878 ASSERT_LE(0, child);
879 if (child == 0) {
880 int err;
881
882 EXPECT_EQ(0, close(pipe_parent[1]));
883 EXPECT_EQ(0, close(unnamed_sockets[1]));
884
885 if (variant->domain == SCOPE_SANDBOX)
886 create_scoped_domain(
887 _metadata, LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
888 else if (variant->domain == OTHER_SANDBOX)
889 create_fs_domain(_metadata);
890
891 /* Waits for parent to listen. */
892 ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
893 EXPECT_EQ(0, close(pipe_parent[0]));
894
895 /* Checks that we can send data through a datagram socket. */
896 ASSERT_EQ(1, write(unnamed_sockets[0], "a", 1));
897 EXPECT_EQ(0, close(unnamed_sockets[0]));
898
899 /* Connects with pathname sockets. */
900 stream_pathname_socket = socket(AF_UNIX, SOCK_STREAM, 0);
901 ASSERT_LE(0, stream_pathname_socket);
902 ASSERT_EQ(0,
903 connect(stream_pathname_socket, &stream_pathname_addr,
904 sizeof(stream_pathname_addr)));
905 ASSERT_EQ(1, write(stream_pathname_socket, "b", 1));
906 EXPECT_EQ(0, close(stream_pathname_socket));
907
908 /* Sends without connection. */
909 dgram_pathname_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
910 ASSERT_LE(0, dgram_pathname_socket);
911 err = sendto(dgram_pathname_socket, "c", 1, 0,
912 &dgram_pathname_addr, sizeof(dgram_pathname_addr));
913 EXPECT_EQ(1, err);
914
915 /* Sends with connection. */
916 ASSERT_EQ(0,
917 connect(dgram_pathname_socket, &dgram_pathname_addr,
918 sizeof(dgram_pathname_addr)));
919 ASSERT_EQ(1, write(dgram_pathname_socket, "d", 1));
920 EXPECT_EQ(0, close(dgram_pathname_socket));
921
922 /* Connects with abstract sockets. */
923 stream_abstract_socket = socket(AF_UNIX, SOCK_STREAM, 0);
924 ASSERT_LE(0, stream_abstract_socket);
925 err = connect(stream_abstract_socket,
926 &stream_abstract_addr.unix_addr,
927 stream_abstract_addr.unix_addr_len);
928 if (variant->domain == SCOPE_SANDBOX) {
929 EXPECT_EQ(-1, err);
930 EXPECT_EQ(EPERM, errno);
931 } else {
932 EXPECT_EQ(0, err);
933 ASSERT_EQ(1, write(stream_abstract_socket, "e", 1));
934 }
935 EXPECT_EQ(0, close(stream_abstract_socket));
936
937 /* Sends without connection. */
938 dgram_abstract_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
939 ASSERT_LE(0, dgram_abstract_socket);
940 err = sendto(dgram_abstract_socket, "f", 1, 0,
941 &dgram_abstract_addr.unix_addr,
942 dgram_abstract_addr.unix_addr_len);
943 if (variant->domain == SCOPE_SANDBOX) {
944 EXPECT_EQ(-1, err);
945 EXPECT_EQ(EPERM, errno);
946 } else {
947 EXPECT_EQ(1, err);
948 }
949
950 /* Sends with connection. */
951 err = connect(dgram_abstract_socket,
952 &dgram_abstract_addr.unix_addr,
953 dgram_abstract_addr.unix_addr_len);
954 if (variant->domain == SCOPE_SANDBOX) {
955 EXPECT_EQ(-1, err);
956 EXPECT_EQ(EPERM, errno);
957 } else {
958 EXPECT_EQ(0, err);
959 ASSERT_EQ(1, write(dgram_abstract_socket, "g", 1));
960 }
961 EXPECT_EQ(0, close(dgram_abstract_socket));
962
963 _exit(_metadata->exit_code);
964 return;
965 }
966 EXPECT_EQ(0, close(pipe_parent[0]));
967 EXPECT_EQ(0, close(unnamed_sockets[0]));
968
969 /* Sets up pathname servers. */
970 stream_pathname_socket = socket(AF_UNIX, SOCK_STREAM, 0);
971 ASSERT_LE(0, stream_pathname_socket);
972 ASSERT_EQ(0, bind(stream_pathname_socket, &stream_pathname_addr,
973 sizeof(stream_pathname_addr)));
974 ASSERT_EQ(0, listen(stream_pathname_socket, backlog));
975
976 dgram_pathname_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
977 ASSERT_LE(0, dgram_pathname_socket);
978 ASSERT_EQ(0, bind(dgram_pathname_socket, &dgram_pathname_addr,
979 sizeof(dgram_pathname_addr)));
980
981 /* Sets up abstract servers. */
982 stream_abstract_socket = socket(AF_UNIX, SOCK_STREAM, 0);
983 ASSERT_LE(0, stream_abstract_socket);
984 ASSERT_EQ(0,
985 bind(stream_abstract_socket, &stream_abstract_addr.unix_addr,
986 stream_abstract_addr.unix_addr_len));
987
988 dgram_abstract_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
989 ASSERT_LE(0, dgram_abstract_socket);
990 ASSERT_EQ(0, bind(dgram_abstract_socket, &dgram_abstract_addr.unix_addr,
991 dgram_abstract_addr.unix_addr_len));
992 ASSERT_EQ(0, listen(stream_abstract_socket, backlog));
993
994 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
995 EXPECT_EQ(0, close(pipe_parent[1]));
996
997 /* Reads from unnamed socket. */
998 ASSERT_EQ(1, read(unnamed_sockets[1], &buf_parent, sizeof(buf_parent)));
999 ASSERT_EQ('a', buf_parent);
1000 EXPECT_LE(0, close(unnamed_sockets[1]));
1001
1002 /* Reads from pathname sockets. */
1003 data_socket = accept(stream_pathname_socket, NULL, NULL);
1004 ASSERT_LE(0, data_socket);
1005 ASSERT_EQ(1, read(data_socket, &buf_parent, sizeof(buf_parent)));
1006 ASSERT_EQ('b', buf_parent);
1007 EXPECT_EQ(0, close(data_socket));
1008 EXPECT_EQ(0, close(stream_pathname_socket));
1009
1010 ASSERT_EQ(1,
1011 read(dgram_pathname_socket, &buf_parent, sizeof(buf_parent)));
1012 ASSERT_EQ('c', buf_parent);
1013 ASSERT_EQ(1,
1014 read(dgram_pathname_socket, &buf_parent, sizeof(buf_parent)));
1015 ASSERT_EQ('d', buf_parent);
1016 EXPECT_EQ(0, close(dgram_pathname_socket));
1017
1018 if (variant->domain != SCOPE_SANDBOX) {
1019 /* Reads from abstract sockets if allowed to send. */
1020 data_socket = accept(stream_abstract_socket, NULL, NULL);
1021 ASSERT_LE(0, data_socket);
1022 ASSERT_EQ(1,
1023 read(data_socket, &buf_parent, sizeof(buf_parent)));
1024 ASSERT_EQ('e', buf_parent);
1025 EXPECT_EQ(0, close(data_socket));
1026
1027 ASSERT_EQ(1, read(dgram_abstract_socket, &buf_parent,
1028 sizeof(buf_parent)));
1029 ASSERT_EQ('f', buf_parent);
1030 ASSERT_EQ(1, read(dgram_abstract_socket, &buf_parent,
1031 sizeof(buf_parent)));
1032 ASSERT_EQ('g', buf_parent);
1033 }
1034
1035 /* Waits for all abstract socket tests. */
1036 ASSERT_EQ(child, waitpid(child, &status, 0));
1037 EXPECT_EQ(0, close(stream_abstract_socket));
1038 EXPECT_EQ(0, close(dgram_abstract_socket));
1039
1040 if (WIFSIGNALED(status) || !WIFEXITED(status) ||
1041 WEXITSTATUS(status) != EXIT_SUCCESS)
1042 _metadata->exit_code = KSFT_FAIL;
1043 }
1044
TEST(datagram_sockets)1045 TEST(datagram_sockets)
1046 {
1047 struct service_fixture connected_addr, non_connected_addr;
1048 int server_conn_socket, server_unconn_socket;
1049 int pipe_parent[2], pipe_child[2];
1050 int status;
1051 char buf;
1052 pid_t child;
1053
1054 drop_caps(_metadata);
1055 memset(&connected_addr, 0, sizeof(connected_addr));
1056 set_unix_address(&connected_addr, 0);
1057 memset(&non_connected_addr, 0, sizeof(non_connected_addr));
1058 set_unix_address(&non_connected_addr, 1);
1059
1060 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
1061 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
1062
1063 child = fork();
1064 ASSERT_LE(0, child);
1065 if (child == 0) {
1066 int client_conn_socket, client_unconn_socket;
1067
1068 EXPECT_EQ(0, close(pipe_parent[1]));
1069 EXPECT_EQ(0, close(pipe_child[0]));
1070
1071 client_conn_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
1072 client_unconn_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
1073 ASSERT_LE(0, client_conn_socket);
1074 ASSERT_LE(0, client_unconn_socket);
1075
1076 /* Waits for parent to listen. */
1077 ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));
1078 ASSERT_EQ(0,
1079 connect(client_conn_socket, &connected_addr.unix_addr,
1080 connected_addr.unix_addr_len));
1081
1082 /*
1083 * Both connected and non-connected sockets can send data when
1084 * the domain is not scoped.
1085 */
1086 ASSERT_EQ(1, send(client_conn_socket, ".", 1, 0));
1087 ASSERT_EQ(1, sendto(client_unconn_socket, ".", 1, 0,
1088 &non_connected_addr.unix_addr,
1089 non_connected_addr.unix_addr_len));
1090 ASSERT_EQ(1, write(pipe_child[1], ".", 1));
1091
1092 /* Scopes the domain. */
1093 create_scoped_domain(_metadata,
1094 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
1095
1096 /*
1097 * Connected socket sends data to the receiver, but the
1098 * non-connected socket must fail to send data.
1099 */
1100 ASSERT_EQ(1, send(client_conn_socket, ".", 1, 0));
1101 ASSERT_EQ(-1, sendto(client_unconn_socket, ".", 1, 0,
1102 &non_connected_addr.unix_addr,
1103 non_connected_addr.unix_addr_len));
1104 ASSERT_EQ(EPERM, errno);
1105 ASSERT_EQ(1, write(pipe_child[1], ".", 1));
1106
1107 EXPECT_EQ(0, close(client_conn_socket));
1108 EXPECT_EQ(0, close(client_unconn_socket));
1109 _exit(_metadata->exit_code);
1110 return;
1111 }
1112 EXPECT_EQ(0, close(pipe_parent[0]));
1113 EXPECT_EQ(0, close(pipe_child[1]));
1114
1115 server_conn_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
1116 server_unconn_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
1117 ASSERT_LE(0, server_conn_socket);
1118 ASSERT_LE(0, server_unconn_socket);
1119
1120 ASSERT_EQ(0, bind(server_conn_socket, &connected_addr.unix_addr,
1121 connected_addr.unix_addr_len));
1122 ASSERT_EQ(0, bind(server_unconn_socket, &non_connected_addr.unix_addr,
1123 non_connected_addr.unix_addr_len));
1124 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
1125
1126 /* Waits for child to test. */
1127 ASSERT_EQ(1, read(pipe_child[0], &buf, 1));
1128 ASSERT_EQ(1, recv(server_conn_socket, &buf, 1, 0));
1129 ASSERT_EQ(1, recv(server_unconn_socket, &buf, 1, 0));
1130
1131 /*
1132 * Connected datagram socket will receive data, but
1133 * non-connected datagram socket does not receive data.
1134 */
1135 ASSERT_EQ(1, read(pipe_child[0], &buf, 1));
1136 ASSERT_EQ(1, recv(server_conn_socket, &buf, 1, 0));
1137
1138 /* Waits for all tests to finish. */
1139 ASSERT_EQ(child, waitpid(child, &status, 0));
1140 EXPECT_EQ(0, close(server_conn_socket));
1141 EXPECT_EQ(0, close(server_unconn_socket));
1142
1143 if (WIFSIGNALED(status) || !WIFEXITED(status) ||
1144 WEXITSTATUS(status) != EXIT_SUCCESS)
1145 _metadata->exit_code = KSFT_FAIL;
1146 }
1147
TEST(self_connect)1148 TEST(self_connect)
1149 {
1150 struct service_fixture connected_addr, non_connected_addr;
1151 int connected_socket, non_connected_socket, status;
1152 pid_t child;
1153
1154 drop_caps(_metadata);
1155 memset(&connected_addr, 0, sizeof(connected_addr));
1156 set_unix_address(&connected_addr, 0);
1157 memset(&non_connected_addr, 0, sizeof(non_connected_addr));
1158 set_unix_address(&non_connected_addr, 1);
1159
1160 connected_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
1161 non_connected_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
1162 ASSERT_LE(0, connected_socket);
1163 ASSERT_LE(0, non_connected_socket);
1164
1165 ASSERT_EQ(0, bind(connected_socket, &connected_addr.unix_addr,
1166 connected_addr.unix_addr_len));
1167 ASSERT_EQ(0, bind(non_connected_socket, &non_connected_addr.unix_addr,
1168 non_connected_addr.unix_addr_len));
1169
1170 child = fork();
1171 ASSERT_LE(0, child);
1172 if (child == 0) {
1173 /* Child's domain is scoped. */
1174 create_scoped_domain(_metadata,
1175 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
1176
1177 /*
1178 * The child inherits the sockets, and cannot connect or
1179 * send data to them.
1180 */
1181 ASSERT_EQ(-1,
1182 connect(connected_socket, &connected_addr.unix_addr,
1183 connected_addr.unix_addr_len));
1184 ASSERT_EQ(EPERM, errno);
1185
1186 ASSERT_EQ(-1, sendto(connected_socket, ".", 1, 0,
1187 &connected_addr.unix_addr,
1188 connected_addr.unix_addr_len));
1189 ASSERT_EQ(EPERM, errno);
1190
1191 ASSERT_EQ(-1, sendto(non_connected_socket, ".", 1, 0,
1192 &non_connected_addr.unix_addr,
1193 non_connected_addr.unix_addr_len));
1194 ASSERT_EQ(EPERM, errno);
1195
1196 EXPECT_EQ(0, close(connected_socket));
1197 EXPECT_EQ(0, close(non_connected_socket));
1198 _exit(_metadata->exit_code);
1199 return;
1200 }
1201
1202 /* Waits for all tests to finish. */
1203 ASSERT_EQ(child, waitpid(child, &status, 0));
1204 EXPECT_EQ(0, close(connected_socket));
1205 EXPECT_EQ(0, close(non_connected_socket));
1206
1207 if (WIFSIGNALED(status) || !WIFEXITED(status) ||
1208 WEXITSTATUS(status) != EXIT_SUCCESS)
1209 _metadata->exit_code = KSFT_FAIL;
1210 }
1211
1212 /* Trace tests */
1213
1214 /* clang-format off */
FIXTURE(trace_unix)1215 FIXTURE(trace_unix) {
1216 /* clang-format on */
1217 int tracefs_ok;
1218 };
1219
FIXTURE_SETUP(trace_unix)1220 FIXTURE_SETUP(trace_unix)
1221 {
1222 int ret;
1223
1224 set_cap(_metadata, CAP_SYS_ADMIN);
1225 ASSERT_EQ(0, unshare(CLONE_NEWNS | CLONE_NEWNET));
1226 ASSERT_EQ(0, mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL));
1227
1228 ret = tracefs_fixture_setup();
1229 if (ret) {
1230 clear_cap(_metadata, CAP_SYS_ADMIN);
1231 self->tracefs_ok = 0;
1232 SKIP(return, "tracefs not available");
1233 }
1234 self->tracefs_ok = 1;
1235
1236 ASSERT_EQ(0, tracefs_enable_event(
1237 TRACEFS_DENY_SCOPE_ABSTRACT_UNIX_SOCKET_ENABLE,
1238 true));
1239 ASSERT_EQ(0, tracefs_clear());
1240 clear_cap(_metadata, CAP_SYS_ADMIN);
1241 }
1242
FIXTURE_TEARDOWN(trace_unix)1243 FIXTURE_TEARDOWN(trace_unix)
1244 {
1245 if (!self->tracefs_ok)
1246 return;
1247
1248 set_cap(_metadata, CAP_SYS_ADMIN);
1249 tracefs_enable_event(TRACEFS_DENY_SCOPE_ABSTRACT_UNIX_SOCKET_ENABLE,
1250 false);
1251 tracefs_fixture_teardown();
1252 clear_cap(_metadata, CAP_SYS_ADMIN);
1253 }
1254
1255 static const char
1256 trace_unix_max_name[sizeof(((struct sockaddr_un *)0)->sun_path)] = {
1257 [0 ... sizeof(trace_unix_max_name) - 2] = 'x',
1258 };
1259
1260 /* clang-format off */
FIXTURE_VARIANT(trace_unix)1261 FIXTURE_VARIANT(trace_unix) {
1262 /* clang-format on */
1263 int sock_type; /* SOCK_STREAM (connect) or SOCK_DGRAM (sendto). */
1264 bool sandbox;
1265 bool sandbox_target; /* Peer owned by a domain: peer_domain != 0. */
1266 int expect_denied;
1267 const char *name; /* NULL generates a PID-based binary name. */
1268 size_t name_len;
1269 };
1270
1271 /* clang-format off */
1272
1273 /* Stream: sandboxed client connect() to an unsandboxed peer (peer_domain=0). */
FIXTURE_VARIANT_ADD(trace_unix,stream_denied)1274 FIXTURE_VARIANT_ADD(trace_unix, stream_denied) {
1275 .sock_type = SOCK_STREAM, .sandbox = true,
1276 .sandbox_target = false, .expect_denied = 1,
1277 };
1278
1279 /* Stream: peer socket owned by a domain, so peer_domain != 0. */
FIXTURE_VARIANT_ADD(trace_unix,stream_denied_scoped_peer)1280 FIXTURE_VARIANT_ADD(trace_unix, stream_denied_scoped_peer) {
1281 .sock_type = SOCK_STREAM, .sandbox = true,
1282 .sandbox_target = true, .expect_denied = 1,
1283 };
1284
1285 /* Stream: unsandboxed client, connect() succeeds, no event. */
FIXTURE_VARIANT_ADD(trace_unix,stream_allowed)1286 FIXTURE_VARIANT_ADD(trace_unix, stream_allowed) {
1287 .sock_type = SOCK_STREAM, .sandbox = false,
1288 .sandbox_target = false, .expect_denied = 0,
1289 };
1290
1291 /* Stream: lower abstract-name length boundary. */
FIXTURE_VARIANT_ADD(trace_unix,stream_denied_empty_name)1292 FIXTURE_VARIANT_ADD(trace_unix, stream_denied_empty_name) {
1293 .sock_type = SOCK_STREAM,
1294 .sandbox = true,
1295 .sandbox_target = false,
1296 .expect_denied = 1,
1297 .name = "",
1298 .name_len = 0,
1299 };
1300
1301 /* Stream: upper abstract-name length boundary. */
FIXTURE_VARIANT_ADD(trace_unix,stream_denied_max_name)1302 FIXTURE_VARIANT_ADD(trace_unix, stream_denied_max_name) {
1303 .sock_type = SOCK_STREAM,
1304 .sandbox = true,
1305 .sandbox_target = false,
1306 .expect_denied = 1,
1307 .name = trace_unix_max_name,
1308 .name_len = sizeof(trace_unix_max_name) - 1,
1309 };
1310
1311 /* Datagram: sandboxed client sendto() an unsandboxed peer (peer_domain=0). */
FIXTURE_VARIANT_ADD(trace_unix,dgram_denied)1312 FIXTURE_VARIANT_ADD(trace_unix, dgram_denied) {
1313 .sock_type = SOCK_DGRAM, .sandbox = true,
1314 .sandbox_target = false, .expect_denied = 1,
1315 };
1316
1317 /* Datagram: peer socket owned by a domain, so peer_domain != 0. */
FIXTURE_VARIANT_ADD(trace_unix,dgram_denied_scoped_peer)1318 FIXTURE_VARIANT_ADD(trace_unix, dgram_denied_scoped_peer) {
1319 .sock_type = SOCK_DGRAM, .sandbox = true,
1320 .sandbox_target = true, .expect_denied = 1,
1321 };
1322
1323 /* Datagram: unsandboxed client, sendto() succeeds, no event. */
FIXTURE_VARIANT_ADD(trace_unix,dgram_allowed)1324 FIXTURE_VARIANT_ADD(trace_unix, dgram_allowed) {
1325 .sock_type = SOCK_DGRAM, .sandbox = false,
1326 .sandbox_target = false, .expect_denied = 0,
1327 };
1328
1329 /* clang-format on */
1330
1331 /*
1332 * A sandboxed thread reaching an abstract unix socket peer through connect(2)
1333 * (stream) or sendto(2) (datagram) is denied and emits
1334 * landlock_deny_scope_abstract_unix_socket. The default abstract name has a
1335 * space and an embedded NUL followed by an "END" marker to check escaping and
1336 * binary length handling. Additional stream variants cover the minimum and
1337 * maximum abstract-name lengths. peer_pid is only meaningful for a stream peer
1338 * (a datagram peer has no SO_PEERCRED), so it is asserted only there.
1339 */
TEST_F(trace_unix,deny_scope_unix)1340 TEST_F(trace_unix, deny_scope_unix)
1341 {
1342 struct sockaddr_un addr = {
1343 .sun_family = AF_UNIX,
1344 };
1345 char *buf, field[128], expected_pid[16];
1346 int server_fd, count, status, name_len, addr_len;
1347 pid_t child;
1348
1349 if (!self->tracefs_ok)
1350 SKIP(return, "tracefs not available");
1351
1352 /*
1353 * For the non-zero peer_domain case, sandbox the parent before it
1354 * creates the server socket, so the socket carries the parent's domain
1355 * and peer_domain= is non-zero.
1356 */
1357 if (variant->sandbox_target)
1358 create_scoped_domain(_metadata,
1359 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
1360
1361 server_fd = socket(AF_UNIX, variant->sock_type | SOCK_CLOEXEC, 0);
1362 ASSERT_LE(0, server_fd);
1363
1364 addr.sun_path[0] = '\0';
1365 if (variant->name) {
1366 ASSERT_LE(variant->name_len, sizeof(addr.sun_path) - 1);
1367 memcpy(addr.sun_path + 1, variant->name, variant->name_len);
1368 name_len = variant->name_len;
1369 } else {
1370 name_len = snprintf(addr.sun_path + 1,
1371 sizeof(addr.sun_path) - 1,
1372 "landlock_trace_test_%d ", getpid());
1373 addr.sun_path[1 + name_len] = '\0';
1374 memcpy(addr.sun_path + 1 + name_len + 1, "END", 3);
1375 name_len += 1 + 3;
1376 }
1377 addr_len = offsetof(struct sockaddr_un, sun_path) + 1 + name_len;
1378
1379 ASSERT_EQ(0, bind(server_fd, (struct sockaddr *)&addr, addr_len));
1380 if (variant->sock_type == SOCK_STREAM)
1381 ASSERT_EQ(0, listen(server_fd, 1));
1382
1383 child = fork();
1384 ASSERT_LE(0, child);
1385
1386 if (child == 0) {
1387 int client_fd, ret;
1388
1389 if (variant->sandbox) {
1390 struct landlock_ruleset_attr ruleset_attr = {
1391 .scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
1392 };
1393 int ruleset_fd;
1394
1395 ruleset_fd = landlock_create_ruleset(
1396 &ruleset_attr, sizeof(ruleset_attr), 0);
1397 if (ruleset_fd < 0)
1398 _exit(1);
1399
1400 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1401 if (landlock_restrict_self(ruleset_fd, 0)) {
1402 close(ruleset_fd);
1403 _exit(1);
1404 }
1405 close(ruleset_fd);
1406 }
1407
1408 client_fd =
1409 socket(AF_UNIX, variant->sock_type | SOCK_CLOEXEC, 0);
1410 if (client_fd < 0)
1411 _exit(1);
1412
1413 if (variant->sock_type == SOCK_STREAM)
1414 ret = connect(client_fd, (struct sockaddr *)&addr,
1415 addr_len);
1416 else
1417 ret = sendto(client_fd, ".", 1, 0,
1418 (struct sockaddr *)&addr, addr_len);
1419
1420 if (variant->sandbox) {
1421 /* Reaching the peer should be denied. */
1422 if (ret != -1 || errno != EPERM) {
1423 close(client_fd);
1424 _exit(2);
1425 }
1426 } else {
1427 /* No sandbox: stream connect() == 0, sendto() == 1. */
1428 int ok = variant->sock_type == SOCK_STREAM ? 0 : 1;
1429
1430 if (ret != ok) {
1431 close(client_fd);
1432 _exit(2);
1433 }
1434 }
1435 close(client_fd);
1436 _exit(0);
1437 }
1438
1439 ASSERT_EQ(child, waitpid(child, &status, 0));
1440 ASSERT_TRUE(WIFEXITED(status));
1441 EXPECT_EQ(0, WEXITSTATUS(status));
1442 close(server_fd);
1443
1444 buf = tracefs_read_buf();
1445 ASSERT_NE(NULL, buf);
1446
1447 count = tracefs_count_matches(
1448 buf, REGEX_DENY_SCOPE_ABSTRACT_UNIX_SOCKET(TRACE_TASK));
1449 if (!variant->expect_denied) {
1450 EXPECT_EQ(0, count)
1451 {
1452 TH_LOG("Expected 0 deny_scope events, got %d\n%s",
1453 count, buf);
1454 }
1455 free(buf);
1456 return;
1457 }
1458
1459 EXPECT_EQ(variant->expect_denied, count)
1460 {
1461 TH_LOG("Expected deny_scope_abstract_unix_socket event, "
1462 "got %d\n%s",
1463 count, buf);
1464 }
1465
1466 ASSERT_EQ(0, tracefs_extract_field(
1467 buf,
1468 REGEX_DENY_SCOPE_ABSTRACT_UNIX_SOCKET(TRACE_TASK),
1469 "sun_path", field, sizeof(field)));
1470 if (variant->name) {
1471 EXPECT_STREQ(variant->name, field);
1472 } else {
1473 /* An embedded NUL must not truncate the following marker. */
1474 EXPECT_NE(NULL, strstr(field, "END"))
1475 {
1476 TH_LOG("sun_path truncated or unescaped: %s", field);
1477 }
1478 }
1479
1480 /* peer_pid is the parent's PID for a stream peer (0 for datagram). */
1481 if (variant->sock_type == SOCK_STREAM) {
1482 snprintf(expected_pid, sizeof(expected_pid), "%d", getpid());
1483 ASSERT_EQ(0, tracefs_extract_field(
1484 buf,
1485 REGEX_DENY_SCOPE_ABSTRACT_UNIX_SOCKET(
1486 TRACE_TASK),
1487 "peer_pid", field, sizeof(field)));
1488 EXPECT_STREQ(expected_pid, field);
1489 }
1490
1491 /* peer_domain: 0 when the peer is unsandboxed, non-zero otherwise. */
1492 ASSERT_EQ(0, tracefs_extract_field(
1493 buf,
1494 REGEX_DENY_SCOPE_ABSTRACT_UNIX_SOCKET(TRACE_TASK),
1495 "peer_domain", field, sizeof(field)));
1496 EXPECT_EQ(variant->sandbox_target, strcmp("0", field) != 0)
1497 {
1498 TH_LOG("Unexpected peer_domain=%s", field);
1499 }
1500
1501 free(buf);
1502 }
1503
1504 TEST_HARNESS_MAIN
1505