24928745 problem in SERVICE/QUAGGA s11u3-sru
authorBrian Utterback <brian.utterback@oracle.com>
Tue, 14 Feb 2017 18:38:21 -0800
branchs11u3-sru
changeset 7672 036be1e2dc00
parent 7667 a58a865e7e8a
child 7673 8e6af99ed7da
24928745 problem in SERVICE/QUAGGA
components/quagga/patches/39-cve-2016-4049.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/quagga/patches/39-cve-2016-4049.patch	Tue Feb 14 18:38:21 2017 -0800
@@ -0,0 +1,290 @@
+This patch fixes CVE-2016-4049, "bgpd bgp_dump_routes_func() Lets Remote Users
+Cause the Target Service to Crash" This bug is fixed in Quagga version
+1.1.0 and the patch can be removed after upgrading to a version later than
+that.
+See:
+http://git.savannah.gnu.org/gitweb/?p=quagga.git;a=commit;h=b4e011985232f28d98e4df88c7cb13ee8f95ef46 
+
+*** bgpd/bgp_dump.c
+--- bgpd/bgp_dump.c
+*************** bgp_dump_routes_index_table(struct bgp *
+*** 271,281 ****
+  }
+  
+  
+  /* Runs under child process. */
+  static unsigned int
+  bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
+  {
+-   struct stream *obuf;
+    struct bgp_info *info;
+    struct bgp_node *rn;
+    struct bgp *bgp;
+--- 271,364 ----
+  }
+  
+  
++ static struct bgp_info *
++ bgp_dump_route_node_record (int afi, struct bgp_node *rn, struct bgp_info *info, unsigned int seq)
++ {
++   struct stream *obuf;
++   size_t sizep;
++   size_t endp;
++ 
++   obuf = bgp_dump_obuf;
++   stream_reset(obuf);
++ 
++   /* MRT header */
++   if (afi == AFI_IP)
++     bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST);
++   else if (afi == AFI_IP6)
++     bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST);
++ 
++   /* Sequence number */
++   stream_putl(obuf, seq);
++ 
++   /* Prefix length */
++   stream_putc (obuf, rn->p.prefixlen);
++ 
++   /* Prefix */
++   if (afi == AFI_IP)
++   {
++     /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
++     stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
++   }
++   else if (afi == AFI_IP6)
++   {
++     /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
++     stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
++   }
++ 
++   /* Save where we are now, so we can overwride the entry count later */
++   sizep = stream_get_endp(obuf);
++ 
++   /* Entry count */
++   uint16_t entry_count = 0;
++ 
++   /* Entry count, note that this is overwritten later */
++   stream_putw(obuf, 0);
++ 
++   endp = stream_get_endp(obuf);
++   for (; info; info = info->next)
++   {
++     size_t cur_endp;
++ 
++     /* Peer index */
++     stream_putw(obuf, info->peer->table_dump_index);
++ 
++     /* Originated */
++ #ifdef HAVE_CLOCK_MONOTONIC
++           stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
++ #else
++     stream_putl (obuf, info->uptime);
++ #endif /* HAVE_CLOCK_MONOTONIC */
++ 
++     /* Dump attribute. */
++     /* Skip prefix & AFI/SAFI for MP_NLRI */
++     bgp_dump_routes_attr (obuf, info->attr, &rn->p);
++ 
++     cur_endp = stream_get_endp(obuf);
++     if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
++                    + BGP_DUMP_HEADER_SIZE)
++     {
++       stream_set_endp(obuf, endp);
++       break;
++     }
++ 
++     entry_count++;
++     endp = cur_endp;
++   }
++ 
++   /* Overwrite the entry count, now that we know the right number */
++   stream_putw_at (obuf, sizep, entry_count);
++ 
++   bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
++   fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
++ 
++   return info;
++ }
++ 
++ 
+  /* Runs under child process. */
+  static unsigned int
+  bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
+  {
+    struct bgp_info *info;
+    struct bgp_node *rn;
+    struct bgp *bgp;
+*************** bgp_dump_routes_func (int afi, int first
+*** 294,380 ****
+    if(first_run)
+      bgp_dump_routes_index_table(bgp);
+  
+-   obuf = bgp_dump_obuf;
+-   stream_reset(obuf);
+- 
+    /* Walk down each BGP route. */
+    table = bgp->rib[afi][SAFI_UNICAST];
+  
+    for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+      {
+!       if(!rn->info)
+!         continue;
+! 
+!       stream_reset(obuf);
+! 
+!       /* MRT header */
+!       if (afi == AFI_IP)
+!         {
+!           bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST);
+!         }
+! #ifdef HAVE_IPV6
+!       else if (afi == AFI_IP6)
+!         {
+!           bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST);
+!         }
+! #endif /* HAVE_IPV6 */
+! 
+!       /* Sequence number */
+!       stream_putl(obuf, seq);
+! 
+!       /* Prefix length */
+!       stream_putc (obuf, rn->p.prefixlen);
+! 
+!       /* Prefix */
+!       if (afi == AFI_IP)
+!         {
+!           /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
+!           stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
+!         }
+! #ifdef HAVE_IPV6
+!       else if (afi == AFI_IP6)
+!         {
+!           /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
+!           stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
+!         }
+! #endif /* HAVE_IPV6 */
+! 
+!       /* Save where we are now, so we can overwride the entry count later */
+!       int sizep = stream_get_endp(obuf);
+! 
+!       /* Entry count */
+!       uint16_t entry_count = 0;
+! 
+!       /* Entry count, note that this is overwritten later */
+!       stream_putw(obuf, 0);
+! 
+!       for (info = rn->info; info; info = info->next)
+!         {
+!           entry_count++;
+! 
+!           /* Peer index */
+!           stream_putw(obuf, info->peer->table_dump_index);
+! 
+!           /* Originated */
+! #ifdef HAVE_CLOCK_MONOTONIC
+!           stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
+! #else
+!           stream_putl (obuf, info->uptime);
+! #endif /* HAVE_CLOCK_MONOTONIC */
+! 
+!           /* Dump attribute. */
+!           /* Skip prefix & AFI/SAFI for MP_NLRI */
+!           bgp_dump_routes_attr (obuf, info->attr, &rn->p);
+!         }
+! 
+!       /* Overwrite the entry count, now that we know the right number */
+!       stream_putw_at (obuf, sizep, entry_count);
+! 
+!       seq++;
+! 
+!       bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
+!       fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
+! 
+      }
+  
+    fflush (bgp_dump_routes.fp);
+--- 377,393 ----
+    if(first_run)
+      bgp_dump_routes_index_table(bgp);
+  
+    /* Walk down each BGP route. */
+    table = bgp->rib[afi][SAFI_UNICAST];
+  
+    for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+      {
+! 	    info = rn->info;
+! 	    while (info)
+! 	    {
+! 		    info = bgp_dump_route_node_record(afi, rn, info, seq);
+! 		    seq++;
+! 	    }
+      }
+  
+    fflush (bgp_dump_routes.fp);
+*************** bgp_dump_init (void)
+*** 854,861 ****
+    memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
+    memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
+  
+!   bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
+!                               + BGP_DUMP_HEADER_SIZE);
+  
+    install_node (&bgp_dump_node, config_write_bgp_dump);
+  
+--- 867,874 ----
+    memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
+    memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
+  
+!   bgp_dump_obuf = stream_new ((BGP_MAX_PACKET_SIZE << 1)
+!                               + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE);
+  
+    install_node (&bgp_dump_node, config_write_bgp_dump);
+  
+*** lib/stream.c
+--- lib/stream.c
+*************** stream_set_getp (struct stream *s, size_
+*** 214,219 ****
+--- 214,243 ----
+    s->getp = pos;
+  }
+  
++ void
++ stream_set_endp (struct stream *s, size_t pos)
++ {
++   STREAM_VERIFY_SANE(s);
++ 
++   if (!ENDP_VALID(s, pos))
++     {
++       STREAM_BOUND_WARN (s, "set endp");
++       return;
++     }
++ 
++   /*
++    * Make sure the current read pointer is not beyond the new endp.
++    */
++   if (s->getp > pos)
++     {
++       STREAM_BOUND_WARN(s, "set endp");
++       return;
++     }
++ 
++   s->endp = pos;
++   STREAM_VERIFY_SANE(s);
++ }
++ 
+  /* Forward pointer. */
+  void
+  stream_forward_getp (struct stream *s, size_t size)
+*** lib/stream.h
+--- lib/stream.h
+*************** extern size_t stream_get_size (struct st
+*** 146,151 ****
+--- 146,152 ----
+  extern u_char *stream_get_data (struct stream *);
+  
+  extern void stream_set_getp (struct stream *, size_t);
++ extern void stream_set_endp (struct stream *, size_t);
+  extern void stream_forward_getp (struct stream *, size_t);
+  extern void stream_forward_endp (struct stream *, size_t);
+