diff -Nru quagga-0.99.22.4/debian/changelog quagga-0.99.22.4/debian/changelog --- quagga-0.99.22.4/debian/changelog 2016-03-23 12:15:51.000000000 +0000 +++ quagga-0.99.22.4/debian/changelog 2016-10-12 20:04:35.000000000 +0000 @@ -1,3 +1,16 @@ +quagga (0.99.22.4-3ubuntu1.2) trusty-security; urgency=medium + + * SECURITY UPDATE: insecure directory permissions + - debian/quagga.postinst: set proper directory permissions on + /etc/quagga, /var/log/quagga, /var/run/quagga. + - CVE-2016-4036 + * SECURITY UPDATE: denial of service via a large BGP packet + - debian/patches/dump_fix.patch: create multiple MRT records if there + is too much data for a prefix in bgpd/bgp_dump.c. + - CVE-2016-4049 + + -- Marc Deslauriers Wed, 12 Oct 2016 16:03:58 -0400 + quagga (0.99.22.4-3ubuntu1.1) trusty-security; urgency=medium * SECURITY UPDATE: denial of service or arbitrary code execution via diff -Nru quagga-0.99.22.4/debian/patches/dump_fix.patch quagga-0.99.22.4/debian/patches/dump_fix.patch --- quagga-0.99.22.4/debian/patches/dump_fix.patch 1970-01-01 00:00:00.000000000 +0000 +++ quagga-0.99.22.4/debian/patches/dump_fix.patch 2016-08-22 08:27:07.000000000 +0000 @@ -0,0 +1,207 @@ +Description: create multiple MRT records if there is too much data for a prefix. + See https://lists.quagga.net/pipermail/quagga-dev/2016-January/014699.html + (adjusted for 0.99.23) +Author: Evgeny Uskov + +--- a/bgpd/bgp_dump.c 2016-08-22 13:55:04.046255177 +0200 ++++ b/bgpd/bgp_dump.c 2016-08-22 13:55:58.390212180 +0200 +@@ -271,11 +271,94 @@ + } + + ++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 +377,17 @@ + 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 +867,7 @@ + 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 (0x4000); + + install_node (&bgp_dump_node, config_write_bgp_dump); + diff -Nru quagga-0.99.22.4/debian/patches/series quagga-0.99.22.4/debian/patches/series --- quagga-0.99.22.4/debian/patches/series 2016-03-23 12:14:14.000000000 +0000 +++ quagga-0.99.22.4/debian/patches/series 2016-10-12 20:04:18.000000000 +0000 @@ -5,3 +5,4 @@ 50_vtysh__vtysh.conf.sample.diff readline-6.3.diff CVE-2016-2342.patch +dump_fix.patch diff -Nru quagga-0.99.22.4/debian/quagga.postinst quagga-0.99.22.4/debian/quagga.postinst --- quagga-0.99.22.4/debian/quagga.postinst 2012-02-25 17:46:49.000000000 +0000 +++ quagga-0.99.22.4/debian/quagga.postinst 2016-10-12 20:04:24.000000000 +0000 @@ -3,6 +3,14 @@ if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi ${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"} + +if [ "$1" = "configure" ]; then + # Fix permissions for installed elements. + find /etc/quagga -type f -print0 | xargs -0 -I{} sh -c 'chown quagga:quagga {} ; chmod 640 {}' + find /var/log/quagga -type f -print0 | xargs -0 -I{} sh -c 'chown quagga:quagga {} ; chmod 640 {}' + find /var/run/quagga -type f -print0 | xargs -0 -I{} sh -c 'chown quagga:quagga {} ; chmod 600 {}' +fi + # This is most likely due to the answer "no" to the "really stop the server" # question in the prerm script. if [ "$1" = "abort-upgrade" ]; then