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