]> The Tcpdump Group git mirrors - tcpdump/commitdiff
CVE-2017-13030/PIM: Redo bounds checks and add length checks.
authorGuy Harris <[email protected]>
Wed, 22 Mar 2017 21:09:28 +0000 (14:09 -0700)
committerDenis Ovsienko <[email protected]>
Sun, 3 Sep 2017 23:08:58 +0000 (00:08 +0100)
Use ND_TCHECK macros to do bounds checking, and add length checks before
the bounds checks.

Add a bounds check that the review process found was missing.

This fixes a buffer over-read 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.

Update one test output file to reflect the changes.

print-pim.c
tests/TESTLIST
tests/heapoverflow-in_checksum.out
tests/pim_header_asan.out [new file with mode: 0644]
tests/pim_header_asan.pcap [new file with mode: 0644]

index ee18d958132e84d3b5e0f5afebc59fac63eb423e..b5c474694ff601fa809847371c4ad9eaabb6b66b 100644 (file)
@@ -169,20 +169,28 @@ pimv1_join_prune_print(netdissect_options *ndo,
                return;
        }
 
+       if (len < sizeof(struct in_addr))
+               goto trunc;
        ND_TCHECK2(bp[0], sizeof(struct in_addr));
        if (ndo->ndo_vflag > 1)
                ND_PRINT((ndo, "\n"));
        ND_PRINT((ndo, " Upstream Nbr: %s", ipaddr_string(ndo, bp)));
-       ND_TCHECK2(bp[6], 2);
+       bp += 4;
+       len -= 4;
+       if (len < 4)
+               goto trunc;
+       ND_TCHECK2(bp[2], 2);
        if (ndo->ndo_vflag > 1)
                ND_PRINT((ndo, "\n"));
        ND_PRINT((ndo, " Hold time: "));
-       unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[6]));
+       unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[2]));
        if (ndo->ndo_vflag < 2)
                return;
-       bp += 8;
-       len -= 8;
+       bp += 4;
+       len -= 4;
 
+       if (len < 4)
+               goto trunc;
        ND_TCHECK2(bp[0], 4);
        ngroups = bp[3];
        bp += 4;
@@ -192,17 +200,27 @@ pimv1_join_prune_print(netdissect_options *ndo,
                 * XXX - does the address have length "addrlen" and the
                 * mask length "maddrlen"?
                 */
+               if (len < 4)
+                       goto trunc;
                ND_TCHECK2(bp[0], sizeof(struct in_addr));
                ND_PRINT((ndo, "\n\tGroup: %s", ipaddr_string(ndo, bp)));
-               ND_TCHECK2(bp[4], sizeof(struct in_addr));
-               if (EXTRACT_32BITS(&bp[4]) != 0xffffffff)
-                       ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[4])));
-               ND_TCHECK2(bp[8], 4);
-               njoin = EXTRACT_16BITS(&bp[8]);
-               nprune = EXTRACT_16BITS(&bp[10]);
+               bp += 4;
+               len -= 4;
+               if (len < 4)
+                       goto trunc;
+               ND_TCHECK2(bp[0], sizeof(struct in_addr));
+               if (EXTRACT_32BITS(&bp[0]) != 0xffffffff)
+                       ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[0])));
+               bp += 4;
+               len -= 4;
+               if (len < 4)
+                       goto trunc;
+               ND_TCHECK2(bp[0], 4);
+               njoin = EXTRACT_16BITS(&bp[0]);
+               nprune = EXTRACT_16BITS(&bp[2]);
                ND_PRINT((ndo, " joined: %d pruned: %d", njoin, nprune));
-               bp += 12;
-               len -= 12;
+               bp += 4;
+               len -= 4;
                for (njp = 0; njp < (njoin + nprune); njp++) {
                        const char *type;
 
@@ -210,12 +228,15 @@ pimv1_join_prune_print(netdissect_options *ndo,
                                type = "Join ";
                        else
                                type = "Prune";
+                       if (len < 6)
+                               goto trunc;
                        ND_TCHECK2(bp[0], 6);
                        ND_PRINT((ndo, "\n\t%s %s%s%s%s/%d", type,
                            (bp[0] & 0x01) ? "Sparse " : "Dense ",
                            (bp[1] & 0x80) ? "WC " : "",
                            (bp[1] & 0x40) ? "RP " : "SPT ",
-                       ipaddr_string(ndo, &bp[2]), bp[1] & 0x3f));
+                           ipaddr_string(ndo, &bp[2]),
+                           bp[1] & 0x3f));
                        bp += 6;
                        len -= 6;
                }
@@ -230,13 +251,8 @@ void
 pimv1_print(netdissect_options *ndo,
             register const u_char *bp, register u_int len)
 {
-       register const u_char *ep;
        register u_char type;
 
-       ep = (const u_char *)ndo->ndo_snapend;
-       if (bp >= ep)
-               return;
-
        ND_TCHECK(bp[1]);
        type = bp[1];
 
@@ -302,8 +318,11 @@ pimv1_print(netdissect_options *ndo,
        case PIMV1_TYPE_JOIN_PRUNE:
        case PIMV1_TYPE_GRAFT:
        case PIMV1_TYPE_GRAFT_ACK:
-               if (ndo->ndo_vflag)
+               if (ndo->ndo_vflag) {
+                       if (len < 8)
+                               goto trunc;
                        pimv1_join_prune_print(ndo, &bp[8], len - 8);
+               }
                break;
        }
        ND_TCHECK(bp[4]);
@@ -330,6 +349,8 @@ cisco_autorp_print(netdissect_options *ndo,
        int numrps;
        int hold;
 
+       if (len < 8)
+               goto trunc;
        ND_TCHECK(bp[0]);
        ND_PRINT((ndo, " auto-rp "));
        type = bp[0];
@@ -377,10 +398,16 @@ cisco_autorp_print(netdissect_options *ndo,
                int nentries;
                char s;
 
+               if (len < 4)
+                       goto trunc;
                ND_TCHECK2(bp[0], 4);
                ND_PRINT((ndo, " RP %s", ipaddr_string(ndo, bp)));
-               ND_TCHECK(bp[4]);
-               switch (bp[4] & 0x3) {
+               bp += 4;
+               len -= 4;
+               if (len < 1)
+                       goto trunc;
+               ND_TCHECK(bp[0]);
+               switch (bp[0] & 0x3) {
                case 0: ND_PRINT((ndo, " PIMv?"));
                        break;
                case 1: ND_PRINT((ndo, " PIMv1"));
@@ -390,13 +417,20 @@ cisco_autorp_print(netdissect_options *ndo,
                case 3: ND_PRINT((ndo, " PIMv1+2"));
                        break;
                }
-               if (bp[4] & 0xfc)
-                       ND_PRINT((ndo, " [rsvd=0x%02x]", bp[4] & 0xfc));
-               ND_TCHECK(bp[5]);
-               nentries = bp[5];
-               bp += 6; len -= 6;
+               if (bp[0] & 0xfc)
+                       ND_PRINT((ndo, " [rsvd=0x%02x]", bp[0] & 0xfc));
+               bp += 1;
+               len -= 1;
+               if (len < 1)
+                       goto trunc;
+               ND_TCHECK(bp[0]);
+               nentries = bp[0];
+               bp += 1;
+               len -= 1;
                s = ' ';
                for (; nentries; nentries--) {
+                       if (len < 6)
+                               goto trunc;
                        ND_TCHECK2(bp[0], 6);
                        ND_PRINT((ndo, "%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
                                  ipaddr_string(ndo, &bp[2]), bp[1]));
@@ -421,16 +455,13 @@ void
 pim_print(netdissect_options *ndo,
           register const u_char *bp, register u_int len, const u_char *bp2)
 {
-       register const u_char *ep;
        register const struct pim *pim = (const struct pim *)bp;
 
-       ep = (const u_char *)ndo->ndo_snapend;
-       if (bp >= ep)
-               return;
 #ifdef notyet                  /* currently we see only version and type */
        ND_TCHECK(pim->pim_rsv);
 #endif
 
+       ND_TCHECK(pim->pim_typever);
        switch (PIM_VER(pim->pim_typever)) {
        case 2:
                if (!ndo->ndo_vflag) {
@@ -454,6 +485,10 @@ pim_print(netdissect_options *ndo,
                break;
        }
        return;
+
+trunc:
+       ND_PRINT((ndo, "[|pim]"));
+       return;
 }
 
 /*
@@ -496,8 +531,6 @@ pim_print(netdissect_options *ndo,
  *
  */
 
-static int pimv2_addr_len;
-
 enum pimv2_addrtype {
        pimv2_unicast, pimv2_group, pimv2_source
 };
@@ -524,23 +557,24 @@ enum pimv2_addrtype {
  */
 static int
 pimv2_addr_print(netdissect_options *ndo,
-                 const u_char *bp, enum pimv2_addrtype at, int silent)
+                 const u_char *bp, u_int len, enum pimv2_addrtype at,
+                 u_int addr_len, int silent)
 {
        int af;
-       int len, hdrlen;
+       int hdrlen;
 
-       ND_TCHECK(bp[0]);
-
-       if (pimv2_addr_len == 0) {
+       if (addr_len == 0) {
+               if (len < 2)
+                       goto trunc;
                ND_TCHECK(bp[1]);
                switch (bp[0]) {
                case 1:
                        af = AF_INET;
-                       len = sizeof(struct in_addr);
+                       addr_len = (u_int)sizeof(struct in_addr);
                        break;
                case 2:
                        af = AF_INET6;
-                       len = sizeof(struct in6_addr);
+                       addr_len = (u_int)sizeof(struct in6_addr);
                        break;
                default:
                        return -1;
@@ -549,7 +583,7 @@ pimv2_addr_print(netdissect_options *ndo,
                        return -1;
                hdrlen = 2;
        } else {
-               switch (pimv2_addr_len) {
+               switch (addr_len) {
                case sizeof(struct in_addr):
                        af = AF_INET;
                        break;
@@ -560,14 +594,16 @@ pimv2_addr_print(netdissect_options *ndo,
                        return -1;
                        break;
                }
-               len = pimv2_addr_len;
                hdrlen = 0;
        }
 
        bp += hdrlen;
+       len -= hdrlen;
        switch (at) {
        case pimv2_unicast:
-               ND_TCHECK2(bp[0], len);
+               if (len < addr_len)
+                       goto trunc;
+               ND_TCHECK2(bp[0], addr_len);
                if (af == AF_INET) {
                        if (!silent)
                                ND_PRINT((ndo, "%s", ipaddr_string(ndo, bp)));
@@ -576,10 +612,12 @@ pimv2_addr_print(netdissect_options *ndo,
                        if (!silent)
                                ND_PRINT((ndo, "%s", ip6addr_string(ndo, bp)));
                }
-               return hdrlen + len;
+               return hdrlen + addr_len;
        case pimv2_group:
        case pimv2_source:
-               ND_TCHECK2(bp[0], len + 2);
+               if (len < addr_len + 2)
+                       goto trunc;
+               ND_TCHECK2(bp[0], addr_len + 2);
                if (af == AF_INET) {
                        if (!silent) {
                                ND_PRINT((ndo, "%s", ipaddr_string(ndo, bp + 2)));
@@ -608,7 +646,7 @@ pimv2_addr_print(netdissect_options *ndo,
                                ND_PRINT((ndo, ")"));
                        }
                }
-               return hdrlen + 2 + len;
+               return hdrlen + 2 + addr_len;
        default:
                return -1;
        }
@@ -660,17 +698,23 @@ pimv2_print(netdissect_options *ndo,
        register const struct pim *pim = (const struct pim *)bp;
        int advance;
        enum checksum_status cksum_status;
+       int pimv2_addr_len;
 
        ep = (const u_char *)ndo->ndo_snapend;
        if (bp >= ep)
                return;
        if (ep > bp + len)
                ep = bp + len;
+       if (len < 2)
+               goto trunc;
        ND_TCHECK(pim->pim_rsv);
        pimv2_addr_len = pim->pim_rsv;
        if (pimv2_addr_len != 0)
                ND_PRINT((ndo, ", RFC2117-encoding"));
 
+       if (len < 4)
+               goto trunc;
+       ND_TCHECK(pim->pim_cksum);
        ND_PRINT((ndo, ", cksum 0x%04x ", EXTRACT_16BITS(&pim->pim_cksum)));
        if (EXTRACT_16BITS(&pim->pim_cksum) == 0) {
                ND_PRINT((ndo, "(unverified)"));
@@ -711,23 +755,29 @@ pimv2_print(netdissect_options *ndo,
                        break;
                }
        }
+       bp += 4;
+       len -= 4;
 
        switch (PIM_TYPE(pim->pim_typever)) {
        case PIMV2_TYPE_HELLO:
            {
                uint16_t otype, olen;
-               bp += 4;
-               while (bp < ep) {
+               while (len > 0) {
+                       if (len < 4)
+                               goto trunc;
                        ND_TCHECK2(bp[0], 4);
                        otype = EXTRACT_16BITS(&bp[0]);
                        olen = EXTRACT_16BITS(&bp[2]);
-                       ND_TCHECK2(bp[0], 4 + olen);
                        ND_PRINT((ndo, "\n\t  %s Option (%u), length %u, Value: ",
                                  tok2str(pimv2_hello_option_values, "Unknown", otype),
                                  otype,
                                  olen));
                        bp += 4;
+                       len -= 4;
 
+                       if (len < olen)
+                               goto trunc;
+                       ND_TCHECK2(bp[0], olen);
                        switch (otype) {
                        case PIMV2_HELLO_OPTION_HOLDTIME:
                                if (olen != 2) {
@@ -797,14 +847,14 @@ pimv2_print(netdissect_options *ndo,
                        case PIMV2_HELLO_OPTION_ADDRESS_LIST:
                                if (ndo->ndo_vflag > 1) {
                                        const u_char *ptr = bp;
+                                       u_int plen = len;
                                        while (ptr < (bp+olen)) {
                                                ND_PRINT((ndo, "\n\t    "));
-                                               advance = pimv2_addr_print(ndo, ptr, pimv2_unicast, 0);
-                                               if (advance < 0) {
-                                                       ND_PRINT((ndo, "..."));
-                                                       break;
-                                               }
+                                               advance = pimv2_addr_print(ndo, ptr, plen, pimv2_unicast, pimv2_addr_len, 0);
+                                               if (advance < 0)
+                                                       goto trunc;
                                                ptr += advance;
+                                               plen -= advance;
                                        }
                                }
                                break;
@@ -817,6 +867,7 @@ pimv2_print(netdissect_options *ndo,
                        if (ndo->ndo_vflag> 1)
                                print_unknown_data(ndo, bp, "\n\t    ", olen);
                        bp += olen;
+                       len -= olen;
                }
                break;
            }
@@ -825,18 +876,24 @@ pimv2_print(netdissect_options *ndo,
        {
                const struct ip *ip;
 
-               ND_TCHECK2(*(bp + 4), PIMV2_REGISTER_FLAG_LEN);
+               if (len < 4)
+                       goto trunc;
+               ND_TCHECK2(*bp, PIMV2_REGISTER_FLAG_LEN);
 
                ND_PRINT((ndo, ", Flags [ %s ]\n\t",
                          tok2str(pimv2_register_flag_values,
                          "none",
-                         EXTRACT_32BITS(bp+4))));
+                         EXTRACT_32BITS(bp))));
 
-               bp += 8; len -= 8;
+               bp += 4; len -= 4;
                /* encapsulated multicast packet */
+               if (len == 0)
+                       goto trunc;
                ip = (const struct ip *)bp;
+               ND_TCHECK(ip->ip_vhl);
                switch (IP_V(ip)) {
                 case 0: /* Null header */
+                       ND_TCHECK(ip->ip_dst);
                        ND_PRINT((ndo, "IP-Null-header %s > %s",
                                  ipaddr_string(ndo, &ip->ip_src),
                                  ipaddr_string(ndo, &ip->ip_dst)));
@@ -858,22 +915,13 @@ pimv2_print(netdissect_options *ndo,
        }
 
        case PIMV2_TYPE_REGISTER_STOP:
-               bp += 4; len -= 4;
-               if (bp >= ep)
-                       break;
                ND_PRINT((ndo, " group="));
-               if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0)) < 0) {
-                       ND_PRINT((ndo, "..."));
-                       break;
-               }
+               if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
+                       goto trunc;
                bp += advance; len -= advance;
-               if (bp >= ep)
-                       break;
                ND_PRINT((ndo, " source="));
-               if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-                       ND_PRINT((ndo, "..."));
-                       break;
-               }
+               if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+                       goto trunc;
                bp += advance; len -= advance;
                break;
 
@@ -924,19 +972,15 @@ pimv2_print(netdissect_options *ndo,
                uint16_t nprune;
                int i, j;
 
-               bp += 4; len -= 4;
                if (PIM_TYPE(pim->pim_typever) != 7) {  /*not for Graft-ACK*/
-                       if (bp >= ep)
-                               break;
                        ND_PRINT((ndo, ", upstream-neighbor: "));
-                       if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-                               ND_PRINT((ndo, "..."));
-                               break;
-                       }
+                       if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+                               goto trunc;
                        bp += advance; len -= advance;
                }
-               if (bp + 4 > ep)
-                       break;
+               if (len < 4)
+                       goto trunc;
+               ND_TCHECK2(*bp, 4);
                ngroup = bp[1];
                holdtime = EXTRACT_16BITS(&bp[2]);
                ND_PRINT((ndo, "\n\t  %u group(s)", ngroup));
@@ -949,139 +993,125 @@ pimv2_print(netdissect_options *ndo,
                }
                bp += 4; len -= 4;
                for (i = 0; i < ngroup; i++) {
-                       if (bp >= ep)
-                               goto jp_done;
                        ND_PRINT((ndo, "\n\t    group #%u: ", i+1));
-                       if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0)) < 0) {
-                               ND_PRINT((ndo, "...)"));
-                               goto jp_done;
-                       }
+                       if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
+                               goto trunc;
                        bp += advance; len -= advance;
-                       if (bp + 4 > ep) {
-                               ND_PRINT((ndo, "...)"));
-                               goto jp_done;
-                       }
+                       if (len < 4)
+                               goto trunc;
+                       ND_TCHECK2(*bp, 4);
                        njoin = EXTRACT_16BITS(&bp[0]);
                        nprune = EXTRACT_16BITS(&bp[2]);
                        ND_PRINT((ndo, ", joined sources: %u, pruned sources: %u", njoin, nprune));
                        bp += 4; len -= 4;
                        for (j = 0; j < njoin; j++) {
                                ND_PRINT((ndo, "\n\t      joined source #%u: ", j+1));
-                               if ((advance = pimv2_addr_print(ndo, bp, pimv2_source, 0)) < 0) {
-                                       ND_PRINT((ndo, "...)"));
-                                       goto jp_done;
-                               }
+                               if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
+                                       goto trunc;
                                bp += advance; len -= advance;
                        }
                        for (j = 0; j < nprune; j++) {
                                ND_PRINT((ndo, "\n\t      pruned source #%u: ", j+1));
-                               if ((advance = pimv2_addr_print(ndo, bp, pimv2_source, 0)) < 0) {
-                                       ND_PRINT((ndo, "...)"));
-                                       goto jp_done;
-                               }
+                               if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
+                                       goto trunc;
                                bp += advance; len -= advance;
                        }
                }
-       jp_done:
                break;
            }
 
        case PIMV2_TYPE_BOOTSTRAP:
        {
                int i, j, frpcnt;
-               bp += 4;
 
                /* Fragment Tag, Hash Mask len, and BSR-priority */
-               if (bp + sizeof(uint16_t) >= ep) break;
+               if (len < 2)
+                       goto trunc;
+               ND_TCHECK_16BITS(bp);
                ND_PRINT((ndo, " tag=%x", EXTRACT_16BITS(bp)));
-               bp += sizeof(uint16_t);
-               if (bp >= ep) break;
+               bp += 2;
+               len -= 2;
+               if (len < 1)
+                       goto trunc;
+               ND_TCHECK(bp[0]);
                ND_PRINT((ndo, " hashmlen=%d", bp[0]));
-               if (bp + 1 >= ep) break;
+               if (len < 2)
+                       goto trunc;
+               ND_TCHECK(bp[2]);
                ND_PRINT((ndo, " BSRprio=%d", bp[1]));
                bp += 2;
+               len -= 2;
 
                /* Encoded-Unicast-BSR-Address */
-               if (bp >= ep) break;
                ND_PRINT((ndo, " BSR="));
-               if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-                       ND_PRINT((ndo, "..."));
-                       break;
-               }
+               if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+                       goto trunc;
                bp += advance;
+               len -= advance;
 
                for (i = 0; bp < ep; i++) {
                        /* Encoded-Group Address */
                        ND_PRINT((ndo, " (group%d: ", i));
-                       if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0))
-                           < 0) {
-                               ND_PRINT((ndo, "...)"));
-                               goto bs_done;
-                       }
+                       if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
+                               goto trunc;
                        bp += advance;
+                       len -= advance;
 
                        /* RP-Count, Frag RP-Cnt, and rsvd */
-                       if (bp >= ep) {
-                               ND_PRINT((ndo, "...)"));
-                               goto bs_done;
-                       }
+                       if (len < 1)
+                               goto trunc;
+                       ND_TCHECK(bp[0]);
                        ND_PRINT((ndo, " RPcnt=%d", bp[0]));
-                       if (bp + 1 >= ep) {
-                               ND_PRINT((ndo, "...)"));
-                               goto bs_done;
-                       }
+                       if (len < 2)
+                               goto trunc;
+                       ND_TCHECK(bp[1]);
                        ND_PRINT((ndo, " FRPcnt=%d", frpcnt = bp[1]));
+                       if (len < 4)
+                               goto trunc;
                        bp += 4;
+                       len -= 4;
 
                        for (j = 0; j < frpcnt && bp < ep; j++) {
                                /* each RP info */
                                ND_PRINT((ndo, " RP%d=", j));
-                               if ((advance = pimv2_addr_print(ndo, bp,
+                               if ((advance = pimv2_addr_print(ndo, bp, len,
                                                                pimv2_unicast,
-                                                               0)) < 0) {
-                                       ND_PRINT((ndo, "...)"));
-                                       goto bs_done;
-                               }
+                                                               pimv2_addr_len,
+                                                               0)) < 0)
+                                       goto trunc;
                                bp += advance;
+                               len -= advance;
 
-                               if (bp + 1 >= ep) {
-                                       ND_PRINT((ndo, "...)"));
-                                       goto bs_done;
-                               }
+                               if (len < 2)
+                                       goto trunc;
+                               ND_TCHECK_16BITS(bp);
                                ND_PRINT((ndo, ",holdtime="));
                                unsigned_relts_print(ndo, EXTRACT_16BITS(bp));
-                               if (bp + 2 >= ep) {
-                                       ND_PRINT((ndo, "...)"));
-                                       goto bs_done;
-                               }
+                               if (len < 3)
+                                       goto trunc;
+                               ND_TCHECK(bp[2]);
                                ND_PRINT((ndo, ",prio=%d", bp[2]));
+                               if (len < 4)
+                                       goto trunc;
                                bp += 4;
+                               len -= 4;
                        }
                        ND_PRINT((ndo, ")"));
                }
-          bs_done:
                break;
        }
        case PIMV2_TYPE_ASSERT:
-               bp += 4; len -= 4;
-               if (bp >= ep)
-                       break;
                ND_PRINT((ndo, " group="));
-               if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0)) < 0) {
-                       ND_PRINT((ndo, "..."));
-                       break;
-               }
+               if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
+                       goto trunc;
                bp += advance; len -= advance;
-               if (bp >= ep)
-                       break;
                ND_PRINT((ndo, " src="));
-               if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-                       ND_PRINT((ndo, "..."));
-                       break;
-               }
+               if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+                       goto trunc;
                bp += advance; len -= advance;
-               if (bp + 8 > ep)
-                       break;
+               if (len < 8)
+                       goto trunc;
+               ND_TCHECK2(*bp, 8);
                if (bp[0] & 0x80)
                        ND_PRINT((ndo, " RPT"));
                ND_PRINT((ndo, " pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff));
@@ -1091,61 +1121,62 @@ pimv2_print(netdissect_options *ndo,
        case PIMV2_TYPE_CANDIDATE_RP:
        {
                int i, pfxcnt;
-               bp += 4;
 
                /* Prefix-Cnt, Priority, and Holdtime */
-               if (bp >= ep) break;
+               if (len < 1)
+                       goto trunc;
+               ND_TCHECK(bp[0]);
                ND_PRINT((ndo, " prefix-cnt=%d", bp[0]));
                pfxcnt = bp[0];
-               if (bp + 1 >= ep) break;
+               if (len < 2)
+                       goto trunc;
+               ND_TCHECK(bp[1]);
                ND_PRINT((ndo, " prio=%d", bp[1]));
-               if (bp + 3 >= ep) break;
+               if (len < 4)
+                       goto trunc;
+               ND_TCHECK_16BITS(&bp[2]);
                ND_PRINT((ndo, " holdtime="));
                unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[2]));
                bp += 4;
+               len -= 4;
 
                /* Encoded-Unicast-RP-Address */
-               if (bp >= ep) break;
                ND_PRINT((ndo, " RP="));
-               if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-                       ND_PRINT((ndo, "..."));
-                       break;
-               }
+               if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+                       goto trunc;
                bp += advance;
+               len -= advance;
 
                /* Encoded-Group Addresses */
                for (i = 0; i < pfxcnt && bp < ep; i++) {
                        ND_PRINT((ndo, " Group%d=", i));
-                       if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0))
-                           < 0) {
-                               ND_PRINT((ndo, "..."));
-                               break;
-                       }
+                       if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
+                               goto trunc;
                        bp += advance;
+                       len -= advance;
                }
                break;
        }
 
        case PIMV2_TYPE_PRUNE_REFRESH:
                ND_PRINT((ndo, " src="));
-               if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-                       ND_PRINT((ndo, "..."));
-                       break;
-               }
+               if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+                       goto trunc;
                bp += advance;
+               len -= advance;
                ND_PRINT((ndo, " grp="));
-               if ((advance = pimv2_addr_print(ndo, bp, pimv2_group, 0)) < 0) {
-                       ND_PRINT((ndo, "..."));
-                       break;
-               }
+               if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
+                       goto trunc;
                bp += advance;
+               len -= advance;
                ND_PRINT((ndo, " forwarder="));
-               if ((advance = pimv2_addr_print(ndo, bp, pimv2_unicast, 0)) < 0) {
-                       ND_PRINT((ndo, "..."));
-                       break;
-               }
+               if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
+                       goto trunc;
                bp += advance;
-               ND_TCHECK2(bp[0], 2);
+               len -= advance;
+               if (len < 2)
+                       goto trunc;
+               ND_TCHECK_16BITS(bp);
                ND_PRINT((ndo, " TUNR "));
                unsigned_relts_print(ndo, EXTRACT_16BITS(bp));
                break;
index f5d14dd20ae25d0e37bdba1e53e23f6a6fd3a87b..7f18d2605e0f915e7df4da84ef6ba8c72e1ba26e 100644 (file)
@@ -532,6 +532,7 @@ isis_stlv_asan-4    isis_stlv_asan-4.pcap           isis_stlv_asan-4.out    -v
 lldp_mgmt_addr_tlv_asan        lldp_mgmt_addr_tlv_asan.pcap    lldp_mgmt_addr_tlv_asan.out     -v
 bootp_asan             bootp_asan.pcap                 bootp_asan.out          -v
 ppp_ccp_config_deflate_option_asan     ppp_ccp_config_deflate_option_asan.pcap ppp_ccp_config_deflate_option_asan.out  -v
+pim_header_asan                pim_header_asan.pcap            pim_header_asan.out             -v
 
 # RTP tests
 # fuzzed pcap
index fffc6920c222592c28ac1a34ab1195c1461bc294..aa59acb0ccd5136da33364cf7818853af9991841 100644 (file)
@@ -1,3 +1,4 @@
 IP (tos 0x30, ttl 48, id 12336, offset 0, flags [DF], proto PIM (103), length 12336, bad cksum 3030 (->2947)!)
     48.48.48.48 > 48.48.48.48: PIMv2, length 12316
-       Hello, RFC2117-encoding, cksum 0x3030 (unverified)[|pim]
+       Hello, RFC2117-encoding, cksum 0x3030 (unverified)
+         Unknown Option (12336), length 12336, Value: [|pim]
diff --git a/tests/pim_header_asan.out b/tests/pim_header_asan.out
new file mode 100644 (file)
index 0000000..397fe1e
--- /dev/null
@@ -0,0 +1,2 @@
+IP6 (class 0x76, flowlabel 0xf6767, hlim 109, next-header PIM (103) payload length: 30311) 6767:6767:6767:8267:6767:6765:6767:6767 > 6700:80:74:24:2424:2424:2424:2509: PIMv2, length 30311
+       Bootstrap, RFC2117-encoding[|pim]
diff --git a/tests/pim_header_asan.pcap b/tests/pim_header_asan.pcap
new file mode 100644 (file)
index 0000000..12f81be
Binary files /dev/null and b/tests/pim_header_asan.pcap differ