From 00dc018fa6e2b5cf08419223855babf8497c45ef Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 26 Apr 2024 17:44:32 +0800 Subject: [PATCH 1/8] core/load-fragment: add one missing assertion --- src/core/load-fragment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 188e5467136..6d19715e792 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -5213,7 +5213,7 @@ int config_parse_bind_paths( void *userdata) { ExecContext *c = ASSERT_PTR(data); - const Unit *u = userdata; + const Unit *u = ASSERT_PTR(userdata); int r; assert(filename); From 45a36ecff9c4631e5b04836e58c81f24584643a4 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 26 Apr 2024 17:48:53 +0800 Subject: [PATCH 2/8] man/systemd.exec: mount_switch_root uses pivot_root rather than chroot --- man/systemd.exec.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 38bf018ae46..d9ec44983fc 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -125,9 +125,10 @@ Takes a directory path relative to the host's root directory (i.e. the root of the system running the service manager). Sets the root directory for executed processes, with the chroot2 system - call. If this is used, it must be ensured that the process binary and all its auxiliary files are available in - the chroot() jail. Note that setting this parameter might result in additional + project='man-pages'>pivot_root2 + or chroot2 + system call. If this is used, it must be ensured that the process binary and all its auxiliary files + are available in the new root. Note that setting this parameter might result in additional dependencies to be added to the unit (see above). The MountAPIVFS= and PrivateUsers= settings are particularly useful From 0541d2959acc719ef5e0b906590d28e00145e1f4 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 27 Apr 2024 14:12:53 +0800 Subject: [PATCH 3/8] core: use close_and_replace more when deserializing Addresses https://github.com/systemd/systemd/pull/32441#discussion_r1579149873 --- src/core/execute-serialize.c | 14 +++++++------- src/core/manager-serialize.c | 6 ++---- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/core/execute-serialize.c b/src/core/execute-serialize.c index 0b6939b5d5a..7de2066c970 100644 --- a/src/core/execute-serialize.c +++ b/src/core/execute-serialize.c @@ -1597,7 +1597,7 @@ static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) { if (fd < 0) continue; - p->stdin_fd = fd; + close_and_replace(p->stdin_fd, fd); } else if ((val = startswith(l, "exec-parameters-stdout-fd="))) { int fd; @@ -1606,7 +1606,7 @@ static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) { if (fd < 0) continue; - p->stdout_fd = fd; + close_and_replace(p->stdout_fd, fd); } else if ((val = startswith(l, "exec-parameters-stderr-fd="))) { int fd; @@ -1615,7 +1615,7 @@ static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) { if (fd < 0) continue; - p->stderr_fd = fd; + close_and_replace(p->stderr_fd, fd); } else if ((val = startswith(l, "exec-parameters-exec-fd="))) { int fd; @@ -1623,7 +1623,7 @@ static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) { if (fd < 0) continue; - p->exec_fd = fd; + close_and_replace(p->exec_fd, fd); } else if ((val = startswith(l, "exec-parameters-handoff-timestamp-fd="))) { int fd; @@ -1639,13 +1639,13 @@ static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) { if (fd < 0) continue; - p->bpf_restrict_fs_map_fd = fd; + close_and_replace(p->bpf_restrict_fs_map_fd, fd); } else if ((val = startswith(l, "exec-parameters-notify-socket="))) { r = free_and_strdup(&p->notify_socket, val); if (r < 0) return r; } else if ((val = startswith(l, "exec-parameters-open-file="))) { - OpenFile *of = NULL; + OpenFile *of; r = open_file_parse(val, &of); if (r < 0) @@ -1663,7 +1663,7 @@ static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) { if (fd < 0) continue; - p->user_lookup_fd = fd; + close_and_replace(p->user_lookup_fd, fd); } else if ((val = startswith(l, "exec-parameters-files-env="))) { r = deserialize_strv(val, &p->files_env); if (r < 0) diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c index 39a8a0533f0..022d64a288d 100644 --- a/src/core/manager-serialize.c +++ b/src/core/manager-serialize.c @@ -456,8 +456,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { fd = deserialize_fd(fds, val); if (fd >= 0) { m->notify_event_source = sd_event_source_disable_unref(m->notify_event_source); - safe_close(m->notify_fd); - m->notify_fd = fd; + close_and_replace(m->notify_fd, fd); } } else if ((val = startswith(l, "notify-socket="))) { @@ -471,8 +470,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { fd = deserialize_fd(fds, val); if (fd >= 0) { m->cgroups_agent_event_source = sd_event_source_disable_unref(m->cgroups_agent_event_source); - safe_close(m->cgroups_agent_fd); - m->cgroups_agent_fd = fd; + close_and_replace(m->cgroups_agent_fd, fd); } } else if ((val = startswith(l, "user-lookup="))) { From b0c49dbcd75aa1f8771b5940d0e25137fd71f9dd Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 27 Apr 2024 14:08:10 +0800 Subject: [PATCH 4/8] core/manager-serialize: deserialize handoff-timestamp fds Follow-up for 817062e6211e7559ff91bcb7bb5dc4e472fc1646 Fixes #32512 --- src/core/manager-serialize.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c index 022d64a288d..b4af82b4e17 100644 --- a/src/core/manager-serialize.c +++ b/src/core/manager-serialize.c @@ -482,6 +482,15 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { if (r < 0) log_warning_errno(r, "Failed to parse user-lookup fds: \"%s\", ignoring: %m", val); + } else if ((val = startswith(l, "handoff-timestamp-fds="))) { + + m->handoff_timestamp_event_source = sd_event_source_disable_unref(m->handoff_timestamp_event_source); + safe_close_pair(m->handoff_timestamp_fds); + + r = deserialize_fd_many(fds, val, 2, m->handoff_timestamp_fds); + if (r < 0) + log_warning_errno(r, "Failed to parse handoff-timestamp fds: \"%s\", ignoring: %m", val); + } else if ((val = startswith(l, "dynamic-user="))) dynamic_user_deserialize_one(m, val, fds, NULL); else if ((val = startswith(l, "destroy-ipc-uid="))) From 0afd4d214fcb0e59340828f9e927a3f4a6b2afed Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 26 Apr 2024 01:44:15 +0800 Subject: [PATCH 5/8] core/execute: switch mount_apivfs to tristate No functional change, just refactoring. --- src/core/dbus-execute.c | 17 +++--------- src/core/exec-invoke.c | 2 +- src/core/execute-serialize.c | 20 ++++++--------- src/core/execute.c | 5 ++-- src/core/execute.h | 3 +-- src/core/load-fragment-gperf.gperf.in | 2 +- src/core/load-fragment.c | 37 --------------------------- 7 files changed, 17 insertions(+), 69 deletions(-) diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index b3cea73c434..e907aa67aff 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1744,6 +1744,9 @@ int bus_exec_context_set_transient_property( if (streq(name, "PrivateMounts")) return bus_set_transient_tristate(u, name, &c->private_mounts, message, flags, error); + if (streq(name, "MountAPIVFS")) + return bus_set_transient_tristate(u, name, &c->mount_apivfs, message, flags, error); + if (streq(name, "PrivateNetwork")) return bus_set_transient_bool(u, name, &c->private_network, message, flags, error); @@ -2711,20 +2714,6 @@ int bus_exec_context_set_transient_property( return 1; - } else if (streq(name, "MountAPIVFS")) { - bool b; - - r = bus_set_transient_bool(u, name, &b, message, flags, error); - if (r < 0) - return r; - - if (!UNIT_WRITE_FLAGS_NOOP(flags)) { - c->mount_apivfs = b; - c->mount_apivfs_set = true; - } - - return 1; - } else if (streq(name, "WorkingDirectory")) { _cleanup_free_ char *simplified = NULL; bool missing_ok, is_home; diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 2873563c0bc..0492bfba93b 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -3861,7 +3861,7 @@ static bool exec_context_need_unprivileged_private_users( context->private_ipc || context->ipc_namespace_path || context->private_mounts > 0 || - context->mount_apivfs || + context->mount_apivfs > 0 || context->n_bind_mounts > 0 || context->n_temporary_filesystems > 0 || context->root_directory || diff --git a/src/core/execute-serialize.c b/src/core/execute-serialize.c index 7de2066c970..ecd1e70db67 100644 --- a/src/core/execute-serialize.c +++ b/src/core/execute-serialize.c @@ -1832,6 +1832,10 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) { if (r < 0) return r; + r = serialize_item_tristate(f, "exec-context-mount-api-vfs", c->mount_apivfs); + if (r < 0) + return r; + r = serialize_item_tristate(f, "exec-context-memory-ksm", c->memory_ksm); if (r < 0) return r; @@ -1888,12 +1892,6 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) { if (r < 0) return r; - if (c->mount_apivfs_set) { - r = serialize_bool(f, "exec-context-mount-api-vfs", c->mount_apivfs); - if (r < 0) - return r; - } - r = serialize_bool_elide(f, "exec-context-same-pgrp", c->same_pgrp); if (r < 0) return r; @@ -2713,6 +2711,10 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) { r = safe_atoi(val, &c->private_mounts); if (r < 0) return r; + } else if ((val = startswith(l, "exec-context-mount-api-vfs="))) { + r = safe_atoi(val, &c->mount_apivfs); + if (r < 0) + return r; } else if ((val = startswith(l, "exec-context-memory-ksm="))) { r = safe_atoi(val, &c->memory_ksm); if (r < 0) @@ -2780,12 +2782,6 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) { c->protect_system = protect_system_from_string(val); if (c->protect_system < 0) return -EINVAL; - } else if ((val = startswith(l, "exec-context-mount-api-vfs="))) { - r = parse_boolean(val); - if (r < 0) - return r; - c->mount_apivfs = r; - c->mount_apivfs_set = true; } else if ((val = startswith(l, "exec-context-same-pgrp="))) { r = parse_boolean(val); if (r < 0) diff --git a/src/core/execute.c b/src/core/execute.c index 05a7f907a9b..80d5b30720b 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -504,6 +504,7 @@ void exec_context_init(ExecContext *c) { .tty_rows = UINT_MAX, .tty_cols = UINT_MAX, .private_mounts = -1, + .mount_apivfs = -1, .memory_ksm = -1, .set_login_environment = -1, }; @@ -1440,8 +1441,8 @@ bool exec_context_get_effective_mount_apivfs(const ExecContext *c) { assert(c); /* Explicit setting wins */ - if (c->mount_apivfs_set) - return c->mount_apivfs; + if (c->mount_apivfs >= 0) + return c->mount_apivfs > 0; /* Default to "yes" if root directory or image are specified */ if (exec_context_with_rootfs(c)) diff --git a/src/core/execute.h b/src/core/execute.h index 0719d3904a8..77ca1901e7e 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -200,7 +200,6 @@ struct ExecContext { bool nice_set:1; bool ioprio_set:1; bool cpu_sched_set:1; - bool mount_apivfs_set:1; /* This is not exposed to the user but available internally. We need it to make sure that whenever we * spawn /usr/bin/mount it is run in the same process group as us so that the autofs logic detects @@ -313,6 +312,7 @@ struct ExecContext { ProcSubset proc_subset; /* subset= */ int private_mounts; + int mount_apivfs; int memory_ksm; bool private_tmp; bool private_network; @@ -327,7 +327,6 @@ struct ExecContext { ProtectSystem protect_system; ProtectHome protect_home; bool protect_hostname; - bool mount_apivfs; bool dynamic_user; bool remove_ipc; diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in index 27aa27b55a9..5c75dcb155f 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -136,7 +136,7 @@ {{type}}.ProtectSystem, config_parse_protect_system, 0, offsetof({{type}}, exec_context.protect_system) {{type}}.ProtectHome, config_parse_protect_home, 0, offsetof({{type}}, exec_context.protect_home) {{type}}.MountFlags, config_parse_exec_mount_propagation_flag, 0, offsetof({{type}}, exec_context.mount_propagation_flag) -{{type}}.MountAPIVFS, config_parse_exec_mount_apivfs, 0, offsetof({{type}}, exec_context) +{{type}}.MountAPIVFS, config_parse_tristate, 0, offsetof({{type}}, exec_context.mount_apivfs) {{type}}.Personality, config_parse_personality, 0, offsetof({{type}}, exec_context.personality) {{type}}.RuntimeDirectoryPreserve, config_parse_exec_preserve_mode, 0, offsetof({{type}}, exec_context.runtime_directory_preserve_mode) {{type}}.RuntimeDirectoryMode, config_parse_mode, 0, offsetof({{type}}, exec_context.directories[EXEC_DIRECTORY_RUNTIME].mode) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 6d19715e792..d1bcdfe24e0 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1496,43 +1496,6 @@ int config_parse_exec_cpu_sched_policy(const char *unit, return 0; } -int config_parse_exec_mount_apivfs(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = ASSERT_PTR(data); - int k; - - assert(filename); - assert(lvalue); - assert(rvalue); - - if (isempty(rvalue)) { - c->mount_apivfs_set = false; - c->mount_apivfs = false; - return 0; - } - - k = parse_boolean(rvalue); - if (k < 0) { - log_syntax(unit, LOG_WARNING, filename, line, k, - "Failed to parse boolean value, ignoring: %s", - rvalue); - return 0; - } - - c->mount_apivfs_set = true; - c->mount_apivfs = k; - return 0; -} - int config_parse_numa_mask(const char *unit, const char *filename, unsigned line, From 16871b608e1958f05e4e4cca99927df57a09b200 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 26 Apr 2024 11:07:59 +0800 Subject: [PATCH 6/8] core/namespace: use FOREACH_ARRAY at one more place --- src/core/namespace.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/namespace.c b/src/core/namespace.c index 763520842d6..88f5d0f1582 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -2644,9 +2644,9 @@ int setup_namespace(const NamespaceParameters *p, char **error_path) { void bind_mount_free_many(BindMount *b, size_t n) { assert(b || n == 0); - for (size_t i = 0; i < n; i++) { - free(b[i].source); - free(b[i].destination); + FOREACH_ARRAY(i, b, n) { + free(i->source); + free(i->destination); } free(b); From 6117dda8de2040a972098b59d33034684eb53bf4 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 27 Apr 2024 16:46:14 +0800 Subject: [PATCH 7/8] core/namespace: modernize clone_device_node --- src/core/namespace.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/core/namespace.c b/src/core/namespace.c index 88f5d0f1582..1c0a204ee2b 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -902,42 +902,41 @@ static void drop_outside_root(MountList *ml, const char *root_directory) { ml->n_mounts = t - ml->mounts; } -static int clone_device_node( - const char *d, - const char *temporary_mount, - bool *make_devnode) { - +static int clone_device_node(const char *node, const char *temporary_mount, bool *make_devnode) { _cleanup_free_ char *sl = NULL; - const char *dn, *bn, *t; + const char *dn, *bn; struct stat st; int r; - if (stat(d, &st) < 0) { + assert(node); + assert(path_is_absolute(node)); + assert(temporary_mount); + assert(make_devnode); + + if (stat(node, &st) < 0) { if (errno == ENOENT) { - log_debug_errno(errno, "Device node '%s' to clone does not exist, ignoring.", d); + log_debug_errno(errno, "Device node '%s' to clone does not exist.", node); return -ENXIO; } - return log_debug_errno(errno, "Failed to stat() device node '%s' to clone, ignoring: %m", d); + return log_debug_errno(errno, "Failed to stat() device node '%s' to clone: %m", node); } - if (!S_ISBLK(st.st_mode) && - !S_ISCHR(st.st_mode)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "Device node '%s' to clone is not a device node, ignoring.", - d); + r = stat_verify_device_node(&st); + if (r < 0) + return log_debug_errno(r, "Cannot clone device node '%s': %m", node); - dn = strjoina(temporary_mount, d); + dn = strjoina(temporary_mount, node); /* First, try to create device node properly */ if (*make_devnode) { - mac_selinux_create_file_prepare(d, st.st_mode); + mac_selinux_create_file_prepare(node, st.st_mode); r = mknod(dn, st.st_mode, st.st_rdev); mac_selinux_create_file_clear(); if (r >= 0) goto add_symlink; if (errno != EPERM) - return log_debug_errno(errno, "mknod failed for %s: %m", d); + return log_debug_errno(errno, "Failed to mknod '%s': %m", node); /* This didn't work, let's not try this again for the next iterations. */ *make_devnode = false; @@ -947,17 +946,17 @@ static int clone_device_node( * Do not prepare device-node SELinux label (see issue 13762) */ r = mknod(dn, S_IFREG, 0); if (r < 0 && errno != EEXIST) - return log_debug_errno(errno, "mknod() fallback failed for '%s': %m", d); + return log_debug_errno(errno, "Failed to mknod dummy device node for '%s': %m", node); /* Fallback to bind-mounting: The assumption here is that all used device nodes carry standard * properties. Specifically, the devices nodes we bind-mount should either be owned by root:root or * root:tty (e.g. /dev/tty, /dev/ptmx) and should not carry ACLs. */ - r = mount_nofollow_verbose(LOG_DEBUG, d, dn, NULL, MS_BIND, NULL); + r = mount_nofollow_verbose(LOG_DEBUG, node, dn, NULL, MS_BIND, NULL); if (r < 0) return r; add_symlink: - bn = path_startswith(d, "/dev/"); + bn = path_startswith(node, "/dev/"); if (!bn) return 0; @@ -970,7 +969,7 @@ add_symlink: (void) mkdir_parents(sl, 0755); - t = strjoina("../", bn); + const char *t = strjoina("../", bn); if (symlink(t, sl) < 0) log_debug_errno(errno, "Failed to symlink '%s' to '%s', ignoring: %m", t, sl); From 66825795b4716f5fd8f61178cb0fc6f92cc096cb Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sat, 27 Apr 2024 14:25:36 +0800 Subject: [PATCH 8/8] core/namespace: modernize mount_private_dev --- src/core/namespace.c | 103 ++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 61 deletions(-) diff --git a/src/core/namespace.c b/src/core/namespace.c index 1c0a204ee2b..27227a4b522 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -976,7 +976,20 @@ add_symlink: return 0; } -static char *settle_runtime_dir(RuntimeScope scope) { +static int bind_mount_device_dir(const char *temporary_mount, const char *dir) { + const char *t; + + assert(temporary_mount); + assert(dir); + assert(path_is_absolute(dir)); + + t = strjoina(temporary_mount, dir); + + (void) mkdir(t, 0755); + return mount_nofollow_verbose(LOG_DEBUG, dir, t, NULL, MS_BIND, NULL); +} + +static char* settle_runtime_dir(RuntimeScope scope) { char *runtime_dir; if (scope != RUNTIME_SCOPE_USER) @@ -1017,8 +1030,8 @@ static int mount_private_dev(MountEntry *m, RuntimeScope scope) { "/dev/urandom\0" "/dev/tty\0"; - _cleanup_free_ char *temporary_mount = NULL; - const char *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL; + _cleanup_(rmdir_and_freep) char *temporary_mount = NULL; + _cleanup_(umount_and_rmdir_and_freep) char *dev = NULL; bool can_mknod = true; int r; @@ -1028,67 +1041,56 @@ static int mount_private_dev(MountEntry *m, RuntimeScope scope) { if (r < 0) return r; - dev = strjoina(temporary_mount, "/dev"); + dev = path_join(temporary_mount, "dev"); + if (!dev) + return -ENOMEM; + (void) mkdir(dev, 0755); r = mount_nofollow_verbose(LOG_DEBUG, "tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=0755" TMPFS_LIMITS_PRIVATE_DEV); if (r < 0) - goto fail; + return r; r = label_fix_full(AT_FDCWD, dev, "/dev", 0); - if (r < 0) { - log_debug_errno(r, "Failed to fix label of '%s' as /dev: %m", dev); - goto fail; - } - - devpts = strjoina(temporary_mount, "/dev/pts"); - (void) mkdir(devpts, 0755); - r = mount_nofollow_verbose(LOG_DEBUG, "/dev/pts", devpts, NULL, MS_BIND, NULL); if (r < 0) - goto fail; + return log_debug_errno(r, "Failed to fix label of '%s' as /dev/: %m", dev); + + r = bind_mount_device_dir(temporary_mount, "/dev/pts"); + if (r < 0) + return r; /* /dev/ptmx can either be a device node or a symlink to /dev/pts/ptmx. * When /dev/ptmx a device node, /dev/pts/ptmx has 000 permissions making it inaccessible. * Thus, in that case make a clone. * In nspawn and other containers it will be a symlink, in that case make it a symlink. */ r = is_symlink("/dev/ptmx"); - if (r < 0) { - log_debug_errno(r, "Failed to detect whether /dev/ptmx is a symlink or not: %m"); - goto fail; - } else if (r > 0) { - devptmx = strjoina(temporary_mount, "/dev/ptmx"); - if (symlink("pts/ptmx", devptmx) < 0) { - r = log_debug_errno(errno, "Failed to create a symlink '%s' to pts/ptmx: %m", devptmx); - goto fail; - } + if (r < 0) + return log_debug_errno(r, "Failed to detect whether /dev/ptmx is a symlink or not: %m"); + if (r > 0) { + const char *devptmx = strjoina(temporary_mount, "/dev/ptmx"); + if (symlink("pts/ptmx", devptmx) < 0) + return log_debug_errno(errno, "Failed to create symlink '%s' to pts/ptmx: %m", devptmx); } else { r = clone_device_node("/dev/ptmx", temporary_mount, &can_mknod); if (r < 0) - goto fail; + return r; } - devshm = strjoina(temporary_mount, "/dev/shm"); - (void) mkdir(devshm, 0755); - r = mount_nofollow_verbose(LOG_DEBUG, "/dev/shm", devshm, NULL, MS_BIND, NULL); + r = bind_mount_device_dir(temporary_mount, "/dev/shm"); if (r < 0) - goto fail; + return r; - devmqueue = strjoina(temporary_mount, "/dev/mqueue"); - (void) mkdir(devmqueue, 0755); - (void) mount_nofollow_verbose(LOG_DEBUG, "/dev/mqueue", devmqueue, NULL, MS_BIND, NULL); + FOREACH_STRING(d, "/dev/mqueue", "/dev/hugepages") + (void) bind_mount_device_dir(temporary_mount, d); - devhugepages = strjoina(temporary_mount, "/dev/hugepages"); - (void) mkdir(devhugepages, 0755); - (void) mount_nofollow_verbose(LOG_DEBUG, "/dev/hugepages", devhugepages, NULL, MS_BIND, NULL); - - devlog = strjoina(temporary_mount, "/dev/log"); + const char *devlog = strjoina(temporary_mount, "/dev/log"); if (symlink("/run/systemd/journal/dev-log", devlog) < 0) - log_debug_errno(errno, "Failed to create a symlink '%s' to /run/systemd/journal/dev-log, ignoring: %m", devlog); + log_debug_errno(errno, "Failed to create symlink '%s' to /run/systemd/journal/dev-log, ignoring: %m", devlog); NULSTR_FOREACH(d, devnodes) { r = clone_device_node(d, temporary_mount, &can_mknod); /* ENXIO means the *source* is not a device file, skip creation in that case */ if (r < 0 && r != -ENXIO) - goto fail; + return r; } r = dev_setup(temporary_mount, UID_INVALID, GID_INVALID); @@ -1106,31 +1108,10 @@ static int mount_private_dev(MountEntry *m, RuntimeScope scope) { r = mount_nofollow_verbose(LOG_DEBUG, dev, mount_entry_path(m), NULL, MS_MOVE, NULL); if (r < 0) - goto fail; - - (void) rmdir(dev); - (void) rmdir(temporary_mount); + return r; + dev = rmdir_and_free(dev); /* Mount is successfully moved, do not umount() */ return 1; - -fail: - if (devpts) - (void) umount_verbose(LOG_DEBUG, devpts, UMOUNT_NOFOLLOW); - - if (devshm) - (void) umount_verbose(LOG_DEBUG, devshm, UMOUNT_NOFOLLOW); - - if (devhugepages) - (void) umount_verbose(LOG_DEBUG, devhugepages, UMOUNT_NOFOLLOW); - - if (devmqueue) - (void) umount_verbose(LOG_DEBUG, devmqueue, UMOUNT_NOFOLLOW); - - (void) umount_verbose(LOG_DEBUG, dev, UMOUNT_NOFOLLOW); - (void) rmdir(dev); - (void) rmdir(temporary_mount); - - return r; } static int mount_bind_dev(const MountEntry *m) {