# HG changeset patch # User Brian Utterback # Date 1487125351 28800 # Node ID 98611b4a801e73484c8a817ecdf9abc6d4cc48be # Parent cf60591fb76a82365466953908546ad1538aedd3 24928745 problem in SERVICE/QUAGGA diff -r cf60591fb76a -r 98611b4a801e 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:22:31 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); +