From cbed1dc8af748138ba32f079959c577bfa8365b2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2020 17:25:33 +0200 Subject: [PATCH] mount-util: tweak how we find inaccessible device nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On new kernels (>= 5.8) unprivileged users may create the 0:0 character device node. Which is great, as we can use that as inaccessible device nodes if we run unprivileged. Hence, change how we find the right inaccessible device inodes: when the user asks for a block device node, but we have none, try the char device node first. If that doesn't exist, fall back to the socket node as before. This means that: 1. in the best case we'll return a node if the right device node type 2. otherwise we hopefully at least can return a device node if one asked for even if the type doesn't match (i.e. we return char instead of the requested block device node) 3. in the worst case (old kernels…) we'll return a socket node --- src/shared/mount-util.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c index b3fac13f7ee..4d40acfb4c0 100644 --- a/src/shared/mount-util.c +++ b/src/shared/mount-util.c @@ -414,7 +414,6 @@ int mode_to_inaccessible_node( _cleanup_free_ char *d = NULL; const char *node = NULL; - bool fallback = false; assert(ret); @@ -432,12 +431,10 @@ int mode_to_inaccessible_node( case S_IFCHR: node = "/systemd/inaccessible/chr"; - fallback = true; break; case S_IFBLK: node = "/systemd/inaccessible/blk"; - fallback = true; break; case S_IFIFO: @@ -455,7 +452,24 @@ int mode_to_inaccessible_node( if (!d) return -ENOMEM; - if (fallback && access(d, F_OK) < 0) { + /* On new kernels unprivileged users are permitted to create 0:0 char device nodes (because they also + * act as whiteout inode for overlayfs), but no other char or block device nodes. On old kernels no + * device node whatsoever may be created by unprivileged processes. Hence, if the caller asks for the + * inaccessible block device node let's see if the block device node actually exists, and if not, + * fall back to the character device node. From there fall back to the socket device node. This means + * in the best case we'll get the right device node type — but if not we'll hopefully at least get a + * device node at all. */ + + if (S_ISBLK(mode) && + access(d, F_OK) < 0 && errno == ENOENT) { + free(d); + d = path_join(runtime_dir, "/systemd/inaccessible/chr"); + if (!d) + return -ENOMEM; + } + + if (IN_SET(mode & S_IFMT, S_IFBLK, S_IFCHR) && + access(d, F_OK) < 0 && errno == ENOENT) { free(d); d = path_join(runtime_dir, "/systemd/inaccessible/sock"); if (!d)