diff --git a/0003-bgpd-Fix-buffer-overflow-error-in-bgp_dump_routes_fu.patch b/0003-bgpd-Fix-buffer-overflow-error-in-bgp_dump_routes_fu.patch new file mode 100644 index 0000000..c0bd003 --- /dev/null +++ b/0003-bgpd-Fix-buffer-overflow-error-in-bgp_dump_routes_fu.patch @@ -0,0 +1,229 @@ +From af17d2eb7f641c7014a84a71bc0c700b28f1e638 Mon Sep 17 00:00:00 2001 +From: Evgeny Uskov +Date: Wed, 13 Jan 2016 13:58:00 +0300 +Subject: [PATCH 3/3] bgpd: Fix buffer overflow error in bgp_dump_routes_func + +Now if the number of entries for some prefix is too large, multiple +TABLE_DUMP_V2 records are created. In the previous version in such +situation bgpd crashed with SIGABRT. + +Resolves: #1331373 +Cherry-picked from: b4e011985232f28d98e4df88c7cb13ee8f95ef46 +Conflicts: + bgpd/bgp_dump.c +--- + bgpd/bgp_dump.c | 175 +++++++++++++++++++++++++++++++------------------------- + 1 file changed, 96 insertions(+), 79 deletions(-) + +diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c +index a3c9526..a8db612 100644 +--- a/bgpd/bgp_dump.c ++++ b/bgpd/bgp_dump.c +@@ -271,11 +271,98 @@ bgp_dump_routes_index_table(struct bgp *bgp) + } + + ++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 stream *obuf; + struct bgp_info *info; + struct bgp_node *rn; + struct bgp *bgp; +@@ -294,87 +381,17 @@ bgp_dump_routes_func (int afi, int first_run, unsigned int seq) + 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); +- ++ info = rn->info; ++ while (info) ++ { ++ info = bgp_dump_route_node_record(afi, rn, info, seq); ++ seq++; ++ } + } + + fflush (bgp_dump_routes.fp); +@@ -854,8 +871,8 @@ bgp_dump_init (void) + 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); ++ 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); + +-- +2.7.4 + diff --git a/quagga.spec b/quagga.spec index 430561d..e282b47 100644 --- a/quagga.spec +++ b/quagga.spec @@ -29,6 +29,7 @@ Obsoletes: quagga-sysvinit Patch0: 0001-systemd-various-service-file-improvements.patch Patch1: 0002-bgpd-Fix-VU-270232-VPNv4-NLRI-parser-memcpys-to-stac.patch +Patch2: 0003-bgpd-Fix-buffer-overflow-error-in-bgp_dump_routes_fu.patch %define __perl_requires %{SOURCE1} @@ -228,6 +229,7 @@ fi * Fri Oct 21 2016 Michal Sekletar - 0.99.24.1-4 - make routing daemons pull network.target into the boot transaction (#1387654) - fix for CVE-2016-2342 (#1316572) +- fix for CVE-2016-4049 (#1331373) * Thu Feb 04 2016 Fedora Release Engineering - 0.99.24.1-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild