summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYash Shinde <Yash.Shinde@windriver.com>2023-09-29 06:08:38 -0700
committerSteve Sakoman <steve@sakoman.com>2023-10-04 05:21:26 -1000
commitbd19b162aad145fd68dd772f1669d7af2fb70d6f (patch)
treebb3b843ea822c45ee4075cde5874623071845329
parenta61e021c65cb11aa6221f412fb89afc5476cc5e3 (diff)
downloadpoky-bd19b162aad145fd68dd772f1669d7af2fb70d6f.tar.gz
glibc: fix CVE-2023-4806
Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=973fe93a5675c42798b2161c6f29c01b0e243994] (From OE-Core rev: 7591adeb37f9156266ef98b639073e986e3a49f5) Signed-off-by: Yash Shinde <Yash.Shinde@windriver.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
-rw-r--r--meta/recipes-core/glibc/glibc/0024-CVE-2023-4806.patch342
-rw-r--r--meta/recipes-core/glibc/glibc_2.37.bb1
2 files changed, 343 insertions, 0 deletions
diff --git a/meta/recipes-core/glibc/glibc/0024-CVE-2023-4806.patch b/meta/recipes-core/glibc/glibc/0024-CVE-2023-4806.patch
new file mode 100644
index 0000000000..42d91fd340
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/0024-CVE-2023-4806.patch
@@ -0,0 +1,342 @@
1From 973fe93a5675c42798b2161c6f29c01b0e243994 Mon Sep 17 00:00:00 2001
2From: Siddhesh Poyarekar <siddhesh@sourceware.org>
3Date: Fri, 15 Sep 2023 13:51:12 -0400
4Subject: [PATCH] getaddrinfo: Fix use after free in getcanonname
5 (CVE-2023-4806)
6
7When an NSS plugin only implements the _gethostbyname2_r and
8_getcanonname_r callbacks, getaddrinfo could use memory that was freed
9during tmpbuf resizing, through h_name in a previous query response.
10
11The backing store for res->at->name when doing a query with
12gethostbyname3_r or gethostbyname2_r is tmpbuf, which is reallocated in
13gethosts during the query. For AF_INET6 lookup with AI_ALL |
14AI_V4MAPPED, gethosts gets called twice, once for a v6 lookup and second
15for a v4 lookup. In this case, if the first call reallocates tmpbuf
16enough number of times, resulting in a malloc, th->h_name (that
17res->at->name refers to) ends up on a heap allocated storage in tmpbuf.
18Now if the second call to gethosts also causes the plugin callback to
19return NSS_STATUS_TRYAGAIN, tmpbuf will get freed, resulting in a UAF
20reference in res->at->name. This then gets dereferenced in the
21getcanonname_r plugin call, resulting in the use after free.
22
23Fix this by copying h_name over and freeing it at the end. This
24resolves BZ #30843, which is assigned CVE-2023-4806.
25
26Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=973fe93a5675c42798b2161c6f29c01b0e243994]
27CVE: CVE-2023-4806
28
29Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
30
31Signed-off-by: Yash Shinde <Yash.Shinde@windriver.com>
32---
33 nss/Makefile | 15 ++++-
34 nss/nss_test_gai_hv2_canonname.c | 56 +++++++++++++++++
35 nss/tst-nss-gai-hv2-canonname.c | 63 +++++++++++++++++++
36 nss/tst-nss-gai-hv2-canonname.h | 1 +
37 .../postclean.req | 0
38 .../tst-nss-gai-hv2-canonname.script | 2 +
39 sysdeps/posix/getaddrinfo.c | 25 +++++---
40 7 files changed, 152 insertions(+), 10 deletions(-)
41 create mode 100644 nss/nss_test_gai_hv2_canonname.c
42 create mode 100644 nss/tst-nss-gai-hv2-canonname.c
43 create mode 100644 nss/tst-nss-gai-hv2-canonname.h
44 create mode 100644 nss/tst-nss-gai-hv2-canonname.root/postclean.req
45 create mode 100644 nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
46
47diff --git a/nss/Makefile b/nss/Makefile
48index 06fcdc450f..8a5126ecf3 100644
49--- a/nss/Makefile
50+++ b/nss/Makefile
51@@ -82,6 +82,7 @@ tests-container := \
52 tst-nss-test3 \
53 tst-reload1 \
54 tst-reload2 \
55+ tst-nss-gai-hv2-canonname \
56 # tests-container
57
58 # Tests which need libdl
59@@ -145,7 +146,8 @@ libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes))
60 ifeq ($(build-static-nss),yes)
61 tests-static += tst-nss-static
62 endif
63-extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os
64+extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \
65+ nss_test_gai_hv2_canonname.os
66
67 include ../Rules
68
69@@ -180,12 +182,16 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver
70 libof-nss_test1 = extramodules
71 libof-nss_test2 = extramodules
72 libof-nss_test_errno = extramodules
73+libof-nss_test_gai_hv2_canonname = extramodules
74 $(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps)
75 $(build-module)
76 $(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps)
77 $(build-module)
78 $(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps)
79 $(build-module)
80+$(objpfx)/libnss_test_gai_hv2_canonname.so: \
81+ $(objpfx)nss_test_gai_hv2_canonname.os $(link-libc-deps)
82+ $(build-module)
83 $(objpfx)nss_test2.os : nss_test1.c
84 # Use the nss_files suffix for these objects as well.
85 $(objpfx)/libnss_test1.so$(libnss_files.so-version): $(objpfx)/libnss_test1.so
86@@ -195,10 +201,14 @@ $(objpfx)/libnss_test2.so$(libnss_files.so-version): $(objpfx)/libnss_test2.so
87 $(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \
88 $(objpfx)/libnss_test_errno.so
89 $(make-link)
90+$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version): \
91+ $(objpfx)/libnss_test_gai_hv2_canonname.so
92+ $(make-link)
93 $(patsubst %,$(objpfx)%.out,$(tests) $(tests-container)) : \
94 $(objpfx)/libnss_test1.so$(libnss_files.so-version) \
95 $(objpfx)/libnss_test2.so$(libnss_files.so-version) \
96- $(objpfx)/libnss_test_errno.so$(libnss_files.so-version)
97+ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) \
98+ $(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version)
99
100 ifeq (yes,$(have-thread-library))
101 $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library)
102@@ -215,3 +225,4 @@ LDFLAGS-tst-nss-test3 = -Wl,--disable-new-dtags
103 LDFLAGS-tst-nss-test4 = -Wl,--disable-new-dtags
104 LDFLAGS-tst-nss-test5 = -Wl,--disable-new-dtags
105 LDFLAGS-tst-nss-test_errno = -Wl,--disable-new-dtags
106+LDFLAGS-tst-nss-test_gai_hv2_canonname = -Wl,--disable-new-dtags
107diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c
108new file mode 100644
109index 0000000000..4439c83c9f
110--- /dev/null
111+++ b/nss/nss_test_gai_hv2_canonname.c
112@@ -0,0 +1,56 @@
113+/* NSS service provider that only provides gethostbyname2_r.
114+ Copyright The GNU Toolchain Authors.
115+ This file is part of the GNU C Library.
116+
117+ The GNU C Library is free software; you can redistribute it and/or
118+ modify it under the terms of the GNU Lesser General Public
119+ License as published by the Free Software Foundation; either
120+ version 2.1 of the License, or (at your option) any later version.
121+
122+ The GNU C Library is distributed in the hope that it will be useful,
123+ but WITHOUT ANY WARRANTY; without even the implied warranty of
124+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
125+ Lesser General Public License for more details.
126+
127+ You should have received a copy of the GNU Lesser General Public
128+ License along with the GNU C Library; if not, see
129+ <https://www.gnu.org/licenses/>. */
130+
131+#include <nss.h>
132+#include <stdlib.h>
133+#include <string.h>
134+#include "nss/tst-nss-gai-hv2-canonname.h"
135+
136+/* Catch misnamed and functions. */
137+#pragma GCC diagnostic error "-Wmissing-prototypes"
138+NSS_DECLARE_MODULE_FUNCTIONS (test_gai_hv2_canonname)
139+
140+extern enum nss_status _nss_files_gethostbyname2_r (const char *, int,
141+ struct hostent *, char *,
142+ size_t, int *, int *);
143+
144+enum nss_status
145+_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af,
146+ struct hostent *result,
147+ char *buffer, size_t buflen,
148+ int *errnop, int *herrnop)
149+{
150+ return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop,
151+ herrnop);
152+}
153+
154+enum nss_status
155+_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer,
156+ size_t buflen, char **result,
157+ int *errnop, int *h_errnop)
158+{
159+ /* We expect QUERYNAME, which is a small enough string that it shouldn't fail
160+ the test. */
161+ if (memcmp (QUERYNAME, name, sizeof (QUERYNAME))
162+ || buflen < sizeof (QUERYNAME))
163+ abort ();
164+
165+ strncpy (buffer, name, buflen);
166+ *result = buffer;
167+ return NSS_STATUS_SUCCESS;
168+}
169diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c
170new file mode 100644
171index 0000000000..d5f10c07d6
172--- /dev/null
173+++ b/nss/tst-nss-gai-hv2-canonname.c
174@@ -0,0 +1,63 @@
175+/* Test NSS query path for plugins that only implement gethostbyname2
176+ (#30843).
177+ Copyright The GNU Toolchain Authors.
178+ This file is part of the GNU C Library.
179+
180+ The GNU C Library is free software; you can redistribute it and/or
181+ modify it under the terms of the GNU Lesser General Public
182+ License as published by the Free Software Foundation; either
183+ version 2.1 of the License, or (at your option) any later version.
184+
185+ The GNU C Library is distributed in the hope that it will be useful,
186+ but WITHOUT ANY WARRANTY; without even the implied warranty of
187+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
188+ Lesser General Public License for more details.
189+
190+ You should have received a copy of the GNU Lesser General Public
191+ License along with the GNU C Library; if not, see
192+ <https://www.gnu.org/licenses/>. */
193+
194+#include <nss.h>
195+#include <netdb.h>
196+#include <stdlib.h>
197+#include <string.h>
198+#include <support/check.h>
199+#include <support/xstdio.h>
200+#include "nss/tst-nss-gai-hv2-canonname.h"
201+
202+#define PREPARE do_prepare
203+
204+static void do_prepare (int a, char **av)
205+{
206+ FILE *hosts = xfopen ("/etc/hosts", "w");
207+ for (unsigned i = 2; i < 255; i++)
208+ {
209+ fprintf (hosts, "ff01::ff02:ff03:%u:2\ttest.example.com\n", i);
210+ fprintf (hosts, "192.168.0.%u\ttest.example.com\n", i);
211+ }
212+ xfclose (hosts);
213+}
214+
215+static int
216+do_test (void)
217+{
218+ __nss_configure_lookup ("hosts", "test_gai_hv2_canonname");
219+
220+ struct addrinfo hints = {};
221+ struct addrinfo *result = NULL;
222+
223+ hints.ai_family = AF_INET6;
224+ hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_CANONNAME;
225+
226+ int ret = getaddrinfo (QUERYNAME, NULL, &hints, &result);
227+
228+ if (ret != 0)
229+ FAIL_EXIT1 ("getaddrinfo failed: %s\n", gai_strerror (ret));
230+
231+ TEST_COMPARE_STRING (result->ai_canonname, QUERYNAME);
232+
233+ freeaddrinfo(result);
234+ return 0;
235+}
236+
237+#include <support/test-driver.c>
238diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h
239new file mode 100644
240index 0000000000..14f2a9cb08
241--- /dev/null
242+++ b/nss/tst-nss-gai-hv2-canonname.h
243@@ -0,0 +1 @@
244+#define QUERYNAME "test.example.com"
245diff --git a/nss/tst-nss-gai-hv2-canonname.root/postclean.req b/nss/tst-nss-gai-hv2-canonname.root/postclean.req
246new file mode 100644
247index 0000000000..e69de29bb2
248diff --git a/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
249new file mode 100644
250index 0000000000..31848b4a28
251--- /dev/null
252+++ b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
253@@ -0,0 +1,2 @@
254+cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2
255+su
256diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
257index 6ae6744fe4..47f421fddf 100644
258--- a/sysdeps/posix/getaddrinfo.c
259+++ b/sysdeps/posix/getaddrinfo.c
260@@ -120,6 +120,7 @@ struct gaih_result
261 {
262 struct gaih_addrtuple *at;
263 char *canon;
264+ char *h_name;
265 bool free_at;
266 bool got_ipv6;
267 };
268@@ -165,6 +166,7 @@ gaih_result_reset (struct gaih_result *res)
269 if (res->free_at)
270 free (res->at);
271 free (res->canon);
272+ free (res->h_name);
273 memset (res, 0, sizeof (*res));
274 }
275
276@@ -203,9 +205,8 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
277 return 0;
278 }
279
280-/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name
281- is not copied, and the struct hostent object must not be deallocated
282- prematurely. The new addresses are appended to the tuple array in RES. */
283+/* Convert struct hostent to a list of struct gaih_addrtuple objects. The new
284+ addresses are appended to the tuple array in RES. */
285 static bool
286 convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
287 struct hostent *h, struct gaih_result *res)
288@@ -238,6 +239,15 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
289 res->at = array;
290 res->free_at = true;
291
292+ /* Duplicate h_name because it may get reclaimed when the underlying storage
293+ is freed. */
294+ if (res->h_name == NULL)
295+ {
296+ res->h_name = __strdup (h->h_name);
297+ if (res->h_name == NULL)
298+ return false;
299+ }
300+
301 /* Update the next pointers on reallocation. */
302 for (size_t i = 0; i < old; i++)
303 array[i].next = array + i + 1;
304@@ -262,7 +272,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
305 }
306 array[i].next = array + i + 1;
307 }
308- array[0].name = h->h_name;
309 array[count - 1].next = NULL;
310
311 return true;
312@@ -324,15 +333,15 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name,
313 memory allocation failure. The returned string is allocated on the
314 heap; the caller has to free it. */
315 static char *
316-getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
317+getcanonname (nss_action_list nip, const char *hname, const char *name)
318 {
319 nss_getcanonname_r *cfct = __nss_lookup_function (nip, "getcanonname_r");
320 char *s = (char *) name;
321 if (cfct != NULL)
322 {
323 char buf[256];
324- if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf),
325- &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS)
326+ if (DL_CALL_FCT (cfct, (hname ?: name, buf, sizeof (buf), &s, &errno,
327+ &h_errno)) != NSS_STATUS_SUCCESS)
328 /* If the canonical name cannot be determined, use the passed
329 string. */
330 s = (char *) name;
331@@ -771,7 +780,7 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
332 if ((req->ai_flags & AI_CANONNAME) != 0
333 && res->canon == NULL)
334 {
335- char *canonbuf = getcanonname (nip, res->at, name);
336+ char *canonbuf = getcanonname (nip, res->h_name, name);
337 if (canonbuf == NULL)
338 {
339 __resolv_context_put (res_ctx);
340--
3412.39.3
342
diff --git a/meta/recipes-core/glibc/glibc_2.37.bb b/meta/recipes-core/glibc/glibc_2.37.bb
index caf454f368..bce566acd4 100644
--- a/meta/recipes-core/glibc/glibc_2.37.bb
+++ b/meta/recipes-core/glibc/glibc_2.37.bb
@@ -50,6 +50,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \
50 file://0021-fix-create-thread-failed-in-unprivileged-process-BZ-.patch \ 50 file://0021-fix-create-thread-failed-in-unprivileged-process-BZ-.patch \
51 file://0022-Avoid-hardcoded-build-time-paths-in-the-output-binar.patch \ 51 file://0022-Avoid-hardcoded-build-time-paths-in-the-output-binar.patch \
52 file://0023-CVE-2023-4527.patch \ 52 file://0023-CVE-2023-4527.patch \
53 file://0024-CVE-2023-4806.patch \
53" 54"
54S = "${WORKDIR}/git" 55S = "${WORKDIR}/git"
55B = "${WORKDIR}/build-${TARGET_SYS}" 56B = "${WORKDIR}/build-${TARGET_SYS}"