]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-seccomp.c
ASSERT_STREQ for simple cases
[thirdparty/systemd.git] / src / test / test-seccomp.c
CommitLineData
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
46static 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 50TEST(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 108TEST(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 120TEST(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 158TEST(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 169TEST(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 231TEST(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 264TEST(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 365TEST(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 417TEST(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 457TEST(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 544TEST(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 599TEST(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 657TEST(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 730TEST(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 768TEST(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 881TEST(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 939TEST(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(&current_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
996static 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
1008static 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 1026TEST(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 1232DEFINE_TEST_MAIN(LOG_DEBUG);