]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-seccomp.c
Merge pull request #7379 from yuwata/follow-up-7309
[thirdparty/systemd.git] / src / test / test-seccomp.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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
21 #include <poll.h>
22 #include <sched.h>
23 #include <stdlib.h>
24 #include <sys/eventfd.h>
25 #include <sys/mman.h>
26 #include <sys/personality.h>
27 #include <sys/shm.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30
31 #include "alloc-util.h"
32 #include "fd-util.h"
33 #include "macro.h"
34 #include "missing.h"
35 #include "nsflags.h"
36 #include "process-util.h"
37 #include "raw-clone.h"
38 #include "seccomp-util.h"
39 #include "set.h"
40 #include "string-util.h"
41 #include "util.h"
42 #include "virt.h"
43
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
52 static 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
64 static 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
94 static 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
105 static void test_filter_sets(void) {
106 unsigned i;
107 int r;
108
109 if (!is_seccomp_available())
110 return;
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 */
126 r = seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN), syscall_filter_sets + i, SCMP_ACT_ALLOW);
127 else
128 r = seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + i, SCMP_ACT_ERRNO(EUCLEAN));
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))
135 assert_se(fd < 0 && errno == EUCLEAN);
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
148 static void test_restrict_namespace(void) {
149 _cleanup_free_ char *s = NULL;
150 unsigned long ul;
151 pid_t pid;
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;
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
233 static 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) {
248 #if __NR__sysctl > 0
249 assert_se(syscall(__NR__sysctl, NULL) < 0);
250 assert_se(errno == EFAULT);
251 #endif
252
253 assert_se(seccomp_protect_sysctl() >= 0);
254
255 #if __NR__sysctl > 0
256 assert_se(syscall(__NR__sysctl, 0, 0, 0) < 0);
257 assert_se(errno == EPERM);
258 #endif
259
260 _exit(EXIT_SUCCESS);
261 }
262
263 assert_se(wait_for_terminate_and_warn("sysctlseccomp", pid, true) == EXIT_SUCCESS);
264 }
265
266 static 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
302 fd = socket(AF_UNIX, SOCK_DGRAM, 0);
303 #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
304 assert_se(fd >= 0);
305 safe_close(fd);
306 #else
307 assert_se(fd < 0);
308 assert_se(errno == EAFNOSUPPORT);
309 #endif
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
325 fd = socket(AF_UNIX, SOCK_DGRAM, 0);
326 #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
327 assert_se(fd >= 0);
328 safe_close(fd);
329 #else
330 assert_se(fd < 0);
331 assert_se(errno == EAFNOSUPPORT);
332 #endif
333
334 fd = socket(AF_NETLINK, SOCK_DGRAM, 0);
335 #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
336 assert_se(fd >= 0);
337 safe_close(fd);
338 #else
339 assert_se(fd < 0);
340 assert_se(errno == EAFNOSUPPORT);
341 #endif
342
343 _exit(EXIT_SUCCESS);
344 }
345
346 assert_se(wait_for_terminate_and_warn("socketseccomp", pid, true) == EXIT_SUCCESS);
347 }
348
349 static 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
387 static void test_memory_deny_write_execute_mmap(void) {
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
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);
408
409 assert_se(seccomp_memory_deny_write_execute() >= 0);
410
411 p = mmap(NULL, page_size(), PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1,0);
412 #if defined(__x86_64__) || defined(__i386__) || defined(__powerpc64__) || defined(__arm__) || defined(__aarch64__)
413 assert_se(p == MAP_FAILED);
414 assert_se(errno == EPERM);
415 #else /* unknown architectures */
416 assert_se(p != MAP_FAILED);
417 assert_se(munmap(p, page_size()) >= 0);
418 #endif
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
427 assert_se(wait_for_terminate_and_warn("memoryseccomp-mmap", pid, true) == EXIT_SUCCESS);
428 }
429
430 static 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);
459 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
460 assert_se(p == MAP_FAILED);
461 assert_se(errno == EPERM);
462 #else /* __i386__, __powerpc64__, and "unknown" architectures */
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);
475 }
476
477 static 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
511 static 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) {
523 _cleanup_hashmap_free_ Hashmap *s = NULL;
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
532 assert_se(s = hashmap_new(NULL));
533 #if SCMP_SYS(access) >= 0
534 assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_access + 1), INT_TO_PTR(-1)) >= 0);
535 #else
536 assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(-1)) >= 0);
537 #endif
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
546 s = hashmap_free(s);
547
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));
565 #if SCMP_SYS(poll) >= 0
566 assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_poll + 1), INT_TO_PTR(-1)) >= 0);
567 #else
568 assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(-1)) >= 0);
569 #endif
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);
574 assert_se(errno == EILSEQ);
575
576 assert_se(poll(NULL, 0, 0) < 0);
577 assert_se(errno == EUNATCH);
578
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
596 _exit(EXIT_SUCCESS);
597 }
598
599 assert_se(wait_for_terminate_and_warn("syscallrawseccomp", pid, true) == EXIT_SUCCESS);
600 }
601
602 static void test_lock_personality(void) {
603 unsigned long current;
604 pid_t pid;
605
606 if (!is_seccomp_available())
607 return;
608 if (geteuid() != 0)
609 return;
610
611 assert_se(opinionated_personality(&current) >= 0);
612
613 log_info("current personality=%lu", current);
614
615 pid = fork();
616 assert_se(pid >= 0);
617
618 if (pid == 0) {
619 assert_se(seccomp_lock_personality(current) >= 0);
620
621 assert_se((unsigned long) safe_personality(current) == current);
622
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);
628
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 */
641
642 assert_se((unsigned long) personality(current) == current);
643 _exit(EXIT_SUCCESS);
644 }
645
646 assert_se(wait_for_terminate_and_warn("lockpersonalityseccomp", pid, true) == EXIT_SUCCESS);
647 }
648
649 static 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
679 int main(int argc, char *argv[]) {
680
681 log_set_max_level(LOG_DEBUG);
682
683 test_seccomp_arch_to_string();
684 test_architecture_table();
685 test_syscall_filter_set_find();
686 test_filter_sets();
687 test_restrict_namespace();
688 test_protect_sysctl();
689 test_restrict_address_families();
690 test_restrict_realtime();
691 test_memory_deny_write_execute_mmap();
692 test_memory_deny_write_execute_shmat();
693 test_restrict_archs();
694 test_load_syscall_filter_set_raw();
695 test_lock_personality();
696 test_filter_sets_ordered();
697
698 return 0;
699 }