]>
Commit | Line | Data |
---|---|---|
b9215da1 MT |
1 | From b25508dd774b617f99419bdc3cf2ace4560cd2d6 Mon Sep 17 00:00:00 2001 |
2 | From: Florian Weimer <fweimer@redhat.com> | |
3 | Date: Wed, 13 Sep 2023 14:10:56 +0200 | |
4 | Subject: [PATCH 19/27] CVE-2023-4527: Stack read overflow with large TCP | |
5 | responses in no-aaaa mode | |
6 | ||
7 | Without passing alt_dns_packet_buffer, __res_context_search can only | |
8 | store 2048 bytes (what fits into dns_packet_buffer). However, | |
9 | the function returns the total packet size, and the subsequent | |
10 | DNS parsing code in _nss_dns_gethostbyname4_r reads beyond the end | |
11 | of the stack-allocated buffer. | |
12 | ||
13 | Fixes commit f282cdbe7f436c75864e5640a4 ("resolv: Implement no-aaaa | |
14 | stub resolver option") and bug 30842. | |
15 | ||
16 | (cherry picked from commit bd77dd7e73e3530203be1c52c8a29d08270cb25d) | |
17 | --- | |
18 | NEWS | 9 +++ | |
19 | resolv/Makefile | 2 + | |
20 | resolv/nss_dns/dns-host.c | 2 +- | |
21 | resolv/tst-resolv-noaaaa-vc.c | 129 ++++++++++++++++++++++++++++++++++ | |
22 | 4 files changed, 141 insertions(+), 1 deletion(-) | |
23 | create mode 100644 resolv/tst-resolv-noaaaa-vc.c | |
24 | ||
25 | diff --git a/NEWS b/NEWS | |
26 | index 64596d5d09..dfee278a9c 100644 | |
27 | --- a/NEWS | |
28 | +++ b/NEWS | |
29 | @@ -7,12 +7,21 @@ using `glibc' in the "product" field. | |
30 | \f | |
31 | Version 2.38.1 | |
32 | ||
33 | +Security related changes: | |
34 | + | |
35 | + CVE-2023-4527: If the system is configured in no-aaaa mode via | |
36 | + /etc/resolv.conf, getaddrinfo is called for the AF_UNSPEC address | |
37 | + family, and a DNS response is received over TCP that is larger than | |
38 | + 2048 bytes, getaddrinfo may potentially disclose stack contents via | |
39 | + the returned address data, or crash. | |
40 | + | |
41 | The following bugs are resolved with this release: | |
42 | ||
43 | [30723] posix_memalign repeatedly scans long bin lists | |
44 | [30785] Always call destructors in reverse constructor order | |
45 | [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with | |
46 | -D_FILE_OFFSET_BITS=64 | |
47 | + [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) | |
48 | ||
49 | \f | |
50 | Version 2.38 | |
51 | diff --git a/resolv/Makefile b/resolv/Makefile | |
52 | index 054b1fa36c..2f99eb3862 100644 | |
53 | --- a/resolv/Makefile | |
54 | +++ b/resolv/Makefile | |
55 | @@ -102,6 +102,7 @@ tests += \ | |
56 | tst-resolv-invalid-cname \ | |
57 | tst-resolv-network \ | |
58 | tst-resolv-noaaaa \ | |
59 | + tst-resolv-noaaaa-vc \ | |
60 | tst-resolv-nondecimal \ | |
61 | tst-resolv-res_init-multi \ | |
62 | tst-resolv-search \ | |
63 | @@ -293,6 +294,7 @@ $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \ | |
64 | $(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \ | |
65 | $(shared-thread-library) | |
66 | $(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library) | |
67 | +$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library) | |
68 | $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) | |
69 | $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) | |
70 | $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) | |
71 | diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c | |
72 | index 1d60c51f5e..5d0ab30de6 100644 | |
73 | --- a/resolv/nss_dns/dns-host.c | |
74 | +++ b/resolv/nss_dns/dns-host.c | |
75 | @@ -427,7 +427,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, | |
76 | { | |
77 | n = __res_context_search (ctx, name, C_IN, T_A, | |
78 | dns_packet_buffer, sizeof (dns_packet_buffer), | |
79 | - NULL, NULL, NULL, NULL, NULL); | |
80 | + &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); | |
81 | if (n >= 0) | |
82 | status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n, | |
83 | &abuf, pat, errnop, herrnop, ttlp); | |
84 | diff --git a/resolv/tst-resolv-noaaaa-vc.c b/resolv/tst-resolv-noaaaa-vc.c | |
85 | new file mode 100644 | |
86 | index 0000000000..9f5aebd99f | |
87 | --- /dev/null | |
88 | +++ b/resolv/tst-resolv-noaaaa-vc.c | |
89 | @@ -0,0 +1,129 @@ | |
90 | +/* Test the RES_NOAAAA resolver option with a large response. | |
91 | + Copyright (C) 2022-2023 Free Software Foundation, Inc. | |
92 | + This file is part of the GNU C Library. | |
93 | + | |
94 | + The GNU C Library is free software; you can redistribute it and/or | |
95 | + modify it under the terms of the GNU Lesser General Public | |
96 | + License as published by the Free Software Foundation; either | |
97 | + version 2.1 of the License, or (at your option) any later version. | |
98 | + | |
99 | + The GNU C Library is distributed in the hope that it will be useful, | |
100 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
101 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
102 | + Lesser General Public License for more details. | |
103 | + | |
104 | + You should have received a copy of the GNU Lesser General Public | |
105 | + License along with the GNU C Library; if not, see | |
106 | + <https://www.gnu.org/licenses/>. */ | |
107 | + | |
108 | +#include <errno.h> | |
109 | +#include <netdb.h> | |
110 | +#include <resolv.h> | |
111 | +#include <stdbool.h> | |
112 | +#include <stdlib.h> | |
113 | +#include <support/check.h> | |
114 | +#include <support/check_nss.h> | |
115 | +#include <support/resolv_test.h> | |
116 | +#include <support/support.h> | |
117 | +#include <support/xmemstream.h> | |
118 | + | |
119 | +/* Used to keep track of the number of queries. */ | |
120 | +static volatile unsigned int queries; | |
121 | + | |
122 | +/* If true, add a large TXT record at the start of the answer section. */ | |
123 | +static volatile bool stuff_txt; | |
124 | + | |
125 | +static void | |
126 | +response (const struct resolv_response_context *ctx, | |
127 | + struct resolv_response_builder *b, | |
128 | + const char *qname, uint16_t qclass, uint16_t qtype) | |
129 | +{ | |
130 | + /* If not using TCP, just force its use. */ | |
131 | + if (!ctx->tcp) | |
132 | + { | |
133 | + struct resolv_response_flags flags = {.tc = true}; | |
134 | + resolv_response_init (b, flags); | |
135 | + resolv_response_add_question (b, qname, qclass, qtype); | |
136 | + return; | |
137 | + } | |
138 | + | |
139 | + /* The test needs to send four queries, the first three are used to | |
140 | + grow the NSS buffer via the ERANGE handshake. */ | |
141 | + ++queries; | |
142 | + TEST_VERIFY (queries <= 4); | |
143 | + | |
144 | + /* AAAA queries are supposed to be disabled. */ | |
145 | + TEST_COMPARE (qtype, T_A); | |
146 | + TEST_COMPARE (qclass, C_IN); | |
147 | + TEST_COMPARE_STRING (qname, "example.com"); | |
148 | + | |
149 | + struct resolv_response_flags flags = {}; | |
150 | + resolv_response_init (b, flags); | |
151 | + resolv_response_add_question (b, qname, qclass, qtype); | |
152 | + | |
153 | + resolv_response_section (b, ns_s_an); | |
154 | + | |
155 | + if (stuff_txt) | |
156 | + { | |
157 | + resolv_response_open_record (b, qname, qclass, T_TXT, 60); | |
158 | + int zero = 0; | |
159 | + for (int i = 0; i <= 15000; ++i) | |
160 | + resolv_response_add_data (b, &zero, sizeof (zero)); | |
161 | + resolv_response_close_record (b); | |
162 | + } | |
163 | + | |
164 | + for (int i = 0; i < 200; ++i) | |
165 | + { | |
166 | + resolv_response_open_record (b, qname, qclass, qtype, 60); | |
167 | + char ipv4[4] = {192, 0, 2, i + 1}; | |
168 | + resolv_response_add_data (b, &ipv4, sizeof (ipv4)); | |
169 | + resolv_response_close_record (b); | |
170 | + } | |
171 | +} | |
172 | + | |
173 | +static int | |
174 | +do_test (void) | |
175 | +{ | |
176 | + struct resolv_test *obj = resolv_test_start | |
177 | + ((struct resolv_redirect_config) | |
178 | + { | |
179 | + .response_callback = response | |
180 | + }); | |
181 | + | |
182 | + _res.options |= RES_NOAAAA; | |
183 | + | |
184 | + for (int do_stuff_txt = 0; do_stuff_txt < 2; ++do_stuff_txt) | |
185 | + { | |
186 | + queries = 0; | |
187 | + stuff_txt = do_stuff_txt; | |
188 | + | |
189 | + struct addrinfo *ai = NULL; | |
190 | + int ret; | |
191 | + ret = getaddrinfo ("example.com", "80", | |
192 | + &(struct addrinfo) | |
193 | + { | |
194 | + .ai_family = AF_UNSPEC, | |
195 | + .ai_socktype = SOCK_STREAM, | |
196 | + }, &ai); | |
197 | + | |
198 | + char *expected_result; | |
199 | + { | |
200 | + struct xmemstream mem; | |
201 | + xopen_memstream (&mem); | |
202 | + for (int i = 0; i < 200; ++i) | |
203 | + fprintf (mem.out, "address: STREAM/TCP 192.0.2.%d 80\n", i + 1); | |
204 | + xfclose_memstream (&mem); | |
205 | + expected_result = mem.buffer; | |
206 | + } | |
207 | + | |
208 | + check_addrinfo ("example.com", ai, ret, expected_result); | |
209 | + | |
210 | + free (expected_result); | |
211 | + freeaddrinfo (ai); | |
212 | + } | |
213 | + | |
214 | + resolv_test_end (obj); | |
215 | + return 0; | |
216 | +} | |
217 | + | |
218 | +#include <support/test-driver.c> | |
219 | -- | |
220 | 2.39.2 | |
221 |