From: Yu Watanabe Date: Sat, 6 Sep 2025 19:50:04 +0000 (+0900) Subject: test-seccomp-util: several cleanups X-Git-Tag: v259-rc1~535^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=abd0eb20e430eb9e7f1e422eb7500748540194c7;p=thirdparty%2Fsystemd.git test-seccomp-util: several cleanups - use safe_fork() with FORK_WAIT - introduce CHECK_SECCOMP() macro about common checks, - ignore ENOSYS from sched_setscheduler(). --- diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c index a1230ec27ca..13c65a93cda 100644 --- a/src/test/test-seccomp.c +++ b/src/test/test-seccomp.c @@ -42,9 +42,13 @@ # 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; @@ -166,17 +170,11 @@ TEST(syscall_filter_set_find) { } 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)) { @@ -195,11 +193,9 @@ TEST(filter_sets) { 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, @@ -222,8 +218,6 @@ TEST(filter_sets) { _exit(EXIT_SUCCESS); } - - assert_se(wait_for_terminate_and_check(syscall_filter_sets[i].name, pid, WAIT_LOG) == EXIT_SUCCESS); } } @@ -263,12 +257,10 @@ TEST(filter_sets_ordered) { 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); @@ -297,19 +289,10 @@ TEST(restrict_namespace) { 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); @@ -337,7 +320,7 @@ TEST(restrict_namespace) { 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); @@ -357,37 +340,21 @@ TEST(restrict_namespace) { _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)); @@ -409,32 +376,16 @@ TEST(protect_sysctl) { _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); @@ -449,26 +400,15 @@ TEST(protect_syslog) { _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; @@ -536,34 +476,23 @@ TEST(restrict_address_families) { _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); @@ -591,21 +520,13 @@ TEST(restrict_realtime) { _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__); @@ -617,10 +538,8 @@ TEST(memory_deny_write_execute_mmap) { 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); @@ -649,14 +568,11 @@ TEST(memory_deny_write_execute_mmap) { _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)); @@ -666,14 +582,8 @@ TEST(memory_deny_write_execute_shmat) { 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__); @@ -688,10 +598,8 @@ TEST(memory_deny_write_execute_shmat) { 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); @@ -722,26 +630,15 @@ TEST(memory_deny_write_execute_shmat) { _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); @@ -760,26 +657,15 @@ TEST(restrict_archs) { _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); @@ -873,26 +759,15 @@ TEST(load_syscall_filter_set_raw) { _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; @@ -931,32 +806,21 @@ TEST(native_syscalls_filtered) { _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); @@ -988,8 +852,6 @@ TEST(lock_personality) { 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) { @@ -1023,21 +885,12 @@ static int try_fchmodat2(int dirfd, const char *path, mode_t mode, int flags) { } 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; @@ -1224,8 +1077,6 @@ TEST(restrict_suid_sgid) { _exit(EXIT_SUCCESS); } - - assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); } static void test_seccomp_suppress_sync_child(void) { @@ -1258,25 +1109,15 @@ 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);