diff options
author | Todd C. Miller <Todd.Miller@sudo.ws> | 2023-04-18 13:52:26 -0600 |
---|---|---|
committer | Todd C. Miller <Todd.Miller@sudo.ws> | 2023-04-18 13:52:26 -0600 |
commit | b7dc12f149082506ab125eb49bfc1e3a55608c2f (patch) | |
tree | 554cc6dbd48baafa7a5e2e78447734a3f997fea8 /src/ttyname.c | |
parent | d48a3fdeef949d44c817035a85cb4b540b3b5fc4 (diff) | |
download | sudo-b7dc12f149082506ab125eb49bfc1e3a55608c2f.tar.gz |
Avoid calling isatty()/ttyname() on std{in,out,err} if not a char dev.
The user controls these fds so we should avoid calling ioctl(2) on
them unless they correspond to actual character device files.
Diffstat (limited to 'src/ttyname.c')
-rw-r--r-- | src/ttyname.c | 62 |
1 files changed, 46 insertions, 16 deletions
diff --git a/src/ttyname.c b/src/ttyname.c index 12432a507..2a5c288fc 100644 --- a/src/ttyname.c +++ b/src/ttyname.c @@ -185,7 +185,7 @@ get_process_ttyname(char *name, size_t namelen) /* Missing /proc/pid/psinfo file. */ for (i = STDIN_FILENO; i <= STDERR_FILENO; i++) { - if (isatty(i) && fstat(i, &sb) != -1) { + if (sudo_isatty(i, &sb)) { ret = sudo_ttyname_dev(sb.st_rdev, name, namelen); goto done; } @@ -286,7 +286,7 @@ get_process_ttyname(char *name, size_t namelen) /* No parent pid found, /proc/self/stat is missing or corrupt. */ for (i = STDIN_FILENO; i <= STDERR_FILENO; i++) { - if (isatty(i) && fstat(i, &sb) != -1) { + if (sudo_isatty(i, &sb)) { ret = sudo_ttyname_dev(sb.st_rdev, name, namelen); goto done; } @@ -347,25 +347,55 @@ done: char * get_process_ttyname(char *name, size_t namelen) { + struct stat sb; char *tty; + int i; debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL); - if ((tty = ttyname(STDIN_FILENO)) == NULL) { - if ((tty = ttyname(STDOUT_FILENO)) == NULL) - tty = ttyname(STDERR_FILENO); - } - if (tty != NULL) { - if (strlcpy(name, tty, namelen) < namelen) - debug_return_str(name); - errno = ERANGE; - sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, - "unable to store tty from ttyname"); - } else { - sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, - "unable to resolve tty via ttyname"); - errno = ENOENT; + for (i = STDIN_FILENO; i <= STDERR_FILENO; i++) { + /* Only call ttyname() on a character special device. */ + if (fstat(i, &sb) == -1 || !S_ISCHR(sb.st_mode)) + continue; + if ((tty = ttyname(i)) == NULL) + continue; + + if (strlcpy(name, tty, namelen) >= namelen) { + errno = ENAMETOOLONG; + sudo_debug_printf( + SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "unable to store tty from ttyname"); + debug_return_str(NULL); + } + debug_return_str(name); } + sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, + "unable to resolve tty via ttyname"); + errno = ENOENT; debug_return_str(NULL); } #endif + +/* + * Like isatty(3) but stats the fd and stores the result in sb. + * Only calls isatty(3) if fd is a character special device. + * Returns true if a tty, else returns false and sets errno. + */ +bool +sudo_isatty(int fd, struct stat *sb) +{ + bool ret = false; + debug_decl(sudo_isatty, SUDO_DEBUG_EXEC); + + if (fstat(fd, sb) == 0) { + if (!S_ISCHR(sb->st_mode)) { + errno = ENOTTY; + } else { + ret = isatty(fd) == 1; + } + } else { + /* Always initialize sb. */ + memset(sb, 0, sizeof(*sb)); + } + debug_return_bool(ret); +} |