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 <equinox@opensourcerouting.org>
diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c
index bb57bd6..f3b2c33 100644
--- a/isisd/isis_tlv.c
+++ b/isisd/isis_tlv.c
@@ -117,7 +117,7 @@
 #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 @@
 	  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 @@
 		              ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0);
 		}
 	    }
-	  else
-	    {
-	      pnt += length;
-	    }
+
+	  pnt = endpnt;
 	  break;
 
 #ifdef  HAVE_IPV6
@@ -648,11 +655,22 @@
 	   * +---------------------------------------------------------------+
 	   */
 	  *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 @@
 		  listnode_add (tlvs->ipv6_reachs, ipv6_reach);
 		}
 	    }
-	  else
-	    {
-	      pnt += length;
-	    }
+
+	  pnt = endpnt;
 	  break;
 #endif /* HAVE_IPV6 */