commit 968776fbf5cd65c7ea2168912bd9f4379727eb11
Author: Guy Harris <guy@alum.mit.edu>
Date:   Tue Jul 7 11:56:48 2015 -0700

    CVE-2016-7940/Add a bunch of bounds checks, and fix some printing.
    
    The bounds checks fix some heap overflows found with American Fuzzy Lop
    by Hanno Böck.
    
    Add some ND_TTEST_/ND_TCHECK_ macros to extract.h to simplify writing
    bounds checks for code that uses the other macros in that file.
    
    Fix the printing of the SPB BPDU agreement digest - I don't think the
    intent was to print the value of the first 4 bytes, that value + 4, that
    value + 8, etc., I suspect it was to print the first 4 bytes, the next 4
    bytes, etc..

Index: tcpdump-3.9.8/print-stp.c
===================================================================
--- tcpdump-3.9.8.orig/print-stp.c
+++ tcpdump-3.9.8/print-stp.c
@@ -89,6 +89,8 @@ struct tok rstp_obj_port_role_values[] =
     { 0, NULL}
 };
 
+#define TCHECK_BRIDGE_ID(p) TCHECK2(*(p), 8)
+
 static char *
 stp_print_bridge_id(const u_char *p)
 {
@@ -101,21 +103,24 @@ stp_print_bridge_id(const u_char *p)
     return bridge_id_str;
 }
 
-static void
+static int
 stp_print_config_bpdu(const struct stp_bpdu_ *stp_bpdu, u_int length)
 {
+    TCHECK(stp_bpdu->flags);
     printf(", Flags [%s]",
            bittok2str(stp_bpdu_flag_values, "none", stp_bpdu->flags));
 
+    TCHECK(stp_bpdu->port_id);
     printf(", bridge-id %s.%04x, length %u",
            stp_print_bridge_id((const u_char *)&stp_bpdu->bridge_id),
            EXTRACT_16BITS(&stp_bpdu->port_id), length);
 
     /* in non-verbose mode just print the bridge-id */
     if (!vflag) {
-        return;
+        return 1;
     }
 
+    TCHECK(stp_bpdu->forward_delay);
     printf("\n\tmessage-age %.2fs, max-age %.2fs"
            ", hello-time %.2fs, forwarding-delay %.2fs",
            (float)EXTRACT_16BITS(&stp_bpdu->message_age) / STP_TIME_BASE,
@@ -133,6 +138,10 @@ stp_print_config_bpdu(const struct stp_b
                tok2str(rstp_obj_port_role_values, "Unknown",
                        RSTP_EXTRACT_PORT_ROLE(stp_bpdu->flags)));
     }
+    return 1;
+
+trunc:
+    return 0;
 }
 
 /*
@@ -192,7 +201,7 @@ stp_print_config_bpdu(const struct stp_b
 #define MST_BPDU_MSTI_PORT_PRIO_OFFSET	    14
 #define MST_BPDU_MSTI_REMAIN_HOPS_OFFSET    15
 
-static void
+static int
 stp_print_mstp_bpdu(const struct stp_bpdu_ *stp_bpdu, u_int length)
 {
     const u_char    *ptr;
@@ -210,14 +219,16 @@ stp_print_mstp_bpdu(const struct stp_bpd
      * of the packet (DEFAULT_SNAPLEN) to print out cist bridge-id
      */
     if (!vflag) {
-        return;
+        return 1;
     }
 
+    TCHECK(stp_bpdu->port_id);
+    TCHECK_BRIDGE_ID(ptr + MST_BPDU_CIST_BRIDGE_ID_OFFSET);
     printf(", CIST bridge-id %s.%04x, length %u",
            stp_print_bridge_id(ptr + MST_BPDU_CIST_BRIDGE_ID_OFFSET),
            EXTRACT_16BITS(&stp_bpdu->port_id), length);
 
-
+    TCHECK(stp_bpdu->forward_delay);
     printf("\n\tmessage-age %.2fs, max-age %.2fs"
            ", hello-time %.2fs, forwarding-delay %.2fs",
            (float)EXTRACT_16BITS(&stp_bpdu->message_age) / STP_TIME_BASE,
@@ -225,6 +236,8 @@ stp_print_mstp_bpdu(const struct stp_bpd
            (float)EXTRACT_16BITS(&stp_bpdu->hello_time) / STP_TIME_BASE,
            (float)EXTRACT_16BITS(&stp_bpdu->forward_delay) / STP_TIME_BASE);
 
+    TCHECK(stp_bpdu->root_path_cost);
+    TCHECK_32BITS(ptr + MST_BPDU_CIST_INT_PATH_COST_OFFSET);
     printf("\n\tCIST root-id %s, ext-pathcost %u int-pathcost %u",
            stp_print_bridge_id((const u_char *)&stp_bpdu->root_id),
            EXTRACT_32BITS(&stp_bpdu->root_path_cost),
@@ -234,9 +247,11 @@ stp_print_mstp_bpdu(const struct stp_bpd
            tok2str(rstp_obj_port_role_values, "Unknown",
                    RSTP_EXTRACT_PORT_ROLE(stp_bpdu->flags)));
 
+    TCHECK(stp_bpdu->bridge_id);
     printf("\n\tCIST regional-root-id %s",
            stp_print_bridge_id((const u_char *)&stp_bpdu->bridge_id));
 
+    TCHECK_32BITS(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 12);
     printf("\n\tMSTP Configuration Name %s, revision %u, digest %08x%08x%08x%08x",
            ptr + MST_BPDU_CONFIG_NAME_OFFSET,
 	   EXTRACT_16BITS(ptr + MST_BPDU_CONFIG_NAME_OFFSET + 32),
@@ -245,14 +260,18 @@ stp_print_mstp_bpdu(const struct stp_bpd
 	   EXTRACT_32BITS(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 8),
 	   EXTRACT_32BITS(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 12));
 
+    TCHECK(ptr[MST_BPDU_CIST_REMAIN_HOPS_OFFSET]);
     printf("\n\tCIST remaining-hops %d", ptr[MST_BPDU_CIST_REMAIN_HOPS_OFFSET]);
 
     /* Dump all MSTI's */
+    TCHECK_16BITS(ptr + MST_BPDU_VER3_LEN_OFFSET);
     v3len = EXTRACT_16BITS(ptr + MST_BPDU_VER3_LEN_OFFSET);
     if (v3len > MST_BPDU_CONFIG_INFO_LENGTH) {
         len = v3len - MST_BPDU_CONFIG_INFO_LENGTH;
         offset = MST_BPDU_MSTI_OFFSET;
         while (len >= MST_BPDU_MSTI_LENGTH) {
+	    TCHECK2(*(ptr + offset), MST_BPDU_MSTI_LENGTH);
+
             msti = EXTRACT_16BITS(ptr + offset +
                                   MST_BPDU_MSTI_ROOT_PRIO_OFFSET);
             msti = msti & 0x0FFF;
@@ -275,6 +294,10 @@ stp_print_mstp_bpdu(const struct stp_bpd
             offset += MST_BPDU_MSTI_LENGTH;
         }
     }
+    return 1;
+
+ trunc:
+    return 0;
 }
 
 /*
@@ -292,11 +315,13 @@ stp_print(const u_char *p, u_int length)
     if (length < 4)
         goto trunc;
         
+    TCHECK(stp_bpdu->protocol_id);
     if (EXTRACT_16BITS(&stp_bpdu->protocol_id)) {
         printf("unknown STP version, length %u", length);
         return;
     }
 
+    TCHECK(stp_bpdu->protocol_version);
     printf("STP %s", tok2str(stp_proto_values, "Unknown STP protocol (0x%02x)",
                          stp_bpdu->protocol_version));
 
@@ -309,6 +334,7 @@ stp_print(const u_char *p, u_int length)
         return;
     }
 
+    TCHECK(stp_bpdu->bpdu_type);
     printf(", %s", tok2str(stp_bpdu_type_values, "Unknown BPDU Type (0x%02x)",
                            stp_bpdu->bpdu_type));
 
@@ -317,7 +343,8 @@ stp_print(const u_char *p, u_int length)
         if (length < sizeof(struct stp_bpdu_) - 1) {
             goto trunc;
         }
-        stp_print_config_bpdu(stp_bpdu, length);
+	if (!stp_print_config_bpdu(stp_bpdu, length))
+	    goto trunc;
         break;
 
     case STP_BPDU_TYPE_RSTP:
@@ -325,22 +352,26 @@ stp_print(const u_char *p, u_int length)
             if (length < sizeof(struct stp_bpdu_)) {
                 goto trunc;
             }
-            stp_print_config_bpdu(stp_bpdu, length);
+	    if (!stp_print_config_bpdu(stp_bpdu, length))
+		goto trunc;
         } else if (stp_bpdu->protocol_version == STP_PROTO_MSTP) {
             if (length < STP_BPDU_MSTP_MIN_LEN) {
                 goto trunc;
             }
+	    TCHECK(stp_bpdu->v1_length);
             if (stp_bpdu->v1_length != 0) {
                 /* FIX ME: Emit a message here ? */
                 goto trunc;
             }
             /* Validate v3 length */
+	    TCHECK_16BITS(p + MST_BPDU_VER3_LEN_OFFSET);
             mstp_len = EXTRACT_16BITS(p + MST_BPDU_VER3_LEN_OFFSET);
             mstp_len += 2;  /* length encoding itself is 2 bytes */
             if (length < (sizeof(struct stp_bpdu_) + mstp_len)) {
                 goto trunc;
             }
-            stp_print_mstp_bpdu(stp_bpdu, length);
+	    if (!stp_print_mstp_bpdu(stp_bpdu, length))
+		goto trunc;
         }
         break;
 
Index: tcpdump-3.9.8/extract.h
===================================================================
--- tcpdump-3.9.8.orig/extract.h
+++ tcpdump-3.9.8/extract.h
@@ -151,3 +151,28 @@ typedef struct {
 
 #define ND_TTEST_64BITS(p) ND_TTEST2(*(p), 8)
 #define ND_TCHECK_64BITS(p) ND_TCHECK2(*(p), 8)
+
+#define TTEST_8BITS(p) TTEST2(*(p), 1)
+#define TCHECK_8BITS(p) TCHECK2(*(p), 1)
+
+#define TTEST_16BITS(p) TTEST2(*(p), 2)
+#define TCHECK_16BITS(p) TCHECK2(*(p), 2)
+
+#define TTEST_24BITS(p) TTEST2(*(p), 3)
+#define TCHECK_24BITS(p) TCHECK2(*(p), 3)
+
+#define TTEST_32BITS(p) TTEST2(*(p), 4)
+#define TCHECK_32BITS(p) TCHECK2(*(p), 4)
+
+#define TTEST_40BITS(p) TTEST2(*(p), 5)
+#define TCHECK_40BITS(p) TCHECK2(*(p), 5)
+
+#define TTEST_48BITS(p) TTEST2(*(p), 6)
+#define TCHECK_48BITS(p) TCHECK2(*(p), 6)
+
+#define TTEST_56BITS(p) TTEST2(*(p), 7)
+#define TCHECK_56BITS(p) TCHECK2(*(p), 7)
+
+#define TTEST_64BITS(p) TTEST2(*(p), 8)
+#define TCHECK_64BITS(p) TCHECK2(*(p), 8)
+
Index: tcpdump-3.9.8/print-gre.c
===================================================================
--- tcpdump-3.9.8.orig/print-gre.c
+++ tcpdump-3.9.8/print-gre.c
@@ -191,7 +191,7 @@ gre_print_0(const u_char *bp, u_int leng
 			if (af == 0 && srelen == 0)
 				break;
 
-			if (!gre_sre_print(ndo, af, sreoff, srelen, bp, len))
+			if (!gre_sre_print(af, sreoff, srelen, bp, len))
 				goto trunc;
 
 			if (len < srelen)
@@ -336,12 +336,12 @@ gre_sre_print(u_int16_t af, u_int8_t sre
 	switch (af) {
 	case GRESRE_IP:
 		printf(", (rtaf=ip");
-		ret = gre_sre_ip_print(ndo, sreoff, srelen, bp, len);
+		ret = gre_sre_ip_print(sreoff, srelen, bp, len);
 		printf(") ");
 		break;
 	case GRESRE_ASN:
 		printf(", (rtaf=asn");
-		ret = gre_sre_asn_print(ndo, sreoff, srelen, bp, len);
+		ret = gre_sre_asn_print(sreoff, srelen, bp, len);
 		printf(") ");
 		break;
 	default:
