--- /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);
+