From 77c3e07f938a1600d9b416c44b50066f28117643 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 13 Jul 2024 18:54:36 +0200 Subject: [PATCH 1/9] basic/mkdir: merge two if blocks, return more accurate errno --- src/basic/mkdir.c | 8 +++----- src/test/test-mkdir.c | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index f87de0a2bf..3e1545a58b 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -151,15 +151,13 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui if (prefix) { p = path_startswith_full(path, prefix, /* accept_dot_dot= */ false); if (!p) - return -ENOTDIR; - } else - p = path; + return -EINVAL; - if (prefix) { fd = open(prefix, O_PATH|O_DIRECTORY|O_CLOEXEC); if (fd < 0) return -errno; - } + } else + p = path; return mkdirat_parents_internal(fd, p, mode, uid, gid, flags, _mkdirat); } diff --git a/src/test/test-mkdir.c b/src/test/test-mkdir.c index ef00729c08..b2cc910dd1 100644 --- a/src/test/test-mkdir.c +++ b/src/test/test-mkdir.c @@ -75,7 +75,7 @@ TEST(mkdir_p_safe) { assert_se(is_dir(q, false) > 0); assert_se(is_dir(q, true) > 0); - assert_se(mkdir_p_safe(tmp, "/tmp/test-mkdir-outside", 0755, UID_INVALID, GID_INVALID, 0) == -ENOTDIR); + ASSERT_ERROR(mkdir_p_safe(tmp, "/tmp/test-mkdir-outside", 0755, UID_INVALID, GID_INVALID, 0), EINVAL); p = mfree(p); assert_se(p = path_join(tmp, "zero-mode/should-fail-to-create-child")); From 497b17bbad1343a7ee81eb5ff8bbd32df14c2c63 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 13 Jul 2024 18:46:10 +0200 Subject: [PATCH 2/9] core/import-creds: use FOREACH_ARRAY and RET_GATHER where appropriate --- src/core/import-creds.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/core/import-creds.c b/src/core/import-creds.c index 8cc4e19ab6..5709457408 100644 --- a/src/core/import-creds.c +++ b/src/core/import-creds.c @@ -202,8 +202,8 @@ static int import_credentials_boot(void) { continue; } - for (size_t i = 0; i < de->n_entries; i++) { - const struct dirent *d = de->entries[i]; + FOREACH_ARRAY(i, de->entries, de->n_entries) { + const struct dirent *d = *i; _cleanup_close_ int cfd = -EBADF, nfd = -EBADF; _cleanup_free_ char *n = NULL; const char *e; @@ -848,7 +848,7 @@ static void report_credentials(void) { int import_credentials(void) { const char *received_creds_dir = NULL, *received_encrypted_creds_dir = NULL; bool envvar_set = false; - int r, q; + int r; r = get_credentials_dir(&received_creds_dir); if (r < 0 && r != -ENXIO) /* ENXIO → env var not set yet */ @@ -872,15 +872,12 @@ int import_credentials(void) { else r = 0; - if (received_encrypted_creds_dir) { - q = symlink_credential_dir("ENCRYPTED_CREDENTIALS_DIRECTORY", received_encrypted_creds_dir, ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY); - if (r >= 0) - r = q; - } + if (received_encrypted_creds_dir) + RET_GATHER(r, symlink_credential_dir("ENCRYPTED_CREDENTIALS_DIRECTORY", + received_encrypted_creds_dir, + ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY)); - q = merge_credentials_trusted(received_creds_dir); - if (r >= 0) - r = q; + RET_GATHER(r, merge_credentials_trusted(received_creds_dir)); } else { _cleanup_free_ char *v = NULL; @@ -899,10 +896,7 @@ int import_credentials(void) { } r = import_credentials_boot(); - - q = import_credentials_trusted(); - if (r >= 0) - r = q; + RET_GATHER(r, import_credentials_trusted()); } report_credentials(); From efa7a5cfe464bf7a46899b57c9ba26db3621e3c7 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 13 Jul 2024 18:47:41 +0200 Subject: [PATCH 3/9] core/import-creds: use proc_cmdline_get_bool() --- src/core/import-creds.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/core/import-creds.c b/src/core/import-creds.c index 5709457408..2603eab1d9 100644 --- a/src/core/import-creds.c +++ b/src/core/import-creds.c @@ -880,19 +880,14 @@ int import_credentials(void) { RET_GATHER(r, merge_credentials_trusted(received_creds_dir)); } else { - _cleanup_free_ char *v = NULL; + bool import; - r = proc_cmdline_get_key("systemd.import_credentials", PROC_CMDLINE_STRIP_RD_PREFIX, &v); + r = proc_cmdline_get_bool("systemd.import_credentials", PROC_CMDLINE_STRIP_RD_PREFIX|PROC_CMDLINE_TRUE_WHEN_MISSING, &import); if (r < 0) - log_debug_errno(r, "Failed to check if 'systemd.import_credentials=' kernel command line option is set, ignoring: %m"); - else if (r > 0) { - r = parse_boolean(v); - if (r < 0) - log_debug_errno(r, "Failed to parse 'systemd.import_credentials=' parameter, ignoring: %m"); - else if (r == 0) { - log_notice("systemd.import_credentials=no is set, skipping importing of credentials."); - return 0; - } + log_debug_errno(r, "Failed to check systemd.import_credentials= kernel command line option, proceeding: %m"); + else if (!import) { + log_notice("systemd.import_credentials=no is set, skipping importing of credentials."); + return 0; } r = import_credentials_boot(); From 0c7a2a5542eb0b06ae1312082c55b6b12337b9fe Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 13 Jul 2024 18:17:44 +0200 Subject: [PATCH 4/9] core/main: cast ignored retval of machine_id_setup() to void --- src/core/main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/main.c b/src/core/main.c index 706f1ca41c..25f58eb88c 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -2371,10 +2371,12 @@ static int initialize_runtime( (void) import_credentials(); (void) os_release_status(); - (void) hostname_setup(true); + (void) hostname_setup(/* really = */ true); + (void) machine_id_setup(/* root = */ NULL, arg_machine_id, + (first_boot ? MACHINE_ID_SETUP_FORCE_TRANSIENT : 0) | + (arg_machine_id_from_firmware ? MACHINE_ID_SETUP_FORCE_FIRMWARE : 0), + /* ret_machine_id = */ NULL); - machine_id_setup(/* root= */ NULL, arg_machine_id, (first_boot ? MACHINE_ID_SETUP_FORCE_TRANSIENT : 0) | - (arg_machine_id_from_firmware ? MACHINE_ID_SETUP_FORCE_FIRMWARE : 0), /* ret_machine_id = */ NULL); (void) loopback_setup(); bump_unix_max_dgram_qlen(); bump_file_max_and_nr_open(); From 20817cd27216a311021f0a532750c0ed3ae9541c Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 13 Jul 2024 19:04:23 +0200 Subject: [PATCH 5/9] core/main: modernize setup_os_release() a bit --- src/core/main.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/core/main.c b/src/core/main.c index 25f58eb88c..e4d9cac547 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1438,10 +1438,13 @@ static int os_release_status(void) { } static int setup_os_release(RuntimeScope scope) { - _cleanup_free_ char *os_release_dst = NULL; + char os_release_dst[STRLEN("/run/user//systemd/propagate/.os-release-stage/os-release") + DECIMAL_STR_MAX(uid_t)] = + "/run/systemd/propagate/.os-release-stage/os-release"; const char *os_release_src = "/etc/os-release"; int r; + assert(IN_SET(scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER)); + if (access("/etc/os-release", F_OK) < 0) { if (errno != ENOENT) log_debug_errno(errno, "Failed to check if /etc/os-release exists, ignoring: %m"); @@ -1449,22 +1452,17 @@ static int setup_os_release(RuntimeScope scope) { os_release_src = "/usr/lib/os-release"; } - if (scope == RUNTIME_SCOPE_SYSTEM) { - os_release_dst = strdup("/run/systemd/propagate/.os-release-stage/os-release"); - if (!os_release_dst) - return log_oom_debug(); - } else { - if (asprintf(&os_release_dst, "/run/user/" UID_FMT "/systemd/propagate/.os-release-stage/os-release", geteuid()) < 0) - return log_oom_debug(); - } + if (scope == RUNTIME_SCOPE_USER) + xsprintf(os_release_dst, "/run/user/" UID_FMT "/systemd/propagate/.os-release-stage/os-release", geteuid()); r = mkdir_parents_label(os_release_dst, 0755); if (r < 0) - return log_debug_errno(r, "Failed to create parent directory of %s, ignoring: %m", os_release_dst); + return log_debug_errno(r, "Failed to create parent directory of '%s', ignoring: %m", os_release_dst); r = copy_file_atomic(os_release_src, os_release_dst, 0644, COPY_MAC_CREATE|COPY_REPLACE); if (r < 0) - return log_debug_errno(r, "Failed to create %s, ignoring: %m", os_release_dst); + return log_debug_errno(r, "Failed to copy '%s' to '%s', ignoring: %m", + os_release_src, os_release_dst); return 0; } From 0acf4dfef5746be4cc10a9b8de06c12e4cd4f6d4 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 13 Jul 2024 22:27:07 +0200 Subject: [PATCH 6/9] core/main: merge second RUNTIME_SCOPE_SYSTEM block into switch above --- src/core/main.c | 57 +++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/core/main.c b/src/core/main.c index e4d9cac547..1a25372842 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -2392,6 +2392,33 @@ static int initialize_runtime( if (r < 0) log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m", arg_watchdog_device); + if (!cap_test_all(arg_capability_bounding_set)) { + r = capability_bounding_set_drop_usermode(arg_capability_bounding_set); + if (r < 0) { + *ret_error_message = "Failed to drop capability bounding set of usermode helpers"; + return log_struct_errno(LOG_EMERG, r, + LOG_MESSAGE("Failed to drop capability bounding set of usermode helpers: %m"), + "MESSAGE_ID=" SD_MESSAGE_CORE_CAPABILITY_BOUNDING_USER_STR); + } + + r = capability_bounding_set_drop(arg_capability_bounding_set, true); + if (r < 0) { + *ret_error_message = "Failed to drop capability bounding set"; + return log_struct_errno(LOG_EMERG, r, + LOG_MESSAGE("Failed to drop capability bounding set: %m"), + "MESSAGE_ID=" SD_MESSAGE_CORE_CAPABILITY_BOUNDING_STR); + } + } + + if (arg_no_new_privs) { + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { + *ret_error_message = "Failed to disable new privileges"; + return log_struct_errno(LOG_EMERG, errno, + LOG_MESSAGE("Failed to disable new privileges: %m"), + "MESSAGE_ID=" SD_MESSAGE_CORE_DISABLE_PRIVILEGES_STR); + } + } + break; case RUNTIME_SCOPE_USER: { @@ -2424,36 +2451,6 @@ static int initialize_runtime( if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0) log_warning_errno(errno, "Failed to adjust timer slack, ignoring: %m"); - if (arg_runtime_scope == RUNTIME_SCOPE_SYSTEM) { - - if (!cap_test_all(arg_capability_bounding_set)) { - r = capability_bounding_set_drop_usermode(arg_capability_bounding_set); - if (r < 0) { - *ret_error_message = "Failed to drop capability bounding set of usermode helpers"; - return log_struct_errno(LOG_EMERG, r, - LOG_MESSAGE("Failed to drop capability bounding set of usermode helpers: %m"), - "MESSAGE_ID=" SD_MESSAGE_CORE_CAPABILITY_BOUNDING_USER_STR); - } - - r = capability_bounding_set_drop(arg_capability_bounding_set, true); - if (r < 0) { - *ret_error_message = "Failed to drop capability bounding set"; - return log_struct_errno(LOG_EMERG, r, - LOG_MESSAGE("Failed to drop capability bounding set: %m"), - "MESSAGE_ID=" SD_MESSAGE_CORE_CAPABILITY_BOUNDING_STR); - } - } - - if (arg_no_new_privs) { - if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { - *ret_error_message = "Failed to disable new privileges"; - return log_struct_errno(LOG_EMERG, errno, - LOG_MESSAGE("Failed to disable new privileges: %m"), - "MESSAGE_ID=" SD_MESSAGE_CORE_DISABLE_PRIVILEGES_STR); - } - } - } - if (arg_syscall_archs) { r = enforce_syscall_archs(arg_syscall_archs); if (r < 0) { From 9100325690160fa1f09a90452da830298ee17fd3 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 13 Jul 2024 22:27:53 +0200 Subject: [PATCH 7/9] core/main: respect skip_setup for RUNTIME_SCOPE_USER too --- src/core/main.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/core/main.c b/src/core/main.c index 1a25372842..658ebc68b5 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -2435,11 +2435,15 @@ static int initialize_runtime( "MESSAGE_ID=" SD_MESSAGE_CORE_NO_XDGDIR_PATH_STR); } - (void) mkdir_p_label(p, 0755); - (void) make_inaccessible_nodes(p, UID_INVALID, GID_INVALID); - r = setup_os_release(RUNTIME_SCOPE_USER); - if (r < 0) - log_warning_errno(r, "Failed to copy os-release for propagation, ignoring: %m"); + if (!skip_setup) { + (void) mkdir_p_label(p, 0755); + (void) make_inaccessible_nodes(p, UID_INVALID, GID_INVALID); + + r = setup_os_release(RUNTIME_SCOPE_USER); + if (r < 0) + log_warning_errno(r, "Failed to copy os-release for propagation, ignoring: %m"); + } + break; } From 2bff236e70af81adc552df7ce20bbc4e196f32cc Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 13 Jul 2024 22:36:22 +0200 Subject: [PATCH 8/9] core/main: move capability_ambient_set_apply() to initialize_runtime() This is preparation for (user) manager, and we apply capability settings for the system manager in initialize_runtime() too. --- src/core/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/main.c b/src/core/main.c index 658ebc68b5..96cad30d65 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -2444,6 +2444,11 @@ static int initialize_runtime( log_warning_errno(r, "Failed to copy os-release for propagation, ignoring: %m"); } + /* Clear ambient capabilities, so services do not inherit them implicitly. Dropping them does + * not affect the permitted and effective sets which are important for the manager itself to + * operate. */ + (void) capability_ambient_set_apply(0, /* also_inherit= */ false); + break; } @@ -3128,11 +3133,6 @@ int main(int argc, char *argv[]) { /* clear the kernel timestamp, because we are not PID 1 */ kernel_timestamp = DUAL_TIMESTAMP_NULL; - /* Clear ambient capabilities, so services do not inherit them implicitly. Dropping them does - * not affect the permitted and effective sets which are important for the manager itself to - * operate. */ - capability_ambient_set_apply(0, /* also_inherit= */ false); - if (mac_init() < 0) { error_message = "Failed to initialize MAC support"; goto finish; From 87c4f0f824a3f69deac17bff8225f9ef09bd62b0 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 13 Jul 2024 19:10:58 +0200 Subject: [PATCH 9/9] core/main: refuse to run if /usr/ is not populated The support for split-usr has been dropped in v255. So, rather than emitting a warning, let's refuse such unsupported setups completely. --- src/core/main.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/core/main.c b/src/core/main.c index 96cad30d65..ed28102781 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1369,18 +1369,6 @@ static int bump_rlimit_memlock(const struct rlimit *saved_rlimit) { return 0; } -static void test_usr(void) { - - /* Check that /usr is either on the same file system as / or mounted already. */ - - if (dir_is_empty("/usr", /* ignore_hidden_or_backup= */ false) <= 0) - return; - - log_warning("/usr appears to be on its own filesystem and is not already mounted. This is not a supported setup. " - "Some things will probably break (sometimes even silently) in mysterious ways. " - "Consult https://systemd.io/SEPARATE_USR_IS_BROKEN for more information."); -} - static int enforce_syscall_archs(Set *archs) { #if HAVE_SECCOMP int r; @@ -2339,6 +2327,7 @@ static int initialize_runtime( struct rlimit *saved_rlimit_nofile, struct rlimit *saved_rlimit_memlock, const char **ret_error_message) { + int r; assert(ret_error_message); @@ -2363,6 +2352,12 @@ static int initialize_runtime( install_crash_handler(); if (!skip_setup) { + /* Check that /usr/ is either on the same file system as / or mounted already. */ + if (dir_is_empty("/usr", /* ignore_hidden_or_backup = */ true) > 0) { + *ret_error_message = "Refusing to run in unsupported environment where /usr/ is not populated"; + return -ENOEXEC; + } + /* Pull credentials from various sources into a common credential directory (we do * this here, before setting up the machine ID, so that we can use credential info * for setting up the machine ID) */ @@ -2376,9 +2371,10 @@ static int initialize_runtime( /* ret_machine_id = */ NULL); (void) loopback_setup(); + bump_unix_max_dgram_qlen(); bump_file_max_and_nr_open(); - test_usr(); + write_container_id(); /* Copy os-release to the propagate directory, so that we update it for services running