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/core/import-creds.c b/src/core/import-creds.c index 8cc4e19ab6..2603eab1d9 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,37 +872,26 @@ 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; + 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(); - - q = import_credentials_trusted(); - if (r >= 0) - r = q; + RET_GATHER(r, import_credentials_trusted()); } report_credentials(); diff --git a/src/core/main.c b/src/core/main.c index 706f1ca41c..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; @@ -1438,10 +1426,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 +1440,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; } @@ -2341,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); @@ -2365,20 +2352,29 @@ 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) */ (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(); - test_usr(); + write_container_id(); /* Copy os-release to the propagate directory, so that we update it for services running @@ -2392,40 +2388,6 @@ static int initialize_runtime( if (r < 0) log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m", arg_watchdog_device); - break; - - case RUNTIME_SCOPE_USER: { - _cleanup_free_ char *p = NULL; - - /* Create the runtime directory and place the inaccessible device nodes there, if we run in - * user mode. In system mode mount_setup() already did that. */ - - r = xdg_user_runtime_dir(&p, "/systemd"); - if (r < 0) { - *ret_error_message = "$XDG_RUNTIME_DIR is not set"; - return log_struct_errno(LOG_EMERG, r, - LOG_MESSAGE("Failed to determine $XDG_RUNTIME_DIR path: %m"), - "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"); - break; - } - - default: - assert_not_reached(); - } - - if (arg_timer_slack_nsec != NSEC_INFINITY) - 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) { @@ -2452,8 +2414,48 @@ static int initialize_runtime( "MESSAGE_ID=" SD_MESSAGE_CORE_DISABLE_PRIVILEGES_STR); } } + + break; + + case RUNTIME_SCOPE_USER: { + _cleanup_free_ char *p = NULL; + + /* Create the runtime directory and place the inaccessible device nodes there, if we run in + * user mode. In system mode mount_setup() already did that. */ + + r = xdg_user_runtime_dir(&p, "/systemd"); + if (r < 0) { + *ret_error_message = "$XDG_RUNTIME_DIR is not set"; + return log_struct_errno(LOG_EMERG, r, + LOG_MESSAGE("Failed to determine $XDG_RUNTIME_DIR path: %m"), + "MESSAGE_ID=" SD_MESSAGE_CORE_NO_XDGDIR_PATH_STR); + } + + 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"); + } + + /* 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; } + default: + assert_not_reached(); + } + + if (arg_timer_slack_nsec != NSEC_INFINITY) + if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0) + log_warning_errno(errno, "Failed to adjust timer slack, ignoring: %m"); + if (arg_syscall_archs) { r = enforce_syscall_archs(arg_syscall_archs); if (r < 0) { @@ -3127,11 +3129,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; 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"));