]> The Tcpdump Group git mirrors - tcpdump/commitdiff
CVE-2016-7939/Add some bounds checks.
authorGuy Harris <[email protected]>
Fri, 3 Jul 2015 22:16:20 +0000 (15:16 -0700)
committerFrancois-Xavier Le Bail <[email protected]>
Wed, 18 Jan 2017 08:16:36 +0000 (09:16 +0100)
Fixes heap overflows found with American Fuzzy Lop by Hanno Böck.

print-gre.c
tests/TESTLIST
tests/gre-heapoverflow-1.out [new file with mode: 0644]
tests/gre-heapoverflow-1.pcap [new file with mode: 0644]
tests/gre-heapoverflow-2.out [new file with mode: 0644]
tests/gre-heapoverflow-2.pcap [new file with mode: 0644]

index f2aec3d3a987fbf556007c636e6b07834c9986ce..d739e03833c6a8b472dc28d4e5b2ff3ad58daf85 100644 (file)
@@ -80,19 +80,18 @@ static const struct tok gre_flag_values[] = {
 
 static void gre_print_0(netdissect_options *, const u_char *, u_int);
 static void gre_print_1(netdissect_options *, const u_char *, u_int);
-static void gre_sre_print(netdissect_options *, uint16_t, uint8_t, uint8_t, const u_char *, u_int);
-static void gre_sre_ip_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
-static void gre_sre_asn_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
+static int gre_sre_print(netdissect_options *, uint16_t, uint8_t, uint8_t, const u_char *, u_int);
+static int gre_sre_ip_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
+static int gre_sre_asn_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
 
 void
 gre_print(netdissect_options *ndo, const u_char *bp, u_int length)
 {
        u_int len = length, vers;
 
-       if (len < 2) {
-               ND_PRINT((ndo, "%s", tstr));
-               return;
-       }
+       ND_TCHECK2(*bp, 2);
+       if (len < 2)
+               goto trunc;
        vers = EXTRACT_16BITS(bp) & GRE_VERS_MASK;
         ND_PRINT((ndo, "GREv%u",vers));
 
@@ -107,6 +106,11 @@ gre_print(netdissect_options *ndo, const u_char *bp, u_int length)
             ND_PRINT((ndo, " ERROR: unknown-version"));
             break;
         }
+        return;
+
+trunc:
+       ND_PRINT((ndo, "%s", tstr));
+       return;
 }
 
 static void
@@ -123,6 +127,7 @@ gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length)
        len -= 2;
        bp += 2;
 
+       ND_TCHECK2(*bp, 2);
        if (len < 2)
                goto trunc;
        prot = EXTRACT_16BITS(bp);
@@ -130,6 +135,7 @@ gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length)
        bp += 2;
 
        if ((flags & GRE_CP) | (flags & GRE_RP)) {
+               ND_TCHECK2(*bp, 2);
                if (len < 2)
                        goto trunc;
                if (ndo->ndo_vflag)
@@ -137,6 +143,7 @@ gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length)
                bp += 2;
                len -= 2;
 
+               ND_TCHECK2(*bp, 2);
                if (len < 2)
                        goto trunc;
                ND_PRINT((ndo, ", off 0x%x", EXTRACT_16BITS(bp)));
@@ -145,6 +152,7 @@ gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length)
        }
 
        if (flags & GRE_KP) {
+               ND_TCHECK2(*bp, 4);
                if (len < 4)
                        goto trunc;
                ND_PRINT((ndo, ", key=0x%x", EXTRACT_32BITS(bp)));
@@ -153,6 +161,7 @@ gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length)
        }
 
        if (flags & GRE_SP) {
+               ND_TCHECK2(*bp, 4);
                if (len < 4)
                        goto trunc;
                ND_PRINT((ndo, ", seq %u", EXTRACT_32BITS(bp)));
@@ -166,6 +175,7 @@ gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length)
                        uint8_t sreoff;
                        uint8_t srelen;
 
+                       ND_TCHECK2(*bp, 4);
                        if (len < 4)
                                goto trunc;
                        af = EXTRACT_16BITS(bp);
@@ -177,7 +187,8 @@ gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length)
                        if (af == 0 && srelen == 0)
                                break;
 
-                       gre_sre_print(ndo, af, sreoff, srelen, bp, len);
+                       if (!gre_sre_print(ndo, af, sreoff, srelen, bp, len))
+                               goto trunc;
 
                        if (len < srelen)
                                goto trunc;
@@ -243,6 +254,7 @@ gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length)
             ND_PRINT((ndo, ", Flags [%s]",
                    bittok2str(gre_flag_values,"none",flags)));
 
+       ND_TCHECK2(*bp, 2);
        if (len < 2)
                goto trunc;
        prot = EXTRACT_16BITS(bp);
@@ -253,6 +265,7 @@ gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length)
        if (flags & GRE_KP) {
                uint32_t k;
 
+               ND_TCHECK2(*bp, 4);
                if (len < 4)
                        goto trunc;
                k = EXTRACT_32BITS(bp);
@@ -262,6 +275,7 @@ gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length)
        }
 
        if (flags & GRE_SP) {
+               ND_TCHECK2(*bp, 4);
                if (len < 4)
                        goto trunc;
                ND_PRINT((ndo, ", seq %u", EXTRACT_32BITS(bp)));
@@ -270,6 +284,7 @@ gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length)
        }
 
        if (flags & GRE_AP) {
+               ND_TCHECK2(*bp, 4);
                if (len < 4)
                        goto trunc;
                ND_PRINT((ndo, ", ack %u", EXTRACT_32BITS(bp)));
@@ -309,27 +324,31 @@ trunc:
        ND_PRINT((ndo, "%s", tstr));
 }
 
-static void
+static int
 gre_sre_print(netdissect_options *ndo, uint16_t af, uint8_t sreoff,
     uint8_t srelen, const u_char *bp, u_int len)
 {
+       int ret;
+
        switch (af) {
        case GRESRE_IP:
                ND_PRINT((ndo, ", (rtaf=ip"));
-               gre_sre_ip_print(ndo, sreoff, srelen, bp, len);
+               ret = gre_sre_ip_print(ndo, sreoff, srelen, bp, len);
                ND_PRINT((ndo, ")"));
                break;
        case GRESRE_ASN:
                ND_PRINT((ndo, ", (rtaf=asn"));
-               gre_sre_asn_print(ndo, sreoff, srelen, bp, len);
+               ret = gre_sre_asn_print(ndo, sreoff, srelen, bp, len);
                ND_PRINT((ndo, ")"));
                break;
        default:
                ND_PRINT((ndo, ", (rtaf=0x%x)", af));
+               ret = 1;
        }
+       return (ret);
 }
 
-static void
+static int
 gre_sre_ip_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
                  const u_char *bp, u_int len)
 {
@@ -338,20 +357,22 @@ gre_sre_ip_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
 
        if (sreoff & 3) {
                ND_PRINT((ndo, ", badoffset=%u", sreoff));
-               return;
+               return (1);
        }
        if (srelen & 3) {
                ND_PRINT((ndo, ", badlength=%u", srelen));
-               return;
+               return (1);
        }
        if (sreoff >= srelen) {
                ND_PRINT((ndo, ", badoff/len=%u/%u", sreoff, srelen));
-               return;
+               return (1);
        }
 
-       for (;;) {
-               if (len < 4 || srelen == 0)
-                       return;
+       while (srelen != 0) {
+               if (!ND_TTEST2(*bp, sizeof(struct in_addr)))
+                       return (0);
+               if (len < 4)
+                       return (0);
 
                addrtostr(bp, buf, sizeof(buf));
                ND_PRINT((ndo, " %s%s",
@@ -361,9 +382,10 @@ gre_sre_ip_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
                len -= 4;
                srelen -= 4;
        }
+       return (1);
 }
 
-static void
+static int
 gre_sre_asn_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
                   const u_char *bp, u_int len)
 {
@@ -371,20 +393,22 @@ gre_sre_asn_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
 
        if (sreoff & 1) {
                ND_PRINT((ndo, ", badoffset=%u", sreoff));
-               return;
+               return (1);
        }
        if (srelen & 1) {
                ND_PRINT((ndo, ", badlength=%u", srelen));
-               return;
+               return (1);
        }
        if (sreoff >= srelen) {
                ND_PRINT((ndo, ", badoff/len=%u/%u", sreoff, srelen));
-               return;
+               return (1);
        }
 
-       for (;;) {
-               if (len < 2 || srelen == 0)
-                       return;
+       while (srelen != 0) {
+               if (!ND_TTEST2(*bp, 2))
+                       return (0);
+               if (len < 2)
+                       return (0);
 
                ND_PRINT((ndo, " %s%x",
                    ((bp - up) == sreoff) ? "*" : "",
@@ -394,4 +418,5 @@ gre_sre_asn_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
                len -= 2;
                srelen -= 2;
        }
+       return (1);
 }
index 3bab6bb9a013b180b1151c0f4b83c191c1d9961c..a406c8840d558d633cfed1df6edd6ca02da0dc0b 100644 (file)
@@ -377,3 +377,5 @@ heapoverflow-sl_if_print    heapoverflow-sl_if_print.pcap   heapoverflow-sl_if_print.
 heapoverflow-ip_print_demux    heapoverflow-ip_print_demux.pcap        heapoverflow-ip_print_demux.out -t -v -n
 heapoverflow-in_checksum       heapoverflow-in_checksum.pcap   heapoverflow-in_checksum.out    -t -v -n
 heapoverflow-tcp_print heapoverflow-tcp_print.pcap     heapoverflow-tcp_print.out      -t -v -n
+gre-heapoverflow-1     gre-heapoverflow-1.pcap gre-heapoverflow-1.out  -t -v -n
+gre-heapoverflow-2     gre-heapoverflow-2.pcap gre-heapoverflow-2.out  -t -v -n
diff --git a/tests/gre-heapoverflow-1.out b/tests/gre-heapoverflow-1.out
new file mode 100644 (file)
index 0000000..a9b7fd3
--- /dev/null
@@ -0,0 +1,9 @@
+30:30:30:30:30:30 > 30:30:30:30:30:30, ethertype Unknown (0x3030), length 808464432: 
+       0x0000:  3030 3030 3030 3030 3030 3030 3030 3030  0000000000000000
+       0x0010:  3030 3030 3030 3030 3030 3030 3030 3030  0000000000000000
+       0x0020:  3030 3030 3030 3030 3030 3030 3030 3030  0000000000000000
+       0x0030:  3030 3030 3030 3030 3030 3030 3030 3030  0000000000000000
+       0x0040:  3030 3030 3030 3030 3030 3030 3030 3030  0000000000000000
+       0x0050:  3030 3030                                0000
+IP0 (tos 0x30, ttl 48, id 12336, offset 0, flags [none], proto GRE (47), length 12336, options (unknown 48 [bad length 48]), bad cksum 3030 (->855e)!)
+    48.48.48.48 > 48.48.48.48: GREv0, Flags [checksum present, routing present, sequence# present, source routing present][|gre]
diff --git a/tests/gre-heapoverflow-1.pcap b/tests/gre-heapoverflow-1.pcap
new file mode 100644 (file)
index 0000000..369dc8d
Binary files /dev/null and b/tests/gre-heapoverflow-1.pcap differ
diff --git a/tests/gre-heapoverflow-2.out b/tests/gre-heapoverflow-2.out
new file mode 100644 (file)
index 0000000..f1ab2cc
--- /dev/null
@@ -0,0 +1,6 @@
+30:30:30:30:30:30 > 30:30:30:30:30:30, ethertype Unknown (0x3030), length 808464432: 
+       0x0000:  3030 3030 3030 3030 3030 3030 3030 3030  0000000000000000
+       0x0010:  3030 3030 3030 3030 3030 3030 3030 3030  0000000000000000
+       0x0020:  3030                                     00
+IP (tos 0x30, ttl 48, id 12336, offset 0, flags [none], proto GRE (47), length 12336, bad cksum 3030 (->697f)!)
+    48.48.48.48 > 48.48.48.48: GREv0, Flags [checksum present, routing present], sum 0x3030, off 0x3030, (rtaf=0x3030)[|gre]
diff --git a/tests/gre-heapoverflow-2.pcap b/tests/gre-heapoverflow-2.pcap
new file mode 100644 (file)
index 0000000..61483ed
Binary files /dev/null and b/tests/gre-heapoverflow-2.pcap differ