]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
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> | |
f6281133 | 13 | |
add00535 | 14 | #include "alloc-util.h" |
f6281133 LP |
15 | #include "fd-util.h" |
16 | #include "macro.h" | |
0a970718 | 17 | #include "memory-util.h" |
f5947a5e | 18 | #include "missing_sched.h" |
add00535 | 19 | #include "nsflags.h" |
d8b4d14d | 20 | #include "nulstr-util.h" |
f6281133 | 21 | #include "process-util.h" |
add00535 | 22 | #include "raw-clone.h" |
167fc10c | 23 | #include "rm-rf.h" |
f6281133 | 24 | #include "seccomp-util.h" |
469830d1 | 25 | #include "set.h" |
aa34055f | 26 | #include "string-util.h" |
6d7c4033 | 27 | #include "tests.h" |
167fc10c | 28 | #include "tmpfile-util.h" |
469830d1 | 29 | #include "virt.h" |
f6281133 | 30 | |
4df8fe84 | 31 | /* __NR_socket may be invalid due to libseccomp */ |
fb4b0465 | 32 | #if !defined(__NR_socket) || __NR_socket < 0 || defined(__i386__) || defined(__s390x__) || defined(__s390__) |
da1921a5 ZJS |
33 | /* On these archs, socket() is implemented via the socketcall() syscall multiplexer, |
34 | * and we can't restrict it hence via seccomp. */ | |
35 | # define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 1 | |
36 | #else | |
37 | # define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 0 | |
38 | #endif | |
39 | ||
f6281133 LP |
40 | static void test_seccomp_arch_to_string(void) { |
41 | uint32_t a, b; | |
42 | const char *name; | |
43 | ||
f09da7cc ZJS |
44 | log_info("/* %s */", __func__); |
45 | ||
f6281133 LP |
46 | a = seccomp_arch_native(); |
47 | assert_se(a > 0); | |
48 | name = seccomp_arch_to_string(a); | |
49 | assert_se(name); | |
50 | assert_se(seccomp_arch_from_string(name, &b) >= 0); | |
51 | assert_se(a == b); | |
52 | } | |
53 | ||
aa34055f ZJS |
54 | static void test_architecture_table(void) { |
55 | const char *n, *n2; | |
56 | ||
f09da7cc ZJS |
57 | log_info("/* %s */", __func__); |
58 | ||
aa34055f ZJS |
59 | NULSTR_FOREACH(n, |
60 | "native\0" | |
61 | "x86\0" | |
62 | "x86-64\0" | |
63 | "x32\0" | |
64 | "arm\0" | |
65 | "arm64\0" | |
66 | "mips\0" | |
67 | "mips64\0" | |
68 | "mips64-n32\0" | |
69 | "mips-le\0" | |
70 | "mips64-le\0" | |
71 | "mips64-le-n32\0" | |
72 | "ppc\0" | |
73 | "ppc64\0" | |
74 | "ppc64-le\0" | |
75 | "s390\0" | |
76 | "s390x\0") { | |
77 | uint32_t c; | |
78 | ||
79 | assert_se(seccomp_arch_from_string(n, &c) >= 0); | |
80 | n2 = seccomp_arch_to_string(c); | |
81 | log_info("seccomp-arch: %s → 0x%"PRIx32" → %s", n, c, n2); | |
82 | assert_se(streq_ptr(n, n2)); | |
83 | } | |
84 | } | |
85 | ||
f6281133 | 86 | static void test_syscall_filter_set_find(void) { |
f09da7cc ZJS |
87 | log_info("/* %s */", __func__); |
88 | ||
f6281133 LP |
89 | assert_se(!syscall_filter_set_find(NULL)); |
90 | assert_se(!syscall_filter_set_find("")); | |
91 | assert_se(!syscall_filter_set_find("quux")); | |
92 | assert_se(!syscall_filter_set_find("@quux")); | |
93 | ||
94 | assert_se(syscall_filter_set_find("@clock") == syscall_filter_sets + SYSCALL_FILTER_SET_CLOCK); | |
95 | assert_se(syscall_filter_set_find("@default") == syscall_filter_sets + SYSCALL_FILTER_SET_DEFAULT); | |
96 | assert_se(syscall_filter_set_find("@raw-io") == syscall_filter_sets + SYSCALL_FILTER_SET_RAW_IO); | |
97 | } | |
98 | ||
99 | static void test_filter_sets(void) { | |
100 | unsigned i; | |
101 | int r; | |
102 | ||
f09da7cc ZJS |
103 | log_info("/* %s */", __func__); |
104 | ||
cd90ec75 YW |
105 | if (!is_seccomp_available()) { |
106 | log_notice("Seccomp not available, skipping %s", __func__); | |
f6281133 | 107 | return; |
cd90ec75 YW |
108 | } |
109 | if (geteuid() != 0) { | |
110 | log_notice("Not root, skipping %s", __func__); | |
f6281133 | 111 | return; |
cd90ec75 | 112 | } |
f6281133 LP |
113 | |
114 | for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) { | |
115 | pid_t pid; | |
116 | ||
117 | log_info("Testing %s", syscall_filter_sets[i].name); | |
118 | ||
119 | pid = fork(); | |
120 | assert_se(pid >= 0); | |
121 | ||
122 | if (pid == 0) { /* Child? */ | |
123 | int fd; | |
124 | ||
b54f36c6 | 125 | /* If we look at the default set (or one that includes it), whitelist instead of blacklist */ |
70526841 | 126 | if (IN_SET(i, SYSCALL_FILTER_SET_DEFAULT, SYSCALL_FILTER_SET_SYSTEM_SERVICE)) |
b54f36c6 | 127 | r = seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN), syscall_filter_sets + i, SCMP_ACT_ALLOW, true); |
f6281133 | 128 | else |
b54f36c6 | 129 | r = seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + i, SCMP_ACT_ERRNO(EUCLEAN), true); |
f6281133 LP |
130 | if (r < 0) |
131 | _exit(EXIT_FAILURE); | |
132 | ||
133 | /* Test the sycall filter with one random system call */ | |
134 | fd = eventfd(0, EFD_NONBLOCK|EFD_CLOEXEC); | |
135 | if (IN_SET(i, SYSCALL_FILTER_SET_IO_EVENT, SYSCALL_FILTER_SET_DEFAULT)) | |
469830d1 | 136 | assert_se(fd < 0 && errno == EUCLEAN); |
f6281133 LP |
137 | else { |
138 | assert_se(fd >= 0); | |
139 | safe_close(fd); | |
140 | } | |
141 | ||
142 | _exit(EXIT_SUCCESS); | |
143 | } | |
144 | ||
7d4904fe | 145 | assert_se(wait_for_terminate_and_check(syscall_filter_sets[i].name, pid, WAIT_LOG) == EXIT_SUCCESS); |
f6281133 LP |
146 | } |
147 | } | |
148 | ||
23e12f8e ZJS |
149 | static void test_filter_sets_ordered(void) { |
150 | size_t i; | |
151 | ||
f09da7cc ZJS |
152 | log_info("/* %s */", __func__); |
153 | ||
23e12f8e ZJS |
154 | /* Ensure "@default" always remains at the beginning of the list */ |
155 | assert_se(SYSCALL_FILTER_SET_DEFAULT == 0); | |
156 | assert_se(streq(syscall_filter_sets[0].name, "@default")); | |
157 | ||
158 | for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) { | |
159 | const char *k, *p = NULL; | |
160 | ||
161 | /* Make sure each group has a description */ | |
162 | assert_se(!isempty(syscall_filter_sets[0].help)); | |
163 | ||
164 | /* Make sure the groups are ordered alphabetically, except for the first entry */ | |
165 | assert_se(i < 2 || strcmp(syscall_filter_sets[i-1].name, syscall_filter_sets[i].name) < 0); | |
166 | ||
167 | NULSTR_FOREACH(k, syscall_filter_sets[i].value) { | |
168 | ||
169 | /* Ensure each syscall list is in itself ordered, but groups before names */ | |
170 | assert_se(!p || | |
171 | (*p == '@' && *k != '@') || | |
172 | (((*p == '@' && *k == '@') || | |
173 | (*p != '@' && *k != '@')) && | |
174 | strcmp(p, k) < 0)); | |
175 | ||
176 | p = k; | |
177 | } | |
178 | } | |
179 | } | |
180 | ||
add00535 | 181 | static void test_restrict_namespace(void) { |
86c2a9f1 | 182 | char *s = NULL; |
add00535 | 183 | unsigned long ul; |
469830d1 | 184 | pid_t pid; |
add00535 | 185 | |
5f00dc4d LP |
186 | if (!have_namespaces()) { |
187 | log_notice("Testing without namespaces, skipping %s", __func__); | |
188 | return; | |
189 | } | |
190 | ||
f09da7cc ZJS |
191 | log_info("/* %s */", __func__); |
192 | ||
86c2a9f1 YW |
193 | assert_se(namespace_flags_to_string(0, &s) == 0 && streq(s, "")); |
194 | s = mfree(s); | |
195 | assert_se(namespace_flags_to_string(CLONE_NEWNS, &s) == 0 && streq(s, "mnt")); | |
196 | s = mfree(s); | |
197 | assert_se(namespace_flags_to_string(CLONE_NEWNS|CLONE_NEWIPC, &s) == 0 && streq(s, "ipc mnt")); | |
198 | s = mfree(s); | |
199 | assert_se(namespace_flags_to_string(CLONE_NEWCGROUP, &s) == 0 && streq(s, "cgroup")); | |
200 | s = mfree(s); | |
201 | ||
202 | assert_se(namespace_flags_from_string("mnt", &ul) == 0 && ul == CLONE_NEWNS); | |
203 | assert_se(namespace_flags_from_string(NULL, &ul) == 0 && ul == 0); | |
204 | assert_se(namespace_flags_from_string("", &ul) == 0 && ul == 0); | |
205 | assert_se(namespace_flags_from_string("uts", &ul) == 0 && ul == CLONE_NEWUTS); | |
206 | assert_se(namespace_flags_from_string("mnt uts ipc", &ul) == 0 && ul == (CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC)); | |
207 | ||
208 | assert_se(namespace_flags_to_string(CLONE_NEWUTS, &s) == 0 && streq(s, "uts")); | |
209 | assert_se(namespace_flags_from_string(s, &ul) == 0 && ul == CLONE_NEWUTS); | |
210 | s = mfree(s); | |
211 | assert_se(namespace_flags_from_string("ipc", &ul) == 0 && ul == CLONE_NEWIPC); | |
212 | assert_se(namespace_flags_to_string(ul, &s) == 0 && streq(s, "ipc")); | |
213 | s = mfree(s); | |
214 | ||
215 | assert_se(namespace_flags_to_string(NAMESPACE_FLAGS_ALL, &s) == 0); | |
add00535 | 216 | assert_se(streq(s, "cgroup ipc net mnt pid user uts")); |
86c2a9f1 YW |
217 | assert_se(namespace_flags_from_string(s, &ul) == 0 && ul == NAMESPACE_FLAGS_ALL); |
218 | s = mfree(s); | |
add00535 | 219 | |
cd90ec75 YW |
220 | if (!is_seccomp_available()) { |
221 | log_notice("Seccomp not available, skipping remaining tests in %s", __func__); | |
add00535 | 222 | return; |
cd90ec75 YW |
223 | } |
224 | if (geteuid() != 0) { | |
225 | log_notice("Not root, skipping remaining tests in %s", __func__); | |
add00535 | 226 | return; |
cd90ec75 | 227 | } |
add00535 LP |
228 | |
229 | pid = fork(); | |
230 | assert_se(pid >= 0); | |
231 | ||
232 | if (pid == 0) { | |
233 | ||
234 | assert_se(seccomp_restrict_namespaces(CLONE_NEWNS|CLONE_NEWNET) >= 0); | |
235 | ||
236 | assert_se(unshare(CLONE_NEWNS) == 0); | |
237 | assert_se(unshare(CLONE_NEWNET) == 0); | |
238 | assert_se(unshare(CLONE_NEWUTS) == -1); | |
239 | assert_se(errno == EPERM); | |
240 | assert_se(unshare(CLONE_NEWIPC) == -1); | |
241 | assert_se(errno == EPERM); | |
242 | assert_se(unshare(CLONE_NEWNET|CLONE_NEWUTS) == -1); | |
243 | assert_se(errno == EPERM); | |
244 | ||
245 | /* We use fd 0 (stdin) here, which of course will fail with EINVAL on setns(). Except of course our | |
246 | * seccomp filter worked, and hits first and makes it return EPERM */ | |
247 | assert_se(setns(0, CLONE_NEWNS) == -1); | |
248 | assert_se(errno == EINVAL); | |
249 | assert_se(setns(0, CLONE_NEWNET) == -1); | |
250 | assert_se(errno == EINVAL); | |
251 | assert_se(setns(0, CLONE_NEWUTS) == -1); | |
252 | assert_se(errno == EPERM); | |
253 | assert_se(setns(0, CLONE_NEWIPC) == -1); | |
254 | assert_se(errno == EPERM); | |
255 | assert_se(setns(0, CLONE_NEWNET|CLONE_NEWUTS) == -1); | |
256 | assert_se(errno == EPERM); | |
257 | assert_se(setns(0, 0) == -1); | |
258 | assert_se(errno == EPERM); | |
259 | ||
260 | pid = raw_clone(CLONE_NEWNS); | |
261 | assert_se(pid >= 0); | |
262 | if (pid == 0) | |
263 | _exit(EXIT_SUCCESS); | |
264 | pid = raw_clone(CLONE_NEWNET); | |
265 | assert_se(pid >= 0); | |
266 | if (pid == 0) | |
267 | _exit(EXIT_SUCCESS); | |
268 | pid = raw_clone(CLONE_NEWUTS); | |
269 | assert_se(pid < 0); | |
270 | assert_se(errno == EPERM); | |
271 | pid = raw_clone(CLONE_NEWIPC); | |
272 | assert_se(pid < 0); | |
273 | assert_se(errno == EPERM); | |
274 | pid = raw_clone(CLONE_NEWNET|CLONE_NEWUTS); | |
275 | assert_se(pid < 0); | |
276 | assert_se(errno == EPERM); | |
277 | ||
278 | _exit(EXIT_SUCCESS); | |
279 | } | |
280 | ||
7d4904fe | 281 | assert_se(wait_for_terminate_and_check("nsseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
add00535 LP |
282 | } |
283 | ||
469830d1 LP |
284 | static void test_protect_sysctl(void) { |
285 | pid_t pid; | |
286 | ||
f09da7cc ZJS |
287 | log_info("/* %s */", __func__); |
288 | ||
cd90ec75 YW |
289 | if (!is_seccomp_available()) { |
290 | log_notice("Seccomp not available, skipping %s", __func__); | |
469830d1 | 291 | return; |
cd90ec75 YW |
292 | } |
293 | if (geteuid() != 0) { | |
294 | log_notice("Not root, skipping %s", __func__); | |
469830d1 | 295 | return; |
cd90ec75 | 296 | } |
469830d1 | 297 | |
cd90ec75 YW |
298 | /* in containers _sysctl() is likely missing anyway */ |
299 | if (detect_container() > 0) { | |
300 | log_notice("Testing in container, skipping %s", __func__); | |
469830d1 | 301 | return; |
cd90ec75 | 302 | } |
469830d1 LP |
303 | |
304 | pid = fork(); | |
305 | assert_se(pid >= 0); | |
306 | ||
307 | if (pid == 0) { | |
fb4b0465 | 308 | #if defined __NR__sysctl && __NR__sysctl >= 0 |
469830d1 LP |
309 | assert_se(syscall(__NR__sysctl, NULL) < 0); |
310 | assert_se(errno == EFAULT); | |
2e64e8f4 | 311 | #endif |
469830d1 LP |
312 | |
313 | assert_se(seccomp_protect_sysctl() >= 0); | |
314 | ||
fb4b0465 | 315 | #if defined __NR__sysctl && __NR__sysctl >= 0 |
469830d1 LP |
316 | assert_se(syscall(__NR__sysctl, 0, 0, 0) < 0); |
317 | assert_se(errno == EPERM); | |
2e64e8f4 | 318 | #endif |
469830d1 LP |
319 | |
320 | _exit(EXIT_SUCCESS); | |
321 | } | |
322 | ||
7d4904fe | 323 | assert_se(wait_for_terminate_and_check("sysctlseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
469830d1 LP |
324 | } |
325 | ||
97d05f3b KK |
326 | static void test_protect_syslog(void) { |
327 | pid_t pid; | |
328 | ||
329 | log_info("/* %s */", __func__); | |
330 | ||
331 | if (!is_seccomp_available()) { | |
332 | log_notice("Seccomp not available, skipping %s", __func__); | |
333 | return; | |
334 | } | |
335 | if (geteuid() != 0) { | |
336 | log_notice("Not root, skipping %s", __func__); | |
337 | return; | |
338 | } | |
339 | ||
340 | /* in containers syslog() is likely missing anyway */ | |
341 | if (detect_container() > 0) { | |
342 | log_notice("Testing in container, skipping %s", __func__); | |
343 | return; | |
344 | } | |
345 | ||
346 | pid = fork(); | |
347 | assert_se(pid >= 0); | |
348 | ||
349 | if (pid == 0) { | |
fb4b0465 | 350 | #if defined __NR_syslog && __NR_syslog >= 0 |
97d05f3b KK |
351 | assert_se(syscall(__NR_syslog, -1, NULL, 0) < 0); |
352 | assert_se(errno == EINVAL); | |
353 | #endif | |
354 | ||
355 | assert_se(seccomp_protect_syslog() >= 0); | |
356 | ||
fb4b0465 | 357 | #if defined __NR_syslog && __NR_syslog >= 0 |
97d05f3b KK |
358 | assert_se(syscall(__NR_syslog, 0, 0, 0) < 0); |
359 | assert_se(errno == EPERM); | |
360 | #endif | |
361 | ||
362 | _exit(EXIT_SUCCESS); | |
363 | } | |
364 | ||
365 | assert_se(wait_for_terminate_and_check("syslogseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); | |
366 | } | |
367 | ||
469830d1 LP |
368 | static void test_restrict_address_families(void) { |
369 | pid_t pid; | |
370 | ||
f09da7cc ZJS |
371 | log_info("/* %s */", __func__); |
372 | ||
cd90ec75 YW |
373 | if (!is_seccomp_available()) { |
374 | log_notice("Seccomp not available, skipping %s", __func__); | |
469830d1 | 375 | return; |
cd90ec75 YW |
376 | } |
377 | if (geteuid() != 0) { | |
378 | log_notice("Not root, skipping %s", __func__); | |
469830d1 | 379 | return; |
cd90ec75 | 380 | } |
469830d1 LP |
381 | |
382 | pid = fork(); | |
383 | assert_se(pid >= 0); | |
384 | ||
385 | if (pid == 0) { | |
386 | int fd; | |
387 | Set *s; | |
388 | ||
389 | fd = socket(AF_INET, SOCK_DGRAM, 0); | |
390 | assert_se(fd >= 0); | |
391 | safe_close(fd); | |
392 | ||
393 | fd = socket(AF_UNIX, SOCK_DGRAM, 0); | |
394 | assert_se(fd >= 0); | |
395 | safe_close(fd); | |
396 | ||
397 | fd = socket(AF_NETLINK, SOCK_DGRAM, 0); | |
398 | assert_se(fd >= 0); | |
399 | safe_close(fd); | |
400 | ||
401 | assert_se(s = set_new(NULL)); | |
402 | assert_se(set_put(s, INT_TO_PTR(AF_UNIX)) >= 0); | |
403 | ||
404 | assert_se(seccomp_restrict_address_families(s, false) >= 0); | |
405 | ||
406 | fd = socket(AF_INET, SOCK_DGRAM, 0); | |
407 | assert_se(fd >= 0); | |
408 | safe_close(fd); | |
409 | ||
ad8f1479 | 410 | fd = socket(AF_UNIX, SOCK_DGRAM, 0); |
dce0e620 | 411 | #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN |
ad8f1479 LP |
412 | assert_se(fd >= 0); |
413 | safe_close(fd); | |
414 | #else | |
dce0e620 | 415 | assert_se(fd < 0); |
469830d1 | 416 | assert_se(errno == EAFNOSUPPORT); |
ad8f1479 | 417 | #endif |
469830d1 LP |
418 | |
419 | fd = socket(AF_NETLINK, SOCK_DGRAM, 0); | |
420 | assert_se(fd >= 0); | |
421 | safe_close(fd); | |
422 | ||
423 | set_clear(s); | |
424 | ||
425 | assert_se(set_put(s, INT_TO_PTR(AF_INET)) >= 0); | |
426 | ||
427 | assert_se(seccomp_restrict_address_families(s, true) >= 0); | |
428 | ||
429 | fd = socket(AF_INET, SOCK_DGRAM, 0); | |
430 | assert_se(fd >= 0); | |
431 | safe_close(fd); | |
432 | ||
ad8f1479 | 433 | fd = socket(AF_UNIX, SOCK_DGRAM, 0); |
dce0e620 | 434 | #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN |
ad8f1479 LP |
435 | assert_se(fd >= 0); |
436 | safe_close(fd); | |
dce0e620 ZJS |
437 | #else |
438 | assert_se(fd < 0); | |
439 | assert_se(errno == EAFNOSUPPORT); | |
440 | #endif | |
ad8f1479 LP |
441 | |
442 | fd = socket(AF_NETLINK, SOCK_DGRAM, 0); | |
dce0e620 | 443 | #if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN |
ad8f1479 LP |
444 | assert_se(fd >= 0); |
445 | safe_close(fd); | |
446 | #else | |
dce0e620 | 447 | assert_se(fd < 0); |
469830d1 | 448 | assert_se(errno == EAFNOSUPPORT); |
ad8f1479 | 449 | #endif |
469830d1 LP |
450 | |
451 | _exit(EXIT_SUCCESS); | |
452 | } | |
453 | ||
7d4904fe | 454 | assert_se(wait_for_terminate_and_check("socketseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
469830d1 LP |
455 | } |
456 | ||
457 | static void test_restrict_realtime(void) { | |
458 | pid_t pid; | |
459 | ||
f09da7cc ZJS |
460 | log_info("/* %s */", __func__); |
461 | ||
cd90ec75 YW |
462 | if (!is_seccomp_available()) { |
463 | log_notice("Seccomp not available, skipping %s", __func__); | |
469830d1 | 464 | return; |
cd90ec75 YW |
465 | } |
466 | if (geteuid() != 0) { | |
467 | log_notice("Not root, skipping %s", __func__); | |
469830d1 | 468 | return; |
cd90ec75 | 469 | } |
469830d1 | 470 | |
cd90ec75 YW |
471 | /* in containers RT privs are likely missing anyway */ |
472 | if (detect_container() > 0) { | |
473 | log_notice("Testing in container, skipping %s", __func__); | |
469830d1 | 474 | return; |
cd90ec75 | 475 | } |
469830d1 LP |
476 | |
477 | pid = fork(); | |
478 | assert_se(pid >= 0); | |
479 | ||
480 | if (pid == 0) { | |
481 | assert_se(sched_setscheduler(0, SCHED_FIFO, &(struct sched_param) { .sched_priority = 1 }) >= 0); | |
482 | assert_se(sched_setscheduler(0, SCHED_RR, &(struct sched_param) { .sched_priority = 1 }) >= 0); | |
483 | assert_se(sched_setscheduler(0, SCHED_IDLE, &(struct sched_param) { .sched_priority = 0 }) >= 0); | |
484 | assert_se(sched_setscheduler(0, SCHED_BATCH, &(struct sched_param) { .sched_priority = 0 }) >= 0); | |
485 | assert_se(sched_setscheduler(0, SCHED_OTHER, &(struct sched_param) {}) >= 0); | |
486 | ||
487 | assert_se(seccomp_restrict_realtime() >= 0); | |
488 | ||
489 | assert_se(sched_setscheduler(0, SCHED_IDLE, &(struct sched_param) { .sched_priority = 0 }) >= 0); | |
490 | assert_se(sched_setscheduler(0, SCHED_BATCH, &(struct sched_param) { .sched_priority = 0 }) >= 0); | |
491 | assert_se(sched_setscheduler(0, SCHED_OTHER, &(struct sched_param) {}) >= 0); | |
492 | ||
493 | assert_se(sched_setscheduler(0, SCHED_FIFO, &(struct sched_param) { .sched_priority = 1 }) < 0); | |
494 | assert_se(errno == EPERM); | |
495 | assert_se(sched_setscheduler(0, SCHED_RR, &(struct sched_param) { .sched_priority = 1 }) < 0); | |
496 | assert_se(errno == EPERM); | |
497 | ||
498 | _exit(EXIT_SUCCESS); | |
499 | } | |
500 | ||
7d4904fe | 501 | assert_se(wait_for_terminate_and_check("realtimeseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
469830d1 LP |
502 | } |
503 | ||
2a65bd94 | 504 | static void test_memory_deny_write_execute_mmap(void) { |
469830d1 LP |
505 | pid_t pid; |
506 | ||
f09da7cc ZJS |
507 | log_info("/* %s */", __func__); |
508 | ||
cd90ec75 YW |
509 | if (!is_seccomp_available()) { |
510 | log_notice("Seccomp not available, skipping %s", __func__); | |
469830d1 | 511 | return; |
cd90ec75 YW |
512 | } |
513 | if (geteuid() != 0) { | |
514 | log_notice("Not root, skipping %s", __func__); | |
469830d1 | 515 | return; |
cd90ec75 | 516 | } |
469830d1 LP |
517 | |
518 | pid = fork(); | |
519 | assert_se(pid >= 0); | |
520 | ||
521 | if (pid == 0) { | |
522 | void *p; | |
523 | ||
524 | p = mmap(NULL, page_size(), PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1,0); | |
525 | assert_se(p != MAP_FAILED); | |
526 | assert_se(munmap(p, page_size()) >= 0); | |
527 | ||
8a50cf69 LP |
528 | p = mmap(NULL, page_size(), PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1,0); |
529 | assert_se(p != MAP_FAILED); | |
530 | assert_se(munmap(p, page_size()) >= 0); | |
469830d1 | 531 | |
8a50cf69 LP |
532 | assert_se(seccomp_memory_deny_write_execute() >= 0); |
533 | ||
8a50cf69 | 534 | p = mmap(NULL, page_size(), PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1,0); |
4278d1f5 | 535 | #if defined(__x86_64__) || defined(__i386__) || defined(__powerpc64__) || defined(__arm__) || defined(__aarch64__) |
469830d1 LP |
536 | assert_se(p == MAP_FAILED); |
537 | assert_se(errno == EPERM); | |
8a50cf69 | 538 | #endif |
49219b5c CE |
539 | /* Depending on kernel, libseccomp, and glibc versions, other architectures |
540 | * might fail or not. Let's not assert success. */ | |
541 | if (p != MAP_FAILED) | |
542 | assert_se(munmap(p, page_size()) == 0); | |
469830d1 LP |
543 | |
544 | p = mmap(NULL, page_size(), PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1,0); | |
545 | assert_se(p != MAP_FAILED); | |
546 | assert_se(munmap(p, page_size()) >= 0); | |
547 | ||
548 | _exit(EXIT_SUCCESS); | |
549 | } | |
550 | ||
7d4904fe | 551 | assert_se(wait_for_terminate_and_check("memoryseccomp-mmap", pid, WAIT_LOG) == EXIT_SUCCESS); |
2a65bd94 ZJS |
552 | } |
553 | ||
554 | static void test_memory_deny_write_execute_shmat(void) { | |
555 | int shmid; | |
556 | pid_t pid; | |
e55bdf9b | 557 | uint32_t arch; |
2a65bd94 | 558 | |
f09da7cc ZJS |
559 | log_info("/* %s */", __func__); |
560 | ||
e55bdf9b ZJS |
561 | SECCOMP_FOREACH_LOCAL_ARCH(arch) { |
562 | log_debug("arch %s: SCMP_SYS(mmap) = %d", seccomp_arch_to_string(arch), SCMP_SYS(mmap)); | |
563 | log_debug("arch %s: SCMP_SYS(mmap2) = %d", seccomp_arch_to_string(arch), SCMP_SYS(mmap2)); | |
564 | log_debug("arch %s: SCMP_SYS(shmget) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmget)); | |
565 | log_debug("arch %s: SCMP_SYS(shmat) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmat)); | |
566 | log_debug("arch %s: SCMP_SYS(shmdt) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmdt)); | |
567 | } | |
568 | ||
cd90ec75 YW |
569 | if (!is_seccomp_available()) { |
570 | log_notice("Seccomp not available, skipping %s", __func__); | |
2a65bd94 | 571 | return; |
cd90ec75 YW |
572 | } |
573 | if (geteuid() != 0) { | |
574 | log_notice("Not root, skipping %s", __func__); | |
2a65bd94 | 575 | return; |
cd90ec75 | 576 | } |
2a65bd94 ZJS |
577 | |
578 | shmid = shmget(IPC_PRIVATE, page_size(), 0); | |
579 | assert_se(shmid >= 0); | |
580 | ||
581 | pid = fork(); | |
582 | assert_se(pid >= 0); | |
583 | ||
584 | if (pid == 0) { | |
585 | void *p; | |
586 | ||
587 | p = shmat(shmid, NULL, 0); | |
588 | assert_se(p != MAP_FAILED); | |
589 | assert_se(shmdt(p) == 0); | |
590 | ||
591 | p = shmat(shmid, NULL, SHM_EXEC); | |
592 | assert_se(p != MAP_FAILED); | |
593 | assert_se(shmdt(p) == 0); | |
594 | ||
595 | assert_se(seccomp_memory_deny_write_execute() >= 0); | |
596 | ||
597 | p = shmat(shmid, NULL, SHM_EXEC); | |
67fb5f33 | 598 | log_debug_errno(p == MAP_FAILED ? errno : 0, "shmat(SHM_EXEC): %m"); |
4278d1f5 | 599 | #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) |
2a65bd94 ZJS |
600 | assert_se(p == MAP_FAILED); |
601 | assert_se(errno == EPERM); | |
2a65bd94 | 602 | #endif |
67fb5f33 ZJS |
603 | /* Depending on kernel, libseccomp, and glibc versions, other architectures |
604 | * might fail or not. Let's not assert success. */ | |
605 | if (p != MAP_FAILED) | |
606 | assert_se(shmdt(p) == 0); | |
2a65bd94 ZJS |
607 | |
608 | p = shmat(shmid, NULL, 0); | |
67fb5f33 | 609 | log_debug_errno(p == MAP_FAILED ? errno : 0, "shmat(0): %m"); |
2a65bd94 ZJS |
610 | assert_se(p != MAP_FAILED); |
611 | assert_se(shmdt(p) == 0); | |
612 | ||
613 | _exit(EXIT_SUCCESS); | |
614 | } | |
615 | ||
7d4904fe | 616 | assert_se(wait_for_terminate_and_check("memoryseccomp-shmat", pid, WAIT_LOG) == EXIT_SUCCESS); |
469830d1 LP |
617 | } |
618 | ||
619 | static void test_restrict_archs(void) { | |
620 | pid_t pid; | |
621 | ||
f09da7cc ZJS |
622 | log_info("/* %s */", __func__); |
623 | ||
cd90ec75 YW |
624 | if (!is_seccomp_available()) { |
625 | log_notice("Seccomp not available, skipping %s", __func__); | |
469830d1 | 626 | return; |
cd90ec75 YW |
627 | } |
628 | if (geteuid() != 0) { | |
629 | log_notice("Not root, skipping %s", __func__); | |
469830d1 | 630 | return; |
cd90ec75 | 631 | } |
469830d1 LP |
632 | |
633 | pid = fork(); | |
634 | assert_se(pid >= 0); | |
635 | ||
636 | if (pid == 0) { | |
637 | _cleanup_set_free_ Set *s = NULL; | |
638 | ||
639 | assert_se(access("/", F_OK) >= 0); | |
640 | ||
641 | assert_se(s = set_new(NULL)); | |
642 | ||
643 | #ifdef __x86_64__ | |
644 | assert_se(set_put(s, UINT32_TO_PTR(SCMP_ARCH_X86+1)) >= 0); | |
645 | #endif | |
646 | assert_se(seccomp_restrict_archs(s) >= 0); | |
647 | ||
648 | assert_se(access("/", F_OK) >= 0); | |
649 | assert_se(seccomp_restrict_archs(NULL) >= 0); | |
650 | ||
651 | assert_se(access("/", F_OK) >= 0); | |
652 | ||
653 | _exit(EXIT_SUCCESS); | |
654 | } | |
655 | ||
7d4904fe | 656 | assert_se(wait_for_terminate_and_check("archseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
469830d1 LP |
657 | } |
658 | ||
659 | static void test_load_syscall_filter_set_raw(void) { | |
660 | pid_t pid; | |
661 | ||
f09da7cc ZJS |
662 | log_info("/* %s */", __func__); |
663 | ||
cd90ec75 YW |
664 | if (!is_seccomp_available()) { |
665 | log_notice("Seccomp not available, skipping %s", __func__); | |
469830d1 | 666 | return; |
cd90ec75 YW |
667 | } |
668 | if (geteuid() != 0) { | |
669 | log_notice("Not root, skipping %s", __func__); | |
469830d1 | 670 | return; |
cd90ec75 | 671 | } |
469830d1 LP |
672 | |
673 | pid = fork(); | |
674 | assert_se(pid >= 0); | |
675 | ||
676 | if (pid == 0) { | |
b4891260 | 677 | _cleanup_hashmap_free_ Hashmap *s = NULL; |
469830d1 LP |
678 | |
679 | assert_se(access("/", F_OK) >= 0); | |
680 | assert_se(poll(NULL, 0, 0) == 0); | |
681 | ||
7bbc229c | 682 | assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, scmp_act_kill_process(), true) >= 0); |
469830d1 LP |
683 | assert_se(access("/", F_OK) >= 0); |
684 | assert_se(poll(NULL, 0, 0) == 0); | |
685 | ||
b4891260 | 686 | assert_se(s = hashmap_new(NULL)); |
fb4b0465 | 687 | #if defined __NR_access && __NR_access >= 0 |
b4891260 | 688 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_access + 1), INT_TO_PTR(-1)) >= 0); |
f60a865a | 689 | #else |
b4891260 | 690 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(-1)) >= 0); |
f60a865a | 691 | #endif |
469830d1 | 692 | |
b54f36c6 | 693 | assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN), true) >= 0); |
469830d1 LP |
694 | |
695 | assert_se(access("/", F_OK) < 0); | |
696 | assert_se(errno == EUCLEAN); | |
697 | ||
698 | assert_se(poll(NULL, 0, 0) == 0); | |
699 | ||
b4891260 | 700 | s = hashmap_free(s); |
469830d1 | 701 | |
b4891260 | 702 | assert_se(s = hashmap_new(NULL)); |
fb4b0465 | 703 | #if defined __NR_access && __NR_access >= 0 |
b4891260 YW |
704 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_access + 1), INT_TO_PTR(EILSEQ)) >= 0); |
705 | #else | |
706 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(EILSEQ)) >= 0); | |
707 | #endif | |
708 | ||
b54f36c6 | 709 | assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN), true) >= 0); |
b4891260 YW |
710 | |
711 | assert_se(access("/", F_OK) < 0); | |
712 | assert_se(errno == EILSEQ); | |
713 | ||
714 | assert_se(poll(NULL, 0, 0) == 0); | |
715 | ||
716 | s = hashmap_free(s); | |
717 | ||
718 | assert_se(s = hashmap_new(NULL)); | |
fb4b0465 | 719 | #if defined __NR_poll && __NR_poll >= 0 |
b4891260 | 720 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_poll + 1), INT_TO_PTR(-1)) >= 0); |
f60a865a | 721 | #else |
b4891260 | 722 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(-1)) >= 0); |
f60a865a | 723 | #endif |
469830d1 | 724 | |
b54f36c6 | 725 | assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH), true) >= 0); |
469830d1 LP |
726 | |
727 | assert_se(access("/", F_OK) < 0); | |
b4891260 | 728 | assert_se(errno == EILSEQ); |
469830d1 LP |
729 | |
730 | assert_se(poll(NULL, 0, 0) < 0); | |
731 | assert_se(errno == EUNATCH); | |
732 | ||
b4891260 YW |
733 | s = hashmap_free(s); |
734 | ||
735 | assert_se(s = hashmap_new(NULL)); | |
fb4b0465 | 736 | #if defined __NR_poll && __NR_poll >= 0 |
b4891260 YW |
737 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_poll + 1), INT_TO_PTR(EILSEQ)) >= 0); |
738 | #else | |
739 | assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(EILSEQ)) >= 0); | |
740 | #endif | |
741 | ||
b54f36c6 | 742 | assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH), true) >= 0); |
b4891260 YW |
743 | |
744 | assert_se(access("/", F_OK) < 0); | |
745 | assert_se(errno == EILSEQ); | |
746 | ||
747 | assert_se(poll(NULL, 0, 0) < 0); | |
748 | assert_se(errno == EILSEQ); | |
749 | ||
469830d1 LP |
750 | _exit(EXIT_SUCCESS); |
751 | } | |
752 | ||
7d4904fe | 753 | assert_se(wait_for_terminate_and_check("syscallrawseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
469830d1 LP |
754 | } |
755 | ||
78e864e5 | 756 | static void test_lock_personality(void) { |
e8132d63 | 757 | unsigned long current; |
78e864e5 TM |
758 | pid_t pid; |
759 | ||
f09da7cc ZJS |
760 | log_info("/* %s */", __func__); |
761 | ||
cd90ec75 YW |
762 | if (!is_seccomp_available()) { |
763 | log_notice("Seccomp not available, skipping %s", __func__); | |
78e864e5 | 764 | return; |
cd90ec75 YW |
765 | } |
766 | if (geteuid() != 0) { | |
767 | log_notice("Not root, skipping %s", __func__); | |
78e864e5 | 768 | return; |
cd90ec75 | 769 | } |
78e864e5 | 770 | |
e8132d63 LP |
771 | assert_se(opinionated_personality(¤t) >= 0); |
772 | ||
773 | log_info("current personality=%lu", current); | |
774 | ||
78e864e5 TM |
775 | pid = fork(); |
776 | assert_se(pid >= 0); | |
777 | ||
778 | if (pid == 0) { | |
e8132d63 | 779 | assert_se(seccomp_lock_personality(current) >= 0); |
78e864e5 | 780 | |
21022b9d | 781 | assert_se((unsigned long) safe_personality(current) == current); |
e8132d63 | 782 | |
21022b9d LP |
783 | /* Note, we also test that safe_personality() works correctly, by checkig whether errno is properly |
784 | * set, in addition to the return value */ | |
785 | errno = 0; | |
786 | assert_se(safe_personality(PER_LINUX | ADDR_NO_RANDOMIZE) == -EPERM); | |
787 | assert_se(errno == EPERM); | |
e8132d63 | 788 | |
21022b9d LP |
789 | assert_se(safe_personality(PER_LINUX | MMAP_PAGE_ZERO) == -EPERM); |
790 | assert_se(safe_personality(PER_LINUX | ADDR_COMPAT_LAYOUT) == -EPERM); | |
791 | assert_se(safe_personality(PER_LINUX | READ_IMPLIES_EXEC) == -EPERM); | |
792 | assert_se(safe_personality(PER_LINUX_32BIT) == -EPERM); | |
793 | assert_se(safe_personality(PER_SVR4) == -EPERM); | |
794 | assert_se(safe_personality(PER_BSD) == -EPERM); | |
795 | assert_se(safe_personality(current == PER_LINUX ? PER_LINUX32 : PER_LINUX) == -EPERM); | |
796 | assert_se(safe_personality(PER_LINUX32_3GB) == -EPERM); | |
797 | assert_se(safe_personality(PER_UW7) == -EPERM); | |
798 | assert_se(safe_personality(0x42) == -EPERM); | |
799 | ||
800 | assert_se(safe_personality(PERSONALITY_INVALID) == -EPERM); /* maybe remove this later */ | |
e8132d63 LP |
801 | |
802 | assert_se((unsigned long) personality(current) == current); | |
78e864e5 TM |
803 | _exit(EXIT_SUCCESS); |
804 | } | |
805 | ||
7d4904fe | 806 | assert_se(wait_for_terminate_and_check("lockpersonalityseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); |
78e864e5 TM |
807 | } |
808 | ||
167fc10c LP |
809 | static int real_open(const char *path, int flags, mode_t mode) { |
810 | /* glibc internally calls openat() when open() is requested. Let's hence define our own wrapper for | |
dff6c629 ZJS |
811 | * testing purposes that calls the real syscall, on architectures where SYS_open is defined. On |
812 | * other architectures, let's just fall back to the glibc call. */ | |
167fc10c | 813 | |
fb4b0465 | 814 | #if defined __NR_open && __NR_open >= 0 |
4df8fe84 | 815 | return (int) syscall(__NR_open, path, flags, mode); |
dff6c629 ZJS |
816 | #else |
817 | return open(path, flags, mode); | |
818 | #endif | |
167fc10c LP |
819 | } |
820 | ||
821 | static void test_restrict_suid_sgid(void) { | |
822 | pid_t pid; | |
823 | ||
824 | log_info("/* %s */", __func__); | |
825 | ||
826 | if (!is_seccomp_available()) { | |
827 | log_notice("Seccomp not available, skipping %s", __func__); | |
828 | return; | |
829 | } | |
830 | if (geteuid() != 0) { | |
831 | log_notice("Not root, skipping %s", __func__); | |
832 | return; | |
833 | } | |
834 | ||
835 | pid = fork(); | |
836 | assert_se(pid >= 0); | |
837 | ||
838 | if (pid == 0) { | |
839 | char path[] = "/tmp/suidsgidXXXXXX", dir[] = "/tmp/suidsgiddirXXXXXX"; | |
840 | int fd = -1, k = -1; | |
841 | const char *z; | |
842 | ||
843 | fd = mkostemp_safe(path); | |
844 | assert_se(fd >= 0); | |
845 | ||
846 | assert_se(mkdtemp(dir)); | |
847 | z = strjoina(dir, "/test"); | |
848 | ||
849 | assert_se(chmod(path, 0755 | S_ISUID) >= 0); | |
850 | assert_se(chmod(path, 0755 | S_ISGID) >= 0); | |
851 | assert_se(chmod(path, 0755 | S_ISGID | S_ISUID) >= 0); | |
852 | assert_se(chmod(path, 0755) >= 0); | |
853 | ||
854 | assert_se(fchmod(fd, 0755 | S_ISUID) >= 0); | |
855 | assert_se(fchmod(fd, 0755 | S_ISGID) >= 0); | |
856 | assert_se(fchmod(fd, 0755 | S_ISGID | S_ISUID) >= 0); | |
857 | assert_se(fchmod(fd, 0755) >= 0); | |
858 | ||
859 | assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISUID, 0) >= 0); | |
860 | assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID, 0) >= 0); | |
861 | assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) >= 0); | |
862 | assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0); | |
863 | ||
864 | k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID); | |
865 | k = safe_close(k); | |
866 | assert_se(unlink(z) >= 0); | |
867 | ||
868 | k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID); | |
869 | k = safe_close(k); | |
870 | assert_se(unlink(z) >= 0); | |
871 | ||
872 | k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID); | |
873 | k = safe_close(k); | |
874 | assert_se(unlink(z) >= 0); | |
875 | ||
876 | k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644); | |
877 | k = safe_close(k); | |
878 | assert_se(unlink(z) >= 0); | |
879 | ||
880 | k = creat(z, 0644 | S_ISUID); | |
881 | k = safe_close(k); | |
882 | assert_se(unlink(z) >= 0); | |
883 | ||
884 | k = creat(z, 0644 | S_ISGID); | |
885 | k = safe_close(k); | |
886 | assert_se(unlink(z) >= 0); | |
887 | ||
888 | k = creat(z, 0644 | S_ISUID | S_ISGID); | |
889 | k = safe_close(k); | |
890 | assert_se(unlink(z) >= 0); | |
891 | ||
892 | k = creat(z, 0644); | |
893 | k = safe_close(k); | |
894 | assert_se(unlink(z) >= 0); | |
895 | ||
896 | k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID); | |
897 | k = safe_close(k); | |
898 | assert_se(unlink(z) >= 0); | |
899 | ||
900 | k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID); | |
901 | k = safe_close(k); | |
902 | assert_se(unlink(z) >= 0); | |
903 | ||
904 | k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID); | |
905 | k = safe_close(k); | |
906 | assert_se(unlink(z) >= 0); | |
907 | ||
908 | k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644); | |
909 | k = safe_close(k); | |
910 | assert_se(unlink(z) >= 0); | |
911 | ||
912 | assert_se(mkdir(z, 0755 | S_ISUID) >= 0); | |
913 | assert_se(rmdir(z) >= 0); | |
914 | assert_se(mkdir(z, 0755 | S_ISGID) >= 0); | |
915 | assert_se(rmdir(z) >= 0); | |
916 | assert_se(mkdir(z, 0755 | S_ISUID | S_ISGID) >= 0); | |
917 | assert_se(rmdir(z) >= 0); | |
918 | assert_se(mkdir(z, 0755) >= 0); | |
919 | assert_se(rmdir(z) >= 0); | |
920 | ||
921 | assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID) >= 0); | |
922 | assert_se(rmdir(z) >= 0); | |
923 | assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISGID) >= 0); | |
924 | assert_se(rmdir(z) >= 0); | |
925 | assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID | S_ISGID) >= 0); | |
926 | assert_se(rmdir(z) >= 0); | |
927 | assert_se(mkdirat(AT_FDCWD, z, 0755) >= 0); | |
928 | assert_se(rmdir(z) >= 0); | |
929 | ||
930 | assert_se(mknod(z, S_IFREG | 0755 | S_ISUID, 0) >= 0); | |
931 | assert_se(unlink(z) >= 0); | |
932 | assert_se(mknod(z, S_IFREG | 0755 | S_ISGID, 0) >= 0); | |
933 | assert_se(unlink(z) >= 0); | |
934 | assert_se(mknod(z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) >= 0); | |
935 | assert_se(unlink(z) >= 0); | |
936 | assert_se(mknod(z, S_IFREG | 0755, 0) >= 0); | |
937 | assert_se(unlink(z) >= 0); | |
938 | ||
939 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID, 0) >= 0); | |
940 | assert_se(unlink(z) >= 0); | |
941 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISGID, 0) >= 0); | |
942 | assert_se(unlink(z) >= 0); | |
943 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) >= 0); | |
944 | assert_se(unlink(z) >= 0); | |
945 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755, 0) >= 0); | |
946 | assert_se(unlink(z) >= 0); | |
947 | ||
948 | assert_se(seccomp_restrict_suid_sgid() >= 0); | |
949 | ||
950 | assert_se(chmod(path, 0775 | S_ISUID) < 0 && errno == EPERM); | |
951 | assert_se(chmod(path, 0775 | S_ISGID) < 0 && errno == EPERM); | |
952 | assert_se(chmod(path, 0775 | S_ISGID | S_ISUID) < 0 && errno == EPERM); | |
953 | assert_se(chmod(path, 0775) >= 0); | |
954 | ||
955 | assert_se(fchmod(fd, 0775 | S_ISUID) < 0 && errno == EPERM); | |
956 | assert_se(fchmod(fd, 0775 | S_ISGID) < 0 && errno == EPERM); | |
957 | assert_se(fchmod(fd, 0775 | S_ISGID | S_ISUID) < 0 && errno == EPERM); | |
958 | assert_se(fchmod(fd, 0775) >= 0); | |
959 | ||
960 | assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISUID, 0) < 0 && errno == EPERM); | |
961 | assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID, 0) < 0 && errno == EPERM); | |
962 | assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) < 0 && errno == EPERM); | |
963 | assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0); | |
964 | ||
965 | assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM); | |
966 | assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM); | |
967 | assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM); | |
968 | k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644); | |
969 | k = safe_close(k); | |
970 | assert_se(unlink(z) >= 0); | |
971 | ||
972 | assert_se(creat(z, 0644 | S_ISUID) < 0 && errno == EPERM); | |
973 | assert_se(creat(z, 0644 | S_ISGID) < 0 && errno == EPERM); | |
974 | assert_se(creat(z, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM); | |
975 | k = creat(z, 0644); | |
976 | k = safe_close(k); | |
977 | assert_se(unlink(z) >= 0); | |
978 | ||
979 | assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM); | |
980 | assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM); | |
981 | assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM); | |
982 | k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644); | |
983 | k = safe_close(k); | |
984 | assert_se(unlink(z) >= 0); | |
985 | ||
986 | assert_se(mkdir(z, 0755 | S_ISUID) < 0 && errno == EPERM); | |
987 | assert_se(mkdir(z, 0755 | S_ISGID) < 0 && errno == EPERM); | |
988 | assert_se(mkdir(z, 0755 | S_ISUID | S_ISGID) < 0 && errno == EPERM); | |
989 | assert_se(mkdir(z, 0755) >= 0); | |
990 | assert_se(rmdir(z) >= 0); | |
991 | ||
992 | assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID) < 0 && errno == EPERM); | |
993 | assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISGID) < 0 && errno == EPERM); | |
994 | assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID | S_ISGID) < 0 && errno == EPERM); | |
995 | assert_se(mkdirat(AT_FDCWD, z, 0755) >= 0); | |
996 | assert_se(rmdir(z) >= 0); | |
997 | ||
998 | assert_se(mknod(z, S_IFREG | 0755 | S_ISUID, 0) < 0 && errno == EPERM); | |
999 | assert_se(mknod(z, S_IFREG | 0755 | S_ISGID, 0) < 0 && errno == EPERM); | |
1000 | assert_se(mknod(z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) < 0 && errno == EPERM); | |
1001 | assert_se(mknod(z, S_IFREG | 0755, 0) >= 0); | |
1002 | assert_se(unlink(z) >= 0); | |
1003 | ||
1004 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID, 0) < 0 && errno == EPERM); | |
1005 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISGID, 0) < 0 && errno == EPERM); | |
1006 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) < 0 && errno == EPERM); | |
1007 | assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755, 0) >= 0); | |
1008 | assert_se(unlink(z) >= 0); | |
1009 | ||
1010 | assert_se(unlink(path) >= 0); | |
1011 | assert_se(rm_rf(dir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); | |
1012 | ||
1013 | _exit(EXIT_SUCCESS); | |
1014 | } | |
1015 | ||
1016 | assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); | |
1017 | } | |
1018 | ||
f6281133 | 1019 | int main(int argc, char *argv[]) { |
6d7c4033 | 1020 | test_setup_logging(LOG_DEBUG); |
add00535 | 1021 | |
f6281133 | 1022 | test_seccomp_arch_to_string(); |
aa34055f | 1023 | test_architecture_table(); |
f6281133 LP |
1024 | test_syscall_filter_set_find(); |
1025 | test_filter_sets(); | |
23e12f8e | 1026 | test_filter_sets_ordered(); |
add00535 | 1027 | test_restrict_namespace(); |
469830d1 | 1028 | test_protect_sysctl(); |
97d05f3b | 1029 | test_protect_syslog(); |
469830d1 LP |
1030 | test_restrict_address_families(); |
1031 | test_restrict_realtime(); | |
2a65bd94 ZJS |
1032 | test_memory_deny_write_execute_mmap(); |
1033 | test_memory_deny_write_execute_shmat(); | |
469830d1 LP |
1034 | test_restrict_archs(); |
1035 | test_load_syscall_filter_set_raw(); | |
78e864e5 | 1036 | test_lock_personality(); |
167fc10c | 1037 | test_restrict_suid_sgid(); |
f6281133 LP |
1038 | |
1039 | return 0; | |
1040 | } |