diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2020-06-10 10:23:13 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-10 10:23:13 +0200 |
commit | 9664be199af6423856c3838a8582878be1bc8bfa (patch) | |
tree | d9977611ff698ade27e4175cf90bbc101b7320ff /src | |
parent | 2befe404d4dbd398f30d6a14aad1132081dbd1fb (diff) | |
parent | 48b747fa03ec6b7edd7a31621c5b1d6cf123283d (diff) | |
download | systemd-9664be199af6423856c3838a8582878be1bc8bfa.tar.gz |
Merge pull request #16118 from poettering/inaccessible-fixlets
move $XDG_RUNTIME_DIR/inaccessible/ to $XDG_RUNTIME_DIR/systemd/inaccessible
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/mkdir.c | 37 | ||||
-rw-r--r-- | src/core/mount-setup.c | 6 | ||||
-rw-r--r-- | src/core/namespace.c | 6 | ||||
-rw-r--r-- | src/login/user-runtime-dir.c | 2 | ||||
-rw-r--r-- | src/nspawn/nspawn-mount.c | 2 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 2 | ||||
-rw-r--r-- | src/shared/dev-setup.c | 27 | ||||
-rw-r--r-- | src/shared/mount-util.c | 78 | ||||
-rw-r--r-- | src/test/test-dev-setup.c | 1 |
9 files changed, 86 insertions, 75 deletions
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index fa682d4c43..ff20cec985 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -14,11 +14,18 @@ #include "stdio-util.h" #include "user-util.h" -int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir) { +int mkdir_safe_internal( + const char *path, + mode_t mode, + uid_t uid, gid_t gid, + MkdirFlags flags, + mkdir_func_t _mkdir) { + struct stat st; int r; - assert(_mkdir != mkdir); + assert(path); + assert(_mkdir && _mkdir != mkdir); if (_mkdir(path, mode) >= 0) { r = chmod_and_chown(path, mode, uid, gid); @@ -44,19 +51,16 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, Mkd return -errno; } - if (!S_ISDIR(st.st_mode)) { - log_full(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, - "Path \"%s\" already exists and is not a directory, refusing.", path); - return -ENOTDIR; - } + if (!S_ISDIR(st.st_mode)) + return log_full_errno(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, SYNTHETIC_ERRNO(ENOTDIR), + "Path \"%s\" already exists and is not a directory, refusing.", path); if ((st.st_mode & 0007) > (mode & 0007) || (st.st_mode & 0070) > (mode & 0070) || - (st.st_mode & 0700) > (mode & 0700)) { - log_full(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, - "Directory \"%s\" already exists, but has mode %04o that is too permissive (%04o was requested), refusing.", - path, st.st_mode & 0777, mode); - return -EEXIST; - } + (st.st_mode & 0700) > (mode & 0700)) + return log_full_errno(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, SYNTHETIC_ERRNO(EEXIST), + "Directory \"%s\" already exists, but has mode %04o that is too permissive (%04o was requested), refusing.", + path, st.st_mode & 0777, mode); + if ((uid != UID_INVALID && st.st_uid != uid) || (gid != GID_INVALID && st.st_gid != gid)) { char u[DECIMAL_STR_MAX(uid_t)] = "-", g[DECIMAL_STR_MAX(gid_t)] = "-"; @@ -65,10 +69,9 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, Mkd xsprintf(u, UID_FMT, uid); if (gid != UID_INVALID) xsprintf(g, GID_FMT, gid); - log_full(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, - "Directory \"%s\" already exists, but is owned by "UID_FMT":"GID_FMT" (%s:%s was requested), refusing.", - path, st.st_uid, st.st_gid, u, g); - return -EEXIST; + return log_full_errno(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, SYNTHETIC_ERRNO(EEXIST), + "Directory \"%s\" already exists, but is owned by "UID_FMT":"GID_FMT" (%s:%s was requested), refusing.", + path, st.st_uid, st.st_gid, u, g); } return 0; 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 b02274b9a6..6bfc266dc0 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/login/user-runtime-dir.c b/src/login/user-runtime-dir.c index 4055c910c2..fdf0124c41 100644 --- a/src/login/user-runtime-dir.c +++ b/src/login/user-runtime-dir.c @@ -78,7 +78,7 @@ static int user_mkdir_runtime_path( r = mount("tmpfs", runtime_path, "tmpfs", MS_NODEV|MS_NOSUID, options); if (r < 0) { - if (!IN_SET(errno, EPERM, EACCES)) { + if (!ERRNO_IS_PRIVILEGE(errno)) { r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", runtime_path); goto fail; } 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 9a9ddecabb..f3a3ee8a17 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3482,7 +3482,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 <root>/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; + + if (fallback && access(d, F_OK) < 0) { + free(d); + d = path_join(runtime_dir, "/systemd/inaccessible/sock"); + if (!d) + return -ENOMEM; + } - *dest = tmp; + *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"); |