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