]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
conf: handle partially functional device nodes 2460/head
authorChristian Brauner <christian.brauner@ubuntu.com>
Thu, 12 Jul 2018 10:43:34 +0000 (12:43 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Thu, 12 Jul 2018 10:43:34 +0000 (12:43 +0200)
This improves handling kernels which allow userspace to create partially
functional devices nodes.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/conf.c

index d8c6eda1a37a092c8aaefcb37d2e875b0d7d55ae..1ff2f5e0a89e97e12ee542be9248e363ff93a1c5 100644 (file)
@@ -1260,12 +1260,20 @@ static const struct lxc_device_node lxc_devices[] = {
        { "zero",    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 5 },
 };
 
+
+enum {
+       LXC_DEVNODE_BIND,
+       LXC_DEVNODE_MKNOD,
+       LXC_DEVNODE_PARTIAL,
+       LXC_DEVNODE_OPEN,
+};
+
 static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
 {
        int i, ret;
        char path[MAXPATHLEN];
        mode_t cmask;
-       int can_mknod = 1;
+       int use_mknod = LXC_DEVNODE_MKNOD;
 
        ret = snprintf(path, MAXPATHLEN, "%s/dev",
                       rootfs->path ? rootfs->mount : "");
@@ -1288,34 +1296,52 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
                if (ret < 0 || ret >= MAXPATHLEN)
                        return -1;
 
-               /* See
-                * - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=55956b59df336f6738da916dbb520b6e37df9fbd
-                * - https://lists.linuxfoundation.org/pipermail/containers/2018-June/039176.html
-                */
-               if (can_mknod == 2 || (can_mknod == 1 && !am_host_unpriv())) {
+               if (use_mknod >= LXC_DEVNODE_MKNOD) {
                        ret = mknod(path, device->mode, makedev(device->maj, device->min));
                        if (ret == 0 || (ret < 0 && errno == EEXIST)) {
                                DEBUG("Created device node \"%s\"", path);
-                               continue;
-                       }
+                       } else if (ret < 0) {
+                               if (errno != EPERM) {
+                                       SYSERROR("Failed to create device node \"%s\"", path);
+                                       return -1;
+                               }
 
-                       if (errno != EPERM) {
-                               SYSERROR("Failed to create device node \"%s\"", path);
-                               return -1;
+                               use_mknod = LXC_DEVNODE_BIND;
                        }
 
-                       /* This can e.g. happen when the container is
-                        * unprivileged or CAP_MKNOD has been dropped.
-                        */
-                       can_mknod = 2;
-               } else {
-                       can_mknod = 0;
+                       /* Device nodes are fully useable. */
+                       if (use_mknod == LXC_DEVNODE_OPEN)
+                               continue;
+
+                       if (use_mknod == LXC_DEVNODE_MKNOD) {
+                               /* See
+                                * - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=55956b59df336f6738da916dbb520b6e37df9fbd
+                                * - https://lists.linuxfoundation.org/pipermail/containers/2018-June/039176.html
+                                */
+                               ret = open(path, O_RDONLY | O_CLOEXEC);
+                               if (ret >= 0) {
+                                       close(ret);
+                                       /* Device nodes are fully useable. */
+                                       use_mknod = LXC_DEVNODE_OPEN;
+                                       continue;
+                               }
+
+                               SYSTRACE("Failed to open \"%s\" device", path);
+                               /* Device nodes are only partially useable. */
+                               use_mknod = LXC_DEVNODE_PARTIAL;
+                       }
                }
 
-               ret = mknod(path, S_IFREG | 0000, 0);
-               if (ret < 0 && errno != EEXIST) {
-                       SYSERROR("Failed to create file \"%s\"", path);
-                       return -1;
+               if (use_mknod != LXC_DEVNODE_PARTIAL) {
+                       /* If we are dealing with partially functional device
+                        * nodes the prio mknod() call will have created the
+                        * device node so we can use it as a bind-mount target.
+                        */
+                       ret = mknod(path, S_IFREG | 0000, 0);
+                       if (ret < 0 && errno != EEXIST) {
+                               SYSERROR("Failed to create file \"%s\"", path);
+                               return -1;
+                       }
                }
 
                /* Fallback to bind-mounting the device from the host. */