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