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