From f02a09925db53d3e1d29b1917ebbcaa8edf72c12 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 8 May 2012 13:15:45 +0200 Subject: isisd: don't process invalid prefixes from TLVs it's possible to feed invalid prefixes (1.2.3.4/40 or dead::beef/200) on IS-IS. if this is not checked, it will later cause an assert in processing. let's simply abort processing the TLV if the prefix is invalid. * isisd/isis_tlv.c: check prefix lengths for validity Signed-off-by: David Lamparter --- isisd/isis_tlv.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'isisd/isis_tlv.c') diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index bb57bd6b..f3b2c338 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -117,7 +117,7 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, #endif /* HAVE_IPV6 */ u_char virtual; int value_len, retval = ISIS_OK; - u_char *start = stream, *pnt = stream; + u_char *start = stream, *pnt = stream, *endpnt; *found = 0; memset (tlvs, 0, sizeof (struct tlvs)); @@ -584,11 +584,20 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ + endpnt = pnt + length; if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) { while (length > value_len) { te_ipv4_reach = (struct te_ipv4_reachability *) pnt; + if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN) + { + zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach" + "ability prefix length %d", areatag, + te_ipv4_reach->control & 0x3F); + retval = ISIS_WARNING; + break; + } if (!tlvs->te_ipv4_reachs) tlvs->te_ipv4_reachs = list_new (); listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach); @@ -600,10 +609,8 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0); } } - else - { - pnt += length; - } + + pnt = endpnt; break; #ifdef HAVE_IPV6 @@ -648,11 +655,22 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, * +---------------------------------------------------------------+ */ *found |= TLVFLAG_IPV6_REACHABILITY; + endpnt = pnt + length; + if (*expected & TLVFLAG_IPV6_REACHABILITY) { while (length > value_len) { ipv6_reach = (struct ipv6_reachability *) pnt; + if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN) + { + zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach" + "ability prefix length %d", areatag, + ipv6_reach->prefix_len); + retval = ISIS_WARNING; + break; + } + prefix_octets = ((ipv6_reach->prefix_len + 7) / 8); value_len += prefix_octets + 6; pnt += prefix_octets + 6; @@ -662,10 +680,8 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, listnode_add (tlvs->ipv6_reachs, ipv6_reach); } } - else - { - pnt += length; - } + + pnt = endpnt; break; #endif /* HAVE_IPV6 */ -- cgit v1.2.1