From a2200990356bf273594d0f0a066ffc6911e7e0ca Mon Sep 17 00:00:00 2001
From: Guy Harris <guy@alum.mit.edu>
Date: Wed, 15 Mar 2017 12:12:21 -0700
Subject: [PATCH 062/128] CVE-2017-13011/Properly check for buffer overflow in
 bittok2str_internal().

Also, make the buffer bigger.

This fixes a buffer overflow discovered by Bhargava Shastry,
SecT/TU Berlin.

Add a test using the capture file supplied by the reporter(s), modified
so the capture file won't be rejected as an invalid capture.
---
 tests/TESTLIST       |   3 +++
 tests/lldp_asan.out  |  14 ++++++++++++++
 tests/lldp_asan.pcap | Bin 0 -> 94 bytes
 util-print.c         |  23 ++++++++++++++++++-----
 4 files changed, 35 insertions(+), 5 deletions(-)
 create mode 100644 tests/lldp_asan.out
 create mode 100644 tests/lldp_asan.pcap

Index: tcpdump-3.9.8/util.c
===================================================================
--- tcpdump-3.9.8.orig/util.c
+++ tcpdump-3.9.8/util.c
@@ -393,47 +393,67 @@ tok2str(register const struct tok *lp, r
 
 /*
  * Convert a bit token value to a string; use "fmt" if not found.
- * this is useful for parsing bitfields, the output strings are comma seperated
+ * this is useful for parsing bitfields, the output strings are separated
+ * if the s field is positive.
  */
-char *
-bittok2str(register const struct tok *lp, register const char *fmt,
-	   register int v)
+static char *
+bittok2str_internal(register const struct tok *lp, register const char *fmt,
+		    register u_int v, const char *sep)
 {
-        static char buf[256]; /* our stringbuffer */
-        int buflen=0;
-        register int rotbit; /* this is the bit we rotate through all bitpositions */
-        register int tokval;
-
-	while (lp->s != NULL && lp != NULL) {
-            tokval=lp->v;   /* load our first value */
-            rotbit=1;
-            while (rotbit != 0) {
-                /*
-                 * lets AND the rotating bit with our token value
-                 * and see if we have got a match
-                 */
-		if (tokval == (v&rotbit)) {
-                    /* ok we have found something */
-                    buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s, ",lp->s);
-                    break;
-                }
-                rotbit=rotbit<<1; /* no match - lets shift and try again */
-            }
-            lp++;
+        static char buf[1024+1]; /* our string buffer */
+        char *bufp = buf;
+        size_t space_left = sizeof(buf), string_size;
+        register u_int rotbit; /* this is the bit we rotate through all bitpositions */
+        register u_int tokval;
+        const char * sepstr = "";
+	
+	while (lp != NULL && lp->s != NULL) {
+		tokval=lp->v;   /* load our first value */
+		rotbit=1;
+		while (rotbit != 0) {
+			/*
+			 * lets AND the rotating bit with our token value
+			 * and see if we have got a match
+			 */
+			if (tokval == (v&rotbit)) {
+				/* ok we have found something */
+				if (space_left <= 1)
+					return (buf); /* only enough room left for NUL, if that */
+				string_size = strlcpy(bufp, sepstr, space_left);
+				if (string_size >= space_left)
+					return (buf);    /* we ran out of room */
+				bufp += string_size;
+				space_left -= string_size;
+				if (space_left <= 1)
+					return (buf); /* only enough room left for NUL, if that */
+				string_size = strlcpy(bufp, lp->s, space_left);
+				if (string_size >= space_left)
+					return (buf);    /* we ran out of room */
+				bufp += string_size;
+				space_left -= string_size;
+				sepstr = sep;
+				break;
+			}
+			rotbit=rotbit<<1; /* no match - lets shift and try again */
+		}
+		lp++;
 	}
 
-        if (buflen != 0) { /* did we find anything */
-            /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */
-            buf[buflen-2] = '\0';
-            return (buf);
-        }
-        else {
-            /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
-            if (fmt == NULL)
-		fmt = "#%d";
-            (void)snprintf(buf, sizeof(buf), fmt, v);
-            return (buf);
-        }
+        if (bufp == buf)
+		/* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
+		(void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
+        return (buf);
+}
+
+/*
+ * Convert a bit token value to a string; use "fmt" if not found.
+ * this is useful for parsing bitfields, the output strings are comma seperated.
+ */
+char *
+bittok2str(register const struct tok *lp, register const char *fmt,
+           register int v)
+{
+	return (bittok2str_internal(lp, fmt, v, ", "));
 }
 
 /*
