summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2017-03-22 14:09:28 -0700
committerDenis Ovsienko <denis@ovsienko.info>2017-09-13 12:25:44 +0100
commit5dc1860d8267b1e0cb78c9ffa2a40bea2fdb3ddc (patch)
tree61c4957fb95780b4e54532dc0b04d9c18ea2c46c
parent7029d15f148ef24bb7c6668bc640f5470d085e5a (diff)
downloadtcpdump-5dc1860d8267b1e0cb78c9ffa2a40bea2fdb3ddc.tar.gz
CVE-2017-13030/PIM: Redo bounds checks and add length checks.
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.
-rw-r--r--print-pim.c383
-rw-r--r--tests/TESTLIST1
-rw-r--r--tests/heapoverflow-in_checksum.out3
-rw-r--r--tests/pim_header_asan.out2
-rw-r--r--tests/pim_header_asan.pcapbin0 -> 96 bytes
5 files changed, 212 insertions, 177 deletions
diff --git a/print-pim.c b/print-pim.c
index ee18d958..b5c47469 100644
--- a/print-pim.c
+++ b/print-pim.c
@@ -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;
diff --git a/tests/TESTLIST b/tests/TESTLIST
index e553c2ca..0dcfab17 100644
--- a/tests/TESTLIST
+++ b/tests/TESTLIST
@@ -535,6 +535,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
diff --git a/tests/heapoverflow-in_checksum.out b/tests/heapoverflow-in_checksum.out
index fffc6920..aa59acb0 100644
--- a/tests/heapoverflow-in_checksum.out
+++ b/tests/heapoverflow-in_checksum.out
@@ -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
index 00000000..397fe1e1
--- /dev/null
+++ b/tests/pim_header_asan.out
@@ -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
index 00000000..12f81bed
--- /dev/null
+++ b/tests/pim_header_asan.pcap
Binary files differ