From 78e9bb837c258ac0ec7712b3d612cc2f407e731e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 05:50:42 +0200 Subject: Merging upstream version 256. Signed-off-by: Daniel Baumann --- src/shared/dev-setup.c | 64 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 23 deletions(-) (limited to 'src/shared/dev-setup.c') diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c index f7ed161..4b4b625 100644 --- a/src/shared/dev-setup.c +++ b/src/shared/dev-setup.c @@ -7,6 +7,7 @@ #include "alloc-util.h" #include "dev-setup.h" #include "fd-util.h" +#include "fs-util.h" #include "label-util.h" #include "lock-util.h" #include "log.h" @@ -21,13 +22,15 @@ int lock_dev_console(void) { _cleanup_close_ int fd = -EBADF; int r; - fd = open_terminal("/dev/console", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + /* NB: We do not use O_NOFOLLOW here, because some container managers might place a symlink to some + * pty in /dev/console, in which case it should be fine to lock the target TTY. */ + fd = open_terminal("/dev/console", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (fd < 0) return fd; r = lock_generic(fd, LOCK_BSD, LOCK_EX); if (r < 0) - return log_error_errno(r, "Failed to lock /dev/console: %m"); + return r; return TAKE_FD(fd); } @@ -79,15 +82,11 @@ int make_inaccessible_nodes( uid_t uid, gid_t gid) { - static const struct { - const char *name; - mode_t mode; - } table[] = { - { "inaccessible", S_IFDIR | 0755 }, - { "inaccessible/reg", S_IFREG | 0000 }, - { "inaccessible/dir", S_IFDIR | 0000 }, - { "inaccessible/fifo", S_IFIFO | 0000 }, - { "inaccessible/sock", S_IFSOCK | 0000 }, + static const mode_t table[] = { + S_IFREG, + S_IFDIR, + S_IFIFO, + S_IFSOCK, /* 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 prohibits creation of @@ -95,10 +94,13 @@ int make_inaccessible_nodes( * should implement falling back 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 }, + S_IFCHR, + S_IFBLK, + + /* NB: S_IFLNK is not listed here, as there is no such thing as an inaccessible symlink */ }; + _cleanup_close_ int parent_fd = -EBADF, inaccessible_fd = -EBADF; int r; if (!parent_dir) @@ -106,32 +108,48 @@ int make_inaccessible_nodes( BLOCK_WITH_UMASK(0000); + parent_fd = open(parent_dir, O_DIRECTORY|O_CLOEXEC|O_PATH, 0); + if (parent_fd < 0) + return -errno; + + inaccessible_fd = open_mkdir_at_full(parent_fd, "inaccessible", O_CLOEXEC, XO_LABEL, 0755); + if (inaccessible_fd < 0) + return inaccessible_fd; + /* Set up inaccessible (and empty) file nodes of all types. This are used to as mount sources for over-mounting * ("masking") file nodes that shall become inaccessible and empty for specific containers or services. We try * to lock down these nodes as much as we can, but otherwise try to match them as closely as possible with the * underlying file, i.e. in the best case we offer the same node type as the underlying node. */ - for (size_t i = 0; i < ELEMENTSOF(table); i++) { + FOREACH_ELEMENT(m, table) { _cleanup_free_ char *path = NULL; + mode_t inode_type = *m; + const char *fn; - path = path_join(parent_dir, table[i].name); + fn = inode_type_to_string(inode_type); + path = path_join(parent_dir, fn); if (!path) return log_oom(); - if (S_ISDIR(table[i].mode)) - r = mkdir_label(path, table[i].mode & 07777); + if (S_ISDIR(inode_type)) + r = mkdirat_label(inaccessible_fd, fn, 0000); else - r = mknod_label(path, table[i].mode, makedev(0, 0)); - if (r < 0) { + r = mknodat_label(inaccessible_fd, fn, inode_type | 0000, makedev(0, 0)); + if (r == -EEXIST) { + if (fchmodat(inaccessible_fd, fn, 0000, AT_SYMLINK_NOFOLLOW) < 0) + log_debug_errno(errno, "Failed to adjust access mode of existing inode '%s', ignoring: %m", path); + } else if (r < 0) { log_debug_errno(r, "Failed to create '%s', ignoring: %m", path); continue; } - if (uid != UID_INVALID || gid != GID_INVALID) { - if (lchown(path, uid, gid) < 0) - log_debug_errno(errno, "Failed to chown '%s': %m", path); - } + if (uid_is_valid(uid) || gid_is_valid(gid)) + if (fchownat(inaccessible_fd, fn, uid, gid, AT_SYMLINK_NOFOLLOW) < 0) + log_debug_errno(errno, "Failed to chown '%s', ignoring: %m", path); } + if (fchmod(inaccessible_fd, 0555) < 0) + log_debug_errno(errno, "Failed to mark inaccessible directory read-only, ignoring: %m"); + return 0; } -- cgit v1.2.3