wok-4.x view glibc/stuff/patches/glibc-2.22-CVE-2015-7547-getaddrinfo-stack-based-buffer-overflow.patch @ rev 12476

Up glibc (2.22) with CVE patchs
author Stanislas Leduc <shann@slitaz.org>
date Wed Mar 15 11:41:38 2023 +0000 (14 months ago)
parents
children
line source
1 Based on:
3 From b995d95a5943785be3ab862b2d3276f3b4a22481 Mon Sep 17 00:00:00 2001
4 From: Carlos O'Donell <carlos@systemhalted.org>
5 Date: Tue, 16 Feb 2016 21:26:37 -0500
6 Subject: [PATCH] CVE-2015-7547: getaddrinfo() stack-based buffer overflow (Bug
7 18665).
9 * A stack-based buffer overflow was found in libresolv when invoked from
10 libnss_dns, allowing specially crafted DNS responses to seize control
11 of execution flow in the DNS client. The buffer overflow occurs in
12 the functions send_dg (send datagram) and send_vc (send TCP) for the
13 NSS module libnss_dns.so.2 when calling getaddrinfo with AF_UNSPEC
14 family. The use of AF_UNSPEC triggers the low-level resolver code to
15 send out two parallel queries for A and AAAA. A mismanagement of the
16 buffers used for those queries could result in the response of a query
17 writing beyond the alloca allocated buffer created by
18 _nss_dns_gethostbyname4_r. Buffer management is simplified to remove
19 the overflow. Thanks to the Google Security Team and Red Hat for
20 reporting the security impact of this issue, and Robert Holiday of
21 Ciena for reporting the related bug 18665. (CVE-2015-7547)
23 See also:
24 https://sourceware.org/ml/libc-alpha/2016-02/msg00416.html
25 https://sourceware.org/ml/libc-alpha/2016-02/msg00418.html
27 (cherry picked from commit e9db92d3acfe1822d56d11abcea5bfc4c41cf6ca)
28 ---
29 ChangeLog | 15 +++
30 NEWS | 14 +++
31 resolv/nss_dns/dns-host.c | 111 ++++++++++++++++++-
32 resolv/res_query.c | 3 +
33 resolv/res_send.c | 264 ++++++++++++++++++++++++++++++++++------------
34 5 files changed, 338 insertions(+), 69 deletions(-)
36 diff --git a/NEWS b/NEWS
37 index d1daf9b..81ceeae 100644
38 --- a/NEWS
39 +++ b/NEWS
40 @@ -7,6 +7,20 @@ using `glibc' in the "product" field.
42 Version 2.22.1
44 +* A stack-based buffer overflow was found in libresolv when invoked from
45 + libnss_dns, allowing specially crafted DNS responses to seize control
46 + of execution flow in the DNS client. The buffer overflow occurs in
47 + the functions send_dg (send datagram) and send_vc (send TCP) for the
48 + NSS module libnss_dns.so.2 when calling getaddrinfo with AF_UNSPEC
49 + family. The use of AF_UNSPEC triggers the low-level resolver code to
50 + send out two parallel queries for A and AAAA. A mismanagement of the
51 + buffers used for those queries could result in the response of a query
52 + writing beyond the alloca allocated buffer created by
53 + _nss_dns_gethostbyname4_r. Buffer management is simplified to remove
54 + the overflow. Thanks to the Google Security Team and Red Hat for
55 + reporting the security impact of this issue, and Robert Holiday of
56 + Ciena for reporting the related bug 18665. (CVE-2015-7547)
57 +
58 * The following bugs are resolved with this release:
60 17905, 18420, 18421, 18480, 18589, 18743, 18778, 18781, 18787, 18796,
61 diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
62 index 357ac04..a0fe9a8 100644
63 --- a/resolv/nss_dns/dns-host.c
64 +++ b/resolv/nss_dns/dns-host.c
65 @@ -1031,7 +1031,10 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
66 int h_namelen = 0;
68 if (ancount == 0)
69 - return NSS_STATUS_NOTFOUND;
70 + {
71 + *h_errnop = HOST_NOT_FOUND;
72 + return NSS_STATUS_NOTFOUND;
73 + }
75 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
76 {
77 @@ -1208,7 +1211,14 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
78 /* Special case here: if the resolver sent a result but it only
79 contains a CNAME while we are looking for a T_A or T_AAAA record,
80 we fail with NOTFOUND instead of TRYAGAIN. */
81 - return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
82 + if (canon != NULL)
83 + {
84 + *h_errnop = HOST_NOT_FOUND;
85 + return NSS_STATUS_NOTFOUND;
86 + }
87 +
88 + *h_errnop = NETDB_INTERNAL;
89 + return NSS_STATUS_TRYAGAIN;
90 }
93 @@ -1222,11 +1232,101 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
95 enum nss_status status = NSS_STATUS_NOTFOUND;
97 + /* Combining the NSS status of two distinct queries requires some
98 + compromise and attention to symmetry (A or AAAA queries can be
99 + returned in any order). What follows is a breakdown of how this
100 + code is expected to work and why. We discuss only SUCCESS,
101 + TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns
102 + that apply (though RETURN and MERGE exist). We make a distinction
103 + between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
104 + A recoverable TRYAGAIN is almost always due to buffer size issues
105 + and returns ERANGE in errno and the caller is expected to retry
106 + with a larger buffer.
107 +
108 + Lastly, you may be tempted to make significant changes to the
109 + conditions in this code to bring about symmetry between responses.
110 + Please don't change anything without due consideration for
111 + expected application behaviour. Some of the synthesized responses
112 + aren't very well thought out and sometimes appear to imply that
113 + IPv4 responses are always answer 1, and IPv6 responses are always
114 + answer 2, but that's not true (see the implementation of send_dg
115 + and send_vc to see response can arrive in any order, particularly
116 + for UDP). However, we expect it holds roughly enough of the time
117 + that this code works, but certainly needs to be fixed to make this
118 + a more robust implementation.
119 +
120 + ----------------------------------------------
121 + | Answer 1 Status / | Synthesized | Reason |
122 + | Answer 2 Status | Status | |
123 + |--------------------------------------------|
124 + | SUCCESS/SUCCESS | SUCCESS | [1] |
125 + | SUCCESS/TRYAGAIN | TRYAGAIN | [5] |
126 + | SUCCESS/TRYAGAIN' | SUCCESS | [1] |
127 + | SUCCESS/NOTFOUND | SUCCESS | [1] |
128 + | SUCCESS/UNAVAIL | SUCCESS | [1] |
129 + | TRYAGAIN/SUCCESS | TRYAGAIN | [2] |
130 + | TRYAGAIN/TRYAGAIN | TRYAGAIN | [2] |
131 + | TRYAGAIN/TRYAGAIN' | TRYAGAIN | [2] |
132 + | TRYAGAIN/NOTFOUND | TRYAGAIN | [2] |
133 + | TRYAGAIN/UNAVAIL | TRYAGAIN | [2] |
134 + | TRYAGAIN'/SUCCESS | SUCCESS | [3] |
135 + | TRYAGAIN'/TRYAGAIN | TRYAGAIN | [3] |
136 + | TRYAGAIN'/TRYAGAIN' | TRYAGAIN' | [3] |
137 + | TRYAGAIN'/NOTFOUND | TRYAGAIN' | [3] |
138 + | TRYAGAIN'/UNAVAIL | UNAVAIL | [3] |
139 + | NOTFOUND/SUCCESS | SUCCESS | [3] |
140 + | NOTFOUND/TRYAGAIN | TRYAGAIN | [3] |
141 + | NOTFOUND/TRYAGAIN' | TRYAGAIN' | [3] |
142 + | NOTFOUND/NOTFOUND | NOTFOUND | [3] |
143 + | NOTFOUND/UNAVAIL | UNAVAIL | [3] |
144 + | UNAVAIL/SUCCESS | UNAVAIL | [4] |
145 + | UNAVAIL/TRYAGAIN | UNAVAIL | [4] |
146 + | UNAVAIL/TRYAGAIN' | UNAVAIL | [4] |
147 + | UNAVAIL/NOTFOUND | UNAVAIL | [4] |
148 + | UNAVAIL/UNAVAIL | UNAVAIL | [4] |
149 + ----------------------------------------------
150 +
151 + [1] If the first response is a success we return success.
152 + This ignores the state of the second answer and in fact
153 + incorrectly sets errno and h_errno to that of the second
154 + answer. However because the response is a success we ignore
155 + *errnop and *h_errnop (though that means you touched errno on
156 + success). We are being conservative here and returning the
157 + likely IPv4 response in the first answer as a success.
158 +
159 + [2] If the first response is a recoverable TRYAGAIN we return
160 + that instead of looking at the second response. The
161 + expectation here is that we have failed to get an IPv4 response
162 + and should retry both queries.
163 +
164 + [3] If the first response was not a SUCCESS and the second
165 + response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN,
166 + or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the
167 + result from the second response, otherwise the first responses
168 + status is used. Again we have some odd side-effects when the
169 + second response is NOTFOUND because we overwrite *errnop and
170 + *h_errnop that means that a first answer of NOTFOUND might see
171 + its *errnop and *h_errnop values altered. Whether it matters
172 + in practice that a first response NOTFOUND has the wrong
173 + *errnop and *h_errnop is undecided.
174 +
175 + [4] If the first response is UNAVAIL we return that instead of
176 + looking at the second response. The expectation here is that
177 + it will have failed similarly e.g. configuration failure.
178 +
179 + [5] Testing this code is complicated by the fact that truncated
180 + second response buffers might be returned as SUCCESS if the
181 + first answer is a SUCCESS. To fix this we add symmetry to
182 + TRYAGAIN with the second response. If the second response
183 + is a recoverable error we now return TRYAGIN even if the first
184 + response was SUCCESS. */
185 +
186 if (anslen1 > 0)
187 status = gaih_getanswer_slice(answer1, anslen1, qname,
188 &pat, &buffer, &buflen,
189 errnop, h_errnop, ttlp,
190 &first);
191 +
192 if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
193 || (status == NSS_STATUS_TRYAGAIN
194 /* We want to look at the second answer in case of an
195 @@ -1242,8 +1342,15 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
196 &pat, &buffer, &buflen,
197 errnop, h_errnop, ttlp,
198 &first);
199 + /* Use the second response status in some cases. */
200 if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
201 status = status2;
202 + /* Do not return a truncated second response (unless it was
203 + unavoidable e.g. unrecoverable TRYAGAIN). */
204 + if (status == NSS_STATUS_SUCCESS
205 + && (status2 == NSS_STATUS_TRYAGAIN
206 + && *errnop == ERANGE && *h_errnop != NO_RECOVERY))
207 + status = NSS_STATUS_TRYAGAIN;
208 }
210 return status;
211 diff --git a/resolv/res_query.c b/resolv/res_query.c
212 index 4a9b3b3..95470a9 100644
213 --- a/resolv/res_query.c
214 +++ b/resolv/res_query.c
215 @@ -396,6 +396,7 @@ __libc_res_nsearch(res_state statp,
216 {
217 free (*answerp2);
218 *answerp2 = NULL;
219 + *nanswerp2 = 0;
220 *answerp2_malloced = 0;
221 }
222 }
223 @@ -447,6 +448,7 @@ __libc_res_nsearch(res_state statp,
224 {
225 free (*answerp2);
226 *answerp2 = NULL;
227 + *nanswerp2 = 0;
228 *answerp2_malloced = 0;
229 }
231 @@ -521,6 +523,7 @@ __libc_res_nsearch(res_state statp,
232 {
233 free (*answerp2);
234 *answerp2 = NULL;
235 + *nanswerp2 = 0;
236 *answerp2_malloced = 0;
237 }
238 if (saved_herrno != -1)
239 diff --git a/resolv/res_send.c b/resolv/res_send.c
240 index 5e53cc2..6511bb1 100644
241 --- a/resolv/res_send.c
242 +++ b/resolv/res_send.c
243 @@ -1,3 +1,20 @@
244 +/* Copyright (C) 2016 Free Software Foundation, Inc.
245 + This file is part of the GNU C Library.
246 +
247 + The GNU C Library is free software; you can redistribute it and/or
248 + modify it under the terms of the GNU Lesser General Public
249 + License as published by the Free Software Foundation; either
250 + version 2.1 of the License, or (at your option) any later version.
251 +
252 + The GNU C Library is distributed in the hope that it will be useful,
253 + but WITHOUT ANY WARRANTY; without even the implied warranty of
254 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
255 + Lesser General Public License for more details.
256 +
257 + You should have received a copy of the GNU Lesser General Public
258 + License along with the GNU C Library; if not, see
259 + <http://www.gnu.org/licenses/>. */
260 +
261 /*
262 * Copyright (c) 1985, 1989, 1993
263 * The Regents of the University of California. All rights reserved.
264 @@ -363,6 +380,8 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
265 #ifdef USE_HOOKS
266 if (__glibc_unlikely (statp->qhook || statp->rhook)) {
267 if (anssiz < MAXPACKET && ansp) {
268 + /* Always allocate MAXPACKET, callers expect
269 + this specific size. */
270 u_char *buf = malloc (MAXPACKET);
271 if (buf == NULL)
272 return (-1);
273 @@ -638,6 +657,77 @@ get_nsaddr (res_state statp, int n)
274 return (struct sockaddr *) (void *) &statp->nsaddr_list[n];
275 }
277 +/* The send_vc function is responsible for sending a DNS query over TCP
278 + to the nameserver numbered NS from the res_state STATP i.e.
279 + EXT(statp).nssocks[ns]. The function supports sending both IPv4 and
280 + IPv6 queries at the same serially on the same socket.
281 +
282 + Please note that for TCP there is no way to disable sending both
283 + queries, unlike UDP, which honours RES_SNGLKUP and RES_SNGLKUPREOP
284 + and sends the queries serially and waits for the result after each
285 + sent query. This implemetnation should be corrected to honour these
286 + options.
287 +
288 + Please also note that for TCP we send both queries over the same
289 + socket one after another. This technically violates best practice
290 + since the server is allowed to read the first query, respond, and
291 + then close the socket (to service another client). If the server
292 + does this, then the remaining second query in the socket data buffer
293 + will cause the server to send the client an RST which will arrive
294 + asynchronously and the client's OS will likely tear down the socket
295 + receive buffer resulting in a potentially short read and lost
296 + response data. This will force the client to retry the query again,
297 + and this process may repeat until all servers and connection resets
298 + are exhausted and then the query will fail. It's not known if this
299 + happens with any frequency in real DNS server implementations. This
300 + implementation should be corrected to use two sockets by default for
301 + parallel queries.
302 +
303 + The query stored in BUF of BUFLEN length is sent first followed by
304 + the query stored in BUF2 of BUFLEN2 length. Queries are sent
305 + serially on the same socket.
306 +
307 + Answers to the query are stored firstly in *ANSP up to a max of
308 + *ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP
309 + is non-NULL (to indicate that modifying the answer buffer is allowed)
310 + then malloc is used to allocate a new response buffer and ANSCP and
311 + ANSP will both point to the new buffer. If more than *ANSSIZP bytes
312 + are needed but ANSCP is NULL, then as much of the response as
313 + possible is read into the buffer, but the results will be truncated.
314 + When truncation happens because of a small answer buffer the DNS
315 + packets header field TC will bet set to 1, indicating a truncated
316 + message and the rest of the socket data will be read and discarded.
317 +
318 + Answers to the query are stored secondly in *ANSP2 up to a max of
319 + *ANSSIZP2 bytes, with the actual response length stored in
320 + *RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2
321 + is non-NULL (required for a second query) then malloc is used to
322 + allocate a new response buffer, *ANSSIZP2 is set to the new buffer
323 + size and *ANSP2_MALLOCED is set to 1.
324 +
325 + The ANSP2_MALLOCED argument will eventually be removed as the
326 + change in buffer pointer can be used to detect the buffer has
327 + changed and that the caller should use free on the new buffer.
328 +
329 + Note that the answers may arrive in any order from the server and
330 + therefore the first and second answer buffers may not correspond to
331 + the first and second queries.
332 +
333 + It is not supported to call this function with a non-NULL ANSP2
334 + but a NULL ANSCP. Put another way, you can call send_vc with a
335 + single unmodifiable buffer or two modifiable buffers, but no other
336 + combination is supported.
337 +
338 + It is the caller's responsibility to free the malloc allocated
339 + buffers by detecting that the pointers have changed from their
340 + original values i.e. *ANSCP or *ANSP2 has changed.
341 +
342 + If errors are encountered then *TERRNO is set to an appropriate
343 + errno value and a zero result is returned for a recoverable error,
344 + and a less-than zero result is returned for a non-recoverable error.
345 +
346 + If no errors are encountered then *TERRNO is left unmodified and
347 + a the length of the first response in bytes is returned. */
348 static int
349 send_vc(res_state statp,
350 const u_char *buf, int buflen, const u_char *buf2, int buflen2,
351 @@ -647,11 +737,7 @@ send_vc(res_state statp,
352 {
353 const HEADER *hp = (HEADER *) buf;
354 const HEADER *hp2 = (HEADER *) buf2;
355 - u_char *ans = *ansp;
356 - int orig_anssizp = *anssizp;
357 - // XXX REMOVE
358 - // int anssiz = *anssizp;
359 - HEADER *anhp = (HEADER *) ans;
360 + HEADER *anhp = (HEADER *) *ansp;
361 struct sockaddr *nsap = get_nsaddr (statp, ns);
362 int truncating, connreset, n;
363 /* On some architectures compiler might emit a warning indicating
364 @@ -743,6 +829,8 @@ send_vc(res_state statp,
365 * Receive length & response
366 */
367 int recvresp1 = 0;
368 + /* Skip the second response if there is no second query.
369 + To do that we mark the second response as received. */
370 int recvresp2 = buf2 == NULL;
371 uint16_t rlen16;
372 read_len:
373 @@ -779,40 +867,14 @@ send_vc(res_state statp,
374 u_char **thisansp;
375 int *thisresplenp;
376 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
377 + /* We have not received any responses
378 + yet or we only have one response to
379 + receive. */
380 thisanssizp = anssizp;
381 thisansp = anscp ?: ansp;
382 assert (anscp != NULL || ansp2 == NULL);
383 thisresplenp = &resplen;
384 } else {
385 - if (*anssizp != MAXPACKET) {
386 - /* No buffer allocated for the first
387 - reply. We can try to use the rest
388 - of the user-provided buffer. */
389 -#if __GNUC_PREREQ (4, 7)
390 - DIAG_PUSH_NEEDS_COMMENT;
391 - DIAG_IGNORE_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
392 -#endif
393 -#if _STRING_ARCH_unaligned
394 - *anssizp2 = orig_anssizp - resplen;
395 - *ansp2 = *ansp + resplen;
396 -#else
397 - int aligned_resplen
398 - = ((resplen + __alignof__ (HEADER) - 1)
399 - & ~(__alignof__ (HEADER) - 1));
400 - *anssizp2 = orig_anssizp - aligned_resplen;
401 - *ansp2 = *ansp + aligned_resplen;
402 -#endif
403 -#if __GNUC_PREREQ (4, 7)
404 - DIAG_POP_NEEDS_COMMENT;
405 -#endif
406 - } else {
407 - /* The first reply did not fit into the
408 - user-provided buffer. Maybe the second
409 - answer will. */
410 - *anssizp2 = orig_anssizp;
411 - *ansp2 = *ansp;
412 - }
413 -
414 thisanssizp = anssizp2;
415 thisansp = ansp2;
416 thisresplenp = resplen2;
417 @@ -820,10 +882,14 @@ send_vc(res_state statp,
418 anhp = (HEADER *) *thisansp;
420 *thisresplenp = rlen;
421 - if (rlen > *thisanssizp) {
422 - /* Yes, we test ANSCP here. If we have two buffers
423 - both will be allocatable. */
424 - if (__glibc_likely (anscp != NULL)) {
425 + /* Is the answer buffer too small? */
426 + if (*thisanssizp < rlen) {
427 + /* If the current buffer is not the the static
428 + user-supplied buffer then we can reallocate
429 + it. */
430 + if (thisansp != NULL && thisansp != ansp) {
431 + /* Always allocate MAXPACKET, callers expect
432 + this specific size. */
433 u_char *newp = malloc (MAXPACKET);
434 if (newp == NULL) {
435 *terrno = ENOMEM;
436 @@ -835,6 +901,9 @@ send_vc(res_state statp,
437 if (thisansp == ansp2)
438 *ansp2_malloced = 1;
439 anhp = (HEADER *) newp;
440 + /* A uint16_t can't be larger than MAXPACKET
441 + thus it's safe to allocate MAXPACKET but
442 + read RLEN bytes instead. */
443 len = rlen;
444 } else {
445 Dprint(statp->options & RES_DEBUG,
446 @@ -997,6 +1066,66 @@ reopen (res_state statp, int *terrno, int ns)
447 return 1;
448 }
450 +/* The send_dg function is responsible for sending a DNS query over UDP
451 + to the nameserver numbered NS from the res_state STATP i.e.
452 + EXT(statp).nssocks[ns]. The function supports IPv4 and IPv6 queries
453 + along with the ability to send the query in parallel for both stacks
454 + (default) or serially (RES_SINGLKUP). It also supports serial lookup
455 + with a close and reopen of the socket used to talk to the server
456 + (RES_SNGLKUPREOP) to work around broken name servers.
457 +
458 + The query stored in BUF of BUFLEN length is sent first followed by
459 + the query stored in BUF2 of BUFLEN2 length. Queries are sent
460 + in parallel (default) or serially (RES_SINGLKUP or RES_SNGLKUPREOP).
461 +
462 + Answers to the query are stored firstly in *ANSP up to a max of
463 + *ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP
464 + is non-NULL (to indicate that modifying the answer buffer is allowed)
465 + then malloc is used to allocate a new response buffer and ANSCP and
466 + ANSP will both point to the new buffer. If more than *ANSSIZP bytes
467 + are needed but ANSCP is NULL, then as much of the response as
468 + possible is read into the buffer, but the results will be truncated.
469 + When truncation happens because of a small answer buffer the DNS
470 + packets header field TC will bet set to 1, indicating a truncated
471 + message, while the rest of the UDP packet is discarded.
472 +
473 + Answers to the query are stored secondly in *ANSP2 up to a max of
474 + *ANSSIZP2 bytes, with the actual response length stored in
475 + *RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2
476 + is non-NULL (required for a second query) then malloc is used to
477 + allocate a new response buffer, *ANSSIZP2 is set to the new buffer
478 + size and *ANSP2_MALLOCED is set to 1.
479 +
480 + The ANSP2_MALLOCED argument will eventually be removed as the
481 + change in buffer pointer can be used to detect the buffer has
482 + changed and that the caller should use free on the new buffer.
483 +
484 + Note that the answers may arrive in any order from the server and
485 + therefore the first and second answer buffers may not correspond to
486 + the first and second queries.
487 +
488 + It is not supported to call this function with a non-NULL ANSP2
489 + but a NULL ANSCP. Put another way, you can call send_vc with a
490 + single unmodifiable buffer or two modifiable buffers, but no other
491 + combination is supported.
492 +
493 + It is the caller's responsibility to free the malloc allocated
494 + buffers by detecting that the pointers have changed from their
495 + original values i.e. *ANSCP or *ANSP2 has changed.
496 +
497 + If an answer is truncated because of UDP datagram DNS limits then
498 + *V_CIRCUIT is set to 1 and the return value non-zero to indicate to
499 + the caller to retry with TCP. The value *GOTSOMEWHERE is set to 1
500 + if any progress was made reading a response from the nameserver and
501 + is used by the caller to distinguish between ECONNREFUSED and
502 + ETIMEDOUT (the latter if *GOTSOMEWHERE is 1).
503 +
504 + If errors are encountered then *TERRNO is set to an appropriate
505 + errno value and a zero result is returned for a recoverable error,
506 + and a less-than zero result is returned for a non-recoverable error.
507 +
508 + If no errors are encountered then *TERRNO is left unmodified and
509 + a the length of the first response in bytes is returned. */
510 static int
511 send_dg(res_state statp,
512 const u_char *buf, int buflen, const u_char *buf2, int buflen2,
513 @@ -1006,8 +1135,6 @@ send_dg(res_state statp,
514 {
515 const HEADER *hp = (HEADER *) buf;
516 const HEADER *hp2 = (HEADER *) buf2;
517 - u_char *ans = *ansp;
518 - int orig_anssizp = *anssizp;
519 struct timespec now, timeout, finish;
520 struct pollfd pfd[1];
521 int ptimeout;
522 @@ -1040,6 +1167,8 @@ send_dg(res_state statp,
523 int need_recompute = 0;
524 int nwritten = 0;
525 int recvresp1 = 0;
526 + /* Skip the second response if there is no second query.
527 + To do that we mark the second response as received. */
528 int recvresp2 = buf2 == NULL;
529 pfd[0].fd = EXT(statp).nssocks[ns];
530 pfd[0].events = POLLOUT;
531 @@ -1203,55 +1332,56 @@ send_dg(res_state statp,
532 int *thisresplenp;
534 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
535 + /* We have not received any responses
536 + yet or we only have one response to
537 + receive. */
538 thisanssizp = anssizp;
539 thisansp = anscp ?: ansp;
540 assert (anscp != NULL || ansp2 == NULL);
541 thisresplenp = &resplen;
542 } else {
543 - if (*anssizp != MAXPACKET) {
544 - /* No buffer allocated for the first
545 - reply. We can try to use the rest
546 - of the user-provided buffer. */
547 -#if _STRING_ARCH_unaligned
548 - *anssizp2 = orig_anssizp - resplen;
549 - *ansp2 = *ansp + resplen;
550 -#else
551 - int aligned_resplen
552 - = ((resplen + __alignof__ (HEADER) - 1)
553 - & ~(__alignof__ (HEADER) - 1));
554 - *anssizp2 = orig_anssizp - aligned_resplen;
555 - *ansp2 = *ansp + aligned_resplen;
556 -#endif
557 - } else {
558 - /* The first reply did not fit into the
559 - user-provided buffer. Maybe the second
560 - answer will. */
561 - *anssizp2 = orig_anssizp;
562 - *ansp2 = *ansp;
563 - }
564 -
565 thisanssizp = anssizp2;
566 thisansp = ansp2;
567 thisresplenp = resplen2;
568 }
570 if (*thisanssizp < MAXPACKET
571 - /* Yes, we test ANSCP here. If we have two buffers
572 - both will be allocatable. */
573 - && anscp
574 + /* If the current buffer is not the the static
575 + user-supplied buffer then we can reallocate
576 + it. */
577 + && (thisansp != NULL && thisansp != ansp)
578 #ifdef FIONREAD
579 + /* Is the size too small? */
580 && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
581 || *thisanssizp < *thisresplenp)
582 #endif
583 ) {
584 + /* Always allocate MAXPACKET, callers expect
585 + this specific size. */
586 u_char *newp = malloc (MAXPACKET);
587 if (newp != NULL) {
588 - *anssizp = MAXPACKET;
589 - *thisansp = ans = newp;
590 + *thisanssizp = MAXPACKET;
591 + *thisansp = newp;
592 if (thisansp == ansp2)
593 *ansp2_malloced = 1;
594 }
595 }
596 + /* We could end up with truncation if anscp was NULL
597 + (not allowed to change caller's buffer) and the
598 + response buffer size is too small. This isn't a
599 + reliable way to detect truncation because the ioctl
600 + may be an inaccurate report of the UDP message size.
601 + Therefore we use this only to issue debug output.
602 + To do truncation accurately with UDP we need
603 + MSG_TRUNC which is only available on Linux. We
604 + can abstract out the Linux-specific feature in the
605 + future to detect truncation. */
606 + if (__glibc_unlikely (*thisanssizp < *thisresplenp)) {
607 + Dprint(statp->options & RES_DEBUG,
608 + (stdout, ";; response may be truncated (UDP)\n")
609 + );
610 + }
611 +
612 HEADER *anhp = (HEADER *) *thisansp;
613 socklen_t fromlen = sizeof(struct sockaddr_in6);
614 assert (sizeof(from) <= fromlen);
615 --
616 1.9.4