components/quagga/patches/39-cve-2016-4049.patch
changeset 7668 98611b4a801e
equal deleted inserted replaced
7666:cf60591fb76a 7668:98611b4a801e
       
     1 This patch fixes CVE-2016-4049, "bgpd bgp_dump_routes_func() Lets Remote Users
       
     2 Cause the Target Service to Crash" This bug is fixed in Quagga version
       
     3 1.1.0 and the patch can be removed after upgrading to a version later than
       
     4 that.
       
     5 See:
       
     6 http://git.savannah.gnu.org/gitweb/?p=quagga.git;a=commit;h=b4e011985232f28d98e4df88c7cb13ee8f95ef46 
       
     7 
       
     8 *** bgpd/bgp_dump.c
       
     9 --- bgpd/bgp_dump.c
       
    10 *************** bgp_dump_routes_index_table(struct bgp *
       
    11 *** 271,281 ****
       
    12   }
       
    13   
       
    14   
       
    15   /* Runs under child process. */
       
    16   static unsigned int
       
    17   bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
       
    18   {
       
    19 -   struct stream *obuf;
       
    20     struct bgp_info *info;
       
    21     struct bgp_node *rn;
       
    22     struct bgp *bgp;
       
    23 --- 271,364 ----
       
    24   }
       
    25   
       
    26   
       
    27 + static struct bgp_info *
       
    28 + bgp_dump_route_node_record (int afi, struct bgp_node *rn, struct bgp_info *info, unsigned int seq)
       
    29 + {
       
    30 +   struct stream *obuf;
       
    31 +   size_t sizep;
       
    32 +   size_t endp;
       
    33 + 
       
    34 +   obuf = bgp_dump_obuf;
       
    35 +   stream_reset(obuf);
       
    36 + 
       
    37 +   /* MRT header */
       
    38 +   if (afi == AFI_IP)
       
    39 +     bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST);
       
    40 +   else if (afi == AFI_IP6)
       
    41 +     bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST);
       
    42 + 
       
    43 +   /* Sequence number */
       
    44 +   stream_putl(obuf, seq);
       
    45 + 
       
    46 +   /* Prefix length */
       
    47 +   stream_putc (obuf, rn->p.prefixlen);
       
    48 + 
       
    49 +   /* Prefix */
       
    50 +   if (afi == AFI_IP)
       
    51 +   {
       
    52 +     /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
       
    53 +     stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
       
    54 +   }
       
    55 +   else if (afi == AFI_IP6)
       
    56 +   {
       
    57 +     /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
       
    58 +     stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
       
    59 +   }
       
    60 + 
       
    61 +   /* Save where we are now, so we can overwride the entry count later */
       
    62 +   sizep = stream_get_endp(obuf);
       
    63 + 
       
    64 +   /* Entry count */
       
    65 +   uint16_t entry_count = 0;
       
    66 + 
       
    67 +   /* Entry count, note that this is overwritten later */
       
    68 +   stream_putw(obuf, 0);
       
    69 + 
       
    70 +   endp = stream_get_endp(obuf);
       
    71 +   for (; info; info = info->next)
       
    72 +   {
       
    73 +     size_t cur_endp;
       
    74 + 
       
    75 +     /* Peer index */
       
    76 +     stream_putw(obuf, info->peer->table_dump_index);
       
    77 + 
       
    78 +     /* Originated */
       
    79 + #ifdef HAVE_CLOCK_MONOTONIC
       
    80 +           stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
       
    81 + #else
       
    82 +     stream_putl (obuf, info->uptime);
       
    83 + #endif /* HAVE_CLOCK_MONOTONIC */
       
    84 + 
       
    85 +     /* Dump attribute. */
       
    86 +     /* Skip prefix & AFI/SAFI for MP_NLRI */
       
    87 +     bgp_dump_routes_attr (obuf, info->attr, &rn->p);
       
    88 + 
       
    89 +     cur_endp = stream_get_endp(obuf);
       
    90 +     if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
       
    91 +                    + BGP_DUMP_HEADER_SIZE)
       
    92 +     {
       
    93 +       stream_set_endp(obuf, endp);
       
    94 +       break;
       
    95 +     }
       
    96 + 
       
    97 +     entry_count++;
       
    98 +     endp = cur_endp;
       
    99 +   }
       
   100 + 
       
   101 +   /* Overwrite the entry count, now that we know the right number */
       
   102 +   stream_putw_at (obuf, sizep, entry_count);
       
   103 + 
       
   104 +   bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
       
   105 +   fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
       
   106 + 
       
   107 +   return info;
       
   108 + }
       
   109 + 
       
   110 + 
       
   111   /* Runs under child process. */
       
   112   static unsigned int
       
   113   bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
       
   114   {
       
   115     struct bgp_info *info;
       
   116     struct bgp_node *rn;
       
   117     struct bgp *bgp;
       
   118 *************** bgp_dump_routes_func (int afi, int first
       
   119 *** 294,380 ****
       
   120     if(first_run)
       
   121       bgp_dump_routes_index_table(bgp);
       
   122   
       
   123 -   obuf = bgp_dump_obuf;
       
   124 -   stream_reset(obuf);
       
   125 - 
       
   126     /* Walk down each BGP route. */
       
   127     table = bgp->rib[afi][SAFI_UNICAST];
       
   128   
       
   129     for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
       
   130       {
       
   131 !       if(!rn->info)
       
   132 !         continue;
       
   133 ! 
       
   134 !       stream_reset(obuf);
       
   135 ! 
       
   136 !       /* MRT header */
       
   137 !       if (afi == AFI_IP)
       
   138 !         {
       
   139 !           bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST);
       
   140 !         }
       
   141 ! #ifdef HAVE_IPV6
       
   142 !       else if (afi == AFI_IP6)
       
   143 !         {
       
   144 !           bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST);
       
   145 !         }
       
   146 ! #endif /* HAVE_IPV6 */
       
   147 ! 
       
   148 !       /* Sequence number */
       
   149 !       stream_putl(obuf, seq);
       
   150 ! 
       
   151 !       /* Prefix length */
       
   152 !       stream_putc (obuf, rn->p.prefixlen);
       
   153 ! 
       
   154 !       /* Prefix */
       
   155 !       if (afi == AFI_IP)
       
   156 !         {
       
   157 !           /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
       
   158 !           stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
       
   159 !         }
       
   160 ! #ifdef HAVE_IPV6
       
   161 !       else if (afi == AFI_IP6)
       
   162 !         {
       
   163 !           /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
       
   164 !           stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
       
   165 !         }
       
   166 ! #endif /* HAVE_IPV6 */
       
   167 ! 
       
   168 !       /* Save where we are now, so we can overwride the entry count later */
       
   169 !       int sizep = stream_get_endp(obuf);
       
   170 ! 
       
   171 !       /* Entry count */
       
   172 !       uint16_t entry_count = 0;
       
   173 ! 
       
   174 !       /* Entry count, note that this is overwritten later */
       
   175 !       stream_putw(obuf, 0);
       
   176 ! 
       
   177 !       for (info = rn->info; info; info = info->next)
       
   178 !         {
       
   179 !           entry_count++;
       
   180 ! 
       
   181 !           /* Peer index */
       
   182 !           stream_putw(obuf, info->peer->table_dump_index);
       
   183 ! 
       
   184 !           /* Originated */
       
   185 ! #ifdef HAVE_CLOCK_MONOTONIC
       
   186 !           stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
       
   187 ! #else
       
   188 !           stream_putl (obuf, info->uptime);
       
   189 ! #endif /* HAVE_CLOCK_MONOTONIC */
       
   190 ! 
       
   191 !           /* Dump attribute. */
       
   192 !           /* Skip prefix & AFI/SAFI for MP_NLRI */
       
   193 !           bgp_dump_routes_attr (obuf, info->attr, &rn->p);
       
   194 !         }
       
   195 ! 
       
   196 !       /* Overwrite the entry count, now that we know the right number */
       
   197 !       stream_putw_at (obuf, sizep, entry_count);
       
   198 ! 
       
   199 !       seq++;
       
   200 ! 
       
   201 !       bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
       
   202 !       fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
       
   203 ! 
       
   204       }
       
   205   
       
   206     fflush (bgp_dump_routes.fp);
       
   207 --- 377,393 ----
       
   208     if(first_run)
       
   209       bgp_dump_routes_index_table(bgp);
       
   210   
       
   211     /* Walk down each BGP route. */
       
   212     table = bgp->rib[afi][SAFI_UNICAST];
       
   213   
       
   214     for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
       
   215       {
       
   216 ! 	    info = rn->info;
       
   217 ! 	    while (info)
       
   218 ! 	    {
       
   219 ! 		    info = bgp_dump_route_node_record(afi, rn, info, seq);
       
   220 ! 		    seq++;
       
   221 ! 	    }
       
   222       }
       
   223   
       
   224     fflush (bgp_dump_routes.fp);
       
   225 *************** bgp_dump_init (void)
       
   226 *** 854,861 ****
       
   227     memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
       
   228     memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
       
   229   
       
   230 !   bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
       
   231 !                               + BGP_DUMP_HEADER_SIZE);
       
   232   
       
   233     install_node (&bgp_dump_node, config_write_bgp_dump);
       
   234   
       
   235 --- 867,874 ----
       
   236     memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
       
   237     memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
       
   238   
       
   239 !   bgp_dump_obuf = stream_new ((BGP_MAX_PACKET_SIZE << 1)
       
   240 !                               + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE);
       
   241   
       
   242     install_node (&bgp_dump_node, config_write_bgp_dump);
       
   243   
       
   244 *** lib/stream.c
       
   245 --- lib/stream.c
       
   246 *************** stream_set_getp (struct stream *s, size_
       
   247 *** 214,219 ****
       
   248 --- 214,243 ----
       
   249     s->getp = pos;
       
   250   }
       
   251   
       
   252 + void
       
   253 + stream_set_endp (struct stream *s, size_t pos)
       
   254 + {
       
   255 +   STREAM_VERIFY_SANE(s);
       
   256 + 
       
   257 +   if (!ENDP_VALID(s, pos))
       
   258 +     {
       
   259 +       STREAM_BOUND_WARN (s, "set endp");
       
   260 +       return;
       
   261 +     }
       
   262 + 
       
   263 +   /*
       
   264 +    * Make sure the current read pointer is not beyond the new endp.
       
   265 +    */
       
   266 +   if (s->getp > pos)
       
   267 +     {
       
   268 +       STREAM_BOUND_WARN(s, "set endp");
       
   269 +       return;
       
   270 +     }
       
   271 + 
       
   272 +   s->endp = pos;
       
   273 +   STREAM_VERIFY_SANE(s);
       
   274 + }
       
   275 + 
       
   276   /* Forward pointer. */
       
   277   void
       
   278   stream_forward_getp (struct stream *s, size_t size)
       
   279 *** lib/stream.h
       
   280 --- lib/stream.h
       
   281 *************** extern size_t stream_get_size (struct st
       
   282 *** 146,151 ****
       
   283 --- 146,152 ----
       
   284   extern u_char *stream_get_data (struct stream *);
       
   285   
       
   286   extern void stream_set_getp (struct stream *, size_t);
       
   287 + extern void stream_set_endp (struct stream *, size_t);
       
   288   extern void stream_forward_getp (struct stream *, size_t);
       
   289   extern void stream_forward_endp (struct stream *, size_t);
       
   290