2 This file is part of systemd.
4 Copyright 2016 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/eventfd.h>
27 #include "alloc-util.h"
32 #include "process-util.h"
33 #include "raw-clone.h"
34 #include "seccomp-util.h"
36 #include "string-util.h"
40 static void test_seccomp_arch_to_string(void) {
44 a
= seccomp_arch_native();
46 name
= seccomp_arch_to_string(a
);
48 assert_se(seccomp_arch_from_string(name
, &b
) >= 0);
52 static void test_architecture_table(void) {
75 assert_se(seccomp_arch_from_string(n
, &c
) >= 0);
76 n2
= seccomp_arch_to_string(c
);
77 log_info("seccomp-arch: %s → 0x%"PRIx32
" → %s", n
, c
, n2
);
78 assert_se(streq_ptr(n
, n2
));
82 static void test_syscall_filter_set_find(void) {
83 assert_se(!syscall_filter_set_find(NULL
));
84 assert_se(!syscall_filter_set_find(""));
85 assert_se(!syscall_filter_set_find("quux"));
86 assert_se(!syscall_filter_set_find("@quux"));
88 assert_se(syscall_filter_set_find("@clock") == syscall_filter_sets
+ SYSCALL_FILTER_SET_CLOCK
);
89 assert_se(syscall_filter_set_find("@default") == syscall_filter_sets
+ SYSCALL_FILTER_SET_DEFAULT
);
90 assert_se(syscall_filter_set_find("@raw-io") == syscall_filter_sets
+ SYSCALL_FILTER_SET_RAW_IO
);
93 static void test_filter_sets(void) {
97 if (!is_seccomp_available())
102 for (i
= 0; i
< _SYSCALL_FILTER_SET_MAX
; i
++) {
105 log_info("Testing %s", syscall_filter_sets
[i
].name
);
110 if (pid
== 0) { /* Child? */
113 if (i
== SYSCALL_FILTER_SET_DEFAULT
) /* if we look at the default set, whitelist instead of blacklist */
114 r
= seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN
), syscall_filter_sets
+ i
, SCMP_ACT_ALLOW
);
116 r
= seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW
, syscall_filter_sets
+ i
, SCMP_ACT_ERRNO(EUCLEAN
));
120 /* Test the sycall filter with one random system call */
121 fd
= eventfd(0, EFD_NONBLOCK
|EFD_CLOEXEC
);
122 if (IN_SET(i
, SYSCALL_FILTER_SET_IO_EVENT
, SYSCALL_FILTER_SET_DEFAULT
))
123 assert_se(fd
< 0 && errno
== EUCLEAN
);
132 assert_se(wait_for_terminate_and_warn(syscall_filter_sets
[i
].name
, pid
, true) == EXIT_SUCCESS
);
136 static void test_restrict_namespace(void) {
137 _cleanup_free_
char *s
= NULL
;
141 assert_se(namespace_flag_to_string(0) == NULL
);
142 assert_se(streq(namespace_flag_to_string(CLONE_NEWNS
), "mnt"));
143 assert_se(namespace_flag_to_string(CLONE_NEWNS
|CLONE_NEWIPC
) == NULL
);
144 assert_se(streq(namespace_flag_to_string(CLONE_NEWCGROUP
), "cgroup"));
146 assert_se(namespace_flag_from_string("mnt") == CLONE_NEWNS
);
147 assert_se(namespace_flag_from_string(NULL
) == 0);
148 assert_se(namespace_flag_from_string("") == 0);
149 assert_se(namespace_flag_from_string("uts") == CLONE_NEWUTS
);
150 assert_se(namespace_flag_from_string(namespace_flag_to_string(CLONE_NEWUTS
)) == CLONE_NEWUTS
);
151 assert_se(streq(namespace_flag_to_string(namespace_flag_from_string("ipc")), "ipc"));
153 assert_se(namespace_flag_from_string_many(NULL
, &ul
) == 0 && ul
== 0);
154 assert_se(namespace_flag_from_string_many("", &ul
) == 0 && ul
== 0);
155 assert_se(namespace_flag_from_string_many("mnt uts ipc", &ul
) == 0 && ul
== (CLONE_NEWNS
|CLONE_NEWUTS
|CLONE_NEWIPC
));
157 assert_se(namespace_flag_to_string_many(NAMESPACE_FLAGS_ALL
, &s
) == 0);
158 assert_se(streq(s
, "cgroup ipc net mnt pid user uts"));
159 assert_se(namespace_flag_from_string_many(s
, &ul
) == 0 && ul
== NAMESPACE_FLAGS_ALL
);
161 if (!is_seccomp_available())
171 assert_se(seccomp_restrict_namespaces(CLONE_NEWNS
|CLONE_NEWNET
) >= 0);
173 assert_se(unshare(CLONE_NEWNS
) == 0);
174 assert_se(unshare(CLONE_NEWNET
) == 0);
175 assert_se(unshare(CLONE_NEWUTS
) == -1);
176 assert_se(errno
== EPERM
);
177 assert_se(unshare(CLONE_NEWIPC
) == -1);
178 assert_se(errno
== EPERM
);
179 assert_se(unshare(CLONE_NEWNET
|CLONE_NEWUTS
) == -1);
180 assert_se(errno
== EPERM
);
182 /* We use fd 0 (stdin) here, which of course will fail with EINVAL on setns(). Except of course our
183 * seccomp filter worked, and hits first and makes it return EPERM */
184 assert_se(setns(0, CLONE_NEWNS
) == -1);
185 assert_se(errno
== EINVAL
);
186 assert_se(setns(0, CLONE_NEWNET
) == -1);
187 assert_se(errno
== EINVAL
);
188 assert_se(setns(0, CLONE_NEWUTS
) == -1);
189 assert_se(errno
== EPERM
);
190 assert_se(setns(0, CLONE_NEWIPC
) == -1);
191 assert_se(errno
== EPERM
);
192 assert_se(setns(0, CLONE_NEWNET
|CLONE_NEWUTS
) == -1);
193 assert_se(errno
== EPERM
);
194 assert_se(setns(0, 0) == -1);
195 assert_se(errno
== EPERM
);
197 pid
= raw_clone(CLONE_NEWNS
);
201 pid
= raw_clone(CLONE_NEWNET
);
205 pid
= raw_clone(CLONE_NEWUTS
);
207 assert_se(errno
== EPERM
);
208 pid
= raw_clone(CLONE_NEWIPC
);
210 assert_se(errno
== EPERM
);
211 pid
= raw_clone(CLONE_NEWNET
|CLONE_NEWUTS
);
213 assert_se(errno
== EPERM
);
218 assert_se(wait_for_terminate_and_warn("nsseccomp", pid
, true) == EXIT_SUCCESS
);
221 static void test_protect_sysctl(void) {
224 if (!is_seccomp_available())
229 if (detect_container() > 0) /* in containers _sysctl() is likely missing anyway */
236 assert_se(syscall(__NR__sysctl
, NULL
) < 0);
237 assert_se(errno
== EFAULT
);
239 assert_se(seccomp_protect_sysctl() >= 0);
241 assert_se(syscall(__NR__sysctl
, 0, 0, 0) < 0);
242 assert_se(errno
== EPERM
);
247 assert_se(wait_for_terminate_and_warn("sysctlseccomp", pid
, true) == EXIT_SUCCESS
);
250 static void test_restrict_address_families(void) {
253 if (!is_seccomp_available())
265 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
269 fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
273 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, 0);
277 assert_se(s
= set_new(NULL
));
278 assert_se(set_put(s
, INT_TO_PTR(AF_UNIX
)) >= 0);
280 assert_se(seccomp_restrict_address_families(s
, false) >= 0);
282 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
286 #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
287 fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
291 assert_se(socket(AF_UNIX
, SOCK_DGRAM
, 0) < 0);
292 assert_se(errno
== EAFNOSUPPORT
);
295 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, 0);
301 assert_se(set_put(s
, INT_TO_PTR(AF_INET
)) >= 0);
303 assert_se(seccomp_restrict_address_families(s
, true) >= 0);
305 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
309 #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
310 fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
314 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, 0);
318 assert_se(socket(AF_UNIX
, SOCK_DGRAM
, 0) < 0);
319 assert_se(errno
== EAFNOSUPPORT
);
321 assert_se(socket(AF_NETLINK
, SOCK_DGRAM
, 0) < 0);
322 assert_se(errno
== EAFNOSUPPORT
);
328 assert_se(wait_for_terminate_and_warn("socketseccomp", pid
, true) == EXIT_SUCCESS
);
331 static void test_restrict_realtime(void) {
334 if (!is_seccomp_available())
339 if (detect_container() > 0) /* in containers RT privs are likely missing anyway */
346 assert_se(sched_setscheduler(0, SCHED_FIFO
, &(struct sched_param
) { .sched_priority
= 1 }) >= 0);
347 assert_se(sched_setscheduler(0, SCHED_RR
, &(struct sched_param
) { .sched_priority
= 1 }) >= 0);
348 assert_se(sched_setscheduler(0, SCHED_IDLE
, &(struct sched_param
) { .sched_priority
= 0 }) >= 0);
349 assert_se(sched_setscheduler(0, SCHED_BATCH
, &(struct sched_param
) { .sched_priority
= 0 }) >= 0);
350 assert_se(sched_setscheduler(0, SCHED_OTHER
, &(struct sched_param
) {}) >= 0);
352 assert_se(seccomp_restrict_realtime() >= 0);
354 assert_se(sched_setscheduler(0, SCHED_IDLE
, &(struct sched_param
) { .sched_priority
= 0 }) >= 0);
355 assert_se(sched_setscheduler(0, SCHED_BATCH
, &(struct sched_param
) { .sched_priority
= 0 }) >= 0);
356 assert_se(sched_setscheduler(0, SCHED_OTHER
, &(struct sched_param
) {}) >= 0);
358 assert_se(sched_setscheduler(0, SCHED_FIFO
, &(struct sched_param
) { .sched_priority
= 1 }) < 0);
359 assert_se(errno
== EPERM
);
360 assert_se(sched_setscheduler(0, SCHED_RR
, &(struct sched_param
) { .sched_priority
= 1 }) < 0);
361 assert_se(errno
== EPERM
);
366 assert_se(wait_for_terminate_and_warn("realtimeseccomp", pid
, true) == EXIT_SUCCESS
);
369 static void test_memory_deny_write_execute(void) {
372 if (!is_seccomp_available())
383 p
= mmap(NULL
, page_size(), PROT_WRITE
|PROT_EXEC
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1,0);
384 assert_se(p
!= MAP_FAILED
);
385 assert_se(munmap(p
, page_size()) >= 0);
387 seccomp_memory_deny_write_execute();
389 p
= mmap(NULL
, page_size(), PROT_WRITE
|PROT_EXEC
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1,0);
390 assert_se(p
== MAP_FAILED
);
391 assert_se(errno
== EPERM
);
393 p
= mmap(NULL
, page_size(), PROT_WRITE
|PROT_READ
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1,0);
394 assert_se(p
!= MAP_FAILED
);
395 assert_se(munmap(p
, page_size()) >= 0);
400 assert_se(wait_for_terminate_and_warn("memoryseccomp", pid
, true) == EXIT_SUCCESS
);
403 static void test_restrict_archs(void) {
406 if (!is_seccomp_available())
415 _cleanup_set_free_ Set
*s
= NULL
;
417 assert_se(access("/", F_OK
) >= 0);
419 assert_se(s
= set_new(NULL
));
422 assert_se(set_put(s
, UINT32_TO_PTR(SCMP_ARCH_X86
+1)) >= 0);
424 assert_se(seccomp_restrict_archs(s
) >= 0);
426 assert_se(access("/", F_OK
) >= 0);
427 assert_se(seccomp_restrict_archs(NULL
) >= 0);
429 assert_se(access("/", F_OK
) >= 0);
434 assert_se(wait_for_terminate_and_warn("archseccomp", pid
, true) == EXIT_SUCCESS
);
437 static void test_load_syscall_filter_set_raw(void) {
440 if (!is_seccomp_available())
449 _cleanup_set_free_ Set
*s
= NULL
;
451 assert_se(access("/", F_OK
) >= 0);
452 assert_se(poll(NULL
, 0, 0) == 0);
454 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW
, NULL
, SCMP_ACT_KILL
) >= 0);
455 assert_se(access("/", F_OK
) >= 0);
456 assert_se(poll(NULL
, 0, 0) == 0);
458 assert_se(s
= set_new(NULL
));
459 assert_se(set_put(s
, UINT32_TO_PTR(__NR_access
+ 1)) >= 0);
461 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW
, s
, SCMP_ACT_ERRNO(EUCLEAN
)) >= 0);
463 assert_se(access("/", F_OK
) < 0);
464 assert_se(errno
== EUCLEAN
);
466 assert_se(poll(NULL
, 0, 0) == 0);
470 assert_se(s
= set_new(NULL
));
471 assert_se(set_put(s
, UINT32_TO_PTR(__NR_poll
+ 1)) >= 0);
473 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW
, s
, SCMP_ACT_ERRNO(EUNATCH
)) >= 0);
475 assert_se(access("/", F_OK
) < 0);
476 assert_se(errno
== EUCLEAN
);
478 assert_se(poll(NULL
, 0, 0) < 0);
479 assert_se(errno
== EUNATCH
);
484 assert_se(wait_for_terminate_and_warn("syscallrawseccomp", pid
, true) == EXIT_SUCCESS
);
487 int main(int argc
, char *argv
[]) {
489 log_set_max_level(LOG_DEBUG
);
491 test_seccomp_arch_to_string();
492 test_architecture_table();
493 test_syscall_filter_set_find();
495 test_restrict_namespace();
496 test_protect_sysctl();
497 test_restrict_address_families();
498 test_restrict_realtime();
499 test_memory_deny_write_execute();
500 test_restrict_archs();
501 test_load_syscall_filter_set_raw();