• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Copyright (C) 2024 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
4  */
5 
6 #ifndef LANDLOCK_COMMON_H__
7 #define LANDLOCK_COMMON_H__
8 
9 #include "tst_test.h"
10 #include "lapi/prctl.h"
11 #include "lapi/fcntl.h"
12 #include "lapi/landlock.h"
13 
14 #define IPV4_LOCALHOST "127.0.0.1"
15 #define IPV6_LOCALHOST "::1"
16 
17 struct socket_data {
18 	struct sockaddr_in addr_ipv4;
19 	struct sockaddr_in6 addr_ipv6;
20 	size_t address_size;
21 	int fd;
22 };
23 
verify_landlock_is_enabled(void)24 static inline int verify_landlock_is_enabled(void)
25 {
26 	int abi;
27 
28 	abi = tst_syscall(__NR_landlock_create_ruleset,
29 		NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
30 
31 	if (abi < 0) {
32 		if (errno == EOPNOTSUPP) {
33 			tst_brk(TCONF, "Landlock is currently disabled. "
34 				"Please enable it either via CONFIG_LSM or "
35 				"'lsm' kernel parameter.");
36 		}
37 
38 		tst_brk(TBROK | TERRNO, "landlock_create_ruleset error");
39 	}
40 
41 	tst_res(TINFO, "Landlock ABI v%d", abi);
42 
43 	return abi;
44 }
45 
apply_landlock_fs_rule(struct landlock_path_beneath_attr * path_beneath_attr,const int ruleset_fd,const int access,const char * path)46 static inline void apply_landlock_fs_rule(
47 	struct landlock_path_beneath_attr *path_beneath_attr,
48 	const int ruleset_fd,
49 	const int access,
50 	const char *path)
51 {
52 	path_beneath_attr->allowed_access = access;
53 	path_beneath_attr->parent_fd = SAFE_OPEN(path, O_PATH | O_CLOEXEC);
54 
55 	SAFE_LANDLOCK_ADD_RULE(
56 		ruleset_fd,
57 		LANDLOCK_RULE_PATH_BENEATH,
58 		path_beneath_attr,
59 		0);
60 
61 	SAFE_CLOSE(path_beneath_attr->parent_fd);
62 }
63 
apply_landlock_net_rule(struct landlock_net_port_attr * net_attr,const int ruleset_fd,const uint64_t port,const uint64_t access)64 static inline void apply_landlock_net_rule(
65 	struct landlock_net_port_attr *net_attr,
66 	const int ruleset_fd,
67 	const uint64_t port,
68 	const uint64_t access)
69 {
70 	net_attr->port = port;
71 	net_attr->allowed_access = access;
72 
73 	SAFE_LANDLOCK_ADD_RULE(
74 		ruleset_fd,
75 		LANDLOCK_RULE_NET_PORT,
76 		net_attr,
77 		0);
78 }
79 
enforce_ruleset(const int ruleset_fd)80 static inline void enforce_ruleset(const int ruleset_fd)
81 {
82 	SAFE_PRCTL(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
83 	SAFE_LANDLOCK_RESTRICT_SELF(ruleset_fd, 0);
84 }
85 
apply_landlock_fs_layer(void * ruleset_attr,size_t attr_size,struct landlock_path_beneath_attr * path_beneath_attr,const char * path,const int access)86 static inline void apply_landlock_fs_layer(
87 	void *ruleset_attr, size_t attr_size,
88 	struct landlock_path_beneath_attr *path_beneath_attr,
89 	const char *path,
90 	const int access)
91 {
92 	int ruleset_fd;
93 
94 	ruleset_fd = SAFE_LANDLOCK_CREATE_RULESET(ruleset_attr, attr_size, 0);
95 
96 	apply_landlock_fs_rule(path_beneath_attr, ruleset_fd, access, path);
97 	enforce_ruleset(ruleset_fd);
98 
99 	SAFE_CLOSE(ruleset_fd);
100 }
101 
apply_landlock_net_layer(void * ruleset_attr,size_t attr_size,struct landlock_net_port_attr * net_port_attr,const in_port_t port,const uint64_t access)102 static inline void apply_landlock_net_layer(
103 	void *ruleset_attr, size_t attr_size,
104 	struct landlock_net_port_attr *net_port_attr,
105 	const in_port_t port,
106 	const uint64_t access)
107 {
108 	int ruleset_fd;
109 
110 	ruleset_fd = SAFE_LANDLOCK_CREATE_RULESET(ruleset_attr, attr_size, 0);
111 
112 	apply_landlock_net_rule(net_port_attr, ruleset_fd, port, access);
113 	enforce_ruleset(ruleset_fd);
114 
115 	SAFE_CLOSE(ruleset_fd);
116 }
117 
getsocket_port(struct socket_data * socket,const int addr_family)118 static inline in_port_t getsocket_port(struct socket_data *socket,
119 	const int addr_family)
120 {
121 	struct sockaddr_in addr_ipv4;
122 	struct sockaddr_in6 addr_ipv6;
123 	socklen_t len;
124 	in_port_t port = 0;
125 
126 	switch (addr_family) {
127 	case AF_INET:
128 		len = sizeof(addr_ipv4);
129 		memset(&addr_ipv4, 0, len);
130 
131 		SAFE_GETSOCKNAME(socket->fd, (struct sockaddr *)&addr_ipv4, &len);
132 		port = ntohs(addr_ipv4.sin_port);
133 		break;
134 	case AF_INET6:
135 		len = sizeof(addr_ipv6);
136 		memset(&addr_ipv6, 0, len);
137 
138 		SAFE_GETSOCKNAME(socket->fd, (struct sockaddr *)&addr_ipv6, &len);
139 		port = ntohs(addr_ipv6.sin6_port);
140 		break;
141 	default:
142 		tst_brk(TBROK, "Unsupported protocol");
143 		break;
144 	};
145 
146 	return port;
147 }
148 
create_socket(struct socket_data * socket,const int addr_family,const in_port_t port)149 static inline void create_socket(struct socket_data *socket,
150 	const int addr_family, const in_port_t port)
151 {
152 	memset(socket, 0, sizeof(struct socket_data));
153 
154 	switch (addr_family) {
155 	case AF_INET:
156 		if (!port) {
157 			tst_init_sockaddr_inet_bin(&socket->addr_ipv4,
158 				INADDR_ANY, 0);
159 		} else {
160 			tst_init_sockaddr_inet(&socket->addr_ipv4,
161 				IPV4_LOCALHOST, port);
162 		}
163 
164 		socket->address_size = sizeof(struct sockaddr_in);
165 		break;
166 	case AF_INET6:
167 		if (!port) {
168 			tst_init_sockaddr_inet6_bin(&socket->addr_ipv6,
169 				&in6addr_any, 0);
170 		} else {
171 			tst_init_sockaddr_inet6(&socket->addr_ipv6,
172 				IPV6_LOCALHOST, port);
173 		}
174 
175 		socket->address_size = sizeof(struct sockaddr_in6);
176 		break;
177 	default:
178 		tst_brk(TBROK, "Unsupported protocol");
179 		return;
180 	};
181 
182 	socket->fd = SAFE_SOCKET(addr_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
183 }
184 
getsocket_addr(struct socket_data * socket,const int addr_family,struct sockaddr ** addr)185 static inline void getsocket_addr(struct socket_data *socket,
186 	const int addr_family, struct sockaddr **addr)
187 {
188 	switch (addr_family) {
189 	case AF_INET:
190 		*addr = (struct sockaddr *)&socket->addr_ipv4;
191 		break;
192 	case AF_INET6:
193 		*addr = (struct sockaddr *)&socket->addr_ipv6;
194 		break;
195 	default:
196 		break;
197 	};
198 }
199 #endif /* LANDLOCK_COMMON_H__ */
200