screen-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[screen-devel] [PATCH v3 (screen v4)] screen: handle pts devices in diff


From: Christian Brauner
Subject: [screen-devel] [PATCH v3 (screen v4)] screen: handle pts devices in different namespaces
Date: Wed, 5 Apr 2017 14:24:22 +0200

Various programs that deal with namespaces will use pty devices that exist in
another namespace. One obvious candidate are containers. So far ttyname() was
incorrectly handling this case because the pts device stems from the host and
thus cannot be found amongst the current namespace's /dev/pts/<n> entries.
Serge Hallyn and I recently upstreamed patches to glibc that allow ttyname{_r}()
to correctly handle this case. At a minimum, ttyname{_r}() will set errno to
ENODEV in case it finds that the /dev/pts/<n> device that the symlink points to
exists in another namespace.

(The next comment is a little longer but tries to ensure that one can still
understand what is going on after some time has passed.)
In case we detect that ttyname{_r}() returns NULL and sets errno to ENODEV we
have ample reason to assume that the pts device exists in a different
namespace. In this case, the code will set a global flag indicating this case
to true. Furthermore, all operations (e.g. chmod(), chown(), etc.) will now
need to operate on the symbolic link /proc/self/fd/0 directly. While this
sounds straightforward, it becomes difficult to handle this case correctly when
we reattach to an already existing screen session from a different pts device
than the original one. Let's look at the general reattach logic a little
closer:

Assume we are running a shell that uses a pts device from a different
namespace:

        address@hidden:~# ls -al /proc/self/fd/
        total 0
        dr-x------ 2 root root  0 Apr  2 20:22 .
        dr-xr-xr-x 9 root root  0 Apr  2 20:22 ..
        lrwx------ 1 root root 64 Apr  2 20:22 0 -> /dev/pts/6
        lrwx------ 1 root root 64 Apr  2 20:22 1 -> /dev/pts/6
        lrwx------ 1 root root 64 Apr  2 20:22 2 -> /dev/pts/6
        l-wx------ 1 root root 64 Apr  2 20:22 3 -> pipe:[3067913]
        lr-x------ 1 root root 64 Apr  2 20:22 4 -> /proc/27413/fd
        lrwx------ 1 root root 64 Apr  2 20:22 9 -> socket:[32944]

        address@hidden:~# ls -al /dev/pts/
        total 0
        drwxr-xr-x 2 root root      0 Mar 30 17:55 .
        drwxr-xr-x 8 root root    580 Mar 30 17:55 ..
        crw--w---- 1 root tty  136, 0 Mar 30 17:55 0
        crw--w---- 1 root tty  136, 1 Mar 30 17:55 1
        crw--w---- 1 root tty  136, 2 Mar 30 17:55 2
        crw--w---- 1 root tty  136, 3 Mar 30 17:55 3
        crw--w---- 1 root tty  136, 4 Mar 30 17:55 4
        crw-rw-rw- 1 root root   5, 2 Apr  2 20:22 ptmx

(As one can see /dev/pts/6 does not exist in the current namespace.)
Now, start a screen session in this shell. In this case this patch will have
screen directly operate on /proc/self/fd/0.
Let's look at the attach case. When we attach to an existing screen session
where the associated pts device lives in another namespace we need a way to
uniquely identify the pts device that is used and also need a way to get a
valid fd when we need one. This patch solves this by ensuring that a valid file
descriptor to the pts device is sent via a unix socket and SCM_RIGHTS to the
socket and display handling part of screen. However, screen also sends around
the name of the associated pts device or, in the case where the pts device
exists in another namespace, the symlink /proc/self/fd/0. But after having sent
the fd this part of the codebase cannot simply operate on /proc/self/fd/0 since
it very likely refers to a different file. So we need to operate on
/proc/self/fd/<fd-sent-via-SCM_RIGHTS> but also need to ensure that we haven't
been tricked into operating on a tampered with file or device. So we cannot
simply sent /proc/self/fd/0 via the unix socket. Instead we read the contents
of the symbolic link /proc/self/fd/0 in the main function and sent it via the
unix socket. Then in the socket and display handling part of screen, we read
the contents of the /proc/self/fd/<fd-sent-via-SCM_RIGHTS> as well and compare
the pts device names. If they match we know that everything is well. However,
now we also need to update any tty handling code to directly operate on
/proc/self/fd/<fd-sent-via-SCM_RIGHTS>.

Signed-off-by: Christian Brauner <address@hidden>
---
Changelog: 2017-04-05
        - remove attach_tty_is_in_new_ns from socket.c
          This variable is unneeded and it does harm since it may end up falsely
          initialized when not sent over the socket itself. The most promiment
          instance of failure is when starting screen in detached mode
          (screen -dm).
---
 src/attacher.c |  11 +++--
 src/extern.h   |   2 +-
 src/pty.c      |  33 +++++++++++--
 src/screen.c   | 145 ++++++++++++++++++++++++++++++++++-----------------------
 src/socket.c   |  39 +++++++++++++++-
 src/utmp.c     |   6 +--
 6 files changed, 163 insertions(+), 73 deletions(-)

diff --git a/src/attacher.c b/src/attacher.c
index 1052549..ed0d6ea 100644
--- a/src/attacher.c
+++ b/src/attacher.c
@@ -27,6 +27,7 @@
  */
 
 #include "config.h"
+#include <stdbool.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
@@ -58,6 +59,10 @@ extern char *SockName, *SockMatch, SockPath[];
 extern char HostName[];
 extern struct passwd *ppp;
 extern char *attach_tty, *attach_term, *LoginName, *preselect;
+/* Indicator whether the current tty exists in another namespace. */
+extern bool attach_tty_is_in_new_ns;
+/* Content of the tty symlink when attach_tty_is_in_new_ns == true. */
+extern char attach_tty_name_in_ns[];
 extern int xflag, dflag, rflag, quietflag, adaptflag;
 extern struct mode attach_Mode;
 extern struct NewWindow nwin_options;
@@ -226,7 +231,7 @@ int how;
   bzero((char *) &m, sizeof(m));
   m.type = how;
   m.protocol_revision = MSG_REVISION;
-  strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
+  strncpy(m.m_tty, attach_tty_is_in_new_ns ? attach_tty_name_in_ns : 
attach_tty, sizeof(m.m_tty) - 1);
   m.m_tty[sizeof(m.m_tty) - 1] = 0;
 
   if (how == MSG_WINCH)
@@ -482,7 +487,7 @@ AttacherFinit SIGDEFARG
     {
       debug("Detaching backend!\n");
       bzero((char *) &m, sizeof(m));
-      strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
+      strncpy(m.m_tty, attach_tty_is_in_new_ns ? attach_tty_name_in_ns : 
attach_tty, sizeof(m.m_tty) - 1);
       m.m_tty[sizeof(m.m_tty) - 1] = 0;
       debug1("attach_tty is %s\n", attach_tty);
       m.m.detach.dpid = getpid();
@@ -1022,7 +1027,7 @@ int query;
   m.type = query ? MSG_QUERY : MSG_COMMAND;
   if (attach_tty)
     {
-      strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
+      strncpy(m.m_tty, attach_tty_is_in_new_ns ? attach_tty_name_in_ns : 
attach_tty, sizeof(m.m_tty) - 1);
       m.m_tty[sizeof(m.m_tty) - 1] = 0;
     }
   p = m.m.command.cmd;
diff --git a/src/extern.h b/src/extern.h
index 7966008..bd22ebb 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -111,7 +111,7 @@ extern struct baud_values *lookup_baud __P((int bps));
 extern int   SetBaud __P((struct mode *, int, int));
 extern int   SttyMode __P((struct mode *, char *));
 extern int   CheckTtyname __P((char *));
-
+extern char  *GetPtsPathOrSymlink __P((int));
 
 /* mark.c */
 extern int   GetHistory __P((void));
diff --git a/src/pty.c b/src/pty.c
index badf854..1c0660e 100644
--- a/src/pty.c
+++ b/src/pty.c
@@ -198,7 +198,7 @@ OpenPTY(ttyn)
 char **ttyn;
 {
   int f;
-  char *name, *_getpty(); 
+  char *name, *_getpty();
   sigret_t (*sigcld)__P(SIGPROTOARG);
 
   /*
@@ -227,7 +227,7 @@ char **ttyn;
 {
   register int f;
   struct stat buf;
-   
+
   strcpy(PtyName, "/dev/ptc");
   if ((f = open(PtyName, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0)
     return -1;
@@ -277,7 +277,7 @@ char **ttyn;
       signal(SIGCHLD, sigcld);
       close(f);
       return -1;
-    } 
+    }
   signal(SIGCHLD, sigcld);
   strncpy(TtyName, m, sizeof(TtyName));
   initmaster(f);
@@ -301,7 +301,7 @@ char **ttyn;
   strcpy (PtyName, "/dev/ptc");
   if ((f = open (PtyName, O_RDWR | O_NOCTTY)) < 0)
     return -1;
-  strncpy(TtyName, ttyname(f), sizeof(TtyName));
+  strncpy(TtyName, GetPtsPathOrSymlink(f), sizeof(TtyName));
   if (eff_uid && access(TtyName, R_OK | W_OK))
     {
       close(f);
@@ -331,7 +331,7 @@ char **ttyn;
   initmaster(f);
   pty_preopen = 1;
   *ttyn = TtyName;
-  return f;    
+  return f;
 }
 #endif
 
@@ -390,3 +390,26 @@ char **ttyn;
 }
 #endif
 
+/* len(/proc/self/fd/) + len(max 64 bit int) */
+#define MAX_PTS_SYMLINK (14 + 21)
+char *GetPtsPathOrSymlink(int fd)
+{
+       int ret;
+       char *tty_name;
+       static char tty_symlink[MAX_PTS_SYMLINK];
+
+       errno = 0;
+       tty_name = ttyname(fd);
+       if (!tty_name && errno == ENODEV) {
+               ret = snprintf(tty_symlink, MAX_PTS_SYMLINK, 
"/proc/self/fd/%d", fd);
+               if (ret < 0 || ret >= MAX_PTS_SYMLINK)
+                       return NULL;
+               /* We are setting errno to ENODEV to allow callers to check
+                * whether the pts device exists in another namespace.
+                */
+               errno = ENODEV;
+               return tty_symlink;
+       }
+
+       return tty_name;
+}
diff --git a/src/screen.c b/src/screen.c
index 14aaa33..559f809 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -43,6 +43,8 @@
 #include <sys/socket.h>
 #endif
 #include <ctype.h>
+#include <stdbool.h>
+#include <unistd.h>
 #include <fcntl.h>
 
 #if defined(__sun)
@@ -125,7 +127,7 @@ int force_vt = 1;
 int VBellWait, MsgWait, MsgMinWait, SilenceWait;
 
 extern struct acluser *users;
-extern struct display *displays, *display; 
+extern struct display *displays, *display;
 extern struct LayFuncs MarkLf;
 
 extern int visual_bell;
@@ -162,6 +164,7 @@ static char *runbacktick __P((struct backtick *, int *, 
time_t));
 static int   IsSymbol __P((char *, char *));
 static char *ParseChar __P((char *, char *));
 static int   ParseEscape __P((char *));
+static void SetTtyname(bool fatal, struct stat *st);
 static char *pad_expand __P((char *, char *, int, int));
 #ifdef DEBUG
 static void  fds __P((void));
@@ -172,6 +175,10 @@ int nversion;      /* numerical version, used for 
secondary DA */
 /* the attacher */
 struct passwd *ppp;
 char *attach_tty;
+/* Indicator whether the current tty exists in another namespace. */
+bool attach_tty_is_in_new_ns = false;
+/* Content of the tty symlink when attach_tty_is_in_new_ns == true. */
+char attach_tty_name_in_ns[MAXPATHLEN];
 int attach_fd = -1;
 char *attach_term;
 char *LoginName;
@@ -297,7 +304,7 @@ struct passwd *ppp;
   struct spwd *sss = NULL;
   static char *spw = NULL;
 #endif
- 
+
   if (!ppp && !(ppp = getpwnam(name)))
     return NULL;
 
@@ -860,7 +867,7 @@ int main(int ac, char** av)
       nwin_options.aka = SaveStr(nwin_options.aka);
     }
   }
-  
+
   if (SockMatch && strlen(SockMatch) >= MAXSTR)
     Panic(0, "Ridiculously long socketname - try again.");
   if (cmdflag && !rflag && !dflag && !xflag)
@@ -979,34 +986,6 @@ int main(int ac, char** av)
     eff_gid = real_gid; \
   } while (0)
 
-#define SET_TTYNAME(fatal) do \
-  { \
-    int saved_errno = 0; \
-    errno = 0; \
-    if (!(attach_tty = ttyname(0))) \
-    { \
-    /* stdin is a tty but it exists in another namespace. */ \
-    if (fatal && errno == ENODEV) \
-      attach_tty = ""; \
-    else if (fatal) \
-      Panic(0, "Must be connected to a terminal."); \
-    else \
-      attach_tty = ""; \
-    } \
-    else \
-    { \
-    saved_errno = errno; \
-    if (stat(attach_tty, &st)) \
-      Panic(errno, "Cannot access '%s'", attach_tty); \
-    /* Only call CheckTtyname() if the device does not exist in another \
-     * namespace. */ \
-    if (saved_errno != ENODEV && CheckTtyname(attach_tty)) \
-      Panic(0, "Bad tty '%s'", attach_tty); \
-    } \
-    if (strlen(attach_tty) >= MAXPATHLEN) \
-      Panic(0, "TtyName too long - sorry."); \
-  } while (0)
-
   if (home == 0 || *home == '\0')
     home = ppp->pw_dir;
   if (strlen(LoginName) > MAXLOGINLEN)
@@ -1027,7 +1006,7 @@ int main(int ac, char** av)
 #endif
 
     /* ttyname implies isatty */
-    SET_TTYNAME(1);
+    SetTtyname(true, &st);
 #ifdef MULTIUSER
     tty_mode = (int)st.st_mode & 0777;
 #endif
@@ -1041,7 +1020,16 @@ int main(int ac, char** av)
     if (attach_fd == -1) {
       if ((n = secopen(attach_tty, O_RDWR | O_NONBLOCK, 0)) < 0)
         Panic(0, "Cannot open your terminal '%s' - please check.", attach_tty);
-      close(n);
+      /* In case the pts device exists in another namespace we directly operate
+       * on the symbolic link itself. However, this means that we need to keep
+       * the fd open since we have no direct way of identifying the associated
+       * pts device accross namespaces. This is ok though since keeping fds 
open
+       * is done in the codebase already.
+       */
+      if (attach_tty_is_in_new_ns)
+       attach_fd = n;
+      else
+       close(n);
     }
 
     debug2("attach_tty is %s, attach_fd is %d\n", attach_tty, attach_fd);
@@ -1215,7 +1203,7 @@ int main(int ac, char** av)
   signal(SIG_BYE, AttacherFinit);      /* prevent races */
   if (cmdflag) {
     /* attach_tty is not mandatory */
-    SET_TTYNAME(0);
+    SetTtyname(false, &st);
     if (!*av)
       Panic(0, "Please specify a command.");
     SET_GUID();
@@ -1236,7 +1224,7 @@ int main(int ac, char** av)
     debug("screen -r: backend not responding -- still crying\n");
   }
   else if (dflag && !mflag) {
-    SET_TTYNAME(0);
+    SetTtyname(false, &st);
     Attach(MSG_DETACH);
     Msg(0, "[%s %sdetached.]\n", SockName, (dflag > 1 ? "power " : ""));
     eexit(0);
@@ -1244,7 +1232,7 @@ int main(int ac, char** av)
   }
   if (!SockMatch && !mflag && sty) {
     /* attach_tty is not mandatory */
-    SET_TTYNAME(0);
+    SetTtyname(false, &st);
     SET_GUID();
     nwin_options.args = av;
     SendCreateMsg(sty, &nwin);
@@ -1385,7 +1373,7 @@ int main(int ac, char** av)
   (void)StartRc(RcFileName, 0);
 # ifdef UTMPOK
 #  ifndef UTNOKEEP
-  InitUtmp(); 
+  InitUtmp();
 #  endif /* UTNOKEEP */
 # endif /* UTMPOK */
   if (display) {
@@ -1409,7 +1397,7 @@ int main(int ac, char** av)
 #ifdef LOADAV
   InitLoadav();
 #endif /* LOADAV */
- 
+
   MakeNewEnv();
   signal(SIGHUP, SigHup);
   signal(SIGINT, FinitHandler);
@@ -1456,13 +1444,13 @@ int main(int ac, char** av)
       /* NOTREACHED */
     }
   }
-  else if (ac) /* Screen was invoked with a command */ 
+  else if (ac) /* Screen was invoked with a command */
     MakeWindow(&nwin);
 
 #ifdef HAVE_BRAILLE
   StartBraille();
 #endif
-  
+
   if (display && default_startup)
     display_copyright();
   signal(SIGINT, SigInt);
@@ -1623,7 +1611,7 @@ sigret_t SigHup SIGDEFARG
   SIGRETURN;
 }
 
-/* 
+/*
  * the backend's Interrupt handler
  * we cannot insert the intrc directly, as we never know
  * if fore is valid.
@@ -1718,10 +1706,10 @@ static void DoWait()
 # else
 
 # ifdef USE_WAIT2
-  /* 
-   * From: address@hidden (John Rouillard) 
+  /*
+   * From: address@hidden (John Rouillard)
    * note that WUNTRACED is not documented to work, but it is defined in
-   * /usr/include/sys/wait.h, so it may work 
+   * /usr/include/sys/wait.h, so it may work
    */
   while ((pid = wait2(&wstat, WNOHANG | WUNTRACED )) > 0)
 #  else /* USE_WAIT2 */
@@ -1742,7 +1730,7 @@ static void DoWait()
       if ((p->w_pid && pid == p->w_pid) || (p->w_deadpid && pid == 
p->w_deadpid)) {
       /* child has ceased to exist */
         p->w_pid = 0;
-               
+
 #ifdef BSDJOBS
         if (WIFSTOPPED(wstat)) {
           debug3("Window %d pid %d: WIFSTOPPED (sig %d)\n", p->w_number, pid, 
WSTOPSIG(wstat));
@@ -1850,7 +1838,7 @@ void Finit(int i)
       Kill(D_userpid, SIG_BYE);
   }
   /*
-   * we _cannot_ call eexit(i) here, 
+   * we _cannot_ call eexit(i) here,
    * instead of playing with the Socket above. Sigh.
    */
   exit(i);
@@ -2207,7 +2195,7 @@ DEFINE_VARARGS_FN(Dummy)
 
 /*
  * '^' is allowed as an escape mechanism for control characters. jw.
- * 
+ *
  * Added time insertion using ideas/code from /\ndy Jones
  *   (address@hidden) - thanks a lot!
  *
@@ -2392,7 +2380,7 @@ void setbacktick(int num, int lifespan, int tick, char 
**cmdv)
       setbacktick(num, 0, 0, (char **)0);
       return;
        }
- 
+
     bt->ev.type = EV_READ;
     bt->ev.fd = readpipe(bt->cmdv);
     bt->ev.handler = backtick_fn;
@@ -2482,12 +2470,12 @@ char *MakeWinMsgEv(char *str, struct win *win, int esc, 
int padlen, struct event
   int truncper = 0;
   int trunclong = 0;
   struct backtick *bt = NULL;
- 
+
   if (winmsg_numrend >= 0)
     winmsg_numrend = 0;
   else
     winmsg_numrend = -winmsg_numrend;
-    
+
   tick = 0;
   tm = 0;
   ctrl = 0;
@@ -2523,10 +2511,10 @@ char *MakeWinMsgEv(char *str, struct win *win, int esc, 
int padlen, struct event
 
     if (*++s == esc)   /* double escape ? */
       continue;
- 
+
     if ((plusflg = *s == '+') != 0)
       s++;
- 
+
     if ((minusflg = *s == '-') != 0)
       s++;
 
@@ -3242,7 +3230,7 @@ static void serv_select_fn(struct event *ev, char *data)
         RethinkViewportOffsets(cv);
         if (n > cv->c_layer->l_height)
           n = cv->c_layer->l_height;
-        CV_CALL(cv, 
+        CV_CALL(cv,
             LScrollV(flayer, -n, 0, flayer->l_height - 1, 0);
             LayRedisplayLine(-1, -1, -1, 1);
             for (i = 0; i < n; i++)
@@ -3257,7 +3245,7 @@ static void serv_select_fn(struct event *ev, char *data)
         RethinkViewportOffsets(cv);
         if (n > cv->c_layer->l_height)
           n = cv->c_layer->l_height;
-        CV_CALL(cv, 
+        CV_CALL(cv,
            LScrollV(flayer, n, 0, cv->c_layer->l_height - 1, 0);
            LayRedisplayLine(-1, -1, -1, 1);
            for (i = 0; i < n; i++)
@@ -3276,7 +3264,7 @@ static void serv_select_fn(struct event *ev, char *data)
         RethinkViewportOffsets(cv);
         if (n > cv->c_layer->l_width)
           n = cv->c_layer->l_width;
-        CV_CALL(cv, 
+        CV_CALL(cv,
            LayRedisplayLine(-1, -1, -1, 1);
            for (i = 0; i < flayer->l_height; i++) {
               LScrollH(flayer, -n, i, 0, flayer->l_width - 1, 0, 0);
@@ -3296,7 +3284,7 @@ static void serv_select_fn(struct event *ev, char *data)
         RethinkViewportOffsets(cv);
         if (n > cv->c_layer->l_width)
           n = cv->c_layer->l_width;
-        CV_CALL(cv, 
+        CV_CALL(cv,
            LayRedisplayLine(-1, -1, -1, 1);
            for (i = 0; i < flayer->l_height; i++) {
              LScrollH(flayer, n, i, 0, flayer->l_width - 1, 0, 0);
@@ -3352,9 +3340,9 @@ static void logflush_fn(struct event *ev, char *data)
 /*
  * Interprets ^?, ^@ and other ^-control-char notation.
  * Interprets \ddd octal notation
- * 
- * The result is placed in *cp, p is advanced behind the parsed expression and 
- * returned. 
+ *
+ * The result is placed in *cp, p is advanced behind the parsed expression and
+ * returned.
  */
 static char *ParseChar(char *p, char *cp)
 {
@@ -3396,3 +3384,42 @@ static int ParseEscape(char *p)
   return 0;
 }
 
+void SetTtyname(bool fatal, struct stat *st)
+{
+       int ret;
+       int saved_errno = 0;
+
+       attach_tty_is_in_new_ns = false;
+       memset(&attach_tty_name_in_ns, 0, sizeof(attach_tty_name_in_ns));
+
+       errno = 0;
+       attach_tty = ttyname(0);
+       if (!attach_tty) {
+               if (errno == ENODEV) {
+                       saved_errno = errno;
+                       attach_tty = "/proc/self/fd/0";
+                       attach_tty_is_in_new_ns = true;
+                       ret = readlink(attach_tty, attach_tty_name_in_ns, 
sizeof(attach_tty_name_in_ns));
+                       if (ret < 0 || (size_t)ret >= 
sizeof(attach_tty_name_in_ns))
+                               Panic(0, "Bad tty '%s'", attach_tty);
+               } else if (fatal) {
+                       Panic(0, "Must be connected to a terminal.");
+               } else {
+                       attach_tty = "";
+               }
+       }
+
+       if (attach_tty) {
+               if (stat(attach_tty, st))
+                       Panic(errno, "Cannot access '%s'", attach_tty);
+
+               if (strlen(attach_tty) >= MAXPATHLEN)
+                       Panic(0, "TtyName too long - sorry.");
+
+               /* Only call CheckTtyname() if the device does not exist in
+                * another namespace.
+                */
+               if (saved_errno != ENODEV && CheckTtyname(attach_tty))
+                       Panic(0, "Bad tty '%s'", attach_tty);
+       }
+}
diff --git a/src/socket.c b/src/socket.c
index e464a62..81e0b4b 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -27,6 +27,9 @@
  */
 
 #include "config.h"
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -869,11 +872,43 @@ struct win *wi;
     }
   if (recvfd != -1)
     {
+      int ret;
+      char ttyname_in_ns[MAXPATHLEN];
       char *myttyname;
+
       i = recvfd;
       recvfd = -1;
-      myttyname = ttyname(i);
-      if (myttyname == 0 || strcmp(myttyname, m->m_tty))
+      memset(&ttyname_in_ns, 0, sizeof(ttyname_in_ns));
+      errno = 0;
+      myttyname = GetPtsPathOrSymlink(i);
+      if (myttyname && errno == ENODEV)
+        {
+          ret = readlink(myttyname, ttyname_in_ns, sizeof(ttyname_in_ns));
+          if (ret < 0 || (size_t)ret >= sizeof(ttyname_in_ns))
+            {
+             Msg(errno, "Could not perform necessary sanity checks on pts 
device.");
+             close(i);
+             Kill(pid, SIG_BYE);
+             return -1;
+            }
+          if (strcmp(ttyname_in_ns, m->m_tty))
+            {
+             Msg(errno, "Attach: passed fd does not match tty: %s - %s!", 
ttyname_in_ns, m->m_tty[0] != '\0' ? m->m_tty : "(null)");
+             close(i);
+             Kill(pid, SIG_BYE);
+             return -1;
+           }
+         /* m->m_tty so far contains the actual name of the pts device in the
+          * its (e.g. /dev/pts/0). This name however is not valid in the
+          * current namespace. So after we verified that the symlink returned
+          * by GetPtsPathOrSymlink() refers to the same pts device in this
+          * namespace we need to update m->m_tty to use that symlink for all
+          * future operations.
+          */
+          strncpy(m->m_tty, myttyname, sizeof(m->m_tty) - 1);
+          m->m_tty[sizeof(m->m_tty) - 1] = 0;
+        }
+      else if (myttyname == 0 || strcmp(myttyname, m->m_tty))
        {
          Msg(errno, "Attach: passed fd does not match tty: %s - %s!", 
m->m_tty, myttyname ? myttyname : "NULL");
          close(i);
diff --git a/src/utmp.c b/src/utmp.c
index fa8b87b..8ec2de4 100644
--- a/src/utmp.c
+++ b/src/utmp.c
@@ -361,7 +361,7 @@ RemoveLoginSlot()
       char *tty;
       debug("couln't zap slot -> do mesg n\n");
       D_loginttymode = 0;
-      if ((tty = ttyname(D_userfd)) && stat(tty, &stb) == 0 && (int)stb.st_uid 
== real_uid && !CheckTtyname(tty) && ((int)stb.st_mode & 0777) != 0666)
+      if ((tty = GetPtsPathOrSymlink(D_userfd)) && stat(tty, &stb) == 0 && 
(int)stb.st_uid == real_uid && !CheckTtyname(tty) && ((int)stb.st_mode & 0777) 
!= 0666)
        {
          D_loginttymode = (int)stb.st_mode & 0777;
          chmod(D_usertty, stb.st_mode & 0600);
@@ -387,7 +387,7 @@ RestoreLoginSlot()
     }
   UT_CLOSE;
   D_loginslot = (slot_t)0;
-  if (D_loginttymode && (tty = ttyname(D_userfd)) && !CheckTtyname(tty))
+  if (D_loginttymode && (tty = GetPtsPathOrSymlink(D_userfd)) && 
!CheckTtyname(tty))
     chmod(tty, D_loginttymode);
 }
 
@@ -851,7 +851,7 @@ getlogin()
   static char retbuf[sizeof(u.ut_user)+1];
   int fd;
 
-  for (fd = 0; fd <= 2 && (tty = ttyname(fd)) == NULL; fd++)
+  for (fd = 0; fd <= 2 && (tty = GetPtsPathOrSymlink(fd)) == NULL; fd++)
     ;
   if ((tty == NULL) || CheckTtyname(tty) || ((fd = open(UTMP_FILE, O_RDONLY)) 
< 0))
     return NULL;
-- 
2.11.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]