File quagga-CVE-2016-2342-VPNv4-NLRI-memcpy-stack-overflow.patch of Package quagga.2309

Index: quagga-0.99.22.1/bgpd/bgp_mplsvpn.c
===================================================================
--- quagga-0.99.22.1.orig/bgpd/bgp_mplsvpn.c
+++ quagga-0.99.22.1/bgpd/bgp_mplsvpn.c
@@ -102,6 +102,7 @@ bgp_nlri_parse_vpnv4 (struct peer *peer,
   pnt = packet->nlri;
   lim = pnt + packet->length;
 
+#define VPN_PREFIXLEN_MIN_BYTES (3 + 8) /* label + RD */
   for (; pnt < lim; pnt += psize)
     {
       /* Clear prefix structure. */
@@ -109,19 +110,40 @@ bgp_nlri_parse_vpnv4 (struct peer *peer,
 
       /* Fetch prefix length. */
       prefixlen = *pnt++;
-      p.family = AF_INET;
+      p.family = afi2family (packet->afi);
       psize = PSIZE (prefixlen);
-
-      if (prefixlen < 88)
-	{
-	  zlog_err ("prefix length is less than 88: %d", prefixlen);
-	  return -1;
-	}
-
+      
+      /* sanity check against packet data */
+      if (prefixlen < VPN_PREFIXLEN_MIN_BYTES*8 || (pnt + psize) > lim)
+        {
+          zlog_err ("prefix length (%d) is less than 88"
+                    " or larger than received (%u)",
+                    prefixlen, (uint)(lim-pnt));
+          return -1;
+        }
+      
+      /* sanity check against storage for the IP address portion */
+      if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t) sizeof(p.u))
+        {
+          zlog_err ("prefix length (%d) exceeds prefix storage (%zu)",
+                    prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, sizeof(p.u));
+          return -1;
+        }
+      
+      /* Sanity check against max bitlen of the address family */
+      if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen (&p))
+        {
+          zlog_err ("prefix length (%d) exceeds family (%u) max byte length (%u)",
+                    prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, 
+                    p.family, prefix_blen (&p));
+          return -1;
+                  
+        }
+      
       label = decode_label (pnt);
 
       /* Copyr label to prefix. */
-      tagpnt = pnt;;
+      tagpnt = pnt;
 
       /* Copy routing distinguisher to rd. */
       memcpy (&prd.val, pnt + 3, 8);
@@ -140,8 +162,9 @@ bgp_nlri_parse_vpnv4 (struct peer *peer,
 	  return -1;
 	}
 
-      p.prefixlen = prefixlen - 88;
-      memcpy (&p.u.prefix, pnt + 11, psize - 11);
+      p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES*8;
+      memcpy (&p.u.prefix, pnt + VPN_PREFIXLEN_MIN_BYTES, 
+              psize - VPN_PREFIXLEN_MIN_BYTES);
 
 #if 0
       if (type == RD_TYPE_AS)
@@ -152,9 +175,6 @@ bgp_nlri_parse_vpnv4 (struct peer *peer,
 		   rd_ip.val, inet_ntoa (p.u.prefix4), p.prefixlen);
 #endif /* 0 */
 
-      if (pnt + psize > lim)
-	return -1;
-
       if (attr)
 	bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN,
 		    ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0);
@@ -162,12 +182,12 @@ bgp_nlri_parse_vpnv4 (struct peer *peer,
 	bgp_withdraw (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN,
 		      ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt);
     }
-
   /* Packet length consistency check. */
   if (pnt != lim)
     return -1;
-
+  
   return 0;
+#undef VPN_PREFIXLEN_MIN_BYTES
 }
 
 int
openSUSE Build Service is sponsored by