]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-bpf-devices.c
tree-wide: avoid some loaded terms
[thirdparty/systemd.git] / src / test / test-bpf-devices.c
CommitLineData
7973f564
ZJS
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <sys/resource.h>
4#include <sys/time.h>
5#include <unistd.h>
6
7#include "alloc-util.h"
8#include "bpf-devices.h"
9#include "bpf-program.h"
10#include "cgroup-setup.h"
11#include "errno-list.h"
12#include "fd-util.h"
13#include "fs-util.h"
14#include "path-util.h"
15#include "tests.h"
16
17static void test_policy_closed(const char *cgroup_path, BPFProgram **installed_prog) {
18 _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
19 unsigned wrong = 0;
20 int r;
21
22 log_info("/* %s */", __func__);
23
24 r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_CLOSED, true);
25 assert_se(r >= 0);
26
6b000af4 27 r = bpf_devices_allow_list_static(prog, cgroup_path);
7973f564
ZJS
28 assert_se(r >= 0);
29
30 r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_CLOSED, true, cgroup_path, installed_prog);
31 assert_se(r >= 0);
32
33 const char *s;
34 FOREACH_STRING(s, "/dev/null",
35 "/dev/zero",
36 "/dev/full",
37 "/dev/random",
38 "/dev/urandom",
39 "/dev/tty",
40 "/dev/ptmx") {
41 _cleanup_close_ int fd, fd2;
42
43 fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
44 log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
45 wrong += fd < 0 && errno == EPERM;
46 /* We ignore errors other than EPERM, e.g. ENOENT or ENXIO */
47
48 fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
49 log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
50 wrong += fd2 < 0 && errno == EPERM;
51 }
52 assert_se(wrong == 0);
53}
54
55static void test_policy_strict(const char *cgroup_path, BPFProgram **installed_prog) {
56 _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
57 unsigned wrong = 0;
58 int r;
59
60 log_info("/* %s */", __func__);
61
62 r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
63 assert_se(r >= 0);
64
6b000af4 65 r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/null", "rw");
7973f564
ZJS
66 assert_se(r >= 0);
67
6b000af4 68 r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/random", "r");
7973f564
ZJS
69 assert_se(r >= 0);
70
6b000af4 71 r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/zero", "w");
7973f564
ZJS
72 assert_se(r >= 0);
73
74 r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
75 assert_se(r >= 0);
76
77 {
78 _cleanup_close_ int fd, fd2;
79 const char *s = "/dev/null";
80
81 fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
82 log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
83 wrong += fd < 0;
84
85 fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
86 log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
87 wrong += fd2 < 0;
88 }
89
90 {
91 _cleanup_close_ int fd, fd2;
92 const char *s = "/dev/random";
93
94 fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
95 log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
96 wrong += fd < 0;
97
98 fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
99 log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
100 wrong += fd2 >= 0;
101 }
102
103 {
104 _cleanup_close_ int fd, fd2;
105 const char *s = "/dev/zero";
106
107 fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
108 log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
109 wrong += fd >= 0;
110
111 fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
112 log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
113 wrong += fd2 < 0;
114 }
115
116 {
117 _cleanup_close_ int fd, fd2;
118 const char *s = "/dev/full";
119
120 fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
121 log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
122 wrong += fd >= 0;
123
124 fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
125 log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
126 wrong += fd2 >= 0;
127 }
128
129 assert_se(wrong == 0);
130}
131
6b000af4 132static void test_policy_allow_list_major(const char *pattern, const char *cgroup_path, BPFProgram **installed_prog) {
7973f564
ZJS
133 _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
134 unsigned wrong = 0;
135 int r;
136
137 log_info("/* %s(%s) */", __func__, pattern);
138
139 r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
140 assert_se(r >= 0);
141
6b000af4 142 r = bpf_devices_allow_list_major(prog, cgroup_path, pattern, 'c', "rw");
7973f564
ZJS
143 assert_se(r >= 0);
144
145 r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
146 assert_se(r >= 0);
147
148 /* /dev/null, /dev/full have major==1, /dev/tty has major==5 */
149 {
150 _cleanup_close_ int fd, fd2;
151 const char *s = "/dev/null";
152
153 fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
154 log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
155 wrong += fd < 0;
156
157 fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
158 log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
159 wrong += fd2 < 0;
160 }
161
162 {
163 _cleanup_close_ int fd, fd2;
164 const char *s = "/dev/full";
165
166 fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
167 log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
168 wrong += fd < 0;
169
170 fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
171 log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
172 wrong += fd2 < 0;
173 }
174
175 {
176 _cleanup_close_ int fd, fd2;
177 const char *s = "/dev/tty";
178
179 fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
180 log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
181 wrong += fd >= 0;
182
183 fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
184 log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
185 wrong += fd2 >= 0;
186 }
187
188 assert_se(wrong == 0);
189}
190
6b000af4 191static void test_policy_allow_list_major_star(char type, const char *cgroup_path, BPFProgram **installed_prog) {
7973f564
ZJS
192 _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
193 unsigned wrong = 0;
194 int r;
195
196 log_info("/* %s(type=%c) */", __func__, type);
197
198 r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
199 assert_se(r >= 0);
200
6b000af4 201 r = bpf_devices_allow_list_major(prog, cgroup_path, "*", type, "rw");
7973f564
ZJS
202 assert_se(r >= 0);
203
204 r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
205 assert_se(r >= 0);
206
207 {
208 _cleanup_close_ int fd;
209 const char *s = "/dev/null";
210
211 fd = open(s, O_CLOEXEC|O_RDWR|O_NOCTTY);
212 log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
213 if (type == 'c')
214 wrong += fd < 0;
215 else
216 wrong += fd >= 0;
217 }
218
219 assert_se(wrong == 0);
220}
221
45669ae2
ZJS
222static void test_policy_empty(bool add_mismatched, const char *cgroup_path, BPFProgram **installed_prog) {
223 _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
224 unsigned wrong = 0;
225 int r;
226
227 log_info("/* %s(add_mismatched=%s) */", __func__, yes_no(add_mismatched));
228
229 r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, add_mismatched);
230 assert_se(r >= 0);
231
232 if (add_mismatched) {
6b000af4 233 r = bpf_devices_allow_list_major(prog, cgroup_path, "foobarxxx", 'c', "rw");
45669ae2
ZJS
234 assert_se(r < 0);
235 }
236
237 r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, false, cgroup_path, installed_prog);
238 assert_se(r >= 0);
239
240 {
241 _cleanup_close_ int fd;
242 const char *s = "/dev/null";
243
244 fd = open(s, O_CLOEXEC|O_RDWR|O_NOCTTY);
245 log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
246 wrong += fd >= 0;
247 }
248
249 assert_se(wrong == 0);
250}
251
252
7973f564
ZJS
253int main(int argc, char *argv[]) {
254 _cleanup_free_ char *cgroup = NULL, *parent = NULL;
255 _cleanup_(rmdir_and_freep) char *controller_path = NULL;
256 CGroupMask supported;
257 struct rlimit rl;
258 int r;
259
260 test_setup_logging(LOG_DEBUG);
261
262 assert_se(getrlimit(RLIMIT_MEMLOCK, &rl) >= 0);
263 rl.rlim_cur = rl.rlim_max = MAX(rl.rlim_max, CAN_MEMLOCK_SIZE);
264 (void) setrlimit(RLIMIT_MEMLOCK, &rl);
265
26444635
ZJS
266 r = cg_all_unified();
267 if (r <= 0)
268 return log_tests_skipped("We don't seem to be running with unified cgroup hierarchy");
269
7973f564
ZJS
270 if (!can_memlock())
271 return log_tests_skipped("Can't use mlock()");
272
273 r = enter_cgroup_subroot(&cgroup);
274 if (r == -ENOMEDIUM)
275 return log_tests_skipped("cgroupfs not available");
276
277 r = bpf_devices_supported();
278 if (!r)
279 return log_tests_skipped("BPF device filter not supported");
280 assert_se(r == 1);
281
282 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, cgroup, NULL, &controller_path);
283 assert_se(r >= 0);
284
285 _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
286
287 test_policy_closed(cgroup, &prog);
288 test_policy_strict(cgroup, &prog);
289
6b000af4
LP
290 test_policy_allow_list_major("mem", cgroup, &prog);
291 test_policy_allow_list_major("1", cgroup, &prog);
7973f564 292
6b000af4
LP
293 test_policy_allow_list_major_star('c', cgroup, &prog);
294 test_policy_allow_list_major_star('b', cgroup, &prog);
7973f564 295
45669ae2
ZJS
296 test_policy_empty(false, cgroup, &prog);
297 test_policy_empty(true, cgroup, &prog);
298
7973f564
ZJS
299 assert_se(parent = dirname_malloc(cgroup));
300
301 assert_se(cg_mask_supported(&supported) >= 0);
302 r = cg_attach_everywhere(supported, parent, 0, NULL, NULL);
303 assert_se(r >= 0);
304
305 return 0;
306}