# define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 0
#endif
-static bool have_seccomp_privs(void) {
- 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) */
-}
+#define CHECK_SECCOMP(refuse_container) \
+ if (!is_seccomp_available()) \
+ return (void) log_tests_skipped("Seccomp not available"); \
+ if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) \
+ return (void) log_tests_skipped("Not privileged"); \
+ if (refuse_container && detect_container() > 0) \
+ return (void) log_tests_skipped("Running in container");
TEST(parse_syscall_and_errno) {
_cleanup_free_ char *n = NULL;
}
TEST(filter_sets) {
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
+ int r;
+
+ CHECK_SECCOMP(/* skip_container = */ false);
for (unsigned i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
- pid_t pid;
#if HAVE_VALGRIND_VALGRIND_H
if (RUNNING_ON_VALGRIND && IN_SET(i, SYSCALL_FILTER_SET_DEFAULT, SYSCALL_FILTER_SET_BASIC_IO, SYSCALL_FILTER_SET_SIGNAL)) {
log_info("Testing %s", syscall_filter_sets[i].name);
- pid = fork();
- assert_se(pid >= 0);
-
- if (pid == 0) { /* Child? */
- int fd, r;
+ ASSERT_OK(r = safe_fork("(filter_sets)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
+ int fd;
/* If we look at the default set (or one that includes it), allow-list instead of deny-list */
if (IN_SET(i, SYSCALL_FILTER_SET_DEFAULT,
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check(syscall_filter_sets[i].name, pid, WAIT_LOG) == EXIT_SUCCESS);
}
}
TEST(restrict_namespace) {
char *s = NULL;
unsigned long ul;
- pid_t pid;
+ int r;
- if (!have_namespaces()) {
- log_notice("Testing without namespaces, skipping %s", __func__);
- return;
- }
+ if (!have_namespaces())
+ return (void) log_tests_skipped("Testing without namespaces");
assert_se(namespace_flags_to_string(0, &s) == 0 && isempty(s));
s = mfree(s);
assert_se(namespace_flags_from_string(s, &ul) == 0 && ul == NAMESPACE_FLAGS_ALL);
s = mfree(s);
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping remaining tests in %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping remaining tests in %s", __func__);
- return;
- }
-
- pid = fork();
- assert_se(pid >= 0);
+ CHECK_SECCOMP(/* skip_container = */ false);
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(restrict-namespace)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
assert_se(seccomp_restrict_namespaces(CLONE_NEWNS|CLONE_NEWNET) >= 0);
assert_se(setns(0, 0) == -1);
assert_se(errno == EPERM);
- pid = raw_clone(CLONE_NEWNS);
+ pid_t pid = raw_clone(CLONE_NEWNS);
assert_se(pid >= 0);
if (pid == 0)
_exit(EXIT_SUCCESS);
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check("nsseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
TEST(protect_sysctl) {
- pid_t pid;
- _cleanup_free_ char *seccomp = NULL;
-
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
+ int r;
/* in containers _sysctl() is likely missing anyway */
- if (detect_container() > 0) {
- log_notice("Testing in container, skipping %s", __func__);
- return;
- }
+ CHECK_SECCOMP(/* skip_container = */ true);
+ _cleanup_free_ char *seccomp = NULL;
assert_se(get_proc_field("/proc/self/status", "Seccomp", &seccomp) == 0);
if (!streq(seccomp, "0"))
log_warning("Warning: seccomp filter detected, results may be unreliable for %s", __func__);
- pid = fork();
- assert_se(pid >= 0);
-
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(protect-sysctl)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
#if defined __NR__sysctl && __NR__sysctl >= 0
assert_se(syscall(__NR__sysctl, NULL) < 0);
assert_se(IN_SET(errno, EFAULT, ENOSYS));
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check("sysctlseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
TEST(protect_syslog) {
- pid_t pid;
-
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
+ int r;
/* in containers syslog() is likely missing anyway */
- if (detect_container() > 0) {
- log_notice("Testing in container, skipping %s", __func__);
- return;
- }
-
- pid = fork();
- assert_se(pid >= 0);
+ CHECK_SECCOMP(/* skip_container = */ true);
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(protect-syslog)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
#if defined __NR_syslog && __NR_syslog >= 0
assert_se(syscall(__NR_syslog, -1, NULL, 0) < 0);
assert_se(errno == EINVAL);
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check("syslogseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
TEST(restrict_address_families) {
- pid_t pid;
-
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
+ int r;
- pid = fork();
- assert_se(pid >= 0);
+ CHECK_SECCOMP(/* skip_container = */ false);
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(restrict-address-families)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
int fd;
Set *s;
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check("socketseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
TEST(restrict_realtime) {
- pid_t pid;
-
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
+ int r;
/* in containers RT privs are likely missing anyway */
- if (detect_container() > 0) {
- log_notice("Testing in container, skipping %s", __func__);
- return;
- }
+ CHECK_SECCOMP(/* skip_container = */ true);
- pid = fork();
- assert_se(pid >= 0);
-
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(restrict-realtime)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
/* On some CI environments, the restriction may be already enabled. */
if (sched_setscheduler(0, SCHED_FIFO, &(struct sched_param) { .sched_priority = 1 }) < 0) {
+ if (errno == ENOSYS) {
+ log_tests_skipped("sched_setscheduler() is not available or already filtered");
+ _exit(EXIT_SUCCESS);
+ }
+
log_full_errno(errno == EPERM ? LOG_DEBUG : LOG_WARNING, errno,
"Failed to set scheduler parameter for FIFO: %m");
assert(errno == EPERM);
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check("realtimeseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
TEST(memory_deny_write_execute_mmap) {
- pid_t pid;
+ int r;
+
+ CHECK_SECCOMP(/* skip_container = */ false);
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
#if HAVE_VALGRIND_VALGRIND_H
if (RUNNING_ON_VALGRIND) {
log_notice("Running on valgrind, skipping %s", __func__);
return;
#endif
- pid = fork();
- assert_se(pid >= 0);
-
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(memory_deny_write_execute_mmap)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
void *p;
p = mmap(NULL, page_size(), PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check("memoryseccomp-mmap", pid, WAIT_LOG) == EXIT_SUCCESS);
}
TEST(memory_deny_write_execute_shmat) {
- int shmid;
- pid_t pid;
uint32_t arch;
+ int r, shmid;
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
log_debug("arch %s: SCMP_SYS(mmap) = %d", seccomp_arch_to_string(arch), SCMP_SYS(mmap));
log_debug("arch %s: SCMP_SYS(shmdt) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmdt));
}
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs() || have_effective_cap(CAP_IPC_OWNER) <= 0) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
+ CHECK_SECCOMP(/* skip_container = */ false);
+
#if HAVE_VALGRIND_VALGRIND_H
if (RUNNING_ON_VALGRIND) {
log_notice("Running on valgrind, skipping %s", __func__);
shmid = shmget(IPC_PRIVATE, page_size(), 0);
assert_se(shmid >= 0);
- pid = fork();
- assert_se(pid >= 0);
-
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(memory-deny-write-execute)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
void *p;
p = shmat(shmid, NULL, 0);
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check("memoryseccomp-shmat", pid, WAIT_LOG) == EXIT_SUCCESS);
}
TEST(restrict_archs) {
- pid_t pid;
-
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
+ int r;
- pid = fork();
- assert_se(pid >= 0);
+ CHECK_SECCOMP(/* skip_container = */ false);
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(restrict-archs)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
_cleanup_set_free_ Set *s = NULL;
assert_se(access("/", F_OK) >= 0);
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check("archseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
TEST(load_syscall_filter_set_raw) {
- pid_t pid;
-
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
+ int r;
- pid = fork();
- assert_se(pid >= 0);
+ CHECK_SECCOMP(/* skip_container = */ false);
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(load-filter)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
_cleanup_hashmap_free_ Hashmap *s = NULL;
assert_se(access("/", F_OK) >= 0);
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check("syscallrawseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
TEST(native_syscalls_filtered) {
- pid_t pid;
-
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
+ int r;
- pid = fork();
- assert_se(pid >= 0);
+ CHECK_SECCOMP(/* skip_container = */ false);
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(native-syscalls)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
_cleanup_set_free_ Set *arch_s = NULL;
_cleanup_hashmap_free_ Hashmap *s = NULL;
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check("nativeseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
TEST(lock_personality) {
unsigned long current_opinionated;
- pid_t pid;
+ int r;
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
+ CHECK_SECCOMP(/* skip_container = */ false);
assert_se(opinionated_personality(¤t_opinionated) >= 0);
log_info("current personality=0x%lX", (unsigned long) safe_personality(PERSONALITY_INVALID));
log_info("current opinionated personality=0x%lX", current_opinionated);
- pid = fork();
- assert_se(pid >= 0);
-
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(lock-personality)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
unsigned long current;
assert_se(seccomp_lock_personality(current_opinionated) >= 0);
assert_se((current & OPINIONATED_PERSONALITY_MASK) == current_opinionated);
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check("lockpersonalityseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
static int real_open(const char *path, int flags, mode_t mode) {
}
TEST(restrict_suid_sgid) {
- pid_t pid;
-
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
+ int r;
- pid = fork();
- assert_se(pid >= 0);
+ CHECK_SECCOMP(/* skip_container = */ false);
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(suid-sgid)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
char path[] = "/tmp/suidsgidXXXXXX", dir[] = "/tmp/suidsgiddirXXXXXX";
int fd = -EBADF, k = -EBADF;
const char *z;
_exit(EXIT_SUCCESS);
}
-
- assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
static void test_seccomp_suppress_sync_child(void) {
}
TEST(seccomp_suppress_sync) {
- pid_t pid;
-
- if (!is_seccomp_available()) {
- log_notice("Seccomp not available, skipping %s", __func__);
- return;
- }
- if (!have_seccomp_privs()) {
- log_notice("Not privileged, skipping %s", __func__);
- return;
- }
+ int r;
- ASSERT_OK_ERRNO(pid = fork());
+ CHECK_SECCOMP(/* skip_container = */ false);
- if (pid == 0) {
+ ASSERT_OK(r = safe_fork("(suppress-sync)", FORK_LOG | FORK_WAIT, NULL));
+ if (r == 0) {
test_seccomp_suppress_sync_child();
_exit(EXIT_SUCCESS);
}
-
- ASSERT_EQ(wait_for_terminate_and_check("seccomp_suppress_sync", pid, WAIT_LOG), EXIT_SUCCESS);
}
DEFINE_TEST_MAIN(LOG_DEBUG);