All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
@ 2017-08-16 17:12 Christian Brauner
  2017-08-16 17:12 ` [PATCH 1/1] " Christian Brauner
  2017-08-16 18:26 ` [PATCH 0/1] " Linus Torvalds
  0 siblings, 2 replies; 55+ messages in thread
From: Christian Brauner @ 2017-08-16 17:12 UTC (permalink / raw)
  To: linux-kernel, serge, torvalds, viro; +Cc: Christian Brauner

Hi,

Recently the kernel has implemented the TIOCGPTPEER ioctl() call which allows
users to retrieve an fd for the slave side of a pty solely based on the
corresponding fd for the master side. The ioctl()-based fd retrieval however
causes the "/proc/<pid>/fd/<pty-slave-fd>" symlink to point to the wrong dentry.
Currently, it will always point to "/". The following simple program can be used
to illustrate the problem when run on a system that implements the TIOCGPTPEER
ioctl() call.

#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>

int main()
{
	int master;
	int ret = -1, slave = -1;
	char buf[4096], path[4096];

	master = open("/dev/ptmx", O_RDWR | O_NOCTTY);
	if (master < 0)
		return -1;

	ret = grantpt(master);
	if (ret < 0)
		return -1;

	ret = unlockpt(master);
	if (ret < 0)
		goto on_error;

	slave = ioctl(master, TIOCGPTPEER, O_RDWR | O_NOCTTY);
	if (slave < 0)
		goto on_error;

	ret = snprintf(path, 4096, "/proc/self/fd/%d", slave);
	if (ret < 0 || ret >= 4096)
		goto on_error;

	ret = readlink(path, buf, sizeof(buf));
	if (ret < 0)
		goto on_error;
	printf("I point to \"%s\"\n", buf);

on_error:
	close(master);
	if (slave >= 0)
		close(slave);
	return ret;
}

With the symlink pointing to the wrong path any interesting path-based operation
on the slave side will fail. Also this will cause ttyname{_r}() to falsely
report that this fd does not return to a tty. So I really think this needs to be
fixed. The fix however doesn't seem super obvious to me. It seems the most
straightforward way for now is to behave like the implementation of pipes and
sockets that implement a dynamic_dname() method to correctly set the content of
the "/proc/<pid>/fd/<n>" symlink without requiring special-casing in the proc
implementation itself. I prefer this approach. The downside of this however is
that in case the devpts is not mounted at its standard "/dev/pts" location but
e.g. at "/mnt" the content of the corresponding "/proc/<pid>/fd/<n>" symlink
will still be "/dev/pts/<idx>" although it should likely be "/mnt/<idx". I've
gone over this back and forth in my head but I think that this is not a deal
breaker. All libcs currently hard-code "/dev/pts/<idx>" into their
implementation of ptsname{_r}() and so wouldn't be affected by this change at
all. Furthermore, mounting devpts somewhere other than "/dev/pts" (e.g. "/mnt")
doesn't seem to work and from what I gather from LKML is not really expected nor
supported to work.
All ioctl() I've seens so far that return fds seems to implement a
dynamic_dname() method and I didn't see any other way how to do this here. One
thing that came to mind was to somehow get at the "absolute path" for the slave
side dentry such that you retrieve the mountpoint for the devpts fs and then
combine this with the pty slave index to generate the proc name. However, the
concept of an absolute path does not really make sense for dentries and in the
face of bind-mounts it becomes questionable what devpts instance should win.
Furthermore, the dynamic_dname() method will only allow you to access the dentry
itself and not a struct path which would contain the vfsmount information. In
any case, here is my patch, when applied the fd returned by ioctl(fd,
TIOCGPTPEER) will have the correct content ("/dev/pts/<idx>"):

Christian Brauner (1):
  devpts: use dynamic_dname() to generate proc name

 fs/devpts/inode.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

-- 
2.13.3

^ permalink raw reply	[flat|nested] 55+ messages in thread

* [PATCH 1/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 17:12 [PATCH 0/1] devpts: use dynamic_dname() to generate proc name Christian Brauner
@ 2017-08-16 17:12 ` Christian Brauner
  2017-08-16 18:26 ` [PATCH 0/1] " Linus Torvalds
  1 sibling, 0 replies; 55+ messages in thread
From: Christian Brauner @ 2017-08-16 17:12 UTC (permalink / raw)
  To: linux-kernel, serge, torvalds, viro; +Cc: Christian Brauner

Recently the kernel has implemented the TIOCGPTPEER ioctl() call which allows
users to retrieve an fd for the slave side of a pty solely based on the
corresponding fd for the master side. The ioctl()-based fd retrieval however
causes the "/proc/<pid>/fd/<pty-slave-fd>" symlink to point to the wrong dentry.
Currently, it will always point to "/".

With the symlink pointing to the wrong path any interesting path-based operation
on the slave side will fail. Also this will cause ttyname{_r}() to falsely
report that this fd does not return to a tty. So I really think this needs to be
fixed. The fix however doesn't seem super obvious to me. It seems the most
straightforward way for now is to behave like the implementation of pipes and
sockets that implement a dynamic_dname() method to correctly set the content of
the "/proc/<pid>/fd/<n>" symlink without requiring special-casing in the proc
implementation itself. I prefer this approach. The downside of this however is
that in case the devpts is not mounted at its standard "/dev/pts" location but
e.g. at "/mnt" the content of the corresponding "/proc/<pid>/fd/<n>" symlink
will still be "/dev/pts/<idx>" although it should likely be "/mnt/<idx". I've
gone over this back and forth in my head but I think that this is not a deal
breaker. All libcs currently hard-code "/dev/pts/<idx>" into their
implementation of ptsname{_r}() and so wouldn't be affected by this change at
all. Furthermore, mounting devpts somewhere other than "/dev/pts" (e.g. "/mnt")
doesn't seem to work and from what I gather from LKML is not really expected nor
supported to work.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
---
 fs/devpts/inode.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 108df2e3602c..1b1b9b0813e8 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -369,6 +369,18 @@ static const struct super_operations devpts_sops = {
 	.show_options	= devpts_show_options,
 };
 
+/*
+ * pty_peer_dname() is called from d_path().
+ */
+static char *pty_peer_dname(struct dentry *dentry, char *buffer, int buflen)
+{
+	return dynamic_dname(dentry, buffer, buflen, "/dev/pts/%pd", dentry);
+}
+
+static const struct dentry_operations devpts_dops = {
+	.d_dname = pty_peer_dname,
+};
+
 static void *new_pts_fs_info(struct super_block *sb)
 {
 	struct pts_fs_info *fsi;
@@ -397,6 +409,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
 	s->s_magic = DEVPTS_SUPER_MAGIC;
 	s->s_op = &devpts_sops;
 	s->s_time_gran = 1;
+	s->s_d_op = &devpts_dops;
 
 	error = -ENOMEM;
 	s->s_fs_info = new_pts_fs_info(s);
-- 
2.13.3

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 17:12 [PATCH 0/1] devpts: use dynamic_dname() to generate proc name Christian Brauner
  2017-08-16 17:12 ` [PATCH 1/1] " Christian Brauner
@ 2017-08-16 18:26 ` Linus Torvalds
  2017-08-16 18:48   ` Linus Torvalds
  1 sibling, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-16 18:26 UTC (permalink / raw)
  To: Christian Brauner; +Cc: Linux Kernel Mailing List, Serge E. Hallyn, Al Viro

On Wed, Aug 16, 2017 at 10:12 AM, Christian Brauner
<christian.brauner@ubuntu.com> wrote:
>
> Recently the kernel has implemented the TIOCGPTPEER ioctl() call which allows
> users to retrieve an fd for the slave side of a pty solely based on the
> corresponding fd for the master side. The ioctl()-based fd retrieval however
> causes the "/proc/<pid>/fd/<pty-slave-fd>" symlink to point to the wrong dentry.
> Currently, it will always point to "/". The following simple program can be used
> to illustrate the problem when run on a system that implements the TIOCGPTPEER
> ioctl() call.

I think your patch is wrong - we need to actually use the *right*
path, rather than hardcode "/dev/pts/%d" in there.

Hardcoding "/dev/pts/%d" is something that user space can already do.
The kernel can and should do better.

That "dynamic_dname()" helper is for things that don't really have a
real pathname at all, so things like pipes and other file descriptors
that were opened without an associated entry in a filesystem (sockets,
other "special" inodes with no filesystem backing).

For things like pts slaves, we actually *do* have a real pathname -
and we should expose it. If the devpts filesystem is mounted somewhere
else than /dev/pts, it should give that correct pathname.

I also think your test program is a bit buggy, and silly:

>         ret = snprintf(path, 4096, "/proc/self/fd/%d", slave);
>         if (ret < 0 || ret >= 4096)
>                 goto on_error;
>
>         ret = readlink(path, buf, sizeof(buf));
>         if (ret < 0)
>                 goto on_error;
>         printf("I point to \"%s\"\n", buf);

This just smells wrong to me. And not just because you don't
NUL-terminate the readlink() return value (or just use "%.*s" with
ret, buf) .

We should just give people a better way to get the pathname than that
readlink on /proc/self/fd/<fd> thing. It's kind of ridiculous that we
don't. We already have a "getcwd()" system call that only does it for
cwd.

So I think we could/should just add a system call for 'fdname()' or similar.

                Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 18:26 ` [PATCH 0/1] " Linus Torvalds
@ 2017-08-16 18:48   ` Linus Torvalds
  2017-08-16 19:48     ` Christian Brauner
  0 siblings, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-16 18:48 UTC (permalink / raw)
  To: Christian Brauner; +Cc: Linux Kernel Mailing List, Serge E. Hallyn, Al Viro

On Wed, Aug 16, 2017 at 11:26 AM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> Hardcoding "/dev/pts/%d" is something that user space can already do.
> The kernel can and should do better.

Put another way: there's no point in applying the patch as-is, since
existing glibc ptsname() does the same thing better and faster
entirely in user space.

Also, we already do special things to get a path for this, but it
clearly isn't working. See the

        /* We need to cache a fake path for TIOCGPTPEER. */

comment in ptmx_open(). Why doesn't the file d_path get filled in
correctly there, I wonder.

Because The regular

        readlink("/proc/self/fd/0", ...)

that 'tty' does works correctly.  I think we've done something
incorrect in pty_open_peer(), which means that the fd path hasn't been
fully filled in.

Fixing that *should* fix the readlink() automatically, since it
clearly works for the 'tty' binary.

I'm wondering why it's not working as-is. "vfs_open()" does that

        file->f_path = *path;

thing. Why aren't we getting the right path? The ptmx_open() code
looks ok to me.

Al, do you see what the issue is, and why we don't get a proper path
on that readlink?

            Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 18:48   ` Linus Torvalds
@ 2017-08-16 19:48     ` Christian Brauner
  2017-08-16 19:56       ` Linus Torvalds
  0 siblings, 1 reply; 55+ messages in thread
From: Christian Brauner @ 2017-08-16 19:48 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Brauner, Linux Kernel Mailing List, Serge E. Hallyn, Al Viro

On Wed, Aug 16, 2017 at 11:48:48AM -0700, Linus Torvalds wrote:
> On Wed, Aug 16, 2017 at 11:26 AM, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
> >
> > Hardcoding "/dev/pts/%d" is something that user space can already do.
> > The kernel can and should do better.
> 
> Put another way: there's no point in applying the patch as-is, since
> existing glibc ptsname() does the same thing better and faster
> entirely in user space.

Right. I actually took that to be an argument for this patch not against it. :)
Another point I was trying to make in my initial mail is that ttyname{_r}() will
currently look at "/proc/self/fd/<nr> to detect the name of the associated pts
device and it will error out if the content it reads is not a "/dev/pts/<n>"
path. Afaict musl and glibc both currently rely on this. This would be broken
with the current TIOCGPTPEER change.

> 
> Also, we already do special things to get a path for this, but it
> clearly isn't working. See the
> 
>         /* We need to cache a fake path for TIOCGPTPEER. */
> 
> comment in ptmx_open(). Why doesn't the file d_path get filled in
> correctly there, I wonder.
> 
> Because The regular
> 
>         readlink("/proc/self/fd/0", ...)
> 
> that 'tty' does works correctly.  I think we've done something
> incorrect in pty_open_peer(), which means that the fd path hasn't been
> fully filled in.
> 
> Fixing that *should* fix the readlink() automatically, since it
> clearly works for the 'tty' binary.
> 
> I'm wondering why it's not working as-is. "vfs_open()" does that
> 
>         file->f_path = *path;
> 
> thing. Why aren't we getting the right path? The ptmx_open() code
> looks ok to me.

I thought - and sorry if I'm completely wrong here - that the proc name came
from the open(const char *pathname, ...) call. Currently the only way to
retrieve a slave side fd for a given pty pair is by calling open("/dev/pts/<n>",
O_RDWR | O_NOCTTY). This would take care of placing the correct path in the proc
symlink through do_filp_open() and friends. However, for ioctl() calls that open
dentries to return an fd this is not possible and - or so I thought - the proc
name is/has to be generated via dynamic_dname(). But again, I might be totally
off here.

Christian

> 
> Al, do you see what the issue is, and why we don't get a proper path
> on that readlink?
> 
>             Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 19:48     ` Christian Brauner
@ 2017-08-16 19:56       ` Linus Torvalds
  2017-08-16 20:19         ` Linus Torvalds
  0 siblings, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-16 19:56 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Christian Brauner, Linux Kernel Mailing List, Serge E. Hallyn, Al Viro

On Wed, Aug 16, 2017 at 12:48 PM, Christian Brauner
<christian.brauner@canonical.com> wrote:
>
> I thought - and sorry if I'm completely wrong here - that the proc name came
> from the open(const char *pathname, ...) call.

No. It comes from the path associated with the file descriptor, and is
expanded from the dentry tree.

Which is why you get a full pathname even when you only opened
something using a relative pathname.

So the fact that we _don't_ get the right pathname for the pts entry
here means that something got screwed up in setting filp->f_path to
the right thing. We have all the code in place that _tries_ to do it,
but it clearly has a bug somewhere.

               Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 19:56       ` Linus Torvalds
@ 2017-08-16 20:19         ` Linus Torvalds
  2017-08-16 20:30           ` Linus Torvalds
  2017-08-17  1:37           ` Eric W. Biederman
  0 siblings, 2 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-16 20:19 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Christian Brauner, Linux Kernel Mailing List, Serge E. Hallyn, Al Viro

On Wed, Aug 16, 2017 at 12:56 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> So the fact that we _don't_ get the right pathname for the pts entry
> here means that something got screwed up in setting filp->f_path to
> the right thing. We have all the code in place that _tries_ to do it,
> but it clearly has a bug somewhere.

Ok, I think I see what the bug is, although I don't have a fix for it yet.

We generate the path largely correctly: the path has a nice dentry
that contains the right pts number, and has the right parent pointer
that points to the root of the pts mount.

And we also fill in the path 'mnt' field. Everything should be fine.

Except when we actually hit that root dentry of the pts mount, the
code in prepend_path() hits this condition:

                if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
                        struct mount *parent = ACCESS_ONCE(mnt->mnt_parent);
                        /* Escaped? */
                        if (dentry != vfsmnt->mnt_root) {

and we break out, and reset the path to '/' because we think it
somehow escaped out of the user namespace.

So it looks like we filled in the path with the *wrong* mount information.

And THAT in turn is because we fill the path with the mount
information for the "/dev/ptmx" field - which is *not* in the
/dev/pts/ mount - that's the mount for '/dev'.

So we have a dentry and a mnt, but they simply aren't paired up correctly.

And you can see this with your test program: if you open /dev/pts/ptmx
for the master, it actually works correctly (but you need to make sure
the permissions for that ptmx node allow that).

Anyway, I know what's wrong, next step is to figure out what the fix is.

                   Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 20:19         ` Linus Torvalds
@ 2017-08-16 20:30           ` Linus Torvalds
  2017-08-16 21:03             ` Linus Torvalds
  2017-08-17  1:37           ` Eric W. Biederman
  1 sibling, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-16 20:30 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Christian Brauner, Linux Kernel Mailing List, Serge E. Hallyn, Al Viro

On Wed, Aug 16, 2017 at 1:19 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> Anyway, I know what's wrong, next step is to figure out what the fix is.

Grr, We actually look up the right mnt in devpts_acquire(), but we
don't save it.  We only save the superblock pointer, because that's
traditionally what we used.

I suspect the easiest fix is to just add a "mnt" argument to
devpts_acquire(),  It shouldn't be too painful. Let me try.

              Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 20:30           ` Linus Torvalds
@ 2017-08-16 21:03             ` Linus Torvalds
  2017-08-16 21:37               ` Christian Brauner
  2017-08-16 22:46               ` Eric W. Biederman
  0 siblings, 2 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-16 21:03 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Christian Brauner, Linux Kernel Mailing List, Serge E. Hallyn, Al Viro

[-- Attachment #1: Type: text/plain, Size: 476 bytes --]

On Wed, Aug 16, 2017 at 1:30 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> I suspect the easiest fix is to just add a "mnt" argument to
> devpts_acquire(),  It shouldn't be too painful. Let me try.

Ok, here's a *very* lightly tested patch. It might have new bugs, but
it makes your test program DTRT.

Al, mind going over this and making sure I didn't miss anything?

And Christian, if you can beat on this, that would be good.

                        Linus

[-- Attachment #2: patch.diff --]
[-- Type: text/plain, Size: 2851 bytes --]

 drivers/tty/pty.c         | 15 +++++++++++----
 fs/devpts/inode.c         |  4 +++-
 include/linux/devpts_fs.h |  2 +-
 3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 284749fb0f6b..432f514e3f42 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -793,6 +793,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 	struct tty_struct *tty;
 	struct path *pts_path;
 	struct dentry *dentry;
+	struct vfsmount *mnt;
 	int retval;
 	int index;
 
@@ -805,7 +806,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 	if (retval)
 		return retval;
 
-	fsi = devpts_acquire(filp);
+	fsi = devpts_acquire(filp, &mnt);
 	if (IS_ERR(fsi)) {
 		retval = PTR_ERR(fsi);
 		goto out_free_file;
@@ -849,9 +850,14 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 	pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
 	if (!pts_path)
 		goto err_release;
-	pts_path->mnt = filp->f_path.mnt;
-	pts_path->dentry = dentry;
-	path_get(pts_path);
+
+	/*
+	 * The mnt already got a ref from devpts_acquire(),
+	 * so we only dget() on the dentry.
+	 */
+	pts_path->mnt = mnt;
+	pts_path->dentry = dget(dentry);
+
 	tty->link->driver_data = pts_path;
 
 	retval = ptm_driver->ops->open(tty, filp);
@@ -874,6 +880,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 	devpts_kill_index(fsi, index);
 out_put_fsi:
 	devpts_release(fsi);
+	mntput(mnt);
 out_free_file:
 	tty_free_file(filp);
 	return retval;
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 108df2e3602c..44dfbca9306f 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -133,7 +133,7 @@ static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
-struct pts_fs_info *devpts_acquire(struct file *filp)
+struct pts_fs_info *devpts_acquire(struct file *filp, struct vfsmount **ptsmnt)
 {
 	struct pts_fs_info *result;
 	struct path path;
@@ -142,6 +142,7 @@ struct pts_fs_info *devpts_acquire(struct file *filp)
 
 	path = filp->f_path;
 	path_get(&path);
+	*ptsmnt = NULL;
 
 	/* Has the devpts filesystem already been found? */
 	sb = path.mnt->mnt_sb;
@@ -165,6 +166,7 @@ struct pts_fs_info *devpts_acquire(struct file *filp)
 	 * pty code needs to hold extra references in case of last /dev/tty close
 	 */
 	atomic_inc(&sb->s_active);
+	*ptsmnt = mntget(path.mnt);
 	result = DEVPTS_SB(sb);
 
 out:
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
index 277ab9af9ac2..7883e901f65c 100644
--- a/include/linux/devpts_fs.h
+++ b/include/linux/devpts_fs.h
@@ -19,7 +19,7 @@
 
 struct pts_fs_info;
 
-struct pts_fs_info *devpts_acquire(struct file *);
+struct pts_fs_info *devpts_acquire(struct file *, struct vfsmount **ptsmnt);
 void devpts_release(struct pts_fs_info *);
 
 int devpts_new_index(struct pts_fs_info *);

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 21:03             ` Linus Torvalds
@ 2017-08-16 21:37               ` Christian Brauner
  2017-08-16 21:45                 ` Linus Torvalds
  2017-08-16 22:46               ` Eric W. Biederman
  1 sibling, 1 reply; 55+ messages in thread
From: Christian Brauner @ 2017-08-16 21:37 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Brauner, Linux Kernel Mailing List, Serge E. Hallyn, Al Viro

On Wed, Aug 16, 2017 at 11:03 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> On Wed, Aug 16, 2017 at 1:30 PM, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
>>
>> I suspect the easiest fix is to just add a "mnt" argument to
>> devpts_acquire(),  It shouldn't be too painful. Let me try.
>
> Ok, here's a *very* lightly tested patch. It might have new bugs, but
> it makes your test program DTRT.

Cool. Very happy this could be fixed so quickly!

>
> Al, mind going over this and making sure I didn't miss anything?
>
> And Christian, if you can beat on this, that would be good.

Yes, I can pound on this nicely with liblxc. We have patch
( https://github.com/lxc/lxc/pull/1728 ) up for review that
allocates pty fds from private devpts mounts in different namespaces
and sends those fds around between different namespaces. This
was one of the original motivations for implementing TIOCGPTPEER.
I had marked it as blocked until this bug was fixed which now seems
to be the case.

Thanks Linus!
Christian

>
>                         Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 21:37               ` Christian Brauner
@ 2017-08-16 21:45                 ` Linus Torvalds
  2017-08-16 21:55                   ` Linus Torvalds
  2017-08-16 22:28                   ` Christian Brauner
  0 siblings, 2 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-16 21:45 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Christian Brauner, Linux Kernel Mailing List, Serge E. Hallyn, Al Viro

On Wed, Aug 16, 2017 at 2:37 PM, Christian Brauner
<christian.brauner@canonical.com> wrote:
>> And Christian, if you can beat on this, that would be good.
>
> Yes, I can pound on this nicely with liblxc. We have patch
> ( https://github.com/lxc/lxc/pull/1728 ) up for review that
> allocates pty fds from private devpts mounts in different namespaces
> and sends those fds around between different namespaces.

Good. Testing that this works with different pts filesystems in
different places is exactly the kind of thing I'd like to see. I only
tested with my single pts filesystem that is mounted at /dev/pts, and
making sure it works when there are multiple mounts and in different
places is exactly the kind of testing this should get.

For example, if some namespace has it's pty's in _its_ /dev/pts/
hierarchy, and you then pass such a pty to somebody else that either
doesn't have that pts mount at all, or has it visible somewhere
entirely different, the result should now be something else than that
"/dev/pts/n" path.

But it would be good to just test this in general too, and make sure I
didn't screw up some reference count or something. The patch *looks*
obviously correct, but ...

               Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 21:45                 ` Linus Torvalds
@ 2017-08-16 21:55                   ` Linus Torvalds
  2017-08-16 22:05                     ` Christian Brauner
  2017-08-16 22:28                   ` Christian Brauner
  1 sibling, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-16 21:55 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Christian Brauner, Linux Kernel Mailing List, Serge E. Hallyn, Al Viro

On Wed, Aug 16, 2017 at 2:45 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> But it would be good to just test this in general too, and make sure I
> didn't screw up some reference count or something. The patch *looks*
> obviously correct, but ...

Side note: I suspect it should be marked for stable, but it's going to
be basically impossible to back-port this any further than 4.7 or
something where we made each pts mount its own proper filesystem. The
code before that was a mess, and this is never going to work right in
old kernels.

Of course, TIOCGPTPEER itself is much more recent than that and was
done in this merge window, so hopefully you haven't backported it and
expect this all to work in some older kernel?

               Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 21:55                   ` Linus Torvalds
@ 2017-08-16 22:05                     ` Christian Brauner
  0 siblings, 0 replies; 55+ messages in thread
From: Christian Brauner @ 2017-08-16 22:05 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Brauner, Linux Kernel Mailing List, Serge E. Hallyn, Al Viro

On Wed, Aug 16, 2017 at 11:55 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> On Wed, Aug 16, 2017 at 2:45 PM, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
>>
>> But it would be good to just test this in general too, and make sure I
>> didn't screw up some reference count or something. The patch *looks*
>> obviously correct, but ...
>
> Side note: I suspect it should be marked for stable, but it's going to
> be basically impossible to back-port this any further than 4.7 or
> something where we made each pts mount its own proper filesystem. The
> code before that was a mess, and this is never going to work right in
> old kernels.

Yeah, it would be nice if this could make it into stable at least and of course
into 4.13 but I take it that's a given anyway.

>
> Of course, TIOCGPTPEER itself is much more recent than that and was
> done in this merge window, so hopefully you haven't backported it and
> expect this all to work in some older kernel?

No, I haven't backported anything and we never intended to.
Serge, Stéphane, and I were very careful to not blindly rely on anything
that recent and - imho - security sensitive in our api. I see this more as a
"tech-preview" until this has seen some decent userspace testing. Even
if the kernel side seems fine now a lot of the userspace pty api is currently
using path-based operations instead of operations on the pty fds themselves.
This is tricky and error-prone when sending around pty fds between
different namespaces as one can see from the ttyname{_r}() example above.

Christian

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 21:45                 ` Linus Torvalds
  2017-08-16 21:55                   ` Linus Torvalds
@ 2017-08-16 22:28                   ` Christian Brauner
  2017-08-23 15:31                     ` Eric W. Biederman
  1 sibling, 1 reply; 55+ messages in thread
From: Christian Brauner @ 2017-08-16 22:28 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Brauner, Linux Kernel Mailing List, Serge E. Hallyn, Al Viro

On Wed, Aug 16, 2017 at 11:45 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> On Wed, Aug 16, 2017 at 2:37 PM, Christian Brauner
> <christian.brauner@canonical.com> wrote:
>>> And Christian, if you can beat on this, that would be good.
>>
>> Yes, I can pound on this nicely with liblxc. We have patch
>> ( https://github.com/lxc/lxc/pull/1728 ) up for review that
>> allocates pty fds from private devpts mounts in different namespaces
>> and sends those fds around between different namespaces.
>
> Good. Testing that this works with different pts filesystems in
> different places is exactly the kind of thing I'd like to see. I only
> tested with my single pts filesystem that is mounted at /dev/pts, and
> making sure it works when there are multiple mounts and in different
> places is exactly the kind of testing this should get.

I'm compiling a kernel now and depending on how good the in-flight
wifi is I try to test this right away and answer here if that helps. If the
in-flight wifi sucks it might take me until tomorrow.

>
> For example, if some namespace has it's pty's in _its_ /dev/pts/
> hierarchy, and you then pass such a pty to somebody else that either
> doesn't have that pts mount at all, or has it visible somewhere
> entirely different, the result should now be something else than that
> "/dev/pts/n" path.
>
> But it would be good to just test this in general too, and make sure I
> didn't screw up some reference count or something. The patch *looks*
> obviously correct, but ...
>
>                Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 21:03             ` Linus Torvalds
  2017-08-16 21:37               ` Christian Brauner
@ 2017-08-16 22:46               ` Eric W. Biederman
  2017-08-16 22:58                 ` Linus Torvalds
  1 sibling, 1 reply; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-16 22:46 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Brauner, Christian Brauner, Linux Kernel Mailing List,
	Serge E. Hallyn, Al Viro

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Wed, Aug 16, 2017 at 1:30 PM, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
>>
>> I suspect the easiest fix is to just add a "mnt" argument to
>> devpts_acquire(),  It shouldn't be too painful. Let me try.
>
> Ok, here's a *very* lightly tested patch. It might have new bugs, but
> it makes your test program DTRT.
>
> Al, mind going over this and making sure I didn't miss anything?
>
> And Christian, if you can beat on this, that would be good.

Linus reading through this it looks like your error handling is wrong.

> diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
> index 284749fb0f6b..432f514e3f42 100644
> --- a/drivers/tty/pty.c
> +++ b/drivers/tty/pty.c
> @@ -793,6 +793,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
>  	struct tty_struct *tty;
>  	struct path *pts_path;
>  	struct dentry *dentry;
> +	struct vfsmount *mnt;
>  	int retval;
>  	int index;
>  
> @@ -805,7 +806,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
>  	if (retval)
>  		return retval;
>  
> -	fsi = devpts_acquire(filp);
> +	fsi = devpts_acquire(filp, &mnt);
>  	if (IS_ERR(fsi)) {
>  		retval = PTR_ERR(fsi);
>  		goto out_free_file;
> @@ -849,9 +850,14 @@ static int ptmx_open(struct inode *inode, struct file *filp)
>  	pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
>  	if (!pts_path)
>  		goto err_release;
> -	pts_path->mnt = filp->f_path.mnt;
> -	pts_path->dentry = dentry;
> -	path_get(pts_path);
> +
> +	/*
> +	 * The mnt already got a ref from devpts_acquire(),
> +	 * so we only dget() on the dentry.
> +	 */
> +	pts_path->mnt = mnt;
> +	pts_path->dentry = dget(dentry);
> +
>  	tty->link->driver_data = pts_path;
>  
>  	retval = ptm_driver->ops->open(tty, filp);
        ^^^^^^^

If this open fails the code jumps to err_put_path which falls
through into out_put_fsi.  But it also does path_put(pts_path).
Which will result in a double mntput of mnt.

So I think err_path_put needs to be updated to just put the dentry,
and let the later mntput put the mount.

> @@ -874,6 +880,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
>  	devpts_kill_index(fsi, index);
>  out_put_fsi:
>  	devpts_release(fsi);
> +	mntput(mnt);
>  out_free_file:
>  	tty_free_file(filp);
>  	return retval;

Eric

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 22:46               ` Eric W. Biederman
@ 2017-08-16 22:58                 ` Linus Torvalds
  2017-08-16 23:51                   ` Eric W. Biederman
  0 siblings, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-16 22:58 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Christian Brauner, Christian Brauner, Linux Kernel Mailing List,
	Serge E. Hallyn, Al Viro

On Wed, Aug 16, 2017 at 3:46 PM, Eric W. Biederman
<ebiederm@xmission.com> wrote:
>>       tty->link->driver_data = pts_path;
>>
>>       retval = ptm_driver->ops->open(tty, filp);
>         ^^^^^^^
>
> If this open fails the code jumps to err_put_path which falls
> through into out_put_fsi.

No it doesn't.

err_path_put falls through to err_release, but that then does a
"return retval;". It doesn't get to out_put_fsi.

Now, I _do_ want people to check the release path, but I don't think
this was it.  Or am I blind and missing something?

                 Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 22:58                 ` Linus Torvalds
@ 2017-08-16 23:51                   ` Eric W. Biederman
  2017-08-17  0:08                     ` Linus Torvalds
  0 siblings, 1 reply; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-16 23:51 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Brauner, Christian Brauner, Linux Kernel Mailing List,
	Serge E. Hallyn, Al Viro

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Wed, Aug 16, 2017 at 3:46 PM, Eric W. Biederman
> <ebiederm@xmission.com> wrote:
>>>       tty->link->driver_data = pts_path;
>>>
>>>       retval = ptm_driver->ops->open(tty, filp);
>>         ^^^^^^^
>>
>> If this open fails the code jumps to err_put_path which falls
>> through into out_put_fsi.
>
> No it doesn't.
>
> err_path_put falls through to err_release, but that then does a
> "return retval;". It doesn't get to out_put_fsi.

*Blink* You are right I missed that.

In which case I am concerned about failures that make it to err_release.
Unless I am missing something (again) failures that jump to err_release
won't call mntput and will result in a mnt leak.

> Now, I _do_ want people to check the release path, but I don't think
> this was it.  Or am I blind and missing something?

Eric

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 23:51                   ` Eric W. Biederman
@ 2017-08-17  0:08                     ` Linus Torvalds
  2017-08-17  1:24                       ` Eric W. Biederman
  2017-08-24  0:24                       ` Stefan Lippers-Hollmann
  0 siblings, 2 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-17  0:08 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Christian Brauner, Christian Brauner, Linux Kernel Mailing List,
	Serge E. Hallyn, Al Viro

[-- Attachment #1: Type: text/plain, Size: 671 bytes --]

On Wed, Aug 16, 2017 at 4:51 PM, Eric W. Biederman
<ebiederm@xmission.com> wrote:
>
> *Blink* You are right I missed that.
>
> In which case I am concerned about failures that make it to err_release.
> Unless I am missing something (again) failures that jump to err_release
> won't call mntput and will result in a mnt leak.

Yes, I think you're right.

Maybe this attached patch is better anyway. It's smaller, because it
keeps more closely to the old code, and just adds a mntput() in all
the exit cases, and depends on the "path_get()" to have incremented
the mnt refcount one extra time.

Can you find something in this one?

ENTIRELY UNTESTED!

               Linus

[-- Attachment #2: patch.diff --]
[-- Type: text/plain, Size: 2883 bytes --]

 drivers/tty/pty.c         | 7 +++++--
 fs/devpts/inode.c         | 4 +++-
 include/linux/devpts_fs.h | 2 +-
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 284749fb0f6b..1fc80ea87c13 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -793,6 +793,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 	struct tty_struct *tty;
 	struct path *pts_path;
 	struct dentry *dentry;
+	struct vfsmount *mnt;
 	int retval;
 	int index;
 
@@ -805,7 +806,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 	if (retval)
 		return retval;
 
-	fsi = devpts_acquire(filp);
+	fsi = devpts_acquire(filp, &mnt);
 	if (IS_ERR(fsi)) {
 		retval = PTR_ERR(fsi);
 		goto out_free_file;
@@ -849,7 +850,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 	pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
 	if (!pts_path)
 		goto err_release;
-	pts_path->mnt = filp->f_path.mnt;
+	pts_path->mnt = mnt;
 	pts_path->dentry = dentry;
 	path_get(pts_path);
 	tty->link->driver_data = pts_path;
@@ -866,6 +867,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 	path_put(pts_path);
 	kfree(pts_path);
 err_release:
+	mntput(mnt);
 	tty_unlock(tty);
 	// This will also put-ref the fsi
 	tty_release(inode, filp);
@@ -874,6 +876,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 	devpts_kill_index(fsi, index);
 out_put_fsi:
 	devpts_release(fsi);
+	mntput(mnt);
 out_free_file:
 	tty_free_file(filp);
 	return retval;
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 108df2e3602c..44dfbca9306f 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -133,7 +133,7 @@ static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
-struct pts_fs_info *devpts_acquire(struct file *filp)
+struct pts_fs_info *devpts_acquire(struct file *filp, struct vfsmount **ptsmnt)
 {
 	struct pts_fs_info *result;
 	struct path path;
@@ -142,6 +142,7 @@ struct pts_fs_info *devpts_acquire(struct file *filp)
 
 	path = filp->f_path;
 	path_get(&path);
+	*ptsmnt = NULL;
 
 	/* Has the devpts filesystem already been found? */
 	sb = path.mnt->mnt_sb;
@@ -165,6 +166,7 @@ struct pts_fs_info *devpts_acquire(struct file *filp)
 	 * pty code needs to hold extra references in case of last /dev/tty close
 	 */
 	atomic_inc(&sb->s_active);
+	*ptsmnt = mntget(path.mnt);
 	result = DEVPTS_SB(sb);
 
 out:
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
index 277ab9af9ac2..7883e901f65c 100644
--- a/include/linux/devpts_fs.h
+++ b/include/linux/devpts_fs.h
@@ -19,7 +19,7 @@
 
 struct pts_fs_info;
 
-struct pts_fs_info *devpts_acquire(struct file *);
+struct pts_fs_info *devpts_acquire(struct file *, struct vfsmount **ptsmnt);
 void devpts_release(struct pts_fs_info *);
 
 int devpts_new_index(struct pts_fs_info *);

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-17  0:08                     ` Linus Torvalds
@ 2017-08-17  1:24                       ` Eric W. Biederman
  2017-08-24  0:24                       ` Stefan Lippers-Hollmann
  1 sibling, 0 replies; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-17  1:24 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Brauner, Christian Brauner, Linux Kernel Mailing List,
	Serge E. Hallyn, Al Viro

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Wed, Aug 16, 2017 at 4:51 PM, Eric W. Biederman
> <ebiederm@xmission.com> wrote:
>>
>> *Blink* You are right I missed that.
>>
>> In which case I am concerned about failures that make it to err_release.
>> Unless I am missing something (again) failures that jump to err_release
>> won't call mntput and will result in a mnt leak.
>
> Yes, I think you're right.
>
> Maybe this attached patch is better anyway. It's smaller, because it
> keeps more closely to the old code, and just adds a mntput() in all
> the exit cases, and depends on the "path_get()" to have incremented
> the mnt refcount one extra time.
>
> Can you find something in this one?

My eyeballs don't see any problems with the patch below.

Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>


Eric


> ENTIRELY UNTESTED!
>
>                Linus
>
>  drivers/tty/pty.c         | 7 +++++--
>  fs/devpts/inode.c         | 4 +++-
>  include/linux/devpts_fs.h | 2 +-
>  3 files changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
> index 284749fb0f6b..1fc80ea87c13 100644
> --- a/drivers/tty/pty.c
> +++ b/drivers/tty/pty.c
> @@ -793,6 +793,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
>  	struct tty_struct *tty;
>  	struct path *pts_path;
>  	struct dentry *dentry;
> +	struct vfsmount *mnt;
>  	int retval;
>  	int index;
>  
> @@ -805,7 +806,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
>  	if (retval)
>  		return retval;
>  
> -	fsi = devpts_acquire(filp);
> +	fsi = devpts_acquire(filp, &mnt);
>  	if (IS_ERR(fsi)) {
>  		retval = PTR_ERR(fsi);
>  		goto out_free_file;
> @@ -849,7 +850,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
>  	pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
>  	if (!pts_path)
>  		goto err_release;
> -	pts_path->mnt = filp->f_path.mnt;
> +	pts_path->mnt = mnt;
>  	pts_path->dentry = dentry;
>  	path_get(pts_path);
>  	tty->link->driver_data = pts_path;
> @@ -866,6 +867,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
>  	path_put(pts_path);
>  	kfree(pts_path);
>  err_release:
> +	mntput(mnt);
>  	tty_unlock(tty);
>  	// This will also put-ref the fsi
>  	tty_release(inode, filp);
> @@ -874,6 +876,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
>  	devpts_kill_index(fsi, index);
>  out_put_fsi:
>  	devpts_release(fsi);
> +	mntput(mnt);
>  out_free_file:
>  	tty_free_file(filp);
>  	return retval;
> diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
> index 108df2e3602c..44dfbca9306f 100644
> --- a/fs/devpts/inode.c
> +++ b/fs/devpts/inode.c
> @@ -133,7 +133,7 @@ static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
>  	return sb->s_fs_info;
>  }
>  
> -struct pts_fs_info *devpts_acquire(struct file *filp)
> +struct pts_fs_info *devpts_acquire(struct file *filp, struct vfsmount **ptsmnt)
>  {
>  	struct pts_fs_info *result;
>  	struct path path;
> @@ -142,6 +142,7 @@ struct pts_fs_info *devpts_acquire(struct file *filp)
>  
>  	path = filp->f_path;
>  	path_get(&path);
> +	*ptsmnt = NULL;
>  
>  	/* Has the devpts filesystem already been found? */
>  	sb = path.mnt->mnt_sb;
> @@ -165,6 +166,7 @@ struct pts_fs_info *devpts_acquire(struct file *filp)
>  	 * pty code needs to hold extra references in case of last /dev/tty close
>  	 */
>  	atomic_inc(&sb->s_active);
> +	*ptsmnt = mntget(path.mnt);
>  	result = DEVPTS_SB(sb);
>  
>  out:
> diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
> index 277ab9af9ac2..7883e901f65c 100644
> --- a/include/linux/devpts_fs.h
> +++ b/include/linux/devpts_fs.h
> @@ -19,7 +19,7 @@
>  
>  struct pts_fs_info;
>  
> -struct pts_fs_info *devpts_acquire(struct file *);
> +struct pts_fs_info *devpts_acquire(struct file *, struct vfsmount **ptsmnt);
>  void devpts_release(struct pts_fs_info *);
>  
>  int devpts_new_index(struct pts_fs_info *);

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 20:19         ` Linus Torvalds
  2017-08-16 20:30           ` Linus Torvalds
@ 2017-08-17  1:37           ` Eric W. Biederman
  1 sibling, 0 replies; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-17  1:37 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Brauner, Christian Brauner, Linux Kernel Mailing List,
	Serge E. Hallyn, Al Viro

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Wed, Aug 16, 2017 at 12:56 PM, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
>>
>> So the fact that we _don't_ get the right pathname for the pts entry
>> here means that something got screwed up in setting filp->f_path to
>> the right thing. We have all the code in place that _tries_ to do it,
>> but it clearly has a bug somewhere.
>
> Ok, I think I see what the bug is, although I don't have a fix for it yet.
>
> We generate the path largely correctly: the path has a nice dentry
> that contains the right pts number, and has the right parent pointer
> that points to the root of the pts mount.
>
> And we also fill in the path 'mnt' field. Everything should be fine.
>
> Except when we actually hit that root dentry of the pts mount, the
> code in prepend_path() hits this condition:
>
>                 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
>                         struct mount *parent = ACCESS_ONCE(mnt->mnt_parent);
>                         /* Escaped? */
>                         if (dentry != vfsmnt->mnt_root) {
>
> and we break out, and reset the path to '/' because we think it
> somehow escaped out of the user namespace.

Escaped it's bind mount actually.  There should always be a path
from mnt_root to a dentry under that mount point.  In some rare caseses
involving bind mounts a rename that moves a dentry from one directory to
another can result in dentries that are not reachable from mnt_root.

As those entries do not have a path in a meaningful sense setting the
path to '/' is the best we can do.

This condition should be limited to bind mounts as any dentry on a
filesystem is descendent from the filesystems root directory.

The rest of your analysis below is correct.

My apologies for the pendantic reply.  I am repling just so that someone
doesn't find this in an email archive 20 years from now and become
impossibly confused.


> So it looks like we filled in the path with the *wrong* mount information.
>
> And THAT in turn is because we fill the path with the mount
> information for the "/dev/ptmx" field - which is *not* in the
> /dev/pts/ mount - that's the mount for '/dev'.
>
> So we have a dentry and a mnt, but they simply aren't paired up correctly.
>
> And you can see this with your test program: if you open /dev/pts/ptmx
> for the master, it actually works correctly (but you need to make sure
> the permissions for that ptmx node allow that).
>
> Anyway, I know what's wrong, next step is to figure out what the fix is.
>
>                    Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-16 22:28                   ` Christian Brauner
@ 2017-08-23 15:31                     ` Eric W. Biederman
  2017-08-23 21:15                       ` Christian Brauner
  0 siblings, 1 reply; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-23 15:31 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Linus Torvalds, Christian Brauner, Linux Kernel Mailing List,
	Serge E. Hallyn, Al Viro

Christian Brauner <christian.brauner@canonical.com> writes:

> On Wed, Aug 16, 2017 at 11:45 PM, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
>> On Wed, Aug 16, 2017 at 2:37 PM, Christian Brauner
>> <christian.brauner@canonical.com> wrote:
>>>> And Christian, if you can beat on this, that would be good.
>>>
>>> Yes, I can pound on this nicely with liblxc. We have patch
>>> ( https://github.com/lxc/lxc/pull/1728 ) up for review that
>>> allocates pty fds from private devpts mounts in different namespaces
>>> and sends those fds around between different namespaces.
>>
>> Good. Testing that this works with different pts filesystems in
>> different places is exactly the kind of thing I'd like to see. I only
>> tested with my single pts filesystem that is mounted at /dev/pts, and
>> making sure it works when there are multiple mounts and in different
>> places is exactly the kind of testing this should get.
>
> I'm compiling a kernel now and depending on how good the in-flight
> wifi is I try to test this right away and answer here if that helps. If the
> in-flight wifi sucks it might take me until tomorrow.

Linus has merged the fix but have you been able to test and verify all
is well from your side?

Eric

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-23 15:31                     ` Eric W. Biederman
@ 2017-08-23 21:15                       ` Christian Brauner
  0 siblings, 0 replies; 55+ messages in thread
From: Christian Brauner @ 2017-08-23 21:15 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Linus Torvalds, Christian Brauner, Linux Kernel Mailing List,
	Serge E. Hallyn, Al Viro

On Wed, Aug 23, 2017 at 10:31:53AM -0500, Eric W. Biederman wrote:
> Christian Brauner <christian.brauner@canonical.com> writes:
> 
> > On Wed, Aug 16, 2017 at 11:45 PM, Linus Torvalds
> > <torvalds@linux-foundation.org> wrote:
> >> On Wed, Aug 16, 2017 at 2:37 PM, Christian Brauner
> >> <christian.brauner@canonical.com> wrote:
> >>>> And Christian, if you can beat on this, that would be good.
> >>>
> >>> Yes, I can pound on this nicely with liblxc. We have patch
> >>> ( https://github.com/lxc/lxc/pull/1728 ) up for review that
> >>> allocates pty fds from private devpts mounts in different namespaces
> >>> and sends those fds around between different namespaces.
> >>
> >> Good. Testing that this works with different pts filesystems in
> >> different places is exactly the kind of thing I'd like to see. I only
> >> tested with my single pts filesystem that is mounted at /dev/pts, and
> >> making sure it works when there are multiple mounts and in different
> >> places is exactly the kind of testing this should get.
> >
> > I'm compiling a kernel now and depending on how good the in-flight
> > wifi is I try to test this right away and answer here if that helps. If the
> > in-flight wifi sucks it might take me until tomorrow.
> 
> Linus has merged the fix but have you been able to test and verify all
> is well from your side?

Hi Eric,

Sorry for the late reply! So I've tested the patch and it does what I expect it
to do, i.e. it places the correct path as the content of /proc/<pid>/fd/<n>.
However, if I'm correct not in all cases. But I need to confirm this first and I
didn't want to start pointless discussions before having something reliable.
Thanks!

The reason for the late reply is that I was investigating some other "weirdness"
related to this patch which also - I believe - touches on the bind-mount
escaping you mentioned in your previous mail. It relates to an idea I had in
mind for a while now but never thought through sufficiently. I hope to find some
time on the weekend to think about this more clearly. I had hoped to bundle this
up with my testing but didn't get around to it.

Christian

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-17  0:08                     ` Linus Torvalds
  2017-08-17  1:24                       ` Eric W. Biederman
@ 2017-08-24  0:24                       ` Stefan Lippers-Hollmann
  2017-08-24  0:42                         ` Linus Torvalds
  1 sibling, 1 reply; 55+ messages in thread
From: Stefan Lippers-Hollmann @ 2017-08-24  0:24 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Eric W. Biederman, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis


[-- Attachment #1.1: Type: text/plain, Size: 5581 bytes --]

Hi

On 2017-08-16, Linus Torvalds wrote:
> On Wed, Aug 16, 2017 at 4:51 PM, Eric W. Biederman
> <ebiederm@xmission.com> wrote:
[...]
> Maybe this attached patch is better anyway. It's smaller, because it
> keeps more closely to the old code, and just adds a mntput() in all
> the exit cases, and depends on the "path_get()" to have incremented
> the mnt refcount one extra time.
> 
> Can you find something in this one?
> 
> ENTIRELY UNTESTED!

This patch[1] as part of 4.13-rc6 (up to, at least, 
v4.13-rc6-45-g6470812e2226) introduces a regression for me when using
pbuilder 0.228.7[2] (a helper to build Debian packages in a chroot and
to create and update its chroots) when trying to umount /dev/ptmx (inside
the chroot) on Debian/ unstable (full log and pbuilder configuration 
file[3] attached).

[...]
Setting up build-essential (12.3) ...
Processing triggers for libc-bin (2.24-15) ...
I: unmounting dev/ptmx filesystem
W: Could not unmount dev/ptmx: umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)
W: Retrying to unmount dev/ptmx in 5s
umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

  Could not unmount dev/ptmx, some programs might
  still be using files in /proc (klogd?).
  Please check and kill these processes manually
  so that I can unmount dev/ptmx.  Last umount error was:
umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)
[...]

lsof isn't revealing (but this might point towards gvfs 1.30.4-1+b1 
involvement), fuser -k doesn't release the ressource.

Kernel v4.13-rc5 and before (at least 4.11.x and 4.12.x) are not
affected, but this problem is reliably reproducible on three different 
x86_64 systems running Debian/ unstable when the host is running a 
kernel >=4.6.13-rc6. Unfortunately I haven't really found an easier/
smaller way to reproduce this issue yet, but creating a new build
chroot[4] always triggers this problem, updating an existing build
chroot[5] (which also mounts and umounts /dev/ptmx) triggers most of 
the time, but not reliably - building a package (e.g. the kernel, also 
mounting and umounting /dev/ptmx) also triggered this issue at least 
once (but I didn't try this more often).

My git bisection log is this:

$ git bisect log
git bisect start
# good: [ef954844c7ace62f773f4f23e28d2d915adc419f] Linux 4.13-rc5
git bisect good ef954844c7ace62f773f4f23e28d2d915adc419f
# bad: [14ccee78fc82f5512908f4424f541549a5705b89] Linux 4.13-rc6
git bisect bad 14ccee78fc82f5512908f4424f541549a5705b89
# bad: [cb247857f3dae0bdb843362c35027a0066b963a4] Merge tag 'sound-4.13-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
git bisect bad cb247857f3dae0bdb843362c35027a0066b963a4
# good: [88a5c690b66110ad255380d8f629c629cf6ca559] bpf: fix bpf_trace_printk on 32 bit archs
git bisect good 88a5c690b66110ad255380d8f629c629cf6ca559
# bad: [3bc6c906eacec34f0d8dcfd3c7e4513edf152297] Merge branch 'parisc-4.13-5' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux
git bisect bad 3bc6c906eacec34f0d8dcfd3c7e4513edf152297
# good: [40c6d1b9e2fc4251ca19fa69398f6fa34e813e27] Merge tag 'linux-kselftest-4.13-rc6-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
git bisect good 40c6d1b9e2fc4251ca19fa69398f6fa34e813e27
# good: [ac9a40905a610fb02086a37b11ff4bf046825a88] Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
git bisect good ac9a40905a610fb02086a37b11ff4bf046825a88
# bad: [99f781b1bfc199ec8eb86d4e015920faf79d5d57] Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
git bisect bad 99f781b1bfc199ec8eb86d4e015920faf79d5d57
# good: [41e327b586762833e48b3703d53312ac32f05f24] quota: correct space limit check
git bisect good 41e327b586762833e48b3703d53312ac32f05f24

Reverting just c8c03f1858331e85d397bacccd34ef409aae993c from
v4.13-rc6-65-g2acf097f16ab reliably fixes the problem for me.

Regards
	Stefan Lippers-Hollmann

[1]	commit c8c03f1858331e85d397bacccd34ef409aae993c (HEAD)
	Author: Linus Torvalds <torvalds@linux-foundation.org>
	Date:   Wed Aug 16 17:08:07 2017 -0700
	Subject: pty: fix the cached path of the pty slave file 
	              descriptor in the master
[2]	https://packages.qa.debian.org/p/pbuilder.html
	https://pbuilder.alioth.debian.org/
	https://anonscm.debian.org/git/pbuilder/pbuilder.git
	mounting/ umounting /dev/ptmx happens in
	https://anonscm.debian.org/git/pbuilder/pbuilder.git/tree/pbuilder-modules
[3]	the configuration file as attached relies on BUILDUSERNAME="pbuilder"
	and BUILDUSERID="$(getent passwd $BUILDUSERNAME | cut -d\: -f3)",
	commenting those out should be possible, my full BUILDUSER* setup
	is:
	# addgroup --system pbuilder
	# adduser --system --disabled-password --ingroup pbuilder --gecos "pbuilder buildd user" --home /var/run/pbuilder pbuilder
	# chown pbuilder:pbuilder /var/cache/pbuilder/deps /var/cache/pbuilder/build-result
	# chmod 2775 /var/cache/pbuilder/deps /var/cache/pbuilder/build-result
[4]	sudo /usr/sbin/pbuilder create --configfile pbuilderrc.debian.sid.amd64
[5]	sudo /usr/sbin/pbuilder update --configfile pbuilderrc.debian.sid.amd64

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: pbuilder.log --]
[-- Type: text/x-log, Size: 27874 bytes --]

sudo /usr/sbin/pbuilder create --configfile /etc/pbuilder/pbuilderrc.debian.sid.amd64
W: /root/.pbuilderrc does not exist
I: Distribution is sid.
I: Current time: Thu Aug 24 00:07:28 CEST 2017
I: pbuilder-time-stamp: 1503526048
I: Building the build environment
I: running cdebootstrap
/usr/bin/cdebootstrap
P: Retrieving Release
P: Retrieving Release.gpg
P: Validating Release
I: Good signature from "Debian Archive Automatic Signing Key (7.0/wheezy) <ftpmaster@debian.org>"
I: Good signature from "Debian Archive Automatic Signing Key (8/jessie) <ftpmaster@debian.org>"
P: Parsing Release
P: Retrieving Packages.xz
P: Validating Packages.xz
P: Parsing Packages
P: Retrieving gcc-7-base
P: Validating gcc-7-base
P: Retrieving libgcc1
P: Validating libgcc1
P: Retrieving libc6
P: Validating libc6
P: Retrieving libattr1
P: Validating libattr1
P: Retrieving libacl1
P: Validating libacl1
P: Retrieving libpcre3
P: Validating libpcre3
P: Retrieving libselinux1
P: Validating libselinux1
P: Retrieving tar
P: Validating tar
P: Retrieving libbz2-1.0
P: Validating libbz2-1.0
P: Retrieving liblzma5
P: Validating liblzma5
P: Retrieving zlib1g
P: Validating zlib1g
P: Retrieving dpkg
P: Validating dpkg
P: Retrieving perl-base
P: Validating perl-base
P: Retrieving init-system-helpers
P: Validating init-system-helpers
P: Retrieving debianutils
P: Validating debianutils
P: Retrieving libaudit-common
P: Validating libaudit-common
P: Retrieving libcap-ng0
P: Validating libcap-ng0
P: Retrieving libaudit1
P: Validating libaudit1
P: Retrieving debconf
P: Validating debconf
P: Retrieving libpam0g
P: Validating libpam0g
P: Retrieving libsemanage-common
P: Validating libsemanage-common
P: Retrieving libsepol1
P: Validating libsepol1
P: Retrieving libustr-1.0-1
P: Validating libustr-1.0-1
P: Retrieving libsemanage1
P: Validating libsemanage1
P: Retrieving libdb5.3
P: Validating libdb5.3
P: Retrieving libpam-modules-bin
P: Validating libpam-modules-bin
P: Retrieving libpam-modules
P: Validating libpam-modules
P: Retrieving passwd
P: Validating passwd
P: Retrieving adduser
P: Validating adduser
P: Retrieving libgpg-error0
P: Validating libgpg-error0
P: Retrieving libgcrypt20
P: Validating libgcrypt20
P: Retrieving gpgv
P: Validating gpgv
P: Retrieving debian-archive-keyring
P: Validating debian-archive-keyring
P: Retrieving liblz4-1
P: Validating liblz4-1
P: Retrieving libstdc++6
P: Validating libstdc++6
P: Retrieving libapt-pkg5.0
P: Validating libapt-pkg5.0
P: Retrieving libgmp10
P: Validating libgmp10
P: Retrieving libnettle6
P: Validating libnettle6
P: Retrieving libhogweed4
P: Validating libhogweed4
P: Retrieving libunistring2
P: Validating libunistring2
P: Retrieving libidn2-0
P: Validating libidn2-0
P: Retrieving libffi6
P: Validating libffi6
P: Retrieving libp11-kit0
P: Validating libp11-kit0
P: Retrieving libtasn1-6
P: Validating libtasn1-6
P: Retrieving libgnutls30
P: Validating libgnutls30
P: Retrieving apt
P: Validating apt
P: Retrieving dash
P: Validating dash
P: Retrieving diffutils
P: Validating diffutils
P: Retrieving coreutils
P: Validating coreutils
P: Retrieving mawk
P: Validating mawk
P: Retrieving base-files
P: Validating base-files
P: Retrieving libtinfo5
P: Validating libtinfo5
P: Retrieving bash
P: Validating bash
P: Retrieving libdebconfclient0
P: Validating libdebconfclient0
P: Retrieving base-passwd
P: Validating base-passwd
P: Retrieving libuuid1
P: Validating libuuid1
P: Retrieving libblkid1
P: Validating libblkid1
P: Retrieving libfdisk1
P: Validating libfdisk1
P: Retrieving libmount1
P: Validating libmount1
P: Retrieving libncursesw5
P: Validating libncursesw5
P: Retrieving libsmartcols1
P: Validating libsmartcols1
P: Retrieving fdisk
P: Validating fdisk
P: Retrieving libsystemd0
P: Validating libsystemd0
P: Retrieving libudev1
P: Validating libudev1
P: Retrieving util-linux
P: Validating util-linux
P: Retrieving sysvinit-utils
P: Validating sysvinit-utils
P: Retrieving gzip
P: Validating gzip
P: Retrieving sed
P: Validating sed
P: Retrieving bsdutils
P: Validating bsdutils
P: Retrieving e2fslibs
P: Validating e2fslibs
P: Retrieving libcomerr2
P: Validating libcomerr2
P: Retrieving libss2
P: Validating libss2
P: Retrieving e2fsprogs
P: Validating e2fsprogs
P: Retrieving libc-bin
P: Validating libc-bin
P: Retrieving findutils
P: Validating findutils
P: Retrieving grep
P: Validating grep
P: Retrieving hostname
P: Validating hostname
P: Retrieving libpam-runtime
P: Validating libpam-runtime
P: Retrieving login
P: Validating login
P: Retrieving ncurses-bin
P: Validating ncurses-bin
P: Retrieving ncurses-base
P: Validating ncurses-base
P: Extracting gcc-7-base
P: Extracting libgcc1
P: Extracting libc6
P: Extracting libattr1
P: Extracting libacl1
P: Extracting libpcre3
P: Extracting libselinux1
P: Extracting tar
P: Extracting libbz2-1.0
P: Extracting liblzma5
P: Extracting zlib1g
P: Extracting dpkg
P: Extracting perl-base
P: Extracting init-system-helpers
P: Extracting debianutils
P: Extracting dash
P: Extracting diffutils
P: Extracting coreutils
P: Extracting mawk
P: Extracting base-files
P: Extracting libtinfo5
P: Extracting bash
P: Extracting libdebconfclient0
P: Extracting base-passwd
P: Extracting libuuid1
P: Extracting libblkid1
P: Extracting libfdisk1
P: Extracting libmount1
P: Extracting libncursesw5
P: Extracting libsmartcols1
P: Extracting fdisk
P: Extracting libaudit-common
P: Extracting libcap-ng0
P: Extracting libaudit1
P: Extracting debconf
P: Extracting libpam0g
P: Extracting libgpg-error0
P: Extracting libgcrypt20
P: Extracting liblz4-1
P: Extracting libsystemd0
P: Extracting libudev1
P: Extracting util-linux
P: Extracting sysvinit-utils
P: Extracting gzip
P: Extracting sed
P: Extracting bsdutils
P: Extracting e2fslibs
P: Extracting libcomerr2
P: Extracting libss2
P: Extracting e2fsprogs
P: Extracting libc-bin
P: Extracting findutils
P: Extracting grep
P: Extracting hostname
P: Extracting libdb5.3
P: Extracting libpam-modules-bin
P: Extracting libpam-modules
P: Extracting libpam-runtime
P: Extracting login
P: Extracting ncurses-bin
P: Extracting ncurses-base
P: Unpacking package dpkg
P: Configuring package dpkg
P: Unpacking package base-passwd
P: Configuring package base-passwd
P: Configuring helper cdebootstrap-helper-rc.d
P: Configuring helper cdebootstrap-helper-makedev
P: Unpacking package tar
P: Unpacking package perl-base
P: Unpacking package init-system-helpers
P: Unpacking package debianutils
P: Unpacking package dash
P: Unpacking package diffutils
P: Unpacking package coreutils
P: Unpacking package mawk
P: Unpacking package base-files
P: Unpacking package bash
P: Unpacking package fdisk
P: Unpacking package libaudit-common
P: Unpacking package debconf
P: Unpacking package util-linux
P: Unpacking package sysvinit-utils
P: Unpacking package gzip
P: Unpacking package sed
P: Unpacking package bsdutils
P: Unpacking package e2fsprogs
P: Unpacking package libc-bin
P: Unpacking package findutils
P: Unpacking package grep
P: Unpacking package hostname
P: Unpacking package libpam-modules-bin
P: Unpacking package libpam-runtime
P: Unpacking package login
P: Unpacking package ncurses-bin
P: Unpacking package ncurses-base
P: Configuring package ncurses-base
P: Configuring package libaudit-common
P: Configuring package libc-bin
P: Configuring package diffutils
P: Configuring package findutils
P: Configuring package sed
P: Configuring package debianutils
P: Configuring package hostname
P: Configuring package mawk
P: Configuring package base-files
P: Configuring package ncurses-bin
P: Configuring package bsdutils
P: Configuring package coreutils
P: Configuring package tar
P: Configuring package fdisk
P: Configuring package perl-base
P: Configuring package grep
P: Configuring package debconf
P: Configuring package gzip
P: Configuring package dash
P: Configuring package init-system-helpers
P: Configuring package util-linux
P: Configuring package libpam-modules-bin
P: Configuring package bash
P: Configuring package e2fsprogs
P: Configuring package sysvinit-utils
P: Configuring package libpam-runtime
P: Configuring package login
P: Unpacking package libsemanage-common
P: Unpacking package passwd
P: Unpacking package adduser
P: Unpacking package gpgv
P: Unpacking package debian-archive-keyring
P: Unpacking package apt
P: Configuring package libsemanage-common
P: Configuring package passwd
P: Configuring package adduser
P: Configuring package gpgv
P: Configuring package debian-archive-keyring
P: Configuring package apt
P: Configuring helper cdebootstrap-helper-apt
P: Retrieving lsb-base
P: Retrieving libassuan0
P: Retrieving readline-common
P: Retrieving libreadline7
P: Retrieving gpgconf
P: Retrieving libksba8
P: Retrieving libsasl2-modules-db
P: Retrieving libsasl2-2
P: Retrieving libldap-common
P: Retrieving libldap-2.4-2
P: Retrieving libnpth0
P: Retrieving dirmngr
P: Retrieving gnupg-l10n
P: Retrieving gnupg-utils
P: Retrieving pinentry-curses
P: Retrieving gpg-agent
P: Retrieving libsqlite3-0
P: Retrieving gpg
P: Retrieving gpg-wks-client
P: Retrieving gpg-wks-server
P: Retrieving gpgsm
P: Retrieving gnupg
P: Unpacking package lsb-base
P: Unpacking package readline-common
P: Unpacking package gpgconf
P: Unpacking package libldap-common
P: Unpacking package dirmngr
P: Unpacking package gnupg-l10n
P: Unpacking package gnupg-utils
P: Unpacking package pinentry-curses
P: Unpacking package gpg-agent
P: Unpacking package gpg
P: Unpacking package gpg-wks-client
P: Unpacking package gpg-wks-server
P: Unpacking package gpgsm
P: Unpacking package gnupg
P: Configuring package readline-common
P: Configuring package libldap-common
P: Configuring package gnupg-l10n
P: Configuring package lsb-base
P: Configuring package gpgconf
P: Configuring package gpgsm
P: Configuring package gnupg-utils
P: Configuring package pinentry-curses
P: Configuring package dirmngr
P: Configuring package gpg
P: Configuring package gpg-agent
P: Configuring package gpg-wks-server
P: Configuring package gpg-wks-client
P: Configuring package gnupg
P: Deconfiguring helper cdebootstrap-helper-apt
P: Deconfiguring helper cdebootstrap-helper-makedev
P: Writing apt sources.list
P: Writing hosts
P: Writing resolv.conf
I: debootstrap finished
I: copying local configuration
I: Installing apt-lines
I: Copy  /usr/lib/pbuilder/aptconfdir/apt.conf.d  to chroot
I: copying apt key file /usr/share/keyrings/debian-archive-keyring.gpg to /var/cache/pbuilder/build/1340/etc/apt/trusted.gpg.d/debian-archive-keyring.gpg
I: Refreshing the base.tgz
I: upgrading packages
I: mounting /proc filesystem
I: mounting /sys filesystem
I: creating /{dev,run}/shm
I: mounting /dev/pts filesystem
I: redirecting /dev/ptmx to /dev/pts/ptmx
I: policy-rc.d already exists
Get:1 http://ftp.de.debian.org/debian sid InRelease [228 kB]
Get:2 http://ftp.de.debian.org/debian sid/main amd64 Packages [7635 kB]
Fetched 7863 kB in 1s (5918 kB/s)
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
Calculating upgrade...
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Reading package lists...
Building dependency tree...
Reading state information...
The following additional packages will be installed:
  binutils bzip2 cpp cpp-7 g++ g++-7 gcc gcc-7 libasan4 libatomic1 libc-dev-bin libc6-dev libcc1-0 libcilkrts5 libdpkg-perl libgcc-7-dev libgdbm3 libgomp1 libisl15 libitm1 liblsan0 libmpc3 libmpfr4 libmpx2 libperl5.26 libquadmath0 libstdc++-7-dev libtsan0 libubsan0 linux-libc-dev make patch perl perl-modules-5.26 xz-utils
Suggested packages:
  binutils-doc bzip2-doc cpp-doc gcc-7-locales debian-keyring g++-multilib g++-7-multilib gcc-7-doc libstdc++6-7-dbg gcc-multilib manpages-dev autoconf automake libtool flex bison gdb gcc-doc gcc-7-multilib libgcc1-dbg libgomp1-dbg libitm1-dbg libatomic1-dbg libasan4-dbg liblsan0-dbg libtsan0-dbg libubsan0-dbg libcilkrts5-dbg libmpx2-dbg libquadmath0-dbg glibc-doc
  libstdc++-7-doc make-doc ed diffutils-doc perl-doc libterm-readline-gnu-perl | libterm-readline-perl-perl
Recommended packages:
  fakeroot libalgorithm-merge-perl manpages manpages-dev libfile-fcntllock-perl liblocale-gettext-perl netbase rename
The following NEW packages will be installed:
  binutils build-essential bzip2 cpp cpp-7 dpkg-dev g++ g++-7 gcc gcc-7 libasan4 libatomic1 libc-dev-bin libc6-dev libcc1-0 libcilkrts5 libdpkg-perl libgcc-7-dev libgdbm3 libgomp1 libisl15 libitm1 liblsan0 libmpc3 libmpfr4 libmpx2 libperl5.26 libquadmath0 libstdc++-7-dev libtsan0 libubsan0 linux-libc-dev make patch perl perl-modules-5.26 xz-utils
0 upgraded, 37 newly installed, 0 to remove and 0 not upgraded.
Need to get 124 MB of archives.
After this operation, 601 MB of additional disk space will be used.
Get:1 http://ftp.de.debian.org/debian sid/main amd64 perl-modules-5.26 all 5.26.0-5 [2823 kB]
Get:2 http://ftp.de.debian.org/debian sid/main amd64 libgdbm3 amd64 1.8.3-14 [30.0 kB]
Get:3 http://ftp.de.debian.org/debian sid/main amd64 libperl5.26 amd64 5.26.0-5 [3586 kB]
Get:4 http://ftp.de.debian.org/debian sid/main amd64 perl amd64 5.26.0-5 [205 kB]
Get:5 http://ftp.de.debian.org/debian sid/main amd64 bzip2 amd64 1.0.6-8.1 [47.5 kB]
Get:6 http://ftp.de.debian.org/debian sid/main amd64 xz-utils amd64 5.2.2-1.3 [266 kB]
Get:7 http://ftp.de.debian.org/debian sid/main amd64 binutils amd64 2.29-5 [4049 kB]
Get:8 http://ftp.de.debian.org/debian sid/main amd64 libc-dev-bin amd64 2.24-15 [259 kB]
Get:9 http://ftp.de.debian.org/debian sid/main amd64 linux-libc-dev amd64 4.12.6-1 [1327 kB]
Get:10 http://ftp.de.debian.org/debian sid/main amd64 libc6-dev amd64 2.24-15 [2368 kB]
Get:11 http://ftp.de.debian.org/debian sid/main amd64 libisl15 amd64 0.18-1 [564 kB]
Get:12 http://ftp.de.debian.org/debian sid/main amd64 libmpfr4 amd64 3.1.5-1 [556 kB]
Get:13 http://ftp.de.debian.org/debian sid/main amd64 libmpc3 amd64 1.0.3-1+b2 [39.9 kB]
Get:14 http://ftp.de.debian.org/debian sid/main amd64 cpp-7 amd64 7.2.0-1 [32.8 MB]
Get:15 http://ftp.de.debian.org/debian sid/main amd64 cpp amd64 4:7.1.0-2 [18.9 kB]
Get:16 http://ftp.de.debian.org/debian sid/main amd64 libcc1-0 amd64 7.2.0-1 [37.8 kB]
Get:17 http://ftp.de.debian.org/debian sid/main amd64 libgomp1 amd64 7.2.0-1 [75.3 kB]
Get:18 http://ftp.de.debian.org/debian sid/main amd64 libitm1 amd64 7.2.0-1 [27.3 kB]
Get:19 http://ftp.de.debian.org/debian sid/main amd64 libatomic1 amd64 7.2.0-1 [8838 B]
Get:20 http://ftp.de.debian.org/debian sid/main amd64 libasan4 amd64 7.2.0-1 [349 kB]
Get:21 http://ftp.de.debian.org/debian sid/main amd64 liblsan0 amd64 7.2.0-1 [125 kB]
Get:22 http://ftp.de.debian.org/debian sid/main amd64 libtsan0 amd64 7.2.0-1 [271 kB]
Get:23 http://ftp.de.debian.org/debian sid/main amd64 libubsan0 amd64 7.2.0-1 [117 kB]
Get:24 http://ftp.de.debian.org/debian sid/main amd64 libcilkrts5 amd64 7.2.0-1 [42.2 kB]
Get:25 http://ftp.de.debian.org/debian sid/main amd64 libmpx2 amd64 7.2.0-1 [11.4 kB]
Get:26 http://ftp.de.debian.org/debian sid/main amd64 libquadmath0 amd64 7.2.0-1 [132 kB]
Get:27 http://ftp.de.debian.org/debian sid/main amd64 libgcc-7-dev amd64 7.2.0-1 [2356 kB]
Get:28 http://ftp.de.debian.org/debian sid/main amd64 gcc-7 amd64 7.2.0-1 [31.9 MB]
Get:29 http://ftp.de.debian.org/debian sid/main amd64 gcc amd64 4:7.1.0-2 [5102 B]
Get:30 http://ftp.de.debian.org/debian sid/main amd64 libstdc++-7-dev amd64 7.2.0-1 [1443 kB]
Get:31 http://ftp.de.debian.org/debian sid/main amd64 g++-7 amd64 7.2.0-1 [35.1 MB]
Get:32 http://ftp.de.debian.org/debian sid/main amd64 g++ amd64 4:7.1.0-2 [1542 B]
Get:33 http://ftp.de.debian.org/debian sid/main amd64 make amd64 4.1-9.1 [302 kB]
Get:34 http://ftp.de.debian.org/debian sid/main amd64 libdpkg-perl all 1.18.24 [1283 kB]
Get:35 http://ftp.de.debian.org/debian sid/main amd64 patch amd64 2.7.5-1+b2 [112 kB]
Get:36 http://ftp.de.debian.org/debian sid/main amd64 dpkg-dev all 1.18.24 [1592 kB]
Get:37 http://ftp.de.debian.org/debian sid/main amd64 build-essential amd64 12.3 [7346 B]
Fetched 124 MB in 3s (38.6 MB/s)
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package perl-modules-5.26.
(Reading database ... 4748 files and directories currently installed.)
Preparing to unpack .../00-perl-modules-5.26_5.26.0-5_all.deb ...
Unpacking perl-modules-5.26 (5.26.0-5) ...
Selecting previously unselected package libgdbm3:amd64.
Preparing to unpack .../01-libgdbm3_1.8.3-14_amd64.deb ...
Unpacking libgdbm3:amd64 (1.8.3-14) ...
Selecting previously unselected package libperl5.26:amd64.
Preparing to unpack .../02-libperl5.26_5.26.0-5_amd64.deb ...
Unpacking libperl5.26:amd64 (5.26.0-5) ...
Selecting previously unselected package perl.
Preparing to unpack .../03-perl_5.26.0-5_amd64.deb ...
Unpacking perl (5.26.0-5) ...
Selecting previously unselected package bzip2.
Preparing to unpack .../04-bzip2_1.0.6-8.1_amd64.deb ...
Unpacking bzip2 (1.0.6-8.1) ...
Selecting previously unselected package xz-utils.
Preparing to unpack .../05-xz-utils_5.2.2-1.3_amd64.deb ...
Unpacking xz-utils (5.2.2-1.3) ...
Selecting previously unselected package binutils.
Preparing to unpack .../06-binutils_2.29-5_amd64.deb ...
Unpacking binutils (2.29-5) ...
Selecting previously unselected package libc-dev-bin.
Preparing to unpack .../07-libc-dev-bin_2.24-15_amd64.deb ...
Unpacking libc-dev-bin (2.24-15) ...
Selecting previously unselected package linux-libc-dev:amd64.
Preparing to unpack .../08-linux-libc-dev_4.12.6-1_amd64.deb ...
Unpacking linux-libc-dev:amd64 (4.12.6-1) ...
Selecting previously unselected package libc6-dev:amd64.
Preparing to unpack .../09-libc6-dev_2.24-15_amd64.deb ...
Unpacking libc6-dev:amd64 (2.24-15) ...
Selecting previously unselected package libisl15:amd64.
Preparing to unpack .../10-libisl15_0.18-1_amd64.deb ...
Unpacking libisl15:amd64 (0.18-1) ...
Selecting previously unselected package libmpfr4:amd64.
Preparing to unpack .../11-libmpfr4_3.1.5-1_amd64.deb ...
Unpacking libmpfr4:amd64 (3.1.5-1) ...
Selecting previously unselected package libmpc3:amd64.
Preparing to unpack .../12-libmpc3_1.0.3-1+b2_amd64.deb ...
Unpacking libmpc3:amd64 (1.0.3-1+b2) ...
Selecting previously unselected package cpp-7.
Preparing to unpack .../13-cpp-7_7.2.0-1_amd64.deb ...
Unpacking cpp-7 (7.2.0-1) ...
Selecting previously unselected package cpp.
Preparing to unpack .../14-cpp_4%3a7.1.0-2_amd64.deb ...
Unpacking cpp (4:7.1.0-2) ...
Selecting previously unselected package libcc1-0:amd64.
Preparing to unpack .../15-libcc1-0_7.2.0-1_amd64.deb ...
Unpacking libcc1-0:amd64 (7.2.0-1) ...
Selecting previously unselected package libgomp1:amd64.
Preparing to unpack .../16-libgomp1_7.2.0-1_amd64.deb ...
Unpacking libgomp1:amd64 (7.2.0-1) ...
Selecting previously unselected package libitm1:amd64.
Preparing to unpack .../17-libitm1_7.2.0-1_amd64.deb ...
Unpacking libitm1:amd64 (7.2.0-1) ...
Selecting previously unselected package libatomic1:amd64.
Preparing to unpack .../18-libatomic1_7.2.0-1_amd64.deb ...
Unpacking libatomic1:amd64 (7.2.0-1) ...
Selecting previously unselected package libasan4:amd64.
Preparing to unpack .../19-libasan4_7.2.0-1_amd64.deb ...
Unpacking libasan4:amd64 (7.2.0-1) ...
Selecting previously unselected package liblsan0:amd64.
Preparing to unpack .../20-liblsan0_7.2.0-1_amd64.deb ...
Unpacking liblsan0:amd64 (7.2.0-1) ...
Selecting previously unselected package libtsan0:amd64.
Preparing to unpack .../21-libtsan0_7.2.0-1_amd64.deb ...
Unpacking libtsan0:amd64 (7.2.0-1) ...
Selecting previously unselected package libubsan0:amd64.
Preparing to unpack .../22-libubsan0_7.2.0-1_amd64.deb ...
Unpacking libubsan0:amd64 (7.2.0-1) ...
Selecting previously unselected package libcilkrts5:amd64.
Preparing to unpack .../23-libcilkrts5_7.2.0-1_amd64.deb ...
Unpacking libcilkrts5:amd64 (7.2.0-1) ...
Selecting previously unselected package libmpx2:amd64.
Preparing to unpack .../24-libmpx2_7.2.0-1_amd64.deb ...
Unpacking libmpx2:amd64 (7.2.0-1) ...
Selecting previously unselected package libquadmath0:amd64.
Preparing to unpack .../25-libquadmath0_7.2.0-1_amd64.deb ...
Unpacking libquadmath0:amd64 (7.2.0-1) ...
Selecting previously unselected package libgcc-7-dev:amd64.
Preparing to unpack .../26-libgcc-7-dev_7.2.0-1_amd64.deb ...
Unpacking libgcc-7-dev:amd64 (7.2.0-1) ...
Selecting previously unselected package gcc-7.
Preparing to unpack .../27-gcc-7_7.2.0-1_amd64.deb ...
Unpacking gcc-7 (7.2.0-1) ...
Selecting previously unselected package gcc.
Preparing to unpack .../28-gcc_4%3a7.1.0-2_amd64.deb ...
Unpacking gcc (4:7.1.0-2) ...
Selecting previously unselected package libstdc++-7-dev:amd64.
Preparing to unpack .../29-libstdc++-7-dev_7.2.0-1_amd64.deb ...
Unpacking libstdc++-7-dev:amd64 (7.2.0-1) ...
Selecting previously unselected package g++-7.
Preparing to unpack .../30-g++-7_7.2.0-1_amd64.deb ...
Unpacking g++-7 (7.2.0-1) ...
Selecting previously unselected package g++.
Preparing to unpack .../31-g++_4%3a7.1.0-2_amd64.deb ...
Unpacking g++ (4:7.1.0-2) ...
Selecting previously unselected package make.
Preparing to unpack .../32-make_4.1-9.1_amd64.deb ...
Unpacking make (4.1-9.1) ...
Selecting previously unselected package libdpkg-perl.
Preparing to unpack .../33-libdpkg-perl_1.18.24_all.deb ...
Unpacking libdpkg-perl (1.18.24) ...
Selecting previously unselected package patch.
Preparing to unpack .../34-patch_2.7.5-1+b2_amd64.deb ...
Unpacking patch (2.7.5-1+b2) ...
Selecting previously unselected package dpkg-dev.
Preparing to unpack .../35-dpkg-dev_1.18.24_all.deb ...
Unpacking dpkg-dev (1.18.24) ...
Selecting previously unselected package build-essential.
Preparing to unpack .../36-build-essential_12.3_amd64.deb ...
Unpacking build-essential (12.3) ...
Setting up libquadmath0:amd64 (7.2.0-1) ...
Setting up libgomp1:amd64 (7.2.0-1) ...
Setting up libatomic1:amd64 (7.2.0-1) ...
Setting up libgdbm3:amd64 (1.8.3-14) ...
Setting up libcc1-0:amd64 (7.2.0-1) ...
Setting up make (4.1-9.1) ...
Setting up libasan4:amd64 (7.2.0-1) ...
Setting up libcilkrts5:amd64 (7.2.0-1) ...
Setting up libubsan0:amd64 (7.2.0-1) ...
Setting up libtsan0:amd64 (7.2.0-1) ...
Setting up linux-libc-dev:amd64 (4.12.6-1) ...
Setting up perl-modules-5.26 (5.26.0-5) ...
Setting up bzip2 (1.0.6-8.1) ...
Setting up liblsan0:amd64 (7.2.0-1) ...
Setting up libmpx2:amd64 (7.2.0-1) ...
Setting up libisl15:amd64 (0.18-1) ...
Setting up patch (2.7.5-1+b2) ...
Processing triggers for libc-bin (2.24-15) ...
Setting up libperl5.26:amd64 (5.26.0-5) ...
Setting up xz-utils (5.2.2-1.3) ...
update-alternatives: using /usr/bin/xz to provide /usr/bin/lzma (lzma) in auto mode
Setting up libmpfr4:amd64 (3.1.5-1) ...
Setting up libmpc3:amd64 (1.0.3-1+b2) ...
Setting up binutils (2.29-5) ...
Setting up libc-dev-bin (2.24-15) ...
Setting up libc6-dev:amd64 (2.24-15) ...
Setting up libitm1:amd64 (7.2.0-1) ...
Setting up libgcc-7-dev:amd64 (7.2.0-1) ...
Setting up cpp-7 (7.2.0-1) ...
Setting up libstdc++-7-dev:amd64 (7.2.0-1) ...
Setting up perl (5.26.0-5) ...
update-alternatives: using /usr/bin/prename to provide /usr/bin/rename (rename) in auto mode
Setting up cpp (4:7.1.0-2) ...
Setting up gcc-7 (7.2.0-1) ...
Setting up g++-7 (7.2.0-1) ...
Setting up libdpkg-perl (1.18.24) ...
Setting up gcc (4:7.1.0-2) ...
Setting up dpkg-dev (1.18.24) ...
Setting up g++ (4:7.1.0-2) ...
update-alternatives: using /usr/bin/g++ to provide /usr/bin/c++ (c++) in auto mode
Setting up build-essential (12.3) ...
Processing triggers for libc-bin (2.24-15) ...
I: unmounting dev/ptmx filesystem
W: Could not unmount dev/ptmx: umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)
W: Retrying to unmount dev/ptmx in 5s
umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

  Could not unmount dev/ptmx, some programs might
  still be using files in /proc (klogd?).
  Please check and kill these processes manually
  so that I can unmount dev/ptmx.  Last umount error was:
umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

  Could not unmount dev/ptmx, some programs might
  still be using files in /proc (klogd?).
  Please check and kill these processes manually
  so that I can unmount dev/ptmx.  Last umount error was:
umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

  Could not unmount dev/ptmx, some programs might
  still be using files in /proc (klogd?).
  Please check and kill these processes manually
  so that I can unmount dev/ptmx.  Last umount error was:
umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

  Could not unmount dev/ptmx, some programs might
  still be using files in /proc (klogd?).
  Please check and kill these processes manually
  so that I can unmount dev/ptmx.  Last umount error was:
umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

  Could not unmount dev/ptmx, some programs might
  still be using files in /proc (klogd?).
  Please check and kill these processes manually
  so that I can unmount dev/ptmx.  Last umount error was:
umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

  Could not unmount dev/ptmx, some programs might
  still be using files in /proc (klogd?).
  Please check and kill these processes manually
  so that I can unmount dev/ptmx.  Last umount error was:
umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)

[-- Attachment #1.3: pbuilderrc.debian.sid.amd64 --]
[-- Type: application/octet-stream, Size: 1703 bytes --]

LOGLEVEL=I
USECOLORS=auto
BUILDPLACE=/var/cache/pbuilder/build
BUILDDIR=/build
BUILD_HOME=/nonexistent
MIRRORSITE="http://ftp.de.debian.org/debian/"
if wget -S http://proxyserver:3128 2>&1 | grep -q Server\:\ squid; then
	http_proxy=http://proxyserver:3128
	https_proxy=http://proxyserver:3128
	ftp_proxy=http://proxyserver:3128
	export http_proxy https_proxy ftp_proxy
fi
USEPROC=yes
USEDEVFS=no
USEDEVPTS=yes
USESYSFS=yes
USENETWORK=no
USERUNSHM=yes
BUILDRESULT="/var/cache/pbuilder/build-result/"
COMPONENTS="main"
APTCACHE=""
APTCACHEHARDLINK="yes"
REMOVEPACKAGES=""
HOOKDIR="/usr/lib/pbuilder/hooks/"
EATMYDATA=no
CCACHEDIR=""
export DEBIAN_FRONTEND="noninteractive"
DEBEMAIL=""
BUILDSOURCEROOTCMD="fakeroot"
PBUILDERROOTCMD="sudo -E"
PBUILDERSATISFYDEPENDSCMD="/usr/lib/pbuilder/pbuilder-satisfydepends-apt"
ALLOWUNTRUSTED=no
export APTGETOPT=()
export APTITUDEOPT=()
DEBDELTA=no
DEBBUILDOPTS=""
DEB_BUILD_OPTIONS="parallel=$(($(nproc) * 2)) $DEB_BUILD_OPTIONS"
export DEB_BUILD_OPTIONS
APTCONFDIR="/usr/lib/pbuilder/aptconfdir"
BUILDUSERNAME="pbuilder"
BUILDUSERID="$(getent passwd $BUILDUSERNAME | cut -d\: -f3)"
BINDMOUNTS=""
DEBOOTSTRAPOPTS=(
    '--variant=buildd'
    '--force-check-gpg'
    )
unset DEBOOTSTRAPOPTS
DEBOOTSTRAPOPTS=(
    '--flavour=minimal'
    '--include=gnupg'
    )
APTKEYRINGS=( "/usr/share/keyrings/debian-archive-keyring.gpg" )
export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
export SHELL=/bin/dash
DEBOOTSTRAP="cdebootstrap"
PKGNAME_LOGFILE_EXTENSION="_$(dpkg --print-architecture).build"
PKGNAME_LOGFILE=""
AUTOCLEANAPTCACHE=""
COMPRESSPROG="gzip"
CONFDIR="/etc/pbuilder/conf_files"
BASETGZ="/var/cache/pbuilder/debian.sid.amd64.tgz"
DEBOOTSTRAPOPTS+=( '--arch=amd64' )

[-- Attachment #2: Digitale Signatur von OpenPGP --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24  0:24                       ` Stefan Lippers-Hollmann
@ 2017-08-24  0:42                         ` Linus Torvalds
  2017-08-24  1:16                           ` Linus Torvalds
  2017-08-24  1:25                           ` Eric W. Biederman
  0 siblings, 2 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24  0:42 UTC (permalink / raw)
  To: Stefan Lippers-Hollmann
  Cc: Eric W. Biederman, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

On Wed, Aug 23, 2017 at 5:24 PM, Stefan Lippers-Hollmann <s.l-h@gmx.de> wrote:
>
> This patch[1] as part of 4.13-rc6 (up to, at least,
> v4.13-rc6-45-g6470812e2226) introduces a regression for me when using
> pbuilder 0.228.7[2] (a helper to build Debian packages in a chroot and
> to create and update its chroots) when trying to umount /dev/ptmx (inside
> the chroot) on Debian/ unstable (full log and pbuilder configuration
> file[3] attached).
>
> [...]
> Setting up build-essential (12.3) ...
> Processing triggers for libc-bin (2.24-15) ...
> I: unmounting dev/ptmx filesystem
> W: Could not unmount dev/ptmx: umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy

Yes, that patch definitely keeps a reference to the pts filesystem
around while a pty is open.

We always used to do that, but we did it differently - we would keep
the 's_active' count elevated so that the superblock never went away,
even after it was unmounted.

Now it does an actual mntget(), and that makes umount _notice_ that
the filesystem is still busy.

How annoying.

Because in a very real sehse the filesystem really is busy, but we
used to hide it (perhaps on purpose - it's possible that people hit
this problem before).

Let me try to think about alteratives. Clearly this is a regression
and I need to fix it, I just need to figure out _how_.

                   Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24  0:42                         ` Linus Torvalds
@ 2017-08-24  1:16                           ` Linus Torvalds
  2017-08-24  1:25                           ` Eric W. Biederman
  1 sibling, 0 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24  1:16 UTC (permalink / raw)
  To: Stefan Lippers-Hollmann
  Cc: Eric W. Biederman, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

On Wed, Aug 23, 2017 at 5:42 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> Let me try to think about alteratives. Clearly this is a regression
> and I need to fix it, I just need to figure out _how_.

Ok, sadly, I think it's unfixable with the current model.

We literally used to keep the wrong 'struct path' around, and sadly,
fixing the struct path to point to the right vfsmount fundamentally
means that we'd be keeping the mount count elevated for that pts
mount.

And that fundamentally means that umount() will return -EBUSY. There's
no way around it.

So I think I will have to just revert that fix.

Damn.

Now, I think there's a way forward: get rid of the 'struct path'
(which is bogus anyway), and only remember the pts denty.

Then, at TIOCGPTPEER time (which is why we currently have that 'struct
path' anyway), look up the right 'vfsmount' by looking up the 'pts'
path again.

That's a rather bigger patch than the one I'll have to revert, I'm afraid ;(

                 Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24  0:42                         ` Linus Torvalds
  2017-08-24  1:16                           ` Linus Torvalds
@ 2017-08-24  1:25                           ` Eric W. Biederman
  2017-08-24  1:32                             ` Linus Torvalds
  1 sibling, 1 reply; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-24  1:25 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Wed, Aug 23, 2017 at 5:24 PM, Stefan Lippers-Hollmann <s.l-h@gmx.de> wrote:
>>
>> This patch[1] as part of 4.13-rc6 (up to, at least,
>> v4.13-rc6-45-g6470812e2226) introduces a regression for me when using
>> pbuilder 0.228.7[2] (a helper to build Debian packages in a chroot and
>> to create and update its chroots) when trying to umount /dev/ptmx (inside
>> the chroot) on Debian/ unstable (full log and pbuilder configuration
>> file[3] attached).
>>
>> [...]
>> Setting up build-essential (12.3) ...
>> Processing triggers for libc-bin (2.24-15) ...
>> I: unmounting dev/ptmx filesystem
>> W: Could not unmount dev/ptmx: umount: /var/cache/pbuilder/build/1340/dev/ptmx: target is busy
>
> Yes, that patch definitely keeps a reference to the pts filesystem
> around while a pty is open.
>
> We always used to do that, but we did it differently - we would keep
> the 's_active' count elevated so that the superblock never went away,
> even after it was unmounted.
>
> Now it does an actual mntget(), and that makes umount _notice_ that
> the filesystem is still busy.
>
> How annoying.
>
> Because in a very real sehse the filesystem really is busy, but we
> used to hide it (perhaps on purpose - it's possible that people hit
> this problem before).
>
> Let me try to think about alteratives. Clearly this is a regression
> and I need to fix it, I just need to figure out _how_.

The new behavior is that when we open ptmx we cache a path the slave
pty.

If instead of caching that path we call devpts_acquire to compute the
mount point of the dentry we should be able to skip caching mountpoint
in ptmx_open.

That should trivially remove the regression.

We will have to fail if someone crazy unmounted the devpts filesystem
before we ask for the peer file descriptor.  But otherwise the behavior
should be exactly the same.

Eric

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24  1:25                           ` Eric W. Biederman
@ 2017-08-24  1:32                             ` Linus Torvalds
  2017-08-24  1:49                               ` Linus Torvalds
  0 siblings, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24  1:32 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

On Wed, Aug 23, 2017 at 6:25 PM, Eric W. Biederman
<ebiederm@xmission.com> wrote:
>
> The new behavior is that when we open ptmx we cache a path the slave
> pty.

Yes. It's not strictly "new", though - we've done that for a while,
and if you used /dev/pts/ptmx you'd even have had the *right* path
for a while ;)

And this exact issue that Stefan is reporting.

But nobody ever used /dev/pts/ptmx, so nobody got the right path, and
nobody kept an extra reference to the pts mount.

> If instead of caching that path we call devpts_acquire to compute the
> mount point of the dentry we should be able to skip caching mountpoint
> in ptmx_open.

Yes, that's my plan - get rid of the 'struct path' entirely, make
'driver_data' point to just the dentry, and then at TIOCGPTPEER time
just re-create the path by looking up the vfsmount again (by doingf
that "pts" lookup again)

It should all be _fairly_ straightforward, but it's definitely a
rather bigger change than that "just fix the path" patch was.

Anyway, it's already reverted in my tree, I'll push it out after I've
verified that there isn't some silly build issue (there won't be, but
I've been burned by "this is obviously correct" too many times, so now
I always build before pushing anything out unless I'm on my laptop of
something when it's just too inconvenient).

                      Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24  1:32                             ` Linus Torvalds
@ 2017-08-24  1:49                               ` Linus Torvalds
  2017-08-24  2:01                                 ` Linus Torvalds
  0 siblings, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24  1:49 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

On Wed, Aug 23, 2017 at 6:32 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> It should all be _fairly_ straightforward, but it's definitely a
> rather bigger change than that "just fix the path" patch was.

Argh. And it's *not* fairly straightforward, because the
tty_operations "ioctl()" function pointer only gets 'struct tty *'.

So in the TIOCGPTPEER path, we don't actually have access to the file
pointer of the fd we're doing the ioctl on.

And that's where the 'struct path' to the 'ptmx' node is - which we
need to then look up the 'pts' directory.

How very annoying. I think that's why we did it all at ptmx_open()
time, because then we had all the information.

                Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24  1:49                               ` Linus Torvalds
@ 2017-08-24  2:01                                 ` Linus Torvalds
  2017-08-24  3:11                                   ` Eric W. Biederman
  0 siblings, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24  2:01 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

On Wed, Aug 23, 2017 at 6:49 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> Argh. And it's *not* fairly straightforward, because the
> tty_operations "ioctl()" function pointer only gets 'struct tty *'.
>
> So in the TIOCGPTPEER path, we don't actually have access to the file
> pointer of the fd we're doing the ioctl on.
>
> And that's where the 'struct path' to the 'ptmx' node is - which we
> need to then look up the 'pts' directory.
>
> How very annoying. I think that's why we did it all at ptmx_open()
> time, because then we had all the information.

Anyway, the revert is pushed out. So we're back to the old behavior
that gives the wrong pathname in /proc.

And I think I can handle the lack of a 'struct file *' to the ioctl
operations by just special-casing TIOCGPTPEER directly in tty_ioctl()
itself.

That's where we handle "generic" tty ioctls, and doing pty stuff there
is kind of wrong, but pty's are special.

But I think I'll leave it for tomorrow. So Eric, if you feel like
looking at this, I'd appreciate it.

                Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24  2:01                                 ` Linus Torvalds
@ 2017-08-24  3:11                                   ` Eric W. Biederman
  2017-08-24  3:24                                     ` Linus Torvalds
  2017-08-24  4:24                                     ` Stefan Lippers-Hollmann
  0 siblings, 2 replies; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-24  3:11 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Wed, Aug 23, 2017 at 6:49 PM, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
>>
>> Argh. And it's *not* fairly straightforward, because the
>> tty_operations "ioctl()" function pointer only gets 'struct tty *'.
>>
>> So in the TIOCGPTPEER path, we don't actually have access to the file
>> pointer of the fd we're doing the ioctl on.
>>
>> And that's where the 'struct path' to the 'ptmx' node is - which we
>> need to then look up the 'pts' directory.
>>
>> How very annoying. I think that's why we did it all at ptmx_open()
>> time, because then we had all the information.
>
> Anyway, the revert is pushed out. So we're back to the old behavior
> that gives the wrong pathname in /proc.
>
> And I think I can handle the lack of a 'struct file *' to the ioctl
> operations by just special-casing TIOCGPTPEER directly in tty_ioctl()
> itself.
>
> That's where we handle "generic" tty ioctls, and doing pty stuff there
> is kind of wrong, but pty's are special.
>
> But I think I'll leave it for tomorrow. So Eric, if you feel like
> looking at this, I'd appreciate it.

This is so far untested (except for compiling) but I think this will
work.

I factor out devpts_ptmx_path out of devpts_acquire so the code
doesn't have to do unnecessary and confusing work, and add the
new function devpts_mnt.

I revert the code to keep anything except a dentry in
tty->link->driver_data.

And reduce the peer opening to a single function ptm_open_peer.

It takes lines of code but the result is very straightforward code.

Eric


 drivers/tty/pty.c         | 63 ++++++++++++++++++++---------------------------
 drivers/tty/tty_io.c      |  3 +++
 fs/devpts/inode.c         | 60 +++++++++++++++++++++++++++++++++-----------
 include/linux/devpts_fs.h | 10 ++++++++
 4 files changed, 85 insertions(+), 51 deletions(-)
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 284749fb0f6b..269e6ea65a33 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -69,13 +69,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
 #ifdef CONFIG_UNIX98_PTYS
 		if (tty->driver == ptm_driver) {
 			mutex_lock(&devpts_mutex);
-			if (tty->link->driver_data) {
-				struct path *path = tty->link->driver_data;
-
-				devpts_pty_kill(path->dentry);
-				path_put(path);
-				kfree(path);
-			}
+			if (tty->link->driver_data)
+				devpts_pty_kill(tty->link->driver_data);
 			mutex_unlock(&devpts_mutex);
 		}
 #endif
@@ -607,25 +602,25 @@ static inline void legacy_pty_init(void) { }
 static struct cdev ptmx_cdev;
 
 /**
- *	pty_open_peer - open the peer of a pty
- *	@tty: the peer of the pty being opened
+ *	ptm_open_peer - open the peer of a pty
+ *	@master: the open struct file of the ptmx device node
+ *	@tty: the master of the pty being opened
+ *	@flags: the flags for open
  *
- *	Open the cached dentry in tty->link, providing a safe way for userspace
- *	to get the slave end of a pty (where they have the master fd and cannot
- *	access or trust the mount namespace /dev/pts was mounted inside).
+ *	Provide a race free way for userspace to open the slave end of a pty
+ *	(where they have the master fd and cannot access or trust the mount
+ *	namespace /dev/pts was mounted inside).
  */
-static struct file *pty_open_peer(struct tty_struct *tty, int flags)
-{
-	if (tty->driver->subtype != PTY_TYPE_MASTER)
-		return ERR_PTR(-EIO);
-	return dentry_open(tty->link->driver_data, flags, current_cred());
-}
-
-static int pty_get_peer(struct tty_struct *tty, int flags)
+int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
 {
 	int fd = -1;
 	struct file *filp = NULL;
 	int retval = -EINVAL;
+	struct path path;
+
+	if ((tty->driver->type != TTY_DRIVER_TYPE_PTY) ||
+	    (tty->driver->subtype != PTY_TYPE_MASTER))
+		return -EIO;
 
 	fd = get_unused_fd_flags(0);
 	if (fd < 0) {
@@ -633,7 +628,16 @@ static int pty_get_peer(struct tty_struct *tty, int flags)
 		goto err;
 	}
 
-	filp = pty_open_peer(tty, flags);
+	/* Compute the slave's path */
+	path.mnt = devpts_mnt(filp);
+	if (IS_ERR(path.mnt)) {
+		retval = PTR_ERR(path.mnt);
+		goto err_put;
+	}
+	path.dentry = tty->link->driver_data;
+
+	filp = dentry_open(&path, flags, current_cred());
+	mntput(path.mnt);
 	if (IS_ERR(filp)) {
 		retval = PTR_ERR(filp);
 		goto err_put;
@@ -662,8 +666,6 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
 		return pty_get_pktmode(tty, (int __user *)arg);
 	case TIOCGPTN: /* Get PT Number */
 		return put_user(tty->index, (unsigned int __user *)arg);
-	case TIOCGPTPEER: /* Open the other end */
-		return pty_get_peer(tty, (int) arg);
 	case TIOCSIG:    /* Send signal to other side of pty */
 		return pty_signal(tty, (int) arg);
 	}
@@ -791,7 +793,6 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 {
 	struct pts_fs_info *fsi;
 	struct tty_struct *tty;
-	struct path *pts_path;
 	struct dentry *dentry;
 	int retval;
 	int index;
@@ -845,26 +846,16 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 		retval = PTR_ERR(dentry);
 		goto err_release;
 	}
-	/* We need to cache a fake path for TIOCGPTPEER. */
-	pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
-	if (!pts_path)
-		goto err_release;
-	pts_path->mnt = filp->f_path.mnt;
-	pts_path->dentry = dentry;
-	path_get(pts_path);
-	tty->link->driver_data = pts_path;
+	tty->link->driver_data = dentry;
 
 	retval = ptm_driver->ops->open(tty, filp);
 	if (retval)
-		goto err_path_put;
+		goto err_release;
 
 	tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
 
 	tty_unlock(tty);
 	return 0;
-err_path_put:
-	path_put(pts_path);
-	kfree(pts_path);
 err_release:
 	tty_unlock(tty);
 	// This will also put-ref the fsi
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 974b13d24401..ba3371449a5c 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2518,6 +2518,9 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case TIOCSSERIAL:
 		tty_warn_deprecated_flags(p);
 		break;
+	case TIOCGPTPEER:
+		retval = ptm_open_peer(file, tty, (int)arg);
+		break;
 	default:
 		retval = tty_jobctrl_ioctl(tty, real_tty, file, cmd, arg);
 		if (retval != -ENOIOCTLCMD)
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 108df2e3602c..6e8816cf7d54 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -133,37 +133,67 @@ static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
-struct pts_fs_info *devpts_acquire(struct file *filp)
+static int devpts_ptmx_path(struct path *path)
 {
-	struct pts_fs_info *result;
-	struct path path;
 	struct super_block *sb;
-	int err;
-
-	path = filp->f_path;
-	path_get(&path);
+	int err = 0;
 
 	/* Has the devpts filesystem already been found? */
-	sb = path.mnt->mnt_sb;
+	sb = path->mnt->mnt_sb;
 	if (sb->s_magic != DEVPTS_SUPER_MAGIC) {
 		/* Is a devpts filesystem at "pts" in the same directory? */
-		err = path_pts(&path);
-		if (err) {
-			result = ERR_PTR(err);
+		err = path_pts(path);
+		if (err)
 			goto out;
-		}
 
 		/* Is the path the root of a devpts filesystem? */
-		result = ERR_PTR(-ENODEV);
-		sb = path.mnt->mnt_sb;
+		err = -ENODEV;
+		sb = path->mnt->mnt_sb;
 		if ((sb->s_magic != DEVPTS_SUPER_MAGIC) ||
-		    (path.mnt->mnt_root != sb->s_root))
+		    (path->mnt->mnt_root != sb->s_root))
 			goto out;
 	}
 
+out:
+	return err;
+}
+
+struct vfsmount *devpts_mnt(struct file *filp)
+{
+	struct path path;
+	int err;
+
+	path = filp->f_path;
+	path_get(&path);
+
+	err = devpts_ptmx_path(&path);
+	if (err) {
+		path_put(&path);
+		path.mnt = ERR_PTR(err);
+	}
+	return path.mnt;
+}
+
+struct pts_fs_info *devpts_acquire(struct file *filp)
+{
+	struct pts_fs_info *result;
+	struct path path;
+	struct super_block *sb;
+	int err;
+
+	path = filp->f_path;
+	path_get(&path);
+
+	err = devpts_ptmx_path(&path);
+	if (err) {
+		result = ERR_PTR(err);
+		goto out;
+	}
+
 	/*
 	 * pty code needs to hold extra references in case of last /dev/tty close
 	 */
+	sb = path.mnt->mnt_sb;
 	atomic_inc(&sb->s_active);
 	result = DEVPTS_SB(sb);
 
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
index 277ab9af9ac2..e27c548acfb0 100644
--- a/include/linux/devpts_fs.h
+++ b/include/linux/devpts_fs.h
@@ -19,6 +19,7 @@
 
 struct pts_fs_info;
 
+struct vfsmount *devpts_mnt(struct file *);
 struct pts_fs_info *devpts_acquire(struct file *);
 void devpts_release(struct pts_fs_info *);
 
@@ -32,6 +33,15 @@ void *devpts_get_priv(struct dentry *);
 /* unlink */
 void devpts_pty_kill(struct dentry *);
 
+/* in pty.c */
+int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags);
+
+#else
+static inline int
+ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
+{
+	return -EIO;
+}
 #endif
 
 

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24  3:11                                   ` Eric W. Biederman
@ 2017-08-24  3:24                                     ` Linus Torvalds
  2017-08-24 15:51                                       ` Eric W. Biederman
  2017-08-24  4:24                                     ` Stefan Lippers-Hollmann
  1 sibling, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24  3:24 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

On Wed, Aug 23, 2017 at 8:11 PM, Eric W. Biederman
<ebiederm@xmission.com> wrote:
> -static int pty_get_peer(struct tty_struct *tty, int flags)
> +int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
>  {
>         int fd = -1;
>         struct file *filp = NULL;
>         int retval = -EINVAL;
> +       struct path path;
> +
> +       if ((tty->driver->type != TTY_DRIVER_TYPE_PTY) ||
> +           (tty->driver->subtype != PTY_TYPE_MASTER))
> +               return -EIO;

No. Afaik, that could be a legact PTY, which wouldn't be ok.

I think you need to do

        if (tty->driver != ptm_driver)
                return -EIO;

which should check both that it's the unix98 pty, and that it's the master.

Maybe I'm missing something.

That check used to be implicit, in that only the unix98 pty's could
reach that pty_unix98_ioctl() function, so then testing just that it
was a master was sufficient.

> -       /* We need to cache a fake path for TIOCGPTPEER. */
> -       pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
> -       if (!pts_path)
> -               goto err_release;
> -       pts_path->mnt = filp->f_path.mnt;
> -       pts_path->dentry = dentry;
> -       path_get(pts_path);
> -       tty->link->driver_data = pts_path;
> +       tty->link->driver_data = dentry;

We used to do "path_get()". Shouldn't we now use "dget()"?

But maybe the slave dentry is guaranteed to be around and we don't
need to do that. So your approach may be fine. You did remove all the
path_put() calls too, so I guess it all matches up.

So this looks like it could be fine, but I'd like to make sure.

> +struct vfsmount *devpts_mnt(struct file *filp)
> +{
> +       struct path path;
> +       int err;
> +
> +       path = filp->f_path;
> +       path_get(&path);
> +
> +       err = devpts_ptmx_path(&path);
> +       if (err) {
> +               path_put(&path);
> +               path.mnt = ERR_PTR(err);
> +       }
> +       return path.mnt;
> +}

That can't be right. You're leaking the dentry that you're not returning, no?

But yes, apart from those comments, this looks like what I envisioned.

Needs testing, and needs more looking at those reference counts, but
otherwise looks good.

And while the patch is a bit bigger, I do like getting rid of that
'struct path' thing, and keeping just the dentry.

                      Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24  3:11                                   ` Eric W. Biederman
  2017-08-24  3:24                                     ` Linus Torvalds
@ 2017-08-24  4:24                                     ` Stefan Lippers-Hollmann
  2017-08-24 15:54                                       ` Eric W. Biederman
  1 sibling, 1 reply; 55+ messages in thread
From: Stefan Lippers-Hollmann @ 2017-08-24  4:24 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Linus Torvalds, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

[-- Attachment #1: Type: text/plain, Size: 1151 bytes --]

Hi

On 2017-08-23, Eric W. Biederman wrote:
> Linus Torvalds <torvalds@linux-foundation.org> writes:
> > On Wed, Aug 23, 2017 at 6:49 PM, Linus Torvalds <torvalds@linux-foundation.org> wrote:  
[...]
> This is so far untested (except for compiling) but I think this will
> work.
> 
> I factor out devpts_ptmx_path out of devpts_acquire so the code
> doesn't have to do unnecessary and confusing work, and add the
> new function devpts_mnt.
> 
> I revert the code to keep anything except a dentry in
> tty->link->driver_data.
> 
> And reduce the peer opening to a single function ptm_open_peer.
> 
> It takes lines of code but the result is very straightforward code.

I've given this a quick test, while it seems to fix the initial problem
with umounting /dev/ptmx, it does introduce a new one - trying to open 
an xterm (KDE5's konsole to be exact) doesn't open a shell (the shell 
window remains totally empty) and trying to ssh into the system fails 
with "PTY allocation request failed on channel 0", logging in via a 
real tty and creating a new pbuilder chroot from there succeeds.

Regards
	Stefan Lippers-Hollmann

[-- Attachment #2: Digitale Signatur von OpenPGP --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24  3:24                                     ` Linus Torvalds
@ 2017-08-24 15:51                                       ` Eric W. Biederman
  0 siblings, 0 replies; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-24 15:51 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Wed, Aug 23, 2017 at 8:11 PM, Eric W. Biederman
> <ebiederm@xmission.com> wrote:
>> -static int pty_get_peer(struct tty_struct *tty, int flags)
>> +int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
>>  {
>>         int fd = -1;
>>         struct file *filp = NULL;
>>         int retval = -EINVAL;
>> +       struct path path;
>> +
>> +       if ((tty->driver->type != TTY_DRIVER_TYPE_PTY) ||
>> +           (tty->driver->subtype != PTY_TYPE_MASTER))
>> +               return -EIO;
>
> No. Afaik, that could be a legact PTY, which wouldn't be ok.
>
> I think you need to do
>
>         if (tty->driver != ptm_driver)
>                 return -EIO;
>
> which should check both that it's the unix98 pty, and that it's the master.
>
> Maybe I'm missing something.
>
> That check used to be implicit, in that only the unix98 pty's could
> reach that pty_unix98_ioctl() function, so then testing just that it
> was a master was sufficient.

No.  That seems correct.  Change made.  If nothing else it is cheaper
and clearer so even if the other version wasn't wrong it is a good idea.

>> -       /* We need to cache a fake path for TIOCGPTPEER. */
>> -       pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
>> -       if (!pts_path)
>> -               goto err_release;
>> -       pts_path->mnt = filp->f_path.mnt;
>> -       pts_path->dentry = dentry;
>> -       path_get(pts_path);
>> -       tty->link->driver_data = pts_path;
>> +       tty->link->driver_data = dentry;
>
> We used to do "path_get()". Shouldn't we now use "dget()"?
>
> But maybe the slave dentry is guaranteed to be around and we don't
> need to do that. So your approach may be fine. You did remove all the
> path_put() calls too, so I guess it all matches up.
>
> So this looks like it could be fine, but I'd like to make sure.

That change is a revert to the old v4.12 code.  So it is definitely
not regression inducing.

Further devpts_pty_new allocates a dentry keeps it in the devpts
filesystem.  The dentry is good until devpts_pty_kill where the
dentry is unlinked and killed.

I figure not differences from v4.12 if the logic hasn't changed
seems a good good way to cut down on the search for bugs/regressions.

>> +struct vfsmount *devpts_mnt(struct file *filp)
>> +{
>> +       struct path path;
>> +       int err;
>> +
>> +       path = filp->f_path;
>> +       path_get(&path);
>> +
>> +       err = devpts_ptmx_path(&path);
>> +       if (err) {
>> +               path_put(&path);
>> +               path.mnt = ERR_PTR(err);
>> +       }
>> +       return path.mnt;
>> +}
>
> That can't be right. You're leaking the dentry that you're not returning, no?

Correct. That is buggy.  Will fix before I resend.

> But yes, apart from those comments, this looks like what I envisioned.
>
> Needs testing, and needs more looking at those reference counts, but
> otherwise looks good.
>
> And while the patch is a bit bigger, I do like getting rid of that
> 'struct path' thing, and keeping just the dentry.

Eric

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24  4:24                                     ` Stefan Lippers-Hollmann
@ 2017-08-24 15:54                                       ` Eric W. Biederman
  2017-08-24 17:52                                         ` Linus Torvalds
  0 siblings, 1 reply; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-24 15:54 UTC (permalink / raw)
  To: Stefan Lippers-Hollmann
  Cc: Linus Torvalds, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

Stefan Lippers-Hollmann <s.l-h@gmx.de> writes:

> Hi
>
> On 2017-08-23, Eric W. Biederman wrote:
>> Linus Torvalds <torvalds@linux-foundation.org> writes:
>> > On Wed, Aug 23, 2017 at 6:49 PM, Linus Torvalds <torvalds@linux-foundation.org> wrote:  
> [...]
>> This is so far untested (except for compiling) but I think this will
>> work.
>> 
>> I factor out devpts_ptmx_path out of devpts_acquire so the code
>> doesn't have to do unnecessary and confusing work, and add the
>> new function devpts_mnt.
>> 
>> I revert the code to keep anything except a dentry in
>> tty->link->driver_data.
>> 
>> And reduce the peer opening to a single function ptm_open_peer.
>> 
>> It takes lines of code but the result is very straightforward code.
>
> I've given this a quick test, while it seems to fix the initial problem
> with umounting /dev/ptmx, it does introduce a new one - trying to open 
> an xterm (KDE5's konsole to be exact) doesn't open a shell (the shell 
> window remains totally empty) and trying to ssh into the system fails 
> with "PTY allocation request failed on channel 0", logging in via a 
> real tty and creating a new pbuilder chroot from there succeeds.

Weird.  There is at least one leak inducing bug in there.  So perhaps
that is the cause.   *Scratches my head*  Are you also testing the new
ioctl?

I will resend shortly with a version that has no differences in the old
code from v4.12 (other than the refactoring in fs/devpts/inode.c).
Which should make it very hard to have a regression.

Eric

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 15:54                                       ` Eric W. Biederman
@ 2017-08-24 17:52                                         ` Linus Torvalds
  2017-08-24 18:06                                           ` Linus Torvalds
  0 siblings, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24 17:52 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

On Thu, Aug 24, 2017 at 8:54 AM, Eric W. Biederman
<ebiederm@xmission.com> wrote:
>
> Weird.  There is at least one leak inducing bug in there.  So perhaps
> that is the cause.   *Scratches my head*  Are you also testing the new
> ioctl?

I can verify, and it's not the leak. I tried your patch with that leak
fix (and the other fixes I pointed out), and I see similar issues that
Stefan noted.

With gnome-terminal, the terminal window opens, and then it says

   Failed to open PTY: No such device

and the terminal obviously doesn't work.

And I see the error: your devpts_ptmx_path() code always returns
-ENODEV because you set the error unconditionally before an error
check, and then you don't clear it if the error didn't happen.

I'll test the fix.

                    Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 17:52                                         ` Linus Torvalds
@ 2017-08-24 18:06                                           ` Linus Torvalds
  2017-08-24 18:13                                             ` Linus Torvalds
  0 siblings, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24 18:06 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

On Thu, Aug 24, 2017 at 10:52 AM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> I'll test the fix.

Yes, that was it, and things work with that fixed.

But that still fails the TIOCGPTPEER ioctl with an NULL pointer
dereference in devpts_mnt,  I probably messed up when I fixed the
dentry refcount leak.

               Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 18:06                                           ` Linus Torvalds
@ 2017-08-24 18:13                                             ` Linus Torvalds
  2017-08-24 18:31                                               ` Linus Torvalds
  2017-08-24 18:40                                               ` Eric W. Biederman
  0 siblings, 2 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24 18:13 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

[-- Attachment #1: Type: text/plain, Size: 547 bytes --]

On Thu, Aug 24, 2017 at 11:06 AM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> But that still fails the TIOCGPTPEER ioctl with an NULL pointer
> dereference in devpts_mnt,  I probably messed up when I fixed the
> dentry refcount leak.

No, that was another bug in the original patch.

ptm_open_peer() passed in 'filp' to devpts_mnt(), but it should
obviously pass in the 'master' one.

filp is NULL at that point.

The attached patch should work. It's Eric's original patch with
various cleanups and fixes.

                    Linus

[-- Attachment #2: patch.diff --]
[-- Type: text/plain, Size: 7312 bytes --]

 drivers/tty/pty.c         | 64 ++++++++++++++++++++---------------------------
 drivers/tty/tty_io.c      |  3 +++
 fs/devpts/inode.c         | 63 ++++++++++++++++++++++++++++++++++------------
 include/linux/devpts_fs.h | 10 ++++++++
 4 files changed, 87 insertions(+), 53 deletions(-)

diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 284749fb0f6b..bfd66fcff7a3 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -69,13 +69,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
 #ifdef CONFIG_UNIX98_PTYS
 		if (tty->driver == ptm_driver) {
 			mutex_lock(&devpts_mutex);
-			if (tty->link->driver_data) {
-				struct path *path = tty->link->driver_data;
-
-				devpts_pty_kill(path->dentry);
-				path_put(path);
-				kfree(path);
-			}
+			if (tty->link->driver_data)
+				devpts_pty_kill(tty->link->driver_data);
 			mutex_unlock(&devpts_mutex);
 		}
 #endif
@@ -607,25 +602,24 @@ static inline void legacy_pty_init(void) { }
 static struct cdev ptmx_cdev;
 
 /**
- *	pty_open_peer - open the peer of a pty
- *	@tty: the peer of the pty being opened
+ *	ptm_open_peer - open the peer of a pty
+ *	@master: the open struct file of the ptmx device node
+ *	@tty: the master of the pty being opened
+ *	@flags: the flags for open
  *
- *	Open the cached dentry in tty->link, providing a safe way for userspace
- *	to get the slave end of a pty (where they have the master fd and cannot
- *	access or trust the mount namespace /dev/pts was mounted inside).
+ *	Provide a race free way for userspace to open the slave end of a pty
+ *	(where they have the master fd and cannot access or trust the mount
+ *	namespace /dev/pts was mounted inside).
  */
-static struct file *pty_open_peer(struct tty_struct *tty, int flags)
-{
-	if (tty->driver->subtype != PTY_TYPE_MASTER)
-		return ERR_PTR(-EIO);
-	return dentry_open(tty->link->driver_data, flags, current_cred());
-}
-
-static int pty_get_peer(struct tty_struct *tty, int flags)
+int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
 {
 	int fd = -1;
-	struct file *filp = NULL;
+	struct file *filp;
 	int retval = -EINVAL;
+	struct path path;
+
+	if (tty->driver != ptm_driver)
+		return -EIO;
 
 	fd = get_unused_fd_flags(0);
 	if (fd < 0) {
@@ -633,7 +627,16 @@ static int pty_get_peer(struct tty_struct *tty, int flags)
 		goto err;
 	}
 
-	filp = pty_open_peer(tty, flags);
+	/* Compute the slave's path */
+	path.mnt = devpts_mnt(master);
+	if (IS_ERR(path.mnt)) {
+		retval = PTR_ERR(path.mnt);
+		goto err_put;
+	}
+	path.dentry = tty->link->driver_data;
+
+	filp = dentry_open(&path, flags, current_cred());
+	mntput(path.mnt);
 	if (IS_ERR(filp)) {
 		retval = PTR_ERR(filp);
 		goto err_put;
@@ -662,8 +665,6 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
 		return pty_get_pktmode(tty, (int __user *)arg);
 	case TIOCGPTN: /* Get PT Number */
 		return put_user(tty->index, (unsigned int __user *)arg);
-	case TIOCGPTPEER: /* Open the other end */
-		return pty_get_peer(tty, (int) arg);
 	case TIOCSIG:    /* Send signal to other side of pty */
 		return pty_signal(tty, (int) arg);
 	}
@@ -791,7 +792,6 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 {
 	struct pts_fs_info *fsi;
 	struct tty_struct *tty;
-	struct path *pts_path;
 	struct dentry *dentry;
 	int retval;
 	int index;
@@ -845,26 +845,16 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 		retval = PTR_ERR(dentry);
 		goto err_release;
 	}
-	/* We need to cache a fake path for TIOCGPTPEER. */
-	pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
-	if (!pts_path)
-		goto err_release;
-	pts_path->mnt = filp->f_path.mnt;
-	pts_path->dentry = dentry;
-	path_get(pts_path);
-	tty->link->driver_data = pts_path;
+	tty->link->driver_data = dentry;
 
 	retval = ptm_driver->ops->open(tty, filp);
 	if (retval)
-		goto err_path_put;
+		goto err_release;
 
 	tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
 
 	tty_unlock(tty);
 	return 0;
-err_path_put:
-	path_put(pts_path);
-	kfree(pts_path);
 err_release:
 	tty_unlock(tty);
 	// This will also put-ref the fsi
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 974b13d24401..ba3371449a5c 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2518,6 +2518,9 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case TIOCSSERIAL:
 		tty_warn_deprecated_flags(p);
 		break;
+	case TIOCGPTPEER:
+		retval = ptm_open_peer(file, tty, (int)arg);
+		break;
 	default:
 		retval = tty_jobctrl_ioctl(tty, real_tty, file, cmd, arg);
 		if (retval != -ENOIOCTLCMD)
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 108df2e3602c..8ed105a22de3 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -133,6 +133,48 @@ static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
+static int devpts_ptmx_path(struct path *path)
+{
+	int err;
+	struct super_block *sb;
+
+	/* Has the devpts filesystem already been found? */
+	sb = path->mnt->mnt_sb;
+	if (sb->s_magic == DEVPTS_SUPER_MAGIC)
+		return 0;
+
+	/* Is a devpts filesystem at "pts" in the same directory? */
+	err = path_pts(path);
+	if (err)
+		return err;
+
+	sb = path->mnt->mnt_sb;
+
+	/* Is the path the root of a devpts filesystem? */
+	if ((sb->s_magic != DEVPTS_SUPER_MAGIC) ||
+	    (path->mnt->mnt_root != sb->s_root))
+		return -ENODEV;
+
+	return 0;
+}
+
+struct vfsmount *devpts_mnt(struct file *filp)
+{
+	struct path path;
+	int err;
+
+	path = filp->f_path;
+	path_get(&path);
+
+	err = devpts_ptmx_path(&path);
+	if (err) {
+		mntput(path.mnt);
+		path.mnt = ERR_PTR(err);
+	}
+	dput(path.dentry);
+	return path.mnt;
+}
+
 struct pts_fs_info *devpts_acquire(struct file *filp)
 {
 	struct pts_fs_info *result;
@@ -143,27 +185,16 @@ struct pts_fs_info *devpts_acquire(struct file *filp)
 	path = filp->f_path;
 	path_get(&path);
 
-	/* Has the devpts filesystem already been found? */
-	sb = path.mnt->mnt_sb;
-	if (sb->s_magic != DEVPTS_SUPER_MAGIC) {
-		/* Is a devpts filesystem at "pts" in the same directory? */
-		err = path_pts(&path);
-		if (err) {
-			result = ERR_PTR(err);
-			goto out;
-		}
-
-		/* Is the path the root of a devpts filesystem? */
-		result = ERR_PTR(-ENODEV);
-		sb = path.mnt->mnt_sb;
-		if ((sb->s_magic != DEVPTS_SUPER_MAGIC) ||
-		    (path.mnt->mnt_root != sb->s_root))
-			goto out;
+	err = devpts_ptmx_path(&path);
+	if (err) {
+		result = ERR_PTR(err);
+		goto out;
 	}
 
 	/*
 	 * pty code needs to hold extra references in case of last /dev/tty close
 	 */
+	sb = path.mnt->mnt_sb;
 	atomic_inc(&sb->s_active);
 	result = DEVPTS_SB(sb);
 
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
index 277ab9af9ac2..e27c548acfb0 100644
--- a/include/linux/devpts_fs.h
+++ b/include/linux/devpts_fs.h
@@ -19,6 +19,7 @@
 
 struct pts_fs_info;
 
+struct vfsmount *devpts_mnt(struct file *);
 struct pts_fs_info *devpts_acquire(struct file *);
 void devpts_release(struct pts_fs_info *);
 
@@ -32,6 +33,15 @@ void *devpts_get_priv(struct dentry *);
 /* unlink */
 void devpts_pty_kill(struct dentry *);
 
+/* in pty.c */
+int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags);
+
+#else
+static inline int
+ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
+{
+	return -EIO;
+}
 #endif
 
 

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 18:13                                             ` Linus Torvalds
@ 2017-08-24 18:31                                               ` Linus Torvalds
  2017-08-24 18:36                                                 ` Linus Torvalds
  2017-08-24 18:40                                               ` Eric W. Biederman
  1 sibling, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24 18:31 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

On Thu, Aug 24, 2017 at 11:13 AM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> The attached patch should work. It's Eric's original patch with
> various cleanups and fixes.

No, one more bug in there: Eric did

+ case TIOCGPTPEER:
+        retval = ptm_open_peer(file, tty, (int)arg);
+        break;

to call that ptm_open_peer(), but that's bogus. The "break;" will just
cause it to continue with the tty ioctl handling, and result in
-ENOTTY in the end.

So it actually *did* open the slave, but then threw the returned fd value away.

It should just do a "return ptm_open_peer(file, tty, (int)arg);" instead.

                       Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 18:31                                               ` Linus Torvalds
@ 2017-08-24 18:36                                                 ` Linus Torvalds
  2017-08-24 20:24                                                   ` Stefan Lippers-Hollmann
  0 siblings, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24 18:36 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

[-- Attachment #1: Type: text/plain, Size: 431 bytes --]

On Thu, Aug 24, 2017 at 11:31 AM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> It should just do a "return ptm_open_peer(file, tty, (int)arg);" instead.

Here's the actual tested patch. It "WorksForMe(tm)", including the
TIOCGPTPEER ioctl, and also verified that it gets the pathname right
in /proc, which was the original problem.

But I did *not* check that pbuilder is still happy. Stefan?

                  Linus

[-- Attachment #2: patch.diff --]
[-- Type: text/plain, Size: 7299 bytes --]

 drivers/tty/pty.c         | 64 ++++++++++++++++++++---------------------------
 drivers/tty/tty_io.c      |  2 ++
 fs/devpts/inode.c         | 63 ++++++++++++++++++++++++++++++++++------------
 include/linux/devpts_fs.h | 10 ++++++++
 4 files changed, 86 insertions(+), 53 deletions(-)

diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 284749fb0f6b..bfd66fcff7a3 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -69,13 +69,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
 #ifdef CONFIG_UNIX98_PTYS
 		if (tty->driver == ptm_driver) {
 			mutex_lock(&devpts_mutex);
-			if (tty->link->driver_data) {
-				struct path *path = tty->link->driver_data;
-
-				devpts_pty_kill(path->dentry);
-				path_put(path);
-				kfree(path);
-			}
+			if (tty->link->driver_data)
+				devpts_pty_kill(tty->link->driver_data);
 			mutex_unlock(&devpts_mutex);
 		}
 #endif
@@ -607,25 +602,24 @@ static inline void legacy_pty_init(void) { }
 static struct cdev ptmx_cdev;
 
 /**
- *	pty_open_peer - open the peer of a pty
- *	@tty: the peer of the pty being opened
+ *	ptm_open_peer - open the peer of a pty
+ *	@master: the open struct file of the ptmx device node
+ *	@tty: the master of the pty being opened
+ *	@flags: the flags for open
  *
- *	Open the cached dentry in tty->link, providing a safe way for userspace
- *	to get the slave end of a pty (where they have the master fd and cannot
- *	access or trust the mount namespace /dev/pts was mounted inside).
+ *	Provide a race free way for userspace to open the slave end of a pty
+ *	(where they have the master fd and cannot access or trust the mount
+ *	namespace /dev/pts was mounted inside).
  */
-static struct file *pty_open_peer(struct tty_struct *tty, int flags)
-{
-	if (tty->driver->subtype != PTY_TYPE_MASTER)
-		return ERR_PTR(-EIO);
-	return dentry_open(tty->link->driver_data, flags, current_cred());
-}
-
-static int pty_get_peer(struct tty_struct *tty, int flags)
+int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
 {
 	int fd = -1;
-	struct file *filp = NULL;
+	struct file *filp;
 	int retval = -EINVAL;
+	struct path path;
+
+	if (tty->driver != ptm_driver)
+		return -EIO;
 
 	fd = get_unused_fd_flags(0);
 	if (fd < 0) {
@@ -633,7 +627,16 @@ static int pty_get_peer(struct tty_struct *tty, int flags)
 		goto err;
 	}
 
-	filp = pty_open_peer(tty, flags);
+	/* Compute the slave's path */
+	path.mnt = devpts_mnt(master);
+	if (IS_ERR(path.mnt)) {
+		retval = PTR_ERR(path.mnt);
+		goto err_put;
+	}
+	path.dentry = tty->link->driver_data;
+
+	filp = dentry_open(&path, flags, current_cred());
+	mntput(path.mnt);
 	if (IS_ERR(filp)) {
 		retval = PTR_ERR(filp);
 		goto err_put;
@@ -662,8 +665,6 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
 		return pty_get_pktmode(tty, (int __user *)arg);
 	case TIOCGPTN: /* Get PT Number */
 		return put_user(tty->index, (unsigned int __user *)arg);
-	case TIOCGPTPEER: /* Open the other end */
-		return pty_get_peer(tty, (int) arg);
 	case TIOCSIG:    /* Send signal to other side of pty */
 		return pty_signal(tty, (int) arg);
 	}
@@ -791,7 +792,6 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 {
 	struct pts_fs_info *fsi;
 	struct tty_struct *tty;
-	struct path *pts_path;
 	struct dentry *dentry;
 	int retval;
 	int index;
@@ -845,26 +845,16 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 		retval = PTR_ERR(dentry);
 		goto err_release;
 	}
-	/* We need to cache a fake path for TIOCGPTPEER. */
-	pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
-	if (!pts_path)
-		goto err_release;
-	pts_path->mnt = filp->f_path.mnt;
-	pts_path->dentry = dentry;
-	path_get(pts_path);
-	tty->link->driver_data = pts_path;
+	tty->link->driver_data = dentry;
 
 	retval = ptm_driver->ops->open(tty, filp);
 	if (retval)
-		goto err_path_put;
+		goto err_release;
 
 	tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
 
 	tty_unlock(tty);
 	return 0;
-err_path_put:
-	path_put(pts_path);
-	kfree(pts_path);
 err_release:
 	tty_unlock(tty);
 	// This will also put-ref the fsi
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 974b13d24401..18be15fc3e18 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2518,6 +2518,8 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case TIOCSSERIAL:
 		tty_warn_deprecated_flags(p);
 		break;
+	case TIOCGPTPEER:
+		return ptm_open_peer(file, tty, (int)arg);
 	default:
 		retval = tty_jobctrl_ioctl(tty, real_tty, file, cmd, arg);
 		if (retval != -ENOIOCTLCMD)
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 108df2e3602c..8ed105a22de3 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -133,6 +133,48 @@ static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
+static int devpts_ptmx_path(struct path *path)
+{
+	int err;
+	struct super_block *sb;
+
+	/* Has the devpts filesystem already been found? */
+	sb = path->mnt->mnt_sb;
+	if (sb->s_magic == DEVPTS_SUPER_MAGIC)
+		return 0;
+
+	/* Is a devpts filesystem at "pts" in the same directory? */
+	err = path_pts(path);
+	if (err)
+		return err;
+
+	sb = path->mnt->mnt_sb;
+
+	/* Is the path the root of a devpts filesystem? */
+	if ((sb->s_magic != DEVPTS_SUPER_MAGIC) ||
+	    (path->mnt->mnt_root != sb->s_root))
+		return -ENODEV;
+
+	return 0;
+}
+
+struct vfsmount *devpts_mnt(struct file *filp)
+{
+	struct path path;
+	int err;
+
+	path = filp->f_path;
+	path_get(&path);
+
+	err = devpts_ptmx_path(&path);
+	if (err) {
+		mntput(path.mnt);
+		path.mnt = ERR_PTR(err);
+	}
+	dput(path.dentry);
+	return path.mnt;
+}
+
 struct pts_fs_info *devpts_acquire(struct file *filp)
 {
 	struct pts_fs_info *result;
@@ -143,27 +185,16 @@ struct pts_fs_info *devpts_acquire(struct file *filp)
 	path = filp->f_path;
 	path_get(&path);
 
-	/* Has the devpts filesystem already been found? */
-	sb = path.mnt->mnt_sb;
-	if (sb->s_magic != DEVPTS_SUPER_MAGIC) {
-		/* Is a devpts filesystem at "pts" in the same directory? */
-		err = path_pts(&path);
-		if (err) {
-			result = ERR_PTR(err);
-			goto out;
-		}
-
-		/* Is the path the root of a devpts filesystem? */
-		result = ERR_PTR(-ENODEV);
-		sb = path.mnt->mnt_sb;
-		if ((sb->s_magic != DEVPTS_SUPER_MAGIC) ||
-		    (path.mnt->mnt_root != sb->s_root))
-			goto out;
+	err = devpts_ptmx_path(&path);
+	if (err) {
+		result = ERR_PTR(err);
+		goto out;
 	}
 
 	/*
 	 * pty code needs to hold extra references in case of last /dev/tty close
 	 */
+	sb = path.mnt->mnt_sb;
 	atomic_inc(&sb->s_active);
 	result = DEVPTS_SB(sb);
 
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
index 277ab9af9ac2..e27c548acfb0 100644
--- a/include/linux/devpts_fs.h
+++ b/include/linux/devpts_fs.h
@@ -19,6 +19,7 @@
 
 struct pts_fs_info;
 
+struct vfsmount *devpts_mnt(struct file *);
 struct pts_fs_info *devpts_acquire(struct file *);
 void devpts_release(struct pts_fs_info *);
 
@@ -32,6 +33,15 @@ void *devpts_get_priv(struct dentry *);
 /* unlink */
 void devpts_pty_kill(struct dentry *);
 
+/* in pty.c */
+int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags);
+
+#else
+static inline int
+ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
+{
+	return -EIO;
+}
 #endif
 
 

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 18:13                                             ` Linus Torvalds
  2017-08-24 18:31                                               ` Linus Torvalds
@ 2017-08-24 18:40                                               ` Eric W. Biederman
  2017-08-24 18:51                                                 ` Linus Torvalds
       [not found]                                                 ` <CAPP7u0WHqDfxTW6hmc=DsmHuoALZcrWdU-Odu=FfoTX26SGHQg@mail.gmail.com>
  1 sibling, 2 replies; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-24 18:40 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Thu, Aug 24, 2017 at 11:06 AM, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
>>
>> But that still fails the TIOCGPTPEER ioctl with an NULL pointer
>> dereference in devpts_mnt,  I probably messed up when I fixed the
>> dentry refcount leak.
>
> No, that was another bug in the original patch.
>
> ptm_open_peer() passed in 'filp' to devpts_mnt(), but it should
> obviously pass in the 'master' one.
>
> filp is NULL at that point.
>
> The attached patch should work. It's Eric's original patch with
> various cleanups and fixes.

It still retains two of my bugs.  I forgot to return from ioctl in
tty_io.c without which the return code is lost.  I failed to verify
that the devpts filesystem we find via path lookup is the same one
that was found when /dev/ptmx was opened.

Here is my tested version of the patch.

It survives light testing here.

Eric


From: "Eric W. Biederman" <ebiederm@xmission.com>
Date: Thu, 24 Aug 2017 10:55:19 -0500
Subject: [PATCH] pty: Repair TIOCGPTPEER

The implementation of TIOCGPTPEER has two issues.

When /dev/ptmx (as opposed to /dev/pts/ptmx) is opened the wrong
vfsmount is passed to dentry_open.  Which results in the kernel displaying
the wrong pathname for the peer.

The second is simply by caching the vfsmount and dentry of the peer it leaves
them open, in a way they were not previously Which because of the inreased
reference counts can cause unnecessary behaviour differences resulting in
regressions.

To fix these move the ioctl into tty_io.c at a generic level allowing
the ioctl to have access to the struct file on which the ioctl is
being called.  This allows the path of the slave to be derived when
opening the slave through TIOCGPTPEER instead of requiring the path to
the slave be cached.  Thus removing the need for caching the path.

A new function devpts_ptmx_path is factored out of devpts_acquire and
used to implement a function devpts_mntget.   The new function devpts_mntget
takes a filp to perform the lookup on and fsi so that it can confirm
that the superblock that is found by devpts_ptmx_path is the proper superblock.

Fixes: 54ebbfb16034 ("tty: add TIOCGPTPEER ioctl")
Reported-by: Christian Brauner <christian.brauner@canonical.com>
Reported-by: Stefan Lippers-Hollmann <s.l-h@gmx.de>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
---
 drivers/tty/pty.c         | 62 +++++++++++++++++++--------------------------
 drivers/tty/tty_io.c      |  3 +++
 fs/devpts/inode.c         | 64 ++++++++++++++++++++++++++++++++++++-----------
 include/linux/devpts_fs.h | 10 ++++++++
 4 files changed, 89 insertions(+), 50 deletions(-)

diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 284749fb0f6b..3856bd228fa9 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -69,13 +69,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
 #ifdef CONFIG_UNIX98_PTYS
 		if (tty->driver == ptm_driver) {
 			mutex_lock(&devpts_mutex);
-			if (tty->link->driver_data) {
-				struct path *path = tty->link->driver_data;
-
-				devpts_pty_kill(path->dentry);
-				path_put(path);
-				kfree(path);
-			}
+			if (tty->link->driver_data)
+				devpts_pty_kill(tty->link->driver_data);
 			mutex_unlock(&devpts_mutex);
 		}
 #endif
@@ -607,25 +602,24 @@ static inline void legacy_pty_init(void) { }
 static struct cdev ptmx_cdev;
 
 /**
- *	pty_open_peer - open the peer of a pty
- *	@tty: the peer of the pty being opened
+ *	ptm_open_peer - open the peer of a pty
+ *	@master: the open struct file of the ptmx device node
+ *	@tty: the master of the pty being opened
+ *	@flags: the flags for open
  *
- *	Open the cached dentry in tty->link, providing a safe way for userspace
- *	to get the slave end of a pty (where they have the master fd and cannot
- *	access or trust the mount namespace /dev/pts was mounted inside).
+ *	Provide a race free way for userspace to open the slave end of a pty
+ *	(where they have the master fd and cannot access or trust the mount
+ *	namespace /dev/pts was mounted inside).
  */
-static struct file *pty_open_peer(struct tty_struct *tty, int flags)
-{
-	if (tty->driver->subtype != PTY_TYPE_MASTER)
-		return ERR_PTR(-EIO);
-	return dentry_open(tty->link->driver_data, flags, current_cred());
-}
-
-static int pty_get_peer(struct tty_struct *tty, int flags)
+int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
 {
 	int fd = -1;
 	struct file *filp = NULL;
 	int retval = -EINVAL;
+	struct path path;
+
+	if (tty->driver != ptm_driver)
+		return -EIO;
 
 	fd = get_unused_fd_flags(0);
 	if (fd < 0) {
@@ -633,7 +627,16 @@ static int pty_get_peer(struct tty_struct *tty, int flags)
 		goto err;
 	}
 
-	filp = pty_open_peer(tty, flags);
+	/* Compute the slave's path */
+	path.mnt = devpts_mntget(master, tty->driver_data);
+	if (IS_ERR(path.mnt)) {
+		retval = PTR_ERR(path.mnt);
+		goto err_put;
+	}
+	path.dentry = tty->link->driver_data;
+
+	filp = dentry_open(&path, flags, current_cred());
+	mntput(path.mnt);
 	if (IS_ERR(filp)) {
 		retval = PTR_ERR(filp);
 		goto err_put;
@@ -662,8 +665,6 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
 		return pty_get_pktmode(tty, (int __user *)arg);
 	case TIOCGPTN: /* Get PT Number */
 		return put_user(tty->index, (unsigned int __user *)arg);
-	case TIOCGPTPEER: /* Open the other end */
-		return pty_get_peer(tty, (int) arg);
 	case TIOCSIG:    /* Send signal to other side of pty */
 		return pty_signal(tty, (int) arg);
 	}
@@ -791,7 +792,6 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 {
 	struct pts_fs_info *fsi;
 	struct tty_struct *tty;
-	struct path *pts_path;
 	struct dentry *dentry;
 	int retval;
 	int index;
@@ -845,26 +845,16 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 		retval = PTR_ERR(dentry);
 		goto err_release;
 	}
-	/* We need to cache a fake path for TIOCGPTPEER. */
-	pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
-	if (!pts_path)
-		goto err_release;
-	pts_path->mnt = filp->f_path.mnt;
-	pts_path->dentry = dentry;
-	path_get(pts_path);
-	tty->link->driver_data = pts_path;
+	tty->link->driver_data = dentry;
 
 	retval = ptm_driver->ops->open(tty, filp);
 	if (retval)
-		goto err_path_put;
+		goto err_release;
 
 	tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
 
 	tty_unlock(tty);
 	return 0;
-err_path_put:
-	path_put(pts_path);
-	kfree(pts_path);
 err_release:
 	tty_unlock(tty);
 	// This will also put-ref the fsi
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 974b13d24401..10c4038c0e8d 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2518,6 +2518,9 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case TIOCSSERIAL:
 		tty_warn_deprecated_flags(p);
 		break;
+	case TIOCGPTPEER:
+		/* Special because the struct file is needed */
+		return ptm_open_peer(file, tty, (int)arg);
 	default:
 		retval = tty_jobctrl_ioctl(tty, real_tty, file, cmd, arg);
 		if (retval != -ENOIOCTLCMD)
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 108df2e3602c..809da242a452 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -133,37 +133,73 @@ static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
-struct pts_fs_info *devpts_acquire(struct file *filp)
+static int devpts_ptmx_path(struct path *path)
 {
-	struct pts_fs_info *result;
-	struct path path;
 	struct super_block *sb;
 	int err;
 
-	path = filp->f_path;
-	path_get(&path);
-
 	/* Has the devpts filesystem already been found? */
-	sb = path.mnt->mnt_sb;
+	sb = path->mnt->mnt_sb;
 	if (sb->s_magic != DEVPTS_SUPER_MAGIC) {
 		/* Is a devpts filesystem at "pts" in the same directory? */
-		err = path_pts(&path);
-		if (err) {
-			result = ERR_PTR(err);
+		err = path_pts(path);
+		if (err)
 			goto out;
-		}
 
 		/* Is the path the root of a devpts filesystem? */
-		result = ERR_PTR(-ENODEV);
-		sb = path.mnt->mnt_sb;
+		err = -ENODEV;
+		sb = path->mnt->mnt_sb;
 		if ((sb->s_magic != DEVPTS_SUPER_MAGIC) ||
-		    (path.mnt->mnt_root != sb->s_root))
+		    (path->mnt->mnt_root != sb->s_root))
 			goto out;
 	}
 
+	err = 0;
+out:
+	return err;
+}
+
+struct vfsmount *devpts_mntget(struct file *filp, struct pts_fs_info *fsi)
+{
+	struct path path;
+	int err;
+
+	path = filp->f_path;
+	path_get(&path);
+
+	err = devpts_ptmx_path(&path);
+	dput(path.dentry);
+	if (err) {
+		mntput(path.mnt);
+		path.mnt = ERR_PTR(err);
+	}
+	if (DEVPTS_SB(path.mnt->mnt_sb) != fsi) {
+		mntput(path.mnt);
+		path.mnt = ERR_PTR(-ENODEV);
+	}
+	return path.mnt;
+}
+
+struct pts_fs_info *devpts_acquire(struct file *filp)
+{
+	struct pts_fs_info *result;
+	struct path path;
+	struct super_block *sb;
+	int err;
+
+	path = filp->f_path;
+	path_get(&path);
+
+	err = devpts_ptmx_path(&path);
+	if (err) {
+		result = ERR_PTR(err);
+		goto out;
+	}
+
 	/*
 	 * pty code needs to hold extra references in case of last /dev/tty close
 	 */
+	sb = path.mnt->mnt_sb;
 	atomic_inc(&sb->s_active);
 	result = DEVPTS_SB(sb);
 
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
index 277ab9af9ac2..100cb4343763 100644
--- a/include/linux/devpts_fs.h
+++ b/include/linux/devpts_fs.h
@@ -19,6 +19,7 @@
 
 struct pts_fs_info;
 
+struct vfsmount *devpts_mntget(struct file *, struct pts_fs_info *);
 struct pts_fs_info *devpts_acquire(struct file *);
 void devpts_release(struct pts_fs_info *);
 
@@ -32,6 +33,15 @@ void *devpts_get_priv(struct dentry *);
 /* unlink */
 void devpts_pty_kill(struct dentry *);
 
+/* in pty.c */
+int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags);
+
+#else
+static inline int
+ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
+{
+	return -EIO;
+}
 #endif
 
 
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 18:40                                               ` Eric W. Biederman
@ 2017-08-24 18:51                                                 ` Linus Torvalds
  2017-08-24 19:23                                                   ` Eric W. Biederman
  2017-08-24 20:13                                                   ` [PATCH v3] pty: Repair TIOCGPTPEER Eric W. Biederman
       [not found]                                                 ` <CAPP7u0WHqDfxTW6hmc=DsmHuoALZcrWdU-Odu=FfoTX26SGHQg@mail.gmail.com>
  1 sibling, 2 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24 18:51 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

On Thu, Aug 24, 2017 at 11:40 AM, Eric W. Biederman
<ebiederm@xmission.com> wrote:
>
> Here is my tested version of the patch.

Can you please take my cleanups to devpts_ptmx_path() too?

Those 'goto err' statements are disgusting, when a plain 'return
-ERRNO' works cleaner.

And that "struct file *filp = NULL;" is bogus - you added the NULL
initialization because you mis-used "filp" early, and with that fixed
it's just garbage.

Other than that, it looks fine to me.

                Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
       [not found]                                                 ` <CAPP7u0WHqDfxTW6hmc=DsmHuoALZcrWdU-Odu=FfoTX26SGHQg@mail.gmail.com>
@ 2017-08-24 19:22                                                   ` Linus Torvalds
  2017-08-24 19:25                                                     ` Linus Torvalds
  2017-08-24 20:43                                                     ` Eric W. Biederman
  2017-08-24 19:48                                                   ` Eric W. Biederman
  1 sibling, 2 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24 19:22 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Eric W. Biederman, Al Viro, Serge Hallyn,
	Stefan Lippers-Hollmann, Christian Brauner, Thorsten Leemhuis,
	Linux Kernel Mailing List

On Thu, Aug 24, 2017 at 12:01 PM, Christian Brauner
<christian.brauner@canonical.com> wrote:
>
> I've touched on this in my original message, I wonder whether we currently
> support  mounting  devpts at a different  a location and expect an open on a
> newly created slave to work.

Yes. That is very much intended to work.

> Say I mount devpts at /mnt and to open("/mnt/ptmx", O_RDWR | O_NOCTTY) and get a new slave pty at /mnt/1 do we
> expect open("/mnt/1, O_RDWR | O_NOCTTY) to work?

Yes.

Except you actually don't want to use "/mnt/ptmx". That ptmx node
inside the pts filesystem is garbage that we never actually used,
because the permissions aren't sane. It should probably be removed,
but because somebody *might* have used it, we have left it alone.

So what you're actually *supposed* to do is

 - create a ptmx node and a pts directory in /mnt

 - mount devpts on /mnt/pts

 - use /mnt/ptmx to create new pty's, which should just look up that
pts mount directly.

And yes, the pathname should then be /mnt/pts/X for the slave side,
and /mnt/ptmx for the master.

In fact, I just tested that TIOCGPTPEER, including using your original
test-program (this is me as root in my home directory):

  [root@i7 torvalds]# mkdir dummy
  [root@i7 torvalds]# cd dummy/
  [root@i7 dummy]# mknod ptmx c 5 2
  [root@i7 dummy]# mkdir pts
  [root@i7 dummy]# mount -t devpts devpts pts
  [root@i7 dummy]# ../a.out
  I point to "/home/torvalds/dummy/pts/0"
  [root@i7 dummy]# umount pts/
  [root@i7 dummy]# cd ..
  [root@i7 torvalds]# rm -rf dummy

There's two things to note there:

 - look at that "I point to" - it's not hardcoded to /dev/pts/X

 - look at the pts number: each pts filesystem has its own private
numbers, so despite the fact that in another window I *also* have that
ptx/0:

        [torvalds@i7 linux]$ tty
        /dev/pts/0

    that new devpts instance has its *own* pts/0, which is a
completely different pty.

this is one of those big cleanups we did with the pts filesystem some time ago.

               Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 18:51                                                 ` Linus Torvalds
@ 2017-08-24 19:23                                                   ` Eric W. Biederman
  2017-08-24 20:13                                                   ` [PATCH v3] pty: Repair TIOCGPTPEER Eric W. Biederman
  1 sibling, 0 replies; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-24 19:23 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Thu, Aug 24, 2017 at 11:40 AM, Eric W. Biederman
> <ebiederm@xmission.com> wrote:
>>
>> Here is my tested version of the patch.
>
> Can you please take my cleanups to devpts_ptmx_path() too?

Let met take a look.  

> Those 'goto err' statements are disgusting, when a plain 'return
> -ERRNO' works cleaner.

Yes those look like good cleanups.  I had tried to preserve the original
logic in devpts_ptmx_path from devpts_acquire to make it easier to
see if I had goofed.   But that out and out failed so cleanups
so the code is easier to read look like a very good thing.

> And that "struct file *filp = NULL;" is bogus - you added the NULL
> initialization because you mis-used "filp" early, and with that fixed
> it's just garbage.

Actually the NULL initialization is a hold over from the original
version of that function.  But I agree without it gcc could have
caught my use of the wrong variable, so removing it looks like a good
idea.

> Other than that, it looks fine to me.

Thanks.  I will respin and retest and see where things are at.

Eric

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 19:22                                                   ` [PATCH 0/1] devpts: use dynamic_dname() to generate proc name Linus Torvalds
@ 2017-08-24 19:25                                                     ` Linus Torvalds
  2017-08-24 20:43                                                     ` Eric W. Biederman
  1 sibling, 0 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24 19:25 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Eric W. Biederman, Al Viro, Serge Hallyn,
	Stefan Lippers-Hollmann, Christian Brauner, Thorsten Leemhuis,
	Linux Kernel Mailing List

On Thu, Aug 24, 2017 at 12:22 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>   [root@i7 dummy]# ../a.out
>   I point to "/home/torvalds/dummy/pts/0"

Note: that "a.out" binary is modified from  your original code.

It's modified to correctly print out the readdir() results, but it's
also modified to open just "ptmx" for the above trial (so it doesn't
open /dev/ptmx, it's opening that ptmx node in the current directory,
which is why it then reports that

   I point to "/home/torvalds/dummy/pts/0"

thing.

So it's not your *original* test-program, it's slightly tweaked for this test.

          Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
       [not found]                                                 ` <CAPP7u0WHqDfxTW6hmc=DsmHuoALZcrWdU-Odu=FfoTX26SGHQg@mail.gmail.com>
  2017-08-24 19:22                                                   ` [PATCH 0/1] devpts: use dynamic_dname() to generate proc name Linus Torvalds
@ 2017-08-24 19:48                                                   ` Eric W. Biederman
  1 sibling, 0 replies; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-24 19:48 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Al Viro, Serge Hallyn, Stefan Lippers-Hollmann,
	Christian Brauner, Thorsten Leemhuis, Linux Kernel Mailing List,
	Linus Torvalds

Christian Brauner <christian.brauner@canonical.com> writes:

> On Aug 24, 2017 20:41, "Eric W. Biederman" <ebiederm@xmission.com> wrote:
>
> > The implementation of TIOCGPTPEER has two issues.
> >
> > When /dev/ptmx (as opposed to 
>
> I've touched on this in my original message, I wonder whether we
> currently support mounting devpts at a different a location and expect
> an open on a newly created slave to work. Say I mount devpts at /mnt
> and to open("/mnt/ptmx", O_RDWR | O_NOCTTY) and get a new slave pty at
> /mnt/1 do we expect open("/mnt/1, O_RDWR | O_NOCTTY) to work?

Yes.

In particular one of my crazy test cases when I did the last round
of cleanups to devpts was someone had created a chroot including
a /dev/ptmx device node and mounted devpts at the appropriate path
inside the chroot.  Which is in part why /dev/ptmx does a relative
lookup of the devpts filesystem.

Now glibc won't work with devpts mounted somewhere else.  As it has
/dev/pts/... hardcoded.  But the kernel should work fine.  The case you
described using /mnt/ptmx instead of a random /dev/ptmx device now
should work especially well as none of this crazy relative path lookup
work needs to happen.

There are little things such as TIOCSPTLCK and perhaps chmod that need
to be called in your example before the slave open will succeed (without
O_PATH) but yes that case most definitely should work.

Eric

^ permalink raw reply	[flat|nested] 55+ messages in thread

* [PATCH v3] pty: Repair TIOCGPTPEER
  2017-08-24 18:51                                                 ` Linus Torvalds
  2017-08-24 19:23                                                   ` Eric W. Biederman
@ 2017-08-24 20:13                                                   ` Eric W. Biederman
  2017-08-24 21:01                                                     ` Stefan Lippers-Hollmann
  1 sibling, 1 reply; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-24 20:13 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Stefan Lippers-Hollmann, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis


The implementation of TIOCGPTPEER has two issues.

When /dev/ptmx (as opposed to /dev/pts/ptmx) is opened the wrong
vfsmount is passed to dentry_open.  Which results in the kernel displaying
the wrong pathname for the peer.

The second is simply by caching the vfsmount and dentry of the peer it leaves
them open, in a way they were not previously Which because of the inreased
reference counts can cause unnecessary behaviour differences resulting in
regressions.

To fix these move the ioctl into tty_io.c at a generic level allowing
the ioctl to have access to the struct file on which the ioctl is
being called.  This allows the path of the slave to be derived when
opening the slave through TIOCGPTPEER instead of requiring the path to
the slave be cached.  Thus removing the need for caching the path.

A new function devpts_ptmx_path is factored out of devpts_acquire and
used to implement a function devpts_mntget.   The new function devpts_mntget
takes a filp to perform the lookup on and fsi so that it can confirm
that the superblock that is found by devpts_ptmx_path is the proper superblock.

v2: Lots of fixes to make the code actually work
v3: Suggestions by Linus
    - Removed the unnecessary initialization of filp in ptm_open_peer
    - Simplified devpts_ptmx_path as gotos are no longer required

Fixes: 54ebbfb16034 ("tty: add TIOCGPTPEER ioctl")
Reported-by: Christian Brauner <christian.brauner@canonical.com>
Reported-by: Stefan Lippers-Hollmann <s.l-h@gmx.de>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
---
 drivers/tty/pty.c         | 64 ++++++++++++++++++++--------------------------
 drivers/tty/tty_io.c      |  3 +++
 fs/devpts/inode.c         | 65 +++++++++++++++++++++++++++++++++++------------
 include/linux/devpts_fs.h | 10 ++++++++
 4 files changed, 89 insertions(+), 53 deletions(-)

diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 284749fb0f6b..a6d5164c33a9 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -69,13 +69,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
 #ifdef CONFIG_UNIX98_PTYS
 		if (tty->driver == ptm_driver) {
 			mutex_lock(&devpts_mutex);
-			if (tty->link->driver_data) {
-				struct path *path = tty->link->driver_data;
-
-				devpts_pty_kill(path->dentry);
-				path_put(path);
-				kfree(path);
-			}
+			if (tty->link->driver_data)
+				devpts_pty_kill(tty->link->driver_data);
 			mutex_unlock(&devpts_mutex);
 		}
 #endif
@@ -607,25 +602,24 @@ static inline void legacy_pty_init(void) { }
 static struct cdev ptmx_cdev;
 
 /**
- *	pty_open_peer - open the peer of a pty
- *	@tty: the peer of the pty being opened
+ *	ptm_open_peer - open the peer of a pty
+ *	@master: the open struct file of the ptmx device node
+ *	@tty: the master of the pty being opened
+ *	@flags: the flags for open
  *
- *	Open the cached dentry in tty->link, providing a safe way for userspace
- *	to get the slave end of a pty (where they have the master fd and cannot
- *	access or trust the mount namespace /dev/pts was mounted inside).
+ *	Provide a race free way for userspace to open the slave end of a pty
+ *	(where they have the master fd and cannot access or trust the mount
+ *	namespace /dev/pts was mounted inside).
  */
-static struct file *pty_open_peer(struct tty_struct *tty, int flags)
-{
-	if (tty->driver->subtype != PTY_TYPE_MASTER)
-		return ERR_PTR(-EIO);
-	return dentry_open(tty->link->driver_data, flags, current_cred());
-}
-
-static int pty_get_peer(struct tty_struct *tty, int flags)
+int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
 {
 	int fd = -1;
-	struct file *filp = NULL;
+	struct file *filp;
 	int retval = -EINVAL;
+	struct path path;
+
+	if (tty->driver != ptm_driver)
+		return -EIO;
 
 	fd = get_unused_fd_flags(0);
 	if (fd < 0) {
@@ -633,7 +627,16 @@ static int pty_get_peer(struct tty_struct *tty, int flags)
 		goto err;
 	}
 
-	filp = pty_open_peer(tty, flags);
+	/* Compute the slave's path */
+	path.mnt = devpts_mntget(master, tty->driver_data);
+	if (IS_ERR(path.mnt)) {
+		retval = PTR_ERR(path.mnt);
+		goto err_put;
+	}
+	path.dentry = tty->link->driver_data;
+
+	filp = dentry_open(&path, flags, current_cred());
+	mntput(path.mnt);
 	if (IS_ERR(filp)) {
 		retval = PTR_ERR(filp);
 		goto err_put;
@@ -662,8 +665,6 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
 		return pty_get_pktmode(tty, (int __user *)arg);
 	case TIOCGPTN: /* Get PT Number */
 		return put_user(tty->index, (unsigned int __user *)arg);
-	case TIOCGPTPEER: /* Open the other end */
-		return pty_get_peer(tty, (int) arg);
 	case TIOCSIG:    /* Send signal to other side of pty */
 		return pty_signal(tty, (int) arg);
 	}
@@ -791,7 +792,6 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 {
 	struct pts_fs_info *fsi;
 	struct tty_struct *tty;
-	struct path *pts_path;
 	struct dentry *dentry;
 	int retval;
 	int index;
@@ -845,26 +845,16 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 		retval = PTR_ERR(dentry);
 		goto err_release;
 	}
-	/* We need to cache a fake path for TIOCGPTPEER. */
-	pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
-	if (!pts_path)
-		goto err_release;
-	pts_path->mnt = filp->f_path.mnt;
-	pts_path->dentry = dentry;
-	path_get(pts_path);
-	tty->link->driver_data = pts_path;
+	tty->link->driver_data = dentry;
 
 	retval = ptm_driver->ops->open(tty, filp);
 	if (retval)
-		goto err_path_put;
+		goto err_release;
 
 	tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
 
 	tty_unlock(tty);
 	return 0;
-err_path_put:
-	path_put(pts_path);
-	kfree(pts_path);
 err_release:
 	tty_unlock(tty);
 	// This will also put-ref the fsi
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 974b13d24401..10c4038c0e8d 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2518,6 +2518,9 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case TIOCSSERIAL:
 		tty_warn_deprecated_flags(p);
 		break;
+	case TIOCGPTPEER:
+		/* Special because the struct file is needed */
+		return ptm_open_peer(file, tty, (int)arg);
 	default:
 		retval = tty_jobctrl_ioctl(tty, real_tty, file, cmd, arg);
 		if (retval != -ENOIOCTLCMD)
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 108df2e3602c..7eae33ffa3fc 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -133,6 +133,50 @@ static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
+static int devpts_ptmx_path(struct path *path)
+{
+	struct super_block *sb;
+	int err;
+
+	/* Has the devpts filesystem already been found? */
+	if (path->mnt->mnt_sb->s_magic == DEVPTS_SUPER_MAGIC)
+		return 0;
+
+	/* Is a devpts filesystem at "pts" in the same directory? */
+	err = path_pts(path);
+	if (err)
+		return err;
+
+	/* Is the path the root of a devpts filesystem? */
+	sb = path->mnt->mnt_sb;
+	if ((sb->s_magic != DEVPTS_SUPER_MAGIC) ||
+	    (path->mnt->mnt_root != sb->s_root))
+		return -ENODEV;
+
+	return 0;
+}
+
+struct vfsmount *devpts_mntget(struct file *filp, struct pts_fs_info *fsi)
+{
+	struct path path;
+	int err;
+
+	path = filp->f_path;
+	path_get(&path);
+
+	err = devpts_ptmx_path(&path);
+	dput(path.dentry);
+	if (err) {
+		mntput(path.mnt);
+		path.mnt = ERR_PTR(err);
+	}
+	if (DEVPTS_SB(path.mnt->mnt_sb) != fsi) {
+		mntput(path.mnt);
+		path.mnt = ERR_PTR(-ENODEV);
+	}
+	return path.mnt;
+}
+
 struct pts_fs_info *devpts_acquire(struct file *filp)
 {
 	struct pts_fs_info *result;
@@ -143,27 +187,16 @@ struct pts_fs_info *devpts_acquire(struct file *filp)
 	path = filp->f_path;
 	path_get(&path);
 
-	/* Has the devpts filesystem already been found? */
-	sb = path.mnt->mnt_sb;
-	if (sb->s_magic != DEVPTS_SUPER_MAGIC) {
-		/* Is a devpts filesystem at "pts" in the same directory? */
-		err = path_pts(&path);
-		if (err) {
-			result = ERR_PTR(err);
-			goto out;
-		}
-
-		/* Is the path the root of a devpts filesystem? */
-		result = ERR_PTR(-ENODEV);
-		sb = path.mnt->mnt_sb;
-		if ((sb->s_magic != DEVPTS_SUPER_MAGIC) ||
-		    (path.mnt->mnt_root != sb->s_root))
-			goto out;
+	err = devpts_ptmx_path(&path);
+	if (err) {
+		result = ERR_PTR(err);
+		goto out;
 	}
 
 	/*
 	 * pty code needs to hold extra references in case of last /dev/tty close
 	 */
+	sb = path.mnt->mnt_sb;
 	atomic_inc(&sb->s_active);
 	result = DEVPTS_SB(sb);
 
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
index 277ab9af9ac2..100cb4343763 100644
--- a/include/linux/devpts_fs.h
+++ b/include/linux/devpts_fs.h
@@ -19,6 +19,7 @@
 
 struct pts_fs_info;
 
+struct vfsmount *devpts_mntget(struct file *, struct pts_fs_info *);
 struct pts_fs_info *devpts_acquire(struct file *);
 void devpts_release(struct pts_fs_info *);
 
@@ -32,6 +33,15 @@ void *devpts_get_priv(struct dentry *);
 /* unlink */
 void devpts_pty_kill(struct dentry *);
 
+/* in pty.c */
+int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags);
+
+#else
+static inline int
+ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
+{
+	return -EIO;
+}
 #endif
 
 
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 18:36                                                 ` Linus Torvalds
@ 2017-08-24 20:24                                                   ` Stefan Lippers-Hollmann
  2017-08-24 20:27                                                     ` Linus Torvalds
  0 siblings, 1 reply; 55+ messages in thread
From: Stefan Lippers-Hollmann @ 2017-08-24 20:24 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Eric W. Biederman, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

Hi

[ sorry for the re-send, this accidentally only reached you, rather than
 the mailing list and the other recipients as well ]

On 2017-08-24, Linus Torvalds wrote:
> On Thu, Aug 24, 2017 at 11:31 AM, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
> >
> > It should just do a "return ptm_open_peer(file, tty, (int)arg);" instead.  
> 
> Here's the actual tested patch. It "WorksForMe(tm)", including the
> TIOCGPTPEER ioctl, and also verified that it gets the pathname right
> in /proc, which was the original problem.
> 
> But I did *not* check that pbuilder is still happy. Stefan?

This patch seems to work, ssh, xterm (konsole5), real tty and pbuilder
(creating- and updating the build chroots, just as well as building 
several fairly involved packages) are fine with this patch on top of 
v4.13-rc6-66-g143c97cc6529 (tested on x86_64).

Thanks a lot
	Stefan Lippers-Hollmann

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 20:24                                                   ` Stefan Lippers-Hollmann
@ 2017-08-24 20:27                                                     ` Linus Torvalds
  0 siblings, 0 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24 20:27 UTC (permalink / raw)
  To: Stefan Lippers-Hollmann
  Cc: Eric W. Biederman, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

On Thu, Aug 24, 2017 at 1:24 PM, Stefan Lippers-Hollmann <s.l-h@gmx.de> wrote:
>
> This patch seems to work, ssh, xterm (konsole5), real tty and pbuilder
> (creating- and updating the build chroots, just as well as building
> several fairly involved packages) are fine with this patch on top of
> v4.13-rc6-66-g143c97cc6529 (tested on x86_64).

Ok. I just committed Eric's final patch, which is pretty much exactly
the same as what I sent out except with an added verification that the
mount has not changed.

So I marked you as having "Reported-and-tested" it, even if the
version you tested was not 100% identical.

Will push out after the usual final build test,

            Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 19:22                                                   ` [PATCH 0/1] devpts: use dynamic_dname() to generate proc name Linus Torvalds
  2017-08-24 19:25                                                     ` Linus Torvalds
@ 2017-08-24 20:43                                                     ` Eric W. Biederman
  2017-08-24 21:07                                                       ` Linus Torvalds
  1 sibling, 1 reply; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-24 20:43 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Brauner, Al Viro, Serge Hallyn,
	Stefan Lippers-Hollmann, Christian Brauner, Thorsten Leemhuis,
	Linux Kernel Mailing List

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Thu, Aug 24, 2017 at 12:01 PM, Christian Brauner
> <christian.brauner@canonical.com> wrote:
>>
>> I've touched on this in my original message, I wonder whether we currently
>> support  mounting  devpts at a different  a location and expect an open on a
>> newly created slave to work.
>
> Yes. That is very much intended to work.
>
>> Say I mount devpts at /mnt and to open("/mnt/ptmx", O_RDWR | O_NOCTTY) and get a new slave pty at /mnt/1 do we
>> expect open("/mnt/1, O_RDWR | O_NOCTTY) to work?
>
> Yes.
>
> Except you actually don't want to use "/mnt/ptmx". That ptmx node
> inside the pts filesystem is garbage that we never actually used,
> because the permissions aren't sane. It should probably be removed,
> but because somebody *might* have used it, we have left it alone.

The ptmx node on devpts is used.

Use of that device node is way more prevalent then crazy weird cases
that required us to make /dev/ptmx perform relative lookups.  People
just set the ptmxmode= boot parameter when mounting devpts if they care.

Every use case I am aware of where people actually knew about multiple
instances of devpts used the ptmx node in the devpts filesystem.


If everyone used devtmpfs we could have fixed the permissions on the
ptmx node in devpts and made /dev/ptmx a symlink instead of a device
node.   Saving lots of complexity.

Unfortunately there were crazy weird cases out there where people
created chroots or mounted devpts multiple times during boot that
defeated every strategy except making /dev/ptmx perform a relative
lookup for devpts.

The reasons I did not fix the permissions on the ptmx deivcd node was
that given the magnitude of the change needed to get to the sensible
behavior of every mount of devpts creating a new filesystem, any
unnecessary changes were just plain scary.

Further the kind of regression that would be introduced if we changed
the permissions would be a security hole if someone has some really
weird and crazy permissions on /dev/ptmx and does not use devtmpfs.




That said I could not find a distribution being that crazy and I had a
very good sample of them.  So I expect we can fix the default permissions
on ptmx node of devpts and not have anyone notice or care.



I would encourage people who are doing new things to actually use the
ptmx node on devpts because there is less overhead and it is simpler.


There are just enough weird one off scripts like xen image builder (I
think that was the nasty test case that broke in debian) that I can't
imagine ever being able to responsibly remove the path based lookups in
/dev/ptmx.  I do dream of it sometimes.


It might be worth fixing the default permissions on the devpts ptmx node
and updating glibc to try /dev/pts/ptmx first.  That would shave off a
few cycles in opening ptys.  If you add TIOCGPTPEER there are probably
enough cleanups and simplifications that it would be worth it just
for the code improvements.


With glibc fixed we could even dream of a day when /dev/ptmx could be
completely removed.

Eric

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH v3] pty: Repair TIOCGPTPEER
  2017-08-24 20:13                                                   ` [PATCH v3] pty: Repair TIOCGPTPEER Eric W. Biederman
@ 2017-08-24 21:01                                                     ` Stefan Lippers-Hollmann
  0 siblings, 0 replies; 55+ messages in thread
From: Stefan Lippers-Hollmann @ 2017-08-24 21:01 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Linus Torvalds, Christian Brauner, Christian Brauner,
	Linux Kernel Mailing List, Serge E. Hallyn, Al Viro,
	Thorsten Leemhuis

[-- Attachment #1: Type: text/plain, Size: 670 bytes --]

Hi

On 2017-08-24, Eric W. Biederman wrote:
> The implementation of TIOCGPTPEER has two issues.
> 
> When /dev/ptmx (as opposed to /dev/pts/ptmx) is opened the wrong
> vfsmount is passed to dentry_open.  Which results in the kernel displaying
> the wrong pathname for the peer.

[...]

> v2: Lots of fixes to make the code actually work
> v3: Suggestions by Linus
>     - Removed the unnecessary initialization of filp in ptm_open_peer
>     - Simplified devpts_ptmx_path as gotos are no longer required

This version of the patch is working for me as well in all my test
(including pbuilder) so far, thanks a lot.

Regards
	Stefan Lippers-Hollmann

[-- Attachment #2: Digitale Signatur von OpenPGP --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 20:43                                                     ` Eric W. Biederman
@ 2017-08-24 21:07                                                       ` Linus Torvalds
  2017-08-24 23:01                                                         ` Eric W. Biederman
  0 siblings, 1 reply; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24 21:07 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Christian Brauner, Al Viro, Serge Hallyn,
	Stefan Lippers-Hollmann, Christian Brauner, Thorsten Leemhuis,
	Linux Kernel Mailing List

On Thu, Aug 24, 2017 at 1:43 PM, Eric W. Biederman
<ebiederm@xmission.com> wrote:
>
> There are just enough weird one off scripts like xen image builder (I
> think that was the nasty test case that broke in debian) that I can't
> imagine ever being able to responsibly remove the path based lookups in
> /dev/ptmx.  I do dream of it sometimes.

Not going to happen.

The fact is, /dev/ptmx is the simply the standard location.
/dev/pts/ptmx simply is *not*.

So pretty much every single user that ever uses pty's will use
/dev/ptmx, it's just how it has always worked.

Trying to change it to anything else is just stupid. There's no
upside, there is only downsides - mainly the "we'll have to support
the standard way anyway, that newfangled way doesn't add anything".

Our "pts" lookup isn't expensive.

So quite frankly, we should discourage people from using the
non-standard place. It really has no real advantages, and it's simply
not worth it.

               Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 21:07                                                       ` Linus Torvalds
@ 2017-08-24 23:01                                                         ` Eric W. Biederman
  2017-08-24 23:27                                                           ` Linus Torvalds
  2017-08-24 23:37                                                           ` Christian Brauner
  0 siblings, 2 replies; 55+ messages in thread
From: Eric W. Biederman @ 2017-08-24 23:01 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Brauner, Al Viro, Serge Hallyn,
	Stefan Lippers-Hollmann, Christian Brauner, Thorsten Leemhuis,
	Linux Kernel Mailing List

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Thu, Aug 24, 2017 at 1:43 PM, Eric W. Biederman
> <ebiederm@xmission.com> wrote:
>>
>> There are just enough weird one off scripts like xen image builder (I
>> think that was the nasty test case that broke in debian) that I can't
>> imagine ever being able to responsibly remove the path based lookups in
>> /dev/ptmx.  I do dream of it sometimes.
>
> Not going to happen.

Which is what I said.

> The fact is, /dev/ptmx is the simply the standard location.
> /dev/pts/ptmx simply is *not*.

The standard is posix_openpt().  That is a syscall on the bsds.
Opening something called ptmx at this point is a Linuxism.

There are a lot of programs that are going to be calling posix_openpt()
simply because /dev/ptmx can not be counted on to exist.

> So pretty much every single user that ever uses pty's will use
> /dev/ptmx, it's just how it has always worked.
>
> Trying to change it to anything else is just stupid. There's no
> upside, there is only downsides - mainly the "we'll have to support
> the standard way anyway, that newfangled way doesn't add anything".

Except the new fangled way does add quite a bit.  Not everyone who
mounts devpts has permission to call mknod.  So /dev/ptmx frequently
winds up either being a bind mount or a symlink to /dev/pts/ptmx in
containers.

It is going to take a long time but device nodes like one of those
filesystem features thare are very slowly on their way out.

> Our "pts" lookup isn't expensive.
>
> So quite frankly, we should discourage people from using the
> non-standard place. It really has no real advantages, and it's simply
> not worth it.

The "pts" lookup admitted isn't runtime expensive.  I could propbably
measure a cost but anyone who is creating ptys fast enough to care
likely has other issues.

The "pts" lookup does have some real maintenance costs as it takes
someone with a pretty deep understanding of things to figure out what is
going on.  I hope things have finally been abstracted well enough, and
the code is used heavily enough we don't have to worry about a
regression there.   I still worry.

As for non-standard locations.  Anything that isn't /dev/ptmx and
/dev/pts/NNN simply won't work for anything isn't very specialized.
At which point I don't think there is any reason to skip using the ptmx
node on the devpts filesystem as you have already given up compatibility
with everything else.

But I agree it doesn't look worth it to change glibc to deal with an
alternate location for /dev/ptmx.  I see a huge point in changing glibc
to use the new TIOCGPTPEER ioctl when available as that is really the
functionality the glibc internals are after.

Eric

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 23:01                                                         ` Eric W. Biederman
@ 2017-08-24 23:27                                                           ` Linus Torvalds
  2017-08-24 23:37                                                           ` Christian Brauner
  1 sibling, 0 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-24 23:27 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Christian Brauner, Al Viro, Serge Hallyn,
	Stefan Lippers-Hollmann, Christian Brauner, Thorsten Leemhuis,
	Linux Kernel Mailing List

On Thu, Aug 24, 2017 at 4:01 PM, Eric W. Biederman
<ebiederm@xmission.com> wrote:
> Linus Torvalds <torvalds@linux-foundation.org> writes:
>
>> On Thu, Aug 24, 2017 at 1:43 PM, Eric W. Biederman
>> <ebiederm@xmission.com> wrote:
>>>
>>> There are just enough weird one off scripts like xen image builder (I
>>> think that was the nasty test case that broke in debian) that I can't
>>> imagine ever being able to responsibly remove the path based lookups in
>>> /dev/ptmx.  I do dream of it sometimes.
>>
>> Not going to happen.
>
> Which is what I said.

Yes, but you then went on to say that we should encourage "/dev/pts/ptmx"

Which is BS.

It's not a standard location, and it doesn't have any advantages.

It was a bad idea and due to a bad implementation. We fixed it. Let it go.

>> The fact is, /dev/ptmx is the simply the standard location.
>> /dev/pts/ptmx simply is *not*.
>
> The standard is posix_openpt().  That is a syscall on the bsds.
> Opening something called ptmx at this point is a Linuxism.

Bzzt. Thank you for playing, but you're completely and utterly wrong.

Look around a bit more.

posix_openpt() may be what you *wish* the standard was, but no,
/dev/ptmx is not a linuxism.

Really. It's the SysV STREAMS standard location, and it is what Sysv
pty users _will_ use directly.

Linux didn't make up that name.

Solaris, HP-UX-11, other sysv code bases all use /dev/ptmx

The whole "posix_openpt()" thing came later, in an attempt to just
unify the BSD and Sysv models.

Just google for "streams pty" if you don't believe me.

So really. The only linuxism here is that stupid /dev/pts/ptmx.

> There are a lot of programs that are going to be calling posix_openpt()
> simply because /dev/ptmx can not be counted on to exist.

.. and there are probably even more programs that simply use
"/dev/ptmx". If you came from a sysv world, or if you just happened to
copy any of the hundreds of examples on the interenet, that's what you
would do.

Christ, just go to Wikipedia. And I quote:

  'BSD PTYs have been rendered obsolete by Unix98 ptys whose naming
   system does not limit the number of pseudo-terminals and access to
   which occurs without danger of race conditions. /dev/ptmx is the
   "pseudo-terminal master multiplexer". Opening it returns a file
   descriptor of a master node and causes an associated slave node
   /dev/pts/N to be created.[5]'

That's from

    https://en.wikipedia.org/wiki/Pseudoterminal

so stop blathering garbage. The fact is, /dev/ptmx is the standard
location, and /dev/pts/ptmx is, and always has been, an abomination.

Now, if you want to be portable, "posix_openpt()" is indeed what you
should use, but that doesn't change the basic point.

There's a very real reason why people use "/dev/ptmx", and no, it's
not a linuxism.

                       Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 23:01                                                         ` Eric W. Biederman
  2017-08-24 23:27                                                           ` Linus Torvalds
@ 2017-08-24 23:37                                                           ` Christian Brauner
  2017-08-26  1:00                                                             ` Linus Torvalds
  1 sibling, 1 reply; 55+ messages in thread
From: Christian Brauner @ 2017-08-24 23:37 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Linus Torvalds, Al Viro, Serge Hallyn, Stefan Lippers-Hollmann,
	Christian Brauner, Thorsten Leemhuis, Linux Kernel Mailing List

On Thu, Aug 24, 2017 at 06:01:36PM -0500, Eric W. Biederman wrote:
> Linus Torvalds <torvalds@linux-foundation.org> writes:
> 
> > On Thu, Aug 24, 2017 at 1:43 PM, Eric W. Biederman
> > <ebiederm@xmission.com> wrote:
> >>
> >> There are just enough weird one off scripts like xen image builder (I
> >> think that was the nasty test case that broke in debian) that I can't
> >> imagine ever being able to responsibly remove the path based lookups in
> >> /dev/ptmx.  I do dream of it sometimes.
> >
> > Not going to happen.
> 
> Which is what I said.
> 
> > The fact is, /dev/ptmx is the simply the standard location.
> > /dev/pts/ptmx simply is *not*.
> 
> The standard is posix_openpt().  That is a syscall on the bsds.
> Opening something called ptmx at this point is a Linuxism.
> 
> There are a lot of programs that are going to be calling posix_openpt()
> simply because /dev/ptmx can not be counted on to exist.
> 
> > So pretty much every single user that ever uses pty's will use
> > /dev/ptmx, it's just how it has always worked.
> >
> > Trying to change it to anything else is just stupid. There's no
> > upside, there is only downsides - mainly the "we'll have to support
> > the standard way anyway, that newfangled way doesn't add anything".
> 
> Except the new fangled way does add quite a bit.  Not everyone who
> mounts devpts has permission to call mknod.  So /dev/ptmx frequently
> winds up either being a bind mount or a symlink to /dev/pts/ptmx in
> containers.

In fact, /dev/ptmx being a symlink or bind-mount is the *standard* in containers
even for non-user namespaced containers or containers that do not retain
CAP_MKNOD.

> 
> It is going to take a long time but device nodes like one of those
> filesystem features thare are very slowly on their way out.

This related to the point above: The fact that we can mount a devpts at its
standard location but are unable to also have/create an additional device node
at the *standard location* is usually quite irritating for people who do not
know about this "legacy" behaviour. But yeah, it's probably going away but
that's going to be a long long time. I agree that userspace is the place to
slowly make the transition though. :)

> 
> > Our "pts" lookup isn't expensive.
> >
> > So quite frankly, we should discourage people from using the
> > non-standard place. It really has no real advantages, and it's simply
> > not worth it.
> 
> The "pts" lookup admitted isn't runtime expensive.  I could propbably
> measure a cost but anyone who is creating ptys fast enough to care
> likely has other issues.
> 
> The "pts" lookup does have some real maintenance costs as it takes
> someone with a pretty deep understanding of things to figure out what is
> going on.  I hope things have finally been abstracted well enough, and
> the code is used heavily enough we don't have to worry about a
> regression there.   I still worry.
> 
> As for non-standard locations.  Anything that isn't /dev/ptmx and
> /dev/pts/NNN simply won't work for anything isn't very specialized.

I was mainly asking about non-standard locations because I experienced weird
behaviour when trying to open("/mnt/<slave-idx", O_RDWR | O_NOCTTY). Mind you I
did all the steps that grantpt() + unlockpt() usually do purely file descriptor
based. But I think this was due to the faulty TIOCGPTPEER implemenation before
which should now be fixed.

> At which point I don't think there is any reason to skip using the ptmx
> node on the devpts filesystem as you have already given up compatibility
> with everything else.
> 
> But I agree it doesn't look worth it to change glibc to deal with an
> alternate location for /dev/ptmx.  I see a huge point in changing glibc
> to use the new TIOCGPTPEER ioctl when available as that is really the
> functionality the glibc internals are after.

That's a patch I've been looking into. But TIOCGPTPEER alone won't be enough. A
couple of other function such as grantpt() need to switch from path-based
operation to file descriptor based operations too (Something I tried to point
out in one of my previous mails.). The whole user-space api could do - imho -
with a redo. The kernel is doing the right thing and exposing the right bits
mostly; TIOCGPTPEER being a good step. But user-space wise it's actually a
little security nightmare as soon as namespaces and - sorry for the buzzword -
*containers* come into play. @Eric, are you going to be at Plumbers again this
year? That's maybe a good chance to discuss some of this if there's still
interest.

Christian

> 
> Eric

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 0/1] devpts: use dynamic_dname() to generate proc name
  2017-08-24 23:37                                                           ` Christian Brauner
@ 2017-08-26  1:00                                                             ` Linus Torvalds
  0 siblings, 0 replies; 55+ messages in thread
From: Linus Torvalds @ 2017-08-26  1:00 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Eric W. Biederman, Al Viro, Serge Hallyn,
	Stefan Lippers-Hollmann, Christian Brauner, Thorsten Leemhuis,
	Linux Kernel Mailing List

On Thu, Aug 24, 2017 at 4:37 PM, Christian Brauner
<christian.brauner@canonical.com> wrote:
>
> In fact, /dev/ptmx being a symlink or bind-mount is the *standard* in containers
> even for non-user namespaced containers or containers that do not retain
> CAP_MKNOD.

Yes.

I think using /dev/pts/ptmx is nice from a kernel standpoint, but I
really think that user space should *never* use it.

The distro or container setup can do whatever it wants to made
/dev/ptmx then point into the pts directory. Either the traditional
device node, the symlink, or the bind mount works fine. But the point
is that glibc definitely should *not* point to /dev/pts/ptmx itself,
because it's simply not the right path. On lots of distributions that
path simply will not work.

And yes, I agree that the user interface to this all is particularly
nasty. With TIOCGPTPEER we have a nice way to get the pts file
descriptor, but the "normal" way to get to it involves opening a path
given by ptsname(), so we en dup in the crazy situation that we can
easily open the file without the path, but then we use the fd to get
the path (that we didn't need) and then people open it with that path,
because the standard sequence to get a pts is

  master = getpt() / posix_openpt() / open("/dev/ptmx", O_RDWR | O_NOCTTY);
  grantpt(master);
  unlockpt(master);
  name = ptsname(master);
  slave = open(name, O_RDWR);

which is kind of silly. And I'm not talking about the three different
ways to open the master side. I'm talking about all the rest, which is
all just pretty much garbage.

But I guess none of this is really performance-critical.

                Linus

^ permalink raw reply	[flat|nested] 55+ messages in thread

end of thread, other threads:[~2017-08-26  1:00 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-16 17:12 [PATCH 0/1] devpts: use dynamic_dname() to generate proc name Christian Brauner
2017-08-16 17:12 ` [PATCH 1/1] " Christian Brauner
2017-08-16 18:26 ` [PATCH 0/1] " Linus Torvalds
2017-08-16 18:48   ` Linus Torvalds
2017-08-16 19:48     ` Christian Brauner
2017-08-16 19:56       ` Linus Torvalds
2017-08-16 20:19         ` Linus Torvalds
2017-08-16 20:30           ` Linus Torvalds
2017-08-16 21:03             ` Linus Torvalds
2017-08-16 21:37               ` Christian Brauner
2017-08-16 21:45                 ` Linus Torvalds
2017-08-16 21:55                   ` Linus Torvalds
2017-08-16 22:05                     ` Christian Brauner
2017-08-16 22:28                   ` Christian Brauner
2017-08-23 15:31                     ` Eric W. Biederman
2017-08-23 21:15                       ` Christian Brauner
2017-08-16 22:46               ` Eric W. Biederman
2017-08-16 22:58                 ` Linus Torvalds
2017-08-16 23:51                   ` Eric W. Biederman
2017-08-17  0:08                     ` Linus Torvalds
2017-08-17  1:24                       ` Eric W. Biederman
2017-08-24  0:24                       ` Stefan Lippers-Hollmann
2017-08-24  0:42                         ` Linus Torvalds
2017-08-24  1:16                           ` Linus Torvalds
2017-08-24  1:25                           ` Eric W. Biederman
2017-08-24  1:32                             ` Linus Torvalds
2017-08-24  1:49                               ` Linus Torvalds
2017-08-24  2:01                                 ` Linus Torvalds
2017-08-24  3:11                                   ` Eric W. Biederman
2017-08-24  3:24                                     ` Linus Torvalds
2017-08-24 15:51                                       ` Eric W. Biederman
2017-08-24  4:24                                     ` Stefan Lippers-Hollmann
2017-08-24 15:54                                       ` Eric W. Biederman
2017-08-24 17:52                                         ` Linus Torvalds
2017-08-24 18:06                                           ` Linus Torvalds
2017-08-24 18:13                                             ` Linus Torvalds
2017-08-24 18:31                                               ` Linus Torvalds
2017-08-24 18:36                                                 ` Linus Torvalds
2017-08-24 20:24                                                   ` Stefan Lippers-Hollmann
2017-08-24 20:27                                                     ` Linus Torvalds
2017-08-24 18:40                                               ` Eric W. Biederman
2017-08-24 18:51                                                 ` Linus Torvalds
2017-08-24 19:23                                                   ` Eric W. Biederman
2017-08-24 20:13                                                   ` [PATCH v3] pty: Repair TIOCGPTPEER Eric W. Biederman
2017-08-24 21:01                                                     ` Stefan Lippers-Hollmann
     [not found]                                                 ` <CAPP7u0WHqDfxTW6hmc=DsmHuoALZcrWdU-Odu=FfoTX26SGHQg@mail.gmail.com>
2017-08-24 19:22                                                   ` [PATCH 0/1] devpts: use dynamic_dname() to generate proc name Linus Torvalds
2017-08-24 19:25                                                     ` Linus Torvalds
2017-08-24 20:43                                                     ` Eric W. Biederman
2017-08-24 21:07                                                       ` Linus Torvalds
2017-08-24 23:01                                                         ` Eric W. Biederman
2017-08-24 23:27                                                           ` Linus Torvalds
2017-08-24 23:37                                                           ` Christian Brauner
2017-08-26  1:00                                                             ` Linus Torvalds
2017-08-24 19:48                                                   ` Eric W. Biederman
2017-08-17  1:37           ` Eric W. Biederman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.