]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
f6281133 | 2 | |
f5947a5e | 3 | #include <fcntl.h> |
d7e454ba | 4 | #include <poll.h> |
f6281133 LP |
5 | #include <stdlib.h> |
6 | #include <sys/eventfd.h> | |
469830d1 | 7 | #include <sys/mman.h> |
78e864e5 | 8 | #include <sys/personality.h> |
2a65bd94 | 9 | #include <sys/shm.h> |
dff6c629 | 10 | #include <sys/syscall.h> |
2a65bd94 ZJS |
11 | #include <sys/types.h> |
12 | #include <unistd.h> | |
866f698b YW |
13 | #if HAVE_VALGRIND_VALGRIND_H |
14 | #include <valgrind/valgrind.h> | |
15 | #endif | |
f6281133 | 16 | |
add00535 | 17 | #include "alloc-util.h" |
6da5d7de | 18 | #include "capability-util.h" |
f6281133 | 19 | #include "fd-util.h" |
3c14dc61 | 20 | #include "fileio.h" |
f6281133 | 21 | #include "macro.h" |
0a970718 | 22 | #include "memory-util.h" |
f5947a5e | 23 | #include "missing_sched.h" |
c21566d9 | 24 | #include "missing_syscall.h" |
add00535 | 25 | #include "nsflags.h" |
d8b4d14d | 26 | #include "nulstr-util.h" |
f6281133 | 27 | #include "process-util.h" |
add00535 | 28 | #include "raw-clone.h" |
167fc10c | 29 | #include "rm-rf.h" |
f6281133 | 30 | #include "seccomp-util.h" |
469830d1 | 31 | #include "set.h" |
aa34055f | 32 | #include "string-util.h" |
6d7c4033 | 33 | #include "tests.h" |
167fc10c | 34 | #include "tmpfile-util.h" |
469830d1 | 35 | #include "virt.h" |
f6281133 | 36 | |
4df8fe84 | 37 | /* __NR_socket may be invalid due to libseccomp */ |
d5923e38 | 38 | #if !defined(__NR_socket) || __NR_socket < 0 || defined(__i386__) || defined(__s390x__) || defined(__s390__) || defined(__powerpc64__) || defined(__powerpc__) |
da1921a5 ZJS |
39 | /* On these archs, socket() is implemented via the socketcall() syscall multiplexer, |
40 | * and we can't restrict it hence via seccomp. */ | |
41 | # define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 1 | |
42 | #else | |
43 | # define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 0 | |
44 | #endif | |
45 | ||
6da5d7de LP |
46 | static bool have_seccomp_privs(void) { |
47 | return geteuid() == 0 && have_effective_cap(CAP_SYS_ADMIN) > 0; /* If we are root but CAP_SYS_ADMIN we can't do caps (unless we also do NNP) */ | |
48 | } | |
49 | ||
4f7452a8 | 50 | TEST(parse_syscall_and_errno) { |
17884f97 YW |
51 | _cleanup_free_ char *n = NULL; |
52 | int e; | |
53 | ||
54 | assert_se(parse_syscall_and_errno("uname:EILSEQ", &n, &e) >= 0); | |
c79e88b3 | 55 | ASSERT_STREQ(n, "uname"); |
17884f97 YW |
56 | assert_se(e == errno_from_name("EILSEQ") && e >= 0); |
57 | n = mfree(n); | |
58 | ||
59 | assert_se(parse_syscall_and_errno("uname:EINVAL", &n, &e) >= 0); | |
c79e88b3 | 60 | ASSERT_STREQ(n, "uname"); |
17884f97 YW |
61 | assert_se(e == errno_from_name("EINVAL") && e >= 0); |
62 | n = mfree(n); | |
63 | ||
64 | assert_se(parse_syscall_and_errno("@sync:4095", &n, &e) >= 0); | |
c79e88b3 | 65 | ASSERT_STREQ(n, "@sync"); |
17884f97 YW |
66 | assert_se(e == 4095); |
67 | n = mfree(n); | |
68 | ||
69 | /* If errno is omitted, then e is set to -1 */ | |
70 | assert_se(parse_syscall_and_errno("mount", &n, &e) >= 0); | |
c79e88b3 | 71 | ASSERT_STREQ(n, "mount"); |
17884f97 YW |
72 | assert_se(e == -1); |
73 | n = mfree(n); | |
74 | ||
75 | /* parse_syscall_and_errno() does not check the syscall name is valid or not. */ | |
76 | assert_se(parse_syscall_and_errno("hoge:255", &n, &e) >= 0); | |
c79e88b3 | 77 | ASSERT_STREQ(n, "hoge"); |
17884f97 YW |
78 | assert_se(e == 255); |
79 | n = mfree(n); | |
80 | ||
335171ca YW |
81 | /* 0 is also a valid errno. */ |
82 | assert_se(parse_syscall_and_errno("hoge:0", &n, &e) >= 0); | |
c79e88b3 | 83 | ASSERT_STREQ(n, "hoge"); |
335171ca YW |
84 | assert_se(e == 0); |
85 | n = mfree(n); | |
86 | ||
17884f97 | 87 | assert_se(parse_syscall_and_errno("hoge:kill", &n, &e) >= 0); |
c79e88b3 | 88 | ASSERT_STREQ(n, "hoge"); |
17884f97 YW |
89 | assert_se(e == SECCOMP_ERROR_NUMBER_KILL); |
90 | n = mfree(n); | |
91 | ||
92 | /* The function checks the syscall name is empty or not. */ | |
93 | assert_se(parse_syscall_and_errno("", &n, &e) == -EINVAL); | |
94 | assert_se(parse_syscall_and_errno(":255", &n, &e) == -EINVAL); | |
95 | ||
96 | /* errno must be a valid errno name or number between 0 and ERRNO_MAX == 4095, or "kill" */ | |
97 | assert_se(parse_syscall_and_errno("hoge:4096", &n, &e) == -ERANGE); | |
98 | assert_se(parse_syscall_and_errno("hoge:-3", &n, &e) == -ERANGE); | |
99 | assert_se(parse_syscall_and_errno("hoge:12.3", &n, &e) == -EINVAL); | |
100 | assert_se(parse_syscall_and_errno("hoge:123junk", &n, &e) == -EINVAL); | |
101 | assert_se(parse_syscall_and_errno("hoge:junk123", &n, &e) == -EINVAL); | |
102 | assert_se(parse_syscall_and_errno("hoge:255:EILSEQ", &n, &e) == -EINVAL); | |
103 | assert_se(parse_syscall_and_errno("hoge:-EINVAL", &n, &e) == -EINVAL); | |
104 | assert_se(parse_syscall_and_errno("hoge:EINVALaaa", &n, &e) == -EINVAL); | |
105 | assert_se(parse_syscall_and_errno("hoge:", &n, &e) == -EINVAL); | |
106 | } | |
107 | ||
4f7452a8 | 108 | TEST(seccomp_arch_to_string) { |
f6281133 LP |
109 | uint32_t a, b; |
110 | const char *name; | |
111 | ||
112 | a = seccomp_arch_native(); | |
113 | assert_se(a > 0); | |
114 | name = seccomp_arch_to_string(a); | |
115 | assert_se(name); | |
116 | assert_se(seccomp_arch_from_string(name, &b) >= 0); | |
117 | assert_se(a == b); | |
118 | } | |
119 | ||
4f7452a8 | 120 | TEST(architecture_table) { |
12e2b70f | 121 | const char *n2; |
aa34055f ZJS |
122 | |
123 | NULSTR_FOREACH(n, | |
124 | "native\0" | |
125 | "x86\0" | |
126 | "x86-64\0" | |
127 | "x32\0" | |
128 | "arm\0" | |
129 | "arm64\0" | |
f9d3fb6b XW |
130 | #ifdef SCMP_ARCH_LOONGARCH64 |
131 | "loongarch64\0" | |
132 | #endif | |
aa34055f ZJS |
133 | "mips\0" |
134 | "mips64\0" | |
135 | "mips64-n32\0" | |
136 | "mips-le\0" | |
137 | "mips64-le\0" | |
138 | "mips64-le-n32\0" | |
344e6b62 SJ |
139 | "parisc\0" |
140 | "parisc64\0" | |
aa34055f ZJS |
141 | "ppc\0" |
142 | "ppc64\0" | |
143 | "ppc64-le\0" | |
f9252236 AJ |
144 | #ifdef SCMP_ARCH_RISCV64 |
145 | "riscv64\0" | |
146 | #endif | |
aa34055f ZJS |
147 | "s390\0" |
148 | "s390x\0") { | |
149 | uint32_t c; | |
150 | ||
151 | assert_se(seccomp_arch_from_string(n, &c) >= 0); | |
152 | n2 = seccomp_arch_to_string(c); | |
153 | log_info("seccomp-arch: %s → 0x%"PRIx32" → %s", n, c, n2); | |
c79e88b3 | 154 | ASSERT_STREQ(n, n2); |
aa34055f ZJS |
155 | } |
156 | } | |
157 | ||
4f7452a8 | 158 | TEST(syscall_filter_set_find) { |
f6281133 LP |
159 | assert_se(!syscall_filter_set_find(NULL)); |
160 | assert_se(!syscall_filter_set_find("")); | |
161 | assert_se(!syscall_filter_set_find("quux")); | |
162 | assert_se(!syscall_filter_set_find("@quux")); | |
163 | ||
164 | assert_se(syscall_filter_set_find("@clock") == syscall_filter_sets + SYSCALL_FILTER_SET_CLOCK); | |
165 | assert_se(syscall_filter_set_find("@default") == syscall_filter_sets + SYSCALL_FILTER_SET_DEFAULT); | |
166 | assert_se(syscall_filter_set_find("@raw-io") == syscall_filter_sets + SYSCALL_FILTER_SET_RAW_IO); | |
167 | } | |
168 | ||
4f7452a8 | 169 | TEST(filter_sets) { |
cd90ec75 YW |
170 | if (!is_seccomp_available()) { |
171 | log_notice("Seccomp not available, skipping %s", __func__); | |
f6281133 | 172 | return; |
cd90ec75 | 173 | } |
6da5d7de LP |
174 | if (!have_seccomp_privs()) { |
175 | log_notice("Not privileged, skipping %s", __func__); | |
f6281133 | 176 | return; |
cd90ec75 | 177 | } |
f6281133 | 178 | |
604b163a | 179 | for (unsigned i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) { |
f6281133 LP |
180 | pid_t pid; |
181 | ||
866f698b YW |
182 | #if HAVE_VALGRIND_VALGRIND_H |
183 | if (RUNNING_ON_VALGRIND && IN_SET(i, SYSCALL_FILTER_SET_DEFAULT, SYSCALL_FILTER_SET_BASIC_IO, SYSCALL_FILTER_SET_SIGNAL)) { | |
184 | /* valgrind at least requires rt_sigprocmask(), read(), write(). */ | |
185 | log_info("Running on valgrind, skipping %s", syscall_filter_sets[i].name); | |
186 | continue; | |
187 | } | |
188 | #endif | |
a0dfd10a YW |
189 | #if HAS_FEATURE_ADDRESS_SANITIZER |
190 | if (IN_SET(i, SYSCALL_FILTER_SET_DEFAULT, SYSCALL_FILTER_SET_BASIC_IO, SYSCALL_FILTER_SET_SIGNAL)) { | |
191 | /* ASAN at least requires sigaltstack(), read(), write(). */ | |
192 | log_info("Running on address sanitizer, skipping %s", syscall_filter_sets[i].name); | |
193 | continue; | |
194 | } | |
195 | #endif | |
866f698b | 196 | |
f6281133 LP |
197 | log_info("Testing %s", syscall_filter_sets[i].name); |
198 | ||
199 | pid = fork(); | |
200 | assert_se(pid >= 0); | |
201 | ||
202 | if (pid == 0) { /* Child? */ | |
604b163a | 203 | int fd, r; |
f6281133 | 204 | |
6b000af4 | 205 | /* If we look at the default set (or one that includes it), allow-list instead of deny-list */ |
95aac012 ZJS |
206 | if (IN_SET(i, SYSCALL_FILTER_SET_DEFAULT, |
207 | SYSCALL_FILTER_SET_SYSTEM_SERVICE, | |
208 | SYSCALL_FILTER_SET_KNOWN)) | |
b54f36c6 | 209 | r = seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN), syscall_filter_sets + i, SCMP_ACT_ALLOW, true); |
f6281133 | 210 | else |
b54f36c6 | 211 | r = seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + i, SCMP_ACT_ERRNO(EUCLEAN), true); |
f6281133 LP |
212 | if (r < 0) |
213 | _exit(EXIT_FAILURE); | |
214 | ||
215 | /* Test the sycall filter with one random system call */ | |
216 | fd = eventfd(0, EFD_NONBLOCK|EFD_CLOEXEC); | |
217 | if (IN_SET(i, SYSCALL_FILTER_SET_IO_EVENT, SYSCALL_FILTER_SET_DEFAULT)) | |
469830d1 | 218 | assert_se(fd < 0 && errno == EUCLEAN); |
f6281133 LP |
219 | else { |
220 | assert_se(fd >= 0); | |
221 | safe_close(fd); | |
222 | } | |
223 | ||
224 | _exit(EXIT_SUCCESS); | |
225 | } | |
226 | ||
7d4904fe | 227 | assert_se(wait_for_terminate_and_check(syscall_filter_sets[i].name, pid, WAIT_LOG) == EXIT_SUCCESS); |
f6281133 LP |
228 | } |
229 | } | |
230 | ||
4f7452a8 | 231 | TEST(filter_sets_ordered) { |
23e12f8e ZJS |
232 | /* Ensure "@default" always remains at the beginning of the list */ |
233 | assert_se(SYSCALL_FILTER_SET_DEFAULT == 0); | |
c79e88b3 | 234 | ASSERT_STREQ(syscall_filter_sets[0].name, "@default"); |
23e12f8e | 235 | |
95aac012 ZJS |
236 | /* Ensure "@known" always remains at the end of the list */ |
237 | assert_se(SYSCALL_FILTER_SET_KNOWN == _SYSCALL_FILTER_SET_MAX - 1); | |
c79e88b3 | 238 | ASSERT_STREQ(syscall_filter_sets[SYSCALL_FILTER_SET_KNOWN].name, "@known"); |
95aac012 ZJS |
239 | |
240 | for (size_t i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) { | |
12e2b70f | 241 | const char *p = NULL; |
23e12f8e ZJS |
242 | |
243 | /* Make sure each group has a description */ | |
244 | assert_se(!isempty(syscall_filter_sets[0].help)); | |
245 | ||
95aac012 ZJS |
246 | /* Make sure the groups are ordered alphabetically, except for the first and last entries */ |
247 | assert_se(i < 2 || i == _SYSCALL_FILTER_SET_MAX - 1 || | |
248 | strcmp(syscall_filter_sets[i-1].name, syscall_filter_sets[i].name) < 0); | |
23e12f8e ZJS |
249 | |
250 | NULSTR_FOREACH(k, syscall_filter_sets[i].value) { | |
251 | ||
252 | /* Ensure each syscall list is in itself ordered, but groups before names */ | |
253 | assert_se(!p || | |
254 | (*p == '@' && *k != '@') || | |
255 | (((*p == '@' && *k == '@') || | |
256 | (*p != '@' && *k != '@')) && | |
257 | strcmp(p, k) < 0)); | |
258 | ||
259 | p = k; | |
260 | } | |
261 | } | |
262 | } | |
263 | ||
4f7452a8 | 264 | TEST(restrict_namespace) { |
86c2a9f1 | 265 | char *s = NULL; |
add00535 | 266 | unsigned long ul; |
469830d1 | 267 | pid_t pid; |
add00535 | 268 | |
5f00dc4d LP |
269 | if (!have_namespaces()) { |
270 | log_notice("Testing without namespaces, skipping %s", __func__); | |
271 | return; | |
272 | } | |
273 | ||
dd0395b5 | 274 | assert_se(namespace_flags_to_string(0, &s) == 0 && isempty(s)); |
86c2a9f1 YW |
275 | s = mfree(s); |
276 | assert_se(namespace_flags_to_string(CLONE_NEWNS, &s) == 0 && streq(s, "mnt")); | |
277 | s = mfree(s); | |
278 | assert_se(namespace_flags_to_string(CLONE_NEWNS|CLONE_NEWIPC, &s) == 0 && streq(s, "ipc mnt")); | |
279 | s = mfree(s); | |
280 | assert_se(namespace_flags_to_string(CLONE_NEWCGROUP, &s) == 0 && streq(s, "cgroup")); | |
281 | s = mfree(s); | |
282 | ||
283 | assert_se(namespace_flags_from_string("mnt", &ul) == 0 && ul == CLONE_NEWNS); | |
284 | assert_se(namespace_flags_from_string(NULL, &ul) == 0 && ul == 0); | |
285 | assert_se(namespace_flags_from_string("", &ul) == 0 && ul == 0); | |
286 | assert_se(namespace_flags_from_string("uts", &ul) == 0 && ul == CLONE_NEWUTS); | |
287 | assert_se(namespace_flags_from_string("mnt uts ipc", &ul) == 0 && ul == (CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC)); | |
288 | ||
289 | assert_se(namespace_flags_to_string(CLONE_NEWUTS, &s) == 0 && streq(s, "uts")); | |
290 | assert_se(namespace_flags_from_string(s, &ul) == 0 && ul == CLONE_NEWUTS); | |
291 | s = mfree(s); | |
292 | assert_se(namespace_flags_from_string("ipc", &ul) == 0 && ul == CLONE_NEWIPC); | |
293 | assert_se(namespace_flags_to_string(ul, &s) == 0 && streq(s, "ipc")); | |
294 | s = mfree(s); | |
295 | ||
296 | assert_se(namespace_flags_to_string(NAMESPACE_FLAGS_ALL, &s) == 0); | |
c79e88b3 | 297 | ASSERT_STREQ(s, "cgroup ipc net mnt pid user uts"); |
86c2a9f1 YW |
298 | assert_se(namespace_flags_from_string(s, &ul) == 0 && ul == NAMESPACE_FLAGS_ALL); |
299 | s = mfree(s); | |
add00535 | 300 | |
cd90ec75 YW |
301 | if (!is_seccomp_available()) { |
302 | log_notice("Seccomp not available, skipping remaining tests in %s", __func__); | |
add00535 | 303 | return; |
cd90ec75 | 304 | } |
6da5d7de LP |
305 | if (!have_seccomp_privs()) { |
306 | log_notice("Not privileged, skipping remaining tests in %s", __func__); | |
add00535 | 307 | return; |
cd90ec75 | 308 | } |
add00535 LP |
309 | |
310 | pid = fork(); | |
311 | assert_se(pid >= 0); | |
312 | ||
313 | if (pid == 0) { | |
314 | ||
315 | assert_se(seccomp_restrict_namespaces(CLONE_NEWNS|CLONE_NEWNET) >= 0); | |
316 | ||
317 | assert_se(unshare(CLONE_NEWNS) == 0); | |
318 | assert_se(unshare(CLONE_NEWNET) == 0); | |
319 | assert_se(unshare(CLONE_NEWUTS) == -1); | |
320 | assert_se(errno == EPERM); | |
321 | assert_se(unshare(CLONE_NEWIPC) == -1); | |
322 | assert_se(errno == EPERM); | |
323 | assert_se(unshare(CLONE_NEWNET|CLONE_NEWUTS) == -1); | |
324 | assert_se(errno == EPERM); | |
325 | ||
326 | /* We use fd 0 (stdin) here, which of course will fail with EINVAL on setns(). Except of course our | |
327 | * seccomp filter worked, and hits first and makes it return EPERM */ | |
328 | assert_se(setns(0, CLONE_NEWNS) == -1); | |
329 | assert_se(errno == EINVAL); | |
330 | assert_se(setns(0, CLONE_NEWNET) == -1); | |
331 | assert_se(errno == EINVAL); | |
332 | assert_se(setns(0, CLONE_NEWUTS) == -1); | |
333 | assert_se(errno == EPERM); | |
334 | assert_se(setns(0, CLONE_NEWIPC) == -1); | |
335 | assert_se(errno == EPERM); | |
336 | assert_se(setns(0, CLONE_NEWNET|CLONE_NEWUTS) == -1); | |
337 | assert_se(errno == EPERM); | |
338 | assert_se(setns(0, 0) == -1); | |
339 | assert_se(errno == EPERM); | |
340 | ||
341 | pid = raw_clone(CLONE_NEWNS); | |
342 | assert_se(pid >= 0); | |
343 | if (pid == 0) | |
344 | _exit(EXIT_SUCCESS); | |
345 | pid = raw_clone(CLONE_NEWNET); | |
346 | assert_se(pid >= 0); | |
347 | if (pid == 0) | |
348 | _exit(EXIT_SUCCESS); | |
349 | pid = raw_clone(CLONE_NEWUTS); | |
350 | assert_se(pid < 0); | |
351 | assert_se(errno == EPERM); | |
352 | pid = raw_clone(CLONE_NEWIPC); | |
353 | assert_se(pid < 0); | |
354 | assert_se(errno == EPERM); | |
355 | pid = raw_clone(CLONE_NEWNET|CLONE_NEWUTS); | |
356 | assert_se(pid < 0); | |
357 | assert_se(errno == EPERM); | |
358 | ||
359 | _exit(EXIT_SUCCESS); | |
360 | } | |
361 | ||
7d4904fe | 362 | assert_se(wait_for_terminate_and_check("nsseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
add00535 LP |
363 | } |
364 | ||
4f7452a8 | 365 | TEST(protect_sysctl) { |
469830d1 | 366 | pid_t pid; |
3c14dc61 | 367 | _cleanup_free_ char *seccomp = NULL; |
469830d1 | 368 | |
cd90ec75 YW |
369 | if (!is_seccomp_available()) { |
370 | log_notice("Seccomp not available, skipping %s", __func__); | |
469830d1 | 371 | return; |
cd90ec75 | 372 | } |
6da5d7de LP |
373 | if (!have_seccomp_privs()) { |
374 | log_notice("Not privileged, skipping %s", __func__); | |
469830d1 | 375 | return; |
cd90ec75 | 376 | } |
469830d1 | 377 | |
cd90ec75 YW |
378 | /* in containers _sysctl() is likely missing anyway */ |
379 | if (detect_container() > 0) { | |
380 | log_notice("Testing in container, skipping %s", __func__); | |
469830d1 | 381 | return; |
cd90ec75 | 382 | } |
469830d1 | 383 | |
3c14dc61 TM |
384 | assert_se(get_proc_field("/proc/self/status", "Seccomp", WHITESPACE, &seccomp) == 0); |
385 | if (!streq(seccomp, "0")) | |
386 | log_warning("Warning: seccomp filter detected, results may be unreliable for %s", __func__); | |
387 | ||
469830d1 LP |
388 | pid = fork(); |
389 | assert_se(pid >= 0); | |
390 | ||
391 | if (pid == 0) { | |
fb4b0465 | 392 | #if defined __NR__sysctl && __NR__sysctl >= 0 |
469830d1 | 393 | assert_se(syscall(__NR__sysctl, NULL) < 0); |
0af05e48 | 394 | assert_se(IN_SET(errno, EFAULT, ENOSYS)); |
2e64e8f4 | 395 | #endif |
469830d1 LP |
396 | |
397 | assert_se(seccomp_protect_sysctl() >= 0); | |
398 | ||
866f698b YW |
399 | #if HAVE_VALGRIND_VALGRIND_H |
400 | if (RUNNING_ON_VALGRIND) { | |
401 | log_info("Running on valgrind, skipping syscall/EPERM test"); | |
402 | _exit(EXIT_SUCCESS); | |
403 | } | |
404 | #endif | |
405 | ||
fb4b0465 | 406 | #if defined __NR__sysctl && __NR__sysctl >= 0 |
469830d1 LP |
407 | assert_se(syscall(__NR__sysctl, 0, 0, 0) < 0); |
408 | assert_se(errno == EPERM); | |
2e64e8f4 | 409 | #endif |
469830d1 LP |
410 | |
411 | _exit(EXIT_SUCCESS); | |
412 | } | |
413 | ||
7d4904fe | 414 | assert_se(wait_for_terminate_and_check("sysctlseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
469830d1 LP |
415 | } |
416 | ||
4f7452a8 | 417 | TEST(protect_syslog) { |
97d05f3b KK |
418 | pid_t pid; |
419 | ||
97d05f3b KK |
420 | if (!is_seccomp_available()) { |
421 | log_notice("Seccomp not available, skipping %s", __func__); | |
422 | return; | |
423 | } | |
6da5d7de LP |
424 | if (!have_seccomp_privs()) { |
425 | log_notice("Not privileged, skipping %s", __func__); | |
97d05f3b KK |
426 | return; |
427 | } | |
428 | ||
429 | /* in containers syslog() is likely missing anyway */ | |
430 | if (detect_container() > 0) { | |
431 | log_notice("Testing in container, skipping %s", __func__); | |
432 | return; | |
433 | } | |
434 | ||
435 | pid = fork(); | |
436 | assert_se(pid >= 0); | |
437 | ||
438 | if (pid == 0) { | |
fb4b0465 | 439 | #if defined __NR_syslog && __NR_syslog >= 0 |
97d05f3b KK |
440 | assert_se(syscall(__NR_syslog, -1, NULL, 0) < 0); |
441 | assert_se(errno == EINVAL); | |
442 | #endif | |
443 | ||
444 | assert_se(seccomp_protect_syslog() >= 0); | |
445 | ||
fb4b0465 | 446 | #if defined __NR_syslog && __NR_syslog >= 0 |
97d05f3b KK |
447 | assert_se(syscall(__NR_syslog, 0, 0, 0) < 0); |
448 | assert_se(errno == EPERM); | |
449 | #endif | |
450 | ||
451 | _exit(EXIT_SUCCESS); | |
452 | } | |
453 | ||
454 | assert_se(wait_for_terminate_and_check("syslogseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); | |
455 | } | |
456 | ||
4f7452a8 | 457 | TEST(restrict_address_families) { |
469830d1 LP |
458 | pid_t pid; |
459 | ||
cd90ec75 YW |
460 | if (!is_seccomp_available()) { |
461 | log_notice("Seccomp not available, skipping %s", __func__); | |
469830d1 | 462 | return; |
cd90ec75 | 463 | } |
6da5d7de LP |
464 | if (!have_seccomp_privs()) { |
465 | log_notice("Not privileged, skipping %s", __func__); | |
469830d1 | 466 | return; |
cd90ec75 | 467 | } |
469830d1 LP |
468 | |
469 | pid = fork(); | |
470 | assert_se(pid >= 0); | |
471 | ||
472 | if (pid == 0) { | |
473 | int fd; | |
474 | Set *s; | |
475 | ||
476 | fd = socket(AF_INET, SOCK_DGRAM, 0); | |
477 | assert_se(fd >= 0); | |
478 | safe_close(fd); | |
479 | ||
480 | fd = socket(AF_UNIX, SOCK_DGRAM, 0); | |
481 | assert_se(fd >= 0); | |
482 | safe_close(fd); | |
483 | ||
484 | fd = socket(AF_NETLINK, SOCK_DGRAM, 0); | |
485 | assert_se(fd >= 0); | |
486 | safe_close(fd); | |
487 | ||
488 | assert_se(s = set_new(NULL)); | |
489 | assert_se(set_put(s, INT_TO_PTR(AF_UNIX)) >= 0); | |
490 | ||
491 | assert_se(seccomp_restrict_address_families(s, false) >= 0); | |
492 | ||
493 | fd = socket(AF_INET, SOCK_DGRAM, 0); | |
494 | assert_se(fd >= 0); | |
495 | safe_close(fd); | |
496 | ||
ad8f1479 | 497 | fd = socket(AF_UNIX, SOCK_DGRAM, 0); |
dce0e620 | 498 | #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN |
ad8f1479 LP |
499 | assert_se(fd >= 0); |
500 | safe_close(fd); | |
501 | #else | |
dce0e620 | 502 | assert_se(fd < 0); |
469830d1 | 503 | assert_se(errno == EAFNOSUPPORT); |
ad8f1479 | 504 | #endif |
469830d1 LP |
505 | |
506 | fd = socket(AF_NETLINK, SOCK_DGRAM, 0); | |
507 | assert_se(fd >= 0); | |
508 | safe_close(fd); | |
509 | ||
510 | set_clear(s); | |
511 | ||
512 | assert_se(set_put(s, INT_TO_PTR(AF_INET)) >= 0); | |
513 | ||
514 | assert_se(seccomp_restrict_address_families(s, true) >= 0); | |
515 | ||
516 | fd = socket(AF_INET, SOCK_DGRAM, 0); | |
517 | assert_se(fd >= 0); | |
518 | safe_close(fd); | |
519 | ||
ad8f1479 | 520 | fd = socket(AF_UNIX, SOCK_DGRAM, 0); |
dce0e620 | 521 | #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN |
ad8f1479 LP |
522 | assert_se(fd >= 0); |
523 | safe_close(fd); | |
dce0e620 ZJS |
524 | #else |
525 | assert_se(fd < 0); | |
526 | assert_se(errno == EAFNOSUPPORT); | |
527 | #endif | |
ad8f1479 LP |
528 | |
529 | fd = socket(AF_NETLINK, SOCK_DGRAM, 0); | |
dce0e620 | 530 | #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN |
ad8f1479 LP |
531 | assert_se(fd >= 0); |
532 | safe_close(fd); | |
533 | #else | |
dce0e620 | 534 | assert_se(fd < 0); |
469830d1 | 535 | assert_se(errno == EAFNOSUPPORT); |
ad8f1479 | 536 | #endif |
469830d1 LP |
537 | |
538 | _exit(EXIT_SUCCESS); | |
539 | } | |
540 | ||
7d4904fe | 541 | assert_se(wait_for_terminate_and_check("socketseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
469830d1 LP |
542 | } |
543 | ||
4f7452a8 | 544 | TEST(restrict_realtime) { |
469830d1 LP |
545 | pid_t pid; |
546 | ||
cd90ec75 YW |
547 | if (!is_seccomp_available()) { |
548 | log_notice("Seccomp not available, skipping %s", __func__); | |
469830d1 | 549 | return; |
cd90ec75 | 550 | } |
6da5d7de LP |
551 | if (!have_seccomp_privs()) { |
552 | log_notice("Not privileged, skipping %s", __func__); | |
469830d1 | 553 | return; |
cd90ec75 | 554 | } |
469830d1 | 555 | |
cd90ec75 YW |
556 | /* in containers RT privs are likely missing anyway */ |
557 | if (detect_container() > 0) { | |
558 | log_notice("Testing in container, skipping %s", __func__); | |
469830d1 | 559 | return; |
cd90ec75 | 560 | } |
469830d1 LP |
561 | |
562 | pid = fork(); | |
563 | assert_se(pid >= 0); | |
564 | ||
565 | if (pid == 0) { | |
a9002749 YW |
566 | /* On some CI environments, the restriction may be already enabled. */ |
567 | if (sched_setscheduler(0, SCHED_FIFO, &(struct sched_param) { .sched_priority = 1 }) < 0) { | |
568 | log_full_errno(errno == EPERM ? LOG_DEBUG : LOG_WARNING, errno, | |
569 | "Failed to set scheduler parameter for FIFO: %m"); | |
570 | assert(errno == EPERM); | |
571 | } | |
572 | if (sched_setscheduler(0, SCHED_RR, &(struct sched_param) { .sched_priority = 1 }) < 0) { | |
573 | log_full_errno(errno == EPERM ? LOG_DEBUG : LOG_WARNING, errno, | |
574 | "Failed to set scheduler parameter for RR: %m"); | |
575 | assert(errno == EPERM); | |
576 | } | |
577 | ||
469830d1 LP |
578 | assert_se(sched_setscheduler(0, SCHED_IDLE, &(struct sched_param) { .sched_priority = 0 }) >= 0); |
579 | assert_se(sched_setscheduler(0, SCHED_BATCH, &(struct sched_param) { .sched_priority = 0 }) >= 0); | |
580 | assert_se(sched_setscheduler(0, SCHED_OTHER, &(struct sched_param) {}) >= 0); | |
581 | ||
a9002749 | 582 | assert_se(seccomp_restrict_realtime_full(ENOANO) >= 0); |
469830d1 LP |
583 | |
584 | assert_se(sched_setscheduler(0, SCHED_IDLE, &(struct sched_param) { .sched_priority = 0 }) >= 0); | |
585 | assert_se(sched_setscheduler(0, SCHED_BATCH, &(struct sched_param) { .sched_priority = 0 }) >= 0); | |
586 | assert_se(sched_setscheduler(0, SCHED_OTHER, &(struct sched_param) {}) >= 0); | |
587 | ||
588 | assert_se(sched_setscheduler(0, SCHED_FIFO, &(struct sched_param) { .sched_priority = 1 }) < 0); | |
a9002749 | 589 | assert_se(errno == ENOANO); |
469830d1 | 590 | assert_se(sched_setscheduler(0, SCHED_RR, &(struct sched_param) { .sched_priority = 1 }) < 0); |
a9002749 | 591 | assert_se(errno == ENOANO); |
469830d1 LP |
592 | |
593 | _exit(EXIT_SUCCESS); | |
594 | } | |
595 | ||
7d4904fe | 596 | assert_se(wait_for_terminate_and_check("realtimeseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
469830d1 LP |
597 | } |
598 | ||
4f7452a8 | 599 | TEST(memory_deny_write_execute_mmap) { |
469830d1 LP |
600 | pid_t pid; |
601 | ||
cd90ec75 YW |
602 | if (!is_seccomp_available()) { |
603 | log_notice("Seccomp not available, skipping %s", __func__); | |
469830d1 | 604 | return; |
cd90ec75 | 605 | } |
6da5d7de LP |
606 | if (!have_seccomp_privs()) { |
607 | log_notice("Not privileged, skipping %s", __func__); | |
469830d1 | 608 | return; |
cd90ec75 | 609 | } |
866f698b YW |
610 | #if HAVE_VALGRIND_VALGRIND_H |
611 | if (RUNNING_ON_VALGRIND) { | |
612 | log_notice("Running on valgrind, skipping %s", __func__); | |
613 | return; | |
614 | } | |
615 | #endif | |
a0dfd10a YW |
616 | #if HAS_FEATURE_ADDRESS_SANITIZER |
617 | log_notice("Running on address sanitizer, skipping %s", __func__); | |
618 | return; | |
619 | #endif | |
469830d1 LP |
620 | |
621 | pid = fork(); | |
622 | assert_se(pid >= 0); | |
623 | ||
624 | if (pid == 0) { | |
625 | void *p; | |
626 | ||
7f5c82aa | 627 | p = mmap(NULL, page_size(), PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
469830d1 LP |
628 | assert_se(p != MAP_FAILED); |
629 | assert_se(munmap(p, page_size()) >= 0); | |
630 | ||
7f5c82aa | 631 | p = mmap(NULL, page_size(), PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
8a50cf69 LP |
632 | assert_se(p != MAP_FAILED); |
633 | assert_se(munmap(p, page_size()) >= 0); | |
469830d1 | 634 | |
8a50cf69 LP |
635 | assert_se(seccomp_memory_deny_write_execute() >= 0); |
636 | ||
7f5c82aa | 637 | p = mmap(NULL, page_size(), PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
f9d3fb6b | 638 | #if defined(__x86_64__) || defined(__i386__) || defined(__powerpc64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch_lp64) |
469830d1 LP |
639 | assert_se(p == MAP_FAILED); |
640 | assert_se(errno == EPERM); | |
8a50cf69 | 641 | #endif |
49219b5c CE |
642 | /* Depending on kernel, libseccomp, and glibc versions, other architectures |
643 | * might fail or not. Let's not assert success. */ | |
644 | if (p != MAP_FAILED) | |
645 | assert_se(munmap(p, page_size()) == 0); | |
469830d1 | 646 | |
7f5c82aa | 647 | p = mmap(NULL, page_size(), PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
469830d1 LP |
648 | assert_se(p != MAP_FAILED); |
649 | assert_se(munmap(p, page_size()) >= 0); | |
650 | ||
651 | _exit(EXIT_SUCCESS); | |
652 | } | |
653 | ||
7d4904fe | 654 | assert_se(wait_for_terminate_and_check("memoryseccomp-mmap", pid, WAIT_LOG) == EXIT_SUCCESS); |
2a65bd94 ZJS |
655 | } |
656 | ||
4f7452a8 | 657 | TEST(memory_deny_write_execute_shmat) { |
2a65bd94 ZJS |
658 | int shmid; |
659 | pid_t pid; | |
e55bdf9b | 660 | uint32_t arch; |
2a65bd94 | 661 | |
e55bdf9b ZJS |
662 | SECCOMP_FOREACH_LOCAL_ARCH(arch) { |
663 | log_debug("arch %s: SCMP_SYS(mmap) = %d", seccomp_arch_to_string(arch), SCMP_SYS(mmap)); | |
664 | log_debug("arch %s: SCMP_SYS(mmap2) = %d", seccomp_arch_to_string(arch), SCMP_SYS(mmap2)); | |
665 | log_debug("arch %s: SCMP_SYS(shmget) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmget)); | |
666 | log_debug("arch %s: SCMP_SYS(shmat) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmat)); | |
667 | log_debug("arch %s: SCMP_SYS(shmdt) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmdt)); | |
668 | } | |
669 | ||
cd90ec75 YW |
670 | if (!is_seccomp_available()) { |
671 | log_notice("Seccomp not available, skipping %s", __func__); | |
2a65bd94 | 672 | return; |
cd90ec75 | 673 | } |
7e46a5c0 | 674 | if (!have_seccomp_privs() || have_effective_cap(CAP_IPC_OWNER) <= 0) { |
6da5d7de | 675 | log_notice("Not privileged, skipping %s", __func__); |
2a65bd94 | 676 | return; |
cd90ec75 | 677 | } |
866f698b YW |
678 | #if HAVE_VALGRIND_VALGRIND_H |
679 | if (RUNNING_ON_VALGRIND) { | |
680 | log_notice("Running on valgrind, skipping %s", __func__); | |
681 | return; | |
682 | } | |
683 | #endif | |
a0dfd10a YW |
684 | #if HAS_FEATURE_ADDRESS_SANITIZER |
685 | log_notice("Running on address sanitizer, skipping %s", __func__); | |
686 | return; | |
687 | #endif | |
2a65bd94 ZJS |
688 | |
689 | shmid = shmget(IPC_PRIVATE, page_size(), 0); | |
690 | assert_se(shmid >= 0); | |
691 | ||
692 | pid = fork(); | |
693 | assert_se(pid >= 0); | |
694 | ||
695 | if (pid == 0) { | |
696 | void *p; | |
697 | ||
698 | p = shmat(shmid, NULL, 0); | |
699 | assert_se(p != MAP_FAILED); | |
700 | assert_se(shmdt(p) == 0); | |
701 | ||
702 | p = shmat(shmid, NULL, SHM_EXEC); | |
703 | assert_se(p != MAP_FAILED); | |
704 | assert_se(shmdt(p) == 0); | |
705 | ||
706 | assert_se(seccomp_memory_deny_write_execute() >= 0); | |
707 | ||
708 | p = shmat(shmid, NULL, SHM_EXEC); | |
67fb5f33 | 709 | log_debug_errno(p == MAP_FAILED ? errno : 0, "shmat(SHM_EXEC): %m"); |
f9d3fb6b | 710 | #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch_lp64) |
2a65bd94 ZJS |
711 | assert_se(p == MAP_FAILED); |
712 | assert_se(errno == EPERM); | |
2a65bd94 | 713 | #endif |
67fb5f33 ZJS |
714 | /* Depending on kernel, libseccomp, and glibc versions, other architectures |
715 | * might fail or not. Let's not assert success. */ | |
716 | if (p != MAP_FAILED) | |
717 | assert_se(shmdt(p) == 0); | |
2a65bd94 ZJS |
718 | |
719 | p = shmat(shmid, NULL, 0); | |
67fb5f33 | 720 | log_debug_errno(p == MAP_FAILED ? errno : 0, "shmat(0): %m"); |
2a65bd94 ZJS |
721 | assert_se(p != MAP_FAILED); |
722 | assert_se(shmdt(p) == 0); | |
723 | ||
724 | _exit(EXIT_SUCCESS); | |
725 | } | |
726 | ||
7d4904fe | 727 | assert_se(wait_for_terminate_and_check("memoryseccomp-shmat", pid, WAIT_LOG) == EXIT_SUCCESS); |
469830d1 LP |
728 | } |
729 | ||
4f7452a8 | 730 | TEST(restrict_archs) { |
469830d1 LP |
731 | pid_t pid; |
732 | ||
cd90ec75 YW |
733 | if (!is_seccomp_available()) { |
734 | log_notice("Seccomp not available, skipping %s", __func__); | |
469830d1 | 735 | return; |
cd90ec75 | 736 | } |
6da5d7de LP |
737 | if (!have_seccomp_privs()) { |
738 | log_notice("Not privileged, skipping %s", __func__); | |
469830d1 | 739 | return; |
cd90ec75 | 740 | } |
469830d1 LP |
741 | |
742 | pid = fork(); | |
743 | assert_se(pid >= 0); | |
744 | ||
745 | if (pid == 0) { | |
746 | _cleanup_set_free_ Set *s = NULL; | |
747 | ||
748 | assert_se(access("/", F_OK) >= 0); | |
749 | ||
750 | assert_se(s = set_new(NULL)); | |
751 | ||
752 | #ifdef __x86_64__ | |
753 | assert_se(set_put(s, UINT32_TO_PTR(SCMP_ARCH_X86+1)) >= 0); | |
754 | #endif | |
755 | assert_se(seccomp_restrict_archs(s) >= 0); | |
756 | ||
757 | assert_se(access("/", F_OK) >= 0); | |
758 | assert_se(seccomp_restrict_archs(NULL) >= 0); | |
759 | ||
760 | assert_se(access("/", F_OK) >= 0); | |
761 | ||
762 | _exit(EXIT_SUCCESS); | |
763 | } | |
764 | ||
7d4904fe | 765 | assert_se(wait_for_terminate_and_check("archseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
469830d1 LP |
766 | } |
767 | ||
4f7452a8 | 768 | TEST(load_syscall_filter_set_raw) { |
469830d1 LP |
769 | pid_t pid; |
770 | ||
cd90ec75 YW |
771 | if (!is_seccomp_available()) { |
772 | log_notice("Seccomp not available, skipping %s", __func__); | |
469830d1 | 773 | return; |
cd90ec75 | 774 | } |
6da5d7de LP |
775 | if (!have_seccomp_privs()) { |
776 | log_notice("Not privileged, skipping %s", __func__); | |
469830d1 | 777 | return; |
cd90ec75 | 778 | } |
469830d1 LP |
779 | |
780 | pid = fork(); | |
781 | assert_se(pid >= 0); | |
782 | ||
783 | if (pid == 0) { | |
b4891260 | 784 | _cleanup_hashmap_free_ Hashmap *s = NULL; |
469830d1 LP |
785 | |
786 | assert_se(access("/", F_OK) >= 0); | |
787 | assert_se(poll(NULL, 0, 0) == 0); | |
788 | ||
7bbc229c | 789 | assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, scmp_act_kill_process(), true) >= 0); |
469830d1 LP |
790 | assert_se(access("/", F_OK) >= 0); |
791 | assert_se(poll(NULL, 0, 0) == 0); | |
792 | ||
b4891260 | 793 | assert_se(s = hashmap_new(NULL)); |
fb4b0465 | 794 | #if defined __NR_access && __NR_access >= 0 |
b4891260 | 795 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_access + 1), INT_TO_PTR(-1)) >= 0); |
74224056 YW |
796 | log_debug("has access()"); |
797 | #endif | |
798 | #if defined __NR_faccessat && __NR_faccessat >= 0 | |
b4891260 | 799 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(-1)) >= 0); |
74224056 YW |
800 | log_debug("has faccessat()"); |
801 | #endif | |
802 | #if defined __NR_faccessat2 && __NR_faccessat2 >= 0 | |
803 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat2 + 1), INT_TO_PTR(-1)) >= 0); | |
804 | log_debug("has faccessat2()"); | |
f60a865a | 805 | #endif |
469830d1 | 806 | |
74224056 | 807 | assert_se(!hashmap_isempty(s)); |
b54f36c6 | 808 | assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN), true) >= 0); |
469830d1 LP |
809 | |
810 | assert_se(access("/", F_OK) < 0); | |
811 | assert_se(errno == EUCLEAN); | |
812 | ||
813 | assert_se(poll(NULL, 0, 0) == 0); | |
814 | ||
74224056 | 815 | hashmap_clear(s); |
fb4b0465 | 816 | #if defined __NR_access && __NR_access >= 0 |
b4891260 | 817 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_access + 1), INT_TO_PTR(EILSEQ)) >= 0); |
74224056 YW |
818 | #endif |
819 | #if defined __NR_faccessat && __NR_faccessat >= 0 | |
b4891260 YW |
820 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(EILSEQ)) >= 0); |
821 | #endif | |
74224056 YW |
822 | #if defined __NR_faccessat2 && __NR_faccessat2 >= 0 |
823 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat2 + 1), INT_TO_PTR(EILSEQ)) >= 0); | |
824 | #endif | |
b4891260 | 825 | |
b54f36c6 | 826 | assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN), true) >= 0); |
b4891260 YW |
827 | |
828 | assert_se(access("/", F_OK) < 0); | |
829 | assert_se(errno == EILSEQ); | |
830 | ||
831 | assert_se(poll(NULL, 0, 0) == 0); | |
832 | ||
74224056 | 833 | hashmap_clear(s); |
fb4b0465 | 834 | #if defined __NR_poll && __NR_poll >= 0 |
b4891260 | 835 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_poll + 1), INT_TO_PTR(-1)) >= 0); |
74224056 YW |
836 | log_debug("has poll()"); |
837 | #endif | |
838 | #if defined __NR_ppoll && __NR_ppoll >= 0 | |
b4891260 | 839 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(-1)) >= 0); |
74224056 YW |
840 | log_debug("has ppoll()"); |
841 | #endif | |
842 | #if defined __NR_ppoll_time64 && __NR_ppoll_time64 >= 0 | |
843 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll_time64 + 1), INT_TO_PTR(-1)) >= 0); | |
844 | log_debug("has ppoll_time64()"); | |
f60a865a | 845 | #endif |
469830d1 | 846 | |
74224056 | 847 | assert_se(!hashmap_isempty(s)); |
b54f36c6 | 848 | assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH), true) >= 0); |
469830d1 LP |
849 | |
850 | assert_se(access("/", F_OK) < 0); | |
b4891260 | 851 | assert_se(errno == EILSEQ); |
469830d1 LP |
852 | |
853 | assert_se(poll(NULL, 0, 0) < 0); | |
854 | assert_se(errno == EUNATCH); | |
855 | ||
74224056 | 856 | hashmap_clear(s); |
fb4b0465 | 857 | #if defined __NR_poll && __NR_poll >= 0 |
b4891260 | 858 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_poll + 1), INT_TO_PTR(EILSEQ)) >= 0); |
74224056 YW |
859 | #endif |
860 | #if defined __NR_ppoll && __NR_ppoll >= 0 | |
b4891260 | 861 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(EILSEQ)) >= 0); |
74224056 YW |
862 | #endif |
863 | #if defined __NR_ppoll_time64 && __NR_ppoll_time64 >= 0 | |
864 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll_time64 + 1), INT_TO_PTR(EILSEQ)) >= 0); | |
b4891260 YW |
865 | #endif |
866 | ||
b54f36c6 | 867 | assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH), true) >= 0); |
b4891260 YW |
868 | |
869 | assert_se(access("/", F_OK) < 0); | |
870 | assert_se(errno == EILSEQ); | |
871 | ||
872 | assert_se(poll(NULL, 0, 0) < 0); | |
873 | assert_se(errno == EILSEQ); | |
874 | ||
469830d1 LP |
875 | _exit(EXIT_SUCCESS); |
876 | } | |
877 | ||
7d4904fe | 878 | assert_se(wait_for_terminate_and_check("syscallrawseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
469830d1 LP |
879 | } |
880 | ||
4f7452a8 | 881 | TEST(native_syscalls_filtered) { |
08bf703c BB |
882 | pid_t pid; |
883 | ||
08bf703c BB |
884 | if (!is_seccomp_available()) { |
885 | log_notice("Seccomp not available, skipping %s", __func__); | |
886 | return; | |
887 | } | |
888 | if (!have_seccomp_privs()) { | |
889 | log_notice("Not privileged, skipping %s", __func__); | |
890 | return; | |
891 | } | |
892 | ||
893 | pid = fork(); | |
894 | assert_se(pid >= 0); | |
895 | ||
896 | if (pid == 0) { | |
897 | _cleanup_set_free_ Set *arch_s = NULL; | |
898 | _cleanup_hashmap_free_ Hashmap *s = NULL; | |
899 | ||
900 | /* Passing "native" or an empty set is equivalent, just do both here. */ | |
901 | assert_se(arch_s = set_new(NULL)); | |
902 | assert_se(seccomp_restrict_archs(arch_s) >= 0); | |
903 | assert_se(set_put(arch_s, SCMP_ARCH_NATIVE) >= 0); | |
904 | assert_se(seccomp_restrict_archs(arch_s) >= 0); | |
905 | ||
906 | assert_se(access("/", F_OK) >= 0); | |
907 | assert_se(poll(NULL, 0, 0) == 0); | |
908 | ||
909 | assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, scmp_act_kill_process(), true) >= 0); | |
910 | assert_se(access("/", F_OK) >= 0); | |
911 | assert_se(poll(NULL, 0, 0) == 0); | |
912 | ||
913 | assert_se(s = hashmap_new(NULL)); | |
914 | #if defined __NR_access && __NR_access >= 0 | |
915 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_access + 1), INT_TO_PTR(-1)) >= 0); | |
916 | log_debug("has access()"); | |
917 | #endif | |
918 | #if defined __NR_faccessat && __NR_faccessat >= 0 | |
919 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(-1)) >= 0); | |
920 | log_debug("has faccessat()"); | |
921 | #endif | |
922 | #if defined __NR_faccessat2 && __NR_faccessat2 >= 0 | |
923 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat2 + 1), INT_TO_PTR(-1)) >= 0); | |
924 | log_debug("has faccessat2()"); | |
925 | #endif | |
926 | ||
927 | assert_se(!hashmap_isempty(s)); | |
928 | assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN), true) >= 0); | |
929 | ||
930 | assert_se(access("/", F_OK) < 0); | |
931 | assert_se(errno == EUCLEAN); | |
932 | ||
933 | _exit(EXIT_SUCCESS); | |
934 | } | |
935 | ||
936 | assert_se(wait_for_terminate_and_check("nativeseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); | |
937 | } | |
938 | ||
4f7452a8 | 939 | TEST(lock_personality) { |
3dc51ab2 | 940 | unsigned long current_opinionated; |
78e864e5 TM |
941 | pid_t pid; |
942 | ||
cd90ec75 YW |
943 | if (!is_seccomp_available()) { |
944 | log_notice("Seccomp not available, skipping %s", __func__); | |
78e864e5 | 945 | return; |
cd90ec75 | 946 | } |
6da5d7de LP |
947 | if (!have_seccomp_privs()) { |
948 | log_notice("Not privileged, skipping %s", __func__); | |
78e864e5 | 949 | return; |
cd90ec75 | 950 | } |
78e864e5 | 951 | |
3dc51ab2 | 952 | assert_se(opinionated_personality(¤t_opinionated) >= 0); |
e8132d63 | 953 | |
3dc51ab2 FS |
954 | log_info("current personality=0x%lX", (unsigned long) safe_personality(PERSONALITY_INVALID)); |
955 | log_info("current opinionated personality=0x%lX", current_opinionated); | |
e8132d63 | 956 | |
78e864e5 TM |
957 | pid = fork(); |
958 | assert_se(pid >= 0); | |
959 | ||
960 | if (pid == 0) { | |
3dc51ab2 | 961 | unsigned long current; |
78e864e5 | 962 | |
3dc51ab2 FS |
963 | assert_se(seccomp_lock_personality(current_opinionated) >= 0); |
964 | ||
965 | current = safe_personality(current_opinionated); | |
966 | assert_se((current & OPINIONATED_PERSONALITY_MASK) == current_opinionated); | |
e8132d63 | 967 | |
894dad29 | 968 | /* Note, we also test that safe_personality() works correctly, by checking whether errno is properly |
21022b9d LP |
969 | * set, in addition to the return value */ |
970 | errno = 0; | |
894dad29 | 971 | assert_se(safe_personality(PER_LINUX | MMAP_PAGE_ZERO) == -EPERM); |
21022b9d | 972 | assert_se(errno == EPERM); |
e8132d63 | 973 | |
894dad29 FS |
974 | if (!FLAGS_SET(current, ADDR_NO_RANDOMIZE)) |
975 | assert_se(safe_personality(PER_LINUX | ADDR_NO_RANDOMIZE) == -EPERM); | |
21022b9d LP |
976 | assert_se(safe_personality(PER_LINUX | ADDR_COMPAT_LAYOUT) == -EPERM); |
977 | assert_se(safe_personality(PER_LINUX | READ_IMPLIES_EXEC) == -EPERM); | |
978 | assert_se(safe_personality(PER_LINUX_32BIT) == -EPERM); | |
979 | assert_se(safe_personality(PER_SVR4) == -EPERM); | |
980 | assert_se(safe_personality(PER_BSD) == -EPERM); | |
3dc51ab2 | 981 | assert_se(safe_personality(current_opinionated == PER_LINUX ? PER_LINUX32 : PER_LINUX) == -EPERM); |
21022b9d LP |
982 | assert_se(safe_personality(PER_LINUX32_3GB) == -EPERM); |
983 | assert_se(safe_personality(PER_UW7) == -EPERM); | |
984 | assert_se(safe_personality(0x42) == -EPERM); | |
985 | ||
986 | assert_se(safe_personality(PERSONALITY_INVALID) == -EPERM); /* maybe remove this later */ | |
e8132d63 | 987 | |
3dc51ab2 FS |
988 | current = safe_personality(current_opinionated); |
989 | assert_se((current & OPINIONATED_PERSONALITY_MASK) == current_opinionated); | |
78e864e5 TM |
990 | _exit(EXIT_SUCCESS); |
991 | } | |
992 | ||
7d4904fe | 993 | assert_se(wait_for_terminate_and_check("lockpersonalityseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
78e864e5 TM |
994 | } |
995 | ||
167fc10c LP |
996 | static int real_open(const char *path, int flags, mode_t mode) { |
997 | /* glibc internally calls openat() when open() is requested. Let's hence define our own wrapper for | |
dff6c629 ZJS |
998 | * testing purposes that calls the real syscall, on architectures where SYS_open is defined. On |
999 | * other architectures, let's just fall back to the glibc call. */ | |
167fc10c | 1000 | |
fb4b0465 | 1001 | #if defined __NR_open && __NR_open >= 0 |
4df8fe84 | 1002 | return (int) syscall(__NR_open, path, flags, mode); |
dff6c629 ZJS |
1003 | #else |
1004 | return open(path, flags, mode); | |
1005 | #endif | |
167fc10c LP |
1006 | } |
1007 | ||
c21566d9 AM |
1008 | static int try_fchmodat2(int dirfd, const char *path, mode_t mode, int flags) { |
1009 | int r; | |
1010 | ||
8b45281d AM |
1011 | /* glibc does not provide a direct wrapper for fchmodat2(). Let's hence define our own wrapper for |
1012 | * testing purposes that calls the real syscall, on architectures and in environments where | |
1013 | * SYS_fchmodat2 is defined. Otherwise, let's just fall back to the glibc fchmodat() call. */ | |
1014 | ||
c21566d9 AM |
1015 | /* Not supported by fchmodat() */ |
1016 | assert_se(!FLAGS_SET(flags, AT_EMPTY_PATH)); | |
1017 | ||
1018 | r = RET_NERRNO(fchmodat2(dirfd, path, mode, flags)); | |
1019 | if (r != -ENOSYS) | |
1020 | return r; | |
1021 | ||
8b45281d | 1022 | /* The syscall might still be unsupported by kernel or libseccomp. */ |
c21566d9 | 1023 | return RET_NERRNO(fchmodat(dirfd, path, mode, flags)); |
8b45281d AM |
1024 | } |
1025 | ||
4f7452a8 | 1026 | TEST(restrict_suid_sgid) { |
167fc10c LP |
1027 | pid_t pid; |
1028 | ||
167fc10c LP |
1029 | if (!is_seccomp_available()) { |
1030 | log_notice("Seccomp not available, skipping %s", __func__); | |
1031 | return; | |
1032 | } | |
6da5d7de LP |
1033 | if (!have_seccomp_privs()) { |
1034 | log_notice("Not privileged, skipping %s", __func__); | |
167fc10c LP |
1035 | return; |
1036 | } | |
1037 | ||
1038 | pid = fork(); | |
1039 | assert_se(pid >= 0); | |
1040 | ||
1041 | if (pid == 0) { | |
1042 | char path[] = "/tmp/suidsgidXXXXXX", dir[] = "/tmp/suidsgiddirXXXXXX"; | |
254d1313 | 1043 | int fd = -EBADF, k = -EBADF; |
167fc10c LP |
1044 | const char *z; |
1045 | ||
1046 | fd = mkostemp_safe(path); | |
1047 | assert_se(fd >= 0); | |
1048 | ||
1049 | assert_se(mkdtemp(dir)); | |
1050 | z = strjoina(dir, "/test"); | |
1051 | ||
1052 | assert_se(chmod(path, 0755 | S_ISUID) >= 0); | |
1053 | assert_se(chmod(path, 0755 | S_ISGID) >= 0); | |
1054 | assert_se(chmod(path, 0755 | S_ISGID | S_ISUID) >= 0); | |
1055 | assert_se(chmod(path, 0755) >= 0); | |
1056 | ||
1057 | assert_se(fchmod(fd, 0755 | S_ISUID) >= 0); | |
1058 | assert_se(fchmod(fd, 0755 | S_ISGID) >= 0); | |
1059 | assert_se(fchmod(fd, 0755 | S_ISGID | S_ISUID) >= 0); | |
1060 | assert_se(fchmod(fd, 0755) >= 0); | |
1061 | ||
1062 | assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISUID, 0) >= 0); | |
1063 | assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID, 0) >= 0); | |
1064 | assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) >= 0); | |
1065 | assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0); | |
1066 | ||
8b45281d AM |
1067 | assert_se(try_fchmodat2(AT_FDCWD, path, 0755 | S_ISUID, 0) >= 0); |
1068 | assert_se(try_fchmodat2(AT_FDCWD, path, 0755 | S_ISGID, 0) >= 0); | |
1069 | assert_se(try_fchmodat2(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) >= 0); | |
1070 | assert_se(try_fchmodat2(AT_FDCWD, path, 0755, 0) >= 0); | |
1071 | ||
167fc10c LP |
1072 | k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID); |
1073 | k = safe_close(k); | |
1074 | assert_se(unlink(z) >= 0); | |
1075 | ||
1076 | k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID); | |
1077 | k = safe_close(k); | |
1078 | assert_se(unlink(z) >= 0); | |
1079 | ||
1080 | k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID); | |
1081 | k = safe_close(k); | |
1082 | assert_se(unlink(z) >= 0); | |
1083 | ||
1084 | k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644); | |
1085 | k = safe_close(k); | |
1086 | assert_se(unlink(z) >= 0); | |
1087 | ||
1088 | k = creat(z, 0644 | S_ISUID); | |
1089 | k = safe_close(k); | |
1090 | assert_se(unlink(z) >= 0); | |
1091 | ||
1092 | k = creat(z, 0644 | S_ISGID); | |
1093 | k = safe_close(k); | |
1094 | assert_se(unlink(z) >= 0); | |
1095 | ||
1096 | k = creat(z, 0644 | S_ISUID | S_ISGID); | |
1097 | k = safe_close(k); | |
1098 | assert_se(unlink(z) >= 0); | |
1099 | ||
1100 | k = creat(z, 0644); | |
1101 | k = safe_close(k); | |
1102 | assert_se(unlink(z) >= 0); | |
1103 | ||
1104 | k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID); | |
1105 | k = safe_close(k); | |
1106 | assert_se(unlink(z) >= 0); | |
1107 | ||
1108 | k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID); | |
1109 | k = safe_close(k); | |
1110 | assert_se(unlink(z) >= 0); | |
1111 | ||
1112 | k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID); | |
1113 | k = safe_close(k); | |
1114 | assert_se(unlink(z) >= 0); | |
1115 | ||
1116 | k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644); | |
1117 | k = safe_close(k); | |
1118 | assert_se(unlink(z) >= 0); | |
1119 | ||
1120 | assert_se(mkdir(z, 0755 | S_ISUID) >= 0); | |
1121 | assert_se(rmdir(z) >= 0); | |
1122 | assert_se(mkdir(z, 0755 | S_ISGID) >= 0); | |
1123 | assert_se(rmdir(z) >= 0); | |
1124 | assert_se(mkdir(z, 0755 | S_ISUID | S_ISGID) >= 0); | |
1125 | assert_se(rmdir(z) >= 0); | |
1126 | assert_se(mkdir(z, 0755) >= 0); | |
1127 | assert_se(rmdir(z) >= 0); | |
1128 | ||
1129 | assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID) >= 0); | |
1130 | assert_se(rmdir(z) >= 0); | |
1131 | assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISGID) >= 0); | |
1132 | assert_se(rmdir(z) >= 0); | |
1133 | assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID | S_ISGID) >= 0); | |
1134 | assert_se(rmdir(z) >= 0); | |
1135 | assert_se(mkdirat(AT_FDCWD, z, 0755) >= 0); | |
1136 | assert_se(rmdir(z) >= 0); | |
1137 | ||
1138 | assert_se(mknod(z, S_IFREG | 0755 | S_ISUID, 0) >= 0); | |
1139 | assert_se(unlink(z) >= 0); | |
1140 | assert_se(mknod(z, S_IFREG | 0755 | S_ISGID, 0) >= 0); | |
1141 | assert_se(unlink(z) >= 0); | |
1142 | assert_se(mknod(z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) >= 0); | |
1143 | assert_se(unlink(z) >= 0); | |
1144 | assert_se(mknod(z, S_IFREG | 0755, 0) >= 0); | |
1145 | assert_se(unlink(z) >= 0); | |
1146 | ||
1147 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID, 0) >= 0); | |
1148 | assert_se(unlink(z) >= 0); | |
1149 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISGID, 0) >= 0); | |
1150 | assert_se(unlink(z) >= 0); | |
1151 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) >= 0); | |
1152 | assert_se(unlink(z) >= 0); | |
1153 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755, 0) >= 0); | |
1154 | assert_se(unlink(z) >= 0); | |
1155 | ||
1156 | assert_se(seccomp_restrict_suid_sgid() >= 0); | |
1157 | ||
1158 | assert_se(chmod(path, 0775 | S_ISUID) < 0 && errno == EPERM); | |
1159 | assert_se(chmod(path, 0775 | S_ISGID) < 0 && errno == EPERM); | |
1160 | assert_se(chmod(path, 0775 | S_ISGID | S_ISUID) < 0 && errno == EPERM); | |
1161 | assert_se(chmod(path, 0775) >= 0); | |
1162 | ||
1163 | assert_se(fchmod(fd, 0775 | S_ISUID) < 0 && errno == EPERM); | |
1164 | assert_se(fchmod(fd, 0775 | S_ISGID) < 0 && errno == EPERM); | |
1165 | assert_se(fchmod(fd, 0775 | S_ISGID | S_ISUID) < 0 && errno == EPERM); | |
1166 | assert_se(fchmod(fd, 0775) >= 0); | |
1167 | ||
1168 | assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISUID, 0) < 0 && errno == EPERM); | |
1169 | assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID, 0) < 0 && errno == EPERM); | |
1170 | assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) < 0 && errno == EPERM); | |
1171 | assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0); | |
1172 | ||
8b45281d AM |
1173 | assert_se(try_fchmodat2(AT_FDCWD, path, 0755 | S_ISUID, 0) < 0 && errno == EPERM); |
1174 | assert_se(try_fchmodat2(AT_FDCWD, path, 0755 | S_ISGID, 0) < 0 && errno == EPERM); | |
1175 | assert_se(try_fchmodat2(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) < 0 && errno == EPERM); | |
1176 | assert_se(try_fchmodat2(AT_FDCWD, path, 0755, 0) >= 0); | |
1177 | ||
167fc10c LP |
1178 | assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM); |
1179 | assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM); | |
1180 | assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM); | |
1181 | k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644); | |
1182 | k = safe_close(k); | |
1183 | assert_se(unlink(z) >= 0); | |
1184 | ||
1185 | assert_se(creat(z, 0644 | S_ISUID) < 0 && errno == EPERM); | |
1186 | assert_se(creat(z, 0644 | S_ISGID) < 0 && errno == EPERM); | |
1187 | assert_se(creat(z, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM); | |
1188 | k = creat(z, 0644); | |
1189 | k = safe_close(k); | |
1190 | assert_se(unlink(z) >= 0); | |
1191 | ||
1192 | assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM); | |
1193 | assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM); | |
1194 | assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM); | |
1195 | k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644); | |
1196 | k = safe_close(k); | |
1197 | assert_se(unlink(z) >= 0); | |
1198 | ||
1199 | assert_se(mkdir(z, 0755 | S_ISUID) < 0 && errno == EPERM); | |
1200 | assert_se(mkdir(z, 0755 | S_ISGID) < 0 && errno == EPERM); | |
1201 | assert_se(mkdir(z, 0755 | S_ISUID | S_ISGID) < 0 && errno == EPERM); | |
1202 | assert_se(mkdir(z, 0755) >= 0); | |
1203 | assert_se(rmdir(z) >= 0); | |
1204 | ||
1205 | assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID) < 0 && errno == EPERM); | |
1206 | assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISGID) < 0 && errno == EPERM); | |
1207 | assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID | S_ISGID) < 0 && errno == EPERM); | |
1208 | assert_se(mkdirat(AT_FDCWD, z, 0755) >= 0); | |
1209 | assert_se(rmdir(z) >= 0); | |
1210 | ||
1211 | assert_se(mknod(z, S_IFREG | 0755 | S_ISUID, 0) < 0 && errno == EPERM); | |
1212 | assert_se(mknod(z, S_IFREG | 0755 | S_ISGID, 0) < 0 && errno == EPERM); | |
1213 | assert_se(mknod(z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) < 0 && errno == EPERM); | |
1214 | assert_se(mknod(z, S_IFREG | 0755, 0) >= 0); | |
1215 | assert_se(unlink(z) >= 0); | |
1216 | ||
1217 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID, 0) < 0 && errno == EPERM); | |
1218 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISGID, 0) < 0 && errno == EPERM); | |
1219 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) < 0 && errno == EPERM); | |
1220 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755, 0) >= 0); | |
1221 | assert_se(unlink(z) >= 0); | |
1222 | ||
1223 | assert_se(unlink(path) >= 0); | |
1224 | assert_se(rm_rf(dir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); | |
1225 | ||
1226 | _exit(EXIT_SUCCESS); | |
1227 | } | |
1228 | ||
1229 | assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); | |
1230 | } | |
1231 | ||
4f7452a8 | 1232 | DEFINE_TEST_MAIN(LOG_DEBUG); |