1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Landlock tests - Network
4 *
5 * Copyright © 2022-2023 Huawei Tech. Co., Ltd.
6 * Copyright © 2023 Microsoft Corporation
7 */
8
9#define _GNU_SOURCE
10#include <arpa/inet.h>
11#include <errno.h>
12#include <fcntl.h>
13#include <linux/landlock.h>
14#include <linux/in.h>
15#include <sched.h>
16#include <stdint.h>
17#include <string.h>
18#include <sys/prctl.h>
19#include <sys/socket.h>
20#include <sys/syscall.h>
21#include <sys/un.h>
22
23#include "common.h"
24
25const short sock_port_start = (1 << 10);
26
27static const char loopback_ipv4[] = "127.0.0.1";
28static const char loopback_ipv6[] = "::1";
29
30/* Number pending connections queue to be hold. */
31const short backlog = 10;
32
33enum sandbox_type {
34 NO_SANDBOX,
35 /* This may be used to test rules that allow *and* deny accesses. */
36 TCP_SANDBOX,
37};
38
39struct protocol_variant {
40 int domain;
41 int type;
42};
43
44struct service_fixture {
45 struct protocol_variant protocol;
46 /* port is also stored in ipv4_addr.sin_port or ipv6_addr.sin6_port */
47 unsigned short port;
48 union {
49 struct sockaddr_in ipv4_addr;
50 struct sockaddr_in6 ipv6_addr;
51 struct {
52 struct sockaddr_un unix_addr;
53 socklen_t unix_addr_len;
54 };
55 };
56};
57
58static pid_t sys_gettid(void)
59{
60 return syscall(__NR_gettid);
61}
62
63static int set_service(struct service_fixture *const srv,
64 const struct protocol_variant prot,
65 const unsigned short index)
66{
67 memset(srv, 0, sizeof(*srv));
68
69 /*
70 * Copies all protocol properties in case of the variant only contains
71 * a subset of them.
72 */
73 srv->protocol = prot;
74
75 /* Checks for port overflow. */
76 if (index > 2)
77 return 1;
78 srv->port = sock_port_start << (2 * index);
79
80 switch (prot.domain) {
81 case AF_UNSPEC:
82 case AF_INET:
83 srv->ipv4_addr.sin_family = prot.domain;
84 srv->ipv4_addr.sin_port = htons(srv->port);
85 srv->ipv4_addr.sin_addr.s_addr = inet_addr(loopback_ipv4);
86 return 0;
87
88 case AF_INET6:
89 srv->ipv6_addr.sin6_family = prot.domain;
90 srv->ipv6_addr.sin6_port = htons(srv->port);
91 inet_pton(AF_INET6, loopback_ipv6, &srv->ipv6_addr.sin6_addr);
92 return 0;
93
94 case AF_UNIX:
95 srv->unix_addr.sun_family = prot.domain;
96 sprintf(buf: srv->unix_addr.sun_path,
97 fmt: "_selftests-landlock-net-tid%d-index%d", sys_gettid(),
98 index);
99 srv->unix_addr_len = SUN_LEN(&srv->unix_addr);
100 srv->unix_addr.sun_path[0] = '\0';
101 return 0;
102 }
103 return 1;
104}
105
106static void setup_loopback(struct __test_metadata *const _metadata)
107{
108 set_cap(_metadata, CAP_SYS_ADMIN);
109 ASSERT_EQ(0, unshare(CLONE_NEWNET));
110 clear_cap(_metadata, CAP_SYS_ADMIN);
111
112 set_ambient_cap(_metadata, CAP_NET_ADMIN);
113 ASSERT_EQ(0, system("ip link set dev lo up"));
114 clear_ambient_cap(_metadata, CAP_NET_ADMIN);
115}
116
117static bool is_restricted(const struct protocol_variant *const prot,
118 const enum sandbox_type sandbox)
119{
120 switch (prot->domain) {
121 case AF_INET:
122 case AF_INET6:
123 switch (prot->type) {
124 case SOCK_STREAM:
125 return sandbox == TCP_SANDBOX;
126 }
127 break;
128 }
129 return false;
130}
131
132static int socket_variant(const struct service_fixture *const srv)
133{
134 int ret;
135
136 ret = socket(srv->protocol.domain, srv->protocol.type | SOCK_CLOEXEC,
137 0);
138 if (ret < 0)
139 return -errno;
140 return ret;
141}
142
143#ifndef SIN6_LEN_RFC2133
144#define SIN6_LEN_RFC2133 24
145#endif
146
147static socklen_t get_addrlen(const struct service_fixture *const srv,
148 const bool minimal)
149{
150 switch (srv->protocol.domain) {
151 case AF_UNSPEC:
152 case AF_INET:
153 return sizeof(srv->ipv4_addr);
154
155 case AF_INET6:
156 if (minimal)
157 return SIN6_LEN_RFC2133;
158 return sizeof(srv->ipv6_addr);
159
160 case AF_UNIX:
161 if (minimal)
162 return sizeof(srv->unix_addr) -
163 sizeof(srv->unix_addr.sun_path);
164 return srv->unix_addr_len;
165
166 default:
167 return 0;
168 }
169}
170
171static void set_port(struct service_fixture *const srv, uint16_t port)
172{
173 switch (srv->protocol.domain) {
174 case AF_UNSPEC:
175 case AF_INET:
176 srv->ipv4_addr.sin_port = htons(port);
177 return;
178
179 case AF_INET6:
180 srv->ipv6_addr.sin6_port = htons(port);
181 return;
182
183 default:
184 return;
185 }
186}
187
188static uint16_t get_binded_port(int socket_fd,
189 const struct protocol_variant *const prot)
190{
191 struct sockaddr_in ipv4_addr;
192 struct sockaddr_in6 ipv6_addr;
193 socklen_t ipv4_addr_len, ipv6_addr_len;
194
195 /* Gets binded port. */
196 switch (prot->domain) {
197 case AF_UNSPEC:
198 case AF_INET:
199 ipv4_addr_len = sizeof(ipv4_addr);
200 getsockname(socket_fd, &ipv4_addr, &ipv4_addr_len);
201 return ntohs(ipv4_addr.sin_port);
202
203 case AF_INET6:
204 ipv6_addr_len = sizeof(ipv6_addr);
205 getsockname(socket_fd, &ipv6_addr, &ipv6_addr_len);
206 return ntohs(ipv6_addr.sin6_port);
207
208 default:
209 return 0;
210 }
211}
212
213static int bind_variant_addrlen(const int sock_fd,
214 const struct service_fixture *const srv,
215 const socklen_t addrlen)
216{
217 int ret;
218
219 switch (srv->protocol.domain) {
220 case AF_UNSPEC:
221 case AF_INET:
222 ret = bind(sock_fd, &srv->ipv4_addr, addrlen);
223 break;
224
225 case AF_INET6:
226 ret = bind(sock_fd, &srv->ipv6_addr, addrlen);
227 break;
228
229 case AF_UNIX:
230 ret = bind(sock_fd, &srv->unix_addr, addrlen);
231 break;
232
233 default:
234 errno = EAFNOSUPPORT;
235 return -errno;
236 }
237
238 if (ret < 0)
239 return -errno;
240 return ret;
241}
242
243static int bind_variant(const int sock_fd,
244 const struct service_fixture *const srv)
245{
246 return bind_variant_addrlen(sock_fd, srv, get_addrlen(srv, false));
247}
248
249static int connect_variant_addrlen(const int sock_fd,
250 const struct service_fixture *const srv,
251 const socklen_t addrlen)
252{
253 int ret;
254
255 switch (srv->protocol.domain) {
256 case AF_UNSPEC:
257 case AF_INET:
258 ret = connect(sock_fd, &srv->ipv4_addr, addrlen);
259 break;
260
261 case AF_INET6:
262 ret = connect(sock_fd, &srv->ipv6_addr, addrlen);
263 break;
264
265 case AF_UNIX:
266 ret = connect(sock_fd, &srv->unix_addr, addrlen);
267 break;
268
269 default:
270 errno = -EAFNOSUPPORT;
271 return -errno;
272 }
273
274 if (ret < 0)
275 return -errno;
276 return ret;
277}
278
279static int connect_variant(const int sock_fd,
280 const struct service_fixture *const srv)
281{
282 return connect_variant_addrlen(sock_fd, srv, get_addrlen(srv, false));
283}
284
285FIXTURE(protocol)
286{
287 struct service_fixture srv0, srv1, srv2, unspec_any0, unspec_srv0;
288};
289
290FIXTURE_VARIANT(protocol)
291{
292 const enum sandbox_type sandbox;
293 const struct protocol_variant prot;
294};
295
296FIXTURE_SETUP(protocol)
297{
298 const struct protocol_variant prot_unspec = {
299 .domain = AF_UNSPEC,
300 .type = SOCK_STREAM,
301 };
302
303 disable_caps(_metadata);
304
305 ASSERT_EQ(0, set_service(&self->srv0, variant->prot, 0));
306 ASSERT_EQ(0, set_service(&self->srv1, variant->prot, 1));
307 ASSERT_EQ(0, set_service(&self->srv2, variant->prot, 2));
308
309 ASSERT_EQ(0, set_service(&self->unspec_srv0, prot_unspec, 0));
310
311 ASSERT_EQ(0, set_service(&self->unspec_any0, prot_unspec, 0));
312 self->unspec_any0.ipv4_addr.sin_addr.s_addr = htonl(INADDR_ANY);
313
314 setup_loopback(_metadata);
315};
316
317FIXTURE_TEARDOWN(protocol)
318{
319}
320
321/* clang-format off */
322FIXTURE_VARIANT_ADD(protocol, no_sandbox_with_ipv4_tcp) {
323 /* clang-format on */
324 .sandbox = NO_SANDBOX,
325 .prot = {
326 .domain = AF_INET,
327 .type = SOCK_STREAM,
328 },
329};
330
331/* clang-format off */
332FIXTURE_VARIANT_ADD(protocol, no_sandbox_with_ipv6_tcp) {
333 /* clang-format on */
334 .sandbox = NO_SANDBOX,
335 .prot = {
336 .domain = AF_INET6,
337 .type = SOCK_STREAM,
338 },
339};
340
341/* clang-format off */
342FIXTURE_VARIANT_ADD(protocol, no_sandbox_with_ipv4_udp) {
343 /* clang-format on */
344 .sandbox = NO_SANDBOX,
345 .prot = {
346 .domain = AF_INET,
347 .type = SOCK_DGRAM,
348 },
349};
350
351/* clang-format off */
352FIXTURE_VARIANT_ADD(protocol, no_sandbox_with_ipv6_udp) {
353 /* clang-format on */
354 .sandbox = NO_SANDBOX,
355 .prot = {
356 .domain = AF_INET6,
357 .type = SOCK_DGRAM,
358 },
359};
360
361/* clang-format off */
362FIXTURE_VARIANT_ADD(protocol, no_sandbox_with_unix_stream) {
363 /* clang-format on */
364 .sandbox = NO_SANDBOX,
365 .prot = {
366 .domain = AF_UNIX,
367 .type = SOCK_STREAM,
368 },
369};
370
371/* clang-format off */
372FIXTURE_VARIANT_ADD(protocol, no_sandbox_with_unix_datagram) {
373 /* clang-format on */
374 .sandbox = NO_SANDBOX,
375 .prot = {
376 .domain = AF_UNIX,
377 .type = SOCK_DGRAM,
378 },
379};
380
381/* clang-format off */
382FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_ipv4_tcp) {
383 /* clang-format on */
384 .sandbox = TCP_SANDBOX,
385 .prot = {
386 .domain = AF_INET,
387 .type = SOCK_STREAM,
388 },
389};
390
391/* clang-format off */
392FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_ipv6_tcp) {
393 /* clang-format on */
394 .sandbox = TCP_SANDBOX,
395 .prot = {
396 .domain = AF_INET6,
397 .type = SOCK_STREAM,
398 },
399};
400
401/* clang-format off */
402FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_ipv4_udp) {
403 /* clang-format on */
404 .sandbox = TCP_SANDBOX,
405 .prot = {
406 .domain = AF_INET,
407 .type = SOCK_DGRAM,
408 },
409};
410
411/* clang-format off */
412FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_ipv6_udp) {
413 /* clang-format on */
414 .sandbox = TCP_SANDBOX,
415 .prot = {
416 .domain = AF_INET6,
417 .type = SOCK_DGRAM,
418 },
419};
420
421/* clang-format off */
422FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_unix_stream) {
423 /* clang-format on */
424 .sandbox = TCP_SANDBOX,
425 .prot = {
426 .domain = AF_UNIX,
427 .type = SOCK_STREAM,
428 },
429};
430
431/* clang-format off */
432FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_unix_datagram) {
433 /* clang-format on */
434 .sandbox = TCP_SANDBOX,
435 .prot = {
436 .domain = AF_UNIX,
437 .type = SOCK_DGRAM,
438 },
439};
440
441static void test_bind_and_connect(struct __test_metadata *const _metadata,
442 const struct service_fixture *const srv,
443 const bool deny_bind, const bool deny_connect)
444{
445 char buf = '\0';
446 int inval_fd, bind_fd, client_fd, status, ret;
447 pid_t child;
448
449 /* Starts invalid addrlen tests with bind. */
450 inval_fd = socket_variant(srv);
451 ASSERT_LE(0, inval_fd)
452 {
453 TH_LOG("Failed to create socket: %s", strerror(errno));
454 }
455
456 /* Tries to bind with zero as addrlen. */
457 EXPECT_EQ(-EINVAL, bind_variant_addrlen(inval_fd, srv, 0));
458
459 /* Tries to bind with too small addrlen. */
460 EXPECT_EQ(-EINVAL, bind_variant_addrlen(inval_fd, srv,
461 get_addrlen(srv, true) - 1));
462
463 /* Tries to bind with minimal addrlen. */
464 ret = bind_variant_addrlen(inval_fd, srv, get_addrlen(srv, true));
465 if (deny_bind) {
466 EXPECT_EQ(-EACCES, ret);
467 } else {
468 EXPECT_EQ(0, ret)
469 {
470 TH_LOG("Failed to bind to socket: %s", strerror(errno));
471 }
472 }
473 EXPECT_EQ(0, close(inval_fd));
474
475 /* Starts invalid addrlen tests with connect. */
476 inval_fd = socket_variant(srv);
477 ASSERT_LE(0, inval_fd);
478
479 /* Tries to connect with zero as addrlen. */
480 EXPECT_EQ(-EINVAL, connect_variant_addrlen(inval_fd, srv, 0));
481
482 /* Tries to connect with too small addrlen. */
483 EXPECT_EQ(-EINVAL, connect_variant_addrlen(inval_fd, srv,
484 get_addrlen(srv, true) - 1));
485
486 /* Tries to connect with minimal addrlen. */
487 ret = connect_variant_addrlen(inval_fd, srv, get_addrlen(srv, true));
488 if (srv->protocol.domain == AF_UNIX) {
489 EXPECT_EQ(-EINVAL, ret);
490 } else if (deny_connect) {
491 EXPECT_EQ(-EACCES, ret);
492 } else if (srv->protocol.type == SOCK_STREAM) {
493 /* No listening server, whatever the value of deny_bind. */
494 EXPECT_EQ(-ECONNREFUSED, ret);
495 } else {
496 EXPECT_EQ(0, ret)
497 {
498 TH_LOG("Failed to connect to socket: %s",
499 strerror(errno));
500 }
501 }
502 EXPECT_EQ(0, close(inval_fd));
503
504 /* Starts connection tests. */
505 bind_fd = socket_variant(srv);
506 ASSERT_LE(0, bind_fd);
507
508 ret = bind_variant(sock_fd: bind_fd, srv);
509 if (deny_bind) {
510 EXPECT_EQ(-EACCES, ret);
511 } else {
512 EXPECT_EQ(0, ret);
513
514 /* Creates a listening socket. */
515 if (srv->protocol.type == SOCK_STREAM)
516 EXPECT_EQ(0, listen(bind_fd, backlog));
517 }
518
519 child = fork();
520 ASSERT_LE(0, child);
521 if (child == 0) {
522 int connect_fd, ret;
523
524 /* Closes listening socket for the child. */
525 EXPECT_EQ(0, close(bind_fd));
526
527 /* Starts connection tests. */
528 connect_fd = socket_variant(srv);
529 ASSERT_LE(0, connect_fd);
530 ret = connect_variant(sock_fd: connect_fd, srv);
531 if (deny_connect) {
532 EXPECT_EQ(-EACCES, ret);
533 } else if (deny_bind) {
534 /* No listening server. */
535 EXPECT_EQ(-ECONNREFUSED, ret);
536 } else {
537 EXPECT_EQ(0, ret);
538 EXPECT_EQ(1, write(connect_fd, ".", 1));
539 }
540
541 EXPECT_EQ(0, close(connect_fd));
542 _exit(_metadata->exit_code);
543 return;
544 }
545
546 /* Accepts connection from the child. */
547 client_fd = bind_fd;
548 if (!deny_bind && !deny_connect) {
549 if (srv->protocol.type == SOCK_STREAM) {
550 client_fd = accept(bind_fd, NULL, 0);
551 ASSERT_LE(0, client_fd);
552 }
553
554 EXPECT_EQ(1, read(client_fd, &buf, 1));
555 EXPECT_EQ('.', buf);
556 }
557
558 EXPECT_EQ(child, waitpid(child, &status, 0));
559 EXPECT_EQ(1, WIFEXITED(status));
560 EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
561
562 /* Closes connection, if any. */
563 if (client_fd != bind_fd)
564 EXPECT_LE(0, close(client_fd));
565
566 /* Closes listening socket. */
567 EXPECT_EQ(0, close(bind_fd));
568}
569
570TEST_F(protocol, bind)
571{
572 if (variant->sandbox == TCP_SANDBOX) {
573 const struct landlock_ruleset_attr ruleset_attr = {
574 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
575 LANDLOCK_ACCESS_NET_CONNECT_TCP,
576 };
577 const struct landlock_net_port_attr tcp_bind_connect_p0 = {
578 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
579 LANDLOCK_ACCESS_NET_CONNECT_TCP,
580 .port = self->srv0.port,
581 };
582 const struct landlock_net_port_attr tcp_connect_p1 = {
583 .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP,
584 .port = self->srv1.port,
585 };
586 int ruleset_fd;
587
588 ruleset_fd = landlock_create_ruleset(attr: &ruleset_attr,
589 size: sizeof(ruleset_attr), flags: 0);
590 ASSERT_LE(0, ruleset_fd);
591
592 /* Allows connect and bind for the first port. */
593 ASSERT_EQ(0,
594 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
595 &tcp_bind_connect_p0, 0));
596
597 /* Allows connect and denies bind for the second port. */
598 ASSERT_EQ(0,
599 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
600 &tcp_connect_p1, 0));
601
602 enforce_ruleset(_metadata, ruleset_fd);
603 EXPECT_EQ(0, close(ruleset_fd));
604 }
605
606 /* Binds a socket to the first port. */
607 test_bind_and_connect(_metadata, srv: &self->srv0, deny_bind: false, deny_connect: false);
608
609 /* Binds a socket to the second port. */
610 test_bind_and_connect(_metadata, srv: &self->srv1,
611 deny_bind: is_restricted(prot: &variant->prot, sandbox: variant->sandbox),
612 deny_connect: false);
613
614 /* Binds a socket to the third port. */
615 test_bind_and_connect(_metadata, srv: &self->srv2,
616 deny_bind: is_restricted(prot: &variant->prot, sandbox: variant->sandbox),
617 deny_connect: is_restricted(prot: &variant->prot, sandbox: variant->sandbox));
618}
619
620TEST_F(protocol, connect)
621{
622 if (variant->sandbox == TCP_SANDBOX) {
623 const struct landlock_ruleset_attr ruleset_attr = {
624 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
625 LANDLOCK_ACCESS_NET_CONNECT_TCP,
626 };
627 const struct landlock_net_port_attr tcp_bind_connect_p0 = {
628 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
629 LANDLOCK_ACCESS_NET_CONNECT_TCP,
630 .port = self->srv0.port,
631 };
632 const struct landlock_net_port_attr tcp_bind_p1 = {
633 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
634 .port = self->srv1.port,
635 };
636 int ruleset_fd;
637
638 ruleset_fd = landlock_create_ruleset(attr: &ruleset_attr,
639 size: sizeof(ruleset_attr), flags: 0);
640 ASSERT_LE(0, ruleset_fd);
641
642 /* Allows connect and bind for the first port. */
643 ASSERT_EQ(0,
644 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
645 &tcp_bind_connect_p0, 0));
646
647 /* Allows bind and denies connect for the second port. */
648 ASSERT_EQ(0,
649 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
650 &tcp_bind_p1, 0));
651
652 enforce_ruleset(_metadata, ruleset_fd);
653 EXPECT_EQ(0, close(ruleset_fd));
654 }
655
656 test_bind_and_connect(_metadata, srv: &self->srv0, deny_bind: false, deny_connect: false);
657
658 test_bind_and_connect(_metadata, srv: &self->srv1, deny_bind: false,
659 deny_connect: is_restricted(prot: &variant->prot, sandbox: variant->sandbox));
660
661 test_bind_and_connect(_metadata, srv: &self->srv2,
662 deny_bind: is_restricted(prot: &variant->prot, sandbox: variant->sandbox),
663 deny_connect: is_restricted(prot: &variant->prot, sandbox: variant->sandbox));
664}
665
666TEST_F(protocol, bind_unspec)
667{
668 const struct landlock_ruleset_attr ruleset_attr = {
669 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP,
670 };
671 const struct landlock_net_port_attr tcp_bind = {
672 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
673 .port = self->srv0.port,
674 };
675 int bind_fd, ret;
676
677 if (variant->sandbox == TCP_SANDBOX) {
678 const int ruleset_fd = landlock_create_ruleset(
679 attr: &ruleset_attr, size: sizeof(ruleset_attr), flags: 0);
680 ASSERT_LE(0, ruleset_fd);
681
682 /* Allows bind. */
683 ASSERT_EQ(0,
684 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
685 &tcp_bind, 0));
686 enforce_ruleset(_metadata, ruleset_fd);
687 EXPECT_EQ(0, close(ruleset_fd));
688 }
689
690 bind_fd = socket_variant(srv: &self->srv0);
691 ASSERT_LE(0, bind_fd);
692
693 /* Allowed bind on AF_UNSPEC/INADDR_ANY. */
694 ret = bind_variant(sock_fd: bind_fd, srv: &self->unspec_any0);
695 if (variant->prot.domain == AF_INET) {
696 EXPECT_EQ(0, ret)
697 {
698 TH_LOG("Failed to bind to unspec/any socket: %s",
699 strerror(errno));
700 }
701 } else {
702 EXPECT_EQ(-EINVAL, ret);
703 }
704 EXPECT_EQ(0, close(bind_fd));
705
706 if (variant->sandbox == TCP_SANDBOX) {
707 const int ruleset_fd = landlock_create_ruleset(
708 attr: &ruleset_attr, size: sizeof(ruleset_attr), flags: 0);
709 ASSERT_LE(0, ruleset_fd);
710
711 /* Denies bind. */
712 enforce_ruleset(_metadata, ruleset_fd);
713 EXPECT_EQ(0, close(ruleset_fd));
714 }
715
716 bind_fd = socket_variant(srv: &self->srv0);
717 ASSERT_LE(0, bind_fd);
718
719 /* Denied bind on AF_UNSPEC/INADDR_ANY. */
720 ret = bind_variant(sock_fd: bind_fd, srv: &self->unspec_any0);
721 if (variant->prot.domain == AF_INET) {
722 if (is_restricted(prot: &variant->prot, sandbox: variant->sandbox)) {
723 EXPECT_EQ(-EACCES, ret);
724 } else {
725 EXPECT_EQ(0, ret);
726 }
727 } else {
728 EXPECT_EQ(-EINVAL, ret);
729 }
730 EXPECT_EQ(0, close(bind_fd));
731
732 /* Checks bind with AF_UNSPEC and the loopback address. */
733 bind_fd = socket_variant(srv: &self->srv0);
734 ASSERT_LE(0, bind_fd);
735 ret = bind_variant(sock_fd: bind_fd, srv: &self->unspec_srv0);
736 if (variant->prot.domain == AF_INET) {
737 EXPECT_EQ(-EAFNOSUPPORT, ret);
738 } else {
739 EXPECT_EQ(-EINVAL, ret)
740 {
741 TH_LOG("Wrong bind error: %s", strerror(errno));
742 }
743 }
744 EXPECT_EQ(0, close(bind_fd));
745}
746
747TEST_F(protocol, connect_unspec)
748{
749 const struct landlock_ruleset_attr ruleset_attr = {
750 .handled_access_net = LANDLOCK_ACCESS_NET_CONNECT_TCP,
751 };
752 const struct landlock_net_port_attr tcp_connect = {
753 .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP,
754 .port = self->srv0.port,
755 };
756 int bind_fd, client_fd, status;
757 pid_t child;
758
759 /* Specific connection tests. */
760 bind_fd = socket_variant(srv: &self->srv0);
761 ASSERT_LE(0, bind_fd);
762 EXPECT_EQ(0, bind_variant(bind_fd, &self->srv0));
763 if (self->srv0.protocol.type == SOCK_STREAM)
764 EXPECT_EQ(0, listen(bind_fd, backlog));
765
766 child = fork();
767 ASSERT_LE(0, child);
768 if (child == 0) {
769 int connect_fd, ret;
770
771 /* Closes listening socket for the child. */
772 EXPECT_EQ(0, close(bind_fd));
773
774 connect_fd = socket_variant(srv: &self->srv0);
775 ASSERT_LE(0, connect_fd);
776 EXPECT_EQ(0, connect_variant(connect_fd, &self->srv0));
777
778 /* Tries to connect again, or set peer. */
779 ret = connect_variant(sock_fd: connect_fd, srv: &self->srv0);
780 if (self->srv0.protocol.type == SOCK_STREAM) {
781 EXPECT_EQ(-EISCONN, ret);
782 } else {
783 EXPECT_EQ(0, ret);
784 }
785
786 if (variant->sandbox == TCP_SANDBOX) {
787 const int ruleset_fd = landlock_create_ruleset(
788 attr: &ruleset_attr, size: sizeof(ruleset_attr), flags: 0);
789 ASSERT_LE(0, ruleset_fd);
790
791 /* Allows connect. */
792 ASSERT_EQ(0, landlock_add_rule(ruleset_fd,
793 LANDLOCK_RULE_NET_PORT,
794 &tcp_connect, 0));
795 enforce_ruleset(_metadata, ruleset_fd);
796 EXPECT_EQ(0, close(ruleset_fd));
797 }
798
799 /* Disconnects already connected socket, or set peer. */
800 ret = connect_variant(sock_fd: connect_fd, srv: &self->unspec_any0);
801 if (self->srv0.protocol.domain == AF_UNIX &&
802 self->srv0.protocol.type == SOCK_STREAM) {
803 EXPECT_EQ(-EINVAL, ret);
804 } else {
805 EXPECT_EQ(0, ret);
806 }
807
808 /* Tries to reconnect, or set peer. */
809 ret = connect_variant(sock_fd: connect_fd, srv: &self->srv0);
810 if (self->srv0.protocol.domain == AF_UNIX &&
811 self->srv0.protocol.type == SOCK_STREAM) {
812 EXPECT_EQ(-EISCONN, ret);
813 } else {
814 EXPECT_EQ(0, ret);
815 }
816
817 if (variant->sandbox == TCP_SANDBOX) {
818 const int ruleset_fd = landlock_create_ruleset(
819 attr: &ruleset_attr, size: sizeof(ruleset_attr), flags: 0);
820 ASSERT_LE(0, ruleset_fd);
821
822 /* Denies connect. */
823 enforce_ruleset(_metadata, ruleset_fd);
824 EXPECT_EQ(0, close(ruleset_fd));
825 }
826
827 ret = connect_variant(sock_fd: connect_fd, srv: &self->unspec_any0);
828 if (self->srv0.protocol.domain == AF_UNIX &&
829 self->srv0.protocol.type == SOCK_STREAM) {
830 EXPECT_EQ(-EINVAL, ret);
831 } else {
832 /* Always allowed to disconnect. */
833 EXPECT_EQ(0, ret);
834 }
835
836 EXPECT_EQ(0, close(connect_fd));
837 _exit(_metadata->exit_code);
838 return;
839 }
840
841 client_fd = bind_fd;
842 if (self->srv0.protocol.type == SOCK_STREAM) {
843 client_fd = accept(bind_fd, NULL, 0);
844 ASSERT_LE(0, client_fd);
845 }
846
847 EXPECT_EQ(child, waitpid(child, &status, 0));
848 EXPECT_EQ(1, WIFEXITED(status));
849 EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
850
851 /* Closes connection, if any. */
852 if (client_fd != bind_fd)
853 EXPECT_LE(0, close(client_fd));
854
855 /* Closes listening socket. */
856 EXPECT_EQ(0, close(bind_fd));
857}
858
859FIXTURE(ipv4)
860{
861 struct service_fixture srv0, srv1;
862};
863
864FIXTURE_VARIANT(ipv4)
865{
866 const enum sandbox_type sandbox;
867 const int type;
868};
869
870/* clang-format off */
871FIXTURE_VARIANT_ADD(ipv4, no_sandbox_with_tcp) {
872 /* clang-format on */
873 .sandbox = NO_SANDBOX,
874 .type = SOCK_STREAM,
875};
876
877/* clang-format off */
878FIXTURE_VARIANT_ADD(ipv4, tcp_sandbox_with_tcp) {
879 /* clang-format on */
880 .sandbox = TCP_SANDBOX,
881 .type = SOCK_STREAM,
882};
883
884/* clang-format off */
885FIXTURE_VARIANT_ADD(ipv4, no_sandbox_with_udp) {
886 /* clang-format on */
887 .sandbox = NO_SANDBOX,
888 .type = SOCK_DGRAM,
889};
890
891/* clang-format off */
892FIXTURE_VARIANT_ADD(ipv4, tcp_sandbox_with_udp) {
893 /* clang-format on */
894 .sandbox = TCP_SANDBOX,
895 .type = SOCK_DGRAM,
896};
897
898FIXTURE_SETUP(ipv4)
899{
900 const struct protocol_variant prot = {
901 .domain = AF_INET,
902 .type = variant->type,
903 };
904
905 disable_caps(_metadata);
906
907 set_service(srv: &self->srv0, prot, index: 0);
908 set_service(srv: &self->srv1, prot, index: 1);
909
910 setup_loopback(_metadata);
911};
912
913FIXTURE_TEARDOWN(ipv4)
914{
915}
916
917TEST_F(ipv4, from_unix_to_inet)
918{
919 int unix_stream_fd, unix_dgram_fd;
920
921 if (variant->sandbox == TCP_SANDBOX) {
922 const struct landlock_ruleset_attr ruleset_attr = {
923 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
924 LANDLOCK_ACCESS_NET_CONNECT_TCP,
925 };
926 const struct landlock_net_port_attr tcp_bind_connect_p0 = {
927 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
928 LANDLOCK_ACCESS_NET_CONNECT_TCP,
929 .port = self->srv0.port,
930 };
931 int ruleset_fd;
932
933 /* Denies connect and bind to check errno value. */
934 ruleset_fd = landlock_create_ruleset(attr: &ruleset_attr,
935 size: sizeof(ruleset_attr), flags: 0);
936 ASSERT_LE(0, ruleset_fd);
937
938 /* Allows connect and bind for srv0. */
939 ASSERT_EQ(0,
940 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
941 &tcp_bind_connect_p0, 0));
942
943 enforce_ruleset(_metadata, ruleset_fd);
944 EXPECT_EQ(0, close(ruleset_fd));
945 }
946
947 unix_stream_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
948 ASSERT_LE(0, unix_stream_fd);
949
950 unix_dgram_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
951 ASSERT_LE(0, unix_dgram_fd);
952
953 /* Checks unix stream bind and connect for srv0. */
954 EXPECT_EQ(-EINVAL, bind_variant(unix_stream_fd, &self->srv0));
955 EXPECT_EQ(-EINVAL, connect_variant(unix_stream_fd, &self->srv0));
956
957 /* Checks unix stream bind and connect for srv1. */
958 EXPECT_EQ(-EINVAL, bind_variant(unix_stream_fd, &self->srv1))
959 {
960 TH_LOG("Wrong bind error: %s", strerror(errno));
961 }
962 EXPECT_EQ(-EINVAL, connect_variant(unix_stream_fd, &self->srv1));
963
964 /* Checks unix datagram bind and connect for srv0. */
965 EXPECT_EQ(-EINVAL, bind_variant(unix_dgram_fd, &self->srv0));
966 EXPECT_EQ(-EINVAL, connect_variant(unix_dgram_fd, &self->srv0));
967
968 /* Checks unix datagram bind and connect for srv1. */
969 EXPECT_EQ(-EINVAL, bind_variant(unix_dgram_fd, &self->srv1));
970 EXPECT_EQ(-EINVAL, connect_variant(unix_dgram_fd, &self->srv1));
971}
972
973FIXTURE(tcp_layers)
974{
975 struct service_fixture srv0, srv1;
976};
977
978FIXTURE_VARIANT(tcp_layers)
979{
980 const size_t num_layers;
981 const int domain;
982};
983
984FIXTURE_SETUP(tcp_layers)
985{
986 const struct protocol_variant prot = {
987 .domain = variant->domain,
988 .type = SOCK_STREAM,
989 };
990
991 disable_caps(_metadata);
992
993 ASSERT_EQ(0, set_service(&self->srv0, prot, 0));
994 ASSERT_EQ(0, set_service(&self->srv1, prot, 1));
995
996 setup_loopback(_metadata);
997};
998
999FIXTURE_TEARDOWN(tcp_layers)
1000{
1001}
1002
1003/* clang-format off */
1004FIXTURE_VARIANT_ADD(tcp_layers, no_sandbox_with_ipv4) {
1005 /* clang-format on */
1006 .domain = AF_INET,
1007 .num_layers = 0,
1008};
1009
1010/* clang-format off */
1011FIXTURE_VARIANT_ADD(tcp_layers, one_sandbox_with_ipv4) {
1012 /* clang-format on */
1013 .domain = AF_INET,
1014 .num_layers = 1,
1015};
1016
1017/* clang-format off */
1018FIXTURE_VARIANT_ADD(tcp_layers, two_sandboxes_with_ipv4) {
1019 /* clang-format on */
1020 .domain = AF_INET,
1021 .num_layers = 2,
1022};
1023
1024/* clang-format off */
1025FIXTURE_VARIANT_ADD(tcp_layers, three_sandboxes_with_ipv4) {
1026 /* clang-format on */
1027 .domain = AF_INET,
1028 .num_layers = 3,
1029};
1030
1031/* clang-format off */
1032FIXTURE_VARIANT_ADD(tcp_layers, no_sandbox_with_ipv6) {
1033 /* clang-format on */
1034 .domain = AF_INET6,
1035 .num_layers = 0,
1036};
1037
1038/* clang-format off */
1039FIXTURE_VARIANT_ADD(tcp_layers, one_sandbox_with_ipv6) {
1040 /* clang-format on */
1041 .domain = AF_INET6,
1042 .num_layers = 1,
1043};
1044
1045/* clang-format off */
1046FIXTURE_VARIANT_ADD(tcp_layers, two_sandboxes_with_ipv6) {
1047 /* clang-format on */
1048 .domain = AF_INET6,
1049 .num_layers = 2,
1050};
1051
1052/* clang-format off */
1053FIXTURE_VARIANT_ADD(tcp_layers, three_sandboxes_with_ipv6) {
1054 /* clang-format on */
1055 .domain = AF_INET6,
1056 .num_layers = 3,
1057};
1058
1059TEST_F(tcp_layers, ruleset_overlap)
1060{
1061 const struct landlock_ruleset_attr ruleset_attr = {
1062 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
1063 LANDLOCK_ACCESS_NET_CONNECT_TCP,
1064 };
1065 const struct landlock_net_port_attr tcp_bind = {
1066 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
1067 .port = self->srv0.port,
1068 };
1069 const struct landlock_net_port_attr tcp_bind_connect = {
1070 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
1071 LANDLOCK_ACCESS_NET_CONNECT_TCP,
1072 .port = self->srv0.port,
1073 };
1074
1075 if (variant->num_layers >= 1) {
1076 int ruleset_fd;
1077
1078 ruleset_fd = landlock_create_ruleset(attr: &ruleset_attr,
1079 size: sizeof(ruleset_attr), flags: 0);
1080 ASSERT_LE(0, ruleset_fd);
1081
1082 /* Allows bind. */
1083 ASSERT_EQ(0,
1084 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1085 &tcp_bind, 0));
1086 /* Also allows bind, but allows connect too. */
1087 ASSERT_EQ(0,
1088 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1089 &tcp_bind_connect, 0));
1090 enforce_ruleset(_metadata, ruleset_fd);
1091 EXPECT_EQ(0, close(ruleset_fd));
1092 }
1093
1094 if (variant->num_layers >= 2) {
1095 int ruleset_fd;
1096
1097 /* Creates another ruleset layer. */
1098 ruleset_fd = landlock_create_ruleset(attr: &ruleset_attr,
1099 size: sizeof(ruleset_attr), flags: 0);
1100 ASSERT_LE(0, ruleset_fd);
1101
1102 /* Only allows bind. */
1103 ASSERT_EQ(0,
1104 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1105 &tcp_bind, 0));
1106 enforce_ruleset(_metadata, ruleset_fd);
1107 EXPECT_EQ(0, close(ruleset_fd));
1108 }
1109
1110 if (variant->num_layers >= 3) {
1111 int ruleset_fd;
1112
1113 /* Creates another ruleset layer. */
1114 ruleset_fd = landlock_create_ruleset(attr: &ruleset_attr,
1115 size: sizeof(ruleset_attr), flags: 0);
1116 ASSERT_LE(0, ruleset_fd);
1117
1118 /* Try to allow bind and connect. */
1119 ASSERT_EQ(0,
1120 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1121 &tcp_bind_connect, 0));
1122 enforce_ruleset(_metadata, ruleset_fd);
1123 EXPECT_EQ(0, close(ruleset_fd));
1124 }
1125
1126 /*
1127 * Forbids to connect to the socket because only one ruleset layer
1128 * allows connect.
1129 */
1130 test_bind_and_connect(_metadata, srv: &self->srv0, deny_bind: false,
1131 deny_connect: variant->num_layers >= 2);
1132}
1133
1134TEST_F(tcp_layers, ruleset_expand)
1135{
1136 if (variant->num_layers >= 1) {
1137 const struct landlock_ruleset_attr ruleset_attr = {
1138 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP,
1139 };
1140 /* Allows bind for srv0. */
1141 const struct landlock_net_port_attr bind_srv0 = {
1142 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
1143 .port = self->srv0.port,
1144 };
1145 int ruleset_fd;
1146
1147 ruleset_fd = landlock_create_ruleset(attr: &ruleset_attr,
1148 size: sizeof(ruleset_attr), flags: 0);
1149 ASSERT_LE(0, ruleset_fd);
1150 ASSERT_EQ(0,
1151 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1152 &bind_srv0, 0));
1153 enforce_ruleset(_metadata, ruleset_fd);
1154 EXPECT_EQ(0, close(ruleset_fd));
1155 }
1156
1157 if (variant->num_layers >= 2) {
1158 /* Expands network mask with connect action. */
1159 const struct landlock_ruleset_attr ruleset_attr = {
1160 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
1161 LANDLOCK_ACCESS_NET_CONNECT_TCP,
1162 };
1163 /* Allows bind for srv0 and connect to srv0. */
1164 const struct landlock_net_port_attr tcp_bind_connect_p0 = {
1165 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
1166 LANDLOCK_ACCESS_NET_CONNECT_TCP,
1167 .port = self->srv0.port,
1168 };
1169 /* Try to allow bind for srv1. */
1170 const struct landlock_net_port_attr tcp_bind_p1 = {
1171 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
1172 .port = self->srv1.port,
1173 };
1174 int ruleset_fd;
1175
1176 ruleset_fd = landlock_create_ruleset(attr: &ruleset_attr,
1177 size: sizeof(ruleset_attr), flags: 0);
1178 ASSERT_LE(0, ruleset_fd);
1179 ASSERT_EQ(0,
1180 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1181 &tcp_bind_connect_p0, 0));
1182 ASSERT_EQ(0,
1183 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1184 &tcp_bind_p1, 0));
1185 enforce_ruleset(_metadata, ruleset_fd);
1186 EXPECT_EQ(0, close(ruleset_fd));
1187 }
1188
1189 if (variant->num_layers >= 3) {
1190 const struct landlock_ruleset_attr ruleset_attr = {
1191 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
1192 LANDLOCK_ACCESS_NET_CONNECT_TCP,
1193 };
1194 /* Allows connect to srv0, without bind rule. */
1195 const struct landlock_net_port_attr tcp_bind_p0 = {
1196 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
1197 .port = self->srv0.port,
1198 };
1199 int ruleset_fd;
1200
1201 ruleset_fd = landlock_create_ruleset(attr: &ruleset_attr,
1202 size: sizeof(ruleset_attr), flags: 0);
1203 ASSERT_LE(0, ruleset_fd);
1204 ASSERT_EQ(0,
1205 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1206 &tcp_bind_p0, 0));
1207 enforce_ruleset(_metadata, ruleset_fd);
1208 EXPECT_EQ(0, close(ruleset_fd));
1209 }
1210
1211 test_bind_and_connect(_metadata, srv: &self->srv0, deny_bind: false,
1212 deny_connect: variant->num_layers >= 3);
1213
1214 test_bind_and_connect(_metadata, srv: &self->srv1, deny_bind: variant->num_layers >= 1,
1215 deny_connect: variant->num_layers >= 2);
1216}
1217
1218/* clang-format off */
1219FIXTURE(mini) {};
1220/* clang-format on */
1221
1222FIXTURE_SETUP(mini)
1223{
1224 disable_caps(_metadata);
1225
1226 setup_loopback(_metadata);
1227};
1228
1229FIXTURE_TEARDOWN(mini)
1230{
1231}
1232
1233/* clang-format off */
1234
1235#define ACCESS_LAST LANDLOCK_ACCESS_NET_CONNECT_TCP
1236
1237#define ACCESS_ALL ( \
1238 LANDLOCK_ACCESS_NET_BIND_TCP | \
1239 LANDLOCK_ACCESS_NET_CONNECT_TCP)
1240
1241/* clang-format on */
1242
1243TEST_F(mini, network_access_rights)
1244{
1245 const struct landlock_ruleset_attr ruleset_attr = {
1246 .handled_access_net = ACCESS_ALL,
1247 };
1248 struct landlock_net_port_attr net_port = {
1249 .port = sock_port_start,
1250 };
1251 int ruleset_fd;
1252 __u64 access;
1253
1254 ruleset_fd =
1255 landlock_create_ruleset(attr: &ruleset_attr, size: sizeof(ruleset_attr), flags: 0);
1256 ASSERT_LE(0, ruleset_fd);
1257
1258 for (access = 1; access <= ACCESS_LAST; access <<= 1) {
1259 net_port.allowed_access = access;
1260 EXPECT_EQ(0,
1261 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1262 &net_port, 0))
1263 {
1264 TH_LOG("Failed to add rule with access 0x%llx: %s",
1265 access, strerror(errno));
1266 }
1267 }
1268 EXPECT_EQ(0, close(ruleset_fd));
1269}
1270
1271/* Checks invalid attribute, out of landlock network access range. */
1272TEST_F(mini, ruleset_with_unknown_access)
1273{
1274 __u64 access_mask;
1275
1276 for (access_mask = 1ULL << 63; access_mask != ACCESS_LAST;
1277 access_mask >>= 1) {
1278 const struct landlock_ruleset_attr ruleset_attr = {
1279 .handled_access_net = access_mask,
1280 };
1281
1282 EXPECT_EQ(-1, landlock_create_ruleset(&ruleset_attr,
1283 sizeof(ruleset_attr), 0));
1284 EXPECT_EQ(EINVAL, errno);
1285 }
1286}
1287
1288TEST_F(mini, rule_with_unknown_access)
1289{
1290 const struct landlock_ruleset_attr ruleset_attr = {
1291 .handled_access_net = ACCESS_ALL,
1292 };
1293 struct landlock_net_port_attr net_port = {
1294 .port = sock_port_start,
1295 };
1296 int ruleset_fd;
1297 __u64 access;
1298
1299 ruleset_fd =
1300 landlock_create_ruleset(attr: &ruleset_attr, size: sizeof(ruleset_attr), flags: 0);
1301 ASSERT_LE(0, ruleset_fd);
1302
1303 for (access = 1ULL << 63; access != ACCESS_LAST; access >>= 1) {
1304 net_port.allowed_access = access;
1305 EXPECT_EQ(-1,
1306 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1307 &net_port, 0));
1308 EXPECT_EQ(EINVAL, errno);
1309 }
1310 EXPECT_EQ(0, close(ruleset_fd));
1311}
1312
1313TEST_F(mini, rule_with_unhandled_access)
1314{
1315 struct landlock_ruleset_attr ruleset_attr = {
1316 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP,
1317 };
1318 struct landlock_net_port_attr net_port = {
1319 .port = sock_port_start,
1320 };
1321 int ruleset_fd;
1322 __u64 access;
1323
1324 ruleset_fd =
1325 landlock_create_ruleset(attr: &ruleset_attr, size: sizeof(ruleset_attr), flags: 0);
1326 ASSERT_LE(0, ruleset_fd);
1327
1328 for (access = 1; access > 0; access <<= 1) {
1329 int err;
1330
1331 net_port.allowed_access = access;
1332 err = landlock_add_rule(ruleset_fd, rule_type: LANDLOCK_RULE_NET_PORT,
1333 rule_attr: &net_port, flags: 0);
1334 if (access == ruleset_attr.handled_access_net) {
1335 EXPECT_EQ(0, err);
1336 } else {
1337 EXPECT_EQ(-1, err);
1338 EXPECT_EQ(EINVAL, errno);
1339 }
1340 }
1341
1342 EXPECT_EQ(0, close(ruleset_fd));
1343}
1344
1345TEST_F(mini, inval)
1346{
1347 const struct landlock_ruleset_attr ruleset_attr = {
1348 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP
1349 };
1350 const struct landlock_net_port_attr tcp_bind_connect = {
1351 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
1352 LANDLOCK_ACCESS_NET_CONNECT_TCP,
1353 .port = sock_port_start,
1354 };
1355 const struct landlock_net_port_attr tcp_denied = {
1356 .allowed_access = 0,
1357 .port = sock_port_start,
1358 };
1359 const struct landlock_net_port_attr tcp_bind = {
1360 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
1361 .port = sock_port_start,
1362 };
1363 int ruleset_fd;
1364
1365 ruleset_fd =
1366 landlock_create_ruleset(attr: &ruleset_attr, size: sizeof(ruleset_attr), flags: 0);
1367 ASSERT_LE(0, ruleset_fd);
1368
1369 /* Checks unhandled allowed_access. */
1370 EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1371 &tcp_bind_connect, 0));
1372 EXPECT_EQ(EINVAL, errno);
1373
1374 /* Checks zero access value. */
1375 EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1376 &tcp_denied, 0));
1377 EXPECT_EQ(ENOMSG, errno);
1378
1379 /* Adds with legitimate values. */
1380 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1381 &tcp_bind, 0));
1382}
1383
1384TEST_F(mini, tcp_port_overflow)
1385{
1386 const struct landlock_ruleset_attr ruleset_attr = {
1387 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
1388 LANDLOCK_ACCESS_NET_CONNECT_TCP,
1389 };
1390 const struct landlock_net_port_attr port_max_bind = {
1391 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
1392 .port = UINT16_MAX,
1393 };
1394 const struct landlock_net_port_attr port_max_connect = {
1395 .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP,
1396 .port = UINT16_MAX,
1397 };
1398 const struct landlock_net_port_attr port_overflow1 = {
1399 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
1400 .port = UINT16_MAX + 1,
1401 };
1402 const struct landlock_net_port_attr port_overflow2 = {
1403 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
1404 .port = UINT16_MAX + 2,
1405 };
1406 const struct landlock_net_port_attr port_overflow3 = {
1407 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
1408 .port = UINT32_MAX + 1UL,
1409 };
1410 const struct landlock_net_port_attr port_overflow4 = {
1411 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
1412 .port = UINT32_MAX + 2UL,
1413 };
1414 const struct protocol_variant ipv4_tcp = {
1415 .domain = AF_INET,
1416 .type = SOCK_STREAM,
1417 };
1418 struct service_fixture srv_denied, srv_max_allowed;
1419 int ruleset_fd;
1420
1421 ASSERT_EQ(0, set_service(&srv_denied, ipv4_tcp, 0));
1422
1423 /* Be careful to avoid port inconsistencies. */
1424 srv_max_allowed = srv_denied;
1425 srv_max_allowed.port = port_max_bind.port;
1426 srv_max_allowed.ipv4_addr.sin_port = htons(port_max_bind.port);
1427
1428 ruleset_fd =
1429 landlock_create_ruleset(attr: &ruleset_attr, size: sizeof(ruleset_attr), flags: 0);
1430 ASSERT_LE(0, ruleset_fd);
1431
1432 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1433 &port_max_bind, 0));
1434
1435 EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1436 &port_overflow1, 0));
1437 EXPECT_EQ(EINVAL, errno);
1438
1439 EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1440 &port_overflow2, 0));
1441 EXPECT_EQ(EINVAL, errno);
1442
1443 EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1444 &port_overflow3, 0));
1445 EXPECT_EQ(EINVAL, errno);
1446
1447 /* Interleaves with invalid rule additions. */
1448 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1449 &port_max_connect, 0));
1450
1451 EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1452 &port_overflow4, 0));
1453 EXPECT_EQ(EINVAL, errno);
1454
1455 enforce_ruleset(_metadata, ruleset_fd);
1456
1457 test_bind_and_connect(_metadata, srv: &srv_denied, deny_bind: true, deny_connect: true);
1458 test_bind_and_connect(_metadata, srv: &srv_max_allowed, deny_bind: false, deny_connect: false);
1459}
1460
1461FIXTURE(ipv4_tcp)
1462{
1463 struct service_fixture srv0, srv1;
1464};
1465
1466FIXTURE_SETUP(ipv4_tcp)
1467{
1468 const struct protocol_variant ipv4_tcp = {
1469 .domain = AF_INET,
1470 .type = SOCK_STREAM,
1471 };
1472
1473 disable_caps(_metadata);
1474
1475 ASSERT_EQ(0, set_service(&self->srv0, ipv4_tcp, 0));
1476 ASSERT_EQ(0, set_service(&self->srv1, ipv4_tcp, 1));
1477
1478 setup_loopback(_metadata);
1479};
1480
1481FIXTURE_TEARDOWN(ipv4_tcp)
1482{
1483}
1484
1485TEST_F(ipv4_tcp, port_endianness)
1486{
1487 const struct landlock_ruleset_attr ruleset_attr = {
1488 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
1489 LANDLOCK_ACCESS_NET_CONNECT_TCP,
1490 };
1491 const struct landlock_net_port_attr bind_host_endian_p0 = {
1492 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
1493 /* Host port format. */
1494 .port = self->srv0.port,
1495 };
1496 const struct landlock_net_port_attr connect_big_endian_p0 = {
1497 .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP,
1498 /* Big endian port format. */
1499 .port = htons(self->srv0.port),
1500 };
1501 const struct landlock_net_port_attr bind_connect_host_endian_p1 = {
1502 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
1503 LANDLOCK_ACCESS_NET_CONNECT_TCP,
1504 /* Host port format. */
1505 .port = self->srv1.port,
1506 };
1507 const unsigned int one = 1;
1508 const char little_endian = *(const char *)&one;
1509 int ruleset_fd;
1510
1511 ruleset_fd =
1512 landlock_create_ruleset(attr: &ruleset_attr, size: sizeof(ruleset_attr), flags: 0);
1513 ASSERT_LE(0, ruleset_fd);
1514 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1515 &bind_host_endian_p0, 0));
1516 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1517 &connect_big_endian_p0, 0));
1518 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1519 &bind_connect_host_endian_p1, 0));
1520 enforce_ruleset(_metadata, ruleset_fd);
1521
1522 /* No restriction for big endinan CPU. */
1523 test_bind_and_connect(_metadata, srv: &self->srv0, deny_bind: false, deny_connect: little_endian);
1524
1525 /* No restriction for any CPU. */
1526 test_bind_and_connect(_metadata, srv: &self->srv1, deny_bind: false, deny_connect: false);
1527}
1528
1529TEST_F(ipv4_tcp, with_fs)
1530{
1531 const struct landlock_ruleset_attr ruleset_attr_fs_net = {
1532 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR,
1533 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP,
1534 };
1535 struct landlock_path_beneath_attr path_beneath = {
1536 .allowed_access = LANDLOCK_ACCESS_FS_READ_DIR,
1537 .parent_fd = -1,
1538 };
1539 struct landlock_net_port_attr tcp_bind = {
1540 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
1541 .port = self->srv0.port,
1542 };
1543 int ruleset_fd, bind_fd, dir_fd;
1544
1545 /* Creates ruleset both for filesystem and network access. */
1546 ruleset_fd = landlock_create_ruleset(attr: &ruleset_attr_fs_net,
1547 size: sizeof(ruleset_attr_fs_net), flags: 0);
1548 ASSERT_LE(0, ruleset_fd);
1549
1550 /* Adds a filesystem rule. */
1551 path_beneath.parent_fd = open("/dev", O_PATH | O_DIRECTORY | O_CLOEXEC);
1552 ASSERT_LE(0, path_beneath.parent_fd);
1553 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
1554 &path_beneath, 0));
1555 EXPECT_EQ(0, close(path_beneath.parent_fd));
1556
1557 /* Adds a network rule. */
1558 ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1559 &tcp_bind, 0));
1560
1561 enforce_ruleset(_metadata, ruleset_fd);
1562 EXPECT_EQ(0, close(ruleset_fd));
1563
1564 /* Tests file access. */
1565 dir_fd = open("/dev", O_RDONLY);
1566 EXPECT_LE(0, dir_fd);
1567 EXPECT_EQ(0, close(dir_fd));
1568
1569 dir_fd = open("/", O_RDONLY);
1570 EXPECT_EQ(-1, dir_fd);
1571 EXPECT_EQ(EACCES, errno);
1572
1573 /* Tests port binding. */
1574 bind_fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
1575 ASSERT_LE(0, bind_fd);
1576 EXPECT_EQ(0, bind_variant(bind_fd, &self->srv0));
1577 EXPECT_EQ(0, close(bind_fd));
1578
1579 bind_fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
1580 ASSERT_LE(0, bind_fd);
1581 EXPECT_EQ(-EACCES, bind_variant(bind_fd, &self->srv1));
1582}
1583
1584FIXTURE(port_specific)
1585{
1586 struct service_fixture srv0;
1587};
1588
1589FIXTURE_VARIANT(port_specific)
1590{
1591 const enum sandbox_type sandbox;
1592 const struct protocol_variant prot;
1593};
1594
1595/* clang-format off */
1596FIXTURE_VARIANT_ADD(port_specific, no_sandbox_with_ipv4) {
1597 /* clang-format on */
1598 .sandbox = NO_SANDBOX,
1599 .prot = {
1600 .domain = AF_INET,
1601 .type = SOCK_STREAM,
1602 },
1603};
1604
1605/* clang-format off */
1606FIXTURE_VARIANT_ADD(port_specific, sandbox_with_ipv4) {
1607 /* clang-format on */
1608 .sandbox = TCP_SANDBOX,
1609 .prot = {
1610 .domain = AF_INET,
1611 .type = SOCK_STREAM,
1612 },
1613};
1614
1615/* clang-format off */
1616FIXTURE_VARIANT_ADD(port_specific, no_sandbox_with_ipv6) {
1617 /* clang-format on */
1618 .sandbox = NO_SANDBOX,
1619 .prot = {
1620 .domain = AF_INET6,
1621 .type = SOCK_STREAM,
1622 },
1623};
1624
1625/* clang-format off */
1626FIXTURE_VARIANT_ADD(port_specific, sandbox_with_ipv6) {
1627 /* clang-format on */
1628 .sandbox = TCP_SANDBOX,
1629 .prot = {
1630 .domain = AF_INET6,
1631 .type = SOCK_STREAM,
1632 },
1633};
1634
1635FIXTURE_SETUP(port_specific)
1636{
1637 disable_caps(_metadata);
1638
1639 ASSERT_EQ(0, set_service(&self->srv0, variant->prot, 0));
1640
1641 setup_loopback(_metadata);
1642};
1643
1644FIXTURE_TEARDOWN(port_specific)
1645{
1646}
1647
1648TEST_F(port_specific, bind_connect_zero)
1649{
1650 int bind_fd, connect_fd, ret;
1651 uint16_t port;
1652
1653 /* Adds a rule layer with bind and connect actions. */
1654 if (variant->sandbox == TCP_SANDBOX) {
1655 const struct landlock_ruleset_attr ruleset_attr = {
1656 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
1657 LANDLOCK_ACCESS_NET_CONNECT_TCP
1658 };
1659 const struct landlock_net_port_attr tcp_bind_connect_zero = {
1660 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
1661 LANDLOCK_ACCESS_NET_CONNECT_TCP,
1662 .port = 0,
1663 };
1664 int ruleset_fd;
1665
1666 ruleset_fd = landlock_create_ruleset(attr: &ruleset_attr,
1667 size: sizeof(ruleset_attr), flags: 0);
1668 ASSERT_LE(0, ruleset_fd);
1669
1670 /* Checks zero port value on bind and connect actions. */
1671 EXPECT_EQ(0,
1672 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1673 &tcp_bind_connect_zero, 0));
1674
1675 enforce_ruleset(_metadata, ruleset_fd);
1676 EXPECT_EQ(0, close(ruleset_fd));
1677 }
1678
1679 bind_fd = socket_variant(srv: &self->srv0);
1680 ASSERT_LE(0, bind_fd);
1681
1682 connect_fd = socket_variant(srv: &self->srv0);
1683 ASSERT_LE(0, connect_fd);
1684
1685 /* Sets address port to 0 for both protocol families. */
1686 set_port(srv: &self->srv0, port: 0);
1687 /*
1688 * Binds on port 0, which selects a random port within
1689 * ip_local_port_range.
1690 */
1691 ret = bind_variant(sock_fd: bind_fd, srv: &self->srv0);
1692 EXPECT_EQ(0, ret);
1693
1694 EXPECT_EQ(0, listen(bind_fd, backlog));
1695
1696 /* Connects on port 0. */
1697 ret = connect_variant(sock_fd: connect_fd, srv: &self->srv0);
1698 EXPECT_EQ(-ECONNREFUSED, ret);
1699
1700 /* Sets binded port for both protocol families. */
1701 port = get_binded_port(socket_fd: bind_fd, prot: &variant->prot);
1702 EXPECT_NE(0, port);
1703 set_port(srv: &self->srv0, port);
1704 /* Connects on the binded port. */
1705 ret = connect_variant(sock_fd: connect_fd, srv: &self->srv0);
1706 if (is_restricted(prot: &variant->prot, sandbox: variant->sandbox)) {
1707 /* Denied by Landlock. */
1708 EXPECT_EQ(-EACCES, ret);
1709 } else {
1710 EXPECT_EQ(0, ret);
1711 }
1712
1713 EXPECT_EQ(0, close(connect_fd));
1714 EXPECT_EQ(0, close(bind_fd));
1715}
1716
1717TEST_F(port_specific, bind_connect_1023)
1718{
1719 int bind_fd, connect_fd, ret;
1720
1721 /* Adds a rule layer with bind and connect actions. */
1722 if (variant->sandbox == TCP_SANDBOX) {
1723 const struct landlock_ruleset_attr ruleset_attr = {
1724 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
1725 LANDLOCK_ACCESS_NET_CONNECT_TCP
1726 };
1727 /* A rule with port value less than 1024. */
1728 const struct landlock_net_port_attr tcp_bind_connect_low_range = {
1729 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
1730 LANDLOCK_ACCESS_NET_CONNECT_TCP,
1731 .port = 1023,
1732 };
1733 /* A rule with 1024 port. */
1734 const struct landlock_net_port_attr tcp_bind_connect = {
1735 .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
1736 LANDLOCK_ACCESS_NET_CONNECT_TCP,
1737 .port = 1024,
1738 };
1739 int ruleset_fd;
1740
1741 ruleset_fd = landlock_create_ruleset(attr: &ruleset_attr,
1742 size: sizeof(ruleset_attr), flags: 0);
1743 ASSERT_LE(0, ruleset_fd);
1744
1745 ASSERT_EQ(0,
1746 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1747 &tcp_bind_connect_low_range, 0));
1748 ASSERT_EQ(0,
1749 landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
1750 &tcp_bind_connect, 0));
1751
1752 enforce_ruleset(_metadata, ruleset_fd);
1753 EXPECT_EQ(0, close(ruleset_fd));
1754 }
1755
1756 bind_fd = socket_variant(srv: &self->srv0);
1757 ASSERT_LE(0, bind_fd);
1758
1759 connect_fd = socket_variant(srv: &self->srv0);
1760 ASSERT_LE(0, connect_fd);
1761
1762 /* Sets address port to 1023 for both protocol families. */
1763 set_port(srv: &self->srv0, port: 1023);
1764 /* Binds on port 1023. */
1765 ret = bind_variant(sock_fd: bind_fd, srv: &self->srv0);
1766 /* Denied by the system. */
1767 EXPECT_EQ(-EACCES, ret);
1768
1769 /* Binds on port 1023. */
1770 set_cap(_metadata, CAP_NET_BIND_SERVICE);
1771 ret = bind_variant(sock_fd: bind_fd, srv: &self->srv0);
1772 clear_cap(_metadata, CAP_NET_BIND_SERVICE);
1773 EXPECT_EQ(0, ret);
1774 EXPECT_EQ(0, listen(bind_fd, backlog));
1775
1776 /* Connects on the binded port 1023. */
1777 ret = connect_variant(sock_fd: connect_fd, srv: &self->srv0);
1778 EXPECT_EQ(0, ret);
1779
1780 EXPECT_EQ(0, close(connect_fd));
1781 EXPECT_EQ(0, close(bind_fd));
1782
1783 bind_fd = socket_variant(srv: &self->srv0);
1784 ASSERT_LE(0, bind_fd);
1785
1786 connect_fd = socket_variant(srv: &self->srv0);
1787 ASSERT_LE(0, connect_fd);
1788
1789 /* Sets address port to 1024 for both protocol families. */
1790 set_port(srv: &self->srv0, port: 1024);
1791 /* Binds on port 1024. */
1792 ret = bind_variant(sock_fd: bind_fd, srv: &self->srv0);
1793 EXPECT_EQ(0, ret);
1794 EXPECT_EQ(0, listen(bind_fd, backlog));
1795
1796 /* Connects on the binded port 1024. */
1797 ret = connect_variant(sock_fd: connect_fd, srv: &self->srv0);
1798 EXPECT_EQ(0, ret);
1799
1800 EXPECT_EQ(0, close(connect_fd));
1801 EXPECT_EQ(0, close(bind_fd));
1802}
1803
1804TEST_HARNESS_MAIN
1805

source code of linux/tools/testing/selftests/landlock/net_test.c