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 SECCOMP_RESTRICT_NAMESPACES_BROKEN == 0
163 if (!is_seccomp_available())
173 assert_se(seccomp_restrict_namespaces(CLONE_NEWNS
|CLONE_NEWNET
) >= 0);
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
);
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
);
199 pid
= raw_clone(CLONE_NEWNS
);
203 pid
= raw_clone(CLONE_NEWNET
);
207 pid
= raw_clone(CLONE_NEWUTS
);
209 assert_se(errno
== EPERM
);
210 pid
= raw_clone(CLONE_NEWIPC
);
212 assert_se(errno
== EPERM
);
213 pid
= raw_clone(CLONE_NEWNET
|CLONE_NEWUTS
);
215 assert_se(errno
== EPERM
);
220 assert_se(wait_for_terminate_and_warn("nsseccomp", pid
, true) == EXIT_SUCCESS
);
224 static void test_protect_sysctl(void) {
227 if (!is_seccomp_available())
232 if (detect_container() > 0) /* in containers _sysctl() is likely missing anyway */
239 assert_se(syscall(__NR__sysctl
, NULL
) < 0);
240 assert_se(errno
== EFAULT
);
242 assert_se(seccomp_protect_sysctl() >= 0);
244 assert_se(syscall(__NR__sysctl
, 0, 0, 0) < 0);
245 assert_se(errno
== EPERM
);
250 assert_se(wait_for_terminate_and_warn("sysctlseccomp", pid
, true) == EXIT_SUCCESS
);
253 static void test_restrict_address_families(void) {
256 if (!is_seccomp_available())
268 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
272 fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
276 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, 0);
280 assert_se(s
= set_new(NULL
));
281 assert_se(set_put(s
, INT_TO_PTR(AF_UNIX
)) >= 0);
283 assert_se(seccomp_restrict_address_families(s
, false) >= 0);
285 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
289 #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
290 fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
294 assert_se(socket(AF_UNIX
, SOCK_DGRAM
, 0) < 0);
295 assert_se(errno
== EAFNOSUPPORT
);
298 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, 0);
304 assert_se(set_put(s
, INT_TO_PTR(AF_INET
)) >= 0);
306 assert_se(seccomp_restrict_address_families(s
, true) >= 0);
308 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
312 #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
313 fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
317 fd
= socket(AF_NETLINK
, SOCK_DGRAM
, 0);
321 assert_se(socket(AF_UNIX
, SOCK_DGRAM
, 0) < 0);
322 assert_se(errno
== EAFNOSUPPORT
);
324 assert_se(socket(AF_NETLINK
, SOCK_DGRAM
, 0) < 0);
325 assert_se(errno
== EAFNOSUPPORT
);
331 assert_se(wait_for_terminate_and_warn("socketseccomp", pid
, true) == EXIT_SUCCESS
);
334 static void test_restrict_realtime(void) {
337 if (!is_seccomp_available())
342 if (detect_container() > 0) /* in containers RT privs are likely missing anyway */
349 assert_se(sched_setscheduler(0, SCHED_FIFO
, &(struct sched_param
) { .sched_priority
= 1 }) >= 0);
350 assert_se(sched_setscheduler(0, SCHED_RR
, &(struct sched_param
) { .sched_priority
= 1 }) >= 0);
351 assert_se(sched_setscheduler(0, SCHED_IDLE
, &(struct sched_param
) { .sched_priority
= 0 }) >= 0);
352 assert_se(sched_setscheduler(0, SCHED_BATCH
, &(struct sched_param
) { .sched_priority
= 0 }) >= 0);
353 assert_se(sched_setscheduler(0, SCHED_OTHER
, &(struct sched_param
) {}) >= 0);
355 assert_se(seccomp_restrict_realtime() >= 0);
357 assert_se(sched_setscheduler(0, SCHED_IDLE
, &(struct sched_param
) { .sched_priority
= 0 }) >= 0);
358 assert_se(sched_setscheduler(0, SCHED_BATCH
, &(struct sched_param
) { .sched_priority
= 0 }) >= 0);
359 assert_se(sched_setscheduler(0, SCHED_OTHER
, &(struct sched_param
) {}) >= 0);
361 assert_se(sched_setscheduler(0, SCHED_FIFO
, &(struct sched_param
) { .sched_priority
= 1 }) < 0);
362 assert_se(errno
== EPERM
);
363 assert_se(sched_setscheduler(0, SCHED_RR
, &(struct sched_param
) { .sched_priority
= 1 }) < 0);
364 assert_se(errno
== EPERM
);
369 assert_se(wait_for_terminate_and_warn("realtimeseccomp", pid
, true) == EXIT_SUCCESS
);
372 static void test_memory_deny_write_execute(void) {
375 if (!is_seccomp_available())
386 p
= mmap(NULL
, page_size(), PROT_WRITE
|PROT_EXEC
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1,0);
387 assert_se(p
!= MAP_FAILED
);
388 assert_se(munmap(p
, page_size()) >= 0);
390 p
= mmap(NULL
, page_size(), PROT_WRITE
|PROT_READ
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1,0);
391 assert_se(p
!= MAP_FAILED
);
392 assert_se(munmap(p
, page_size()) >= 0);
394 assert_se(seccomp_memory_deny_write_execute() >= 0);
396 #if SECCOMP_MEMORY_DENY_WRITE_EXECUTE_BROKEN
397 p
= mmap(NULL
, page_size(), PROT_WRITE
|PROT_EXEC
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1,0);
398 assert_se(p
!= MAP_FAILED
);
399 assert_se(munmap(p
, page_size()) >= 0);
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(errno
== EPERM
);
406 p
= mmap(NULL
, page_size(), PROT_WRITE
|PROT_READ
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1,0);
407 assert_se(p
!= MAP_FAILED
);
408 assert_se(munmap(p
, page_size()) >= 0);
413 assert_se(wait_for_terminate_and_warn("memoryseccomp", pid
, true) == EXIT_SUCCESS
);
416 static void test_restrict_archs(void) {
419 if (!is_seccomp_available())
428 _cleanup_set_free_ Set
*s
= NULL
;
430 assert_se(access("/", F_OK
) >= 0);
432 assert_se(s
= set_new(NULL
));
435 assert_se(set_put(s
, UINT32_TO_PTR(SCMP_ARCH_X86
+1)) >= 0);
437 assert_se(seccomp_restrict_archs(s
) >= 0);
439 assert_se(access("/", F_OK
) >= 0);
440 assert_se(seccomp_restrict_archs(NULL
) >= 0);
442 assert_se(access("/", F_OK
) >= 0);
447 assert_se(wait_for_terminate_and_warn("archseccomp", pid
, true) == EXIT_SUCCESS
);
450 static void test_load_syscall_filter_set_raw(void) {
453 if (!is_seccomp_available())
462 _cleanup_set_free_ Set
*s
= NULL
;
464 assert_se(access("/", F_OK
) >= 0);
465 assert_se(poll(NULL
, 0, 0) == 0);
467 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW
, NULL
, SCMP_ACT_KILL
) >= 0);
468 assert_se(access("/", F_OK
) >= 0);
469 assert_se(poll(NULL
, 0, 0) == 0);
471 assert_se(s
= set_new(NULL
));
472 assert_se(set_put(s
, UINT32_TO_PTR(__NR_access
+ 1)) >= 0);
474 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW
, s
, SCMP_ACT_ERRNO(EUCLEAN
)) >= 0);
476 assert_se(access("/", F_OK
) < 0);
477 assert_se(errno
== EUCLEAN
);
479 assert_se(poll(NULL
, 0, 0) == 0);
483 assert_se(s
= set_new(NULL
));
484 assert_se(set_put(s
, UINT32_TO_PTR(__NR_poll
+ 1)) >= 0);
486 assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW
, s
, SCMP_ACT_ERRNO(EUNATCH
)) >= 0);
488 assert_se(access("/", F_OK
) < 0);
489 assert_se(errno
== EUCLEAN
);
491 assert_se(poll(NULL
, 0, 0) < 0);
492 assert_se(errno
== EUNATCH
);
497 assert_se(wait_for_terminate_and_warn("syscallrawseccomp", pid
, true) == EXIT_SUCCESS
);
500 int main(int argc
, char *argv
[]) {
502 log_set_max_level(LOG_DEBUG
);
504 test_seccomp_arch_to_string();
505 test_architecture_table();
506 test_syscall_filter_set_find();
508 test_restrict_namespace();
509 test_protect_sysctl();
510 test_restrict_address_families();
511 test_restrict_realtime();
512 test_memory_deny_write_execute();
513 test_restrict_archs();
514 test_load_syscall_filter_set_raw();