]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-seccomp.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / test / test-seccomp.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
f6281133
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2016 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
d7e454ba 21#include <poll.h>
469830d1 22#include <sched.h>
f6281133
LP
23#include <stdlib.h>
24#include <sys/eventfd.h>
469830d1 25#include <sys/mman.h>
78e864e5 26#include <sys/personality.h>
2a65bd94
ZJS
27#include <sys/shm.h>
28#include <sys/types.h>
29#include <unistd.h>
f6281133 30
add00535 31#include "alloc-util.h"
f6281133
LP
32#include "fd-util.h"
33#include "macro.h"
add00535
LP
34#include "missing.h"
35#include "nsflags.h"
f6281133 36#include "process-util.h"
add00535 37#include "raw-clone.h"
f6281133 38#include "seccomp-util.h"
469830d1 39#include "set.h"
aa34055f
ZJS
40#include "string-util.h"
41#include "util.h"
469830d1 42#include "virt.h"
f6281133 43
da1921a5
ZJS
44#if SCMP_SYS(socket) < 0 || defined(__i386__) || defined(__s390x__) || defined(__s390__)
45/* On these archs, socket() is implemented via the socketcall() syscall multiplexer,
46 * and we can't restrict it hence via seccomp. */
47# define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 1
48#else
49# define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 0
50#endif
51
f6281133
LP
52static void test_seccomp_arch_to_string(void) {
53 uint32_t a, b;
54 const char *name;
55
56 a = seccomp_arch_native();
57 assert_se(a > 0);
58 name = seccomp_arch_to_string(a);
59 assert_se(name);
60 assert_se(seccomp_arch_from_string(name, &b) >= 0);
61 assert_se(a == b);
62}
63
aa34055f
ZJS
64static void test_architecture_table(void) {
65 const char *n, *n2;
66
67 NULSTR_FOREACH(n,
68 "native\0"
69 "x86\0"
70 "x86-64\0"
71 "x32\0"
72 "arm\0"
73 "arm64\0"
74 "mips\0"
75 "mips64\0"
76 "mips64-n32\0"
77 "mips-le\0"
78 "mips64-le\0"
79 "mips64-le-n32\0"
80 "ppc\0"
81 "ppc64\0"
82 "ppc64-le\0"
83 "s390\0"
84 "s390x\0") {
85 uint32_t c;
86
87 assert_se(seccomp_arch_from_string(n, &c) >= 0);
88 n2 = seccomp_arch_to_string(c);
89 log_info("seccomp-arch: %s → 0x%"PRIx32" → %s", n, c, n2);
90 assert_se(streq_ptr(n, n2));
91 }
92}
93
f6281133
LP
94static void test_syscall_filter_set_find(void) {
95 assert_se(!syscall_filter_set_find(NULL));
96 assert_se(!syscall_filter_set_find(""));
97 assert_se(!syscall_filter_set_find("quux"));
98 assert_se(!syscall_filter_set_find("@quux"));
99
100 assert_se(syscall_filter_set_find("@clock") == syscall_filter_sets + SYSCALL_FILTER_SET_CLOCK);
101 assert_se(syscall_filter_set_find("@default") == syscall_filter_sets + SYSCALL_FILTER_SET_DEFAULT);
102 assert_se(syscall_filter_set_find("@raw-io") == syscall_filter_sets + SYSCALL_FILTER_SET_RAW_IO);
103}
104
105static void test_filter_sets(void) {
106 unsigned i;
107 int r;
108
109 if (!is_seccomp_available())
110 return;
f6281133
LP
111 if (geteuid() != 0)
112 return;
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 (i == SYSCALL_FILTER_SET_DEFAULT) /* if we look at the default set, whitelist instead of blacklist */
469830d1 126 r = seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN), syscall_filter_sets + i, SCMP_ACT_ALLOW);
f6281133 127 else
469830d1 128 r = seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + i, SCMP_ACT_ERRNO(EUCLEAN));
f6281133
LP
129 if (r < 0)
130 _exit(EXIT_FAILURE);
131
132 /* Test the sycall filter with one random system call */
133 fd = eventfd(0, EFD_NONBLOCK|EFD_CLOEXEC);
134 if (IN_SET(i, SYSCALL_FILTER_SET_IO_EVENT, SYSCALL_FILTER_SET_DEFAULT))
469830d1 135 assert_se(fd < 0 && errno == EUCLEAN);
f6281133
LP
136 else {
137 assert_se(fd >= 0);
138 safe_close(fd);
139 }
140
141 _exit(EXIT_SUCCESS);
142 }
143
144 assert_se(wait_for_terminate_and_warn(syscall_filter_sets[i].name, pid, true) == EXIT_SUCCESS);
145 }
146}
147
add00535
LP
148static void test_restrict_namespace(void) {
149 _cleanup_free_ char *s = NULL;
add00535 150 unsigned long ul;
469830d1 151 pid_t pid;
add00535
LP
152
153 assert_se(namespace_flag_to_string(0) == NULL);
154 assert_se(streq(namespace_flag_to_string(CLONE_NEWNS), "mnt"));
155 assert_se(namespace_flag_to_string(CLONE_NEWNS|CLONE_NEWIPC) == NULL);
156 assert_se(streq(namespace_flag_to_string(CLONE_NEWCGROUP), "cgroup"));
157
158 assert_se(namespace_flag_from_string("mnt") == CLONE_NEWNS);
159 assert_se(namespace_flag_from_string(NULL) == 0);
160 assert_se(namespace_flag_from_string("") == 0);
161 assert_se(namespace_flag_from_string("uts") == CLONE_NEWUTS);
162 assert_se(namespace_flag_from_string(namespace_flag_to_string(CLONE_NEWUTS)) == CLONE_NEWUTS);
163 assert_se(streq(namespace_flag_to_string(namespace_flag_from_string("ipc")), "ipc"));
164
165 assert_se(namespace_flag_from_string_many(NULL, &ul) == 0 && ul == 0);
166 assert_se(namespace_flag_from_string_many("", &ul) == 0 && ul == 0);
167 assert_se(namespace_flag_from_string_many("mnt uts ipc", &ul) == 0 && ul == (CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC));
168
169 assert_se(namespace_flag_to_string_many(NAMESPACE_FLAGS_ALL, &s) == 0);
170 assert_se(streq(s, "cgroup ipc net mnt pid user uts"));
171 assert_se(namespace_flag_from_string_many(s, &ul) == 0 && ul == NAMESPACE_FLAGS_ALL);
172
173 if (!is_seccomp_available())
174 return;
add00535
LP
175 if (geteuid() != 0)
176 return;
177
178 pid = fork();
179 assert_se(pid >= 0);
180
181 if (pid == 0) {
182
183 assert_se(seccomp_restrict_namespaces(CLONE_NEWNS|CLONE_NEWNET) >= 0);
184
185 assert_se(unshare(CLONE_NEWNS) == 0);
186 assert_se(unshare(CLONE_NEWNET) == 0);
187 assert_se(unshare(CLONE_NEWUTS) == -1);
188 assert_se(errno == EPERM);
189 assert_se(unshare(CLONE_NEWIPC) == -1);
190 assert_se(errno == EPERM);
191 assert_se(unshare(CLONE_NEWNET|CLONE_NEWUTS) == -1);
192 assert_se(errno == EPERM);
193
194 /* We use fd 0 (stdin) here, which of course will fail with EINVAL on setns(). Except of course our
195 * seccomp filter worked, and hits first and makes it return EPERM */
196 assert_se(setns(0, CLONE_NEWNS) == -1);
197 assert_se(errno == EINVAL);
198 assert_se(setns(0, CLONE_NEWNET) == -1);
199 assert_se(errno == EINVAL);
200 assert_se(setns(0, CLONE_NEWUTS) == -1);
201 assert_se(errno == EPERM);
202 assert_se(setns(0, CLONE_NEWIPC) == -1);
203 assert_se(errno == EPERM);
204 assert_se(setns(0, CLONE_NEWNET|CLONE_NEWUTS) == -1);
205 assert_se(errno == EPERM);
206 assert_se(setns(0, 0) == -1);
207 assert_se(errno == EPERM);
208
209 pid = raw_clone(CLONE_NEWNS);
210 assert_se(pid >= 0);
211 if (pid == 0)
212 _exit(EXIT_SUCCESS);
213 pid = raw_clone(CLONE_NEWNET);
214 assert_se(pid >= 0);
215 if (pid == 0)
216 _exit(EXIT_SUCCESS);
217 pid = raw_clone(CLONE_NEWUTS);
218 assert_se(pid < 0);
219 assert_se(errno == EPERM);
220 pid = raw_clone(CLONE_NEWIPC);
221 assert_se(pid < 0);
222 assert_se(errno == EPERM);
223 pid = raw_clone(CLONE_NEWNET|CLONE_NEWUTS);
224 assert_se(pid < 0);
225 assert_se(errno == EPERM);
226
227 _exit(EXIT_SUCCESS);
228 }
229
230 assert_se(wait_for_terminate_and_warn("nsseccomp", pid, true) == EXIT_SUCCESS);
231}
232
469830d1
LP
233static void test_protect_sysctl(void) {
234 pid_t pid;
235
236 if (!is_seccomp_available())
237 return;
238 if (geteuid() != 0)
239 return;
240
241 if (detect_container() > 0) /* in containers _sysctl() is likely missing anyway */
242 return;
243
244 pid = fork();
245 assert_se(pid >= 0);
246
247 if (pid == 0) {
2e64e8f4 248#if __NR__sysctl > 0
469830d1
LP
249 assert_se(syscall(__NR__sysctl, NULL) < 0);
250 assert_se(errno == EFAULT);
2e64e8f4 251#endif
469830d1
LP
252
253 assert_se(seccomp_protect_sysctl() >= 0);
254
2e64e8f4 255#if __NR__sysctl > 0
469830d1
LP
256 assert_se(syscall(__NR__sysctl, 0, 0, 0) < 0);
257 assert_se(errno == EPERM);
2e64e8f4 258#endif
469830d1
LP
259
260 _exit(EXIT_SUCCESS);
261 }
262
263 assert_se(wait_for_terminate_and_warn("sysctlseccomp", pid, true) == EXIT_SUCCESS);
264}
265
266static void test_restrict_address_families(void) {
267 pid_t pid;
268
269 if (!is_seccomp_available())
270 return;
271 if (geteuid() != 0)
272 return;
273
274 pid = fork();
275 assert_se(pid >= 0);
276
277 if (pid == 0) {
278 int fd;
279 Set *s;
280
281 fd = socket(AF_INET, SOCK_DGRAM, 0);
282 assert_se(fd >= 0);
283 safe_close(fd);
284
285 fd = socket(AF_UNIX, SOCK_DGRAM, 0);
286 assert_se(fd >= 0);
287 safe_close(fd);
288
289 fd = socket(AF_NETLINK, SOCK_DGRAM, 0);
290 assert_se(fd >= 0);
291 safe_close(fd);
292
293 assert_se(s = set_new(NULL));
294 assert_se(set_put(s, INT_TO_PTR(AF_UNIX)) >= 0);
295
296 assert_se(seccomp_restrict_address_families(s, false) >= 0);
297
298 fd = socket(AF_INET, SOCK_DGRAM, 0);
299 assert_se(fd >= 0);
300 safe_close(fd);
301
ad8f1479 302 fd = socket(AF_UNIX, SOCK_DGRAM, 0);
dce0e620 303#if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
ad8f1479
LP
304 assert_se(fd >= 0);
305 safe_close(fd);
306#else
dce0e620 307 assert_se(fd < 0);
469830d1 308 assert_se(errno == EAFNOSUPPORT);
ad8f1479 309#endif
469830d1
LP
310
311 fd = socket(AF_NETLINK, SOCK_DGRAM, 0);
312 assert_se(fd >= 0);
313 safe_close(fd);
314
315 set_clear(s);
316
317 assert_se(set_put(s, INT_TO_PTR(AF_INET)) >= 0);
318
319 assert_se(seccomp_restrict_address_families(s, true) >= 0);
320
321 fd = socket(AF_INET, SOCK_DGRAM, 0);
322 assert_se(fd >= 0);
323 safe_close(fd);
324
ad8f1479 325 fd = socket(AF_UNIX, SOCK_DGRAM, 0);
dce0e620 326#if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
ad8f1479
LP
327 assert_se(fd >= 0);
328 safe_close(fd);
dce0e620
ZJS
329#else
330 assert_se(fd < 0);
331 assert_se(errno == EAFNOSUPPORT);
332#endif
ad8f1479
LP
333
334 fd = socket(AF_NETLINK, SOCK_DGRAM, 0);
dce0e620 335#if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
ad8f1479
LP
336 assert_se(fd >= 0);
337 safe_close(fd);
338#else
dce0e620 339 assert_se(fd < 0);
469830d1 340 assert_se(errno == EAFNOSUPPORT);
ad8f1479 341#endif
469830d1
LP
342
343 _exit(EXIT_SUCCESS);
344 }
345
346 assert_se(wait_for_terminate_and_warn("socketseccomp", pid, true) == EXIT_SUCCESS);
347}
348
349static void test_restrict_realtime(void) {
350 pid_t pid;
351
352 if (!is_seccomp_available())
353 return;
354 if (geteuid() != 0)
355 return;
356
357 if (detect_container() > 0) /* in containers RT privs are likely missing anyway */
358 return;
359
360 pid = fork();
361 assert_se(pid >= 0);
362
363 if (pid == 0) {
364 assert_se(sched_setscheduler(0, SCHED_FIFO, &(struct sched_param) { .sched_priority = 1 }) >= 0);
365 assert_se(sched_setscheduler(0, SCHED_RR, &(struct sched_param) { .sched_priority = 1 }) >= 0);
366 assert_se(sched_setscheduler(0, SCHED_IDLE, &(struct sched_param) { .sched_priority = 0 }) >= 0);
367 assert_se(sched_setscheduler(0, SCHED_BATCH, &(struct sched_param) { .sched_priority = 0 }) >= 0);
368 assert_se(sched_setscheduler(0, SCHED_OTHER, &(struct sched_param) {}) >= 0);
369
370 assert_se(seccomp_restrict_realtime() >= 0);
371
372 assert_se(sched_setscheduler(0, SCHED_IDLE, &(struct sched_param) { .sched_priority = 0 }) >= 0);
373 assert_se(sched_setscheduler(0, SCHED_BATCH, &(struct sched_param) { .sched_priority = 0 }) >= 0);
374 assert_se(sched_setscheduler(0, SCHED_OTHER, &(struct sched_param) {}) >= 0);
375
376 assert_se(sched_setscheduler(0, SCHED_FIFO, &(struct sched_param) { .sched_priority = 1 }) < 0);
377 assert_se(errno == EPERM);
378 assert_se(sched_setscheduler(0, SCHED_RR, &(struct sched_param) { .sched_priority = 1 }) < 0);
379 assert_se(errno == EPERM);
380
381 _exit(EXIT_SUCCESS);
382 }
383
384 assert_se(wait_for_terminate_and_warn("realtimeseccomp", pid, true) == EXIT_SUCCESS);
385}
386
2a65bd94 387static void test_memory_deny_write_execute_mmap(void) {
469830d1
LP
388 pid_t pid;
389
390 if (!is_seccomp_available())
391 return;
392 if (geteuid() != 0)
393 return;
394
395 pid = fork();
396 assert_se(pid >= 0);
397
398 if (pid == 0) {
399 void *p;
400
401 p = mmap(NULL, page_size(), PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1,0);
402 assert_se(p != MAP_FAILED);
403 assert_se(munmap(p, page_size()) >= 0);
404
8a50cf69
LP
405 p = mmap(NULL, page_size(), PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1,0);
406 assert_se(p != MAP_FAILED);
407 assert_se(munmap(p, page_size()) >= 0);
469830d1 408
8a50cf69
LP
409 assert_se(seccomp_memory_deny_write_execute() >= 0);
410
8a50cf69 411 p = mmap(NULL, page_size(), PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1,0);
4278d1f5 412#if defined(__x86_64__) || defined(__i386__) || defined(__powerpc64__) || defined(__arm__) || defined(__aarch64__)
469830d1
LP
413 assert_se(p == MAP_FAILED);
414 assert_se(errno == EPERM);
2a65bd94
ZJS
415#else /* unknown architectures */
416 assert_se(p != MAP_FAILED);
417 assert_se(munmap(p, page_size()) >= 0);
8a50cf69 418#endif
469830d1
LP
419
420 p = mmap(NULL, page_size(), PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1,0);
421 assert_se(p != MAP_FAILED);
422 assert_se(munmap(p, page_size()) >= 0);
423
424 _exit(EXIT_SUCCESS);
425 }
426
2a65bd94
ZJS
427 assert_se(wait_for_terminate_and_warn("memoryseccomp-mmap", pid, true) == EXIT_SUCCESS);
428}
429
430static void test_memory_deny_write_execute_shmat(void) {
431 int shmid;
432 pid_t pid;
433
434 if (!is_seccomp_available())
435 return;
436 if (geteuid() != 0)
437 return;
438
439 shmid = shmget(IPC_PRIVATE, page_size(), 0);
440 assert_se(shmid >= 0);
441
442 pid = fork();
443 assert_se(pid >= 0);
444
445 if (pid == 0) {
446 void *p;
447
448 p = shmat(shmid, NULL, 0);
449 assert_se(p != MAP_FAILED);
450 assert_se(shmdt(p) == 0);
451
452 p = shmat(shmid, NULL, SHM_EXEC);
453 assert_se(p != MAP_FAILED);
454 assert_se(shmdt(p) == 0);
455
456 assert_se(seccomp_memory_deny_write_execute() >= 0);
457
458 p = shmat(shmid, NULL, SHM_EXEC);
4278d1f5 459#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
2a65bd94
ZJS
460 assert_se(p == MAP_FAILED);
461 assert_se(errno == EPERM);
2a8d6e63 462#else /* __i386__, __powerpc64__, and "unknown" architectures */
2a65bd94
ZJS
463 assert_se(p != MAP_FAILED);
464 assert_se(shmdt(p) == 0);
465#endif
466
467 p = shmat(shmid, NULL, 0);
468 assert_se(p != MAP_FAILED);
469 assert_se(shmdt(p) == 0);
470
471 _exit(EXIT_SUCCESS);
472 }
473
474 assert_se(wait_for_terminate_and_warn("memoryseccomp-shmat", pid, true) == EXIT_SUCCESS);
469830d1
LP
475}
476
477static void test_restrict_archs(void) {
478 pid_t pid;
479
480 if (!is_seccomp_available())
481 return;
482 if (geteuid() != 0)
483 return;
484
485 pid = fork();
486 assert_se(pid >= 0);
487
488 if (pid == 0) {
489 _cleanup_set_free_ Set *s = NULL;
490
491 assert_se(access("/", F_OK) >= 0);
492
493 assert_se(s = set_new(NULL));
494
495#ifdef __x86_64__
496 assert_se(set_put(s, UINT32_TO_PTR(SCMP_ARCH_X86+1)) >= 0);
497#endif
498 assert_se(seccomp_restrict_archs(s) >= 0);
499
500 assert_se(access("/", F_OK) >= 0);
501 assert_se(seccomp_restrict_archs(NULL) >= 0);
502
503 assert_se(access("/", F_OK) >= 0);
504
505 _exit(EXIT_SUCCESS);
506 }
507
508 assert_se(wait_for_terminate_and_warn("archseccomp", pid, true) == EXIT_SUCCESS);
509}
510
511static void test_load_syscall_filter_set_raw(void) {
512 pid_t pid;
513
514 if (!is_seccomp_available())
515 return;
516 if (geteuid() != 0)
517 return;
518
519 pid = fork();
520 assert_se(pid >= 0);
521
522 if (pid == 0) {
b4891260 523 _cleanup_hashmap_free_ Hashmap *s = NULL;
469830d1
LP
524
525 assert_se(access("/", F_OK) >= 0);
526 assert_se(poll(NULL, 0, 0) == 0);
527
528 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, SCMP_ACT_KILL) >= 0);
529 assert_se(access("/", F_OK) >= 0);
530 assert_se(poll(NULL, 0, 0) == 0);
531
b4891260 532 assert_se(s = hashmap_new(NULL));
f60a865a 533#if SCMP_SYS(access) >= 0
b4891260 534 assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_access + 1), INT_TO_PTR(-1)) >= 0);
f60a865a 535#else
b4891260 536 assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(-1)) >= 0);
f60a865a 537#endif
469830d1
LP
538
539 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN)) >= 0);
540
541 assert_se(access("/", F_OK) < 0);
542 assert_se(errno == EUCLEAN);
543
544 assert_se(poll(NULL, 0, 0) == 0);
545
b4891260 546 s = hashmap_free(s);
469830d1 547
b4891260
YW
548 assert_se(s = hashmap_new(NULL));
549#if SCMP_SYS(access) >= 0
550 assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_access + 1), INT_TO_PTR(EILSEQ)) >= 0);
551#else
552 assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(EILSEQ)) >= 0);
553#endif
554
555 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN)) >= 0);
556
557 assert_se(access("/", F_OK) < 0);
558 assert_se(errno == EILSEQ);
559
560 assert_se(poll(NULL, 0, 0) == 0);
561
562 s = hashmap_free(s);
563
564 assert_se(s = hashmap_new(NULL));
f60a865a 565#if SCMP_SYS(poll) >= 0
b4891260 566 assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_poll + 1), INT_TO_PTR(-1)) >= 0);
f60a865a 567#else
b4891260 568 assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(-1)) >= 0);
f60a865a 569#endif
469830d1
LP
570
571 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH)) >= 0);
572
573 assert_se(access("/", F_OK) < 0);
b4891260 574 assert_se(errno == EILSEQ);
469830d1
LP
575
576 assert_se(poll(NULL, 0, 0) < 0);
577 assert_se(errno == EUNATCH);
578
b4891260
YW
579 s = hashmap_free(s);
580
581 assert_se(s = hashmap_new(NULL));
582#if SCMP_SYS(poll) >= 0
583 assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_poll + 1), INT_TO_PTR(EILSEQ)) >= 0);
584#else
585 assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(EILSEQ)) >= 0);
586#endif
587
588 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH)) >= 0);
589
590 assert_se(access("/", F_OK) < 0);
591 assert_se(errno == EILSEQ);
592
593 assert_se(poll(NULL, 0, 0) < 0);
594 assert_se(errno == EILSEQ);
595
469830d1
LP
596 _exit(EXIT_SUCCESS);
597 }
598
599 assert_se(wait_for_terminate_and_warn("syscallrawseccomp", pid, true) == EXIT_SUCCESS);
600}
601
78e864e5 602static void test_lock_personality(void) {
e8132d63 603 unsigned long current;
78e864e5
TM
604 pid_t pid;
605
606 if (!is_seccomp_available())
607 return;
608 if (geteuid() != 0)
609 return;
610
e8132d63
LP
611 assert_se(opinionated_personality(&current) >= 0);
612
613 log_info("current personality=%lu", current);
614
78e864e5
TM
615 pid = fork();
616 assert_se(pid >= 0);
617
618 if (pid == 0) {
e8132d63 619 assert_se(seccomp_lock_personality(current) >= 0);
78e864e5 620
21022b9d 621 assert_se((unsigned long) safe_personality(current) == current);
e8132d63 622
21022b9d
LP
623 /* Note, we also test that safe_personality() works correctly, by checkig whether errno is properly
624 * set, in addition to the return value */
625 errno = 0;
626 assert_se(safe_personality(PER_LINUX | ADDR_NO_RANDOMIZE) == -EPERM);
627 assert_se(errno == EPERM);
e8132d63 628
21022b9d
LP
629 assert_se(safe_personality(PER_LINUX | MMAP_PAGE_ZERO) == -EPERM);
630 assert_se(safe_personality(PER_LINUX | ADDR_COMPAT_LAYOUT) == -EPERM);
631 assert_se(safe_personality(PER_LINUX | READ_IMPLIES_EXEC) == -EPERM);
632 assert_se(safe_personality(PER_LINUX_32BIT) == -EPERM);
633 assert_se(safe_personality(PER_SVR4) == -EPERM);
634 assert_se(safe_personality(PER_BSD) == -EPERM);
635 assert_se(safe_personality(current == PER_LINUX ? PER_LINUX32 : PER_LINUX) == -EPERM);
636 assert_se(safe_personality(PER_LINUX32_3GB) == -EPERM);
637 assert_se(safe_personality(PER_UW7) == -EPERM);
638 assert_se(safe_personality(0x42) == -EPERM);
639
640 assert_se(safe_personality(PERSONALITY_INVALID) == -EPERM); /* maybe remove this later */
e8132d63
LP
641
642 assert_se((unsigned long) personality(current) == current);
78e864e5
TM
643 _exit(EXIT_SUCCESS);
644 }
645
646 assert_se(wait_for_terminate_and_warn("lockpersonalityseccomp", pid, true) == EXIT_SUCCESS);
647}
648
25e94f8c
LP
649static void test_filter_sets_ordered(void) {
650 size_t i;
651
652 /* Ensure "@default" always remains at the beginning of the list */
653 assert_se(SYSCALL_FILTER_SET_DEFAULT == 0);
654 assert_se(streq(syscall_filter_sets[0].name, "@default"));
655
656 for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
657 const char *k, *p = NULL;
658
659 /* Make sure each group has a description */
660 assert_se(!isempty(syscall_filter_sets[0].help));
661
662 /* Make sure the groups are ordered alphabetically, except for the first entry */
663 assert_se(i < 2 || strcmp(syscall_filter_sets[i-1].name, syscall_filter_sets[i].name) < 0);
664
665 NULSTR_FOREACH(k, syscall_filter_sets[i].value) {
666
667 /* Ensure each syscall list is in itself ordered, but groups before names */
668 assert_se(!p ||
669 (*p == '@' && *k != '@') ||
670 (((*p == '@' && *k == '@') ||
671 (*p != '@' && *k != '@')) &&
672 strcmp(p, k) < 0));
673
674 p = k;
675 }
676 }
677}
678
f6281133
LP
679int main(int argc, char *argv[]) {
680
add00535
LP
681 log_set_max_level(LOG_DEBUG);
682
f6281133 683 test_seccomp_arch_to_string();
aa34055f 684 test_architecture_table();
f6281133
LP
685 test_syscall_filter_set_find();
686 test_filter_sets();
add00535 687 test_restrict_namespace();
469830d1
LP
688 test_protect_sysctl();
689 test_restrict_address_families();
690 test_restrict_realtime();
2a65bd94
ZJS
691 test_memory_deny_write_execute_mmap();
692 test_memory_deny_write_execute_shmat();
469830d1
LP
693 test_restrict_archs();
694 test_load_syscall_filter_set_raw();
78e864e5 695 test_lock_personality();
25e94f8c 696 test_filter_sets_ordered();
f6281133
LP
697
698 return 0;
699}