From b7efb8ab5b17aaccabe864a0f5aac1c4d0afe450 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Sat, 16 Nov 2024 08:17:51 -0700 Subject: [PATCH] sudo_ttyname_dev: On Linux try to use /proc/self/fd/{0,1,2} if possible. If one of std{in,out,err} matches the specified device, try to resolve it to a path by using /proc/self/fd/{0,1,2}. This avoids searching all of /dev and works in a chroot where /proc is mounted but /dev/pts is not. GitHub issue #421. --- lib/util/ttyname_dev.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/util/ttyname_dev.c b/lib/util/ttyname_dev.c index 2136e3de55..77ef76600d 100644 --- a/lib/util/ttyname_dev.c +++ b/lib/util/ttyname_dev.c @@ -253,11 +253,39 @@ char * sudo_ttyname_dev_v1(dev_t rdev, char *buf, size_t buflen) { const char *devsearch, *devsearch_end; - char path[PATH_MAX], *ret; + char path[PATH_MAX], *ret = NULL; const char *cp, *ep; size_t len; debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL); +#ifdef __linux__ + /* + * First check std{in,out,err} and use /proc/self/fd/{0,1,2} if possible. + */ + for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd++) { + char fdpath[] = "/proc/self/fd/N"; + struct stat sb; + + if (fstat(fd, &sb) == -1 || !S_ISCHR(sb.st_mode)) + continue; + if (rdev != sb.st_rdev) + continue; + + fdpath[sizeof("/proc/self/fd/N") - 2] = '0' + fd; + len = readlink(fdpath, buf, buflen); + if (len != (size_t)-1) { + if (len == buflen) { + errno = ERANGE; /* buf too small */ + } else { + /* readlink(2) does not NUL-terminate. */ + buf[len] = '\0'; + ret = buf; + } + goto done; + } + } +#endif + /* * First, check /dev/console. */