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/>.
21 #include <sys/eventfd.h>
25 #include "alloc-util.h"
30 #include "process-util.h"
31 #include "raw-clone.h"
32 #include "seccomp-util.h"
33 #include "string-util.h"
36 static void test_seccomp_arch_to_string(void) {
40 a
= seccomp_arch_native();
42 name
= seccomp_arch_to_string(a
);
44 assert_se(seccomp_arch_from_string(name
, &b
) >= 0);
48 static void test_architecture_table(void) {
71 assert_se(seccomp_arch_from_string(n
, &c
) >= 0);
72 n2
= seccomp_arch_to_string(c
);
73 log_info("seccomp-arch: %s → 0x%"PRIx32
" → %s", n
, c
, n2
);
74 assert_se(streq_ptr(n
, n2
));
78 static void test_syscall_filter_set_find(void) {
79 assert_se(!syscall_filter_set_find(NULL
));
80 assert_se(!syscall_filter_set_find(""));
81 assert_se(!syscall_filter_set_find("quux"));
82 assert_se(!syscall_filter_set_find("@quux"));
84 assert_se(syscall_filter_set_find("@clock") == syscall_filter_sets
+ SYSCALL_FILTER_SET_CLOCK
);
85 assert_se(syscall_filter_set_find("@default") == syscall_filter_sets
+ SYSCALL_FILTER_SET_DEFAULT
);
86 assert_se(syscall_filter_set_find("@raw-io") == syscall_filter_sets
+ SYSCALL_FILTER_SET_RAW_IO
);
89 static void test_filter_sets(void) {
93 if (!is_seccomp_available())
99 for (i
= 0; i
< _SYSCALL_FILTER_SET_MAX
; i
++) {
102 log_info("Testing %s", syscall_filter_sets
[i
].name
);
107 if (pid
== 0) { /* Child? */
110 if (i
== SYSCALL_FILTER_SET_DEFAULT
) /* if we look at the default set, whitelist instead of blacklist */
111 r
= seccomp_load_filter_set(SCMP_ACT_ERRNO(EPERM
), syscall_filter_sets
+ i
, SCMP_ACT_ALLOW
);
113 r
= seccomp_load_filter_set(SCMP_ACT_ALLOW
, syscall_filter_sets
+ i
, SCMP_ACT_ERRNO(EPERM
));
117 /* Test the sycall filter with one random system call */
118 fd
= eventfd(0, EFD_NONBLOCK
|EFD_CLOEXEC
);
119 if (IN_SET(i
, SYSCALL_FILTER_SET_IO_EVENT
, SYSCALL_FILTER_SET_DEFAULT
))
120 assert_se(fd
< 0 && errno
== EPERM
);
129 assert_se(wait_for_terminate_and_warn(syscall_filter_sets
[i
].name
, pid
, true) == EXIT_SUCCESS
);
133 static void test_restrict_namespace(void) {
134 _cleanup_free_
char *s
= NULL
;
138 assert_se(namespace_flag_to_string(0) == NULL
);
139 assert_se(streq(namespace_flag_to_string(CLONE_NEWNS
), "mnt"));
140 assert_se(namespace_flag_to_string(CLONE_NEWNS
|CLONE_NEWIPC
) == NULL
);
141 assert_se(streq(namespace_flag_to_string(CLONE_NEWCGROUP
), "cgroup"));
143 assert_se(namespace_flag_from_string("mnt") == CLONE_NEWNS
);
144 assert_se(namespace_flag_from_string(NULL
) == 0);
145 assert_se(namespace_flag_from_string("") == 0);
146 assert_se(namespace_flag_from_string("uts") == CLONE_NEWUTS
);
147 assert_se(namespace_flag_from_string(namespace_flag_to_string(CLONE_NEWUTS
)) == CLONE_NEWUTS
);
148 assert_se(streq(namespace_flag_to_string(namespace_flag_from_string("ipc")), "ipc"));
150 assert_se(namespace_flag_from_string_many(NULL
, &ul
) == 0 && ul
== 0);
151 assert_se(namespace_flag_from_string_many("", &ul
) == 0 && ul
== 0);
152 assert_se(namespace_flag_from_string_many("mnt uts ipc", &ul
) == 0 && ul
== (CLONE_NEWNS
|CLONE_NEWUTS
|CLONE_NEWIPC
));
154 assert_se(namespace_flag_to_string_many(NAMESPACE_FLAGS_ALL
, &s
) == 0);
155 assert_se(streq(s
, "cgroup ipc net mnt pid user uts"));
156 assert_se(namespace_flag_from_string_many(s
, &ul
) == 0 && ul
== NAMESPACE_FLAGS_ALL
);
158 if (!is_seccomp_available())
169 assert_se(seccomp_restrict_namespaces(CLONE_NEWNS
|CLONE_NEWNET
) >= 0);
171 assert_se(unshare(CLONE_NEWNS
) == 0);
172 assert_se(unshare(CLONE_NEWNET
) == 0);
173 assert_se(unshare(CLONE_NEWUTS
) == -1);
174 assert_se(errno
== EPERM
);
175 assert_se(unshare(CLONE_NEWIPC
) == -1);
176 assert_se(errno
== EPERM
);
177 assert_se(unshare(CLONE_NEWNET
|CLONE_NEWUTS
) == -1);
178 assert_se(errno
== EPERM
);
180 /* We use fd 0 (stdin) here, which of course will fail with EINVAL on setns(). Except of course our
181 * seccomp filter worked, and hits first and makes it return EPERM */
182 assert_se(setns(0, CLONE_NEWNS
) == -1);
183 assert_se(errno
== EINVAL
);
184 assert_se(setns(0, CLONE_NEWNET
) == -1);
185 assert_se(errno
== EINVAL
);
186 assert_se(setns(0, CLONE_NEWUTS
) == -1);
187 assert_se(errno
== EPERM
);
188 assert_se(setns(0, CLONE_NEWIPC
) == -1);
189 assert_se(errno
== EPERM
);
190 assert_se(setns(0, CLONE_NEWNET
|CLONE_NEWUTS
) == -1);
191 assert_se(errno
== EPERM
);
192 assert_se(setns(0, 0) == -1);
193 assert_se(errno
== EPERM
);
195 pid
= raw_clone(CLONE_NEWNS
);
199 pid
= raw_clone(CLONE_NEWNET
);
203 pid
= raw_clone(CLONE_NEWUTS
);
205 assert_se(errno
== EPERM
);
206 pid
= raw_clone(CLONE_NEWIPC
);
208 assert_se(errno
== EPERM
);
209 pid
= raw_clone(CLONE_NEWNET
|CLONE_NEWUTS
);
211 assert_se(errno
== EPERM
);
216 assert_se(wait_for_terminate_and_warn("nsseccomp", pid
, true) == EXIT_SUCCESS
);
219 int main(int argc
, char *argv
[]) {
221 log_set_max_level(LOG_DEBUG
);
223 test_seccomp_arch_to_string();
224 test_architecture_table();
225 test_syscall_filter_set_find();
227 test_restrict_namespace();