]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
autodev: adapt to changes in Linux 4.18 2438/head
authorChristian Brauner <christian.brauner@ubuntu.com>
Fri, 29 Jun 2018 11:58:52 +0000 (13:58 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Fri, 29 Jun 2018 12:36:13 +0000 (14:36 +0200)
Starting with commit
55956b59df33 ("vfs: Allow userns root to call mknod on owned filesystems.")
Linux will allow mknod() in user namespaces for userns root if CAP_MKNOD is
available.
However, these device nodes are useless since

static struct super_block *alloc_super(struct file_system_type *type, int flags,
                                       struct user_namespace *user_ns)
{
        /* <snip> */

        if (s->s_user_ns != &init_user_ns)
                s->s_iflags |= SB_I_NODEV;

        /* <snip> */
}

will set the SB_I_NODEV flag on the filesystem. When a device node created in
non-init userns is open()ed the call chain will hit:

bool may_open_dev(const struct path *path)
{
        return !(path->mnt->mnt_flags & MNT_NODEV) &&
                !(path->mnt->mnt_sb->s_iflags & SB_I_NODEV);
}

which will cause an EPERM because the device node is located on an fs
owned by non-init-userns and thus doesn't grant access to device nodes due to
SB_I_NODEV.

The solution is straightforward. Unless you're real root you should bind-mount
device nodes.

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

index ee0e7bddd71edaf5df00c56b58b8ff3c835caaf0..ebf32eac1863dfc078ade5ea3a46aa9c26c72288 100644 (file)
@@ -1238,6 +1238,7 @@ struct lxc_device_node {
 };
 
 static const struct lxc_device_node lxc_devices[] = {
+       { "console", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 5 },
        { "full",    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 7 },
        { "null",    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 3 },
        { "random",  S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 8 },
@@ -1251,7 +1252,7 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
        int i, ret;
        char path[MAXPATHLEN];
        mode_t cmask;
-       bool can_mknod = true;
+       int can_mknod = 1;
 
        ret = snprintf(path, MAXPATHLEN, "%s/dev",
                       rootfs->path ? rootfs->mount : "");
@@ -1274,7 +1275,11 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
                if (ret < 0 || ret >= MAXPATHLEN)
                        return -1;
 
-               if (can_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
+                */
+               if (can_mknod == 2 || (can_mknod == 1 && !am_host_unpriv())) {
                        ret = mknod(path, device->mode, makedev(device->maj, device->min));
                        if (ret == 0 || (ret < 0 && errno == EEXIST)) {
                                DEBUG("Created device node \"%s\"", path);
@@ -1289,7 +1294,9 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
                        /* This can e.g. happen when the container is
                         * unprivileged or CAP_MKNOD has been dropped.
                         */
-                       can_mknod = false;
+                       can_mknod = 2;
+               } else {
+                       can_mknod = 0;
                }
 
                ret = mknod(path, S_IFREG, 0);