]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
mount-util: tweak how we find inaccessible device nodes
authorLennart Poettering <lennart@poettering.net>
Wed, 19 Aug 2020 15:25:33 +0000 (17:25 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 20 Aug 2020 16:15:29 +0000 (18:15 +0200)
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

index b3fac13f7ee9cd487c1edd518c8435c0f1de9ca3..4d40acfb4c06dfc8e598b8cbe87d530827deeac5 100644 (file)
@@ -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)