From: Christian Brauner Date: Fri, 29 Jun 2018 11:58:52 +0000 (+0200) Subject: autodev: adapt to changes in Linux 4.18 X-Git-Tag: lxc-3.1.0~226^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F2438%2Fhead;p=thirdparty%2Flxc.git autodev: adapt to changes in Linux 4.18 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) { /* */ if (s->s_user_ns != &init_user_ns) s->s_iflags |= SB_I_NODEV; /* */ } 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 --- diff --git a/src/lxc/conf.c b/src/lxc/conf.c index ee0e7bddd..ebf32eac1 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -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);