Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <poll.h>
4 : : #include <sched.h>
5 : : #include <stdlib.h>
6 : : #include <sys/eventfd.h>
7 : : #include <sys/mman.h>
8 : : #include <sys/personality.h>
9 : : #include <sys/shm.h>
10 : : #include <sys/syscall.h>
11 : : #include <sys/types.h>
12 : : #include <unistd.h>
13 : :
14 : : #include "alloc-util.h"
15 : : #include "fd-util.h"
16 : : #include "macro.h"
17 : : #include "memory-util.h"
18 : : #include "missing.h"
19 : : #include "nsflags.h"
20 : : #include "nulstr-util.h"
21 : : #include "process-util.h"
22 : : #include "raw-clone.h"
23 : : #include "rm-rf.h"
24 : : #include "seccomp-util.h"
25 : : #include "set.h"
26 : : #include "string-util.h"
27 : : #include "tests.h"
28 : : #include "tmpfile-util.h"
29 : : #include "virt.h"
30 : :
31 : : #if SCMP_SYS(socket) < 0 || defined(__i386__) || defined(__s390x__) || defined(__s390__)
32 : : /* On these archs, socket() is implemented via the socketcall() syscall multiplexer,
33 : : * and we can't restrict it hence via seccomp. */
34 : : # define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 1
35 : : #else
36 : : # define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 0
37 : : #endif
38 : :
39 : 4 : static void test_seccomp_arch_to_string(void) {
40 : : uint32_t a, b;
41 : : const char *name;
42 : :
43 [ + - ]: 4 : log_info("/* %s */", __func__);
44 : :
45 : 4 : a = seccomp_arch_native();
46 [ - + ]: 4 : assert_se(a > 0);
47 : 4 : name = seccomp_arch_to_string(a);
48 [ - + ]: 4 : assert_se(name);
49 [ - + ]: 4 : assert_se(seccomp_arch_from_string(name, &b) >= 0);
50 [ - + ]: 4 : assert_se(a == b);
51 : 4 : }
52 : :
53 : 4 : static void test_architecture_table(void) {
54 : : const char *n, *n2;
55 : :
56 [ + - ]: 4 : log_info("/* %s */", __func__);
57 : :
58 [ + - + + ]: 72 : NULSTR_FOREACH(n,
59 : : "native\0"
60 : : "x86\0"
61 : : "x86-64\0"
62 : : "x32\0"
63 : : "arm\0"
64 : : "arm64\0"
65 : : "mips\0"
66 : : "mips64\0"
67 : : "mips64-n32\0"
68 : : "mips-le\0"
69 : : "mips64-le\0"
70 : : "mips64-le-n32\0"
71 : : "ppc\0"
72 : : "ppc64\0"
73 : : "ppc64-le\0"
74 : : "s390\0"
75 : : "s390x\0") {
76 : : uint32_t c;
77 : :
78 [ - + ]: 68 : assert_se(seccomp_arch_from_string(n, &c) >= 0);
79 : 68 : n2 = seccomp_arch_to_string(c);
80 [ + - ]: 68 : log_info("seccomp-arch: %s → 0x%"PRIx32" → %s", n, c, n2);
81 [ - + ]: 68 : assert_se(streq_ptr(n, n2));
82 : : }
83 : 4 : }
84 : :
85 : 4 : static void test_syscall_filter_set_find(void) {
86 [ + - ]: 4 : log_info("/* %s */", __func__);
87 : :
88 [ - + ]: 4 : assert_se(!syscall_filter_set_find(NULL));
89 [ - + ]: 4 : assert_se(!syscall_filter_set_find(""));
90 [ - + ]: 4 : assert_se(!syscall_filter_set_find("quux"));
91 [ - + ]: 4 : assert_se(!syscall_filter_set_find("@quux"));
92 : :
93 [ - + ]: 4 : assert_se(syscall_filter_set_find("@clock") == syscall_filter_sets + SYSCALL_FILTER_SET_CLOCK);
94 [ - + ]: 4 : assert_se(syscall_filter_set_find("@default") == syscall_filter_sets + SYSCALL_FILTER_SET_DEFAULT);
95 [ - + ]: 4 : assert_se(syscall_filter_set_find("@raw-io") == syscall_filter_sets + SYSCALL_FILTER_SET_RAW_IO);
96 : 4 : }
97 : :
98 : 4 : static void test_filter_sets(void) {
99 : : unsigned i;
100 : : int r;
101 : :
102 [ + - ]: 4 : log_info("/* %s */", __func__);
103 : :
104 [ - + ]: 4 : if (!is_seccomp_available()) {
105 [ # # ]: 0 : log_notice("Seccomp not available, skipping %s", __func__);
106 : 0 : return;
107 : : }
108 [ + - ]: 4 : if (geteuid() != 0) {
109 [ + - ]: 4 : log_notice("Not root, skipping %s", __func__);
110 : 4 : return;
111 : : }
112 : :
113 [ # # ]: 0 : for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
114 : : pid_t pid;
115 : :
116 [ # # ]: 0 : log_info("Testing %s", syscall_filter_sets[i].name);
117 : :
118 : 0 : pid = fork();
119 [ # # ]: 0 : assert_se(pid >= 0);
120 : :
121 [ # # ]: 0 : if (pid == 0) { /* Child? */
122 : : int fd;
123 : :
124 : : /* If we look at the default set (or one that includes it), whitelist instead of blacklist */
125 [ # # # # ]: 0 : if (IN_SET(i, SYSCALL_FILTER_SET_DEFAULT, SYSCALL_FILTER_SET_SYSTEM_SERVICE))
126 : 0 : r = seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN), syscall_filter_sets + i, SCMP_ACT_ALLOW, true);
127 : : else
128 : 0 : r = seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + i, SCMP_ACT_ERRNO(EUCLEAN), true);
129 [ # # ]: 0 : if (r < 0)
130 : 0 : _exit(EXIT_FAILURE);
131 : :
132 : : /* Test the sycall filter with one random system call */
133 : 0 : fd = eventfd(0, EFD_NONBLOCK|EFD_CLOEXEC);
134 [ # # # # ]: 0 : if (IN_SET(i, SYSCALL_FILTER_SET_IO_EVENT, SYSCALL_FILTER_SET_DEFAULT))
135 [ # # # # ]: 0 : assert_se(fd < 0 && errno == EUCLEAN);
136 : : else {
137 [ # # ]: 0 : assert_se(fd >= 0);
138 : 0 : safe_close(fd);
139 : : }
140 : :
141 : 0 : _exit(EXIT_SUCCESS);
142 : : }
143 : :
144 [ # # ]: 0 : assert_se(wait_for_terminate_and_check(syscall_filter_sets[i].name, pid, WAIT_LOG) == EXIT_SUCCESS);
145 : : }
146 : : }
147 : :
148 : 4 : static void test_filter_sets_ordered(void) {
149 : : size_t i;
150 : :
151 [ + - ]: 4 : log_info("/* %s */", __func__);
152 : :
153 : : /* Ensure "@default" always remains at the beginning of the list */
154 : : assert_se(SYSCALL_FILTER_SET_DEFAULT == 0);
155 [ - + ]: 4 : assert_se(streq(syscall_filter_sets[0].name, "@default"));
156 : :
157 [ + + ]: 112 : for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
158 : 108 : const char *k, *p = NULL;
159 : :
160 : : /* Make sure each group has a description */
161 [ - + ]: 108 : assert_se(!isempty(syscall_filter_sets[0].help));
162 : :
163 : : /* Make sure the groups are ordered alphabetically, except for the first entry */
164 [ + + - + ]: 108 : assert_se(i < 2 || strcmp(syscall_filter_sets[i-1].name, syscall_filter_sets[i].name) < 0);
165 : :
166 [ + - + + ]: 1912 : NULSTR_FOREACH(k, syscall_filter_sets[i].value) {
167 : :
168 : : /* Ensure each syscall list is in itself ordered, but groups before names */
169 [ + + + + : 1804 : assert_se(!p ||
+ + + + +
+ + + - +
+ + + - -
+ - + + -
- + - + ]
170 : : (*p == '@' && *k != '@') ||
171 : : (((*p == '@' && *k == '@') ||
172 : : (*p != '@' && *k != '@')) &&
173 : : strcmp(p, k) < 0));
174 : :
175 : 1804 : p = k;
176 : : }
177 : : }
178 : 4 : }
179 : :
180 : 4 : static void test_restrict_namespace(void) {
181 : 4 : char *s = NULL;
182 : : unsigned long ul;
183 : : pid_t pid;
184 : :
185 [ + - ]: 4 : if (!have_namespaces()) {
186 [ + - ]: 4 : log_notice("Testing without namespaces, skipping %s", __func__);
187 : 4 : return;
188 : : }
189 : :
190 [ # # ]: 0 : log_info("/* %s */", __func__);
191 : :
192 [ # # # # ]: 0 : assert_se(namespace_flags_to_string(0, &s) == 0 && streq(s, ""));
193 : 0 : s = mfree(s);
194 [ # # # # ]: 0 : assert_se(namespace_flags_to_string(CLONE_NEWNS, &s) == 0 && streq(s, "mnt"));
195 : 0 : s = mfree(s);
196 [ # # # # ]: 0 : assert_se(namespace_flags_to_string(CLONE_NEWNS|CLONE_NEWIPC, &s) == 0 && streq(s, "ipc mnt"));
197 : 0 : s = mfree(s);
198 [ # # # # ]: 0 : assert_se(namespace_flags_to_string(CLONE_NEWCGROUP, &s) == 0 && streq(s, "cgroup"));
199 : 0 : s = mfree(s);
200 : :
201 [ # # # # ]: 0 : assert_se(namespace_flags_from_string("mnt", &ul) == 0 && ul == CLONE_NEWNS);
202 [ # # # # ]: 0 : assert_se(namespace_flags_from_string(NULL, &ul) == 0 && ul == 0);
203 [ # # # # ]: 0 : assert_se(namespace_flags_from_string("", &ul) == 0 && ul == 0);
204 [ # # # # ]: 0 : assert_se(namespace_flags_from_string("uts", &ul) == 0 && ul == CLONE_NEWUTS);
205 [ # # # # ]: 0 : assert_se(namespace_flags_from_string("mnt uts ipc", &ul) == 0 && ul == (CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC));
206 : :
207 [ # # # # ]: 0 : assert_se(namespace_flags_to_string(CLONE_NEWUTS, &s) == 0 && streq(s, "uts"));
208 [ # # # # ]: 0 : assert_se(namespace_flags_from_string(s, &ul) == 0 && ul == CLONE_NEWUTS);
209 : 0 : s = mfree(s);
210 [ # # # # ]: 0 : assert_se(namespace_flags_from_string("ipc", &ul) == 0 && ul == CLONE_NEWIPC);
211 [ # # # # ]: 0 : assert_se(namespace_flags_to_string(ul, &s) == 0 && streq(s, "ipc"));
212 : 0 : s = mfree(s);
213 : :
214 [ # # ]: 0 : assert_se(namespace_flags_to_string(NAMESPACE_FLAGS_ALL, &s) == 0);
215 [ # # ]: 0 : assert_se(streq(s, "cgroup ipc net mnt pid user uts"));
216 [ # # # # ]: 0 : assert_se(namespace_flags_from_string(s, &ul) == 0 && ul == NAMESPACE_FLAGS_ALL);
217 : 0 : s = mfree(s);
218 : :
219 [ # # ]: 0 : if (!is_seccomp_available()) {
220 [ # # ]: 0 : log_notice("Seccomp not available, skipping remaining tests in %s", __func__);
221 : 0 : return;
222 : : }
223 [ # # ]: 0 : if (geteuid() != 0) {
224 [ # # ]: 0 : log_notice("Not root, skipping remaining tests in %s", __func__);
225 : 0 : return;
226 : : }
227 : :
228 : 0 : pid = fork();
229 [ # # ]: 0 : assert_se(pid >= 0);
230 : :
231 [ # # ]: 0 : if (pid == 0) {
232 : :
233 [ # # ]: 0 : assert_se(seccomp_restrict_namespaces(CLONE_NEWNS|CLONE_NEWNET) >= 0);
234 : :
235 [ # # ]: 0 : assert_se(unshare(CLONE_NEWNS) == 0);
236 [ # # ]: 0 : assert_se(unshare(CLONE_NEWNET) == 0);
237 [ # # ]: 0 : assert_se(unshare(CLONE_NEWUTS) == -1);
238 [ # # ]: 0 : assert_se(errno == EPERM);
239 [ # # ]: 0 : assert_se(unshare(CLONE_NEWIPC) == -1);
240 [ # # ]: 0 : assert_se(errno == EPERM);
241 [ # # ]: 0 : assert_se(unshare(CLONE_NEWNET|CLONE_NEWUTS) == -1);
242 [ # # ]: 0 : assert_se(errno == EPERM);
243 : :
244 : : /* We use fd 0 (stdin) here, which of course will fail with EINVAL on setns(). Except of course our
245 : : * seccomp filter worked, and hits first and makes it return EPERM */
246 [ # # ]: 0 : assert_se(setns(0, CLONE_NEWNS) == -1);
247 [ # # ]: 0 : assert_se(errno == EINVAL);
248 [ # # ]: 0 : assert_se(setns(0, CLONE_NEWNET) == -1);
249 [ # # ]: 0 : assert_se(errno == EINVAL);
250 [ # # ]: 0 : assert_se(setns(0, CLONE_NEWUTS) == -1);
251 [ # # ]: 0 : assert_se(errno == EPERM);
252 [ # # ]: 0 : assert_se(setns(0, CLONE_NEWIPC) == -1);
253 [ # # ]: 0 : assert_se(errno == EPERM);
254 [ # # ]: 0 : assert_se(setns(0, CLONE_NEWNET|CLONE_NEWUTS) == -1);
255 [ # # ]: 0 : assert_se(errno == EPERM);
256 [ # # ]: 0 : assert_se(setns(0, 0) == -1);
257 [ # # ]: 0 : assert_se(errno == EPERM);
258 : :
259 : 0 : pid = raw_clone(CLONE_NEWNS);
260 [ # # ]: 0 : assert_se(pid >= 0);
261 [ # # ]: 0 : if (pid == 0)
262 : 0 : _exit(EXIT_SUCCESS);
263 : 0 : pid = raw_clone(CLONE_NEWNET);
264 [ # # ]: 0 : assert_se(pid >= 0);
265 [ # # ]: 0 : if (pid == 0)
266 : 0 : _exit(EXIT_SUCCESS);
267 : 0 : pid = raw_clone(CLONE_NEWUTS);
268 [ # # ]: 0 : assert_se(pid < 0);
269 [ # # ]: 0 : assert_se(errno == EPERM);
270 : 0 : pid = raw_clone(CLONE_NEWIPC);
271 [ # # ]: 0 : assert_se(pid < 0);
272 [ # # ]: 0 : assert_se(errno == EPERM);
273 : 0 : pid = raw_clone(CLONE_NEWNET|CLONE_NEWUTS);
274 [ # # ]: 0 : assert_se(pid < 0);
275 [ # # ]: 0 : assert_se(errno == EPERM);
276 : :
277 : 0 : _exit(EXIT_SUCCESS);
278 : : }
279 : :
280 [ # # ]: 0 : assert_se(wait_for_terminate_and_check("nsseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
281 : : }
282 : :
283 : 4 : static void test_protect_sysctl(void) {
284 : : pid_t pid;
285 : :
286 [ + - ]: 4 : log_info("/* %s */", __func__);
287 : :
288 [ - + ]: 4 : if (!is_seccomp_available()) {
289 [ # # ]: 0 : log_notice("Seccomp not available, skipping %s", __func__);
290 : 0 : return;
291 : : }
292 [ + - ]: 4 : if (geteuid() != 0) {
293 [ + - ]: 4 : log_notice("Not root, skipping %s", __func__);
294 : 4 : return;
295 : : }
296 : :
297 : : /* in containers _sysctl() is likely missing anyway */
298 [ # # ]: 0 : if (detect_container() > 0) {
299 [ # # ]: 0 : log_notice("Testing in container, skipping %s", __func__);
300 : 0 : return;
301 : : }
302 : :
303 : 0 : pid = fork();
304 [ # # ]: 0 : assert_se(pid >= 0);
305 : :
306 [ # # ]: 0 : if (pid == 0) {
307 : : #if __NR__sysctl > 0
308 [ # # ]: 0 : assert_se(syscall(__NR__sysctl, NULL) < 0);
309 [ # # ]: 0 : assert_se(errno == EFAULT);
310 : : #endif
311 : :
312 [ # # ]: 0 : assert_se(seccomp_protect_sysctl() >= 0);
313 : :
314 : : #if __NR__sysctl > 0
315 [ # # ]: 0 : assert_se(syscall(__NR__sysctl, 0, 0, 0) < 0);
316 [ # # ]: 0 : assert_se(errno == EPERM);
317 : : #endif
318 : :
319 : 0 : _exit(EXIT_SUCCESS);
320 : : }
321 : :
322 [ # # ]: 0 : assert_se(wait_for_terminate_and_check("sysctlseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
323 : : }
324 : :
325 : 4 : static void test_restrict_address_families(void) {
326 : : pid_t pid;
327 : :
328 [ + - ]: 4 : log_info("/* %s */", __func__);
329 : :
330 [ - + ]: 4 : if (!is_seccomp_available()) {
331 [ # # ]: 0 : log_notice("Seccomp not available, skipping %s", __func__);
332 : 0 : return;
333 : : }
334 [ + - ]: 4 : if (geteuid() != 0) {
335 [ + - ]: 4 : log_notice("Not root, skipping %s", __func__);
336 : 4 : return;
337 : : }
338 : :
339 : 0 : pid = fork();
340 [ # # ]: 0 : assert_se(pid >= 0);
341 : :
342 [ # # ]: 0 : if (pid == 0) {
343 : : int fd;
344 : : Set *s;
345 : :
346 : 0 : fd = socket(AF_INET, SOCK_DGRAM, 0);
347 [ # # ]: 0 : assert_se(fd >= 0);
348 : 0 : safe_close(fd);
349 : :
350 : 0 : fd = socket(AF_UNIX, SOCK_DGRAM, 0);
351 [ # # ]: 0 : assert_se(fd >= 0);
352 : 0 : safe_close(fd);
353 : :
354 : 0 : fd = socket(AF_NETLINK, SOCK_DGRAM, 0);
355 [ # # ]: 0 : assert_se(fd >= 0);
356 : 0 : safe_close(fd);
357 : :
358 [ # # ]: 0 : assert_se(s = set_new(NULL));
359 [ # # ]: 0 : assert_se(set_put(s, INT_TO_PTR(AF_UNIX)) >= 0);
360 : :
361 [ # # ]: 0 : assert_se(seccomp_restrict_address_families(s, false) >= 0);
362 : :
363 : 0 : fd = socket(AF_INET, SOCK_DGRAM, 0);
364 [ # # ]: 0 : assert_se(fd >= 0);
365 : 0 : safe_close(fd);
366 : :
367 : 0 : fd = socket(AF_UNIX, SOCK_DGRAM, 0);
368 : : #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
369 : : assert_se(fd >= 0);
370 : : safe_close(fd);
371 : : #else
372 [ # # ]: 0 : assert_se(fd < 0);
373 [ # # ]: 0 : assert_se(errno == EAFNOSUPPORT);
374 : : #endif
375 : :
376 : 0 : fd = socket(AF_NETLINK, SOCK_DGRAM, 0);
377 [ # # ]: 0 : assert_se(fd >= 0);
378 : 0 : safe_close(fd);
379 : :
380 : 0 : set_clear(s);
381 : :
382 [ # # ]: 0 : assert_se(set_put(s, INT_TO_PTR(AF_INET)) >= 0);
383 : :
384 [ # # ]: 0 : assert_se(seccomp_restrict_address_families(s, true) >= 0);
385 : :
386 : 0 : fd = socket(AF_INET, SOCK_DGRAM, 0);
387 [ # # ]: 0 : assert_se(fd >= 0);
388 : 0 : safe_close(fd);
389 : :
390 : 0 : fd = socket(AF_UNIX, SOCK_DGRAM, 0);
391 : : #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
392 : : assert_se(fd >= 0);
393 : : safe_close(fd);
394 : : #else
395 [ # # ]: 0 : assert_se(fd < 0);
396 [ # # ]: 0 : assert_se(errno == EAFNOSUPPORT);
397 : : #endif
398 : :
399 : 0 : fd = socket(AF_NETLINK, SOCK_DGRAM, 0);
400 : : #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
401 : : assert_se(fd >= 0);
402 : : safe_close(fd);
403 : : #else
404 [ # # ]: 0 : assert_se(fd < 0);
405 [ # # ]: 0 : assert_se(errno == EAFNOSUPPORT);
406 : : #endif
407 : :
408 : 0 : _exit(EXIT_SUCCESS);
409 : : }
410 : :
411 [ # # ]: 0 : assert_se(wait_for_terminate_and_check("socketseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
412 : : }
413 : :
414 : 4 : static void test_restrict_realtime(void) {
415 : : pid_t pid;
416 : :
417 [ + - ]: 4 : log_info("/* %s */", __func__);
418 : :
419 [ - + ]: 4 : if (!is_seccomp_available()) {
420 [ # # ]: 0 : log_notice("Seccomp not available, skipping %s", __func__);
421 : 0 : return;
422 : : }
423 [ + - ]: 4 : if (geteuid() != 0) {
424 [ + - ]: 4 : log_notice("Not root, skipping %s", __func__);
425 : 4 : return;
426 : : }
427 : :
428 : : /* in containers RT privs are likely missing anyway */
429 [ # # ]: 0 : if (detect_container() > 0) {
430 [ # # ]: 0 : log_notice("Testing in container, skipping %s", __func__);
431 : 0 : return;
432 : : }
433 : :
434 : 0 : pid = fork();
435 [ # # ]: 0 : assert_se(pid >= 0);
436 : :
437 [ # # ]: 0 : if (pid == 0) {
438 [ # # ]: 0 : assert_se(sched_setscheduler(0, SCHED_FIFO, &(struct sched_param) { .sched_priority = 1 }) >= 0);
439 [ # # ]: 0 : assert_se(sched_setscheduler(0, SCHED_RR, &(struct sched_param) { .sched_priority = 1 }) >= 0);
440 [ # # ]: 0 : assert_se(sched_setscheduler(0, SCHED_IDLE, &(struct sched_param) { .sched_priority = 0 }) >= 0);
441 [ # # ]: 0 : assert_se(sched_setscheduler(0, SCHED_BATCH, &(struct sched_param) { .sched_priority = 0 }) >= 0);
442 [ # # ]: 0 : assert_se(sched_setscheduler(0, SCHED_OTHER, &(struct sched_param) {}) >= 0);
443 : :
444 [ # # ]: 0 : assert_se(seccomp_restrict_realtime() >= 0);
445 : :
446 [ # # ]: 0 : assert_se(sched_setscheduler(0, SCHED_IDLE, &(struct sched_param) { .sched_priority = 0 }) >= 0);
447 [ # # ]: 0 : assert_se(sched_setscheduler(0, SCHED_BATCH, &(struct sched_param) { .sched_priority = 0 }) >= 0);
448 [ # # ]: 0 : assert_se(sched_setscheduler(0, SCHED_OTHER, &(struct sched_param) {}) >= 0);
449 : :
450 [ # # ]: 0 : assert_se(sched_setscheduler(0, SCHED_FIFO, &(struct sched_param) { .sched_priority = 1 }) < 0);
451 [ # # ]: 0 : assert_se(errno == EPERM);
452 [ # # ]: 0 : assert_se(sched_setscheduler(0, SCHED_RR, &(struct sched_param) { .sched_priority = 1 }) < 0);
453 [ # # ]: 0 : assert_se(errno == EPERM);
454 : :
455 : 0 : _exit(EXIT_SUCCESS);
456 : : }
457 : :
458 [ # # ]: 0 : assert_se(wait_for_terminate_and_check("realtimeseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
459 : : }
460 : :
461 : 4 : static void test_memory_deny_write_execute_mmap(void) {
462 : : pid_t pid;
463 : :
464 [ + - ]: 4 : log_info("/* %s */", __func__);
465 : :
466 [ - + ]: 4 : if (!is_seccomp_available()) {
467 [ # # ]: 0 : log_notice("Seccomp not available, skipping %s", __func__);
468 : 0 : return;
469 : : }
470 [ + - ]: 4 : if (geteuid() != 0) {
471 [ + - ]: 4 : log_notice("Not root, skipping %s", __func__);
472 : 4 : return;
473 : : }
474 : :
475 : 0 : pid = fork();
476 [ # # ]: 0 : assert_se(pid >= 0);
477 : :
478 [ # # ]: 0 : if (pid == 0) {
479 : : void *p;
480 : :
481 : 0 : p = mmap(NULL, page_size(), PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1,0);
482 [ # # ]: 0 : assert_se(p != MAP_FAILED);
483 [ # # ]: 0 : assert_se(munmap(p, page_size()) >= 0);
484 : :
485 : 0 : p = mmap(NULL, page_size(), PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1,0);
486 [ # # ]: 0 : assert_se(p != MAP_FAILED);
487 [ # # ]: 0 : assert_se(munmap(p, page_size()) >= 0);
488 : :
489 [ # # ]: 0 : assert_se(seccomp_memory_deny_write_execute() >= 0);
490 : :
491 : 0 : p = mmap(NULL, page_size(), PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1,0);
492 : : #if defined(__x86_64__) || defined(__i386__) || defined(__powerpc64__) || defined(__arm__) || defined(__aarch64__)
493 [ # # ]: 0 : assert_se(p == MAP_FAILED);
494 [ # # ]: 0 : assert_se(errno == EPERM);
495 : : #else /* unknown architectures */
496 : : assert_se(p != MAP_FAILED);
497 : : assert_se(munmap(p, page_size()) >= 0);
498 : : #endif
499 : :
500 : 0 : p = mmap(NULL, page_size(), PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1,0);
501 [ # # ]: 0 : assert_se(p != MAP_FAILED);
502 [ # # ]: 0 : assert_se(munmap(p, page_size()) >= 0);
503 : :
504 : 0 : _exit(EXIT_SUCCESS);
505 : : }
506 : :
507 [ # # ]: 0 : assert_se(wait_for_terminate_and_check("memoryseccomp-mmap", pid, WAIT_LOG) == EXIT_SUCCESS);
508 : : }
509 : :
510 : 4 : static void test_memory_deny_write_execute_shmat(void) {
511 : : int shmid;
512 : : pid_t pid;
513 : : uint32_t arch;
514 : :
515 [ + - ]: 4 : log_info("/* %s */", __func__);
516 : :
517 [ + + ]: 16 : SECCOMP_FOREACH_LOCAL_ARCH(arch) {
518 [ + - ]: 12 : log_debug("arch %s: SCMP_SYS(mmap) = %d", seccomp_arch_to_string(arch), SCMP_SYS(mmap));
519 [ + - ]: 12 : log_debug("arch %s: SCMP_SYS(mmap2) = %d", seccomp_arch_to_string(arch), SCMP_SYS(mmap2));
520 [ + - ]: 12 : log_debug("arch %s: SCMP_SYS(shmget) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmget));
521 [ + - ]: 12 : log_debug("arch %s: SCMP_SYS(shmat) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmat));
522 [ + - ]: 12 : log_debug("arch %s: SCMP_SYS(shmdt) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmdt));
523 : : }
524 : :
525 [ - + ]: 4 : if (!is_seccomp_available()) {
526 [ # # ]: 0 : log_notice("Seccomp not available, skipping %s", __func__);
527 : 0 : return;
528 : : }
529 [ + - ]: 4 : if (geteuid() != 0) {
530 [ + - ]: 4 : log_notice("Not root, skipping %s", __func__);
531 : 4 : return;
532 : : }
533 : :
534 : 0 : shmid = shmget(IPC_PRIVATE, page_size(), 0);
535 [ # # ]: 0 : assert_se(shmid >= 0);
536 : :
537 : 0 : pid = fork();
538 [ # # ]: 0 : assert_se(pid >= 0);
539 : :
540 [ # # ]: 0 : if (pid == 0) {
541 : : void *p;
542 : :
543 : 0 : p = shmat(shmid, NULL, 0);
544 [ # # ]: 0 : assert_se(p != MAP_FAILED);
545 [ # # ]: 0 : assert_se(shmdt(p) == 0);
546 : :
547 : 0 : p = shmat(shmid, NULL, SHM_EXEC);
548 [ # # ]: 0 : assert_se(p != MAP_FAILED);
549 [ # # ]: 0 : assert_se(shmdt(p) == 0);
550 : :
551 [ # # ]: 0 : assert_se(seccomp_memory_deny_write_execute() >= 0);
552 : :
553 : 0 : p = shmat(shmid, NULL, SHM_EXEC);
554 [ # # # # ]: 0 : log_debug_errno(p == MAP_FAILED ? errno : 0, "shmat(SHM_EXEC): %m");
555 : : #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
556 [ # # ]: 0 : assert_se(p == MAP_FAILED);
557 [ # # ]: 0 : assert_se(errno == EPERM);
558 : : #endif
559 : : /* Depending on kernel, libseccomp, and glibc versions, other architectures
560 : : * might fail or not. Let's not assert success. */
561 [ # # ]: 0 : if (p != MAP_FAILED)
562 [ # # ]: 0 : assert_se(shmdt(p) == 0);
563 : :
564 : 0 : p = shmat(shmid, NULL, 0);
565 [ # # # # ]: 0 : log_debug_errno(p == MAP_FAILED ? errno : 0, "shmat(0): %m");
566 [ # # ]: 0 : assert_se(p != MAP_FAILED);
567 [ # # ]: 0 : assert_se(shmdt(p) == 0);
568 : :
569 : 0 : _exit(EXIT_SUCCESS);
570 : : }
571 : :
572 [ # # ]: 0 : assert_se(wait_for_terminate_and_check("memoryseccomp-shmat", pid, WAIT_LOG) == EXIT_SUCCESS);
573 : : }
574 : :
575 : 4 : static void test_restrict_archs(void) {
576 : : pid_t pid;
577 : :
578 [ + - ]: 4 : log_info("/* %s */", __func__);
579 : :
580 [ - + ]: 4 : if (!is_seccomp_available()) {
581 [ # # ]: 0 : log_notice("Seccomp not available, skipping %s", __func__);
582 : 0 : return;
583 : : }
584 [ + - ]: 4 : if (geteuid() != 0) {
585 [ + - ]: 4 : log_notice("Not root, skipping %s", __func__);
586 : 4 : return;
587 : : }
588 : :
589 : 0 : pid = fork();
590 [ # # ]: 0 : assert_se(pid >= 0);
591 : :
592 [ # # ]: 0 : if (pid == 0) {
593 : 0 : _cleanup_set_free_ Set *s = NULL;
594 : :
595 [ # # ]: 0 : assert_se(access("/", F_OK) >= 0);
596 : :
597 [ # # ]: 0 : assert_se(s = set_new(NULL));
598 : :
599 : : #ifdef __x86_64__
600 [ # # ]: 0 : assert_se(set_put(s, UINT32_TO_PTR(SCMP_ARCH_X86+1)) >= 0);
601 : : #endif
602 [ # # ]: 0 : assert_se(seccomp_restrict_archs(s) >= 0);
603 : :
604 [ # # ]: 0 : assert_se(access("/", F_OK) >= 0);
605 [ # # ]: 0 : assert_se(seccomp_restrict_archs(NULL) >= 0);
606 : :
607 [ # # ]: 0 : assert_se(access("/", F_OK) >= 0);
608 : :
609 : 0 : _exit(EXIT_SUCCESS);
610 : : }
611 : :
612 [ # # ]: 0 : assert_se(wait_for_terminate_and_check("archseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
613 : : }
614 : :
615 : 4 : static void test_load_syscall_filter_set_raw(void) {
616 : : pid_t pid;
617 : :
618 [ + - ]: 4 : log_info("/* %s */", __func__);
619 : :
620 [ - + ]: 4 : if (!is_seccomp_available()) {
621 [ # # ]: 0 : log_notice("Seccomp not available, skipping %s", __func__);
622 : 0 : return;
623 : : }
624 [ + - ]: 4 : if (geteuid() != 0) {
625 [ + - ]: 4 : log_notice("Not root, skipping %s", __func__);
626 : 4 : return;
627 : : }
628 : :
629 : 0 : pid = fork();
630 [ # # ]: 0 : assert_se(pid >= 0);
631 : :
632 [ # # ]: 0 : if (pid == 0) {
633 : 0 : _cleanup_hashmap_free_ Hashmap *s = NULL;
634 : :
635 [ # # ]: 0 : assert_se(access("/", F_OK) >= 0);
636 [ # # ]: 0 : assert_se(poll(NULL, 0, 0) == 0);
637 : :
638 [ # # ]: 0 : assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, scmp_act_kill_process(), true) >= 0);
639 [ # # ]: 0 : assert_se(access("/", F_OK) >= 0);
640 [ # # ]: 0 : assert_se(poll(NULL, 0, 0) == 0);
641 : :
642 [ # # ]: 0 : assert_se(s = hashmap_new(NULL));
643 : : #if SCMP_SYS(access) >= 0
644 [ # # ]: 0 : assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_access + 1), INT_TO_PTR(-1)) >= 0);
645 : : #else
646 : : assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(-1)) >= 0);
647 : : #endif
648 : :
649 [ # # ]: 0 : assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN), true) >= 0);
650 : :
651 [ # # ]: 0 : assert_se(access("/", F_OK) < 0);
652 [ # # ]: 0 : assert_se(errno == EUCLEAN);
653 : :
654 [ # # ]: 0 : assert_se(poll(NULL, 0, 0) == 0);
655 : :
656 : 0 : s = hashmap_free(s);
657 : :
658 [ # # ]: 0 : assert_se(s = hashmap_new(NULL));
659 : : #if SCMP_SYS(access) >= 0
660 [ # # ]: 0 : assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_access + 1), INT_TO_PTR(EILSEQ)) >= 0);
661 : : #else
662 : : assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(EILSEQ)) >= 0);
663 : : #endif
664 : :
665 [ # # ]: 0 : assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN), true) >= 0);
666 : :
667 [ # # ]: 0 : assert_se(access("/", F_OK) < 0);
668 [ # # ]: 0 : assert_se(errno == EILSEQ);
669 : :
670 [ # # ]: 0 : assert_se(poll(NULL, 0, 0) == 0);
671 : :
672 : 0 : s = hashmap_free(s);
673 : :
674 [ # # ]: 0 : assert_se(s = hashmap_new(NULL));
675 : : #if SCMP_SYS(poll) >= 0
676 [ # # ]: 0 : assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_poll + 1), INT_TO_PTR(-1)) >= 0);
677 : : #else
678 : : assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(-1)) >= 0);
679 : : #endif
680 : :
681 [ # # ]: 0 : assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH), true) >= 0);
682 : :
683 [ # # ]: 0 : assert_se(access("/", F_OK) < 0);
684 [ # # ]: 0 : assert_se(errno == EILSEQ);
685 : :
686 [ # # ]: 0 : assert_se(poll(NULL, 0, 0) < 0);
687 [ # # ]: 0 : assert_se(errno == EUNATCH);
688 : :
689 : 0 : s = hashmap_free(s);
690 : :
691 [ # # ]: 0 : assert_se(s = hashmap_new(NULL));
692 : : #if SCMP_SYS(poll) >= 0
693 [ # # ]: 0 : assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_poll + 1), INT_TO_PTR(EILSEQ)) >= 0);
694 : : #else
695 : : assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(EILSEQ)) >= 0);
696 : : #endif
697 : :
698 [ # # ]: 0 : assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH), true) >= 0);
699 : :
700 [ # # ]: 0 : assert_se(access("/", F_OK) < 0);
701 [ # # ]: 0 : assert_se(errno == EILSEQ);
702 : :
703 [ # # ]: 0 : assert_se(poll(NULL, 0, 0) < 0);
704 [ # # ]: 0 : assert_se(errno == EILSEQ);
705 : :
706 : 0 : _exit(EXIT_SUCCESS);
707 : : }
708 : :
709 [ # # ]: 0 : assert_se(wait_for_terminate_and_check("syscallrawseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
710 : : }
711 : :
712 : 4 : static void test_lock_personality(void) {
713 : : unsigned long current;
714 : : pid_t pid;
715 : :
716 [ + - ]: 4 : log_info("/* %s */", __func__);
717 : :
718 [ - + ]: 4 : if (!is_seccomp_available()) {
719 [ # # ]: 0 : log_notice("Seccomp not available, skipping %s", __func__);
720 : 4 : return;
721 : : }
722 [ + - ]: 4 : if (geteuid() != 0) {
723 [ + - ]: 4 : log_notice("Not root, skipping %s", __func__);
724 : 4 : return;
725 : : }
726 : :
727 [ # # ]: 0 : assert_se(opinionated_personality(¤t) >= 0);
728 : :
729 [ # # ]: 0 : log_info("current personality=%lu", current);
730 : :
731 : 0 : pid = fork();
732 [ # # ]: 0 : assert_se(pid >= 0);
733 : :
734 [ # # ]: 0 : if (pid == 0) {
735 [ # # ]: 0 : assert_se(seccomp_lock_personality(current) >= 0);
736 : :
737 [ # # ]: 0 : assert_se((unsigned long) safe_personality(current) == current);
738 : :
739 : : /* Note, we also test that safe_personality() works correctly, by checkig whether errno is properly
740 : : * set, in addition to the return value */
741 : 0 : errno = 0;
742 [ # # ]: 0 : assert_se(safe_personality(PER_LINUX | ADDR_NO_RANDOMIZE) == -EPERM);
743 [ # # ]: 0 : assert_se(errno == EPERM);
744 : :
745 [ # # ]: 0 : assert_se(safe_personality(PER_LINUX | MMAP_PAGE_ZERO) == -EPERM);
746 [ # # ]: 0 : assert_se(safe_personality(PER_LINUX | ADDR_COMPAT_LAYOUT) == -EPERM);
747 [ # # ]: 0 : assert_se(safe_personality(PER_LINUX | READ_IMPLIES_EXEC) == -EPERM);
748 [ # # ]: 0 : assert_se(safe_personality(PER_LINUX_32BIT) == -EPERM);
749 [ # # ]: 0 : assert_se(safe_personality(PER_SVR4) == -EPERM);
750 [ # # ]: 0 : assert_se(safe_personality(PER_BSD) == -EPERM);
751 [ # # # # ]: 0 : assert_se(safe_personality(current == PER_LINUX ? PER_LINUX32 : PER_LINUX) == -EPERM);
752 [ # # ]: 0 : assert_se(safe_personality(PER_LINUX32_3GB) == -EPERM);
753 [ # # ]: 0 : assert_se(safe_personality(PER_UW7) == -EPERM);
754 [ # # ]: 0 : assert_se(safe_personality(0x42) == -EPERM);
755 : :
756 [ # # ]: 0 : assert_se(safe_personality(PERSONALITY_INVALID) == -EPERM); /* maybe remove this later */
757 : :
758 [ # # ]: 0 : assert_se((unsigned long) personality(current) == current);
759 : 0 : _exit(EXIT_SUCCESS);
760 : : }
761 : :
762 [ # # ]: 0 : assert_se(wait_for_terminate_and_check("lockpersonalityseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
763 : : }
764 : :
765 : 0 : static int real_open(const char *path, int flags, mode_t mode) {
766 : : /* glibc internally calls openat() when open() is requested. Let's hence define our own wrapper for
767 : : * testing purposes that calls the real syscall, on architectures where SYS_open is defined. On
768 : : * other architectures, let's just fall back to the glibc call. */
769 : :
770 : : #ifdef SYS_open
771 : 0 : return (int) syscall(SYS_open, path, flags, mode);
772 : : #else
773 : : return open(path, flags, mode);
774 : : #endif
775 : : }
776 : :
777 : 4 : static void test_restrict_suid_sgid(void) {
778 : : pid_t pid;
779 : :
780 [ + - ]: 4 : log_info("/* %s */", __func__);
781 : :
782 [ - + ]: 4 : if (!is_seccomp_available()) {
783 [ # # ]: 0 : log_notice("Seccomp not available, skipping %s", __func__);
784 : 0 : return;
785 : : }
786 [ + - ]: 4 : if (geteuid() != 0) {
787 [ + - ]: 4 : log_notice("Not root, skipping %s", __func__);
788 : 4 : return;
789 : : }
790 : :
791 : 0 : pid = fork();
792 [ # # ]: 0 : assert_se(pid >= 0);
793 : :
794 [ # # ]: 0 : if (pid == 0) {
795 : 0 : char path[] = "/tmp/suidsgidXXXXXX", dir[] = "/tmp/suidsgiddirXXXXXX";
796 : 0 : int fd = -1, k = -1;
797 : : const char *z;
798 : :
799 : 0 : fd = mkostemp_safe(path);
800 [ # # ]: 0 : assert_se(fd >= 0);
801 : :
802 [ # # ]: 0 : assert_se(mkdtemp(dir));
803 [ # # # # : 0 : z = strjoina(dir, "/test");
# # # # #
# # # ]
804 : :
805 [ # # ]: 0 : assert_se(chmod(path, 0755 | S_ISUID) >= 0);
806 [ # # ]: 0 : assert_se(chmod(path, 0755 | S_ISGID) >= 0);
807 [ # # ]: 0 : assert_se(chmod(path, 0755 | S_ISGID | S_ISUID) >= 0);
808 [ # # ]: 0 : assert_se(chmod(path, 0755) >= 0);
809 : :
810 [ # # ]: 0 : assert_se(fchmod(fd, 0755 | S_ISUID) >= 0);
811 [ # # ]: 0 : assert_se(fchmod(fd, 0755 | S_ISGID) >= 0);
812 [ # # ]: 0 : assert_se(fchmod(fd, 0755 | S_ISGID | S_ISUID) >= 0);
813 [ # # ]: 0 : assert_se(fchmod(fd, 0755) >= 0);
814 : :
815 [ # # ]: 0 : assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISUID, 0) >= 0);
816 [ # # ]: 0 : assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID, 0) >= 0);
817 [ # # ]: 0 : assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) >= 0);
818 [ # # ]: 0 : assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0);
819 : :
820 : 0 : k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID);
821 : 0 : k = safe_close(k);
822 [ # # ]: 0 : assert_se(unlink(z) >= 0);
823 : :
824 : 0 : k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID);
825 : 0 : k = safe_close(k);
826 [ # # ]: 0 : assert_se(unlink(z) >= 0);
827 : :
828 : 0 : k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID);
829 : 0 : k = safe_close(k);
830 [ # # ]: 0 : assert_se(unlink(z) >= 0);
831 : :
832 : 0 : k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
833 : 0 : k = safe_close(k);
834 [ # # ]: 0 : assert_se(unlink(z) >= 0);
835 : :
836 : 0 : k = creat(z, 0644 | S_ISUID);
837 : 0 : k = safe_close(k);
838 [ # # ]: 0 : assert_se(unlink(z) >= 0);
839 : :
840 : 0 : k = creat(z, 0644 | S_ISGID);
841 : 0 : k = safe_close(k);
842 [ # # ]: 0 : assert_se(unlink(z) >= 0);
843 : :
844 : 0 : k = creat(z, 0644 | S_ISUID | S_ISGID);
845 : 0 : k = safe_close(k);
846 [ # # ]: 0 : assert_se(unlink(z) >= 0);
847 : :
848 : 0 : k = creat(z, 0644);
849 : 0 : k = safe_close(k);
850 [ # # ]: 0 : assert_se(unlink(z) >= 0);
851 : :
852 : 0 : k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID);
853 : 0 : k = safe_close(k);
854 [ # # ]: 0 : assert_se(unlink(z) >= 0);
855 : :
856 : 0 : k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID);
857 : 0 : k = safe_close(k);
858 [ # # ]: 0 : assert_se(unlink(z) >= 0);
859 : :
860 : 0 : k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID);
861 : 0 : k = safe_close(k);
862 [ # # ]: 0 : assert_se(unlink(z) >= 0);
863 : :
864 : 0 : k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
865 : 0 : k = safe_close(k);
866 [ # # ]: 0 : assert_se(unlink(z) >= 0);
867 : :
868 [ # # ]: 0 : assert_se(mkdir(z, 0755 | S_ISUID) >= 0);
869 [ # # ]: 0 : assert_se(rmdir(z) >= 0);
870 [ # # ]: 0 : assert_se(mkdir(z, 0755 | S_ISGID) >= 0);
871 [ # # ]: 0 : assert_se(rmdir(z) >= 0);
872 [ # # ]: 0 : assert_se(mkdir(z, 0755 | S_ISUID | S_ISGID) >= 0);
873 [ # # ]: 0 : assert_se(rmdir(z) >= 0);
874 [ # # ]: 0 : assert_se(mkdir(z, 0755) >= 0);
875 [ # # ]: 0 : assert_se(rmdir(z) >= 0);
876 : :
877 [ # # ]: 0 : assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID) >= 0);
878 [ # # ]: 0 : assert_se(rmdir(z) >= 0);
879 [ # # ]: 0 : assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISGID) >= 0);
880 [ # # ]: 0 : assert_se(rmdir(z) >= 0);
881 [ # # ]: 0 : assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID | S_ISGID) >= 0);
882 [ # # ]: 0 : assert_se(rmdir(z) >= 0);
883 [ # # ]: 0 : assert_se(mkdirat(AT_FDCWD, z, 0755) >= 0);
884 [ # # ]: 0 : assert_se(rmdir(z) >= 0);
885 : :
886 [ # # ]: 0 : assert_se(mknod(z, S_IFREG | 0755 | S_ISUID, 0) >= 0);
887 [ # # ]: 0 : assert_se(unlink(z) >= 0);
888 [ # # ]: 0 : assert_se(mknod(z, S_IFREG | 0755 | S_ISGID, 0) >= 0);
889 [ # # ]: 0 : assert_se(unlink(z) >= 0);
890 [ # # ]: 0 : assert_se(mknod(z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) >= 0);
891 [ # # ]: 0 : assert_se(unlink(z) >= 0);
892 [ # # ]: 0 : assert_se(mknod(z, S_IFREG | 0755, 0) >= 0);
893 [ # # ]: 0 : assert_se(unlink(z) >= 0);
894 : :
895 [ # # ]: 0 : assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID, 0) >= 0);
896 [ # # ]: 0 : assert_se(unlink(z) >= 0);
897 [ # # ]: 0 : assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISGID, 0) >= 0);
898 [ # # ]: 0 : assert_se(unlink(z) >= 0);
899 [ # # ]: 0 : assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) >= 0);
900 [ # # ]: 0 : assert_se(unlink(z) >= 0);
901 [ # # ]: 0 : assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755, 0) >= 0);
902 [ # # ]: 0 : assert_se(unlink(z) >= 0);
903 : :
904 [ # # ]: 0 : assert_se(seccomp_restrict_suid_sgid() >= 0);
905 : :
906 [ # # # # ]: 0 : assert_se(chmod(path, 0775 | S_ISUID) < 0 && errno == EPERM);
907 [ # # # # ]: 0 : assert_se(chmod(path, 0775 | S_ISGID) < 0 && errno == EPERM);
908 [ # # # # ]: 0 : assert_se(chmod(path, 0775 | S_ISGID | S_ISUID) < 0 && errno == EPERM);
909 [ # # ]: 0 : assert_se(chmod(path, 0775) >= 0);
910 : :
911 [ # # # # ]: 0 : assert_se(fchmod(fd, 0775 | S_ISUID) < 0 && errno == EPERM);
912 [ # # # # ]: 0 : assert_se(fchmod(fd, 0775 | S_ISGID) < 0 && errno == EPERM);
913 [ # # # # ]: 0 : assert_se(fchmod(fd, 0775 | S_ISGID | S_ISUID) < 0 && errno == EPERM);
914 [ # # ]: 0 : assert_se(fchmod(fd, 0775) >= 0);
915 : :
916 [ # # # # ]: 0 : assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISUID, 0) < 0 && errno == EPERM);
917 [ # # # # ]: 0 : assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID, 0) < 0 && errno == EPERM);
918 [ # # # # ]: 0 : assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) < 0 && errno == EPERM);
919 [ # # ]: 0 : assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0);
920 : :
921 [ # # # # ]: 0 : assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM);
922 [ # # # # ]: 0 : assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM);
923 [ # # # # ]: 0 : assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
924 : 0 : k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
925 : 0 : k = safe_close(k);
926 [ # # ]: 0 : assert_se(unlink(z) >= 0);
927 : :
928 [ # # # # ]: 0 : assert_se(creat(z, 0644 | S_ISUID) < 0 && errno == EPERM);
929 [ # # # # ]: 0 : assert_se(creat(z, 0644 | S_ISGID) < 0 && errno == EPERM);
930 [ # # # # ]: 0 : assert_se(creat(z, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
931 : 0 : k = creat(z, 0644);
932 : 0 : k = safe_close(k);
933 [ # # ]: 0 : assert_se(unlink(z) >= 0);
934 : :
935 [ # # # # ]: 0 : assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM);
936 [ # # # # ]: 0 : assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM);
937 [ # # # # ]: 0 : assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
938 : 0 : k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
939 : 0 : k = safe_close(k);
940 [ # # ]: 0 : assert_se(unlink(z) >= 0);
941 : :
942 [ # # # # ]: 0 : assert_se(mkdir(z, 0755 | S_ISUID) < 0 && errno == EPERM);
943 [ # # # # ]: 0 : assert_se(mkdir(z, 0755 | S_ISGID) < 0 && errno == EPERM);
944 [ # # # # ]: 0 : assert_se(mkdir(z, 0755 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
945 [ # # ]: 0 : assert_se(mkdir(z, 0755) >= 0);
946 [ # # ]: 0 : assert_se(rmdir(z) >= 0);
947 : :
948 [ # # # # ]: 0 : assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID) < 0 && errno == EPERM);
949 [ # # # # ]: 0 : assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISGID) < 0 && errno == EPERM);
950 [ # # # # ]: 0 : assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
951 [ # # ]: 0 : assert_se(mkdirat(AT_FDCWD, z, 0755) >= 0);
952 [ # # ]: 0 : assert_se(rmdir(z) >= 0);
953 : :
954 [ # # # # ]: 0 : assert_se(mknod(z, S_IFREG | 0755 | S_ISUID, 0) < 0 && errno == EPERM);
955 [ # # # # ]: 0 : assert_se(mknod(z, S_IFREG | 0755 | S_ISGID, 0) < 0 && errno == EPERM);
956 [ # # # # ]: 0 : assert_se(mknod(z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) < 0 && errno == EPERM);
957 [ # # ]: 0 : assert_se(mknod(z, S_IFREG | 0755, 0) >= 0);
958 [ # # ]: 0 : assert_se(unlink(z) >= 0);
959 : :
960 [ # # # # ]: 0 : assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID, 0) < 0 && errno == EPERM);
961 [ # # # # ]: 0 : assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISGID, 0) < 0 && errno == EPERM);
962 [ # # # # ]: 0 : assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) < 0 && errno == EPERM);
963 [ # # ]: 0 : assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755, 0) >= 0);
964 [ # # ]: 0 : assert_se(unlink(z) >= 0);
965 : :
966 [ # # ]: 0 : assert_se(unlink(path) >= 0);
967 [ # # ]: 0 : assert_se(rm_rf(dir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
968 : :
969 : 0 : _exit(EXIT_SUCCESS);
970 : : }
971 : :
972 [ # # ]: 0 : assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
973 : : }
974 : :
975 : 4 : int main(int argc, char *argv[]) {
976 : 4 : test_setup_logging(LOG_DEBUG);
977 : :
978 : 4 : test_seccomp_arch_to_string();
979 : 4 : test_architecture_table();
980 : 4 : test_syscall_filter_set_find();
981 : 4 : test_filter_sets();
982 : 4 : test_filter_sets_ordered();
983 : 4 : test_restrict_namespace();
984 : 4 : test_protect_sysctl();
985 : 4 : test_restrict_address_families();
986 : 4 : test_restrict_realtime();
987 : 4 : test_memory_deny_write_execute_mmap();
988 : 4 : test_memory_deny_write_execute_shmat();
989 : 4 : test_restrict_archs();
990 : 4 : test_load_syscall_filter_set_raw();
991 : 4 : test_lock_personality();
992 : 4 : test_restrict_suid_sgid();
993 : :
994 : 4 : return 0;
995 : : }
|