[Bug 1669578] Re: Get ttyname() to work properly in containers
Christian Brauner
christian.brauner at canonical.com
Tue May 2 14:54:18 UTC 2017
@LocutusOfBorg, can you please tell me exactly what you need? From
looking at
git clone https://anonscm.debian.org/git/collab-maint/screen.git
git checkout debian/4.5.1-3
none of the patches that I've pushed upstream are available in this repo.
For this to work you'd need:
1.
commit 78d2a73273786bd7c5f3be481b23a5bee19dc519
Author: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed Mar 22 18:16:52 2017 +0100
handle pty device from different namespace
Various programs that deal with namespaces will use pty devices that exist in
another namespace. One obvious candiate are containers. So far ttyname() was
incorrectly handling this case because the pts device stems from the host and
thus cannot be found amongst the current namespace's /dev/pts/<n> entries.
Serge Hallyn and I recently upstreamed patches to glibc that allow ttyname{_r}()
to correctly handle this case. At a minimum, ttyname{_r}() will set errno to
ENODEV in case it finds that the /dev/pts/<n> device that the symlink points to
exists in another namespace. This commit will allow screen to handle this case
and behave correctly in a container.
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
2.commit 7e755ed62d311b00102b053eee88359bbf8ac2df
Author: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed Apr 5 14:24:22 2017 +0200
screen: handle pts devices in different namespaces
Various programs that deal with namespaces will use pty devices that exist in
another namespace. One obvious candidate are containers. So far ttyname() was
incorrectly handling this case because the pts device stems from the host and
thus cannot be found amongst the current namespace's /dev/pts/<n> entries.
Serge Hallyn and I recently upstreamed patches to glibc that allow ttyname{_r}()
to correctly handle this case. At a minimum, ttyname{_r}() will set errno to
ENODEV in case it finds that the /dev/pts/<n> device that the symlink points to
exists in another namespace.
(The next comment is a little longer but tries to ensure that one can still
understand what is going on after some time has passed.)
In case we detect that ttyname{_r}() returns NULL and sets errno to ENODEV we
have ample reason to assume that the pts device exists in a different
namespace. In this case, the code will set a global flag indicating this case
to true. Furthermore, all operations (e.g. chmod(), chown(), etc.) will now
need to operate on the symbolic link /proc/self/fd/0 directly. While this
sounds straightforward, it becomes difficult to handle this case correctly when
we reattach to an already existing screen session from a different pts device
than the original one. Let's look at the general reattach logic a little
closer:
Assume we are running a shell that uses a pts device from a different
namespace:
root at zest1:~# ls -al /proc/self/fd/
total 0
dr-x------ 2 root root 0 Apr 2 20:22 .
dr-xr-xr-x 9 root root 0 Apr 2 20:22 ..
lrwx------ 1 root root 64 Apr 2 20:22 0 -> /dev/pts/6
lrwx------ 1 root root 64 Apr 2 20:22 1 -> /dev/pts/6
lrwx------ 1 root root 64 Apr 2 20:22 2 -> /dev/pts/6
l-wx------ 1 root root 64 Apr 2 20:22 3 -> pipe:[3067913]
lr-x------ 1 root root 64 Apr 2 20:22 4 -> /proc/27413/fd
lrwx------ 1 root root 64 Apr 2 20:22 9 -> socket:[32944]
root at zest1:~# ls -al /dev/pts/
total 0
drwxr-xr-x 2 root root 0 Mar 30 17:55 .
drwxr-xr-x 8 root root 580 Mar 30 17:55 ..
crw--w---- 1 root tty 136, 0 Mar 30 17:55 0
crw--w---- 1 root tty 136, 1 Mar 30 17:55 1
crw--w---- 1 root tty 136, 2 Mar 30 17:55 2
crw--w---- 1 root tty 136, 3 Mar 30 17:55 3
crw--w---- 1 root tty 136, 4 Mar 30 17:55 4
crw-rw-rw- 1 root root 5, 2 Apr 2 20:22 ptmx
(As one can see /dev/pts/6 does not exist in the current namespace.)
Now, start a screen session in this shell. In this case this patch will have
screen directly operate on /proc/self/fd/0.
Let's look at the attach case. When we attach to an existing screen session
where the associated pts device lives in another namespace we need a way to
uniquely identify the pts device that is used and also need a way to get a
valid fd when we need one. This patch solves this by ensuring that a valid file
descriptor to the pts device is sent via a unix socket and SCM_RIGHTS to the
socket and display handling part of screen. However, screen also sends around
the name of the associated pts device or, in the case where the pts device
exists in another namespace, the symlink /proc/self/fd/0. But after having sent
the fd this part of the codebase cannot simply operate on /proc/self/fd/0 since
it very likely refers to a different file. So we need to operate on
/proc/self/fd/<fd-sent-via-SCM_RIGHTS> but also need to ensure that we haven't
been tricked into operating on a tampered with file or device. So we cannot
simply sent /proc/self/fd/0 via the unix socket. Instead we read the contents
of the symbolic link /proc/self/fd/0 in the main function and sent it via the
unix socket. Then in the socket and display handling part of screen, we read
the contents of the /proc/self/fd/<fd-sent-via-SCM_RIGHTS> as well and compare
the pts device names. If they match we know that everything is well. However,
now we also need to update any tty handling code to directly operate on
/proc/self/fd/<fd-sent-via-SCM_RIGHTS>.
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
3.
commit bab73f99a2dc99604fb38b8fa2c73e3453c12b2a
Author: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu Apr 13 15:55:11 2017 +0200
add compat layer to handle both fifos and sockets
So far screen could only support either sockets or fifos but not both. This
proved to be a blocker for any upgrade. This adds a compatibility layer to
screen v4 to support both sockets and fifos at the same time. The strategy here
is to only support fifos for legacy sessions that already exist. All new
sessions will use sockets by default.
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
For all three patches I've appended version for the Ubuntu package and upstream.
Are you saying you'd need all three ported to screen 4.5.1-3 based on the repo I
pointed out above? I'd like to have this settled before potentially shuffling
a thousand lines of code around.
--
You received this bug notification because you are a member of Ubuntu
Foundations Bugs, which is subscribed to glibc in Ubuntu.
https://bugs.launchpad.net/bugs/1669578
Title:
Get ttyname() to work properly in containers
Status in glibc package in Ubuntu:
Fix Released
Status in screen package in Ubuntu:
Fix Committed
Status in tmux package in Ubuntu:
Fix Released
Bug description:
For the past year or so, the LXD team has been trying to resolve an
issue affecting screen, tmux and a bunch of other software (including
the "tty" command).
The problem comes from the fact that when attaching to a container,
your terminal's pts device comes from the host and therefore can't be
found in /dev/pts/.
glibc makes the assumption that it can readlink /proc/self/fd/0 and
that the target path will exist. This simply isn't true as the symlink
target returned by the kernel, is confusingly relative to the host's
root and not the container's.
Which means that if the target happens to exist, it's actually going
to be an entirely different pts device from the one that you're
actually attached to.
You therefore need to do something along the lines of:
- Resolve the symlink. If the target doesn't exist, return the symlink as the ttyname.
- If the target does exist, check that its major and minor matches that of the symlink itself, if it doesn't, then return the symlink rather than the target.
That's the ideal approach which makes existing software keep working properly without the need for any added code. After about a year of bikeshedding, the proposed glibc upstream fix has now evolved to instead returning ENODEV in the is_pty function. This allows downstream glibc users to detect this case and then use /proc/self/fd/0 rather than the return value of ttyname() but means every software using ttyname() now needs fixing.
As we very much care about Ubuntu running properly inside LXD
containers, our suggested patchset includes both the ENODEV patch as
is still being considered by upstream (stuck on legal validation) AND
another patch which has ttyname() return the symlink when it receives
the ENODEV.
We feel this is the best way to fix the problem entirely right now. Once glibc upstream merges the ENODEV side of this and all affected software get fixed upstream to deal with it, we'll then be able to drop that patch without causing any regressions.
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1669578/+subscriptions
More information about the foundations-bugs
mailing list