|
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 |