mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-23 09:43:32 +08:00
Linux: Require properly configured /dev/pts for PTYs
Current systems do not have BSD terminals, so the fallback code in posix_openpt/getpt does not do anything. Also remove the file system check for /dev/pts. Current systems always have a devpts file system mounted there if /dev/ptmx exists. grantpt is now essentially a no-op. It only verifies that the argument is a ptmx-descriptor. Therefore, this change indirectly addresses bug 24941. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
This commit is contained in:
parent
0a167374fd
commit
174d0b61c7
11
INSTALL
11
INSTALL
@ -184,14 +184,9 @@ if 'CFLAGS' is specified it must enable optimization. For example:
|
||||
'--enable-pt_chown'
|
||||
The file 'pt_chown' is a helper binary for 'grantpt' (*note
|
||||
Pseudo-Terminals: Allocation.) that is installed setuid root to fix
|
||||
up pseudo-terminal ownership. It is not built by default because
|
||||
systems using the Linux kernel are commonly built with the 'devpts'
|
||||
filesystem enabled and mounted at '/dev/pts', which manages
|
||||
pseudo-terminal ownership automatically. By using
|
||||
'--enable-pt_chown', you may build 'pt_chown' and install it setuid
|
||||
and owned by 'root'. The use of 'pt_chown' introduces additional
|
||||
security risks to the system and you should enable it only if you
|
||||
understand and accept those risks.
|
||||
up pseudo-terminal ownership on GNU/Hurd. It is not required on
|
||||
GNU/Linux, and the GNU C Library will not use the installed
|
||||
'pt_chown' program when configured with '--enable-pt_chown'.
|
||||
|
||||
'--disable-werror'
|
||||
By default, the GNU C Library is built with '-Werror'. If you wish
|
||||
|
12
NEWS
12
NEWS
@ -225,6 +225,18 @@ Changes to build and runtime requirements:
|
||||
source tree. ChangeLog files are located in the ChangeLog.old directory as
|
||||
ChangeLog.N where the highest N has the latest entries.
|
||||
|
||||
* On Linux, the system administrator needs to configure /dev/pts with
|
||||
the intended access modes for pseudo-terminals. glibc no longer
|
||||
attemps to adjust permissions of terminal devices. The previous glibc
|
||||
defaults ("tty" group, user read/write and group write) already
|
||||
corresponded to what most systems used, so that grantpt did not
|
||||
perform any adjustments.
|
||||
|
||||
* On Linux, the posix_openpt and getpt functions no longer attempt to
|
||||
use legacy (BSD) pseudo-terminals and assume that if /dev/ptmx exists
|
||||
(and pseudo-terminals are supported), a devpts file system is mounted
|
||||
on /dev/pts. Current systems already meet these requirements.
|
||||
|
||||
Security related changes:
|
||||
|
||||
CVE-2019-19126: ld.so failed to ignore the LD_PREFER_MAP_32BIT_EXEC
|
||||
|
@ -214,14 +214,9 @@ increased program load times.
|
||||
@item --enable-pt_chown
|
||||
The file @file{pt_chown} is a helper binary for @code{grantpt}
|
||||
(@pxref{Allocation, Pseudo-Terminals}) that is installed setuid root to
|
||||
fix up pseudo-terminal ownership. It is not built by default because
|
||||
systems using the Linux kernel are commonly built with the @code{devpts}
|
||||
filesystem enabled and mounted at @file{/dev/pts}, which manages
|
||||
pseudo-terminal ownership automatically. By using
|
||||
@samp{--enable-pt_chown}, you may build @file{pt_chown} and install it
|
||||
setuid and owned by @code{root}. The use of @file{pt_chown} introduces
|
||||
additional security risks to the system and you should enable it only if
|
||||
you understand and accept those risks.
|
||||
fix up pseudo-terminal ownership on GNU/Hurd. It is not required on
|
||||
GNU/Linux, and @theglibc{} will not use the installed @file{pt_chown}
|
||||
program when configured with @option{--enable-pt_chown}.
|
||||
|
||||
@item --disable-werror
|
||||
By default, @theglibc{} is built with @option{-Werror}. If you wish
|
||||
|
@ -16,69 +16,18 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <paths.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include "linux_fsinfo.h"
|
||||
|
||||
/* Path to the master pseudo terminal cloning device. */
|
||||
#define _PATH_DEVPTMX _PATH_DEV "ptmx"
|
||||
/* Directory containing the UNIX98 pseudo terminals. */
|
||||
#define _PATH_DEVPTS _PATH_DEV "pts"
|
||||
|
||||
/* Prototype for function that opens BSD-style master pseudo-terminals. */
|
||||
extern int __bsd_getpt (void) attribute_hidden;
|
||||
|
||||
/* Open a master pseudo terminal and return its file descriptor. */
|
||||
int
|
||||
__posix_openpt (int oflag)
|
||||
{
|
||||
static int have_no_dev_ptmx;
|
||||
int fd;
|
||||
|
||||
if (!have_no_dev_ptmx)
|
||||
{
|
||||
fd = __open (_PATH_DEVPTMX, oflag);
|
||||
if (fd != -1)
|
||||
{
|
||||
struct statfs fsbuf;
|
||||
static int devpts_mounted;
|
||||
|
||||
/* Check that the /dev/pts filesystem is mounted
|
||||
or if /dev is a devfs filesystem (this implies /dev/pts). */
|
||||
if (devpts_mounted
|
||||
|| (__statfs (_PATH_DEVPTS, &fsbuf) == 0
|
||||
&& fsbuf.f_type == DEVPTS_SUPER_MAGIC)
|
||||
|| (__statfs (_PATH_DEV, &fsbuf) == 0
|
||||
&& fsbuf.f_type == DEVFS_SUPER_MAGIC))
|
||||
{
|
||||
/* Everything is ok. */
|
||||
devpts_mounted = 1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* If /dev/pts is not mounted then the UNIX98 pseudo terminals
|
||||
are not usable. */
|
||||
__close (fd);
|
||||
have_no_dev_ptmx = 1;
|
||||
__set_errno (ENOENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errno == ENOENT || errno == ENODEV)
|
||||
have_no_dev_ptmx = 1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
__set_errno (ENOENT);
|
||||
|
||||
return -1;
|
||||
return __open (_PATH_DEVPTMX, oflag);
|
||||
}
|
||||
weak_alias (__posix_openpt, posix_openpt)
|
||||
|
||||
@ -86,16 +35,6 @@ weak_alias (__posix_openpt, posix_openpt)
|
||||
int
|
||||
__getpt (void)
|
||||
{
|
||||
int fd = __posix_openpt (O_RDWR);
|
||||
if (fd == -1)
|
||||
fd = __bsd_getpt ();
|
||||
return fd;
|
||||
return __posix_openpt (O_RDWR);
|
||||
}
|
||||
|
||||
|
||||
#define PTYNAME1 "pqrstuvwxyzabcde";
|
||||
#define PTYNAME2 "0123456789abcdef";
|
||||
|
||||
#define __getpt __bsd_getpt
|
||||
#define HAVE_POSIX_OPENPT
|
||||
#include <sysdeps/unix/bsd/getpt.c>
|
||||
weak_alias (__getpt, getpt)
|
||||
|
@ -1,44 +1,41 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
/* grantpt implementation for Linux.
|
||||
Copyright (C) 1998-2020 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <not-cancel.h>
|
||||
|
||||
#include "pty-private.h"
|
||||
|
||||
#if HAVE_PT_CHOWN
|
||||
/* Close all file descriptors except the one specified. */
|
||||
static void
|
||||
close_all_fds (void)
|
||||
int
|
||||
grantpt (int fd)
|
||||
{
|
||||
DIR *dir = __opendir ("/proc/self/fd");
|
||||
if (dir != NULL)
|
||||
{
|
||||
struct dirent64 *d;
|
||||
while ((d = __readdir64 (dir)) != NULL)
|
||||
if (isdigit (d->d_name[0]))
|
||||
{
|
||||
char *endp;
|
||||
long int fd = strtol (d->d_name, &endp, 10);
|
||||
if (*endp == '\0' && fd != PTY_FILENO && fd != dirfd (dir))
|
||||
__close_nocancel_nostatus (fd);
|
||||
}
|
||||
/* Without pt_chown on Linux, we have delegated the creation of the
|
||||
pty node with the right group and permission mode to the kernel, and
|
||||
non-root users are unlikely to be able to change it. Therefore let's
|
||||
consider that POSIX enforcement is the responsibility of the whole
|
||||
system and not only the GNU libc. */
|
||||
|
||||
__closedir (dir);
|
||||
|
||||
int nullfd = __open_nocancel (_PATH_DEVNULL, O_RDONLY);
|
||||
assert (nullfd == STDIN_FILENO);
|
||||
nullfd = __open_nocancel (_PATH_DEVNULL, O_WRONLY);
|
||||
assert (nullfd == STDOUT_FILENO);
|
||||
__dup2 (STDOUT_FILENO, STDERR_FILENO);
|
||||
}
|
||||
/* Verify that fd refers to a ptmx descriptor. */
|
||||
unsigned int ptyno;
|
||||
int ret = __ioctl (fd, TIOCGPTN, &ptyno);
|
||||
if (ret != 0 && errno == ENOTTY)
|
||||
/* POSIX requires EINVAL instead of ENOTTY provided by the kernel. */
|
||||
__set_errno (EINVAL);
|
||||
return ret;
|
||||
}
|
||||
# define CLOSE_ALL_FDS() close_all_fds()
|
||||
#endif
|
||||
|
||||
#include <sysdeps/unix/grantpt.c>
|
||||
|
@ -21,39 +21,14 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <_itoa.h>
|
||||
|
||||
/* Check if DEV corresponds to a master pseudo terminal device. */
|
||||
#define MASTER_P(Dev) \
|
||||
(__gnu_dev_major ((Dev)) == 2 \
|
||||
|| (__gnu_dev_major ((Dev)) == 4 \
|
||||
&& __gnu_dev_minor ((Dev)) >= 128 && __gnu_dev_minor ((Dev)) < 192) \
|
||||
|| (__gnu_dev_major ((Dev)) >= 128 && __gnu_dev_major ((Dev)) < 136))
|
||||
|
||||
/* Check if DEV corresponds to a slave pseudo terminal device. */
|
||||
#define SLAVE_P(Dev) \
|
||||
(__gnu_dev_major ((Dev)) == 3 \
|
||||
|| (__gnu_dev_major ((Dev)) == 4 \
|
||||
&& __gnu_dev_minor ((Dev)) >= 192 && __gnu_dev_minor ((Dev)) < 256) \
|
||||
|| (__gnu_dev_major ((Dev)) >= 136 && __gnu_dev_major ((Dev)) < 144))
|
||||
|
||||
/* Note that major number 4 corresponds to the old BSD style pseudo
|
||||
terminal devices. As of Linux 2.1.115 these are no longer
|
||||
supported. They have been replaced by major numbers 2 (masters)
|
||||
and 3 (slaves). */
|
||||
|
||||
/* Directory where we can find the slave pty nodes. */
|
||||
#define _PATH_DEVPTS "/dev/pts/"
|
||||
|
||||
/* The are declared in getpt.c. */
|
||||
extern const char __libc_ptyname1[] attribute_hidden;
|
||||
extern const char __libc_ptyname2[] attribute_hidden;
|
||||
|
||||
/* Static buffer for `ptsname'. */
|
||||
static char buffer[sizeof (_PATH_DEVPTS) + 20];
|
||||
|
||||
@ -68,19 +43,15 @@ ptsname (int fd)
|
||||
}
|
||||
|
||||
|
||||
/* Store at most BUFLEN characters of the pathname of the slave pseudo
|
||||
terminal associated with the master FD is open on in BUF.
|
||||
Return 0 on success, otherwise an error number. */
|
||||
int
|
||||
__ptsname_internal (int fd, char *buf, size_t buflen, struct stat64 *stp)
|
||||
__ptsname_r (int fd, char *buf, size_t buflen)
|
||||
{
|
||||
int save_errno = errno;
|
||||
unsigned int ptyno;
|
||||
|
||||
if (!__isatty (fd))
|
||||
{
|
||||
__set_errno (ENOTTY);
|
||||
return ENOTTY;
|
||||
}
|
||||
|
||||
#ifdef TIOCGPTN
|
||||
if (__ioctl (fd, TIOCGPTN, &ptyno) == 0)
|
||||
{
|
||||
/* Buffer we use to print the number in. For a maximum size for
|
||||
@ -101,67 +72,11 @@ __ptsname_internal (int fd, char *buf, size_t buflen, struct stat64 *stp)
|
||||
|
||||
memcpy (__stpcpy (buf, devpts), p, &numbuf[sizeof (numbuf)] - p);
|
||||
}
|
||||
else if (errno != EINVAL)
|
||||
return errno;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (buflen < strlen (_PATH_TTY) + 3)
|
||||
{
|
||||
__set_errno (ERANGE);
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
if (__fxstat64 (_STAT_VER, fd, stp) < 0)
|
||||
return errno;
|
||||
|
||||
/* Check if FD really is a master pseudo terminal. */
|
||||
if (! MASTER_P (stp->st_rdev))
|
||||
{
|
||||
__set_errno (ENOTTY);
|
||||
return ENOTTY;
|
||||
}
|
||||
|
||||
ptyno = __gnu_dev_minor (stp->st_rdev);
|
||||
|
||||
if (ptyno / 16 >= strlen (__libc_ptyname1))
|
||||
{
|
||||
__set_errno (ENOTTY);
|
||||
return ENOTTY;
|
||||
}
|
||||
|
||||
p = __stpcpy (buf, _PATH_TTY);
|
||||
p[0] = __libc_ptyname1[ptyno / 16];
|
||||
p[1] = __libc_ptyname2[ptyno % 16];
|
||||
p[2] = '\0';
|
||||
}
|
||||
|
||||
if (__xstat64 (_STAT_VER, buf, stp) < 0)
|
||||
/* Bad file descriptor, or not a ptmx descriptor. */
|
||||
return errno;
|
||||
|
||||
/* Check if the name we're about to return really corresponds to a
|
||||
slave pseudo terminal. */
|
||||
if (! S_ISCHR (stp->st_mode) || ! SLAVE_P (stp->st_rdev))
|
||||
{
|
||||
/* This really is a configuration problem. */
|
||||
__set_errno (ENOTTY);
|
||||
return ENOTTY;
|
||||
}
|
||||
|
||||
__set_errno (save_errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Store at most BUFLEN characters of the pathname of the slave pseudo
|
||||
terminal associated with the master FD is open on in BUF.
|
||||
Return 0 on success, otherwise an error number. */
|
||||
int
|
||||
__ptsname_r (int fd, char *buf, size_t buflen)
|
||||
{
|
||||
struct stat64 st;
|
||||
return __ptsname_internal (fd, buf, buflen, &st);
|
||||
}
|
||||
weak_alias (__ptsname_r, ptsname_r)
|
||||
|
Loading…
Reference in New Issue
Block a user