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