From b5e99f23ed6054b3c62b9ff304d5843100dbf7e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=98=D0=B0=D0=BD=20=D0=93=D0=B5=D0=BE?= =?UTF-8?q?=D1=80=D0=B3=D0=B8=D0=B5=D0=B2=D1=81=D0=BA=D0=B8?= Date: Tue, 16 Jan 2018 21:27:51 +0100 Subject: [PATCH 1/2] namespace: extract clone_device_node function from mount_private_dev --- src/core/namespace.c | 71 ++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/core/namespace.c b/src/core/namespace.c index aed11c18ee..d5b050fadc 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -496,6 +496,40 @@ static void drop_outside_root(const char *root_directory, MountEntry *m, unsigne *n = t - m; } +static int clone_device_node(const char *d, const char *temporary_mount) +{ + _cleanup_free_ char *dn = NULL; + struct stat st; + int r; + + r = stat(d, &st); + if (r < 0) { + if (errno == ENOENT) + return 0; + return -errno; + } + + if (!S_ISBLK(st.st_mode) && + !S_ISCHR(st.st_mode)) + return -EINVAL; + + if (st.st_rdev == 0) + return 0; + + dn = strappend(temporary_mount, d); + if (!dn) + return -ENOMEM; + + mac_selinux_create_file_prepare(d, st.st_mode); + r = mknod(dn, st.st_mode, st.st_rdev); + mac_selinux_create_file_clear(); + + if (r < 0) + return -errno; + + return 0; +} + static int mount_private_dev(MountEntry *m) { static const char devnodes[] = "/dev/null\0" @@ -557,42 +591,9 @@ static int mount_private_dev(MountEntry *m) { (void) symlink("/run/systemd/journal/dev-log", devlog); NULSTR_FOREACH(d, devnodes) { - _cleanup_free_ char *dn = NULL; - struct stat st; - - r = stat(d, &st); - if (r < 0) { - - if (errno == ENOENT) - continue; - - r = -errno; + r = clone_device_node(d, temporary_mount); + if (r < 0) goto fail; - } - - if (!S_ISBLK(st.st_mode) && - !S_ISCHR(st.st_mode)) { - r = -EINVAL; - goto fail; - } - - if (st.st_rdev == 0) - continue; - - dn = strappend(temporary_mount, d); - if (!dn) { - r = -ENOMEM; - goto fail; - } - - mac_selinux_create_file_prepare(d, st.st_mode); - r = mknod(dn, st.st_mode, st.st_rdev); - mac_selinux_create_file_clear(); - - if (r < 0) { - r = -errno; - goto fail; - } } dev_setup(temporary_mount, UID_INVALID, GID_INVALID); From 414b304ba2ffabf85057b133e7aa0573f0cbd029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=98=D0=B0=D0=BD=20=D0=93=D0=B5=D0=BE?= =?UTF-8?q?=D1=80=D0=B3=D0=B8=D0=B5=D0=B2=D1=81=D0=BA=D0=B8?= Date: Tue, 16 Jan 2018 21:50:36 +0100 Subject: [PATCH 2/2] namespace: only make the symlink /dev/ptmx if it was already a symlink MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …otherwise try to clone it as a device node On most contemporary distros /dev/ptmx is a device node, and /dev/pts/ptmx has 000 inaccessible permissions. In those cases the symlink /dev/ptmx -> /dev/pts/ptmx breaks the pseudo tty support. In that case we better clone the device node. OTOH, in nspawn containers (and possibly others), /dev/pts/ptmx has normal permissions, and /dev/ptmx is a symlink. In that case make the same symlink. fixes #7878 --- src/core/namespace.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/core/namespace.c b/src/core/namespace.c index d5b050fadc..d6c1b1b2fc 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -496,14 +496,12 @@ static void drop_outside_root(const char *root_directory, MountEntry *m, unsigne *n = t - m; } -static int clone_device_node(const char *d, const char *temporary_mount) -{ +static int clone_device_node(const char *d, const char *temporary_mount) { _cleanup_free_ char *dn = NULL; struct stat st; int r; - r = stat(d, &st); - if (r < 0) { + if (stat(d, &st) < 0) { if (errno == ENOENT) return 0; return -errno; @@ -542,6 +540,7 @@ static int mount_private_dev(MountEntry *m) { char temporary_mount[] = "/tmp/namespace-dev-XXXXXX"; const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL; _cleanup_umask_ mode_t u; + struct stat st; int r; assert(m); @@ -565,11 +564,27 @@ static int mount_private_dev(MountEntry *m) { goto fail; } - devptmx = strjoina(temporary_mount, "/dev/ptmx"); - if (symlink("pts/ptmx", devptmx) < 0) { + /* /dev/ptmx can either be a device node or a symlink to /dev/pts/ptmx + * when /dev/ptmx a device node, /dev/pts/ptmx has 000 permissions making it inaccessible + * thus, in that case make a clone + * + * in nspawn and other containers it will be a symlink, in that case make it a symlink + */ + if (lstat("/dev/ptmx", &st) < 0) { r = -errno; goto fail; } + if (S_ISLNK(st.st_mode)) { + devptmx = strjoina(temporary_mount, "/dev/ptmx"); + if (symlink("pts/ptmx", devptmx) < 0) { + r = -errno; + goto fail; + } + } else { + r = clone_device_node("/dev/ptmx", temporary_mount); + if (r < 0) + goto fail; + } devshm = strjoina(temporary_mount, "/dev/shm"); (void) mkdir(devshm, 01777);