1 /* SPDX-License-Identifier: LGPL-2.1+ */
6 #include <sys/eventfd.h>
8 #include <sys/personality.h>
10 #include <sys/syscall.h>
11 #include <sys/types.h>
14 #include "alloc-util.h"
17 #include "memory-util.h"
20 #include "nulstr-util.h"
21 #include "process-util.h"
22 #include "raw-clone.h"
24 #include "seccomp-util.h"
26 #include "string-util.h"
28 #include "tmpfile-util.h"
31 #if SCMP_SYS(socket) < 0 || defined(__i386__) || defined(__s390x__) || defined(__s390__)
32 /* On these archs, socket() is implemented via the socketcall() syscall multiplexer,
33 * and we can't restrict it hence via seccomp. */
34 # define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 1
36 # define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 0
39 static void test_seccomp_arch_to_string(void) {
43 log_info("/* %s */", __func__
);
45 a
= seccomp_arch_native();
47 name
= seccomp_arch_to_string(a
);
49 assert_se(seccomp_arch_from_string(name
, &b
) >= 0);
53 static void test_architecture_table(void) {
56 log_info("/* %s */", __func__
);
78 assert_se(seccomp_arch_from_string(n
, &c
) >= 0);
79 n2
= seccomp_arch_to_string(c
);
80 log_info("seccomp-arch: %s → 0x%"PRIx32
" → %s", n
, c
, n2
);
81 assert_se(streq_ptr(n
, n2
));
85 static void test_syscall_filter_set_find(void) {
86 log_info("/* %s */", __func__
);
88 assert_se(!syscall_filter_set_find(NULL
));
89 assert_se(!syscall_filter_set_find(""));
90 assert_se(!syscall_filter_set_find("quux"));
91 assert_se(!syscall_filter_set_find("@quux"));
93 assert_se(syscall_filter_set_find("@clock") == syscall_filter_sets
+ SYSCALL_FILTER_SET_CLOCK
);
94 assert_se(syscall_filter_set_find("@default") == syscall_filter_sets
+ SYSCALL_FILTER_SET_DEFAULT
);
95 assert_se(syscall_filter_set_find("@raw-io") == syscall_filter_sets
+ SYSCALL_FILTER_SET_RAW_IO
);
98 static void test_filter_sets(void) {
102 log_info("/* %s */", __func__
);
104 if (!is_seccomp_available()) {
105 log_notice("Seccomp not available, skipping %s", __func__
);
108 if (geteuid() != 0) {
109 log_notice("Not root, skipping %s", __func__
);
113 for (i
= 0; i
< _SYSCALL_FILTER_SET_MAX
; i
++) {
116 log_info("Testing %s", syscall_filter_sets
[i
].name
);
121 if (pid
== 0) { /* Child? */
124 /* If we look at the default set (or one that includes it), whitelist instead of blacklist */
125 if (IN_SET(i
, SYSCALL_FILTER_SET_DEFAULT
, SYSCALL_FILTER_SET_SYSTEM_SERVICE
))
126 r
= seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN
), syscall_filter_sets
+ i
, SCMP_ACT_ALLOW
, true);
128 r
= seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW
, syscall_filter_sets
+ i
, SCMP_ACT_ERRNO(EUCLEAN
), true);
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
);
144 assert_se(wait_for_terminate_and_check(syscall_filter_sets
[i
].name
, pid
, WAIT_LOG
) == EXIT_SUCCESS
);
148 static void test_filter_sets_ordered(void) {
151 log_info("/* %s */", __func__
);
153 /* Ensure "@default" always remains at the beginning of the list */
154 assert_se(SYSCALL_FILTER_SET_DEFAULT
== 0);
155 assert_se(streq(syscall_filter_sets
[0].name
, "@default"));
157 for (i
= 0; i
< _SYSCALL_FILTER_SET_MAX
; i
++) {
158 const char *k
, *p
= NULL
;
160 /* Make sure each group has a description */
161 assert_se(!isempty(syscall_filter_sets
[0].help
));
163 /* Make sure the groups are ordered alphabetically, except for the first entry */
164 assert_se(i
< 2 || strcmp(syscall_filter_sets
[i
-1].name
, syscall_filter_sets
[i
].name
) < 0);
166 NULSTR_FOREACH(k
, syscall_filter_sets
[i
].value
) {
168 /* Ensure each syscall list is in itself ordered, but groups before names */
170 (*p
== '@' && *k
!= '@') ||
171 (((*p
== '@' && *k
== '@') ||
172 (*p
!= '@' && *k
!= '@')) &&
180 static void test_restrict_namespace(void) {
185 if (!have_namespaces()) {
186 log_notice("Testing without namespaces, skipping %s", __func__
);
190 log_info("/* %s */", __func__
);
192 assert_se(namespace_flags_to_string(0, &s
) == 0 && streq(s
, ""));
194 assert_se(namespace_flags_to_string(CLONE_NEWNS
, &s
) == 0 && streq(s
, "mnt"));
196 assert_se(namespace_flags_to_string(CLONE_NEWNS
|CLONE_NEWIPC
, &s
) == 0 && streq(s
, "ipc mnt"));
198 assert_se(namespace_flags_to_string(CLONE_NEWCGROUP
, &s
) == 0 && streq(s
, "cgroup"));
201 assert_se(namespace_flags_from_string("mnt", &ul
) == 0 && ul
== CLONE_NEWNS
);
202 assert_se(namespace_flags_from_string(NULL
, &ul
) == 0 && ul
== 0);
203 assert_se(namespace_flags_from_string("", &ul
) == 0 && ul
== 0);
204 assert_se(namespace_flags_from_string("uts", &ul
) == 0 && ul
== CLONE_NEWUTS
);
205 assert_se(namespace_flags_from_string("mnt uts ipc", &ul
) == 0 && ul
== (CLONE_NEWNS
|CLONE_NEWUTS
|CLONE_NEWIPC
));
207 assert_se(namespace_flags_to_string(CLONE_NEWUTS
, &s
) == 0 && streq(s
, "uts"));
208 assert_se(namespace_flags_from_string(s
, &ul
) == 0 && ul
== CLONE_NEWUTS
);
210 assert_se(namespace_flags_from_string("ipc", &ul
) == 0 && ul
== CLONE_NEWIPC
);
211 assert_se(namespace_flags_to_string(ul
, &s
) == 0 && streq(s
, "ipc"));
214 assert_se(namespace_flags_to_string(NAMESPACE_FLAGS_ALL
, &s
) == 0);
215 assert_se(streq(s
, "cgroup ipc net mnt pid user uts"));
216 assert_se(namespace_flags_from_string(s
, &ul
) == 0 && ul
== NAMESPACE_FLAGS_ALL
);
219 if (!is_seccomp_available()) {
220 log_notice("Seccomp not available, skipping remaining tests in %s", __func__
);
223 if (geteuid() != 0) {
224 log_notice("Not root, skipping remaining tests in %s", __func__
);
233 assert_se(seccomp_restrict_namespaces(CLONE_NEWNS
|CLONE_NEWNET
) >= 0);
235 assert_se(unshare(CLONE_NEWNS
) == 0);
236 assert_se(unshare(CLONE_NEWNET
) == 0);
237 assert_se(unshare(CLONE_NEWUTS
) == -1);
238 assert_se(errno
== EPERM
);
239 assert_se(unshare(CLONE_NEWIPC
) == -1);
240 assert_se(errno
== EPERM
);
241 assert_se(unshare(CLONE_NEWNET
|CLONE_NEWUTS
) == -1);
242 assert_se(errno
== EPERM
);
244 /* We use fd 0 (stdin) here, which of course will fail with EINVAL on setns(). Except of course our
245 * seccomp filter worked, and hits first and makes it return EPERM */
246 assert_se(setns(0, CLONE_NEWNS
) == -1);
247 assert_se(errno
== EINVAL
);
248 assert_se(setns(0, CLONE_NEWNET
) == -1);
249 assert_se(errno
== EINVAL
);
250 assert_se(setns(0, CLONE_NEWUTS
) == -1);
251 assert_se(errno
== EPERM
);
252 assert_se(setns(0, CLONE_NEWIPC
) == -1);
253 assert_se(errno
== EPERM
);
254 assert_se(setns(0, CLONE_NEWNET
|CLONE_NEWUTS
) == -1);
255 assert_se(errno
== EPERM
);
256 assert_se(setns(0, 0) == -1);
257 assert_se(errno
== EPERM
);
259 pid
= raw_clone(CLONE_NEWNS
);
263 pid
= raw_clone(CLONE_NEWNET
);
267 pid
= raw_clone(CLONE_NEWUTS
);
269 assert_se(errno
== EPERM
);
270 pid
= raw_clone(CLONE_NEWIPC
);
272 assert_se(errno
== EPERM
);
273 pid
= raw_clone(CLONE_NEWNET
|CLONE_NEWUTS
);
275 assert_se(errno
== EPERM
);
280 assert_se(wait_for_terminate_and_check("nsseccomp", pid
, WAIT_LOG
) == EXIT_SUCCESS
);
283 static void test_protect_sysctl(void) {
286 log_info("/* %s */", __func__
);
288 if (!is_seccomp_available()) {
289 log_notice("Seccomp not available, skipping %s", __func__
);
292 if (geteuid() != 0) {
293 log_notice("Not root, skipping %s", __func__
);
297 /* in containers _sysctl() is likely missing anyway */
298 if (detect_container() > 0) {
299 log_notice("Testing in container, skipping %s", __func__
);
308 assert_se(syscall(__NR__sysctl
, NULL
) < 0);
309 assert_se(errno
== EFAULT
);
312 assert_se(seccomp_protect_sysctl() >= 0);
315 assert_se(syscall(__NR__sysctl
, 0, 0, 0) < 0);
316 assert_se(errno
== EPERM
);
322 assert_se(wait_for_terminate_and_check("sysctlseccomp", pid
, WAIT_LOG
) == EXIT_SUCCESS
);
325 static void test_restrict_address_families(void) {
328 log_info("/* %s */", __func__
);
330 if (!is_seccomp_available()) {
331 log_notice("Seccomp not available, skipping %s", __func__
);
334 if (geteuid() != 0) {
335 log_notice("Not root, skipping %s", __func__
);
346 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
350 fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
354 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, 0);
358 assert_se(s
= set_new(NULL
));
359 assert_se(set_put(s
, INT_TO_PTR(AF_UNIX
)) >= 0);
361 assert_se(seccomp_restrict_address_families(s
, false) >= 0);
363 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
367 fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
368 #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
373 assert_se(errno
== EAFNOSUPPORT
);
376 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, 0);
382 assert_se(set_put(s
, INT_TO_PTR(AF_INET
)) >= 0);
384 assert_se(seccomp_restrict_address_families(s
, true) >= 0);
386 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
390 fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
391 #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
396 assert_se(errno
== EAFNOSUPPORT
);
399 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, 0);
400 #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
405 assert_se(errno
== EAFNOSUPPORT
);
411 assert_se(wait_for_terminate_and_check("socketseccomp", pid
, WAIT_LOG
) == EXIT_SUCCESS
);
414 static void test_restrict_realtime(void) {
417 log_info("/* %s */", __func__
);
419 if (!is_seccomp_available()) {
420 log_notice("Seccomp not available, skipping %s", __func__
);
423 if (geteuid() != 0) {
424 log_notice("Not root, skipping %s", __func__
);
428 /* in containers RT privs are likely missing anyway */
429 if (detect_container() > 0) {
430 log_notice("Testing in container, skipping %s", __func__
);
438 assert_se(sched_setscheduler(0, SCHED_FIFO
, &(struct sched_param
) { .sched_priority
= 1 }) >= 0);
439 assert_se(sched_setscheduler(0, SCHED_RR
, &(struct sched_param
) { .sched_priority
= 1 }) >= 0);
440 assert_se(sched_setscheduler(0, SCHED_IDLE
, &(struct sched_param
) { .sched_priority
= 0 }) >= 0);
441 assert_se(sched_setscheduler(0, SCHED_BATCH
, &(struct sched_param
) { .sched_priority
= 0 }) >= 0);
442 assert_se(sched_setscheduler(0, SCHED_OTHER
, &(struct sched_param
) {}) >= 0);
444 assert_se(seccomp_restrict_realtime() >= 0);
446 assert_se(sched_setscheduler(0, SCHED_IDLE
, &(struct sched_param
) { .sched_priority
= 0 }) >= 0);
447 assert_se(sched_setscheduler(0, SCHED_BATCH
, &(struct sched_param
) { .sched_priority
= 0 }) >= 0);
448 assert_se(sched_setscheduler(0, SCHED_OTHER
, &(struct sched_param
) {}) >= 0);
450 assert_se(sched_setscheduler(0, SCHED_FIFO
, &(struct sched_param
) { .sched_priority
= 1 }) < 0);
451 assert_se(errno
== EPERM
);
452 assert_se(sched_setscheduler(0, SCHED_RR
, &(struct sched_param
) { .sched_priority
= 1 }) < 0);
453 assert_se(errno
== EPERM
);
458 assert_se(wait_for_terminate_and_check("realtimeseccomp", pid
, WAIT_LOG
) == EXIT_SUCCESS
);
461 static void test_memory_deny_write_execute_mmap(void) {
464 log_info("/* %s */", __func__
);
466 if (!is_seccomp_available()) {
467 log_notice("Seccomp not available, skipping %s", __func__
);
470 if (geteuid() != 0) {
471 log_notice("Not root, skipping %s", __func__
);
481 p
= mmap(NULL
, page_size(), PROT_WRITE
|PROT_EXEC
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1,0);
482 assert_se(p
!= MAP_FAILED
);
483 assert_se(munmap(p
, page_size()) >= 0);
485 p
= mmap(NULL
, page_size(), PROT_WRITE
|PROT_READ
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1,0);
486 assert_se(p
!= MAP_FAILED
);
487 assert_se(munmap(p
, page_size()) >= 0);
489 assert_se(seccomp_memory_deny_write_execute() >= 0);
491 p
= mmap(NULL
, page_size(), PROT_WRITE
|PROT_EXEC
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1,0);
492 #if defined(__x86_64__) || defined(__i386__) || defined(__powerpc64__) || defined(__arm__) || defined(__aarch64__)
493 assert_se(p
== MAP_FAILED
);
494 assert_se(errno
== EPERM
);
495 #else /* unknown architectures */
496 assert_se(p
!= MAP_FAILED
);
497 assert_se(munmap(p
, page_size()) >= 0);
500 p
= mmap(NULL
, page_size(), PROT_WRITE
|PROT_READ
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1,0);
501 assert_se(p
!= MAP_FAILED
);
502 assert_se(munmap(p
, page_size()) >= 0);
507 assert_se(wait_for_terminate_and_check("memoryseccomp-mmap", pid
, WAIT_LOG
) == EXIT_SUCCESS
);
510 static void test_memory_deny_write_execute_shmat(void) {
515 log_info("/* %s */", __func__
);
517 SECCOMP_FOREACH_LOCAL_ARCH(arch
) {
518 log_debug("arch %s: SCMP_SYS(mmap) = %d", seccomp_arch_to_string(arch
), SCMP_SYS(mmap
));
519 log_debug("arch %s: SCMP_SYS(mmap2) = %d", seccomp_arch_to_string(arch
), SCMP_SYS(mmap2
));
520 log_debug("arch %s: SCMP_SYS(shmget) = %d", seccomp_arch_to_string(arch
), SCMP_SYS(shmget
));
521 log_debug("arch %s: SCMP_SYS(shmat) = %d", seccomp_arch_to_string(arch
), SCMP_SYS(shmat
));
522 log_debug("arch %s: SCMP_SYS(shmdt) = %d", seccomp_arch_to_string(arch
), SCMP_SYS(shmdt
));
525 if (!is_seccomp_available()) {
526 log_notice("Seccomp not available, skipping %s", __func__
);
529 if (geteuid() != 0) {
530 log_notice("Not root, skipping %s", __func__
);
534 shmid
= shmget(IPC_PRIVATE
, page_size(), 0);
535 assert_se(shmid
>= 0);
543 p
= shmat(shmid
, NULL
, 0);
544 assert_se(p
!= MAP_FAILED
);
545 assert_se(shmdt(p
) == 0);
547 p
= shmat(shmid
, NULL
, SHM_EXEC
);
548 assert_se(p
!= MAP_FAILED
);
549 assert_se(shmdt(p
) == 0);
551 assert_se(seccomp_memory_deny_write_execute() >= 0);
553 p
= shmat(shmid
, NULL
, SHM_EXEC
);
554 log_debug_errno(p
== MAP_FAILED
? errno
: 0, "shmat(SHM_EXEC): %m");
555 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
556 assert_se(p
== MAP_FAILED
);
557 assert_se(errno
== EPERM
);
559 /* Depending on kernel, libseccomp, and glibc versions, other architectures
560 * might fail or not. Let's not assert success. */
562 assert_se(shmdt(p
) == 0);
564 p
= shmat(shmid
, NULL
, 0);
565 log_debug_errno(p
== MAP_FAILED
? errno
: 0, "shmat(0): %m");
566 assert_se(p
!= MAP_FAILED
);
567 assert_se(shmdt(p
) == 0);
572 assert_se(wait_for_terminate_and_check("memoryseccomp-shmat", pid
, WAIT_LOG
) == EXIT_SUCCESS
);
575 static void test_restrict_archs(void) {
578 log_info("/* %s */", __func__
);
580 if (!is_seccomp_available()) {
581 log_notice("Seccomp not available, skipping %s", __func__
);
584 if (geteuid() != 0) {
585 log_notice("Not root, skipping %s", __func__
);
593 _cleanup_set_free_ Set
*s
= NULL
;
595 assert_se(access("/", F_OK
) >= 0);
597 assert_se(s
= set_new(NULL
));
600 assert_se(set_put(s
, UINT32_TO_PTR(SCMP_ARCH_X86
+1)) >= 0);
602 assert_se(seccomp_restrict_archs(s
) >= 0);
604 assert_se(access("/", F_OK
) >= 0);
605 assert_se(seccomp_restrict_archs(NULL
) >= 0);
607 assert_se(access("/", F_OK
) >= 0);
612 assert_se(wait_for_terminate_and_check("archseccomp", pid
, WAIT_LOG
) == EXIT_SUCCESS
);
615 static void test_load_syscall_filter_set_raw(void) {
618 log_info("/* %s */", __func__
);
620 if (!is_seccomp_available()) {
621 log_notice("Seccomp not available, skipping %s", __func__
);
624 if (geteuid() != 0) {
625 log_notice("Not root, skipping %s", __func__
);
633 _cleanup_hashmap_free_ Hashmap
*s
= NULL
;
635 assert_se(access("/", F_OK
) >= 0);
636 assert_se(poll(NULL
, 0, 0) == 0);
638 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW
, NULL
, scmp_act_kill_process(), true) >= 0);
639 assert_se(access("/", F_OK
) >= 0);
640 assert_se(poll(NULL
, 0, 0) == 0);
642 assert_se(s
= hashmap_new(NULL
));
643 #if SCMP_SYS(access) >= 0
644 assert_se(hashmap_put(s
, UINT32_TO_PTR(__NR_access
+ 1), INT_TO_PTR(-1)) >= 0);
646 assert_se(hashmap_put(s
, UINT32_TO_PTR(__NR_faccessat
+ 1), INT_TO_PTR(-1)) >= 0);
649 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW
, s
, SCMP_ACT_ERRNO(EUCLEAN
), true) >= 0);
651 assert_se(access("/", F_OK
) < 0);
652 assert_se(errno
== EUCLEAN
);
654 assert_se(poll(NULL
, 0, 0) == 0);
658 assert_se(s
= hashmap_new(NULL
));
659 #if SCMP_SYS(access) >= 0
660 assert_se(hashmap_put(s
, UINT32_TO_PTR(__NR_access
+ 1), INT_TO_PTR(EILSEQ
)) >= 0);
662 assert_se(hashmap_put(s
, UINT32_TO_PTR(__NR_faccessat
+ 1), INT_TO_PTR(EILSEQ
)) >= 0);
665 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW
, s
, SCMP_ACT_ERRNO(EUCLEAN
), true) >= 0);
667 assert_se(access("/", F_OK
) < 0);
668 assert_se(errno
== EILSEQ
);
670 assert_se(poll(NULL
, 0, 0) == 0);
674 assert_se(s
= hashmap_new(NULL
));
675 #if SCMP_SYS(poll) >= 0
676 assert_se(hashmap_put(s
, UINT32_TO_PTR(__NR_poll
+ 1), INT_TO_PTR(-1)) >= 0);
678 assert_se(hashmap_put(s
, UINT32_TO_PTR(__NR_ppoll
+ 1), INT_TO_PTR(-1)) >= 0);
681 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW
, s
, SCMP_ACT_ERRNO(EUNATCH
), true) >= 0);
683 assert_se(access("/", F_OK
) < 0);
684 assert_se(errno
== EILSEQ
);
686 assert_se(poll(NULL
, 0, 0) < 0);
687 assert_se(errno
== EUNATCH
);
691 assert_se(s
= hashmap_new(NULL
));
692 #if SCMP_SYS(poll) >= 0
693 assert_se(hashmap_put(s
, UINT32_TO_PTR(__NR_poll
+ 1), INT_TO_PTR(EILSEQ
)) >= 0);
695 assert_se(hashmap_put(s
, UINT32_TO_PTR(__NR_ppoll
+ 1), INT_TO_PTR(EILSEQ
)) >= 0);
698 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW
, s
, SCMP_ACT_ERRNO(EUNATCH
), true) >= 0);
700 assert_se(access("/", F_OK
) < 0);
701 assert_se(errno
== EILSEQ
);
703 assert_se(poll(NULL
, 0, 0) < 0);
704 assert_se(errno
== EILSEQ
);
709 assert_se(wait_for_terminate_and_check("syscallrawseccomp", pid
, WAIT_LOG
) == EXIT_SUCCESS
);
712 static void test_lock_personality(void) {
713 unsigned long current
;
716 log_info("/* %s */", __func__
);
718 if (!is_seccomp_available()) {
719 log_notice("Seccomp not available, skipping %s", __func__
);
722 if (geteuid() != 0) {
723 log_notice("Not root, skipping %s", __func__
);
727 assert_se(opinionated_personality(¤t
) >= 0);
729 log_info("current personality=%lu", current
);
735 assert_se(seccomp_lock_personality(current
) >= 0);
737 assert_se((unsigned long) safe_personality(current
) == current
);
739 /* Note, we also test that safe_personality() works correctly, by checkig whether errno is properly
740 * set, in addition to the return value */
742 assert_se(safe_personality(PER_LINUX
| ADDR_NO_RANDOMIZE
) == -EPERM
);
743 assert_se(errno
== EPERM
);
745 assert_se(safe_personality(PER_LINUX
| MMAP_PAGE_ZERO
) == -EPERM
);
746 assert_se(safe_personality(PER_LINUX
| ADDR_COMPAT_LAYOUT
) == -EPERM
);
747 assert_se(safe_personality(PER_LINUX
| READ_IMPLIES_EXEC
) == -EPERM
);
748 assert_se(safe_personality(PER_LINUX_32BIT
) == -EPERM
);
749 assert_se(safe_personality(PER_SVR4
) == -EPERM
);
750 assert_se(safe_personality(PER_BSD
) == -EPERM
);
751 assert_se(safe_personality(current
== PER_LINUX
? PER_LINUX32
: PER_LINUX
) == -EPERM
);
752 assert_se(safe_personality(PER_LINUX32_3GB
) == -EPERM
);
753 assert_se(safe_personality(PER_UW7
) == -EPERM
);
754 assert_se(safe_personality(0x42) == -EPERM
);
756 assert_se(safe_personality(PERSONALITY_INVALID
) == -EPERM
); /* maybe remove this later */
758 assert_se((unsigned long) personality(current
) == current
);
762 assert_se(wait_for_terminate_and_check("lockpersonalityseccomp", pid
, WAIT_LOG
) == EXIT_SUCCESS
);
765 static int real_open(const char *path
, int flags
, mode_t mode
) {
766 /* glibc internally calls openat() when open() is requested. Let's hence define our own wrapper for
767 * testing purposes that calls the real syscall, on architectures where SYS_open is defined. On
768 * other architectures, let's just fall back to the glibc call. */
771 return (int) syscall(SYS_open
, path
, flags
, mode
);
773 return open(path
, flags
, mode
);
777 static void test_restrict_suid_sgid(void) {
780 log_info("/* %s */", __func__
);
782 if (!is_seccomp_available()) {
783 log_notice("Seccomp not available, skipping %s", __func__
);
786 if (geteuid() != 0) {
787 log_notice("Not root, skipping %s", __func__
);
795 char path
[] = "/tmp/suidsgidXXXXXX", dir
[] = "/tmp/suidsgiddirXXXXXX";
799 fd
= mkostemp_safe(path
);
802 assert_se(mkdtemp(dir
));
803 z
= strjoina(dir
, "/test");
805 assert_se(chmod(path
, 0755 | S_ISUID
) >= 0);
806 assert_se(chmod(path
, 0755 | S_ISGID
) >= 0);
807 assert_se(chmod(path
, 0755 | S_ISGID
| S_ISUID
) >= 0);
808 assert_se(chmod(path
, 0755) >= 0);
810 assert_se(fchmod(fd
, 0755 | S_ISUID
) >= 0);
811 assert_se(fchmod(fd
, 0755 | S_ISGID
) >= 0);
812 assert_se(fchmod(fd
, 0755 | S_ISGID
| S_ISUID
) >= 0);
813 assert_se(fchmod(fd
, 0755) >= 0);
815 assert_se(fchmodat(AT_FDCWD
, path
, 0755 | S_ISUID
, 0) >= 0);
816 assert_se(fchmodat(AT_FDCWD
, path
, 0755 | S_ISGID
, 0) >= 0);
817 assert_se(fchmodat(AT_FDCWD
, path
, 0755 | S_ISGID
| S_ISUID
, 0) >= 0);
818 assert_se(fchmodat(AT_FDCWD
, path
, 0755, 0) >= 0);
820 k
= real_open(z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644 | S_ISUID
);
822 assert_se(unlink(z
) >= 0);
824 k
= real_open(z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644 | S_ISGID
);
826 assert_se(unlink(z
) >= 0);
828 k
= real_open(z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644 | S_ISUID
| S_ISGID
);
830 assert_se(unlink(z
) >= 0);
832 k
= real_open(z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644);
834 assert_se(unlink(z
) >= 0);
836 k
= creat(z
, 0644 | S_ISUID
);
838 assert_se(unlink(z
) >= 0);
840 k
= creat(z
, 0644 | S_ISGID
);
842 assert_se(unlink(z
) >= 0);
844 k
= creat(z
, 0644 | S_ISUID
| S_ISGID
);
846 assert_se(unlink(z
) >= 0);
850 assert_se(unlink(z
) >= 0);
852 k
= openat(AT_FDCWD
, z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644 | S_ISUID
);
854 assert_se(unlink(z
) >= 0);
856 k
= openat(AT_FDCWD
, z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644 | S_ISGID
);
858 assert_se(unlink(z
) >= 0);
860 k
= openat(AT_FDCWD
, z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644 | S_ISUID
| S_ISGID
);
862 assert_se(unlink(z
) >= 0);
864 k
= openat(AT_FDCWD
, z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644);
866 assert_se(unlink(z
) >= 0);
868 assert_se(mkdir(z
, 0755 | S_ISUID
) >= 0);
869 assert_se(rmdir(z
) >= 0);
870 assert_se(mkdir(z
, 0755 | S_ISGID
) >= 0);
871 assert_se(rmdir(z
) >= 0);
872 assert_se(mkdir(z
, 0755 | S_ISUID
| S_ISGID
) >= 0);
873 assert_se(rmdir(z
) >= 0);
874 assert_se(mkdir(z
, 0755) >= 0);
875 assert_se(rmdir(z
) >= 0);
877 assert_se(mkdirat(AT_FDCWD
, z
, 0755 | S_ISUID
) >= 0);
878 assert_se(rmdir(z
) >= 0);
879 assert_se(mkdirat(AT_FDCWD
, z
, 0755 | S_ISGID
) >= 0);
880 assert_se(rmdir(z
) >= 0);
881 assert_se(mkdirat(AT_FDCWD
, z
, 0755 | S_ISUID
| S_ISGID
) >= 0);
882 assert_se(rmdir(z
) >= 0);
883 assert_se(mkdirat(AT_FDCWD
, z
, 0755) >= 0);
884 assert_se(rmdir(z
) >= 0);
886 assert_se(mknod(z
, S_IFREG
| 0755 | S_ISUID
, 0) >= 0);
887 assert_se(unlink(z
) >= 0);
888 assert_se(mknod(z
, S_IFREG
| 0755 | S_ISGID
, 0) >= 0);
889 assert_se(unlink(z
) >= 0);
890 assert_se(mknod(z
, S_IFREG
| 0755 | S_ISUID
| S_ISGID
, 0) >= 0);
891 assert_se(unlink(z
) >= 0);
892 assert_se(mknod(z
, S_IFREG
| 0755, 0) >= 0);
893 assert_se(unlink(z
) >= 0);
895 assert_se(mknodat(AT_FDCWD
, z
, S_IFREG
| 0755 | S_ISUID
, 0) >= 0);
896 assert_se(unlink(z
) >= 0);
897 assert_se(mknodat(AT_FDCWD
, z
, S_IFREG
| 0755 | S_ISGID
, 0) >= 0);
898 assert_se(unlink(z
) >= 0);
899 assert_se(mknodat(AT_FDCWD
, z
, S_IFREG
| 0755 | S_ISUID
| S_ISGID
, 0) >= 0);
900 assert_se(unlink(z
) >= 0);
901 assert_se(mknodat(AT_FDCWD
, z
, S_IFREG
| 0755, 0) >= 0);
902 assert_se(unlink(z
) >= 0);
904 assert_se(seccomp_restrict_suid_sgid() >= 0);
906 assert_se(chmod(path
, 0775 | S_ISUID
) < 0 && errno
== EPERM
);
907 assert_se(chmod(path
, 0775 | S_ISGID
) < 0 && errno
== EPERM
);
908 assert_se(chmod(path
, 0775 | S_ISGID
| S_ISUID
) < 0 && errno
== EPERM
);
909 assert_se(chmod(path
, 0775) >= 0);
911 assert_se(fchmod(fd
, 0775 | S_ISUID
) < 0 && errno
== EPERM
);
912 assert_se(fchmod(fd
, 0775 | S_ISGID
) < 0 && errno
== EPERM
);
913 assert_se(fchmod(fd
, 0775 | S_ISGID
| S_ISUID
) < 0 && errno
== EPERM
);
914 assert_se(fchmod(fd
, 0775) >= 0);
916 assert_se(fchmodat(AT_FDCWD
, path
, 0755 | S_ISUID
, 0) < 0 && errno
== EPERM
);
917 assert_se(fchmodat(AT_FDCWD
, path
, 0755 | S_ISGID
, 0) < 0 && errno
== EPERM
);
918 assert_se(fchmodat(AT_FDCWD
, path
, 0755 | S_ISGID
| S_ISUID
, 0) < 0 && errno
== EPERM
);
919 assert_se(fchmodat(AT_FDCWD
, path
, 0755, 0) >= 0);
921 assert_se(real_open(z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644 | S_ISUID
) < 0 && errno
== EPERM
);
922 assert_se(real_open(z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644 | S_ISGID
) < 0 && errno
== EPERM
);
923 assert_se(real_open(z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644 | S_ISUID
| S_ISGID
) < 0 && errno
== EPERM
);
924 k
= real_open(z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644);
926 assert_se(unlink(z
) >= 0);
928 assert_se(creat(z
, 0644 | S_ISUID
) < 0 && errno
== EPERM
);
929 assert_se(creat(z
, 0644 | S_ISGID
) < 0 && errno
== EPERM
);
930 assert_se(creat(z
, 0644 | S_ISUID
| S_ISGID
) < 0 && errno
== EPERM
);
933 assert_se(unlink(z
) >= 0);
935 assert_se(openat(AT_FDCWD
, z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644 | S_ISUID
) < 0 && errno
== EPERM
);
936 assert_se(openat(AT_FDCWD
, z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644 | S_ISGID
) < 0 && errno
== EPERM
);
937 assert_se(openat(AT_FDCWD
, z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644 | S_ISUID
| S_ISGID
) < 0 && errno
== EPERM
);
938 k
= openat(AT_FDCWD
, z
, O_CREAT
|O_RDWR
|O_CLOEXEC
|O_EXCL
, 0644);
940 assert_se(unlink(z
) >= 0);
942 assert_se(mkdir(z
, 0755 | S_ISUID
) < 0 && errno
== EPERM
);
943 assert_se(mkdir(z
, 0755 | S_ISGID
) < 0 && errno
== EPERM
);
944 assert_se(mkdir(z
, 0755 | S_ISUID
| S_ISGID
) < 0 && errno
== EPERM
);
945 assert_se(mkdir(z
, 0755) >= 0);
946 assert_se(rmdir(z
) >= 0);
948 assert_se(mkdirat(AT_FDCWD
, z
, 0755 | S_ISUID
) < 0 && errno
== EPERM
);
949 assert_se(mkdirat(AT_FDCWD
, z
, 0755 | S_ISGID
) < 0 && errno
== EPERM
);
950 assert_se(mkdirat(AT_FDCWD
, z
, 0755 | S_ISUID
| S_ISGID
) < 0 && errno
== EPERM
);
951 assert_se(mkdirat(AT_FDCWD
, z
, 0755) >= 0);
952 assert_se(rmdir(z
) >= 0);
954 assert_se(mknod(z
, S_IFREG
| 0755 | S_ISUID
, 0) < 0 && errno
== EPERM
);
955 assert_se(mknod(z
, S_IFREG
| 0755 | S_ISGID
, 0) < 0 && errno
== EPERM
);
956 assert_se(mknod(z
, S_IFREG
| 0755 | S_ISUID
| S_ISGID
, 0) < 0 && errno
== EPERM
);
957 assert_se(mknod(z
, S_IFREG
| 0755, 0) >= 0);
958 assert_se(unlink(z
) >= 0);
960 assert_se(mknodat(AT_FDCWD
, z
, S_IFREG
| 0755 | S_ISUID
, 0) < 0 && errno
== EPERM
);
961 assert_se(mknodat(AT_FDCWD
, z
, S_IFREG
| 0755 | S_ISGID
, 0) < 0 && errno
== EPERM
);
962 assert_se(mknodat(AT_FDCWD
, z
, S_IFREG
| 0755 | S_ISUID
| S_ISGID
, 0) < 0 && errno
== EPERM
);
963 assert_se(mknodat(AT_FDCWD
, z
, S_IFREG
| 0755, 0) >= 0);
964 assert_se(unlink(z
) >= 0);
966 assert_se(unlink(path
) >= 0);
967 assert_se(rm_rf(dir
, REMOVE_ROOT
|REMOVE_PHYSICAL
) >= 0);
972 assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid
, WAIT_LOG
) == EXIT_SUCCESS
);
975 int main(int argc
, char *argv
[]) {
976 test_setup_logging(LOG_DEBUG
);
978 test_seccomp_arch_to_string();
979 test_architecture_table();
980 test_syscall_filter_set_find();
982 test_filter_sets_ordered();
983 test_restrict_namespace();
984 test_protect_sysctl();
985 test_restrict_address_families();
986 test_restrict_realtime();
987 test_memory_deny_write_execute_mmap();
988 test_memory_deny_write_execute_shmat();
989 test_restrict_archs();
990 test_load_syscall_filter_set_raw();
991 test_lock_personality();
992 test_restrict_suid_sgid();