diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index dd44d5eb92..028c4de280 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -535,9 +535,9 @@ int mount_setup(bool loaded_policy, bool leave_propagation) { (void) mkdir_label("/run/systemd", 0755); (void) mkdir_label("/run/systemd/system", 0755); - /* Also create /run/systemd/inaccessible nodes, so that we always have something to mount inaccessible nodes - * from. */ - (void) make_inaccessible_nodes("/run/systemd", UID_INVALID, GID_INVALID); + /* Also create /run/systemd/inaccessible nodes, so that we always have something to mount + * inaccessible nodes from. */ + (void) make_inaccessible_nodes(NULL, UID_INVALID, GID_INVALID); return 0; } diff --git a/src/core/namespace.c b/src/core/namespace.c index 34eb469fb8..9bea6ea46c 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -939,10 +939,10 @@ static int apply_mount( } if (geteuid() == 0) - runtime_dir = "/run/systemd"; + runtime_dir = "/run"; else { - if (asprintf(&tmp, "/run/user/"UID_FMT, geteuid()) < 0) - log_oom(); + if (asprintf(&tmp, "/run/user/" UID_FMT, geteuid()) < 0) + return -ENOMEM; runtime_dir = tmp; } diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 33cc19a425..eb80c2960b 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -898,7 +898,7 @@ static int mount_inaccessible(const char *dest, CustomMount *m) { return m->graceful ? 0 : r; } - r = mode_to_inaccessible_node("/run/systemd", st.st_mode, &source); + r = mode_to_inaccessible_node(NULL, st.st_mode, &source); if (r < 0) return m->graceful ? 0 : r; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 8e8881749a..0ce71e1103 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3471,7 +3471,7 @@ static int outer_child( (void) dev_setup(directory, arg_uid_shift, arg_uid_shift); - p = prefix_roota(directory, "/run/systemd"); + p = prefix_roota(directory, "/run"); (void) make_inaccessible_nodes(p, arg_uid_shift, arg_uid_shift); r = setup_pts(directory); diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c index 4bce8b167b..6a280cde01 100644 --- a/src/shared/dev-setup.c +++ b/src/shared/dev-setup.c @@ -56,31 +56,38 @@ int dev_setup(const char *prefix, uid_t uid, gid_t gid) { return 0; } -int make_inaccessible_nodes(const char *root, uid_t uid, gid_t gid) { +int make_inaccessible_nodes( + const char *runtime_dir, + uid_t uid, + gid_t gid) { + static const struct { const char *name; mode_t mode; } table[] = { - { "", S_IFDIR | 0755 }, - { "/inaccessible", S_IFDIR | 0000 }, - { "/inaccessible/reg", S_IFREG | 0000 }, - { "/inaccessible/dir", S_IFDIR | 0000 }, - { "/inaccessible/fifo", S_IFIFO | 0000 }, - { "/inaccessible/sock", S_IFSOCK | 0000 }, + { "/systemd", S_IFDIR | 0755 }, + { "/systemd/inaccessible", S_IFDIR | 0000 }, + { "/systemd/inaccessible/reg", S_IFREG | 0000 }, + { "/systemd/inaccessible/dir", S_IFDIR | 0000 }, + { "/systemd/inaccessible/fifo", S_IFIFO | 0000 }, + { "/systemd/inaccessible/sock", S_IFSOCK | 0000 }, /* The following two are likely to fail if we lack the privs for it (for example in an userns * environment, if CAP_SYS_MKNOD is missing, or if a device node policy prohibit major/minor of 0 * device nodes to be created). But that's entirely fine. Consumers of these files should carry * fallback to use a different node then, for example /inaccessible/sock, which is close * enough in behaviour and semantics for most uses. */ - { "/inaccessible/chr", S_IFCHR | 0000 }, - { "/inaccessible/blk", S_IFBLK | 0000 }, + { "/systemd/inaccessible/chr", S_IFCHR | 0000 }, + { "/systemd/inaccessible/blk", S_IFBLK | 0000 }, }; _cleanup_umask_ mode_t u; size_t i; int r; + if (!runtime_dir) + runtime_dir = "/run"; + u = umask(0000); /* Set up inaccessible (and empty) file nodes of all types. This are used to as mount sources for over-mounting @@ -91,7 +98,7 @@ int make_inaccessible_nodes(const char *root, uid_t uid, gid_t gid) { for (i = 0; i < ELEMENTSOF(table); i++) { _cleanup_free_ char *path = NULL; - path = path_join(root, table[i].name); + path = path_join(runtime_dir, table[i].name); if (!path) return log_oom(); diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c index f3ee656c0f..d188e6bd7f 100644 --- a/src/shared/mount-util.c +++ b/src/shared/mount-util.c @@ -397,71 +397,73 @@ int repeat_unmount(const char *path, int flags) { } } -int mode_to_inaccessible_node(const char *runtime_dir, mode_t mode, char **dest) { - /* This function maps a node type to a corresponding inaccessible file node. These nodes are created during - * early boot by PID 1. In some cases we lacked the privs to create the character and block devices (maybe - * because we run in an userns environment, or miss CAP_SYS_MKNOD, or run with a devices policy that excludes - * device nodes with major and minor of 0), but that's fine, in that case we use an AF_UNIX file node instead, - * which is not the same, but close enough for most uses. And most importantly, the kernel allows bind mounts - * from socket nodes to any non-directory file nodes, and that's the most important thing that matters. */ +int mode_to_inaccessible_node( + const char *runtime_dir, + mode_t mode, + char **ret) { + + /* This function maps a node type to a corresponding inaccessible file node. These nodes are created + * during early boot by PID 1. In some cases we lacked the privs to create the character and block + * devices (maybe because we run in an userns environment, or miss CAP_SYS_MKNOD, or run with a + * devices policy that excludes device nodes with major and minor of 0), but that's fine, in that + * case we use an AF_UNIX file node instead, which is not the same, but close enough for most + * uses. And most importantly, the kernel allows bind mounts from socket nodes to any non-directory + * file nodes, and that's the most important thing that matters. + * + * Note that the runtime directory argument shall be the top-level runtime directory, i.e. /run/ if + * we operate in system context and $XDG_RUNTIME_DIR if we operate in user context. */ + _cleanup_free_ char *d = NULL; const char *node = NULL; - char *tmp; + bool fallback = false; - assert(dest); + assert(ret); + + if (!runtime_dir) + runtime_dir = "/run"; switch(mode & S_IFMT) { case S_IFREG: - node = "/inaccessible/reg"; + node = "/systemd/inaccessible/reg"; break; case S_IFDIR: - node = "/inaccessible/dir"; + node = "/systemd/inaccessible/dir"; break; case S_IFCHR: - d = path_join(runtime_dir, "/inaccessible/chr"); - if (!d) - return log_oom(); - - if (access(d, F_OK) == 0) { - *dest = TAKE_PTR(d); - return 0; - } - - node = "/inaccessible/sock"; + node = "/systemd/inaccessible/chr"; + fallback = true; break; case S_IFBLK: - d = path_join(runtime_dir, "/inaccessible/blk"); - if (!d) - return log_oom(); - - if (access(d, F_OK) == 0) { - *dest = TAKE_PTR(d); - return 0; - } - - node = "/inaccessible/sock"; + node = "/systemd/inaccessible/blk"; + fallback = true; break; case S_IFIFO: - node = "/inaccessible/fifo"; + node = "/systemd/inaccessible/fifo"; break; case S_IFSOCK: - node = "/inaccessible/sock"; + node = "/systemd/inaccessible/sock"; break; } - if (!node) return -EINVAL; - tmp = path_join(runtime_dir, node); - if (!tmp) - return log_oom(); + d = path_join(runtime_dir, node); + if (!d) + return -ENOMEM; - *dest = tmp; + if (fallback && access(d, F_OK) < 0) { + free(d); + d = path_join(runtime_dir, "/systemd/inaccessible/sock"); + if (!d) + return -ENOMEM; + } + + *ret = TAKE_PTR(d); return 0; } diff --git a/src/test/test-dev-setup.c b/src/test/test-dev-setup.c index d991fe5200..038484e475 100644 --- a/src/test/test-dev-setup.c +++ b/src/test/test-dev-setup.c @@ -20,7 +20,6 @@ int main(int argc, char *argv[]) { f = prefix_roota(p, "/run"); assert_se(mkdir(f, 0755) >= 0); - f = prefix_roota(p, "/run/systemd"); assert_se(make_inaccessible_nodes(f, 1, 1) >= 0); f = prefix_roota(p, "/run/systemd/inaccessible/reg");