]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
terminal: use /dev/ptmx when allocating pty devices from devpts instances we didn...
authorChristian Brauner <christian.brauner@ubuntu.com>
Tue, 17 Aug 2021 08:43:34 +0000 (10:43 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Tue, 17 Aug 2021 09:39:17 +0000 (11:39 +0200)
When we aren't told what devpts instance to allocate from we assume it
is the one in the caller's mount namespace.
This poses a slight complication, a lot of distros will change
permissions on /dev/ptmx so it can be opened by unprivileged users but
will not change permissions on /dev/pts/ptmx itself. In addition,
/dev/ptmx can either be a symlink, a bind-mount, or a separate device
node. So we need to allow for fairly lax lookup.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/syscall_wrappers.h
src/lxc/terminal.c

index 49c9e05026712828e13ac58e6e9d351b01a4502f..7d62b7c5b0d8b1b34febddfc5273b448af89eb67 100644 (file)
@@ -281,6 +281,7 @@ struct lxc_open_how {
 #define PROTECT_LOOKUP_ABSOLUTE_WITH_SYMLINKS (PROTECT_LOOKUP_ABSOLUTE & ~RESOLVE_NO_SYMLINKS)
 #define PROTECT_LOOKUP_ABSOLUTE_WITH_MAGICLINKS (PROTECT_LOOKUP_ABSOLUTE & ~(RESOLVE_NO_SYMLINKS | RESOLVE_NO_MAGICLINKS))
 #define PROTECT_LOOKUP_ABSOLUTE_XDEV (PROTECT_LOOKUP_ABSOLUTE & ~RESOLVE_NO_XDEV)
+#define PROTECT_LOOKUP_ABSOLUTE_XDEV_SYMLINKS (PROTECT_LOOKUP_ABSOLUTE_WITH_SYMLINKS & ~RESOLVE_NO_XDEV)
 
 #define PROTECT_OPATH_FILE (O_NOFOLLOW | O_PATH | O_CLOEXEC)
 #define PROTECT_OPATH_DIRECTORY (PROTECT_OPATH_FILE | O_DIRECTORY)
index 73e670e8f060f17d66ae36286658703ec7bfe76c..da5748748ff8ae1949e69c479728b8bbe299add2 100644 (file)
@@ -946,14 +946,25 @@ err:
 int lxc_devpts_terminal(int devpts_fd, int *ret_ptx, int *ret_pty,
                        int *ret_pty_nr, bool require_tiocgptpeer)
 {
-       __do_close int fd_ptx = -EBADF, fd_opath_pty = -EBADF, fd_pty = -EBADF;
+       __do_close int fd_devpts = -EBADF, fd_ptx = -EBADF,
+                      fd_opath_pty = -EBADF, fd_pty = -EBADF;
        int pty_nr = -1;
        int ret;
 
+       /*
+        * When we aren't told what devpts instance to allocate from we assume
+        * it is the one in the caller's mount namespace.
+        * This poses a slight complication, a lot of distros will change
+        * permissions on /dev/ptmx so it can be opened by unprivileged users
+        * but will not change permissions on /dev/pts/ptmx itself. In
+        * addition, /dev/ptmx can either be a symlink, a bind-mount, or a
+        * separate device node. So we need to allow for fairly lax lookup.
+        */
        if (devpts_fd < 0)
-               return ret_errno(EBADF);
-
-       fd_ptx = open_beneath(devpts_fd, "ptmx", O_RDWR | O_NOCTTY | O_CLOEXEC);
+               fd_ptx = open_at(-EBADF, "/dev/ptmx", PROTECT_OPEN_RW & ~O_NOFOLLOW,
+                                PROTECT_LOOKUP_ABSOLUTE_XDEV_SYMLINKS, 0);
+       else
+               fd_ptx = open_beneath(devpts_fd, "ptmx", O_RDWR | O_NOCTTY | O_CLOEXEC);
        if (fd_ptx < 0) {
                if (errno == ENOSPC)
                        return systrace("Exceeded number of allocatable terminals");
@@ -961,6 +972,17 @@ int lxc_devpts_terminal(int devpts_fd, int *ret_ptx, int *ret_pty,
                return syserror("Failed to open terminal multiplexer device");
        }
 
+       if (devpts_fd < 0) {
+               fd_devpts = open_at(-EBADF, "/dev/pts", PROTECT_OPATH_DIRECTORY,
+                                   PROTECT_LOOKUP_ABSOLUTE_XDEV, 0);
+               if (fd_devpts < 0)
+                       return syserror("Failed to open devpts instance");
+
+               if (!same_device(fd_devpts, "ptmx", fd_ptx, ""))
+                       return syserror("The acquired ptmx devices don't match");
+               devpts_fd = fd_devpts;
+       }
+
        ret = unlockpt(fd_ptx);
        if (ret < 0)
                return syswarn_set(-ENODEV, "Failed to unlock multiplexer device device");
@@ -1018,7 +1040,6 @@ int lxc_devpts_terminal(int devpts_fd, int *ret_ptx, int *ret_pty,
 
 int lxc_terminal_parent(struct lxc_conf *conf)
 {
-       __do_close int fd_devpts = -EBADF;
        struct lxc_terminal *console = &conf->console;
        int ret;
 
@@ -1030,15 +1051,7 @@ int lxc_terminal_parent(struct lxc_conf *conf)
                return 0;
 
        /* Allocate console for the container from the host's devpts. */
-       fd_devpts = open_at(-EBADF,
-                           "/dev/pts",
-                           PROTECT_OPATH_DIRECTORY,
-                           PROTECT_LOOKUP_ABSOLUTE_XDEV,
-                           0);
-       if (fd_devpts < 0)
-               return syserror("Failed to open devpts instance");
-
-       ret = lxc_devpts_terminal(fd_devpts, &console->ptx, &console->pty,
+       ret = lxc_devpts_terminal(-EBADF, &console->ptx, &console->pty,
                                  &console->pty_nr, false);
        if (ret < 0)
                return syserror("Failed to allocate console");