From: Lennart Poettering Date: Wed, 19 Aug 2020 15:25:33 +0000 (+0200) Subject: mount-util: tweak how we find inaccessible device nodes X-Git-Tag: v247-rc1~392 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cbed1dc8af748138ba32f079959c577bfa8365b2;p=thirdparty%2Fsystemd.git mount-util: tweak how we find inaccessible device nodes 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 --- 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)