commit d07e352f5a8a9cbf7e8f3ed49a316ed906353fd8
Author: Guy Harris <guy@alum.mit.edu>
Date:   Sat Aug 8 12:53:36 2015 -0700

    CVE-2016-7993/Clean up relative time stamp printing.
    
    Have separate routines for signed and unsigned relative time stamps.
    Have the routine for signed time stamps handle the case of -2^31, where
    you can't negate it and have the result fit in a 32-bit signed integer.
    
    There are currently no users of the signed relative time stamp routine,
    but it's there in case anybody needs it (and is passing 32-bit
    quantitites, so that there's a risk that a packet might contain -2^31 as
    the time stamp).
    
    Fixes an array overflow found with American Fuzzy Lop by Hanno Böck.

Index: tcpdump-3.9.8/print-dvmrp.c
===================================================================
--- tcpdump-3.9.8.orig/print-dvmrp.c
+++ tcpdump-3.9.8/print-dvmrp.c
@@ -342,7 +342,7 @@ print_prune(register const u_char *bp)
 	printf(" src %s grp %s", ipaddr_string(bp), ipaddr_string(bp + 4));
 	bp += 8;
 	(void)printf(" timer ");
-	relts_print(EXTRACT_32BITS(bp));
+	unsigned_relts_print(EXTRACT_32BITS(bp));
 	return (0);
 trunc:
 	return (-1);
Index: tcpdump-3.9.8/print-hsrp.c
===================================================================
--- tcpdump-3.9.8.orig/print-hsrp.c
+++ tcpdump-3.9.8/print-hsrp.c
@@ -122,9 +122,9 @@ hsrp_print(register const u_int8_t *bp,
 	printf("addr=%s", ipaddr_string(&hp->hsrp_virtaddr));
 	if (vflag) {
 		printf(" hellotime=");
-		relts_print(hp->hsrp_hellotime);
+		unsigned_relts_print(hp->hsrp_hellotime);
 		printf(" holdtime=");
-		relts_print(hp->hsrp_holdtime);
+		unsigned_relts_print(hp->hsrp_holdtime);
 		printf(" priority=%d", hp->hsrp_priority);
 		printf(" auth=\"");
 		if (fn_printn(hp->hsrp_authdata, sizeof(hp->hsrp_authdata),
Index: tcpdump-3.9.8/print-igmp.c
===================================================================
--- tcpdump-3.9.8.orig/print-igmp.c
+++ tcpdump-3.9.8/print-igmp.c
@@ -208,7 +208,7 @@ static void
 print_igmpv3_query(register const u_char *bp, register u_int len)
 {
     u_int mrc;
-    int mrt;
+    u_int mrt;
     u_int nsrcs;
     register u_int i;
 
@@ -227,7 +227,7 @@ print_igmpv3_query(register const u_char
     }
     if (mrc != 100) {
 	(void)printf(" [max resp time ");
-	relts_print(mrt);
+	unsigned_relts_print(mrt / 10);
 	(void)printf("]");
     }
     TCHECK2(bp[4], 4);
Index: tcpdump-3.9.8/print-lwres.c
===================================================================
--- tcpdump-3.9.8.orig/print-lwres.c
+++ tcpdump-3.9.8/print-lwres.c
@@ -547,7 +547,7 @@ lwres_print(register const u_char *bp, u
 				    EXTRACT_16BITS(&grbn->rdclass)));
 			}
 			printf(" TTL ");
-			relts_print(EXTRACT_32BITS(&grbn->ttl));
+			unsigned_relts_print(EXTRACT_32BITS(&grbn->ttl));
 			printf(" %u/%u", EXTRACT_16BITS(&grbn->nrdatas),
 			    EXTRACT_16BITS(&grbn->nsigs));
 
Index: tcpdump-3.9.8/print-pim.c
===================================================================
--- tcpdump-3.9.8.orig/print-pim.c
+++ tcpdump-3.9.8/print-pim.c
@@ -135,7 +135,7 @@ pimv1_join_prune_print(register const u_
 		hold = EXTRACT_16BITS(&bp[6]);
 		if (hold != 180) {
 			(void)printf("Hold ");
-			relts_print(hold);
+			unsigned_relts_print(hold);
 		}
 		(void)printf("%s (%s/%d, %s", njoin ? "Join" : "Prune",
 		ipaddr_string(&bp[26]), bp[25] & 0x3f,
@@ -157,7 +157,7 @@ pimv1_join_prune_print(register const u_
 	if (vflag > 1)
 		(void)printf("\n");
 	(void)printf(" Hold time: ");
-	relts_print(EXTRACT_16BITS(&bp[6]));
+	unsigned_relts_print(EXTRACT_16BITS(&bp[6]));
 	if (vflag < 2)
 		return;
 	bp += 8;
@@ -243,7 +243,7 @@ pimv1_print(register const u_char *bp, r
 		if (vflag) {
 			TCHECK2(bp[10],2);
 			(void)printf(" (Hold-time ");
-			relts_print(EXTRACT_16BITS(&bp[10]));
+			unsigned_relts_print(EXTRACT_16BITS(&bp[10]));
 			(void)printf(")");
 		}
 		break;
@@ -274,7 +274,7 @@ pimv1_print(register const u_char *bp, r
 			if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
 				(void)printf("/%s", ipaddr_string(&bp[12]));
 			(void)printf(" RP %s hold ", ipaddr_string(&bp[16]));
-			relts_print(EXTRACT_16BITS(&bp[22]));
+			unsigned_relts_print(EXTRACT_16BITS(&bp[22]));
 		}
 		break;
 	case 5:
@@ -351,7 +351,7 @@ cisco_autorp_print(register const u_char
 	(void)printf(" Hold ");
 	hold = EXTRACT_16BITS(&bp[2]);
 	if (hold)
-		relts_print(EXTRACT_16BITS(&bp[2]));
+		unsigned_relts_print(EXTRACT_16BITS(&bp[2]));
 	else
 		printf("FOREVER");
 
@@ -662,7 +662,7 @@ pimv2_print(register const u_char *bp, r
 
 			switch (otype) {
 			case PIMV2_HELLO_OPTION_HOLDTIME:
-                                relts_print(EXTRACT_16BITS(bp));
+				unsigned_relts_print(EXTRACT_16BITS(bp));
                                 break;
 
 			case PIMV2_HELLO_OPTION_LANPRUNEDELAY:
@@ -703,7 +703,7 @@ pimv2_print(register const u_char *bp, r
                                 (void)printf("v%d", *bp);
 				if (*(bp+1) != 0) {
                                     (void)printf(", interval ");
-                                    relts_print(*(bp+1));
+				    unsigned_relts_print(*(bp+1));
 				}
 				if (EXTRACT_16BITS(bp+2) != 0) {
                                     (void)printf(" ?0x%04x?", EXTRACT_16BITS(bp+2));
@@ -868,7 +868,7 @@ pimv2_print(register const u_char *bp, r
 			if (holdtime == 0xffff)
 				(void)printf("infinite");
 			else
-				relts_print(holdtime);
+				unsigned_relts_print(holdtime);
 		}
 		bp += 4; len -= 4;
 		for (i = 0; i < ngroup; i++) {
@@ -972,7 +972,7 @@ pimv2_print(register const u_char *bp, r
 					goto bs_done;
 				}
 				(void)printf(",holdtime=");
-				relts_print(EXTRACT_16BITS(bp));
+				unsigned_relts_print(EXTRACT_16BITS(bp));
 				if (bp + 2 >= ep) {
 					(void)printf("...)");
 					goto bs_done;
@@ -1024,7 +1024,7 @@ pimv2_print(register const u_char *bp, r
 		(void)printf(" prio=%d", bp[1]);
 		if (bp + 3 >= ep) break;
 		(void)printf(" holdtime=");
-		relts_print(EXTRACT_16BITS(&bp[2]));
+		unsigned_relts_print(EXTRACT_16BITS(&bp[2]));
 		bp += 4;
 
 		/* Encoded-Unicast-RP-Address */
@@ -1070,7 +1070,7 @@ pimv2_print(register const u_char *bp, r
 		bp += advance;
 		TCHECK2(bp[0], 2);
 		(void)printf(" TUNR ");
-		relts_print(EXTRACT_16BITS(bp));
+		unsigned_relts_print(EXTRACT_16BITS(bp));
 		break;
 
 
Index: tcpdump-3.9.8/interface.h
===================================================================
--- tcpdump-3.9.8.orig/interface.h
+++ tcpdump-3.9.8/interface.h
@@ -137,7 +137,8 @@ extern int32_t thiszone;	/* seconds offs
 #define TCHECK(var) TCHECK2(var, sizeof(var))
 
 extern void ts_print(const struct timeval *);
-extern void relts_print(int);
+extern void signed_relts_print(int32_t);
+extern void unsigned_relts_print(uint32_t);
 
 extern int fn_print(const u_char *, const u_char *);
 extern u_int fn_printztn(const u_char *, u_int, const u_char *);
Index: tcpdump-3.9.8/util.c
===================================================================
--- tcpdump-3.9.8.orig/util.c
+++ tcpdump-3.9.8/util.c
@@ -257,26 +257,68 @@ ts_print(register const struct timeval *
 }
 
 /*
- * Print a relative number of seconds (e.g. hold time, prune timer)
+ * Print a signed relative number of seconds (e.g. hold time, prune timer)
  * in the form 5m1s.  This does no truncation, so 32230861 seconds
  * is represented as 1y1w1d1h1m1s.
  */
 void
-relts_print(int secs)
+signed_relts_print(int32_t secs)
 {
+	uint32_t secs_abs;
 	static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
-	static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
+	static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
 	const char **l = lengths;
-	const int *s = seconds;
+	const u_int *s = seconds;
 
 	if (secs == 0) {
 		(void)printf("0s");
 		return;
 	}
+	if (secs == -2147483648) {
+		/*
+		 * -2^31; you can't fit its absolute value into a 32-bit
+		 * signed integer.
+		 *
+		 * We calculate the right string by hand.
+		 */
+		printf("-68y5w3h14m8s");
+		return;
+	}
 	if (secs < 0) {
+		/*
+		 * We now know -secs will fit into secs.
+		 */
 		(void)printf("-");
 		secs = -secs;
 	}
+	secs_abs = secs;
+	while (secs_abs > 0) {
+		if (secs_abs >= *s) {
+			printf("%d%s", secs_abs / *s, *l);
+			secs_abs -= (secs_abs / *s) * *s;
+		}
+		s++;
+		l++;
+	}
+}
+
+/*
+ * Print an unsigned relative number of seconds (e.g. hold time, prune timer)
+ * in the form 5m1s.  This does no truncation, so 32230861 seconds
+ * is represented as 1y1w1d1h1m1s.
+ */
+void
+unsigned_relts_print(uint32_t secs)
+{
+	static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
+	static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
+	const char **l = lengths;
+	const u_int *s = seconds;
+
+	if (secs == 0) {
+		printf("0s");
+		return;
+	}
 	while (secs > 0) {
 		if (secs >= *s) {
 			(void)printf("%d%s", secs / *s, *l);
