From: Christian Brauner Date: Tue, 17 Aug 2021 08:43:34 +0000 (+0200) Subject: terminal: use /dev/ptmx when allocating pty devices from devpts instances we didn... X-Git-Tag: lxc-5.0.0~108^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=803839b8b978b29034ba7fe0ca5abe3d60dd8130;p=thirdparty%2Flxc.git terminal: use /dev/ptmx when allocating pty devices from devpts instances we didn't mount ourselves 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 --- diff --git a/src/lxc/syscall_wrappers.h b/src/lxc/syscall_wrappers.h index 49c9e0502..7d62b7c5b 100644 --- a/src/lxc/syscall_wrappers.h +++ b/src/lxc/syscall_wrappers.h @@ -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) diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c index 73e670e8f..da5748748 100644 --- a/src/lxc/terminal.c +++ b/src/lxc/terminal.c @@ -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");