summaryrefslogtreecommitdiff
path: root/debian/patches/CVE-2017-1000368.diff
blob: 593dea3495635e2d31b746531e974acf8485ce11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

# HG changeset patch
# User Todd C. Miller <Todd.Miller@courtesan.com>
# Date 1496243671 21600
# Node ID 15a46f4007dde8e819dd2c70e670a529bbb9d312
# Parent  6f3d9816541ba84055ae5aec6ff9d9523c2a96f3
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!).

diff -r 6f3d9816541b -r 15a46f4007dd src/ttyname.c
--- a/src/ttyname.c	Tue May 30 10:44:11 2017 -0600
+++ b/src/ttyname.c	Wed May 31 09:14:31 2017 -0600
@@ -452,25 +452,37 @@
 get_process_ttyname(char *name, size_t namelen)
 {
     const char path[] = "/proc/self/stat";
-    char *line = NULL;
+    char *cp, buf[1024];
     char *ret = NULL;
-    size_t linesize = 0;
     int serrno = errno;
-    ssize_t len;
-    FILE *fp;
+    ssize_t nread;
+    int fd;
     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) {
-	len = getline(&line, &linesize, fp);
-	fclose(fp);
-	if (len != -1) {
+    /*
+     * Try to determine the tty from tty_nr in /proc/self/stat.
+     * Ignore /proc/self/stat if it contains embedded NUL bytes.
+     */
+    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).
-	     * Since the process name at field 2 "(comm)" may include spaces,
-	     * start at the last ')' found.
+	     * Since the process name at field 2 "(comm)" may include
+	     * whitespace (including newlines), start at the last ')' found.
 	     */
-	    char *cp = strrchr(line, ')');
+	    *cp = '\0';
+	    cp = strrchr(buf, ')');
 	    if (cp != NULL) {
 		char *ep = cp;
 		const char *errstr;
@@ -501,7 +513,8 @@
     errno = ENOENT;
 
 done:
-    free(line);
+    if (fd != -1)
+	close(fd);
     if (ret == NULL)
 	sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
 	    "unable to resolve tty via %s", path);