[lxc-devel] User namespaces

Dwight Engen dwight.engen at oracle.com
Fri Mar 1 18:57:02 UTC 2013


On Mon, 25 Feb 2013 20:26:21 -0800
ebiederm at xmission.com (Eric W. Biederman) wrote:

> Dwight Engen <dwight.engen at oracle.com> writes:
> 
> > On Sun, 24 Feb 2013 21:12:59 -0800
> > ebiederm at xmission.com (Eric W. Biederman) wrote:
> >
> >> Serge Hallyn <serge.hallyn at ubuntu.com> writes:
> >> 
> >> > Quoting Dwight Engen (dwight.engen at oracle.com):
> >> >> I finally got around to testing out user namespaces. Very nice
> >> >> to to have container root not be kuid 0! One thing that I
> >> >> noticed was that mingetty in the container was failing because
> >> >> the call to vhangup(2) failed (and thus no lxc-console). I
> >> >> could patch the container to start mingetty with --nohangup,
> >> >> but that feels like a workaround and wouldn't be good when the
> >> >> terminal got reused in the container. Instead I patched my
> >> >> kernel with:
> >> >> 
> >> >> diff --git a/fs/open.c b/fs/open.c
> >> >> index 9b33c0c..7c54d1d7 100644
> >> >> --- a/fs/open.c
> >> >> +++ b/fs/open.c
> >> >> @@ -1059,7 +1059,7 @@ EXPORT_SYMBOL(sys_close);
> >> >>   */
> >> >>  SYSCALL_DEFINE0(vhangup)
> >> >>  {
> >> >> -	if (capable(CAP_SYS_TTY_CONFIG)) {
> >> >> +	if (ns_capable(current_user_ns(), CAP_SYS_TTY_CONFIG))
> >> >> {
> >> >
> >> > Note there is a nsown_capable(CAP_SYS_TTY_CONFIG) shortcut for
> >> > this, but
> >
> > Ahh, I missed that, thanks!
> >
> >> >>  		tty_vhangup_self();
> >> >>  		return 0;
> >> >>  	}
> >> >> 
> >> >> This lets mingetty work, but I'm not so sure it safe to allow a
> >> >> CAP_SYS_TTY_CONFIG capable process in the namespace hangup
> >> >> whatever terminal it might be able to open and get to be its
> >> >> controlling terminal. I guess the terminal would have to be
> >> >> open()able or TIOCSCTTY'able in the container, but is that
> >> >> enough protection? Thoughts?
> >> >
> >> > I don't think nsown_capable() is sufficient here.  Rather, we
> >> > need to check against the user namespace owning
> >> > get_current_tty().  So what is that, the
> >> > get_current_tty()->pgrp->upid[level]->user_ns ? Or can we walk
> >> > over the get_current_tty()->tty_files and see if any of those
> >> > match?
> >
> > I agree I don't think nsown_capable() is enough. I'm not sure what
> > we should be checking though. I don't think we can use pgrp for the
> > same disassociate reason as tty->session below.
> >
> >> > (Eric cc:d as this may be something he's already thought about.)
> >> 
> >> I have not thought about a less than superprivilege revoke.
> >> 
> >> Is this vhangup happening on pseudo-tty acting as /dev/console?
> >
> > Yes, its done on the ptys lxc set up for the
> > container's /dev/console and /dev/tty[1-4].
> >
> >> Part of me really wants to say the answer should be don't do that
> >> then.
> >
> > I think the reason mingetty wants to do the vhangup is still valid
> > in the container case though? ie. it wants to make sure any process
> > that has fds refering to the slave pty from the last login session
> > get set to hung up ops.
> >
> >> Reading the code the current unprivileged uses of tty_vhangup are:
> >> - The pty master closing.
> >> - A session group leader exiting with a controlling tty (that is
> >> not a pty).
> >> 
> >> Which suggests that if you are root in the user namespace of the
> >> session that currently owns the tty it is reasonable to force a
> >> hangup for regulary ttys.  I don't know about ptys.
> >> 
> >> I guess that would require capabilities in
> >> ns_of_pid(tty->session)->user_ns.
> >> 
> >> Being able to kill the process that is the pty master also seems
> >> reasonable.
> >> 
> >> However I don't think either of those really answer the question
> >> for when it is ok send vhangup to a pty whose master lies outside
> >> of the current user namespace.  Which I am pretty certain is the
> >> case in question.
> >
> > What defines which user namespace a pty is in? I guess I'm not sure
> > if the pty master should be considered outside the new user
> > namespace or not. lxc creates the pty pair while in the parent ns,
> > and chowns the slave into a uid in the new user ns. I guess it
> > could fchown the master too, though it doesn't right now. The
> > mingetty attempting vhangup is in the new user ns.
> >
> > ns_of_pid(tty->session)->user_ns is likely also the new user ns,
> > but I think we can't just use that in a ns_capable check because
> > tty->session might be NULL if the the tty has been disassociated as
> > the controlling terminal. I think we need a check that will work
> > even after disassociation since there could still be fds that need
> > hang up.
> 
> For pty's since they only have the single device node.  We can
> probably do kuid_has_mapping and kgid_has_mapping to see if we should
> have super user privileges over the pty.  But that is specific to
> ptys on /dev/pts. Normal devices potentially can have device nodes
> with different permissions in different places so we can't figure out
> an owner for the device.
> 
> Eric
> 

Yeah, I agree we don't want something pty specific. The following patch
assumes we define a tty as belonging to the user ns of its session
leader (and if it doesn't have one then to init_user_ns) as you first
suggested. I added locking which avoids the race with
disassociate_tty() and ensures the user ns doesn't get unrefed by way of
put_pid(tty->session).

Note that I think TIOCVHANGUP should be checking for CAP_SYS_TTY_CONFIG
instead of CAP_SYS_ADMIN to be consistent with vhangup(2), but I did
not change that in the refactoring here.

--

From 697f842ffc709312e5775e3d1d0782079c3070dc Mon Sep 17 00:00:00 2001
From: Dwight Engen <dwight.engen at oracle.com>
Date: Fri, 1 Mar 2013 13:49:58 -0500
Subject: [PATCH] make vhangup and TIOCVHANGUP namespace aware

Signed-off-by: Dwight Engen <dwight.engen at oracle.com>
---
 drivers/tty/tty_io.c | 36 ++++++++++++++++++++++++++++++------
 fs/open.c            |  6 +-----
 include/linux/tty.h  |  2 +-
 3 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index a057db8..764d4e7 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -104,6 +104,7 @@
 
 #include <linux/kmod.h>
 #include <linux/nsproxy.h>
+#include <linux/pid_namespace.h>
 
 #undef TTY_DEBUG_HANGUP
 
@@ -722,6 +723,29 @@ void tty_vhangup(struct tty_struct *tty)
 
 EXPORT_SYMBOL(tty_vhangup);
 
+/**
+ *	tty_vhangup_check_cap	-	process vhangup checking for capablity
+ *
+ *	Perform a vhangup on the given tty
+ */
+
+static int tty_vhangup_check_cap(struct tty_struct *tty, int cap)
+{
+	unsigned long flags;
+	int retval = 0;
+	struct user_namespace *ns = &init_user_ns;
+
+	spin_lock_irqsave(&tty->ctrl_lock, flags);
+	if (tty->session)
+		ns = ns_of_pid(tty->session)->user_ns;
+	if (!ns_capable(ns, cap))
+		retval = -EPERM;
+	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+	if (!retval)
+		tty_vhangup(tty);
+	return retval;
+}
 
 /**
  *	tty_vhangup_self	-	process vhangup for own ctty
@@ -729,15 +753,18 @@ EXPORT_SYMBOL(tty_vhangup);
  *	Perform a vhangup on the current controlling tty
  */
 
-void tty_vhangup_self(void)
+int tty_vhangup_self(void)
 {
 	struct tty_struct *tty;
+	int retval = 0;
 
 	tty = get_current_tty();
 	if (tty) {
-		tty_vhangup(tty);
+		retval = tty_vhangup_check_cap(tty, CAP_SYS_TTY_CONFIG);
 		tty_kref_put(tty);
 	}
+
+	return retval;
 }
 
 /**
@@ -2710,10 +2737,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case TIOCSETD:
 		return tiocsetd(tty, p);
 	case TIOCVHANGUP:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
-		tty_vhangup(tty);
-		return 0;
+		return tty_vhangup_check_cap(tty, CAP_SYS_ADMIN);
 	case TIOCGDEV:
 	{
 		unsigned int ret = new_encode_dev(tty_devnum(real_tty));
diff --git a/fs/open.c b/fs/open.c
index 9b33c0c..19ac16e 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1059,11 +1059,7 @@ EXPORT_SYMBOL(sys_close);
  */
 SYSCALL_DEFINE0(vhangup)
 {
-	if (capable(CAP_SYS_TTY_CONFIG)) {
-		tty_vhangup_self();
-		return 0;
-	}
-	return -EPERM;
+	return tty_vhangup_self();
 }
 
 /*
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 8db1b56..c9d0e9c 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -379,7 +379,7 @@ extern int tty_signal(int sig, struct tty_struct *tty);
 extern void tty_hangup(struct tty_struct *tty);
 extern void tty_vhangup(struct tty_struct *tty);
 extern void tty_vhangup_locked(struct tty_struct *tty);
-extern void tty_vhangup_self(void);
+extern int tty_vhangup_self(void);
 extern void tty_unhangup(struct file *filp);
 extern int tty_hung_up_p(struct file *filp);
 extern void do_SAK(struct tty_struct *tty);
-- 
1.7.12.3





More information about the lxc-devel mailing list