1
0
mirror of https://github.com/systemd/systemd synced 2024-07-03 08:29:25 +00:00

test-execute: drop capabilities when testing with user manager

Before this, tests are split into two categories, system and user, but
both are running in fully privileged environment. Hence, unprivileged
user scope was mostly not covered by the test.

Let's run all tests in both system and user scopes, and drop capabilities
when Manager is running in user scope.

This also makes the host environment protected more from the test run.
This commit is contained in:
Yu Watanabe 2023-02-03 12:28:31 +09:00
parent f0353cf2e9
commit 4e032f654b
9 changed files with 338 additions and 226 deletions

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdio.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/types.h>
@ -18,6 +19,7 @@
#include "manager.h"
#include "missing_prctl.h"
#include "mkdir.h"
#include "mount-util.h"
#include "path-util.h"
#include "process-util.h"
#include "rm-rf.h"
@ -34,6 +36,8 @@
#include "user-util.h"
#include "virt.h"
#define PRIVATE_UNIT_DIR "/run/test-execute-unit-dir"
static char *user_runtime_unit_dir = NULL;
static bool can_unshare;
@ -413,7 +417,7 @@ static void test_exec_privatedevices(Manager *m) {
test(m, "exec-privatedevices-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatedevices-no.service", 0, CLD_EXITED);
test(m, "exec-privatedevices-disabled-by-prefix.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatedevices-yes-with-group.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatedevices-yes-with-group.service", can_unshare ? 0 : MANAGER_IS_SYSTEM(m) ? EXIT_FAILURE : EXIT_GROUP, CLD_EXITED);
/* We use capsh to test if the capabilities are
* properly set, so be sure that it exists */
@ -424,9 +428,9 @@ static void test_exec_privatedevices(Manager *m) {
}
test(m, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED);
test(m, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED);
test(m, "exec-privatedevices-no-capability-mknod.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatedevices-yes-capability-sys-rawio.service", 0, CLD_EXITED);
test(m, "exec-privatedevices-no-capability-sys-rawio.service", 0, CLD_EXITED);
test(m, "exec-privatedevices-no-capability-sys-rawio.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_protecthome(Manager *m) {
@ -456,7 +460,7 @@ static void test_exec_protectkernelmodules(Manager *m) {
return;
}
test(m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED);
test(m, "exec-protectkernelmodules-no-capabilities.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED);
test(m, "exec-protectkernelmodules-yes-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
}
@ -777,7 +781,7 @@ static void test_exec_systemcallfilter_system(Manager *m) {
return;
}
test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
test(m, "exec-systemcallfilter-system-user.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@ -789,12 +793,12 @@ static void test_exec_systemcallfilter_system(Manager *m) {
return;
}
test(m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
test(m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
#endif
}
static void test_exec_user(Manager *m) {
test(m, "exec-user.service", 0, CLD_EXITED);
test(m, "exec-user.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@ -806,11 +810,11 @@ static void test_exec_user(Manager *m) {
return;
}
test(m, "exec-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
test(m, "exec-user-" NOBODY_USER_NAME ".service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
}
static void test_exec_group(Manager *m) {
test(m, "exec-group.service", 0, CLD_EXITED);
test(m, "exec-group.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@ -822,16 +826,17 @@ static void test_exec_group(Manager *m) {
return;
}
test(m, "exec-group-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
test(m, "exec-group-" NOBODY_GROUP_NAME ".service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
}
static void test_exec_supplementarygroups(Manager *m) {
test(m, "exec-supplementarygroups.service", 0, CLD_EXITED);
test(m, "exec-supplementarygroups-single-group.service", 0, CLD_EXITED);
test(m, "exec-supplementarygroups-single-group-user.service", 0, CLD_EXITED);
test(m, "exec-supplementarygroups-multiple-groups-default-group-user.service", 0, CLD_EXITED);
test(m, "exec-supplementarygroups-multiple-groups-withgid.service", 0, CLD_EXITED);
test(m, "exec-supplementarygroups-multiple-groups-withuid.service", 0, CLD_EXITED);
int status = MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP;
test(m, "exec-supplementarygroups.service", status, CLD_EXITED);
test(m, "exec-supplementarygroups-single-group.service", status, CLD_EXITED);
test(m, "exec-supplementarygroups-single-group-user.service", status, CLD_EXITED);
test(m, "exec-supplementarygroups-multiple-groups-default-group-user.service", status, CLD_EXITED);
test(m, "exec-supplementarygroups-multiple-groups-withgid.service", status, CLD_EXITED);
test(m, "exec-supplementarygroups-multiple-groups-withuid.service", status, CLD_EXITED);
}
static char* private_directory_bad(Manager *m) {
@ -863,14 +868,16 @@ static void test_exec_dynamicuser(Manager *m) {
return;
}
test(m, "exec-dynamicuser-fixeduser.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
int status = can_unshare ? 0 : MANAGER_IS_SYSTEM(m) ? EXIT_NAMESPACE : EXIT_GROUP;
test(m, "exec-dynamicuser-fixeduser.service", status, CLD_EXITED);
if (check_user_has_group_with_same_name("adm"))
test(m, "exec-dynamicuser-fixeduser-adm.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-fixeduser-adm.service", status, CLD_EXITED);
if (check_user_has_group_with_same_name("games"))
test(m, "exec-dynamicuser-fixeduser-games.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-supplementarygroups.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-statedir.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-fixeduser-games.service", status, CLD_EXITED);
test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", status, CLD_EXITED);
test(m, "exec-dynamicuser-supplementarygroups.service", status, CLD_EXITED);
test(m, "exec-dynamicuser-statedir.service", status, CLD_EXITED);
(void) rm_rf("/var/lib/quux", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
@ -882,7 +889,7 @@ static void test_exec_dynamicuser(Manager *m) {
(void) rm_rf("/var/lib/private/waldo", REMOVE_ROOT|REMOVE_PHYSICAL);
test(m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
test(m, "exec-dynamicuser-statedir-migrate-step2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-statedir-migrate-step2.service", status, CLD_EXITED);
test(m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
(void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
@ -890,9 +897,9 @@ static void test_exec_dynamicuser(Manager *m) {
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
test(m, "exec-dynamicuser-runtimedirectory1.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-runtimedirectory2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-runtimedirectory3.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-runtimedirectory1.service", status, CLD_EXITED);
test(m, "exec-dynamicuser-runtimedirectory2.service", status, CLD_EXITED);
test(m, "exec-dynamicuser-runtimedirectory3.service", status, CLD_EXITED);
}
static void test_exec_environment(Manager *m) {
@ -958,9 +965,12 @@ static void test_exec_umask(Manager *m) {
}
static void test_exec_runtimedirectory(Manager *m) {
(void) rm_rf("/run/test-exec_runtimedirectory2", REMOVE_ROOT|REMOVE_PHYSICAL);
test(m, "exec-runtimedirectory.service", 0, CLD_EXITED);
(void) rm_rf("/run/test-exec_runtimedirectory2", REMOVE_ROOT|REMOVE_PHYSICAL);
test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
test(m, "exec-runtimedirectory-owner.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@ -972,7 +982,7 @@ static void test_exec_runtimedirectory(Manager *m) {
return;
}
test(m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
test(m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_GROUP, CLD_EXITED);
}
static void test_exec_capabilityboundingset(Manager *m) {
@ -1046,7 +1056,7 @@ static void test_exec_privatenetwork(Manager *m) {
return;
}
test(m, "exec-privatenetwork-yes.service", can_unshare ? 0 : EXIT_NETWORK, CLD_EXITED);
test(m, "exec-privatenetwork-yes.service", can_unshare ? 0 : MANAGER_IS_SYSTEM(m) ? EXIT_NETWORK : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_oomscoreadjust(Manager *m) {
@ -1056,7 +1066,7 @@ static void test_exec_oomscoreadjust(Manager *m) {
log_notice("Testing in container, skipping remaining tests in %s", __func__);
return;
}
test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
test(m, "exec-oomscoreadjust-negative.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_ioschedulingclass(Manager *m) {
@ -1068,7 +1078,7 @@ static void test_exec_ioschedulingclass(Manager *m) {
log_notice("Testing in container, skipping remaining tests in %s", __func__);
return;
}
test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
test(m, "exec-ioschedulingclass-realtime.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_IOPRIO, CLD_EXITED);
}
static void test_exec_unsetenvironment(Manager *m) {
@ -1077,9 +1087,13 @@ static void test_exec_unsetenvironment(Manager *m) {
static void test_exec_specifier(Manager *m) {
test(m, "exec-specifier.service", 0, CLD_EXITED);
if (MANAGER_IS_SYSTEM(m))
test(m, "exec-specifier-system.service", 0, CLD_EXITED);
else
test(m, "exec-specifier-user.service", 0, CLD_EXITED);
test(m, "exec-specifier@foo-bar.service", 0, CLD_EXITED);
test(m, "exec-specifier-interpolation.service", 0, CLD_EXITED);
test(m, "exec-specifier-credentials-dir.service", 0, CLD_EXITED);
test(m, "exec-specifier-credentials-dir.service", MANAGER_IS_SYSTEM(m) ? 0 : EXIT_CREDENTIALS, CLD_EXITED);
}
static void test_exec_standardinput(Manager *m) {
@ -1112,7 +1126,7 @@ static void test_exec_umask_namespace(Manager *m) {
log_notice("Testing without inaccessible, skipping %s", __func__);
return;
}
test(m, "exec-umask-namespace.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-umask-namespace.service", can_unshare ? 0 : MANAGER_IS_SYSTEM(m) ? EXIT_NAMESPACE : EXIT_GROUP, CLD_EXITED);
}
typedef struct test_entry {
@ -1122,40 +1136,27 @@ typedef struct test_entry {
#define entry(x) {x, #x}
static int run_tests(LookupScope scope, const test_entry tests[], char **patterns) {
static void run_tests(LookupScope scope, char **patterns) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
_cleanup_free_ char *unit_paths = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
int r;
assert_se(tests);
r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m);
m->default_std_output = EXEC_OUTPUT_NULL; /* don't rely on host journald */
if (manager_errno_skip_test(r))
return log_tests_skipped_errno(r, "manager_new");
assert_se(r >= 0);
assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
for (const test_entry *test = tests; test->f; test++)
if (strv_fnmatch_or_empty(patterns, test->name, FNM_NOESCAPE))
test->f(m);
else
log_info("Skipping %s because it does not match any pattern.", test->name);
return 0;
}
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
static const test_entry user_tests[] = {
static const test_entry tests[] = {
entry(test_exec_basic),
entry(test_exec_ambientcapabilities),
entry(test_exec_bindpaths),
entry(test_exec_capabilityboundingset),
entry(test_exec_condition),
entry(test_exec_cpuaffinity),
entry(test_exec_dynamicuser),
entry(test_exec_environment),
entry(test_exec_environmentfile),
entry(test_exec_execsearchpath),
entry(test_exec_execsearchpath_environment),
entry(test_exec_execsearchpath_environment_files),
entry(test_exec_execsearchpath_passenvironment),
entry(test_exec_execsearchpath_specifier),
entry(test_exec_group),
entry(test_exec_ignoresigpipe),
entry(test_exec_inaccessiblepaths),
@ -1174,6 +1175,7 @@ int main(int argc, char *argv[]) {
entry(test_exec_readwritepaths),
entry(test_exec_restrictnamespaces),
entry(test_exec_runtimedirectory),
entry(test_exec_specifier),
entry(test_exec_standardinput),
entry(test_exec_standardoutput),
entry(test_exec_standardoutput_append),
@ -1181,35 +1183,15 @@ int main(int argc, char *argv[]) {
entry(test_exec_supplementarygroups),
entry(test_exec_systemcallerrornumber),
entry(test_exec_systemcallfilter),
entry(test_exec_systemcallfilter_system),
entry(test_exec_temporaryfilesystem),
entry(test_exec_umask),
entry(test_exec_umask_namespace),
entry(test_exec_unsetenvironment),
entry(test_exec_user),
entry(test_exec_workingdirectory),
entry(test_exec_execsearchpath),
entry(test_exec_execsearchpath_environment),
entry(test_exec_execsearchpath_environment_files),
entry(test_exec_execsearchpath_passenvironment),
{},
};
static const test_entry system_tests[] = {
entry(test_exec_dynamicuser),
entry(test_exec_specifier),
entry(test_exec_execsearchpath_specifier),
entry(test_exec_systemcallfilter_system),
entry(test_exec_umask_namespace),
{},
};
int r;
test_setup_logging(LOG_DEBUG);
#if HAS_FEATURE_ADDRESS_SANITIZER
if (strstr_ptr(ci_environment(), "travis") || strstr_ptr(ci_environment(), "github-actions")) {
log_notice("Running on Travis CI/GH Actions under ASan, skipping, see https://github.com/systemd/systemd/issues/10696");
return EXIT_TEST_SKIP;
}
#endif
assert_se(unsetenv("USER") == 0);
assert_se(unsetenv("LOGNAME") == 0);
@ -1217,68 +1199,185 @@ int main(int argc, char *argv[]) {
assert_se(unsetenv("HOME") == 0);
assert_se(unsetenv("TMPDIR") == 0);
can_unshare = have_namespaces();
/* Unset VARx, especially, VAR1, VAR2 and VAR3, which are used in the PassEnvironment test cases,
* otherwise (and if they are present in the environment), `manager_default_environment` will copy
* them into the default environment which is passed to each created job, which will make the tests
* that expect those not to be present to fail. */
assert_se(unsetenv("VAR1") == 0);
assert_se(unsetenv("VAR2") == 0);
assert_se(unsetenv("VAR3") == 0);
assert_se(unsetenv("VAR4") == 0);
assert_se(unsetenv("VAR5") == 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
assert_se(user_runtime_unit_dir = path_join(runtime_dir, "systemd/user"));
assert_se(unit_paths = strjoin(PRIVATE_UNIT_DIR, ":", user_runtime_unit_dir));
assert_se(set_unit_path(unit_paths) >= 0);
r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m);
if (manager_errno_skip_test(r))
return (void) log_tests_skipped_errno(r, "manager_new");
assert_se(r >= 0);
m->default_std_output = EXEC_OUTPUT_NULL; /* don't rely on host journald */
assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
/* Uncomment below if you want to make debugging logs stored to journal. */
//manager_override_log_target(m, LOG_TARGET_AUTO);
//manager_override_log_level(m, LOG_DEBUG);
for (const test_entry *test = tests; test->f; test++)
if (strv_fnmatch_or_empty(patterns, test->name, FNM_NOESCAPE))
test->f(m);
else
log_info("Skipping %s because it does not match any pattern.", test->name);
}
static int prepare_ns(const char *process_name) {
int r;
r = safe_fork(process_name,
FORK_RESET_SIGNALS |
FORK_CLOSE_ALL_FDS |
FORK_DEATHSIG |
FORK_WAIT |
FORK_REOPEN_LOG |
FORK_LOG |
FORK_NEW_MOUNTNS |
FORK_MOUNTNS_SLAVE,
NULL);
assert_se(r >= 0);
if (r == 0) {
_cleanup_free_ char *unit_dir = NULL;
/* Make "/" read-only. */
assert_se(mount_nofollow_verbose(LOG_DEBUG, NULL, "/", NULL, MS_BIND|MS_REMOUNT, NULL) >= 0);
/* Creating a new user namespace in the above means all MS_SHARED mounts become MS_SLAVE.
* Let's put them back to MS_SHARED here, since that's what we want as defaults. (This will
* not reconnect propagation, but simply create new peer groups for all our mounts). */
assert_se(mount_follow_verbose(LOG_DEBUG, NULL, "/", NULL, MS_SHARED|MS_REC, NULL) >= 0);
assert_se(mkdir_p(PRIVATE_UNIT_DIR, 0755) >= 0);
/* Mount tmpfs on the following directories to make not StateDirectory= or friends disturb the host. */
FOREACH_STRING(p, "/root", "/tmp", "/var/tmp", "/var/lib", PRIVATE_UNIT_DIR)
assert_se(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", p, "tmpfs", MS_NOSUID|MS_NODEV, NULL) >= 0);
/* Copy unit files to make them accessible even when unprivileged. */
assert_se(get_testdata_dir("test-execute/", &unit_dir) >= 0);
assert_se(copy_directory(unit_dir, PRIVATE_UNIT_DIR, COPY_MERGE_EMPTY) >= 0);
/* Prepare credstore like tmpfiles.d/credstore.conf for LoadCredential= tests. */
FOREACH_STRING(p, "/run/credstore", "/run/credstore.encrypted") {
assert_se(mkdir_p(p, 0) >= 0);
assert_se(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", p, "tmpfs", MS_NOSUID|MS_NODEV, "mode=0000") >= 0);
}
}
return r;
}
TEST(run_tests_root) {
_cleanup_strv_free_ char **filters = NULL;
if (!have_namespaces())
return (void) log_tests_skipped("unshare() is disabled");
/* safe_fork() clears saved_argv in the child process. Let's copy it. */
assert_se(filters = strv_copy(strv_skip(saved_argv, 1)));
if (prepare_ns("(test-execute-root)") == 0) {
can_unshare = true;
run_tests(LOOKUP_SCOPE_SYSTEM, filters);
_exit(EXIT_SUCCESS);
}
}
TEST(run_tests_without_unshare) {
if (!have_namespaces()) {
/* unshare() is already filtered. */
can_unshare = false;
run_tests(LOOKUP_SCOPE_SYSTEM, strv_skip(saved_argv, 1));
return;
}
#if HAVE_SECCOMP
_cleanup_strv_free_ char **filters = NULL;
int r;
/* The following tests are for 1beab8b0d0ff2d7d1436b52d4a0c3d56dc908962. */
if (!is_seccomp_available())
return (void) log_tests_skipped("Seccomp not available, cannot run unshare() filtered tests");
/* safe_fork() clears saved_argv in the child process. Let's copy it. */
assert_se(filters = strv_copy(strv_skip(saved_argv, 1)));
if (prepare_ns("(test-execute-without-unshare)") == 0) {
_cleanup_hashmap_free_ Hashmap *s = NULL;
r = seccomp_syscall_resolve_name("unshare");
assert_se(r != __NR_SCMP_ERROR);
assert_se(hashmap_ensure_put(&s, NULL, UINT32_TO_PTR(r + 1), INT_TO_PTR(-1)) >= 0);
assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EOPNOTSUPP), true) >= 0);
/* Check unshare() is actually filtered. */
assert_se(unshare(CLONE_NEWNS) < 0);
assert_se(errno == EOPNOTSUPP);
can_unshare = false;
run_tests(LOOKUP_SCOPE_SYSTEM, filters);
_exit(EXIT_SUCCESS);
}
#else
log_tests_skipped("Built without seccomp support, cannot run unshare() filtered tests");
#endif
}
TEST(run_tests_unprivileged) {
_cleanup_strv_free_ char **filters = NULL;
if (!have_namespaces())
return (void) log_tests_skipped("unshare() is disabled");
/* safe_fork() clears saved_argv in the child process. Let's copy it. */
assert_se(filters = strv_copy(strv_skip(saved_argv, 1)));
if (prepare_ns("(test-execute-unprivileged)") == 0) {
assert_se(capability_bounding_set_drop(0, /* right_now = */ true) >= 0);
can_unshare = false;
run_tests(LOOKUP_SCOPE_USER, filters);
_exit(EXIT_SUCCESS);
}
}
static int intro(void) {
#if HAS_FEATURE_ADDRESS_SANITIZER
if (strstr_ptr(ci_environment(), "travis") || strstr_ptr(ci_environment(), "github-actions"))
return log_tests_skipped("Running on Travis CI/GH Actions under ASan, see https://github.com/systemd/systemd/issues/10696");
#endif
/* It is needed otherwise cgroup creation fails */
if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0)
return log_tests_skipped("not privileged");
r = enter_cgroup_subroot(NULL);
if (r == -ENOMEDIUM)
if (enter_cgroup_subroot(NULL) == -ENOMEDIUM)
return log_tests_skipped("cgroupfs not available");
if (path_is_read_only_fs("/sys") > 0)
return log_tests_skipped("/sys is mounted read-only");
_cleanup_free_ char *unit_dir = NULL, *unit_paths = NULL;
assert_se(get_testdata_dir("test-execute/", &unit_dir) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
assert_se(user_runtime_unit_dir = path_join(runtime_dir, "systemd/user"));
assert_se(unit_paths = strjoin(unit_dir, ":", user_runtime_unit_dir));
assert_se(set_unit_path(unit_paths) >= 0);
/* Create dummy network interface for testing PrivateNetwork=yes */
(void) system("ip link add dummy-test-exec type dummy");
/* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test
* cases, otherwise (and if they are present in the environment),
* `manager_default_environment` will copy them into the default
* environment which is passed to each created job, which will make the
* tests that expect those not to be present to fail.
*/
assert_se(unsetenv("VAR1") == 0);
assert_se(unsetenv("VAR2") == 0);
assert_se(unsetenv("VAR3") == 0);
r = run_tests(LOOKUP_SCOPE_USER, user_tests, argv + 1);
if (r != 0)
return r;
r = run_tests(LOOKUP_SCOPE_SYSTEM, system_tests, argv + 1);
if (r != 0)
return r;
#if HAVE_SECCOMP
/* The following tests are for 1beab8b0d0ff2d7d1436b52d4a0c3d56dc908962. */
if (!is_seccomp_available()) {
log_notice("Seccomp not available, skipping unshare() filtered tests.");
return 0;
}
_cleanup_hashmap_free_ Hashmap *s = NULL;
assert_se(s = hashmap_new(NULL));
r = seccomp_syscall_resolve_name("unshare");
assert_se(r != __NR_SCMP_ERROR);
assert_se(hashmap_put(s, UINT32_TO_PTR(r + 1), INT_TO_PTR(-1)) >= 0);
assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EOPNOTSUPP), true) >= 0);
assert_se(unshare(CLONE_NEWNS) < 0);
assert_se(errno == EOPNOTSUPP);
can_unshare = false;
r = run_tests(LOOKUP_SCOPE_USER, user_tests, argv + 1);
if (r != 0)
return r;
return run_tests(LOOKUP_SCOPE_SYSTEM, system_tests, argv + 1);
#else
return 0;
#endif
return EXIT_SUCCESS;
}
static int outro(void) {
(void) system("ip link del dummy-test-exec");
(void) rmdir(PRIVATE_UNIT_DIR);
return EXIT_SUCCESS;
}
DEFINE_TEST_MAIN_FULL(LOG_DEBUG, intro, outro);

View File

@ -3,14 +3,14 @@
Description=Test DynamicUser= migrate StateDirectory= (preparation)
[Service]
ExecStart=test -w /var/lib/test-dynamicuser-migrate
ExecStart=test -w /var/lib/test-dynamicuser-migrate2/hoge
ExecStart=test ! -L /var/lib/test-dynamicuser-migrate
ExecStart=test ! -L /var/lib/test-dynamicuser-migrate2/hoge
ExecStart=test -d /var/lib/test-dynamicuser-migrate
ExecStart=test -d /var/lib/test-dynamicuser-migrate2/hoge
ExecStart=touch /var/lib/test-dynamicuser-migrate/yay
ExecStart=touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=test -w %S/test-dynamicuser-migrate
ExecStart=test -w %S/test-dynamicuser-migrate2/hoge
ExecStart=test ! -L %S/test-dynamicuser-migrate
ExecStart=test ! -L %S/test-dynamicuser-migrate2/hoge
ExecStart=test -d %S/test-dynamicuser-migrate
ExecStart=test -d %S/test-dynamicuser-migrate2/hoge
ExecStart=touch %S/test-dynamicuser-migrate/yay
ExecStart=touch %S/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/test-dynamicuser-migrate:%S/test-dynamicuser-migrate2/hoge"'
Type=oneshot

View File

@ -3,22 +3,22 @@
Description=Test DynamicUser= migrate StateDirectory=
[Service]
ExecStart=test -w /var/lib/test-dynamicuser-migrate
ExecStart=test -w /var/lib/test-dynamicuser-migrate2/hoge
ExecStart=test -L /var/lib/test-dynamicuser-migrate
ExecStart=test -L /var/lib/test-dynamicuser-migrate2/hoge
ExecStart=test -d /var/lib/test-dynamicuser-migrate
ExecStart=test -d /var/lib/test-dynamicuser-migrate2/hoge
ExecStart=test -f /var/lib/test-dynamicuser-migrate/yay
ExecStart=test -f /var/lib/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=test -d /var/lib/private/test-dynamicuser-migrate
ExecStart=test -d /var/lib/private/test-dynamicuser-migrate2/hoge
ExecStart=test -f /var/lib/private/test-dynamicuser-migrate/yay
ExecStart=test -f /var/lib/private/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=touch /var/lib/test-dynamicuser-migrate/yay
ExecStart=touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=touch /var/lib/private/test-dynamicuser-migrate/yay
ExecStart=touch /var/lib/private/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=test -w %S/test-dynamicuser-migrate
ExecStart=test -w %S/test-dynamicuser-migrate2/hoge
ExecStart=test -L %S/test-dynamicuser-migrate
ExecStart=test -L %S/test-dynamicuser-migrate2/hoge
ExecStart=test -d %S/test-dynamicuser-migrate
ExecStart=test -d %S/test-dynamicuser-migrate2/hoge
ExecStart=test -f %S/test-dynamicuser-migrate/yay
ExecStart=test -f %S/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=test -d %S/private/test-dynamicuser-migrate
ExecStart=test -d %S/private/test-dynamicuser-migrate2/hoge
ExecStart=test -f %S/private/test-dynamicuser-migrate/yay
ExecStart=test -f %S/private/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=touch %S/test-dynamicuser-migrate/yay
ExecStart=touch %S/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=touch %S/private/test-dynamicuser-migrate/yay
ExecStart=touch %S/private/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/test-dynamicuser-migrate:%S/test-dynamicuser-migrate2/hoge"'
Type=oneshot

View File

@ -3,71 +3,71 @@
Description=Test DynamicUser= with StateDirectory=
[Service]
ExecStart=test -w /var/lib/waldo
ExecStart=test -w /var/lib/quux/pief
ExecStart=test -w /var/lib/aaa
ExecStart=test -w /var/lib/aaa/bbb
ExecStart=test -w /var/lib/aaa/ccc
ExecStart=test -w /var/lib/xxx
ExecStart=test -w /var/lib/xxx/yyy
ExecStart=test -w /var/lib/xxx/zzz
ExecStart=test -w /var/lib/aaa/111
ExecStart=test -w /var/lib/aaa/222
ExecStart=test -w /var/lib/aaa/333
ExecStart=test -w %S/waldo
ExecStart=test -w %S/quux/pief
ExecStart=test -w %S/aaa
ExecStart=test -w %S/aaa/bbb
ExecStart=test -w %S/aaa/ccc
ExecStart=test -w %S/xxx
ExecStart=test -w %S/xxx/yyy
ExecStart=test -w %S/xxx/zzz
ExecStart=test -w %S/aaa/111
ExecStart=test -w %S/aaa/222
ExecStart=test -w %S/aaa/333
ExecStart=test -d /var/lib/waldo
ExecStart=test -d /var/lib/quux/pief
ExecStart=test -d /var/lib/aaa
ExecStart=test -d /var/lib/aaa/bbb
ExecStart=test -d /var/lib/aaa/ccc
ExecStart=test -d /var/lib/xxx
ExecStart=test -d /var/lib/xxx/yyy
ExecStart=test -d /var/lib/xxx/zzz
ExecStart=test -L /var/lib/aaa/111
ExecStart=test -L /var/lib/aaa/222
ExecStart=test -L /var/lib/aaa/333
ExecStart=test -d %S/waldo
ExecStart=test -d %S/quux/pief
ExecStart=test -d %S/aaa
ExecStart=test -d %S/aaa/bbb
ExecStart=test -d %S/aaa/ccc
ExecStart=test -d %S/xxx
ExecStart=test -d %S/xxx/yyy
ExecStart=test -d %S/xxx/zzz
ExecStart=test -L %S/aaa/111
ExecStart=test -L %S/aaa/222
ExecStart=test -L %S/aaa/333
ExecStart=touch /var/lib/waldo/hoge
ExecStart=touch /var/lib/quux/pief/hoge
ExecStart=touch /var/lib/aaa/hoge
ExecStart=touch /var/lib/aaa/bbb/hoge
ExecStart=touch /var/lib/aaa/ccc/hoge
ExecStart=touch /var/lib/xxx/hoge
ExecStart=touch /var/lib/xxx/yyy/hoge
ExecStart=touch /var/lib/xxx/zzz/hoge
ExecStart=touch /var/lib/aaa/111/foo
ExecStart=touch /var/lib/aaa/222/foo
ExecStart=touch /var/lib/aaa/333/foo
ExecStart=touch %S/waldo/hoge
ExecStart=touch %S/quux/pief/hoge
ExecStart=touch %S/aaa/hoge
ExecStart=touch %S/aaa/bbb/hoge
ExecStart=touch %S/aaa/ccc/hoge
ExecStart=touch %S/xxx/hoge
ExecStart=touch %S/xxx/yyy/hoge
ExecStart=touch %S/xxx/zzz/hoge
ExecStart=touch %S/aaa/111/foo
ExecStart=touch %S/aaa/222/foo
ExecStart=touch %S/aaa/333/foo
ExecStart=test -f /var/lib/waldo/hoge
ExecStart=test -f /var/lib/quux/pief/hoge
ExecStart=test -f /var/lib/aaa/hoge
ExecStart=test -f /var/lib/aaa/bbb/hoge
ExecStart=test -f /var/lib/aaa/ccc/hoge
ExecStart=test -f /var/lib/xxx/hoge
ExecStart=test -f /var/lib/xxx/yyy/hoge
ExecStart=test -f /var/lib/xxx/zzz/hoge
ExecStart=test -f /var/lib/aaa/111/foo
ExecStart=test -f /var/lib/aaa/222/foo
ExecStart=test -f /var/lib/aaa/333/foo
ExecStart=test -f /var/lib/xxx/foo
ExecStart=test -f /var/lib/xxx/yyy/foo
ExecStart=test -f /var/lib/xxx/zzz/foo
ExecStart=test -f %S/waldo/hoge
ExecStart=test -f %S/quux/pief/hoge
ExecStart=test -f %S/aaa/hoge
ExecStart=test -f %S/aaa/bbb/hoge
ExecStart=test -f %S/aaa/ccc/hoge
ExecStart=test -f %S/xxx/hoge
ExecStart=test -f %S/xxx/yyy/hoge
ExecStart=test -f %S/xxx/zzz/hoge
ExecStart=test -f %S/aaa/111/foo
ExecStart=test -f %S/aaa/222/foo
ExecStart=test -f %S/aaa/333/foo
ExecStart=test -f %S/xxx/foo
ExecStart=test -f %S/xxx/yyy/foo
ExecStart=test -f %S/xxx/zzz/foo
ExecStart=test -f /var/lib/private/waldo/hoge
ExecStart=test -f /var/lib/private/quux/pief/hoge
ExecStart=test -f /var/lib/private/aaa/hoge
ExecStart=test -f /var/lib/private/aaa/bbb/hoge
ExecStart=test -f /var/lib/private/aaa/ccc/hoge
ExecStart=test -f /var/lib/private/xxx/hoge
ExecStart=test -f /var/lib/private/xxx/yyy/hoge
ExecStart=test -f /var/lib/private/xxx/zzz/hoge
ExecStart=test -f /var/lib/private/aaa/111/foo
ExecStart=test -f /var/lib/private/aaa/222/foo
ExecStart=test -f /var/lib/private/aaa/333/foo
ExecStart=test -f /var/lib/private/xxx/foo
ExecStart=test -f /var/lib/private/xxx/yyy/foo
ExecStart=test -f /var/lib/private/xxx/zzz/foo
ExecStart=test -f %S/private/waldo/hoge
ExecStart=test -f %S/private/quux/pief/hoge
ExecStart=test -f %S/private/aaa/hoge
ExecStart=test -f %S/private/aaa/bbb/hoge
ExecStart=test -f %S/private/aaa/ccc/hoge
ExecStart=test -f %S/private/xxx/hoge
ExecStart=test -f %S/private/xxx/yyy/hoge
ExecStart=test -f %S/private/xxx/zzz/hoge
ExecStart=test -f %S/private/aaa/111/foo
ExecStart=test -f %S/private/aaa/222/foo
ExecStart=test -f %S/private/aaa/333/foo
ExecStart=test -f %S/private/xxx/foo
ExecStart=test -f %S/private/xxx/yyy/foo
ExecStart=test -f %S/private/xxx/zzz/foo
ExecStart=sh -x -c 'test "$$STATE_DIRECTORY" = "%S/aaa:%S/aaa/bbb:%S/aaa/ccc:%S/quux/pief:%S/waldo:%S/xxx:%S/xxx/yyy:%S/xxx/zzz"'

View File

@ -4,5 +4,6 @@ Description=Test for PrivateNetwork
[Service]
ExecStart=/bin/sh -x -c '! ip link | grep -E "^[0-9]+: " | grep -Ev ": (lo|(erspan|gre|gretap|ip_vti|ip6_vti|ip6gre|ip6tnl|sit|tunl)0@.*):"'
ExecStart=/bin/sh -x -c '! ip link | grep -E "^[0-9]+: " | grep -F ": dummy-test-exec:"'
Type=oneshot
PrivateNetwork=yes

View File

@ -0,0 +1,11 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Unit]
Description=Test for specifiers (system)
[Service]
Type=oneshot
ExecStart=test %t = /run
ExecStart=test %S = /var/lib
ExecStart=test %C = /var/cache
ExecStart=test %L = /var/log
ExecStart=test %E = /etc

View File

@ -0,0 +1,11 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Unit]
Description=Test for specifiers
[Service]
Type=oneshot
ExecStart=sh -c 'test %t = $$XDG_RUNTIME_DIR'
ExecStart=sh -c 'test %S = %h/.config'
ExecStart=sh -c 'test %C = %h/.cache'
ExecStart=sh -c 'test %L = %h/.config/log'
ExecStart=sh -c 'test %E = %h/.config'

View File

@ -13,11 +13,6 @@ ExecStart=test %I = ""
ExecStart=test %j = specifier
ExecStart=test %J = specifier
ExecStart=test %f = /exec/specifier
ExecStart=test %t = /run
ExecStart=test %S = /var/lib
ExecStart=test %C = /var/cache
ExecStart=test %L = /var/log
ExecStart=test %E = /etc
ExecStart=test %T = /tmp
ExecStart=test %V = /var/tmp
ExecStart=test %d = %t/credentials/%n

View File

@ -13,11 +13,6 @@ ExecStart=test %I = foo/bar
ExecStart=test %j = specifier
ExecStart=test %J = specifier
ExecStart=test %f = /foo/bar
ExecStart=test %t = /run
ExecStart=test %S = /var/lib
ExecStart=test %C = /var/cache
ExecStart=test %L = /var/log
ExecStart=test %E = /etc
ExecStart=sh -c 'test %u = $$(id -un)'
ExecStart=sh -c 'test %U = $$(id -u)'
ExecStart=sh -c 'test %g = $$(id -gn)'