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:
parent
edddc0dd57
commit
3269bbc3a8
|
@ -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
|
||||
|
|
|
@ -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);
|
|
@ -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
|
|
@ -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);
|
|
@ -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)
|
||||
{
|
|
@ -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
|
|
@ -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\
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue