From e42a81cd79a5f19fa583e1715c45fba4605b90e0 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 4 Oct 2023 10:28:17 +0800 Subject: [PATCH] fix CVE-2023-4527, CVE-2023-4806, CVE-2023-5156, CVE-2023-4911 --- 0083-CVE-2023-4527.patch | 194 ++++++++++++++++++++++ 0084-CVE-2023-4806.patch | 338 +++++++++++++++++++++++++++++++++++++++ 0085-CVE-2023-5156.patch | 98 ++++++++++++ 0086-CVE-2023-4911.patch | 156 ++++++++++++++++++ glibc.spec | 9 +- 5 files changed, 794 insertions(+), 1 deletion(-) create mode 100644 0083-CVE-2023-4527.patch create mode 100644 0084-CVE-2023-4806.patch create mode 100644 0085-CVE-2023-5156.patch create mode 100644 0086-CVE-2023-4911.patch diff --git a/0083-CVE-2023-4527.patch b/0083-CVE-2023-4527.patch new file mode 100644 index 0000000..2f71bc4 --- /dev/null +++ b/0083-CVE-2023-4527.patch @@ -0,0 +1,194 @@ +From 4ea972b7edd7e36610e8cde18bf7a8149d7bac4f Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Wed, 13 Sep 2023 14:10:56 +0200 +Subject: [PATCH] CVE-2023-4527: Stack read overflow with large TCP responses + in no-aaaa mode + +Without passing alt_dns_packet_buffer, __res_context_search can only +store 2048 bytes (what fits into dns_packet_buffer). However, +the function returns the total packet size, and the subsequent +DNS parsing code in _nss_dns_gethostbyname4_r reads beyond the end +of the stack-allocated buffer. + +Fixes commit f282cdbe7f436c75864e5640a4 ("resolv: Implement no-aaaa +stub resolver option") and bug 30842. + +(cherry picked from commit bd77dd7e73e3530203be1c52c8a29d08270cb25d) +--- + resolv/Makefile | 2 + + resolv/nss_dns/dns-host.c | 2 +- + resolv/tst-resolv-noaaaa-vc.c | 129 ++++++++++++++++++++++++++++++++++ + 4 files changed, 139 insertions(+), 1 deletion(-) + create mode 100644 resolv/tst-resolv-noaaaa-vc.c + +diff --git a/resolv/Makefile b/resolv/Makefile +index f8a92c6cff..28cedf49ee 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -101,6 +101,7 @@ tests += \ + tst-resolv-invalid-cname \ + tst-resolv-network \ + tst-resolv-noaaaa \ ++ tst-resolv-noaaaa-vc \ + tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ +@@ -291,6 +292,7 @@ $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \ + $(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \ + $(shared-thread-library) + $(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 9fa81f23c8..227734da5c 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -427,7 +427,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + { + n = __res_context_search (ctx, name, C_IN, T_A, + dns_packet_buffer, sizeof (dns_packet_buffer), +- NULL, NULL, NULL, NULL, NULL); ++ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); + if (n >= 0) + status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n, + &abuf, pat, errnop, herrnop, ttlp); +diff --git a/resolv/tst-resolv-noaaaa-vc.c b/resolv/tst-resolv-noaaaa-vc.c +new file mode 100644 +index 0000000000..9f5aebd99f +--- /dev/null ++++ b/resolv/tst-resolv-noaaaa-vc.c +@@ -0,0 +1,129 @@ ++/* Test the RES_NOAAAA resolver option with a large response. ++ Copyright (C) 2022-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Used to keep track of the number of queries. */ ++static volatile unsigned int queries; ++ ++/* If true, add a large TXT record at the start of the answer section. */ ++static volatile bool stuff_txt; ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* If not using TCP, just force its use. */ ++ if (!ctx->tcp) ++ { ++ struct resolv_response_flags flags = {.tc = true}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ return; ++ } ++ ++ /* The test needs to send four queries, the first three are used to ++ grow the NSS buffer via the ERANGE handshake. */ ++ ++queries; ++ TEST_VERIFY (queries <= 4); ++ ++ /* AAAA queries are supposed to be disabled. */ ++ TEST_COMPARE (qtype, T_A); ++ TEST_COMPARE (qclass, C_IN); ++ TEST_COMPARE_STRING (qname, "example.com"); ++ ++ struct resolv_response_flags flags = {}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ ++ resolv_response_section (b, ns_s_an); ++ ++ if (stuff_txt) ++ { ++ resolv_response_open_record (b, qname, qclass, T_TXT, 60); ++ int zero = 0; ++ for (int i = 0; i <= 15000; ++i) ++ resolv_response_add_data (b, &zero, sizeof (zero)); ++ resolv_response_close_record (b); ++ } ++ ++ for (int i = 0; i < 200; ++i) ++ { ++ resolv_response_open_record (b, qname, qclass, qtype, 60); ++ char ipv4[4] = {192, 0, 2, i + 1}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ resolv_response_close_record (b); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ _res.options |= RES_NOAAAA; ++ ++ for (int do_stuff_txt = 0; do_stuff_txt < 2; ++do_stuff_txt) ++ { ++ queries = 0; ++ stuff_txt = do_stuff_txt; ++ ++ struct addrinfo *ai = NULL; ++ int ret; ++ ret = getaddrinfo ("example.com", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ ++ char *expected_result; ++ { ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ for (int i = 0; i < 200; ++i) ++ fprintf (mem.out, "address: STREAM/TCP 192.0.2.%d 80\n", i + 1); ++ xfclose_memstream (&mem); ++ expected_result = mem.buffer; ++ } ++ ++ check_addrinfo ("example.com", ai, ret, expected_result); ++ ++ free (expected_result); ++ freeaddrinfo (ai); ++ } ++ ++ resolv_test_end (obj); ++ return 0; ++} ++ ++#include +-- +2.39.3 + diff --git a/0084-CVE-2023-4806.patch b/0084-CVE-2023-4806.patch new file mode 100644 index 0000000..1e7f10b --- /dev/null +++ b/0084-CVE-2023-4806.patch @@ -0,0 +1,338 @@ +From a9728f798ec7f05454c95637ee6581afaa9b487d Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Fri, 15 Sep 2023 13:51:12 -0400 +Subject: [PATCH] getaddrinfo: Fix use after free in getcanonname + (CVE-2023-4806) + +When an NSS plugin only implements the _gethostbyname2_r and +_getcanonname_r callbacks, getaddrinfo could use memory that was freed +during tmpbuf resizing, through h_name in a previous query response. + +The backing store for res->at->name when doing a query with +gethostbyname3_r or gethostbyname2_r is tmpbuf, which is reallocated in +gethosts during the query. For AF_INET6 lookup with AI_ALL | +AI_V4MAPPED, gethosts gets called twice, once for a v6 lookup and second +for a v4 lookup. In this case, if the first call reallocates tmpbuf +enough number of times, resulting in a malloc, th->h_name (that +res->at->name refers to) ends up on a heap allocated storage in tmpbuf. +Now if the second call to gethosts also causes the plugin callback to +return NSS_STATUS_TRYAGAIN, tmpbuf will get freed, resulting in a UAF +reference in res->at->name. This then gets dereferenced in the +getcanonname_r plugin call, resulting in the use after free. + +Fix this by copying h_name over and freeing it at the end. This +resolves BZ #30843, which is assigned CVE-2023-4806. + +Signed-off-by: Siddhesh Poyarekar +(cherry picked from commit 973fe93a5675c42798b2161c6f29c01b0e243994) +--- + nss/Makefile | 15 ++++- + nss/nss_test_gai_hv2_canonname.c | 56 +++++++++++++++++ + nss/tst-nss-gai-hv2-canonname.c | 63 +++++++++++++++++++ + nss/tst-nss-gai-hv2-canonname.h | 1 + + .../postclean.req | 0 + .../tst-nss-gai-hv2-canonname.script | 2 + + sysdeps/posix/getaddrinfo.c | 25 +++++--- + 7 files changed, 152 insertions(+), 10 deletions(-) + create mode 100644 nss/nss_test_gai_hv2_canonname.c + create mode 100644 nss/tst-nss-gai-hv2-canonname.c + create mode 100644 nss/tst-nss-gai-hv2-canonname.h + create mode 100644 nss/tst-nss-gai-hv2-canonname.root/postclean.req + create mode 100644 nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script + +diff --git a/nss/Makefile b/nss/Makefile +index a978e3927a..f0af87e6f1 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -81,6 +81,7 @@ tests-container := \ + tst-nss-test3 \ + tst-reload1 \ + tst-reload2 \ ++ tst-nss-gai-hv2-canonname \ + # tests-container + + # Tests which need libdl +@@ -144,7 +145,8 @@ libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) + ifeq ($(build-static-nss),yes) + tests-static += tst-nss-static + endif +-extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os ++extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \ ++ nss_test_gai_hv2_canonname.os + + include ../Rules + +@@ -179,12 +181,16 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver + libof-nss_test1 = extramodules + libof-nss_test2 = extramodules + libof-nss_test_errno = extramodules ++libof-nss_test_gai_hv2_canonname = extramodules + $(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps) + $(build-module) + $(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps) + $(build-module) + $(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps) + $(build-module) ++$(objpfx)/libnss_test_gai_hv2_canonname.so: \ ++ $(objpfx)nss_test_gai_hv2_canonname.os $(link-libc-deps) ++ $(build-module) + $(objpfx)nss_test2.os : nss_test1.c + # Use the nss_files suffix for these objects as well. + $(objpfx)/libnss_test1.so$(libnss_files.so-version): $(objpfx)/libnss_test1.so +@@ -194,10 +200,14 @@ $(objpfx)/libnss_test2.so$(libnss_files.so-version): $(objpfx)/libnss_test2.so + $(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \ + $(objpfx)/libnss_test_errno.so + $(make-link) ++$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version): \ ++ $(objpfx)/libnss_test_gai_hv2_canonname.so ++ $(make-link) + $(patsubst %,$(objpfx)%.out,$(tests) $(tests-container)) : \ + $(objpfx)/libnss_test1.so$(libnss_files.so-version) \ + $(objpfx)/libnss_test2.so$(libnss_files.so-version) \ +- $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) ++ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) \ ++ $(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version) + + ifeq (yes,$(have-thread-library)) + $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library) +@@ -214,3 +224,4 @@ LDFLAGS-tst-nss-test3 = -Wl,--disable-new-dtags + LDFLAGS-tst-nss-test4 = -Wl,--disable-new-dtags + LDFLAGS-tst-nss-test5 = -Wl,--disable-new-dtags + LDFLAGS-tst-nss-test_errno = -Wl,--disable-new-dtags ++LDFLAGS-tst-nss-test_gai_hv2_canonname = -Wl,--disable-new-dtags +diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c +new file mode 100644 +index 0000000000..4439c83c9f +--- /dev/null ++++ b/nss/nss_test_gai_hv2_canonname.c +@@ -0,0 +1,56 @@ ++/* NSS service provider that only provides gethostbyname2_r. ++ Copyright The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include "nss/tst-nss-gai-hv2-canonname.h" ++ ++/* Catch misnamed and functions. */ ++#pragma GCC diagnostic error "-Wmissing-prototypes" ++NSS_DECLARE_MODULE_FUNCTIONS (test_gai_hv2_canonname) ++ ++extern enum nss_status _nss_files_gethostbyname2_r (const char *, int, ++ struct hostent *, char *, ++ size_t, int *, int *); ++ ++enum nss_status ++_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af, ++ struct hostent *result, ++ char *buffer, size_t buflen, ++ int *errnop, int *herrnop) ++{ ++ return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop, ++ herrnop); ++} ++ ++enum nss_status ++_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer, ++ size_t buflen, char **result, ++ int *errnop, int *h_errnop) ++{ ++ /* We expect QUERYNAME, which is a small enough string that it shouldn't fail ++ the test. */ ++ if (memcmp (QUERYNAME, name, sizeof (QUERYNAME)) ++ || buflen < sizeof (QUERYNAME)) ++ abort (); ++ ++ strncpy (buffer, name, buflen); ++ *result = buffer; ++ return NSS_STATUS_SUCCESS; ++} +diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c +new file mode 100644 +index 0000000000..d5f10c07d6 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.c +@@ -0,0 +1,63 @@ ++/* Test NSS query path for plugins that only implement gethostbyname2 ++ (#30843). ++ Copyright The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "nss/tst-nss-gai-hv2-canonname.h" ++ ++#define PREPARE do_prepare ++ ++static void do_prepare (int a, char **av) ++{ ++ FILE *hosts = xfopen ("/etc/hosts", "w"); ++ for (unsigned i = 2; i < 255; i++) ++ { ++ fprintf (hosts, "ff01::ff02:ff03:%u:2\ttest.example.com\n", i); ++ fprintf (hosts, "192.168.0.%u\ttest.example.com\n", i); ++ } ++ xfclose (hosts); ++} ++ ++static int ++do_test (void) ++{ ++ __nss_configure_lookup ("hosts", "test_gai_hv2_canonname"); ++ ++ struct addrinfo hints = {}; ++ struct addrinfo *result = NULL; ++ ++ hints.ai_family = AF_INET6; ++ hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_CANONNAME; ++ ++ int ret = getaddrinfo (QUERYNAME, NULL, &hints, &result); ++ ++ if (ret != 0) ++ FAIL_EXIT1 ("getaddrinfo failed: %s\n", gai_strerror (ret)); ++ ++ TEST_COMPARE_STRING (result->ai_canonname, QUERYNAME); ++ ++ freeaddrinfo(result); ++ return 0; ++} ++ ++#include +diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h +new file mode 100644 +index 0000000000..14f2a9cb08 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.h +@@ -0,0 +1 @@ ++#define QUERYNAME "test.example.com" +diff --git a/nss/tst-nss-gai-hv2-canonname.root/postclean.req b/nss/tst-nss-gai-hv2-canonname.root/postclean.req +new file mode 100644 +index 0000000000..e69de29bb2 +diff --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 +new file mode 100644 +index 0000000000..31848b4a28 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script +@@ -0,0 +1,2 @@ ++cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2 ++su +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 5cda9bb072..7a43a3bf4c 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -120,6 +120,7 @@ struct gaih_result + { + struct gaih_addrtuple *at; + char *canon; ++ char *h_name; + bool free_at; + bool got_ipv6; + }; +@@ -165,6 +166,7 @@ gaih_result_reset (struct gaih_result *res) + if (res->free_at) + free (res->at); + free (res->canon); ++ free (res->h_name); + memset (res, 0, sizeof (*res)); + } + +@@ -203,9 +205,8 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, + return 0; + } + +-/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name +- is not copied, and the struct hostent object must not be deallocated +- prematurely. The new addresses are appended to the tuple array in RES. */ ++/* Convert struct hostent to a list of struct gaih_addrtuple objects. The new ++ addresses are appended to the tuple array in RES. */ + static bool + convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + struct hostent *h, struct gaih_result *res) +@@ -238,6 +239,15 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + res->at = array; + res->free_at = true; + ++ /* Duplicate h_name because it may get reclaimed when the underlying storage ++ is freed. */ ++ if (res->h_name == NULL) ++ { ++ res->h_name = __strdup (h->h_name); ++ if (res->h_name == NULL) ++ return false; ++ } ++ + /* Update the next pointers on reallocation. */ + for (size_t i = 0; i < old; i++) + array[i].next = array + i + 1; +@@ -262,7 +272,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + } + array[i].next = array + i + 1; + } +- array[0].name = h->h_name; + array[count - 1].next = NULL; + + return true; +@@ -324,15 +333,15 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name, + memory allocation failure. The returned string is allocated on the + heap; the caller has to free it. */ + static char * +-getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name) ++getcanonname (nss_action_list nip, const char *hname, const char *name) + { + nss_getcanonname_r *cfct = __nss_lookup_function (nip, "getcanonname_r"); + char *s = (char *) name; + if (cfct != NULL) + { + char buf[256]; +- if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf), +- &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS) ++ if (DL_CALL_FCT (cfct, (hname ?: name, buf, sizeof (buf), &s, &errno, ++ &h_errno)) != NSS_STATUS_SUCCESS) + /* If the canonical name cannot be determined, use the passed + string. */ + s = (char *) name; +@@ -771,7 +780,7 @@ get_nss_addresses (const char *name, const struct addrinfo *req, + if ((req->ai_flags & AI_CANONNAME) != 0 + && res->canon == NULL) + { +- char *canonbuf = getcanonname (nip, res->at, name); ++ char *canonbuf = getcanonname (nip, res->h_name, name); + if (canonbuf == NULL) + { + __resolv_context_put (res_ctx); +-- +2.39.3 + diff --git a/0085-CVE-2023-5156.patch b/0085-CVE-2023-5156.patch new file mode 100644 index 0000000..59a3c83 --- /dev/null +++ b/0085-CVE-2023-5156.patch @@ -0,0 +1,98 @@ +From 856bac55f98dc840e7c27cfa82262b933385de90 Mon Sep 17 00:00:00 2001 +From: Romain Geissler +Date: Mon, 25 Sep 2023 01:21:51 +0100 +Subject: [PATCH] Fix leak in getaddrinfo introduced by the fix for + CVE-2023-4806 [BZ #30843] + +This patch fixes a very recently added leak in getaddrinfo. + +This was assigned CVE-2023-5156. + +Resolves: BZ #30884 +Related: BZ #30842 + +Reviewed-by: Siddhesh Poyarekar +(cherry picked from commit ec6b95c3303c700eb89eebeda2d7264cc184a796) +--- + nss/Makefile | 20 ++++++++++++++++++++ + nss/tst-nss-gai-hv2-canonname.c | 3 +++ + sysdeps/posix/getaddrinfo.c | 4 +--- + 3 files changed, 24 insertions(+), 3 deletions(-) + +diff --git a/nss/Makefile b/nss/Makefile +index f0af87e6f1..7a52c68791 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -148,6 +148,15 @@ endif + extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \ + nss_test_gai_hv2_canonname.os + ++ifeq ($(run-built-tests),yes) ++ifneq (no,$(PERL)) ++tests-special += $(objpfx)mtrace-tst-nss-gai-hv2-canonname.out ++endif ++endif ++ ++generated += mtrace-tst-nss-gai-hv2-canonname.out \ ++ tst-nss-gai-hv2-canonname.mtrace ++ + include ../Rules + + ifeq (yes,$(have-selinux)) +@@ -216,6 +225,17 @@ endif + $(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so + $(objpfx)tst-nss-files-alias-truncated.out: $(objpfx)/libnss_files.so + ++tst-nss-gai-hv2-canonname-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-nss-gai-hv2-canonname.mtrace \ ++ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so ++$(objpfx)mtrace-tst-nss-gai-hv2-canonname.out: \ ++ $(objpfx)tst-nss-gai-hv2-canonname.out ++ { test -r $(objpfx)tst-nss-gai-hv2-canonname.mtrace \ ++ || ( echo "tst-nss-gai-hv2-canonname.mtrace does not exist"; exit 77; ) \ ++ && $(common-objpfx)malloc/mtrace \ ++ $(objpfx)tst-nss-gai-hv2-canonname.mtrace; } > $@; \ ++ $(evaluate-test) ++ + # Disable DT_RUNPATH on NSS tests so that the glibc internal NSS + # functions can load testing NSS modules via DT_RPATH. + LDFLAGS-tst-nss-test1 = -Wl,--disable-new-dtags +diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c +index d5f10c07d6..7db53cf09d 100644 +--- a/nss/tst-nss-gai-hv2-canonname.c ++++ b/nss/tst-nss-gai-hv2-canonname.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include "nss/tst-nss-gai-hv2-canonname.h" +@@ -41,6 +42,8 @@ static void do_prepare (int a, char **av) + static int + do_test (void) + { ++ mtrace (); ++ + __nss_configure_lookup ("hosts", "test_gai_hv2_canonname"); + + struct addrinfo hints = {}; +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 7a43a3bf4c..f975dcd2bc 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -1196,9 +1196,7 @@ free_and_return: + if (malloc_name) + free ((char *) name); + free (addrmem); +- if (res.free_at) +- free (res.at); +- free (res.canon); ++ gaih_result_reset (&res); + + return result; + } +-- +2.39.3 + diff --git a/0086-CVE-2023-4911.patch b/0086-CVE-2023-4911.patch new file mode 100644 index 0000000..a58a4ab --- /dev/null +++ b/0086-CVE-2023-4911.patch @@ -0,0 +1,156 @@ +From 22955ad85186ee05834e47e665056148ca07699c Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Tue, 19 Sep 2023 18:39:32 -0400 +Subject: [PATCH] tunables: Terminate if end of input is reached + (CVE-2023-4911) + +The string parsing routine may end up writing beyond bounds of tunestr +if the input tunable string is malformed, of the form name=name=val. +This gets processed twice, first as name=name=val and next as name=val, +resulting in tunestr being name=name=val:name=val, thus overflowing +tunestr. + +Terminate the parsing loop at the first instance itself so that tunestr +does not overflow. + +This also fixes up tst-env-setuid-tunables to actually handle failures +correct and add new tests to validate the fix for this CVE. + +Signed-off-by: Siddhesh Poyarekar +Reviewed-by: Carlos O'Donell +(cherry picked from commit 1056e5b4c3f2d90ed2b4a55f96add28da2f4c8fa) +--- + elf/dl-tunables.c | 17 +++++++++------- + elf/tst-env-setuid-tunables.c | 37 +++++++++++++++++++++++++++-------- + 2 files changed, 44 insertions(+), 15 deletions(-) + +diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c +index 8e7ee9df10..76cf8b9da3 100644 +--- a/elf/dl-tunables.c ++++ b/elf/dl-tunables.c +@@ -187,11 +187,7 @@ parse_tunables (char *tunestr, char *valstring) + /* If we reach the end of the string before getting a valid name-value + pair, bail out. */ + if (p[len] == '\0') +- { +- if (__libc_enable_secure) +- tunestr[off] = '\0'; +- return; +- } ++ break; + + /* We did not find a valid name-value pair before encountering the + colon. */ +@@ -251,9 +247,16 @@ parse_tunables (char *tunestr, char *valstring) + } + } + +- if (p[len] != '\0') +- p += len + 1; ++ /* We reached the end while processing the tunable string. */ ++ if (p[len] == '\0') ++ break; ++ ++ p += len + 1; + } ++ ++ /* Terminate tunestr before we leave. */ ++ if (__libc_enable_secure) ++ tunestr[off] = '\0'; + } + #endif + +diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c +index 88182b7b25..5e9e4c5756 100644 +--- a/elf/tst-env-setuid-tunables.c ++++ b/elf/tst-env-setuid-tunables.c +@@ -52,6 +52,8 @@ const char *teststrings[] = + "glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", + "glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096", + "not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.check=2", + "glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2", + "glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096", + ":glibc.malloc.garbage=2:glibc.malloc.check=1", +@@ -70,6 +72,8 @@ const char *resultstrings[] = + "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", ++ "", + "", + "", + "", +@@ -84,11 +88,18 @@ test_child (int off) + const char *val = getenv ("GLIBC_TUNABLES"); + + #if HAVE_TUNABLES ++ printf (" [%d] GLIBC_TUNABLES is %s\n", off, val); ++ fflush (stdout); + if (val != NULL && strcmp (val, resultstrings[off]) == 0) + return 0; + + if (val != NULL) +- printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val); ++ printf (" [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n", ++ off, val, resultstrings[off]); ++ else ++ printf (" [%d] GLIBC_TUNABLES environment variable absent\n", off); ++ ++ fflush (stdout); + + return 1; + #else +@@ -117,21 +128,26 @@ do_test (int argc, char **argv) + if (ret != 0) + exit (1); + +- exit (EXIT_SUCCESS); ++ /* Special return code to make sure that the child executed all the way ++ through. */ ++ exit (42); + } + else + { +- int ret = 0; +- + /* Spawn tests. */ + for (int i = 0; i < array_length (teststrings); i++) + { + char buf[INT_BUFSIZE_BOUND (int)]; + +- printf ("Spawned test for %s (%d)\n", teststrings[i], i); ++ printf ("[%d] Spawned test for %s\n", i, teststrings[i]); + snprintf (buf, sizeof (buf), "%d\n", i); ++ fflush (stdout); + if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0) +- exit (1); ++ { ++ printf (" [%d] Failed to set GLIBC_TUNABLES: %m", i); ++ support_record_failure (); ++ continue; ++ } + + int status = support_capture_subprogram_self_sgid (buf); + +@@ -139,9 +155,14 @@ do_test (int argc, char **argv) + if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) + return EXIT_UNSUPPORTED; + +- ret |= status; ++ if (WEXITSTATUS (status) != 42) ++ { ++ printf (" [%d] child failed with status %d\n", i, ++ WEXITSTATUS (status)); ++ support_record_failure (); ++ } + } +- return ret; ++ return 0; + } + } + +-- +2.39.3 + diff --git a/glibc.spec b/glibc.spec index 748da44..8c045b8 100644 --- a/glibc.spec +++ b/glibc.spec @@ -1,4 +1,4 @@ -%define anolis_release 9 +%define anolis_release 10 %bcond_without testsuite %bcond_without benchtests @@ -178,6 +178,10 @@ Patch0179: 0079-locale-prevent-maybe-uninitialized-errors-with-Os-BZ.patch Patch0180: 0080-sunrpc-Suppress-GCC-Os-warning-on-user2netname.patch Patch0181: 0081-x86-Fix-Os-build-BZ-29576.patch Patch0182: 0082-LoongArch-add-new-relocs-and-fix-from-upstream.patch +Patch0183: 0083-CVE-2023-4527.patch +Patch0184: 0084-CVE-2023-4806.patch +Patch0185: 0085-CVE-2023-5156.patch +Patch0186: 0086-CVE-2023-4911.patch BuildRequires: audit-libs-devel >= 1.1.3 libcap-devel systemtap-sdt-devel BuildRequires: procps-ng util-linux gawk sed >= 3.95 gettext @@ -1112,6 +1116,9 @@ update_gconv_modules_cache () %{_libdir}/libpthread_nonshared.a %changelog +* Wed Oct 04 2023 Funda Wang - 2.36-10 +- fix CVE-2023-4527, CVE-2023-4806, CVE-2023-5156, CVE-2023-4911 + * Tue Aug 15 2023 Funda Wang - 2.36-9 - Add patch for gb18030-2022 from upstream bug#30243 - Correctly move langpack-cmn into langpack-zh