A command name may also contain newline characters so read
/proc/self/stat until EOF. It is not legal for /proc/self/stat to contain embedded NUL bytes so treat the file as corrupt if we see any. With help from Qualys. This is not exploitable due to the /dev traversal changes in sudo 1.8.20p1 (thanks Solar!).
This commit is contained in:
@@ -456,25 +456,37 @@ char *
|
|||||||
get_process_ttyname(char *name, size_t namelen)
|
get_process_ttyname(char *name, size_t namelen)
|
||||||
{
|
{
|
||||||
const char path[] = "/proc/self/stat";
|
const char path[] = "/proc/self/stat";
|
||||||
char *line = NULL;
|
char *cp, buf[1024];
|
||||||
char *ret = NULL;
|
char *ret = NULL;
|
||||||
size_t linesize = 0;
|
|
||||||
int serrno = errno;
|
int serrno = errno;
|
||||||
ssize_t len;
|
ssize_t nread;
|
||||||
FILE *fp;
|
int fd;
|
||||||
debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL)
|
debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
/* Try to determine the tty from tty_nr in /proc/self/stat. */
|
/*
|
||||||
if ((fp = fopen(path, "r")) != NULL) {
|
* Try to determine the tty from tty_nr in /proc/self/stat.
|
||||||
len = getline(&line, &linesize, fp);
|
* Ignore /proc/self/stat if it contains embedded NUL bytes.
|
||||||
fclose(fp);
|
*/
|
||||||
if (len != -1) {
|
if ((fd = open(path, O_RDONLY | O_NOFOLLOW)) != -1) {
|
||||||
|
cp = buf;
|
||||||
|
while ((nread = read(fd, cp, buf + sizeof(buf) - cp)) != 0) {
|
||||||
|
if (nread == -1) {
|
||||||
|
if (errno == EAGAIN || errno == EINTR)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cp += nread;
|
||||||
|
if (cp >= buf + sizeof(buf))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nread == 0 && memchr(buf, '\0', cp - buf) == NULL) {
|
||||||
/*
|
/*
|
||||||
* Field 7 is the tty dev (0 if no tty).
|
* Field 7 is the tty dev (0 if no tty).
|
||||||
* Since the process name at field 2 "(comm)" may include spaces,
|
* Since the process name at field 2 "(comm)" may include
|
||||||
* start at the last ')' found.
|
* whitespace (including newlines), start at the last ')' found.
|
||||||
*/
|
*/
|
||||||
char *cp = strrchr(line, ')');
|
*cp = '\0';
|
||||||
|
cp = strrchr(buf, ')');
|
||||||
if (cp != NULL) {
|
if (cp != NULL) {
|
||||||
char *ep = cp;
|
char *ep = cp;
|
||||||
const char *errstr;
|
const char *errstr;
|
||||||
@@ -505,7 +517,8 @@ get_process_ttyname(char *name, size_t namelen)
|
|||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
free(line);
|
if (fd != -1)
|
||||||
|
close(fd);
|
||||||
if (ret == NULL)
|
if (ret == NULL)
|
||||||
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
"unable to resolve tty via %s", path);
|
"unable to resolve tty via %s", path);
|
||||||
|
Reference in New Issue
Block a user