212ca88
From af17d2eb7f641c7014a84a71bc0c700b28f1e638 Mon Sep 17 00:00:00 2001
212ca88
From: Evgeny Uskov <eu@qrator.net>
212ca88
Date: Wed, 13 Jan 2016 13:58:00 +0300
212ca88
Subject: [PATCH 3/3] bgpd: Fix buffer overflow error in bgp_dump_routes_func
212ca88
212ca88
Now if the number of entries for some prefix is too large, multiple
212ca88
TABLE_DUMP_V2 records are created.  In the previous version in such
212ca88
situation bgpd crashed with SIGABRT.
212ca88
212ca88
Resolves: #1331373
212ca88
Cherry-picked from: b4e011985232f28d98e4df88c7cb13ee8f95ef46
212ca88
Conflicts:
212ca88
	bgpd/bgp_dump.c
212ca88
---
212ca88
 bgpd/bgp_dump.c | 175 +++++++++++++++++++++++++++++++-------------------------
212ca88
 1 file changed, 96 insertions(+), 79 deletions(-)
212ca88
212ca88
diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c
212ca88
index a3c9526..a8db612 100644
212ca88
--- a/bgpd/bgp_dump.c
212ca88
+++ b/bgpd/bgp_dump.c
212ca88
@@ -271,11 +271,98 @@ bgp_dump_routes_index_table(struct bgp *bgp)
212ca88
 }
212ca88
 
212ca88
 
212ca88
+static struct bgp_info *
212ca88
+bgp_dump_route_node_record (int afi, struct bgp_node *rn,
212ca88
+                            struct bgp_info *info, unsigned int seq)
212ca88
+{
212ca88
+  struct stream *obuf;
212ca88
+  size_t sizep;
212ca88
+  size_t endp;
212ca88
+
212ca88
+  obuf = bgp_dump_obuf;
212ca88
+  stream_reset (obuf);
212ca88
+
212ca88
+  /* MRT header */
212ca88
+  if (afi == AFI_IP)
212ca88
+    bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST);
212ca88
+  else if (afi == AFI_IP6)
212ca88
+    bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST);
212ca88
+
212ca88
+  /* Sequence number */
212ca88
+  stream_putl (obuf, seq);
212ca88
+
212ca88
+  /* Prefix length */
212ca88
+  stream_putc (obuf, rn->p.prefixlen);
212ca88
+
212ca88
+  /* Prefix */
212ca88
+  if (afi == AFI_IP)
212ca88
+    {
212ca88
+      /* We'll dump only the useful bits (those not 0), but have to
212ca88
+       * align on 8 bits */
212ca88
+      stream_write (obuf, (u_char *) &rn->p.u.prefix4, 
212ca88
+                    (rn->p.prefixlen + 7) / 8);
212ca88
+    }
212ca88
+  else if (afi == AFI_IP6)
212ca88
+    {
212ca88
+      /* We'll dump only the useful bits (those not 0), but have to
212ca88
+       * align on 8 bits */
212ca88
+      stream_write (obuf, (u_char *) &rn->p.u.prefix6,
212ca88
+                    (rn->p.prefixlen + 7) / 8);
212ca88
+    }
212ca88
+
212ca88
+  /* Save where we are now, so we can overwride the entry count later */
212ca88
+  sizep = stream_get_endp (obuf);
212ca88
+
212ca88
+  /* Entry count */
212ca88
+  uint16_t entry_count = 0;
212ca88
+
212ca88
+  /* Entry count, note that this is overwritten later */
212ca88
+  stream_putw (obuf, 0);
212ca88
+
212ca88
+  endp = stream_get_endp (obuf);
212ca88
+  for (; info; info = info->next)
212ca88
+    {
212ca88
+      size_t cur_endp;
212ca88
+
212ca88
+      /* Peer index */
212ca88
+      stream_putw (obuf, info->peer->table_dump_index);
212ca88
+
212ca88
+      /* Originated */
212ca88
+#ifdef HAVE_CLOCK_MONOTONIC
212ca88
+      stream_putl (obuf, time (NULL) - (bgp_clock () - info->uptime));
212ca88
+#else
212ca88
+      stream_putl (obuf, info->uptime);
212ca88
+#endif /* HAVE_CLOCK_MONOTONIC */
212ca88
+
212ca88
+      /* Dump attribute. */
212ca88
+      /* Skip prefix & AFI/SAFI for MP_NLRI */
212ca88
+      bgp_dump_routes_attr (obuf, info->attr, &rn->p);
212ca88
+
212ca88
+      cur_endp = stream_get_endp (obuf);
212ca88
+      if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
212ca88
+          + BGP_DUMP_HEADER_SIZE)
212ca88
+        {
212ca88
+          stream_set_endp (obuf, endp);
212ca88
+          break;
212ca88
+        }
212ca88
+
212ca88
+      entry_count++;
212ca88
+      endp = cur_endp;
212ca88
+    }
212ca88
+
212ca88
+  /* Overwrite the entry count, now that we know the right number */
212ca88
+  stream_putw_at (obuf, sizep, entry_count);
212ca88
+
212ca88
+  bgp_dump_set_size (obuf, MSG_TABLE_DUMP_V2);
212ca88
+  fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
212ca88
+
212ca88
+  return info;
212ca88
+}
212ca88
+
212ca88
 /* Runs under child process. */
212ca88
 static unsigned int
212ca88
 bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
212ca88
 {
212ca88
-  struct stream *obuf;
212ca88
   struct bgp_info *info;
212ca88
   struct bgp_node *rn;
212ca88
   struct bgp *bgp;
212ca88
@@ -294,87 +381,17 @@ bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
212ca88
   if(first_run)
212ca88
     bgp_dump_routes_index_table(bgp);
212ca88
 
212ca88
-  obuf = bgp_dump_obuf;
212ca88
-  stream_reset(obuf);
212ca88
-
212ca88
   /* Walk down each BGP route. */
212ca88
   table = bgp->rib[afi][SAFI_UNICAST];
212ca88
 
212ca88
   for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
212ca88
     {
212ca88
-      if(!rn->info)
212ca88
-        continue;
212ca88
-
212ca88
-      stream_reset(obuf);
212ca88
-
212ca88
-      /* MRT header */
212ca88
-      if (afi == AFI_IP)
212ca88
-        {
212ca88
-          bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST);
212ca88
-        }
212ca88
-#ifdef HAVE_IPV6
212ca88
-      else if (afi == AFI_IP6)
212ca88
-        {
212ca88
-          bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST);
212ca88
-        }
212ca88
-#endif /* HAVE_IPV6 */
212ca88
-
212ca88
-      /* Sequence number */
212ca88
-      stream_putl(obuf, seq);
212ca88
-
212ca88
-      /* Prefix length */
212ca88
-      stream_putc (obuf, rn->p.prefixlen);
212ca88
-
212ca88
-      /* Prefix */
212ca88
-      if (afi == AFI_IP)
212ca88
-        {
212ca88
-          /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
212ca88
-          stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
212ca88
-        }
212ca88
-#ifdef HAVE_IPV6
212ca88
-      else if (afi == AFI_IP6)
212ca88
-        {
212ca88
-          /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
212ca88
-          stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
212ca88
-        }
212ca88
-#endif /* HAVE_IPV6 */
212ca88
-
212ca88
-      /* Save where we are now, so we can overwride the entry count later */
212ca88
-      int sizep = stream_get_endp(obuf);
212ca88
-
212ca88
-      /* Entry count */
212ca88
-      uint16_t entry_count = 0;
212ca88
-
212ca88
-      /* Entry count, note that this is overwritten later */
212ca88
-      stream_putw(obuf, 0);
212ca88
-
212ca88
-      for (info = rn->info; info; info = info->next)
212ca88
-        {
212ca88
-          entry_count++;
212ca88
-
212ca88
-          /* Peer index */
212ca88
-          stream_putw(obuf, info->peer->table_dump_index);
212ca88
-
212ca88
-          /* Originated */
212ca88
-#ifdef HAVE_CLOCK_MONOTONIC
212ca88
-          stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
212ca88
-#else
212ca88
-          stream_putl (obuf, info->uptime);
212ca88
-#endif /* HAVE_CLOCK_MONOTONIC */
212ca88
-
212ca88
-          /* Dump attribute. */
212ca88
-          /* Skip prefix & AFI/SAFI for MP_NLRI */
212ca88
-          bgp_dump_routes_attr (obuf, info->attr, &rn->p);
212ca88
-        }
212ca88
-
212ca88
-      /* Overwrite the entry count, now that we know the right number */
212ca88
-      stream_putw_at (obuf, sizep, entry_count);
212ca88
-
212ca88
-      seq++;
212ca88
-
212ca88
-      bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
212ca88
-      fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
212ca88
-
212ca88
+      info = rn->info;
212ca88
+      while (info)
212ca88
+      {
212ca88
+        info = bgp_dump_route_node_record(afi, rn, info, seq);
212ca88
+        seq++;
212ca88
+      }
212ca88
     }
212ca88
 
212ca88
   fflush (bgp_dump_routes.fp);
212ca88
@@ -854,8 +871,8 @@ bgp_dump_init (void)
212ca88
   memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
212ca88
   memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
212ca88
 
212ca88
-  bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
212ca88
-                              + BGP_DUMP_HEADER_SIZE);
212ca88
+  bgp_dump_obuf = stream_new ((BGP_MAX_PACKET_SIZE << 1)
212ca88
+                              + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE);
212ca88
 
212ca88
   install_node (&bgp_dump_node, config_write_bgp_dump);
212ca88
 
212ca88
-- 
212ca88
2.7.4
212ca88