Control: tags -1 + patch

On Sun, 05 Mar 2017 at 19:23:40 +0000, Simon McVittie wrote:
> Unfortunately, this does cause a regression for interactive use:
> processes inside an interactive schroot cannot tell that their
> stdin/stdout/stderr is in fact connected to a terminal, because that
> terminal is not visible to them.

The lxc and systemd-nspawn container managers avoid this by bind-mounting
the terminal that is stdin (if any) onto the container's /dev/console.
This seems to work well for schroot too, solving that regression.

The attached patch also makes these changes correctly conditional on
using the Linux kernel, which was a bug in my previous proposal.

systemd-nspawn (and I think also lxc, but I haven't checked) also
sets up a separate pty, mounts *that* into the container, and forwards
data between that pty and the real terminal. I believe this was done to
avoid attacks like processes in the container being able to escape the
container by injecting commands into the real terminal with the TIOCSTI
ioctl. However, my understanding is that schroot is not intended to be
a security boundary (it is a "secure chroot" in the sense that users
cannot escalate their privileges to root, but not in the sense that
processes inside the chroot cannot escape), so that method is probably
unnecessary here. If it is necessary, it would have to be done in the
C++ code, not by configuration.

    S
From: Simon McVittie <s...@debian.org>
Date: Mon, 20 Feb 2017 10:43:24 +0000
Subject: Mount a new instance of /dev/pts in the chroot

This is considered to be best-practice for container managers in
Linux >= v2.6.29 with CONFIG_DEVPTS_MULTIPLE_INSTANCES=y. That config
option was made unconditional in v4.7.

This has some assumptions, which cannot be avoided if we are going to
mount /dev/pts using schroot's fstab:

* If the kernel is older than v4.7, it is assumed to be v2.6.29 or
  later with CONFIG_DEVPTS_MULTIPLE_INSTANCES=y. Users of older kernels,
  or intermediate versions with CONFIG_DEVPTS_MULTIPLE_INSTANCES=n,
  can revert this change via /etc.

* gid 5 must be the right owner for ptys. This is correct for Debian
  (it's the hard-coded tty group specified in base-passwd) and probably
  many other distributions (it's systemd's configure-time default) but
  not necessarily correct everywhere. However, if the host system and the
  chroot disagree on the right gid, schroot's previous behaviour would
  have been wrong anyway, because it bind-mounted the host's /dev/pts.

* /dev/ptmx inside the chroot must be either a real device node (as
  created by debootstrap < 1.0.76) or a symlink to pts/ptmx
  (as created by debootstrap >= 1.0.76).

I have proposed a debootstrap patch to make it create the real device
node again if possible. However, there is a desire for debootstrap
to be runnable under container managers that restrict creation of
device nodes, such as systemd-nspawn; under these container managers,
creating /dev/ptmx as a symlink to pts/ptmx is the best that can be
done.

Bind-mounting /dev/pts/ptmx over /dev/ptmx, so that we get the
new instance's /dev/ptmx equivalent instead of the host's, can only
be done from code, so I have done it in the 10mount hook instead of
in the fstab.

To keep the host system terminal on which we were invoked (which might
itself be a pty, from a different instance of /dev/pts) available to
the chroot, bind-mount it onto /dev/console. This is the same trick
used in the lxc and systemd-nspawn Linux container managers.
---
 etc/profile-templates/buildd/linux/fstab  |  2 +-
 etc/profile-templates/default/linux/fstab |  2 +-
 etc/profile-templates/desktop/linux/fstab |  2 +-
 etc/profile-templates/sbuild/linux/fstab  |  2 +-
 etc/setup.d/10mount                       | 27 +++++++++++++++++++++++++++
 5 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/etc/profile-templates/buildd/linux/fstab b/etc/profile-templates/buildd/linux/fstab
index 26efe88..f2f6136 100644
--- a/etc/profile-templates/buildd/linux/fstab
+++ b/etc/profile-templates/buildd/linux/fstab
@@ -1,4 +1,4 @@
-/dev/pts        /dev/pts        none    rw,bind         0       0
+/dev/pts        /dev/pts        devpts  rw,newinstance,ptmxmode=666,mode=620,gid=5 0 0
 tmpfs           /dev/shm        tmpfs   defaults        0       0
 # Mount a large scratch space for the build, so we don't use up
 # space on an LVM snapshot of the chroot itself.
diff --git a/etc/profile-templates/default/linux/fstab b/etc/profile-templates/default/linux/fstab
index 777f0ed..181ed80 100644
--- a/etc/profile-templates/default/linux/fstab
+++ b/etc/profile-templates/default/linux/fstab
@@ -1,5 +1,5 @@
 /dev            /dev            none    rw,bind         0       0
-/dev/pts        /dev/pts        none    rw,bind         0       0
+/dev/pts        /dev/pts        devpts  rw,newinstance,ptmxmode=666,mode=620,gid=5 0 0
 /home           /home           none    rw,bind         0       0
 /tmp            /tmp            none    rw,bind         0       0
 
diff --git a/etc/profile-templates/desktop/linux/fstab b/etc/profile-templates/desktop/linux/fstab
index 7f61d8d..b0dae37 100644
--- a/etc/profile-templates/desktop/linux/fstab
+++ b/etc/profile-templates/desktop/linux/fstab
@@ -1,5 +1,5 @@
 /dev            /dev            none    rw,bind         0       0
-/dev/pts        /dev/pts        none    rw,bind         0       0
+/dev/pts        /dev/pts        devpts  rw,newinstance,ptmxmode=666,mode=620,gid=5 0 0
 /home           /home           none    rw,bind         0       0
 /tmp            /tmp            none    rw,bind         0       0
 
diff --git a/etc/profile-templates/sbuild/linux/fstab b/etc/profile-templates/sbuild/linux/fstab
index 26efe88..f2f6136 100644
--- a/etc/profile-templates/sbuild/linux/fstab
+++ b/etc/profile-templates/sbuild/linux/fstab
@@ -1,4 +1,4 @@
-/dev/pts        /dev/pts        none    rw,bind         0       0
+/dev/pts        /dev/pts        devpts  rw,newinstance,ptmxmode=666,mode=620,gid=5 0 0
 tmpfs           /dev/shm        tmpfs   defaults        0       0
 # Mount a large scratch space for the build, so we don't use up
 # space on an LVM snapshot of the chroot itself.
diff --git a/etc/setup.d/10mount b/etc/setup.d/10mount
index 296a162..1f70231 100755
--- a/etc/setup.d/10mount
+++ b/etc/setup.d/10mount
@@ -269,3 +269,30 @@ if [ $STAGE = "setup-start" ] || [ $STAGE = "setup-recover" ]; then
     fi
 
 fi
+
+if [ $STAGE = "setup-start" ] || [ $STAGE = "setup-recover" ]; then
+    if [ "$(uname -s)" = "Linux" ]; then
+        # Depending on how /dev was set up, /dev/ptmx might either be
+        # character device (5,2), or a symbolic link to pts/ptmx.
+        # Either way we want it to be equivalent to /dev/pts/ptmx, assuming
+        # both exist.
+        if [ -e "$CHROOT_PATH/dev/pts/ptmx" ] && \
+                [ -e "$CHROOT_PATH/dev/ptmx" ] && \
+                ! [ "$CHROOT_PATH/dev/pts/ptmx" -ef "$CHROOT_PATH/dev/ptmx" ]; then
+            mount --bind "$CHROOT_PATH/dev/pts/ptmx" "$CHROOT_PATH/dev/ptmx"
+        fi
+
+        # If schroot was invoked from a terminal, we still want to be able to
+        # access that terminal. lxc and systemd-nspawn achieve this by
+        # binding it onto /dev/console; so can we.
+        if stdin_tty="$(tty)"; then
+            if [ ! -e "$CHROOT_PATH/dev/console" ]; then
+                # We need something to mount onto, and it might as well be
+                # the correctly-numbered device node.
+                mknod -m700 "$CHROOT_PATH/dev/console" c 5 1
+            fi
+
+            mount --bind "$stdin_tty" "$CHROOT_PATH/dev/console"
+        fi
+    fi
+fi

Reply via email to