glibc: update to 2.39.

Add --enable-option-checking to configure flags and remove unused --with-march
flags. Those flags come from gcc and not glibc.

Also, correct rootsbindir in configparams and remove libc_cv_rootsbindir since
it gets overridden by .m4 scripts in configure and rootsbindir in configparams.
This commit is contained in:
oreo639 2024-03-06 17:59:11 -08:00
parent edddc0dd57
commit 3269bbc3a8
13 changed files with 423 additions and 1641 deletions

View File

@ -17,40 +17,40 @@
# one (order top->bottom) is preferred over the next ones.
#
libc.so musl-1.1.24_7
libc.so.6 glibc-2.38_1
libm.so.6 glibc-2.38_1
libpthread.so.0 glibc-2.38_1
librt.so.1 glibc-2.38_1
libdl.so.2 glibc-2.38_1
ld-linux-x86-64.so.2 glibc-2.38_1 x86_64
ld-linux.so.2 glibc-2.38_1 i686
ld-linux.so.3 glibc-2.38_1 armv5tel
ld-linux-aarch64.so.1 glibc-2.38_1 aarch64
ld-linux-riscv64-lp64d.so.1 glibc-2.38_1 riscv64
ld64.so.2 glibc-2.38_1 ppc64
ld.so.1 glibc-2.38_1 mips
ld.so.1 glibc-2.38_1 ppc
ld-linux-armhf.so.3 glibc-2.38_1
libresolv.so.2 glibc-2.38_1
libanl.so.1 glibc-2.38_1
libthread_db.so.1 glibc-2.38_1
libutil.so.1 glibc-2.38_1
libnsl.so.1 glibc-2.38_1
libnss_db.so.2 glibc-2.38_1
libnss_files.so.2 glibc-2.38_1
libnss_compat.so.2 glibc-2.38_1
libnss_dns.so.2 glibc-2.38_1
libnss_hesiod.so.2 glibc-2.38_1
libBrokenLocale.so.1 glibc-2.38_1
libc.so.6 glibc-2.39_1
libm.so.6 glibc-2.39_1
libpthread.so.0 glibc-2.39_1
librt.so.1 glibc-2.39_1
libdl.so.2 glibc-2.39_1
ld-linux-x86-64.so.2 glibc-2.39_1 x86_64
ld-linux.so.2 glibc-2.39_1 i686
ld-linux.so.3 glibc-2.39_1 armv5tel
ld-linux-aarch64.so.1 glibc-2.39_1 aarch64
ld-linux-riscv64-lp64d.so.1 glibc-2.39_1 riscv64
ld64.so.2 glibc-2.39_1 ppc64
ld.so.1 glibc-2.39_1 mips
ld.so.1 glibc-2.39_1 ppc
ld-linux-armhf.so.3 glibc-2.39_1
libresolv.so.2 glibc-2.39_1
libanl.so.1 glibc-2.39_1
libthread_db.so.1 glibc-2.39_1
libutil.so.1 glibc-2.39_1
libnsl.so.1 glibc-2.39_1
libnss_db.so.2 glibc-2.39_1
libnss_files.so.2 glibc-2.39_1
libnss_compat.so.2 glibc-2.39_1
libnss_dns.so.2 glibc-2.39_1
libnss_hesiod.so.2 glibc-2.39_1
libBrokenLocale.so.1 glibc-2.39_1
libmemusage.so glibc-2.39_1
libSegFault.so glibc-2.39_1
libpcprofile.so glibc-2.39_1
libcidn.so.1 glibc-2.39_1
libmvec.so.1 glibc-2.39_1
libcrypt.so.2 libxcrypt-4.4.36_1
libcrypt.so.1 libxcrypt-compat-4.4.36_1
libSimGearCore.so.2020.3.17 simgear-2020.3.17_1
libSimGearScene.so.2020.3.17 simgear-2020.3.17_1
libmemusage.so glibc-2.38_1
libSegFault.so glibc-2.38_1
libpcprofile.so glibc-2.38_1
libcidn.so.1 glibc-2.38_1
libmvec.so.1 glibc-2.38_1
libcddgmp.so.0 cddlib-0.94m_1
libcdd.so.0 cddlib-0.94m_1
libcowsql.so.0 cowsql-1.15.4_1

View File

@ -1,335 +0,0 @@
From 00ae4f10b504bc4564e9f22f00907093f1ab9338 Mon Sep 17 00:00:00 2001
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
(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 06fcdc450f1..8a5126ecf34 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -82,6 +82,7 @@ tests-container := \
tst-nss-test3 \
tst-reload1 \
tst-reload2 \
+ tst-nss-gai-hv2-canonname \
# tests-container
# Tests which need libdl
@@ -145,7 +146,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
@@ -180,12 +182,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
@@ -195,10 +201,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)
@@ -215,3 +225,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 00000000000..4439c83c9f4
--- /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
+ <https://www.gnu.org/licenses/>. */
+
+#include <nss.h>
+#include <stdlib.h>
+#include <string.h>
+#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 00000000000..d5f10c07d6a
--- /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
+ <https://www.gnu.org/licenses/>. */
+
+#include <nss.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#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 <support/test-driver.c>
diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h
new file mode 100644
index 00000000000..14f2a9cb086
--- /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 00000000000..e69de29bb2d
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 00000000000..31848b4a285
--- /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 0356b622be6..b2236b105c1 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);

View File

@ -0,0 +1,262 @@
From 1b9c1a0047fb26a65a9b2a7b8cd977243f7d353c Mon Sep 17 00:00:00 2001
From: Jakub Jelinek <jakub@redhat.com>
Date: Wed, 31 Jan 2024 19:17:27 +0100
Subject: [PATCH] Use gcc __builtin_stdc_* builtins in stdbit.h if possible
The following patch uses the GCC 14 __builtin_stdc_* builtins in stdbit.h
for the type-generic macros, so that when compiled with GCC 14 or later,
it supports not just 8/16/32/64-bit unsigned integers, but also 128-bit
(if target supports them) and unsigned _BitInt (any supported precision).
And so that the macros don't expand arguments multiple times and can be
evaluated in constant expressions.
The new testcase is gcc's gcc/testsuite/gcc.dg/builtin-stdc-bit-1.c
adjusted to test stdbit.h and the type-generic macros in there instead
of the builtins and adjusted to use glibc test framework rather than
gcc style tests with __builtin_abort ().
Signed-off-by: Jakub Jelinek <jakub@redhat.com>
Reviewed-by: Joseph Myers <josmyers@redhat.com>
(cherry picked from commit da89496337b97e6a2aaf1e81d55cf998f6db1070)
---
manual/stdbit.texi | 8 +-
stdlib/Makefile | 1 +
stdlib/stdbit.h | 84 +++-
stdlib/tst-stdbit-builtins.c | 778 +++++++++++++++++++++++++++++++++++
4 files changed, 856 insertions(+), 15 deletions(-)
create mode 100644 stdlib/tst-stdbit-builtins.c
diff --git a/manual/stdbit.texi b/manual/stdbit.texi
index fe41c671d8..6c75ed9a20 100644
--- a/manual/stdbit.texi
+++ b/manual/stdbit.texi
@@ -32,7 +32,13 @@ and @code{unsigned long long int}. In addition, there is a
corresponding type-generic macro (not listed below), named the same as
the functions but without any suffix such as @samp{_uc}. The
type-generic macro can only be used with an argument of an unsigned
-integer type with a width of 8, 16, 32 or 64 bits.
+integer type with a width of 8, 16, 32 or 64 bits, or when using
+a compiler with support for
+@uref{https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html,@code{__builtin_stdc_bit_ceil}},
+etc.@:, built-in functions such as GCC 14.1 or later
+any unsigned integer type those built-in functions support.
+In GCC 14.1 that includes support for @code{unsigned __int128} and
+@code{unsigned _BitInt(@var{n})} if supported by the target.
@deftypefun {unsigned int} stdc_leading_zeros_uc (unsigned char @var{x})
@deftypefunx {unsigned int} stdc_leading_zeros_us (unsigned short @var{x})
diff --git a/stdlib/stdbit.h b/stdlib/stdbit.h
index f334eb174d..2801590c63 100644
--- a/stdlib/stdbit.h
+++ b/stdlib/stdbit.h
@@ -64,9 +64,13 @@ extern unsigned int stdc_leading_zeros_ul (unsigned long int __x)
__extension__
extern unsigned int stdc_leading_zeros_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_leading_zeros(x) \
+#if __glibc_has_builtin (__builtin_stdc_leading_zeros)
+# define stdc_leading_zeros(x) (__builtin_stdc_leading_zeros (x))
+#else
+# define stdc_leading_zeros(x) \
(stdc_leading_zeros_ull (x) \
- (unsigned int) (8 * (sizeof (0ULL) - sizeof (x))))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_clzll)
static __always_inline unsigned int
@@ -116,9 +120,13 @@ extern unsigned int stdc_leading_ones_ul (unsigned long int __x)
__extension__
extern unsigned int stdc_leading_ones_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_leading_ones(x) \
+#if __glibc_has_builtin (__builtin_stdc_leading_ones)
+# define stdc_leading_ones(x) (__builtin_stdc_leading_ones (x))
+#else
+# define stdc_leading_ones(x) \
(stdc_leading_ones_ull ((unsigned long long int) (x) \
<< 8 * (sizeof (0ULL) - sizeof (x))))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_clzll)
static __always_inline unsigned int
@@ -168,11 +176,15 @@ extern unsigned int stdc_trailing_zeros_ul (unsigned long int __x)
__extension__
extern unsigned int stdc_trailing_zeros_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_trailing_zeros(x) \
+#if __glibc_has_builtin (__builtin_stdc_trailing_zeros)
+# define stdc_trailing_zeros(x) (__builtin_stdc_trailing_zeros (x))
+#else
+# define stdc_trailing_zeros(x) \
(sizeof (x) == 8 ? stdc_trailing_zeros_ull (x) \
: sizeof (x) == 4 ? stdc_trailing_zeros_ui (x) \
: sizeof (x) == 2 ? stdc_trailing_zeros_us (__pacify_uint16 (x)) \
: stdc_trailing_zeros_uc (__pacify_uint8 (x)))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_ctzll)
static __always_inline unsigned int
@@ -222,7 +234,11 @@ extern unsigned int stdc_trailing_ones_ul (unsigned long int __x)
__extension__
extern unsigned int stdc_trailing_ones_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_trailing_ones(x) (stdc_trailing_ones_ull (x))
+#if __glibc_has_builtin (__builtin_stdc_trailing_ones)
+# define stdc_trailing_ones(x) (__builtin_stdc_trailing_ones (x))
+#else
+# define stdc_trailing_ones(x) (stdc_trailing_ones_ull (x))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_ctzll)
static __always_inline unsigned int
@@ -272,11 +288,15 @@ extern unsigned int stdc_first_leading_zero_ul (unsigned long int __x)
__extension__
extern unsigned int stdc_first_leading_zero_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_first_leading_zero(x) \
+#if __glibc_has_builtin (__builtin_stdc_first_leading_zero)
+# define stdc_first_leading_zero(x) (__builtin_stdc_first_leading_zero (x))
+#else
+# define stdc_first_leading_zero(x) \
(sizeof (x) == 8 ? stdc_first_leading_zero_ull (x) \
: sizeof (x) == 4 ? stdc_first_leading_zero_ui (x) \
: sizeof (x) == 2 ? stdc_first_leading_zero_us (__pacify_uint16 (x)) \
: stdc_first_leading_zero_uc (__pacify_uint8 (x)))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_clzll)
static __always_inline unsigned int
@@ -326,11 +346,15 @@ extern unsigned int stdc_first_leading_one_ul (unsigned long int __x)
__extension__
extern unsigned int stdc_first_leading_one_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_first_leading_one(x) \
+#if __glibc_has_builtin (__builtin_stdc_first_leading_one)
+# define stdc_first_leading_one(x) (__builtin_stdc_first_leading_one (x))
+#else
+# define stdc_first_leading_one(x) \
(sizeof (x) == 8 ? stdc_first_leading_one_ull (x) \
: sizeof (x) == 4 ? stdc_first_leading_one_ui (x) \
: sizeof (x) == 2 ? stdc_first_leading_one_us (__pacify_uint16 (x)) \
: stdc_first_leading_one_uc (__pacify_uint8 (x)))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_clzll)
static __always_inline unsigned int
@@ -380,11 +404,15 @@ extern unsigned int stdc_first_trailing_zero_ul (unsigned long int __x)
__extension__
extern unsigned int stdc_first_trailing_zero_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_first_trailing_zero(x) \
+#if __glibc_has_builtin (__builtin_stdc_first_trailing_zero)
+# define stdc_first_trailing_zero(x) (__builtin_stdc_first_trailing_zero (x))
+#else
+# define stdc_first_trailing_zero(x) \
(sizeof (x) == 8 ? stdc_first_trailing_zero_ull (x) \
: sizeof (x) == 4 ? stdc_first_trailing_zero_ui (x) \
: sizeof (x) == 2 ? stdc_first_trailing_zero_us (__pacify_uint16 (x)) \
: stdc_first_trailing_zero_uc (__pacify_uint8 (x)))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_ctzll)
static __always_inline unsigned int
@@ -434,11 +462,15 @@ extern unsigned int stdc_first_trailing_one_ul (unsigned long int __x)
__extension__
extern unsigned int stdc_first_trailing_one_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_first_trailing_one(x) \
+#if __glibc_has_builtin (__builtin_stdc_first_trailing_one)
+# define stdc_first_trailing_one(x) (__builtin_stdc_first_trailing_one (x))
+#else
+# define stdc_first_trailing_one(x) \
(sizeof (x) == 8 ? stdc_first_trailing_one_ull (x) \
: sizeof (x) == 4 ? stdc_first_trailing_one_ui (x) \
: sizeof (x) == 2 ? stdc_first_trailing_one_us (__pacify_uint16 (x)) \
: stdc_first_trailing_one_uc (__pacify_uint8 (x)))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_ctzll)
static __always_inline unsigned int
@@ -488,9 +520,13 @@ extern unsigned int stdc_count_zeros_ul (unsigned long int __x)
__extension__
extern unsigned int stdc_count_zeros_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_count_zeros(x) \
+#if __glibc_has_builtin (__builtin_stdc_count_zeros)
+# define stdc_count_zeros(x) (__builtin_stdc_count_zeros (x))
+#else
+# define stdc_count_zeros(x) \
(stdc_count_zeros_ull (x) \
- (unsigned int) (8 * (sizeof (0ULL) - sizeof (x))))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_popcountll)
static __always_inline unsigned int
@@ -540,7 +576,11 @@ extern unsigned int stdc_count_ones_ul (unsigned long int __x)
__extension__
extern unsigned int stdc_count_ones_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_count_ones(x) (stdc_count_ones_ull (x))
+#if __glibc_has_builtin (__builtin_stdc_count_ones)
+# define stdc_count_ones(x) (__builtin_stdc_count_ones (x))
+#else
+# define stdc_count_ones(x) (stdc_count_ones_ull (x))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_popcountll)
static __always_inline unsigned int
@@ -590,10 +630,14 @@ extern bool stdc_has_single_bit_ul (unsigned long int __x)
__extension__
extern bool stdc_has_single_bit_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_has_single_bit(x) \
+#if __glibc_has_builtin (__builtin_stdc_has_single_bit)
+# define stdc_has_single_bit(x) (__builtin_stdc_has_single_bit (x))
+#else
+# define stdc_has_single_bit(x) \
((bool) (sizeof (x) <= sizeof (unsigned int) \
? stdc_has_single_bit_ui (x) \
: stdc_has_single_bit_ull (x)))
+#endif
static __always_inline bool
__hsb64_inline (uint64_t __x)
@@ -641,7 +685,11 @@ extern unsigned int stdc_bit_width_ul (unsigned long int __x)
__extension__
extern unsigned int stdc_bit_width_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_bit_width(x) (stdc_bit_width_ull (x))
+#if __glibc_has_builtin (__builtin_stdc_bit_width)
+# define stdc_bit_width(x) (__builtin_stdc_bit_width (x))
+#else
+# define stdc_bit_width(x) (stdc_bit_width_ull (x))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_clzll)
static __always_inline unsigned int
@@ -691,7 +739,11 @@ extern unsigned long int stdc_bit_floor_ul (unsigned long int __x)
__extension__
extern unsigned long long int stdc_bit_floor_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_bit_floor(x) ((__typeof (x)) stdc_bit_floor_ull (x))
+#if __glibc_has_builtin (__builtin_stdc_bit_floor)
+# define stdc_bit_floor(x) (__builtin_stdc_bit_floor (x))
+#else
+# define stdc_bit_floor(x) ((__typeof (x)) stdc_bit_floor_ull (x))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_clzll)
static __always_inline uint64_t
@@ -743,7 +795,11 @@ extern unsigned long int stdc_bit_ceil_ul (unsigned long int __x)
__extension__
extern unsigned long long int stdc_bit_ceil_ull (unsigned long long int __x)
__THROW __attribute_const__;
-#define stdc_bit_ceil(x) ((__typeof (x)) stdc_bit_ceil_ull (x))
+#if __glibc_has_builtin (__builtin_stdc_bit_ceil)
+# define stdc_bit_ceil(x) (__builtin_stdc_bit_ceil (x))
+#else
+# define stdc_bit_ceil(x) ((__typeof (x)) stdc_bit_ceil_ull (x))
+#endif
#if __GNUC_PREREQ (3, 4) || __glibc_has_builtin (__builtin_clzll)
static __always_inline uint64_t

View File

@ -1,296 +0,0 @@
From 542b1105852568c3ebc712225ae78b8c8ba31a78 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Fri, 11 Aug 2023 11:18:17 +0200
Subject: [PATCH] malloc: Enable merging of remainders in memalign (bug 30723)
Previously, calling _int_free from _int_memalign could put remainders
into the tcache or into fastbins, where they are invisible to the
low-level allocator. This results in missed merge opportunities
because once these freed chunks become available to the low-level
allocator, further memalign allocations (even of the same size are)
likely obstructing merges.
Furthermore, during forwards merging in _int_memalign, do not
completely give up when the remainder is too small to serve as a
chunk on its own. We can still give it back if it can be merged
with the following unused chunk. This makes it more likely that
memalign calls in a loop achieve a compact memory layout,
independently of initial heap layout.
Drop some useless (unsigned long) casts along the way, and tweak
the style to more closely match GNU on changed lines.
Reviewed-by: DJ Delorie <dj@redhat.com>
---
malloc/malloc.c | 197 +++++++++++++++++++++++++++++-------------------
1 file changed, 121 insertions(+), 76 deletions(-)
diff --git a/malloc/malloc.c b/malloc/malloc.c
index e2f1a615a4..948f9759af 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1086,6 +1086,11 @@ typedef struct malloc_chunk* mchunkptr;
static void* _int_malloc(mstate, size_t);
static void _int_free(mstate, mchunkptr, int);
+static void _int_free_merge_chunk (mstate, mchunkptr, INTERNAL_SIZE_T);
+static INTERNAL_SIZE_T _int_free_create_chunk (mstate,
+ mchunkptr, INTERNAL_SIZE_T,
+ mchunkptr, INTERNAL_SIZE_T);
+static void _int_free_maybe_consolidate (mstate, INTERNAL_SIZE_T);
static void* _int_realloc(mstate, mchunkptr, INTERNAL_SIZE_T,
INTERNAL_SIZE_T);
static void* _int_memalign(mstate, size_t, size_t);
@@ -4637,31 +4642,52 @@ _int_free (mstate av, mchunkptr p, int have_lock)
if (!have_lock)
__libc_lock_lock (av->mutex);
- nextchunk = chunk_at_offset(p, size);
-
- /* Lightweight tests: check whether the block is already the
- top block. */
- if (__glibc_unlikely (p == av->top))
- malloc_printerr ("double free or corruption (top)");
- /* Or whether the next chunk is beyond the boundaries of the arena. */
- if (__builtin_expect (contiguous (av)
- && (char *) nextchunk
- >= ((char *) av->top + chunksize(av->top)), 0))
- malloc_printerr ("double free or corruption (out)");
- /* Or whether the block is actually not marked used. */
- if (__glibc_unlikely (!prev_inuse(nextchunk)))
- malloc_printerr ("double free or corruption (!prev)");
-
- nextsize = chunksize(nextchunk);
- if (__builtin_expect (chunksize_nomask (nextchunk) <= CHUNK_HDR_SZ, 0)
- || __builtin_expect (nextsize >= av->system_mem, 0))
- malloc_printerr ("free(): invalid next size (normal)");
+ _int_free_merge_chunk (av, p, size);
- free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
+ if (!have_lock)
+ __libc_lock_unlock (av->mutex);
+ }
+ /*
+ If the chunk was allocated via mmap, release via munmap().
+ */
+
+ else {
+ munmap_chunk (p);
+ }
+}
+
+/* Try to merge chunk P of SIZE bytes with its neighbors. Put the
+ resulting chunk on the appropriate bin list. P must not be on a
+ bin list yet, and it can be in use. */
+static void
+_int_free_merge_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size)
+{
+ mchunkptr nextchunk = chunk_at_offset(p, size);
+
+ /* Lightweight tests: check whether the block is already the
+ top block. */
+ if (__glibc_unlikely (p == av->top))
+ malloc_printerr ("double free or corruption (top)");
+ /* Or whether the next chunk is beyond the boundaries of the arena. */
+ if (__builtin_expect (contiguous (av)
+ && (char *) nextchunk
+ >= ((char *) av->top + chunksize(av->top)), 0))
+ malloc_printerr ("double free or corruption (out)");
+ /* Or whether the block is actually not marked used. */
+ if (__glibc_unlikely (!prev_inuse(nextchunk)))
+ malloc_printerr ("double free or corruption (!prev)");
+
+ INTERNAL_SIZE_T nextsize = chunksize(nextchunk);
+ if (__builtin_expect (chunksize_nomask (nextchunk) <= CHUNK_HDR_SZ, 0)
+ || __builtin_expect (nextsize >= av->system_mem, 0))
+ malloc_printerr ("free(): invalid next size (normal)");
+
+ free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
- /* consolidate backward */
- if (!prev_inuse(p)) {
- prevsize = prev_size (p);
+ /* Consolidate backward. */
+ if (!prev_inuse(p))
+ {
+ INTERNAL_SIZE_T prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
if (__glibc_unlikely (chunksize(p) != prevsize))
@@ -4669,9 +4695,25 @@ _int_free (mstate av, mchunkptr p, int have_lock)
unlink_chunk (av, p);
}
- if (nextchunk != av->top) {
+ /* Write the chunk header, maybe after merging with the following chunk. */
+ size = _int_free_create_chunk (av, p, size, nextchunk, nextsize);
+ _int_free_maybe_consolidate (av, size);
+}
+
+/* Create a chunk at P of SIZE bytes, with SIZE potentially increased
+ to cover the immediately following chunk NEXTCHUNK of NEXTSIZE
+ bytes (if NEXTCHUNK is unused). The chunk at P is not actually
+ read and does not have to be initialized. After creation, it is
+ placed on the appropriate bin list. The function returns the size
+ of the new chunk. */
+static INTERNAL_SIZE_T
+_int_free_create_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size,
+ mchunkptr nextchunk, INTERNAL_SIZE_T nextsize)
+{
+ if (nextchunk != av->top)
+ {
/* get and clear inuse bit */
- nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
+ bool nextinuse = inuse_bit_at_offset (nextchunk, nextsize);
/* consolidate forward */
if (!nextinuse) {
@@ -4686,8 +4728,8 @@ _int_free (mstate av, mchunkptr p, int have_lock)
been given one chance to be used in malloc.
*/
- bck = unsorted_chunks(av);
- fwd = bck->fd;
+ mchunkptr bck = unsorted_chunks (av);
+ mchunkptr fwd = bck->fd;
if (__glibc_unlikely (fwd->bk != bck))
malloc_printerr ("free(): corrupted unsorted chunks");
p->fd = fwd;
@@ -4706,61 +4748,52 @@ _int_free (mstate av, mchunkptr p, int have_lock)
check_free_chunk(av, p);
}
- /*
- If the chunk borders the current high end of memory,
- consolidate into top
- */
-
- else {
+ else
+ {
+ /* If the chunk borders the current high end of memory,
+ consolidate into top. */
size += nextsize;
set_head(p, size | PREV_INUSE);
av->top = p;
check_chunk(av, p);
}
- /*
- If freeing a large space, consolidate possibly-surrounding
- chunks. Then, if the total unused topmost memory exceeds trim
- threshold, ask malloc_trim to reduce top.
-
- Unless max_fast is 0, we don't know if there are fastbins
- bordering top, so we cannot tell for sure whether threshold
- has been reached unless fastbins are consolidated. But we
- don't want to consolidate on each free. As a compromise,
- consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD
- is reached.
- */
+ return size;
+}
- if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) {
+/* If freeing a large space, consolidate possibly-surrounding
+ chunks. Then, if the total unused topmost memory exceeds trim
+ threshold, ask malloc_trim to reduce top. */
+static void
+_int_free_maybe_consolidate (mstate av, INTERNAL_SIZE_T size)
+{
+ /* Unless max_fast is 0, we don't know if there are fastbins
+ bordering top, so we cannot tell for sure whether threshold has
+ been reached unless fastbins are consolidated. But we don't want
+ to consolidate on each free. As a compromise, consolidation is
+ performed if FASTBIN_CONSOLIDATION_THRESHOLD is reached. */
+ if (size >= FASTBIN_CONSOLIDATION_THRESHOLD)
+ {
if (atomic_load_relaxed (&av->have_fastchunks))
malloc_consolidate(av);
- if (av == &main_arena) {
+ if (av == &main_arena)
+ {
#ifndef MORECORE_CANNOT_TRIM
- if ((unsigned long)(chunksize(av->top)) >=
- (unsigned long)(mp_.trim_threshold))
- systrim(mp_.top_pad, av);
+ if (chunksize (av->top) >= mp_.trim_threshold)
+ systrim (mp_.top_pad, av);
#endif
- } else {
- /* Always try heap_trim(), even if the top chunk is not
- large, because the corresponding heap might go away. */
- heap_info *heap = heap_for_ptr(top(av));
+ }
+ else
+ {
+ /* Always try heap_trim, even if the top chunk is not large,
+ because the corresponding heap might go away. */
+ heap_info *heap = heap_for_ptr (top (av));
- assert(heap->ar_ptr == av);
- heap_trim(heap, mp_.top_pad);
- }
+ assert (heap->ar_ptr == av);
+ heap_trim (heap, mp_.top_pad);
+ }
}
-
- if (!have_lock)
- __libc_lock_unlock (av->mutex);
- }
- /*
- If the chunk was allocated via mmap, release via munmap().
- */
-
- else {
- munmap_chunk (p);
- }
}
/*
@@ -5221,7 +5254,7 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
(av != &main_arena ? NON_MAIN_ARENA : 0));
set_inuse_bit_at_offset (newp, newsize);
set_head_size (p, leadsize | (av != &main_arena ? NON_MAIN_ARENA : 0));
- _int_free (av, p, 1);
+ _int_free_merge_chunk (av, p, leadsize);
p = newp;
assert (newsize >= nb &&
@@ -5232,15 +5265,27 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
if (!chunk_is_mmapped (p))
{
size = chunksize (p);
- if ((unsigned long) (size) > (unsigned long) (nb + MINSIZE))
+ mchunkptr nextchunk = chunk_at_offset(p, size);
+ INTERNAL_SIZE_T nextsize = chunksize(nextchunk);
+ if (size > nb)
{
remainder_size = size - nb;
- remainder = chunk_at_offset (p, nb);
- set_head (remainder, remainder_size | PREV_INUSE |
- (av != &main_arena ? NON_MAIN_ARENA : 0));
- set_head_size (p, nb);
- _int_free (av, remainder, 1);
- }
+ if (remainder_size >= MINSIZE
+ || nextchunk == av->top
+ || !inuse_bit_at_offset (nextchunk, nextsize))
+ {
+ /* We can only give back the tail if it is larger than
+ MINSIZE, or if the following chunk is unused (top
+ chunk or unused in-heap chunk). Otherwise we would
+ create a chunk that is smaller than MINSIZE. */
+ remainder = chunk_at_offset (p, nb);
+ set_head_size (p, nb);
+ remainder_size = _int_free_create_chunk (av, remainder,
+ remainder_size,
+ nextchunk, nextsize);
+ _int_free_maybe_consolidate (av, remainder_size);
+ }
+ }
}
check_inuse_chunk (av, p);

View File

@ -1,252 +0,0 @@
From 0dc7fc1cf094406a138e4d1bcf9553e59edcf89d Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Thu, 10 Aug 2023 19:36:56 +0200
Subject: [PATCH] malloc: Remove bin scanning from memalign (bug 30723)
On the test workload (mpv --cache=yes with VP9 video decoding), the
bin scanning has a very poor success rate (less than 2%). The tcache
scanning has about 50% success rate, so keep that.
Update comments in malloc/tst-memalign-2 to indicate the purpose
of the tests. Even with the scanning removed, the additional
merging opportunities since commit 542b1105852568c3ebc712225ae78b
("malloc: Enable merging of remainders in memalign (bug 30723)")
are sufficient to pass the existing large bins test.
Remove leftover variables from _int_free from refactoring in the
same commit.
Reviewed-by: DJ Delorie <dj@redhat.com>
---
malloc/malloc.c | 169 ++--------------------------------------
malloc/tst-memalign-2.c | 7 +-
2 files changed, 10 insertions(+), 166 deletions(-)
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 948f9759af..d0bbbf3710 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -4488,12 +4488,6 @@ _int_free (mstate av, mchunkptr p, int have_lock)
{
INTERNAL_SIZE_T size; /* its size */
mfastbinptr *fb; /* associated fastbin */
- mchunkptr nextchunk; /* next contiguous chunk */
- INTERNAL_SIZE_T nextsize; /* its size */
- int nextinuse; /* true if nextchunk is used */
- INTERNAL_SIZE_T prevsize; /* size of previous contiguous chunk */
- mchunkptr bck; /* misc temp for linking */
- mchunkptr fwd; /* misc temp for linking */
size = chunksize (p);
@@ -5032,42 +5026,6 @@ _int_realloc (mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
------------------------------ memalign ------------------------------
*/
-/* Returns 0 if the chunk is not and does not contain the requested
- aligned sub-chunk, else returns the amount of "waste" from
- trimming. NB is the *chunk* byte size, not the user byte
- size. */
-static size_t
-chunk_ok_for_memalign (mchunkptr p, size_t alignment, size_t nb)
-{
- void *m = chunk2mem (p);
- INTERNAL_SIZE_T size = chunksize (p);
- void *aligned_m = m;
-
- if (__glibc_unlikely (misaligned_chunk (p)))
- malloc_printerr ("_int_memalign(): unaligned chunk detected");
-
- aligned_m = PTR_ALIGN_UP (m, alignment);
-
- INTERNAL_SIZE_T front_extra = (intptr_t) aligned_m - (intptr_t) m;
-
- /* We can't trim off the front as it's too small. */
- if (front_extra > 0 && front_extra < MINSIZE)
- return 0;
-
- /* If it's a perfect fit, it's an exception to the return value rule
- (we would return zero waste, which looks like "not usable"), so
- handle it here by returning a small non-zero value instead. */
- if (size == nb && front_extra == 0)
- return 1;
-
- /* If the block we need fits in the chunk, calculate total waste. */
- if (size > nb + front_extra)
- return size - nb;
-
- /* Can't use this chunk. */
- return 0;
-}
-
/* BYTES is user requested bytes, not requested chunksize bytes. */
static void *
_int_memalign (mstate av, size_t alignment, size_t bytes)
@@ -5082,7 +5040,6 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
mchunkptr remainder; /* spare room at end to split off */
unsigned long remainder_size; /* its size */
INTERNAL_SIZE_T size;
- mchunkptr victim;
nb = checked_request2size (bytes);
if (nb == 0)
@@ -5101,129 +5058,13 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
we don't find anything in those bins, the common malloc code will
scan starting at 2x. */
- /* This will be set if we found a candidate chunk. */
- victim = NULL;
-
- /* Fast bins are singly-linked, hard to remove a chunk from the middle
- and unlikely to meet our alignment requirements. We have not done
- any experimentation with searching for aligned fastbins. */
-
- if (av != NULL)
- {
- int first_bin_index;
- int first_largebin_index;
- int last_bin_index;
-
- if (in_smallbin_range (nb))
- first_bin_index = smallbin_index (nb);
- else
- first_bin_index = largebin_index (nb);
-
- if (in_smallbin_range (nb * 2))
- last_bin_index = smallbin_index (nb * 2);
- else
- last_bin_index = largebin_index (nb * 2);
-
- first_largebin_index = largebin_index (MIN_LARGE_SIZE);
-
- int victim_index; /* its bin index */
-
- for (victim_index = first_bin_index;
- victim_index < last_bin_index;
- victim_index ++)
- {
- victim = NULL;
-
- if (victim_index < first_largebin_index)
- {
- /* Check small bins. Small bin chunks are doubly-linked despite
- being the same size. */
-
- mchunkptr fwd; /* misc temp for linking */
- mchunkptr bck; /* misc temp for linking */
-
- bck = bin_at (av, victim_index);
- fwd = bck->fd;
- while (fwd != bck)
- {
- if (chunk_ok_for_memalign (fwd, alignment, nb) > 0)
- {
- victim = fwd;
-
- /* Unlink it */
- victim->fd->bk = victim->bk;
- victim->bk->fd = victim->fd;
- break;
- }
-
- fwd = fwd->fd;
- }
- }
- else
- {
- /* Check large bins. */
- mchunkptr fwd; /* misc temp for linking */
- mchunkptr bck; /* misc temp for linking */
- mchunkptr best = NULL;
- size_t best_size = 0;
-
- bck = bin_at (av, victim_index);
- fwd = bck->fd;
+ /* Call malloc with worst case padding to hit alignment. */
+ m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
- while (fwd != bck)
- {
- int extra;
-
- if (chunksize (fwd) < nb)
- break;
- extra = chunk_ok_for_memalign (fwd, alignment, nb);
- if (extra > 0
- && (extra <= best_size || best == NULL))
- {
- best = fwd;
- best_size = extra;
- }
+ if (m == 0)
+ return 0; /* propagate failure */
- fwd = fwd->fd;
- }
- victim = best;
-
- if (victim != NULL)
- {
- unlink_chunk (av, victim);
- break;
- }
- }
-
- if (victim != NULL)
- break;
- }
- }
-
- /* Strategy: find a spot within that chunk that meets the alignment
- request, and then possibly free the leading and trailing space.
- This strategy is incredibly costly and can lead to external
- fragmentation if header and footer chunks are unused. */
-
- if (victim != NULL)
- {
- p = victim;
- m = chunk2mem (p);
- set_inuse (p);
- if (av != &main_arena)
- set_non_main_arena (p);
- }
- else
- {
- /* Call malloc with worst case padding to hit alignment. */
-
- m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
-
- if (m == 0)
- return 0; /* propagate failure */
-
- p = mem2chunk (m);
- }
+ p = mem2chunk (m);
if ((((unsigned long) (m)) % alignment) != 0) /* misaligned */
{
diff --git a/malloc/tst-memalign-2.c b/malloc/tst-memalign-2.c
index f229283dbf..ecd6fa249e 100644
--- a/malloc/tst-memalign-2.c
+++ b/malloc/tst-memalign-2.c
@@ -86,7 +86,8 @@ do_test (void)
TEST_VERIFY (tcache_allocs[i].ptr1 == tcache_allocs[i].ptr2);
}
- /* Test for non-head tcache hits. */
+ /* Test for non-head tcache hits. This exercises the memalign
+ scanning code to find matching allocations. */
for (i = 0; i < array_length (ptr); ++ i)
{
if (i == 4)
@@ -113,7 +114,9 @@ do_test (void)
free (p);
TEST_VERIFY (count > 0);
- /* Large bins test. */
+ /* Large bins test. This verifies that the over-allocated parts
+ that memalign releases for future allocations can be reused by
+ memalign itself at least in some cases. */
for (i = 0; i < LN; ++ i)
{

View File

@ -0,0 +1,80 @@
From 312e159626b67fe11f39e83e222cf4348a3962f3 Mon Sep 17 00:00:00 2001
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu, 1 Feb 2024 14:29:53 -0300
Subject: [PATCH] mips: FIx clone3 implementation (BZ 31325)
For o32 we need to setup a minimal stack frame to allow cprestore
on __thread_start_clone3 (which instruct the linker to save the
gp for PIC). Also, there is no guarantee by kABI that $8 will be
preserved after syscall execution, so we need to save it on the
provided stack.
Checked on mipsel-linux-gnu.
Reported-by: Khem Raj <raj.khem@gmail.com>
Tested-by: Khem Raj <raj.khem@gmail.com>
(cherry picked from commit bbd248ac0d75efdef8fe61ea69b1fb25fb95b6e7)
---
sysdeps/unix/sysv/linux/mips/clone3.S | 32 ++++++++++++++++++++++-----
1 file changed, 27 insertions(+), 5 deletions(-)
diff --git a/sysdeps/unix/sysv/linux/mips/clone3.S b/sysdeps/unix/sysv/linux/mips/clone3.S
index e9fec2fa47..481b8ae963 100644
--- a/sysdeps/unix/sysv/linux/mips/clone3.S
+++ b/sysdeps/unix/sysv/linux/mips/clone3.S
@@ -37,11 +37,6 @@
.text
.set nomips16
-#if _MIPS_SIM == _ABIO32
-# define EXTRA_LOCALS 1
-#else
-# define EXTRA_LOCALS 0
-#endif
#define FRAMESZ ((NARGSAVE*SZREG)+ALSZ)&ALMASK
GPOFF= FRAMESZ-(1*SZREG)
NESTED(__clone3, SZREG, sp)
@@ -68,8 +63,31 @@ NESTED(__clone3, SZREG, sp)
beqz a0, L(error) /* No NULL cl_args pointer. */
beqz a2, L(error) /* No NULL function pointer. */
+#if _MIPS_SIM == _ABIO32
+ /* Both stack and stack_size on clone_args are defined as uint64_t, and
+ there is no need to handle values larger than to 32 bits for o32. */
+# if __BYTE_ORDER == __BIG_ENDIAN
+# define CL_STACKPOINTER_OFFSET 44
+# define CL_STACKSIZE_OFFSET 52
+# else
+# define CL_STACKPOINTER_OFFSET 40
+# define CL_STACKSIZE_OFFSET 48
+# endif
+
+ /* For o32 we need to setup a minimal stack frame to allow cprestore
+ on __thread_start_clone3. Also there is no guarantee by kABI that
+ $8 will be preserved after syscall execution (so we need to save it
+ on the provided stack). */
+ lw t0, CL_STACKPOINTER_OFFSET(a0) /* Load the stack pointer. */
+ lw t1, CL_STACKSIZE_OFFSET(a0) /* Load the stack_size. */
+ addiu t1, -32 /* Update the stack size. */
+ addu t2, t1, t0 /* Calculate the thread stack. */
+ sw a3, 0(t2) /* Save argument pointer. */
+ sw t1, CL_STACKSIZE_OFFSET(a0) /* Save the new stack size. */
+#else
move $8, a3 /* a3 is set to 0/1 for syscall success/error
while a4/$8 is returned unmodified. */
+#endif
/* Do the system call, the kernel expects:
v0: system call number
@@ -125,7 +143,11 @@ L(thread_start_clone3):
/* Restore the arg for user's function. */
move t9, a2 /* Function pointer. */
+#if _MIPS_SIM == _ABIO32
+ PTR_L a0, 0(sp)
+#else
move a0, $8 /* Argument pointer. */
+#endif
/* Call the user's function. */
jal t9

View File

@ -0,0 +1,37 @@
From 63295e4fda1f6dab4bf7442706fe303bf283036c Mon Sep 17 00:00:00 2001
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Mon, 5 Feb 2024 16:10:24 +0000
Subject: [PATCH] arm: Remove wrong ldr from _dl_start_user (BZ 31339)
The commit 49d877a80b29d3002887b084eec6676d9f5fec18 (arm: Remove
_dl_skip_args usage) removed the _SKIP_ARGS literal, which was
previously loader to r4 on loader _start. However, the cleanup did not
remove the following 'ldr r4, [sl, r4]' on _dl_start_user, used to check
to skip the arguments after ld self-relocations.
In my testing, the kernel initially set r4 to 0, which makes the
ldr instruction just read the _GLOBAL_OFFSET_TABLE_. However, since r4
is a callee-saved register; a different runtime might not zero
initialize it and thus trigger an invalid memory access.
Checked on arm-linux-gnu.
Reported-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
(cherry picked from commit 1e25112dc0cb2515d27d8d178b1ecce778a9d37a)
---
sysdeps/arm/dl-machine.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h
index b857bbc868..dd1a0f6b6e 100644
--- a/sysdeps/arm/dl-machine.h
+++ b/sysdeps/arm/dl-machine.h
@@ -139,7 +139,6 @@ _start:\n\
_dl_start_user:\n\
adr r6, .L_GET_GOT\n\
add sl, sl, r6\n\
- ldr r4, [sl, r4]\n\
@ save the entry point in another register\n\
mov r6, r0\n\
@ get the original arg count\n\

View File

@ -1,178 +0,0 @@
From 23514c72b780f3da097ecf33a793b7ba9c2070d2 Mon Sep 17 00:00:00 2001
From: Arjun Shankar <arjun@redhat.com>
Date: Mon, 15 Jan 2024 17:44:43 +0100
Subject: [PATCH] syslog: Fix heap buffer overflow in __vsyslog_internal
(CVE-2023-6246)
__vsyslog_internal did not handle a case where printing a SYSLOG_HEADER
containing a long program name failed to update the required buffer
size, leading to the allocation and overflow of a too-small buffer on
the heap. This commit fixes that. It also adds a new regression test
that uses glibc.malloc.check.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 6bd0e4efcc78f3c0115e5ea9739a1642807450da)
---
misc/Makefile | 8 ++-
misc/syslog.c | 50 +++++++++++++------
misc/tst-syslog-long-progname.c | 39 +++++++++++++++
.../postclean.req | 0
4 files changed, 82 insertions(+), 15 deletions(-)
create mode 100644 misc/tst-syslog-long-progname.c
create mode 100644 misc/tst-syslog-long-progname.root/postclean.req
diff --git a/misc/Makefile b/misc/Makefile
index fe0d49c1de5..90b31952c59 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -289,7 +289,10 @@ tests-special += $(objpfx)tst-error1-mem.out \
$(objpfx)tst-allocate_once-mem.out
endif
-tests-container := tst-syslog
+tests-container := \
+ tst-syslog \
+ tst-syslog-long-progname \
+ # tests-container
CFLAGS-select.c += -fexceptions -fasynchronous-unwind-tables
CFLAGS-tsearch.c += $(uses-callbacks)
@@ -351,6 +354,9 @@ $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \
$(evaluate-test)
+tst-syslog-long-progname-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 \
+ LD_PRELOAD=libc_malloc_debug.so.0
+
$(objpfx)tst-select: $(librt)
$(objpfx)tst-select-time64: $(librt)
$(objpfx)tst-pselect: $(librt)
diff --git a/misc/syslog.c b/misc/syslog.c
index 1b8cb722c51..814d224a1e9 100644
--- a/misc/syslog.c
+++ b/misc/syslog.c
@@ -124,8 +124,9 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
{
/* Try to use a static buffer as an optimization. */
char bufs[1024];
- char *buf = NULL;
- size_t bufsize = 0;
+ char *buf = bufs;
+ size_t bufsize;
+
int msgoff;
int saved_errno = errno;
@@ -177,29 +178,50 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
#define SYSLOG_HEADER_WITHOUT_TS(__pri, __msgoff) \
"<%d>: %n", __pri, __msgoff
- int l;
+ int l, vl;
if (has_ts)
l = __snprintf (bufs, sizeof bufs,
SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
else
l = __snprintf (bufs, sizeof bufs,
SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
+
+ char *pos;
+ size_t len;
+
if (0 <= l && l < sizeof bufs)
{
- va_list apc;
- va_copy (apc, ap);
+ /* At this point, there is still a chance that we can print the
+ remaining part of the log into bufs and use that. */
+ pos = bufs + l;
+ len = sizeof (bufs) - l;
+ }
+ else
+ {
+ buf = NULL;
+ /* We already know that bufs is too small to use for this log message.
+ The next vsnprintf into bufs is used only to calculate the total
+ required buffer length. We will discard bufs contents and allocate
+ an appropriately sized buffer later instead. */
+ pos = bufs;
+ len = sizeof (bufs);
+ }
- /* Restore errno for %m format. */
- __set_errno (saved_errno);
+ {
+ va_list apc;
+ va_copy (apc, ap);
- int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc,
- mode_flags);
- if (0 <= vl && vl < sizeof bufs - l)
- buf = bufs;
- bufsize = l + vl;
+ /* Restore errno for %m format. */
+ __set_errno (saved_errno);
- va_end (apc);
- }
+ vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags);
+
+ if (!(0 <= vl && vl < len))
+ buf = NULL;
+
+ bufsize = l + vl;
+ va_end (apc);
+ }
if (buf == NULL)
{
diff --git a/misc/tst-syslog-long-progname.c b/misc/tst-syslog-long-progname.c
new file mode 100644
index 00000000000..88f37a8a004
--- /dev/null
+++ b/misc/tst-syslog-long-progname.c
@@ -0,0 +1,39 @@
+/* Test heap buffer overflow in syslog with long __progname (CVE-2023-6246)
+ Copyright (C) 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <syslog.h>
+#include <string.h>
+
+extern char * __progname;
+
+static int
+do_test (void)
+{
+ char long_progname[2048];
+
+ memset (long_progname, 'X', sizeof (long_progname) - 1);
+ long_progname[sizeof (long_progname) - 1] = '\0';
+
+ __progname = long_progname;
+
+ syslog (LOG_INFO, "Hello, World!");
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/misc/tst-syslog-long-progname.root/postclean.req b/misc/tst-syslog-long-progname.root/postclean.req
new file mode 100644
index 00000000000..e69de29bb2d

View File

@ -1,103 +0,0 @@
From d0338312aace5bbfef85e03055e1212dd0e49578 Mon Sep 17 00:00:00 2001
From: Arjun Shankar <arjun@redhat.com>
Date: Mon, 15 Jan 2024 17:44:44 +0100
Subject: [PATCH] syslog: Fix heap buffer overflow in __vsyslog_internal
(CVE-2023-6779)
__vsyslog_internal used the return value of snprintf/vsnprintf to
calculate buffer sizes for memory allocation. If these functions (for
any reason) failed and returned -1, the resulting buffer would be too
small to hold output. This commit fixes that.
All snprintf/vsnprintf calls are checked for negative return values and
the function silently returns upon encountering them.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 7e5a0c286da33159d47d0122007aac016f3e02cd)
---
misc/syslog.c | 39 ++++++++++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/misc/syslog.c b/misc/syslog.c
index 814d224a1e..53440e47ad 100644
--- a/misc/syslog.c
+++ b/misc/syslog.c
@@ -185,11 +185,13 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
else
l = __snprintf (bufs, sizeof bufs,
SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
+ if (l < 0)
+ goto out;
char *pos;
size_t len;
- if (0 <= l && l < sizeof bufs)
+ if (l < sizeof bufs)
{
/* At this point, there is still a chance that we can print the
remaining part of the log into bufs and use that. */
@@ -215,12 +217,15 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
__set_errno (saved_errno);
vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags);
+ va_end (apc);
+
+ if (vl < 0)
+ goto out;
- if (!(0 <= vl && vl < len))
+ if (vl >= len)
buf = NULL;
bufsize = l + vl;
- va_end (apc);
}
if (buf == NULL)
@@ -231,25 +236,37 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
/* Tell the cancellation handler to free this buffer. */
clarg.buf = buf;
+ int cl;
if (has_ts)
- __snprintf (buf, l + 1,
- SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
+ cl = __snprintf (buf, l + 1,
+ SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
else
- __snprintf (buf, l + 1,
- SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
+ cl = __snprintf (buf, l + 1,
+ SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
+ if (cl != l)
+ goto out;
va_list apc;
va_copy (apc, ap);
- __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc,
- mode_flags);
+ cl = __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc,
+ mode_flags);
va_end (apc);
+
+ if (cl != vl)
+ goto out;
}
else
{
+ int bl;
/* Nothing much to do but emit an error message. */
- bufsize = __snprintf (bufs, sizeof bufs,
- "out of memory[%d]", __getpid ());
+ bl = __snprintf (bufs, sizeof bufs,
+ "out of memory[%d]", __getpid ());
+ if (bl < 0 || bl >= sizeof bufs)
+ goto out;
+
+ bufsize = bl;
buf = bufs;
+ msgoff = 0;
}
}

View File

@ -1,38 +0,0 @@
From d37c2b20a4787463d192b32041c3406c2bd91de0 Mon Sep 17 00:00:00 2001
From: Arjun Shankar <arjun@redhat.com>
Date: Mon, 15 Jan 2024 17:44:45 +0100
Subject: [PATCH] syslog: Fix integer overflow in __vsyslog_internal
(CVE-2023-6780)
__vsyslog_internal calculated a buffer size by adding two integers, but
did not first check if the addition would overflow. This commit fixes
that.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit ddf542da94caf97ff43cc2875c88749880b7259b)
---
misc/syslog.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/misc/syslog.c b/misc/syslog.c
index 53440e47ad..4af87f54fd 100644
--- a/misc/syslog.c
+++ b/misc/syslog.c
@@ -41,6 +41,7 @@ static char sccsid[] = "@(#)syslog.c 8.4 (Berkeley) 3/18/94";
#include <sys/uio.h>
#include <sys/un.h>
#include <syslog.h>
+#include <limits.h>
static int LogType = SOCK_DGRAM; /* type of socket connection */
static int LogFile = -1; /* fd for log */
@@ -219,7 +220,7 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags);
va_end (apc);
- if (vl < 0)
+ if (vl < 0 || vl >= INT_MAX - l)
goto out;
if (vl >= len)

View File

@ -1,192 +0,0 @@
From b25508dd774b617f99419bdc3cf2ace4560cd2d6 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
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)
---
NEWS | 9 +++
resolv/Makefile | 2 +
resolv/nss_dns/dns-host.c | 2 +-
resolv/tst-resolv-noaaaa-vc.c | 129 ++++++++++++++++++++++++++++++++++
4 files changed, 141 insertions(+), 1 deletion(-)
create mode 100644 resolv/tst-resolv-noaaaa-vc.c
diff --git a/resolv/Makefile b/resolv/Makefile
index 054b1fa36c..2f99eb3862 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -102,6 +102,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 \
@@ -293,6 +294,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 1d60c51f5e..5d0ab30de6 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+/* 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 <support/test-driver.c>

View File

@ -1,198 +0,0 @@
From 0d5f9ea97f1b39f2a855756078771673a68497e1 Mon Sep 17 00:00:00 2001
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Tue, 19 Sep 2023 13:25:40 -0400
Subject: [PATCH] Propagate GLIBC_TUNABLES in setxid binaries
GLIBC_TUNABLES scrubbing happens earlier than envvar scrubbing and some
tunables are required to propagate past setxid boundary, like their
env_alias. Rely on tunable scrubbing to clean out GLIBC_TUNABLES like
before, restoring behaviour in glibc 2.37 and earlier.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
---
sysdeps/generic/unsecvars.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/sysdeps/generic/unsecvars.h b/sysdeps/generic/unsecvars.h
index 81397fb90b..8278c50a84 100644
--- a/sysdeps/generic/unsecvars.h
+++ b/sysdeps/generic/unsecvars.h
@@ -4,7 +4,6 @@
#define UNSECURE_ENVVARS \
"GCONV_PATH\0" \
"GETCONF_DIR\0" \
- "GLIBC_TUNABLES\0" \
"HOSTALIASES\0" \
"LD_AUDIT\0" \
"LD_DEBUG\0" \
--
From 1056e5b4c3f2d90ed2b4a55f96add28da2f4c8fa Mon Sep 17 00:00:00 2001
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
---
NEWS | 5 +++++
elf/dl-tunables.c | 17 +++++++++-------
elf/tst-env-setuid-tunables.c | 37 +++++++++++++++++++++++++++--------
3 files changed, 44 insertions(+), 15 deletions(-)
diff --git a/NEWS b/NEWS
index a94650da64..cc4b81f0ac 100644
--- a/NEWS
+++ b/NEWS
@@ -64,6 +64,11 @@ Security related changes:
an application calls getaddrinfo for AF_INET6 with AI_CANONNAME,
AI_ALL and AI_V4MAPPED flags set.
+ CVE-2023-4911: If a tunable of the form NAME=NAME=VAL is passed in the
+ environment of a setuid program and NAME is valid, it may result in a
+ buffer overflow, which could be exploited to achieve escalated
+ privileges. This flaw was introduced in glibc 2.34.
+
The following bugs are resolved with this release:
[The release manager will add the list generated by
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
index 62b7332d95..cae67efa0a 100644
--- a/elf/dl-tunables.c
+++ b/elf/dl-tunables.c
@@ -180,11 +180,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. */
@@ -244,9 +240,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';
}
/* Enable the glibc.malloc.check tunable in SETUID/SETGID programs only when
diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c
index 7dfb0e073a..f0b92c97e7 100644
--- a/elf/tst-env-setuid-tunables.c
+++ b/elf/tst-env-setuid-tunables.c
@@ -50,6 +50,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",
@@ -68,6 +70,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",
+ "",
"",
"",
"",
@@ -81,11 +85,18 @@ test_child (int off)
{
const char *val = getenv ("GLIBC_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;
}
@@ -106,21 +117,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);
@@ -128,9 +144,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;
}
}

View File

@ -1,14 +1,14 @@
# Template file for 'glibc'
pkgname=glibc
version=2.38
revision=6
version=2.39
revision=1
bootstrap=yes
short_desc="GNU C library"
maintainer="Enno Boland <gottox@voidlinux.org>"
license="GPL-2.0-or-later, LGPL-2.1-or-later, BSD-3-Clause"
homepage="http://www.gnu.org/software/libc"
distfiles="${GNU_SITE}/libc/glibc-${version}.tar.xz"
checksum=fb82998998b2b29965467bc1b69d152e9c307d2cf301c9eafb4555b770ef3fd2
checksum=f77bd47cf8170c57365ae7bf86696c118adb3b120d3259c64c502d3dc1e2d926
# Do not strip these files, objcopy errors out.
nostrip_files="
XBS5_ILP32_OFFBIG
@ -48,13 +48,12 @@ conf_files="
/etc/ld.so.conf"
if [ "$CHROOT_READY" ]; then
hostmakedepends="bison gettext perl python3 texinfo"
# XXX: remove this on the next update
# ensures partial upgrades don't break things like PAM
depends="libxcrypt-compat"
fi
makedepends="kernel-libc-headers"
lib32files="/usr/lib/gconv/gconv-modules"
lib32symlinks="ld-linux.so.2"
# glibc 2.38 stops providing libcrypt.so.1
conflicts="glibc-32bit<2.38_1"
archs="~*-musl"
if [ "$XBPS_TARGET_LIBC" = musl ]; then
broken="no point in building this for musl"
@ -67,20 +66,17 @@ do_configure() {
local _libdir=/usr/lib${XBPS_TARGET_WORDSIZE}
echo "slibdir=${_libdir}" > configparms
echo "rtlddir=${_libdir}" >> configparms
echo "bindir=/usr/bin" >> configparms
echo "sbindir=/usr/bin" >> configparms
echo "rootsbindir=/usr/sbin" >> configparms
echo "rootsbindir=/usr/bin" >> configparms
case "$XBPS_TARGET_MACHINE" in
# Build with -mno-tls-direct-seg-refs to avoid performance
# problems with Xen on x86 32bit.
i686) export CFLAGS+=" -mno-tls-direct-seg-refs";;
# Force hard float ABI.
# To build for soft float: --with-float=soft --without-fp.
armv5*) configure_args+=" --with-march=armv5te --without-fp --with-float=soft";;
armv6l*) configure_args+=" --with-march=armv6 --with-fpu=vfp --with-float=hard";;
armv7l*) configure_args+=" --with-march=armv7-a --with-fpu=vfpv3 --with-float=hard";;
arm64*) configure_args+=" --with-march=armv8-a";;
# Force soft float ABI on armv5.
armv5*) configure_args+=" --without-fp";;
esac
if [ "$CROSS_BUILD" ]; then
@ -103,9 +99,7 @@ do_configure() {
--enable-stack-protector=strong \
--disable-profile --enable-kernel=3.2.0 \
--without-selinux --without-gd \
--disable-werror \
libc_cv_rootsbindir=/usr/bin \
libc_cv_rtlddir=${_libdir} libc_cv_slibdir=${_libdir}
--disable-werror --enable-option-checking
}
post_configure() {
@ -133,7 +127,10 @@ do_install() {
( cd build && make install_root=${DESTDIR} install )
# The C.UTF-8 locale should always be available
if [ -z "${CROSS_BUILD}" ]; then
#
# Use the recently compiled localedef when compiling to/from the same
# architecture, and the host localedef binary otherwise.
if [ "${XBPS_MACHINE%-*}" = "${XBPS_TARGET_MACHINE%-*}" ]; then
make -C localedata DESTDIR="${DESTDIR}" \
objdir="../build" install-files-C.UTF-8/UTF-8
elif command -v localedef >/dev/null 2>&1; then
@ -184,8 +181,6 @@ do_install() {
# Remove tzselect and z{dump,ic}, provided by tzutils.
rm -f ${DESTDIR}/usr/bin/tzselect
rm -f ${DESTDIR}/usr/bin/z{dump,ic}
mv ${DESTDIR}/usr/sbin/* ${DESTDIR}/usr/bin
}
glibc-devel_package() {