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