crux-commits
Threads by month
- ----- 2025 -----
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
October 2022
- 1 participants
- 654 discussions
01 Oct '22
commit e9f89fc74dc5e9d764e2793848fc85212051bfef
Author: Tim Biermann <tbier(a)posteo.de>
Date: Sat Oct 1 16:18:37 2022 +0200
[notify] glibc-32: upstream fixes for CVE-2022-39046
diff --git a/glibc-32/.signature b/glibc-32/.signature
index d9170707..346961ce 100644
--- a/glibc-32/.signature
+++ b/glibc-32/.signature
@@ -1,8 +1,8 @@
untrusted comment: verify with /etc/ports/core.pub
-RWRJc1FUaeVeqjo9bPJnyNtbs00H4I0jpMELqe2PP+oDIRcMcYWSUMgIXE/1f9tv6mDdScYxj2ZfG7y1zNzy7xFG0Hb21bcGcAM=
-SHA256 (Pkgfile) = 5e08a30996fa14ee5d1e224e95bb393cf0d17944d6a37b78105d0400beeb523c
+RWRJc1FUaeVeqo/yaq0daCyYMKbPUqcBeSMqGa3hu37jZ+RoLsJiclGtvbuNnEcVkZvlFgQvjramjaNCA/9u9K76uZKanzOApQw=
+SHA256 (Pkgfile) = bf4f6b622c76910babef8944d76a95bc7ef5009cedd99aca864e698b44d09a10
SHA256 (.footprint) = f676700a19f936a1af944e81a516dbf182723d6ac244eadabd3fd19e9a01daa5
SHA256 (glibc-2.36.tar.xz) = 1c959fea240906226062cb4b1e7ebce71a9f0e3c0836c09e7e3423d434fcfe75
SHA256 (linux-5.15.55.tar.xz) = 1ef6bd508b6c3af3bef2d5b337e4477254dba284c79e329aa38f9763ae3bfdcc
-SHA256 (glibc-2.36-1.patch) = 6245087ab20402836cbd32b52ba944d31aeafc961ba597bcec0fa3727db79eee
+SHA256 (glibc-2.36-2.patch) = 4760e63dc0539952673bae08f3380608b53c74c9726e7f3137979f0f776d2a80
SHA256 (lib32.conf) = 2f174d2bcefe1c29327690514f34d6970fffdd54398320ca23a11b5f1e3c9b2d
diff --git a/glibc-32/Pkgfile b/glibc-32/Pkgfile
index 4b9baf9c..f6a5a858 100644
--- a/glibc-32/Pkgfile
+++ b/glibc-32/Pkgfile
@@ -4,12 +4,12 @@
name=glibc-32
version=2.36
-release=1
+release=2
_kernel_version=5.15.55
source=(https://ftp.gnu.org/gnu/glibc/glibc-$version.tar.xz
https://www.kernel.org/pub/linux/kernel/v5.x/linux-$_kernel_version.tar.xz
- glibc-$version-1.patch lib32.conf)
+ glibc-$version-2.patch lib32.conf)
build() {
# install kernel headers
@@ -18,7 +18,7 @@ build() {
make -C $SRC/linux-$_kernel_version INSTALL_HDR_PATH=$PKG/usr headers_install
chown root:root $PKG/usr
- patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-$version-1.patch
+ patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-$version-2.patch
mkdir $SRC/build
cd $SRC/build
diff --git a/glibc-32/glibc-2.36-1.patch b/glibc-32/glibc-2.36-1.patch
deleted file mode 100644
index 36bf0075..00000000
--- a/glibc-32/glibc-2.36-1.patch
+++ /dev/null
@@ -1,985 +0,0 @@
-diff --git a/NEWS b/NEWS
-index f61e521fc8..ae30900bbc 100644
---- a/NEWS
-+++ b/NEWS
-@@ -4,6 +4,16 @@ See the end for copying conditions.
-
- Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
- using `glibc' in the "product" field.
-+
-+Version 2.36.1
-+
-+The following bugs are resolved with this release:
-+
-+ [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning
-+ [29446] _dlopen now ignores dl_caller argument in static mode
-+ [29485] Linux: Terminate subprocess on late failure in tst-pidfd
-+ [29490] alpha: New __brk_call implementation is broken
-+
-
- Version 2.36
-
-diff --git a/bits/socket.h b/bits/socket.h
-index 2b99dea33b..aac8c49b00 100644
---- a/bits/socket.h
-+++ b/bits/socket.h
-@@ -245,6 +245,12 @@ struct cmsghdr
- + CMSG_ALIGN (sizeof (struct cmsghdr)))
- #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
-
-+/* Given a length, return the additional padding necessary such that
-+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
-+#define __CMSG_PADDING(len) ((sizeof (size_t) \
-+ - ((len) & (sizeof (size_t) - 1))) \
-+ & (sizeof (size_t) - 1))
-+
- extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
- struct cmsghdr *__cmsg) __THROW;
- #ifdef __USE_EXTERN_INLINES
-@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
- _EXTERN_INLINE struct cmsghdr *
- __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
- {
-+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
-+ __mhdr->msg_controllen because the user is required to obtain the first
-+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
-+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
-+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
-+ pointer arithmetic until we check its value. */
-+
-+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
-+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
-+
-+ size_t __size_needed = sizeof (struct cmsghdr)
-+ + __CMSG_PADDING (__cmsg->cmsg_len);
-+
-+ /* The current header is malformed, too small to be a full header. */
- if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
-- /* The kernel header does this so there may be a reason. */
- return (struct cmsghdr *) 0;
-
-+ /* There isn't enough space between __cmsg and the end of the buffer to
-+ hold the current cmsg *and* the next one. */
-+ if (((size_t)
-+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
-+ < __size_needed)
-+ || ((size_t)
-+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
-+ - __size_needed)
-+ < __cmsg->cmsg_len))
-+
-+ return (struct cmsghdr *) 0;
-+
-+ /* Now, we trust cmsg_len and can use it to find the next header. */
- __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
- + CMSG_ALIGN (__cmsg->cmsg_len));
-- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
-- + __mhdr->msg_controllen)
-- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
-- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
-- /* No more entries. */
-- return (struct cmsghdr *) 0;
- return __cmsg;
- }
- #endif /* Use `extern inline'. */
-diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c
-index 2696dde4b1..9b07b4e132 100644
---- a/dlfcn/dlopen.c
-+++ b/dlfcn/dlopen.c
-@@ -90,7 +90,7 @@ compat_symbol (libdl, ___dlopen, dlopen, GLIBC_2_1);
- void *
- __dlopen (const char *file, int mode, void *dl_caller)
- {
-- return dlopen_implementation (file, mode, RETURN_ADDRESS (0));
-+ return dlopen_implementation (file, mode, dl_caller);
- }
-
- void *
-diff --git a/elf/dl-cache.c b/elf/dl-cache.c
-index 8bbf110d02..b97c17b3a9 100644
---- a/elf/dl-cache.c
-+++ b/elf/dl-cache.c
-@@ -509,8 +509,9 @@ _dl_load_cache_lookup (const char *name)
- we are accessing. Therefore we must make the copy of the
- mapping data without using malloc. */
- char *temp;
-- temp = alloca (strlen (best) + 1);
-- strcpy (temp, best);
-+ size_t best_len = strlen (best) + 1;
-+ temp = alloca (best_len);
-+ memcpy (temp, best, best_len);
- return __strdup (temp);
- }
-
-diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
-index 43ab58ffe2..36d204c9b0 100644
---- a/scripts/glibcextract.py
-+++ b/scripts/glibcextract.py
-@@ -17,6 +17,7 @@
- # License along with the GNU C Library; if not, see
- # <https://www.gnu.org/licenses/>.
-
-+import collections
- import os.path
- import re
- import subprocess
-@@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None,
- if not allow_extra_2:
- ret = 1
- return ret
-+
-+CompileResult = collections.namedtuple("CompileResult", "returncode output")
-+
-+def compile_c_snippet(snippet, cc, extra_cc_args=''):
-+ """Compile and return whether the SNIPPET can be build with CC along
-+ EXTRA_CC_ARGS compiler flags. Return a CompileResult with RETURNCODE
-+ being 0 for success, or the failure value and the compiler output.
-+ """
-+ with tempfile.TemporaryDirectory() as temp_dir:
-+ c_file_name = os.path.join(temp_dir, 'test.c')
-+ obj_file_name = os.path.join(temp_dir, 'test.o')
-+ with open(c_file_name, 'w') as c_file:
-+ c_file.write(snippet + '\n')
-+ cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name,
-+ c_file_name]
-+ r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE,
-+ stderr=subprocess.STDOUT)
-+ return CompileResult(r.returncode, r.stdout)
-diff --git a/socket/Makefile b/socket/Makefile
-index 156eec6c85..2bde78387f 100644
---- a/socket/Makefile
-+++ b/socket/Makefile
-@@ -34,6 +34,7 @@ routines := accept bind connect getpeername getsockname getsockopt \
- tests := \
- tst-accept4 \
- tst-sockopt \
-+ tst-cmsghdr \
- # tests
-
- tests-internal := \
-diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c
-new file mode 100644
-index 0000000000..4c6898569b
---- /dev/null
-+++ b/socket/tst-cmsghdr-skeleton.c
-@@ -0,0 +1,92 @@
-+/* Test ancillary data header creation.
-+ Copyright (C) 2022 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/>. */
-+
-+/* We use the preprocessor to generate the function/macro tests instead of
-+ using indirection because having all the macro expansions alongside
-+ each other lets the compiler warn us about suspicious pointer
-+ arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions. */
-+
-+#include <stdint.h>
-+
-+#define RUN_TEST_CONCAT(suffix) run_test_##suffix
-+#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix)
-+
-+static void
-+RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void)
-+{
-+ struct msghdr m = {0};
-+ struct cmsghdr *cmsg;
-+ char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0};
-+
-+ m.msg_control = cmsgbuf;
-+ m.msg_controllen = sizeof (cmsgbuf);
-+
-+ /* First header should point to the start of the buffer. */
-+ cmsg = CMSG_FIRSTHDR (&m);
-+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
-+
-+ /* If the first header length consumes the entire buffer, there is no
-+ space remaining for additional headers. */
-+ cmsg->cmsg_len = sizeof (cmsgbuf);
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg == NULL);
-+
-+ /* The first header length is so big, using it would cause an overflow. */
-+ cmsg = CMSG_FIRSTHDR (&m);
-+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
-+ cmsg->cmsg_len = SIZE_MAX;
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg == NULL);
-+
-+ /* The first header leaves just enough space to hold another header. */
-+ cmsg = CMSG_FIRSTHDR (&m);
-+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
-+ cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr);
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg != NULL);
-+
-+ /* The first header leaves space but not enough for another header. */
-+ cmsg = CMSG_FIRSTHDR (&m);
-+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
-+ cmsg->cmsg_len ++;
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg == NULL);
-+
-+ /* The second header leaves just enough space to hold another header. */
-+ cmsg = CMSG_FIRSTHDR (&m);
-+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
-+ cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD));
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg != NULL);
-+ cmsg->cmsg_len = sizeof (cmsgbuf)
-+ - CMSG_SPACE (sizeof (PAYLOAD)) /* First header. */
-+ - sizeof (struct cmsghdr);
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg != NULL);
-+
-+ /* The second header leaves space but not enough for another header. */
-+ cmsg = CMSG_FIRSTHDR (&m);
-+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg != NULL);
-+ cmsg->cmsg_len ++;
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg == NULL);
-+
-+ return;
-+}
-diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c
-new file mode 100644
-index 0000000000..68c96d3c9d
---- /dev/null
-+++ b/socket/tst-cmsghdr.c
-@@ -0,0 +1,56 @@
-+/* Test ancillary data header creation.
-+ Copyright (C) 2022 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 <sys/socket.h>
-+#include <gnu/lib-names.h>
-+#include <support/xdlfcn.h>
-+#include <support/check.h>
-+
-+#define PAYLOAD "Hello, World!"
-+
-+/* CMSG_NXTHDR is a macro that calls an inline function defined in
-+ bits/socket.h. In case the function cannot be inlined, libc.so carries
-+ a copy. Both versions need to be tested. */
-+
-+#define CMSG_NXTHDR_IMPL CMSG_NXTHDR
-+#include "tst-cmsghdr-skeleton.c"
-+#undef CMSG_NXTHDR_IMPL
-+
-+static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *);
-+
-+#define CMSG_NXTHDR_IMPL cmsg_nxthdr
-+#include "tst-cmsghdr-skeleton.c"
-+#undef CMSG_NXTHDR_IMPL
-+
-+static int
-+do_test (void)
-+{
-+ static void *handle;
-+
-+ run_test_CMSG_NXTHDR ();
-+
-+ handle = xdlopen (LIBC_SO, RTLD_LAZY);
-+ cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *))
-+ xdlsym (handle, "__cmsg_nxthdr");
-+
-+ run_test_cmsg_nxthdr ();
-+
-+ return 0;
-+}
-+
-+#include <support/test-driver.c>
-diff --git a/sysdeps/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h
-index 5b35ea81ec..70fce4fb27 100644
---- a/sysdeps/mach/hurd/bits/socket.h
-+++ b/sysdeps/mach/hurd/bits/socket.h
-@@ -249,6 +249,12 @@ struct cmsghdr
- + CMSG_ALIGN (sizeof (struct cmsghdr)))
- #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
-
-+/* Given a length, return the additional padding necessary such that
-+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
-+#define __CMSG_PADDING(len) ((sizeof (size_t) \
-+ - ((len) & (sizeof (size_t) - 1))) \
-+ & (sizeof (size_t) - 1))
-+
- extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
- struct cmsghdr *__cmsg) __THROW;
- #ifdef __USE_EXTERN_INLINES
-@@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
- _EXTERN_INLINE struct cmsghdr *
- __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
- {
-+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
-+ __mhdr->msg_controllen because the user is required to obtain the first
-+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
-+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
-+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
-+ pointer arithmetic until we check its value. */
-+
-+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
-+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
-+
-+ size_t __size_needed = sizeof (struct cmsghdr)
-+ + __CMSG_PADDING (__cmsg->cmsg_len);
-+
-+ /* The current header is malformed, too small to be a full header. */
- if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
-- /* The kernel header does this so there may be a reason. */
- return (struct cmsghdr *) 0;
-
-+ /* There isn't enough space between __cmsg and the end of the buffer to
-+ hold the current cmsg *and* the next one. */
-+ if (((size_t)
-+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
-+ < __size_needed)
-+ || ((size_t)
-+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
-+ - __size_needed)
-+ < __cmsg->cmsg_len))
-+
-+ return (struct cmsghdr *) 0;
-+
-+ /* Now, we trust cmsg_len and can use it to find the next header. */
- __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
- + CMSG_ALIGN (__cmsg->cmsg_len));
-- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
-- + __mhdr->msg_controllen)
-- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
-- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
-- /* No more entries. */
-- return (struct cmsghdr *) 0;
- return __cmsg;
- }
- #endif /* Use `extern inline'. */
-diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
-index a139a16532..3ceda9fdbf 100644
---- a/sysdeps/unix/sysv/linux/Makefile
-+++ b/sysdeps/unix/sysv/linux/Makefile
-@@ -265,6 +265,14 @@ $(objpfx)tst-mount-consts.out: ../sysdeps/unix/sysv/linux/tst-mount-consts.py
- < /dev/null > $@ 2>&1; $(evaluate-test)
- $(objpfx)tst-mount-consts.out: $(sysdeps-linux-python-deps)
-
-+tests-special += $(objpfx)tst-mount-compile.out
-+$(objpfx)tst-mount-compile.out: ../sysdeps/unix/sysv/linux/tst-mount-compile.py
-+ $(sysdeps-linux-python) \
-+ ../sysdeps/unix/sysv/linux/tst-mount-compile.py \
-+ $(sysdeps-linux-python-cc) \
-+ < /dev/null > $@ 2>&1; $(evaluate-test)
-+$(objpfx)tst-mount-compile.out: $(sysdeps-linux-python-deps)
-+
- tst-rseq-disable-ENV = GLIBC_TUNABLES=glibc.pthread.rseq=0
-
- endif # $(subdir) == misc
-diff --git a/sysdeps/unix/sysv/linux/alpha/brk_call.h b/sysdeps/unix/sysv/linux/alpha/brk_call.h
-index b8088cf13f..0b851b6c86 100644
---- a/sysdeps/unix/sysv/linux/alpha/brk_call.h
-+++ b/sysdeps/unix/sysv/linux/alpha/brk_call.h
-@@ -21,8 +21,7 @@ __brk_call (void *addr)
- {
- unsigned long int result = INTERNAL_SYSCALL_CALL (brk, addr);
- if (result == -ENOMEM)
-- /* Mimic the default error reporting behavior. */
-- return addr;
-- else
-- return (void *) result;
-+ /* Mimic the generic error reporting behavior. */
-+ result = INTERNAL_SYSCALL_CALL (brk, 0);
-+ return (void *) result;
- }
-diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h
-index 4f1f810ea1..539b8d7716 100644
---- a/sysdeps/unix/sysv/linux/bits/socket.h
-+++ b/sysdeps/unix/sysv/linux/bits/socket.h
-@@ -307,6 +307,12 @@ struct cmsghdr
- + CMSG_ALIGN (sizeof (struct cmsghdr)))
- #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
-
-+/* Given a length, return the additional padding necessary such that
-+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
-+#define __CMSG_PADDING(len) ((sizeof (size_t) \
-+ - ((len) & (sizeof (size_t) - 1))) \
-+ & (sizeof (size_t) - 1))
-+
- extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
- struct cmsghdr *__cmsg) __THROW;
- #ifdef __USE_EXTERN_INLINES
-@@ -316,18 +322,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
- _EXTERN_INLINE struct cmsghdr *
- __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
- {
-+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
-+ __mhdr->msg_controllen because the user is required to obtain the first
-+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
-+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
-+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
-+ pointer arithmetic until we check its value. */
-+
-+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
-+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
-+
-+ size_t __size_needed = sizeof (struct cmsghdr)
-+ + __CMSG_PADDING (__cmsg->cmsg_len);
-+
-+ /* The current header is malformed, too small to be a full header. */
- if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
-- /* The kernel header does this so there may be a reason. */
- return (struct cmsghdr *) 0;
-
-+ /* There isn't enough space between __cmsg and the end of the buffer to
-+ hold the current cmsg *and* the next one. */
-+ if (((size_t)
-+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
-+ < __size_needed)
-+ || ((size_t)
-+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
-+ - __size_needed)
-+ < __cmsg->cmsg_len))
-+
-+ return (struct cmsghdr *) 0;
-+
-+ /* Now, we trust cmsg_len and can use it to find the next header. */
- __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
- + CMSG_ALIGN (__cmsg->cmsg_len));
-- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
-- + __mhdr->msg_controllen)
-- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
-- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
-- /* No more entries. */
-- return (struct cmsghdr *) 0;
- return __cmsg;
- }
- #endif /* Use `extern inline'. */
-diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
-index 15b7a3a925..24f72b797a 100644
---- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
-+++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
-@@ -23,18 +23,38 @@
- struct cmsghdr *
- __cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg)
- {
-+ /* We may safely assume that cmsg lies between mhdr->msg_control and
-+ mhdr->msg_controllen because the user is required to obtain the first
-+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
-+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
-+ trust the value of cmsg->cmsg_len and therefore do not use it in any
-+ pointer arithmetic until we check its value. */
-+
-+ unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control;
-+ unsigned char * cmsg_ptr = (unsigned char *) cmsg;
-+
-+ size_t size_needed = sizeof (struct cmsghdr)
-+ + __CMSG_PADDING (cmsg->cmsg_len);
-+
-+ /* The current header is malformed, too small to be a full header. */
- if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr))
-- /* The kernel header does this so there may be a reason. */
-- return NULL;
-+ return (struct cmsghdr *) 0;
-+
-+ /* There isn't enough space between cmsg and the end of the buffer to
-+ hold the current cmsg *and* the next one. */
-+ if (((size_t)
-+ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr)
-+ < size_needed)
-+ || ((size_t)
-+ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr
-+ - size_needed)
-+ < cmsg->cmsg_len))
-+
-+ return (struct cmsghdr *) 0;
-
-+ /* Now, we trust cmsg_len and can use it to find the next header. */
- cmsg = (struct cmsghdr *) ((unsigned char *) cmsg
- + CMSG_ALIGN (cmsg->cmsg_len));
-- if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control
-- + mhdr->msg_controllen)
-- || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len)
-- > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen)))
-- /* No more entries. */
-- return NULL;
- return cmsg;
- }
- libc_hidden_def (__cmsg_nxthdr)
-diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
-index bf4be80f8d..202520ee25 100644
---- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
-+++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
-@@ -122,6 +122,7 @@
- #define __NR_mbind 235
- #define __NR_membarrier 283
- #define __NR_memfd_create 279
-+#define __NR_memfd_secret 447
- #define __NR_migrate_pages 238
- #define __NR_mincore 232
- #define __NR_mkdirat 34
-diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
-index d656aedcc2..4e65f337d4 100644
---- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
-+++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
-@@ -127,6 +127,7 @@
- #define __NR_mbind 235
- #define __NR_membarrier 283
- #define __NR_memfd_create 279
-+#define __NR_memfd_secret 447
- #define __NR_migrate_pages 238
- #define __NR_mincore 232
- #define __NR_mkdirat 34
-diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h
-index f965986ba8..19841d0738 100644
---- a/sysdeps/unix/sysv/linux/sys/mount.h
-+++ b/sysdeps/unix/sysv/linux/sys/mount.h
-@@ -27,77 +27,113 @@
- #include <stddef.h>
- #include <sys/ioctl.h>
-
--#define BLOCK_SIZE 1024
-+#ifdef __has_include
-+# if __has_include ("linux/mount.h")
-+# include "linux/mount.h"
-+# endif
-+#endif
-+
-+
- #define BLOCK_SIZE_BITS 10
-+#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
-
-
- /* These are the fs-independent mount-flags: up to 16 flags are
- supported */
- enum
- {
-+#undef MS_RDONLY
- MS_RDONLY = 1, /* Mount read-only. */
- #define MS_RDONLY MS_RDONLY
-+#undef MS_NOSUID
- MS_NOSUID = 2, /* Ignore suid and sgid bits. */
- #define MS_NOSUID MS_NOSUID
-+#undef MS_NODEV
- MS_NODEV = 4, /* Disallow access to device special files. */
- #define MS_NODEV MS_NODEV
-+#undef MS_NOEXEC
- MS_NOEXEC = 8, /* Disallow program execution. */
- #define MS_NOEXEC MS_NOEXEC
-+#undef MS_SYNCHRONOUS
- MS_SYNCHRONOUS = 16, /* Writes are synced at once. */
- #define MS_SYNCHRONOUS MS_SYNCHRONOUS
-+#undef MS_REMOUNT
- MS_REMOUNT = 32, /* Alter flags of a mounted FS. */
- #define MS_REMOUNT MS_REMOUNT
-+#undef MS_MANDLOCK
- MS_MANDLOCK = 64, /* Allow mandatory locks on an FS. */
- #define MS_MANDLOCK MS_MANDLOCK
-+#undef MS_DIRSYNC
- MS_DIRSYNC = 128, /* Directory modifications are synchronous. */
- #define MS_DIRSYNC MS_DIRSYNC
-+#undef MS_NOSYMFOLLOW
- MS_NOSYMFOLLOW = 256, /* Do not follow symlinks. */
- #define MS_NOSYMFOLLOW MS_NOSYMFOLLOW
-+#undef MS_NOATIME
- MS_NOATIME = 1024, /* Do not update access times. */
- #define MS_NOATIME MS_NOATIME
-+#undef MS_NODIRATIME
- MS_NODIRATIME = 2048, /* Do not update directory access times. */
- #define MS_NODIRATIME MS_NODIRATIME
-+#undef MS_BIND
- MS_BIND = 4096, /* Bind directory at different place. */
- #define MS_BIND MS_BIND
-+#undef MS_MOVE
- MS_MOVE = 8192,
- #define MS_MOVE MS_MOVE
-+#undef MS_REC
- MS_REC = 16384,
- #define MS_REC MS_REC
-+#undef MS_SILENT
- MS_SILENT = 32768,
- #define MS_SILENT MS_SILENT
-+#undef MS_POSIXACL
- MS_POSIXACL = 1 << 16, /* VFS does not apply the umask. */
- #define MS_POSIXACL MS_POSIXACL
-+#undef MS_UNBINDABLE
- MS_UNBINDABLE = 1 << 17, /* Change to unbindable. */
- #define MS_UNBINDABLE MS_UNBINDABLE
-+#undef MS_PRIVATE
- MS_PRIVATE = 1 << 18, /* Change to private. */
- #define MS_PRIVATE MS_PRIVATE
-+#undef MS_SLAVE
- MS_SLAVE = 1 << 19, /* Change to slave. */
- #define MS_SLAVE MS_SLAVE
-+#undef MS_SHARED
- MS_SHARED = 1 << 20, /* Change to shared. */
- #define MS_SHARED MS_SHARED
-+#undef MS_RELATIME
- MS_RELATIME = 1 << 21, /* Update atime relative to mtime/ctime. */
- #define MS_RELATIME MS_RELATIME
-+#undef MS_KERNMOUNT
- MS_KERNMOUNT = 1 << 22, /* This is a kern_mount call. */
- #define MS_KERNMOUNT MS_KERNMOUNT
-+#undef MS_I_VERSION
- MS_I_VERSION = 1 << 23, /* Update inode I_version field. */
- #define MS_I_VERSION MS_I_VERSION
-+#undef MS_STRICTATIME
- MS_STRICTATIME = 1 << 24, /* Always perform atime updates. */
- #define MS_STRICTATIME MS_STRICTATIME
-+#undef MS_LAZYTIME
- MS_LAZYTIME = 1 << 25, /* Update the on-disk [acm]times lazily. */
- #define MS_LAZYTIME MS_LAZYTIME
-+#undef MS_ACTIVE
- MS_ACTIVE = 1 << 30,
- #define MS_ACTIVE MS_ACTIVE
-+#undef MS_NOUSER
- MS_NOUSER = 1 << 31
- #define MS_NOUSER MS_NOUSER
- };
-
- /* Flags that can be altered by MS_REMOUNT */
-+#undef MS_RMT_MASK
- #define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION \
- |MS_LAZYTIME)
-
-
- /* Magic mount flag number. Has to be or-ed to the flag values. */
-
-+#undef MS_MGC_VAL
- #define MS_MGC_VAL 0xc0ed0000 /* Magic flag number to indicate "new" flags */
- #define MS_MGC_MSK 0xffff0000 /* Magic flag number mask */
-
-@@ -106,20 +142,35 @@ enum
- is probably as bad and I don't want to create yet another include
- file. */
-
-+#undef BLKROSET
- #define BLKROSET _IO(0x12, 93) /* Set device read-only (0 = read-write). */
-+#undef BLKROGET
- #define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */
-+#undef BLKRRPART
- #define BLKRRPART _IO(0x12, 95) /* Re-read partition table. */
-+#undef BLKGETSIZE
- #define BLKGETSIZE _IO(0x12, 96) /* Return device size. */
-+#undef BLKFLSBUF
- #define BLKFLSBUF _IO(0x12, 97) /* Flush buffer cache. */
-+#undef BLKRASET
- #define BLKRASET _IO(0x12, 98) /* Set read ahead for block device. */
-+#undef BLKRAGET
- #define BLKRAGET _IO(0x12, 99) /* Get current read ahead setting. */
-+#undef BLKFRASET
- #define BLKFRASET _IO(0x12,100) /* Set filesystem read-ahead. */
-+#undef BLKFRAGET
- #define BLKFRAGET _IO(0x12,101) /* Get filesystem read-ahead. */
-+#undef BLKSECTSET
- #define BLKSECTSET _IO(0x12,102) /* Set max sectors per request. */
-+#undef BLKSECTGET
- #define BLKSECTGET _IO(0x12,103) /* Get max sectors per request. */
-+#undef BLKSSZGET
- #define BLKSSZGET _IO(0x12,104) /* Get block device sector size. */
-+#undef BLKBSZGET
- #define BLKBSZGET _IOR(0x12,112,size_t)
-+#undef BLKBSZSET
- #define BLKBSZSET _IOW(0x12,113,size_t)
-+#undef BLKGETSIZE64
- #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size. */
-
-
-@@ -137,9 +188,6 @@ enum
- };
-
-
--/* fsopen flags. */
--#define FSOPEN_CLOEXEC 0x00000001
--
- /* fsmount flags. */
- #define FSMOUNT_CLOEXEC 0x00000001
-
-@@ -157,6 +205,7 @@ enum
- #define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 /* Do not follow symlinks. */
-
-
-+#ifndef MOUNT_ATTR_SIZE_VER0
- /* For mount_setattr. */
- struct mount_attr
- {
-@@ -165,6 +214,7 @@ struct mount_attr
- uint64_t propagation;
- uint64_t userns_fd;
- };
-+#endif
-
- #define MOUNT_ATTR_SIZE_VER0 32 /* sizeof first published struct */
-
-@@ -185,26 +235,31 @@ struct mount_attr
- #define FSPICK_EMPTY_PATH 0x00000008
-
-
-+#ifndef FSOPEN_CLOEXEC
- /* The type of fsconfig call made. */
- enum fsconfig_command
- {
- FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */
--#define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
-+# define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
- FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */
--#define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
-+# define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
- FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */
--#define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
-+# define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
- FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */
--#define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
-+# define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
- FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */
--#define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
-+# define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
- FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */
--#define FSCONFIG_SET_FD FSCONFIG_SET_FD
-+# define FSCONFIG_SET_FD FSCONFIG_SET_FD
- FSCONFIG_CMD_CREATE = 6, /* Invoke superblock creation */
--#define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
-+# define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
- FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */
--#define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
-+# define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
- };
-+#endif
-+
-+/* fsopen flags. */
-+#define FSOPEN_CLOEXEC 0x00000001
-
- /* open_tree flags. */
- #define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
-diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
-index 6c7b2f7011..028ad3107a 100644
---- a/sysdeps/unix/sysv/linux/syscall-names.list
-+++ b/sysdeps/unix/sysv/linux/syscall-names.list
-@@ -21,8 +21,8 @@
- # This file can list all potential system calls. The names are only
- # used if the installed kernel headers also provide them.
-
--# The list of system calls is current as of Linux 5.18.
--kernel 5.18
-+# The list of system calls is current as of Linux 5.19.
-+kernel 5.19
-
- FAST_atomic_update
- FAST_cmpxchg
-diff --git a/sysdeps/unix/sysv/linux/tst-mount-compile.py b/sysdeps/unix/sysv/linux/tst-mount-compile.py
-new file mode 100755
-index 0000000000..0ec74d4e0b
---- /dev/null
-+++ b/sysdeps/unix/sysv/linux/tst-mount-compile.py
-@@ -0,0 +1,66 @@
-+#!/usr/bin/python3
-+# Check if glibc provided sys/mount.h can be used along related kernel
-+# headers.
-+# Copyright (C) 2022 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/>.
-+
-+import argparse
-+import sys
-+
-+import glibcextract
-+
-+
-+def main():
-+ """The main entry point."""
-+ parser = argparse.ArgumentParser(
-+ description='Check if glibc provided sys/mount.h can be '
-+ ' used along related kernel headers.')
-+ parser.add_argument('--cc', metavar='CC',
-+ help='C compiler (including options) to use')
-+ args = parser.parse_args()
-+
-+ if glibcextract.compile_c_snippet(
-+ '#include <linux/mount.h>',
-+ args.cc).returncode != 0:
-+ sys.exit (77)
-+
-+ def check(testname, snippet):
-+ # Add -Werror to catch macro redefinitions and _ISOMAC to avoid
-+ # internal glibc definitions.
-+ r = glibcextract.compile_c_snippet(snippet, args.cc,
-+ '-Werror -D_ISOMAC')
-+ if r.returncode != 0:
-+ print('error: test {}:\n{}'.format(testname, r.output.decode()))
-+ return r.returncode
-+
-+ status = max(
-+ check("sys/mount.h + linux/mount.h",
-+ "#include <sys/mount.h>\n"
-+ "#include <linux/mount.h>"),
-+ check("sys/mount.h + linux/fs.h",
-+ "#include <sys/mount.h>\n"
-+ "#include <linux/fs.h>"),
-+ check("linux/mount.h + sys/mount.h",
-+ "#include <linux/mount.h>\n"
-+ "#include <sys/mount.h>"),
-+ check("linux/fs.h + sys/mount.h",
-+ "#include <linux/fs.h>\n"
-+ "#include <sys/mount.h>"))
-+ sys.exit(status)
-+
-+if __name__ == '__main__':
-+ main()
-diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py
-index a62f803123..be2ef2daf1 100755
---- a/sysdeps/unix/sysv/linux/tst-mount-consts.py
-+++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py
-@@ -33,6 +33,11 @@ def main():
- help='C compiler (including options) to use')
- args = parser.parse_args()
-
-+ if glibcextract.compile_c_snippet(
-+ '#include <linux/mount.h>',
-+ args.cc).returncode != 0:
-+ sys.exit (77)
-+
- linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
- # Constants in glibc were updated to match Linux v5.16. When glibc
- # constants are updated this value should be updated to match the
-diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
-index 90cbb9be64..d732173abd 100644
---- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
-+++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
-@@ -33,11 +33,13 @@ def main():
- help='C compiler (including options) to use')
- args = parser.parse_args()
-
-- linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
-- # Linux started to provide pidfd.h with 5.10.
-- if linux_version_headers < (5, 10):
-+ if glibcextract.compile_c_snippet(
-+ '#include <linux/pidfd.h>',
-+ args.cc).returncode != 0:
- sys.exit (77)
-- linux_version_glibc = (5, 18)
-+
-+ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
-+ linux_version_glibc = (5, 19)
- sys.exit(glibcextract.compare_macro_consts(
- '#include <sys/pidfd.h>\n',
- '#include <asm/fcntl.h>\n'
-diff --git a/sysdeps/unix/sysv/linux/tst-pidfd.c b/sysdeps/unix/sysv/linux/tst-pidfd.c
-index 037af22290..5711d1c312 100644
---- a/sysdeps/unix/sysv/linux/tst-pidfd.c
-+++ b/sysdeps/unix/sysv/linux/tst-pidfd.c
-@@ -147,8 +147,11 @@ do_test (void)
- may be denied if the process doesn't have CAP_SYS_PTRACE or
- if a LSM security_ptrace_access_check denies access. */
- if (fd == -1 && errno == EPERM)
-- FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
-- "skipping test");
-+ {
-+ TEST_COMPARE (pidfd_send_signal (pidfd, SIGKILL, NULL, 0), 0);
-+ FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
-+ "skipping test");
-+ }
- TEST_VERIFY (fd > 0);
-
- char *path = xasprintf ("/proc/%d/fd/%d", pid, remote_fd);
-diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
-index e6b9e8743a..3d19d5556f 100644
---- a/wcsmbs/Makefile
-+++ b/wcsmbs/Makefile
-@@ -73,6 +73,8 @@ $(objpfx)tst-wcstol-locale.out: $(gen-locales)
- $(objpfx)tst-wcstod-nan-locale.out: $(gen-locales)
- $(objpfx)tst-c16-surrogate.out: $(gen-locales)
- $(objpfx)tst-c32-state.out: $(gen-locales)
-+$(objpfx)test-c8rtomb.out: $(gen-locales)
-+$(objpfx)test-mbrtoc8.out: $(gen-locales)
- endif
-
- $(objpfx)tst-wcstod-round: $(libm)
-diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
-index c37e8619a0..5f7139f279 100644
---- a/wcsmbs/uchar.h
-+++ b/wcsmbs/uchar.h
-@@ -34,8 +34,16 @@
- /* Declare the C2x char8_t typedef in C2x modes, but only if the C++
- __cpp_char8_t feature test macro is not defined. */
- #if __GLIBC_USE (ISOC2X) && !defined __cpp_char8_t
-+#if __GNUC_PREREQ (10, 0) && defined __cplusplus
-+/* Suppress the diagnostic regarding char8_t being a keyword in C++20. */
-+# pragma GCC diagnostic push
-+# pragma GCC diagnostic ignored "-Wc++20-compat"
-+#endif
- /* Define the 8-bit character type. */
- typedef unsigned char char8_t;
-+#if __GNUC_PREREQ (10, 0) && defined __cplusplus
-+# pragma GCC diagnostic pop
-+#endif
- #endif
-
- #ifndef __USE_ISOCXX11
-diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure
---- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:02:32.741186019 +1000
-+++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:03:05.314302356 +1000
-@@ -4,10 +4,10 @@
- test -n "$libc_cv_slibdir" ||
- case "$prefix" in
- /usr | /usr/)
-- libc_cv_slibdir='/lib64'
-- libc_cv_rtlddir='/lib64'
-+ libc_cv_slibdir='/lib'
-+ libc_cv_rtlddir='/lib'
- if test "$libdir" = '${exec_prefix}/lib'; then
-- libdir='${exec_prefix}/lib64';
-+ libdir='${exec_prefix}/lib';
- # Locale data can be shared between 32-bit and 64-bit libraries.
- libc_cv_complocaledir='${exec_prefix}/lib/locale'
- fi
-diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h
---- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:02:32.742186053 +1000
-+++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:03:05.314302356 +1000
-@@ -18,9 +18,9 @@
- #include <sysdeps/generic/ldconfig.h>
-
- #define SYSDEP_KNOWN_INTERPRETER_NAMES \
-- { "/lib/ld-linux.so.2", FLAG_ELF_LIBC6 }, \
-+ { "/lib32/ld-linux.so.2", FLAG_ELF_LIBC6 }, \
- { "/libx32/ld-linux-x32.so.2", FLAG_ELF_LIBC6 }, \
-- { "/lib64/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 },
-+ { "/lib/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 },
- #define SYSDEP_KNOWN_LIBRARY_NAMES \
- { "libc.so.6", FLAG_ELF_LIBC6 }, \
- { "libm.so.6", FLAG_ELF_LIBC6 },
diff --git a/glibc-32/glibc-2.36-2.patch b/glibc-32/glibc-2.36-2.patch
new file mode 100644
index 00000000..b810e453
--- /dev/null
+++ b/glibc-32/glibc-2.36-2.patch
@@ -0,0 +1,6002 @@
+diff --git a/NEWS b/NEWS
+index f61e521fc8..91bcfeb7a6 100644
+--- a/NEWS
++++ b/NEWS
+@@ -5,6 +5,31 @@ See the end for copying conditions.
+ Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
+ using `glibc' in the "product" field.
+
++Version 2.36.1
++
++Security related changes:
++
++ CVE-2022-39046: When the syslog function is passed a crafted input
++ string larger than 1024 bytes, it reads uninitialized memory from the
++ heap and prints it to the target log file, potentially revealing a
++ portion of the contents of the heap.
++
++The following bugs are resolved with this release:
++
++ [12154] Do not fail DNS resolution for CNAMEs which are not host names
++ [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning
++ [29305] Conserve NSS buffer space during DNS packet parsing
++ [29415] nscd: Fix netlink cache invalidation if epoll is used
++ [28937] New DSO dependency sorter does not put new map first if in a cycle
++ [29446] _dlopen now ignores dl_caller argument in static mode
++ [29485] Linux: Terminate subprocess on late failure in tst-pidfd
++ [29490] alpha: New __brk_call implementation is broken
++ [29528] elf: Call __libc_early_init for reused namespaces
++ [29537] libc: [2.34 regression]: Alignment issue on m68k when using
++ [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are
++ [29583] Use 64-bit interfaces in gconv_parseconfdir
++ [29638] libc: stdlib: arc4random fallback is never used
++
+ Version 2.36
+
+ Major new features:
+diff --git a/bits/socket.h b/bits/socket.h
+index 2b99dea33b..aac8c49b00 100644
+--- a/bits/socket.h
++++ b/bits/socket.h
+@@ -245,6 +245,12 @@ struct cmsghdr
+ + CMSG_ALIGN (sizeof (struct cmsghdr)))
+ #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
+
++/* Given a length, return the additional padding necessary such that
++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
++#define __CMSG_PADDING(len) ((sizeof (size_t) \
++ - ((len) & (sizeof (size_t) - 1))) \
++ & (sizeof (size_t) - 1))
++
+ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+ struct cmsghdr *__cmsg) __THROW;
+ #ifdef __USE_EXTERN_INLINES
+@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+ _EXTERN_INLINE struct cmsghdr *
+ __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
+ {
++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
++ __mhdr->msg_controllen because the user is required to obtain the first
++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
++ trust the value of __cmsg->cmsg_len and therefore do not use it in any
++ pointer arithmetic until we check its value. */
++
++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
++
++ size_t __size_needed = sizeof (struct cmsghdr)
++ + __CMSG_PADDING (__cmsg->cmsg_len);
++
++ /* The current header is malformed, too small to be a full header. */
+ if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
+- /* The kernel header does this so there may be a reason. */
+ return (struct cmsghdr *) 0;
+
++ /* There isn't enough space between __cmsg and the end of the buffer to
++ hold the current cmsg *and* the next one. */
++ if (((size_t)
++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
++ < __size_needed)
++ || ((size_t)
++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
++ - __size_needed)
++ < __cmsg->cmsg_len))
++
++ return (struct cmsghdr *) 0;
++
++ /* Now, we trust cmsg_len and can use it to find the next header. */
+ __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
+ + CMSG_ALIGN (__cmsg->cmsg_len));
+- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
+- + __mhdr->msg_controllen)
+- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
+- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
+- /* No more entries. */
+- return (struct cmsghdr *) 0;
+ return __cmsg;
+ }
+ #endif /* Use `extern inline'. */
+diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c
+index 2696dde4b1..9b07b4e132 100644
+--- a/dlfcn/dlopen.c
++++ b/dlfcn/dlopen.c
+@@ -90,7 +90,7 @@ compat_symbol (libdl, ___dlopen, dlopen, GLIBC_2_1);
+ void *
+ __dlopen (const char *file, int mode, void *dl_caller)
+ {
+- return dlopen_implementation (file, mode, RETURN_ADDRESS (0));
++ return dlopen_implementation (file, mode, dl_caller);
+ }
+
+ void *
+diff --git a/elf/Makefile b/elf/Makefile
+index fd77d0c7c8..72178d33ff 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -374,6 +374,8 @@ tests += \
+ tst-align \
+ tst-align2 \
+ tst-align3 \
++ tst-audit-tlsdesc \
++ tst-audit-tlsdesc-dlopen \
+ tst-audit1 \
+ tst-audit2 \
+ tst-audit8 \
+@@ -408,6 +410,7 @@ tests += \
+ tst-dlmopen4 \
+ tst-dlmopen-dlerror \
+ tst-dlmopen-gethostbyname \
++ tst-dlmopen-twice \
+ tst-dlopenfail \
+ tst-dlopenfail-2 \
+ tst-dlopenrpath \
+@@ -765,6 +768,8 @@ modules-names += \
+ tst-alignmod3 \
+ tst-array2dep \
+ tst-array5dep \
++ tst-audit-tlsdesc-mod1 \
++ tst-audit-tlsdesc-mod2 \
+ tst-audit11mod1 \
+ tst-audit11mod2 \
+ tst-audit12mod1 \
+@@ -798,6 +803,7 @@ modules-names += \
+ tst-auditmanymod7 \
+ tst-auditmanymod8 \
+ tst-auditmanymod9 \
++ tst-auditmod-tlsdesc \
+ tst-auditmod1 \
+ tst-auditmod9a \
+ tst-auditmod9b \
+@@ -834,6 +840,8 @@ modules-names += \
+ tst-dlmopen1mod \
+ tst-dlmopen-dlerror-mod \
+ tst-dlmopen-gethostbyname-mod \
++ tst-dlmopen-twice-mod1 \
++ tst-dlmopen-twice-mod2 \
+ tst-dlopenfaillinkmod \
+ tst-dlopenfailmod1 \
+ tst-dlopenfailmod2 \
+@@ -990,23 +998,8 @@ modules-names += tst-gnu2-tls1mod
+ $(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so
+ tst-gnu2-tls1mod.so-no-z-defs = yes
+ CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2
++endif # $(have-mtls-dialect-gnu2)
+
+-tests += tst-audit-tlsdesc tst-audit-tlsdesc-dlopen
+-modules-names += tst-audit-tlsdesc-mod1 tst-audit-tlsdesc-mod2 tst-auditmod-tlsdesc
+-$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
+- $(objpfx)tst-audit-tlsdesc-mod2.so \
+- $(shared-thread-library)
+-CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2
+-CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2
+-$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library)
+-$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \
+- $(objpfx)tst-audit-tlsdesc-mod2.so
+-$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so
+-$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
+-tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
+-$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
+-tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
+-endif
+ ifeq (yes,$(have-protected-data))
+ modules-names += tst-protected1moda tst-protected1modb
+ tests += tst-protected1a tst-protected1b
+@@ -2967,3 +2960,25 @@ $(objpfx)tst-tls-allocation-failure-static-patched.out: \
+ grep -q '^Fatal glibc error: Cannot allocate TLS block$$' $@ \
+ && grep -q '^status: 127$$' $@; \
+ $(evaluate-test)
++
++$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
++ $(objpfx)tst-audit-tlsdesc-mod2.so \
++ $(shared-thread-library)
++ifeq (yes,$(have-mtls-dialect-gnu2))
++# The test is valid for all TLS types, but we want to exercise GNU2
++# TLS if possible.
++CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2
++CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2
++endif
++$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library)
++$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \
++ $(objpfx)tst-audit-tlsdesc-mod2.so
++$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so
++$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
++tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
++$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
++tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
++
++$(objpfx)tst-dlmopen-twice.out: \
++ $(objpfx)tst-dlmopen-twice-mod1.so \
++ $(objpfx)tst-dlmopen-twice-mod2.so
+diff --git a/elf/dl-cache.c b/elf/dl-cache.c
+index 8bbf110d02..b97c17b3a9 100644
+--- a/elf/dl-cache.c
++++ b/elf/dl-cache.c
+@@ -509,8 +509,9 @@ _dl_load_cache_lookup (const char *name)
+ we are accessing. Therefore we must make the copy of the
+ mapping data without using malloc. */
+ char *temp;
+- temp = alloca (strlen (best) + 1);
+- strcpy (temp, best);
++ size_t best_len = strlen (best) + 1;
++ temp = alloca (best_len);
++ memcpy (temp, best, best_len);
+ return __strdup (temp);
+ }
+
+diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
+index 6f161f6ad5..92eb53790e 100644
+--- a/elf/dl-hwcaps.c
++++ b/elf/dl-hwcaps.c
+@@ -193,7 +193,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
+ /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix
+ and a "/" suffix once stored in the result. */
+ hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1;
+- size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
++ size_t hwcaps_sz = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
+ + hwcaps_counts.total_length);
+
+ /* Count the number of bits set in the masked value. */
+@@ -229,11 +229,12 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
+ assert (m == cnt);
+
+ /* Determine the total size of all strings together. */
++ size_t total;
+ if (cnt == 1)
+- total += temp[0].len + 1;
++ total = temp[0].len + 1;
+ else
+ {
+- total += temp[0].len + temp[cnt - 1].len + 2;
++ total = temp[0].len + temp[cnt - 1].len + 2;
+ if (cnt > 2)
+ {
+ total <<= 1;
+@@ -255,6 +256,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
+ /* This is the overall result, including both glibc-hwcaps
+ subdirectories and the legacy hwcaps subdirectories using the
+ power set construction. */
++ total += hwcaps_sz;
+ struct r_strlenpair *overall_result
+ = malloc (*sz * sizeof (*result) + total);
+ if (overall_result == NULL)
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index a23e65926b..46e8066fd8 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -844,11 +844,14 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
+ _dl_signal_error (EINVAL, file, NULL, N_("\
+ no more namespaces available for dlmopen()"));
+ }
+- else if (nsid == GL(dl_nns))
+- {
+- __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
+- ++GL(dl_nns);
+- }
++
++ if (nsid == GL(dl_nns))
++ ++GL(dl_nns);
++
++ /* Initialize the new namespace. Most members are
++ zero-initialized, only the lock needs special treatment. */
++ memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid]));
++ __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
+
+ _dl_debug_update (nsid)->r_state = RT_CONSISTENT;
+ }
+diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
+index 96638d7ed1..3e2a6a584e 100644
+--- a/elf/dl-sort-maps.c
++++ b/elf/dl-sort-maps.c
+@@ -27,12 +27,12 @@
+ If FOR_FINI is true, this is called for finishing an object. */
+ static void
+ _dl_sort_maps_original (struct link_map **maps, unsigned int nmaps,
+- unsigned int skip, bool for_fini)
++ bool force_first, bool for_fini)
+ {
+ /* Allows caller to do the common optimization of skipping the first map,
+ usually the main binary. */
+- maps += skip;
+- nmaps -= skip;
++ maps += force_first;
++ nmaps -= force_first;
+
+ /* A list of one element need not be sorted. */
+ if (nmaps <= 1)
+@@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map,
+
+ static void
+ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
+- unsigned int skip __attribute__ ((unused)), bool for_fini)
++ bool force_first, bool for_fini)
+ {
++ struct link_map *first_map = maps[0];
+ for (int i = nmaps - 1; i >= 0; i--)
+ maps[i]->l_visited = 0;
+
+@@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
+ Adjusting the order so that maps[0] is last traversed naturally avoids
+ this problem.
+
+- Further, the old "optimization" of skipping the main object at maps[0]
+- from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general
+- no longer valid, since traversing along object dependency-links
+- may "find" the main object even when it is not included in the initial
+- order (e.g. a dlopen()'ed shared object can have circular dependencies
+- linked back to itself). In such a case, traversing N-1 objects will
+- create a N-object result, and raise problems.
+-
+ To summarize, just passing in the full list, and iterating from back
+ to front makes things much more straightforward. */
+
+@@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
+ }
+
+ memcpy (maps, rpo, sizeof (struct link_map *) * nmaps);
++
++ /* Skipping the first object at maps[0] is not valid in general,
++ since traversing along object dependency-links may "find" that
++ first object even when it is not included in the initial order
++ (e.g., a dlopen'ed shared object can have circular dependencies
++ linked back to itself). In such a case, traversing N-1 objects
++ will create a N-object result, and raise problems. Instead,
++ force the object back into first place after sorting. This naive
++ approach may introduce further dependency ordering violations
++ compared to rotating the cycle until the first map is again in
++ the first position, but as there is a cycle, at least one
++ violation is already present. */
++ if (force_first && maps[0] != first_map)
++ {
++ int i;
++ for (i = 0; maps[i] != first_map; ++i)
++ ;
++ assert (i < nmaps);
++ memmove (&maps[1], maps, i * sizeof (maps[0]));
++ maps[0] = first_map;
++ }
+ }
+
+ void
+@@ -286,7 +300,7 @@ _dl_sort_maps_init (void)
+
+ void
+ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
+- unsigned int skip, bool for_fini)
++ bool force_first, bool for_fini)
+ {
+ /* It can be tempting to use a static function pointer to store and call
+ the current selected sorting algorithm routine, but experimentation
+@@ -296,9 +310,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
+ input cases. A simple if-case with direct function calls appears to
+ be the fastest. */
+ if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
+- _dl_sort_maps_original (maps, nmaps, skip, for_fini);
++ _dl_sort_maps_original (maps, nmaps, force_first, for_fini);
+ else
+- _dl_sort_maps_dfs (maps, nmaps, skip, for_fini);
++ _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini);
+ }
+
+ #endif /* HAVE_TUNABLES. */
+diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def
+index 5f7f18ef27..4bf9052db1 100644
+--- a/elf/dso-sort-tests-1.def
++++ b/elf/dso-sort-tests-1.def
+@@ -64,3 +64,10 @@ output: b>a>{}<a<b
+ tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c
+ output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
+ output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
++
++# Test that even in the presence of dependency loops involving dlopen'ed
++# object, that object is initialized last (and not unloaded prematurely).
++# Final destructor order is indeterminate due to the cycle.
++tst-bz28937: {+a;+b;-b;+c;%c};a->a1;a->a2;a2->a;b->b1;c->a1;c=>a1
++output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a<a2<c<a1
++output(glibc.rtld.dynamic_sort=2): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a2<a<c<a1
+diff --git a/elf/rtld.c b/elf/rtld.c
+index cbbaf4a331..3e771a93d8 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -2122,6 +2122,12 @@ dl_main (const ElfW(Phdr) *phdr,
+ if (l->l_faked)
+ /* The library was not found. */
+ _dl_printf ("\t%s => not found\n", l->l_libname->name);
++ else if (strcmp (l->l_libname->name, l->l_name) == 0)
++ /* Print vDSO like libraries without duplicate name. Some
++ consumers depend of this format. */
++ _dl_printf ("\t%s (0x%0*Zx)\n", l->l_libname->name,
++ (int) sizeof l->l_map_start * 2,
++ (size_t) l->l_map_start);
+ else
+ _dl_printf ("\t%s => %s (0x%0*Zx)\n",
+ DSO_FILENAME (l->l_libname->name),
+diff --git a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c
+new file mode 100644
+index 0000000000..0eaf04948c
+--- /dev/null
++++ b/elf/tst-dlmopen-twice-mod1.c
+@@ -0,0 +1,37 @@
++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 1.
++ Copyright (C) 2022 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 <stdio.h>
++
++static void __attribute__ ((constructor))
++init (void)
++{
++ puts ("info: tst-dlmopen-twice-mod1.so loaded");
++ fflush (stdout);
++}
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++ puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded");
++ fflush (stdout);
++}
++
++/* Large allocation. The second module does not have this, so it
++ should load libc at a different address. */
++char large_allocate[16 * 1024 * 1024];
+diff --git a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c
+new file mode 100644
+index 0000000000..40c6c01f96
+--- /dev/null
++++ b/elf/tst-dlmopen-twice-mod2.c
+@@ -0,0 +1,50 @@
++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 2.
++ Copyright (C) 2022 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 <ctype.h>
++#include <stdio.h>
++
++static void __attribute__ ((constructor))
++init (void)
++{
++ puts ("info: tst-dlmopen-twice-mod2.so loaded");
++ fflush (stdout);
++}
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++ puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded");
++ fflush (stdout);
++}
++
++int
++run_check (void)
++{
++ puts ("info: about to call isalpha");
++ fflush (stdout);
++
++ volatile char ch = 'a';
++ if (!isalpha (ch))
++ {
++ puts ("error: isalpha ('a') is not true");
++ fflush (stdout);
++ return 1;
++ }
++ return 0;
++}
+diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c
+new file mode 100644
+index 0000000000..449f3c8fa9
+--- /dev/null
++++ b/elf/tst-dlmopen-twice.c
+@@ -0,0 +1,34 @@
++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Main.
++ Copyright (C) 2022 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 <support/xdlfcn.h>
++#include <support/check.h>
++
++static int
++do_test (void)
++{
++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", RTLD_NOW);
++ xdlclose (handle);
++ handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW);
++ int (*run_check) (void) = xdlsym (handle, "run_check");
++ TEST_COMPARE (run_check (), 0);
++ xdlclose (handle);
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
+index debb96b322..b72933b526 100644
+--- a/iconv/gconv_parseconfdir.h
++++ b/iconv/gconv_parseconfdir.h
+@@ -29,14 +29,14 @@
+ # define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr)
+ # define asprintf __asprintf
+ # define opendir __opendir
+-# define readdir __readdir
++# define readdir64 __readdir64
+ # define closedir __closedir
+ # define mempcpy __mempcpy
+-# define struct_stat struct __stat64_t64
+-# define lstat __lstat64_time64
++# define struct_stat64 struct __stat64_t64
++# define lstat64 __lstat64_time64
+ # define feof_unlocked __feof_unlocked
+ #else
+-# define struct_stat struct stat
++# define struct_stat64 struct stat64
+ #endif
+
+ /* Name of the file containing the module information in the directories
+@@ -148,8 +148,8 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
+ DIR *confdir = opendir (buf);
+ if (confdir != NULL)
+ {
+- struct dirent *ent;
+- while ((ent = readdir (confdir)) != NULL)
++ struct dirent64 *ent;
++ while ((ent = readdir64 (confdir)) != NULL)
+ {
+ if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN)
+ continue;
+@@ -161,12 +161,12 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
+ && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
+ {
+ char *conf;
+- struct_stat st;
++ struct_stat64 st;
+ if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
+ continue;
+
+ if (ent->d_type != DT_UNKNOWN
+- || (lstat (conf, &st) != -1 && S_ISREG (st.st_mode)))
++ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode)))
+ found |= read_conf_file (conf, dir, dir_len);
+
+ free (conf);
+diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h
+index 53f1dbc7c3..c27e7886b7 100644
+--- a/include/arpa/nameser.h
++++ b/include/arpa/nameser.h
+@@ -55,6 +55,12 @@ int __ns_name_ntop (const unsigned char *, char *, size_t) __THROW;
+ int __ns_name_unpack (const unsigned char *, const unsigned char *,
+ const unsigned char *, unsigned char *, size_t) __THROW;
+
++/* Like ns_samename, but for uncompressed binary names. Return true
++ if the two arguments compare are equal as case-insensitive domain
++ names. */
++_Bool __ns_samebinaryname (const unsigned char *, const unsigned char *)
++ attribute_hidden;
++
+ #define ns_msg_getflag(handle, flag) \
+ (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift)
+
+@@ -89,5 +95,105 @@ libc_hidden_proto (__ns_name_unpack)
+ extern __typeof (ns_samename) __libc_ns_samename;
+ libc_hidden_proto (__libc_ns_samename)
+
++/* Packet parser helper functions. */
++
++/* Verify that P points to an uncompressed domain name in wire format.
++ On success, return the length of the encoded name, including the
++ terminating null byte. On failure, return -1 and set errno. EOM
++ must point one past the last byte in the packet. */
++int __ns_name_length_uncompressed (const unsigned char *p,
++ const unsigned char *eom) attribute_hidden;
++
++/* Iterator over the resource records in a DNS packet. */
++struct ns_rr_cursor
++{
++ /* These members are not changed after initialization. */
++ const unsigned char *begin; /* First byte of packet. */
++ const unsigned char *end; /* One past the last byte of the packet. */
++ const unsigned char *first_rr; /* First resource record (or packet end). */
++
++ /* Advanced towards the end while reading the packet. */
++ const unsigned char *current;
++};
++
++/* Returns the RCODE field from the DNS header. */
++static inline int
++ns_rr_cursor_rcode (const struct ns_rr_cursor *c)
++{
++ return c->begin[3] & 0x0f; /* Lower 4 bits at offset 3. */
++}
++
++/* Returns the length of the answer section according to the DNS header. */
++static inline int
++ns_rr_cursor_ancount (const struct ns_rr_cursor *c)
++{
++ return c->begin[6] * 256 + c->begin[7]; /* 16 bits at offset 6. */
++}
++
++/* Returns the length of the authority (name server) section according
++ to the DNS header. */
++static inline int
++ns_rr_cursor_nscount (const struct ns_rr_cursor *c)
++{
++ return c->begin[8] * 256 + c->begin[9]; /* 16 bits at offset 8. */
++}
++
++/* Returns the length of the additional data section according to the
++ DNS header. */
++static inline int
++ns_rr_cursor_adcount (const struct ns_rr_cursor *c)
++{
++ return c->begin[10] * 256 + c->begin[11]; /* 16 bits at offset 10. */
++}
++
++/* Returns a pointer to the uncompressed question name in wire
++ format. */
++static inline const unsigned char *
++ns_rr_cursor_qname (const struct ns_rr_cursor *c)
++{
++ return c->begin + 12; /* QNAME starts right after the header. */
++}
++
++/* Returns the question type of the first and only question. */
++static inline const int
++ns_rr_cursor_qtype (const struct ns_rr_cursor *c)
++{
++ /* 16 bits 4 bytes back from the first RR header start. */
++ return c->first_rr[-4] * 256 + c->first_rr[-3];
++}
++
++/* Returns the clss of the first and only question (usally C_IN). */
++static inline const int
++ns_rr_cursor_qclass (const struct ns_rr_cursor *c)
++{
++ /* 16 bits 2 bytes back from the first RR header start. */
++ return c->first_rr[-2] * 256 + c->first_rr[-1];
++}
++
++/* Initializes *C to cover the packet [BUF, BUF+LEN). Returns false
++ if LEN is less than sizeof (*HD), if the packet does not contain a
++ full (uncompressed) question, or if the question count is not 1. */
++_Bool __ns_rr_cursor_init (struct ns_rr_cursor *c,
++ const unsigned char *buf, size_t len)
++ attribute_hidden;
++
++/* Like ns_rr, but the record owner name is not decoded into text format. */
++struct ns_rr_wire
++{
++ unsigned char rname[NS_MAXCDNAME]; /* Owner name of the record. */
++ uint16_t rtype; /* Resource record type (T_*). */
++ uint16_t rclass; /* Resource record class (C_*). */
++ uint32_t ttl; /* Time-to-live field. */
++ const unsigned char *rdata; /* Start of resource record data. */
++ uint16_t rdlength; /* Length of the data at rdata, in bytes. */
++};
++
++/* Attempts to parse the record at C into *RR. On success, return
++ true, and C is advanced past the record, and RR->rdata points to
++ the record data. On failure, errno is set to EMSGSIZE, and false
++ is returned. */
++_Bool __ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr)
++ attribute_hidden;
++
+ # endif /* !_ISOMAC */
+ #endif
+diff --git a/include/bits/wchar2-decl.h b/include/bits/wchar2-decl.h
+new file mode 100644
+index 0000000000..00b1b93342
+--- /dev/null
++++ b/include/bits/wchar2-decl.h
+@@ -0,0 +1 @@
++#include <wcsmbs/bits/wchar2-decl.h>
+diff --git a/include/resolv.h b/include/resolv.h
+index 3590b6f496..4dbbac3800 100644
+--- a/include/resolv.h
++++ b/include/resolv.h
+@@ -70,5 +70,8 @@ libc_hidden_proto (__libc_res_nameinquery)
+ extern __typeof (__res_queriesmatch) __libc_res_queriesmatch;
+ libc_hidden_proto (__libc_res_queriesmatch)
+
++/* Variant of res_hnok which operates on binary (but uncompressed) names. */
++bool __res_binary_hnok (const unsigned char *dn) attribute_hidden;
++
+ # endif /* _RESOLV_H_ && !_ISOMAC */
+ #endif
+diff --git a/misc/syslog.c b/misc/syslog.c
+index 554089bfc4..f67d4b58a4 100644
+--- a/misc/syslog.c
++++ b/misc/syslog.c
+@@ -167,7 +167,7 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
+ _nl_C_locobj_ptr);
+
+ #define SYSLOG_HEADER(__pri, __timestamp, __msgoff, pid) \
+- "<%d>%s %n%s%s%.0d%s: ", \
++ "<%d>%s%n%s%s%.0d%s: ", \
+ __pri, __timestamp, __msgoff, \
+ LogTag == NULL ? __progname : LogTag, \
+ "[" + (pid == 0), pid, "]" + (pid == 0)
+@@ -193,28 +193,32 @@ __vsyslog_internal (int pri, const char *fmt, va_list 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;
+- }
++ buf = bufs;
++ bufsize = l + vl;
+
+ va_end (apc);
+ }
+
+ if (buf == NULL)
+ {
+- buf = malloc (l * sizeof (char));
++ buf = malloc ((bufsize + 1) * sizeof (char));
+ if (buf != NULL)
+ {
+ /* Tell the cancellation handler to free this buffer. */
+ clarg.buf = buf;
+
+ if (has_ts)
+- __snprintf (bufs, sizeof bufs,
++ __snprintf (buf, l + 1,
+ SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
+ else
+- __snprintf (bufs, sizeof bufs,
++ __snprintf (buf, l + 1,
+ SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
++
++ va_list apc;
++ va_copy (apc, ap);
++ __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc,
++ mode_flags);
++ va_end (apc);
+ }
+ else
+ {
+diff --git a/misc/tst-syslog.c b/misc/tst-syslog.c
+index e550d15796..3560b518a2 100644
+--- a/misc/tst-syslog.c
++++ b/misc/tst-syslog.c
+@@ -68,21 +68,19 @@ static const int priorities[] =
+ LOG_DEBUG
+ };
+
+-enum
+- {
+- ident_length = 64,
+- msg_length = 64
+- };
++#define IDENT_LENGTH 64
++#define MSG_LENGTH 1024
+
+ #define SYSLOG_MSG_BASE "syslog_message"
+ #define OPENLOG_IDENT "openlog_ident"
++static char large_message[MSG_LENGTH];
+
+ struct msg_t
+ {
+ int priority;
+ int facility;
+- char ident[ident_length];
+- char msg[msg_length];
++ char ident[IDENT_LENGTH];
++ char msg[MSG_LENGTH];
+ pid_t pid;
+ };
+
+@@ -147,6 +145,37 @@ check_syslog_message (const struct msg_t *msg, int msgnum, int options,
+ return true;
+ }
+
++static void
++send_syslog_large (int options)
++{
++ int facility = LOG_USER;
++ int priority = LOG_INFO;
++
++ syslog (facility | priority, "%s %d %d", large_message, facility,
++ priority);
++}
++
++static void
++send_vsyslog_large (int options)
++{
++ int facility = LOG_USER;
++ int priority = LOG_INFO;
++
++ call_vsyslog (facility | priority, "%s %d %d", large_message, facility,
++ priority);
++}
++
++static bool
++check_syslog_message_large (const struct msg_t *msg, int msgnum, int options,
++ pid_t pid)
++{
++ TEST_COMPARE (msg->facility, LOG_USER);
++ TEST_COMPARE (msg->priority, LOG_INFO);
++ TEST_COMPARE_STRING (msg->msg, large_message);
++
++ return false;
++}
++
+ static void
+ send_openlog (int options)
+ {
+@@ -179,6 +208,17 @@ send_openlog (int options)
+ closelog ();
+ }
+
++static void
++send_openlog_large (int options)
++{
++ /* Define a non-default IDENT and a not default facility. */
++ openlog (OPENLOG_IDENT, options, LOG_LOCAL0);
++
++ syslog (LOG_INFO, "%s %d %d", large_message, LOG_LOCAL0, LOG_INFO);
++
++ closelog ();
++}
++
+ static bool
+ check_openlog_message (const struct msg_t *msg, int msgnum,
+ int options, pid_t pid)
+@@ -189,7 +229,7 @@ check_openlog_message (const struct msg_t *msg, int msgnum,
+ int expected_priority = priorities[msgnum % array_length (priorities)];
+ TEST_COMPARE (msg->priority, expected_priority);
+
+- char expected_ident[ident_length];
++ char expected_ident[IDENT_LENGTH];
+ snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:",
+ OPENLOG_IDENT,
+ options & LOG_PID ? "[" : "",
+@@ -211,17 +251,43 @@ check_openlog_message (const struct msg_t *msg, int msgnum,
+ return true;
+ }
+
++static bool
++check_openlog_message_large (const struct msg_t *msg, int msgnum,
++ int options, pid_t pid)
++{
++ char expected_ident[IDENT_LENGTH];
++ snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:",
++ OPENLOG_IDENT,
++ options & LOG_PID ? "[" : "",
++ options & LOG_PID ? pid : 0,
++ options & LOG_PID ? "]" : "");
++
++ TEST_COMPARE_STRING (msg->ident, expected_ident);
++ TEST_COMPARE_STRING (msg->msg, large_message);
++ TEST_COMPARE (msg->priority, LOG_INFO);
++ TEST_COMPARE (msg->facility, LOG_LOCAL0);
++
++ return false;
++}
++
+ static struct msg_t
+ parse_syslog_msg (const char *msg)
+ {
+ struct msg_t r = { .pid = -1 };
+ int number;
++ int wsb, wsa;
++
++#define STRINPUT(size) XSTRINPUT(size)
++#define XSTRINPUT(size) "%" # size "s"
+
+ /* The message in the form:
+- <179>Apr 8 14:51:19 tst-syslog: syslog message 176 3 */
+- int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d %32s %64s %*d %*d",
+- &number, r.ident, r.msg);
++ <179>Apr 8 14:51:19 tst-syslog: message 176 3 */
++ int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d%n %n" STRINPUT(IDENT_LENGTH)
++ " " STRINPUT(MSG_LENGTH) " %*d %*d",
++ &number, &wsb, &wsa, r.ident, r.msg);
+ TEST_COMPARE (n, 3);
++ /* It should only one space between timestamp and message. */
++ TEST_COMPARE (wsa - wsb, 1);
+
+ r.facility = number & LOG_FACMASK;
+ r.priority = number & LOG_PRIMASK;
+@@ -246,7 +312,7 @@ parse_syslog_console (const char *msg)
+
+ /* The message in the form:
+ openlog_ident: syslog_message 128 0 */
+- int n = sscanf (msg, "%32s %64s %d %d",
++ int n = sscanf (msg, STRINPUT(IDENT_LENGTH) " " STRINPUT(MSG_LENGTH) " %d %d",
+ r.ident, r.msg, &facility, &priority);
+ TEST_COMPARE (n, 4);
+
+@@ -281,7 +347,7 @@ check_syslog_udp (void (*syslog_send)(int), int options,
+ int msgnum = 0;
+ while (1)
+ {
+- char buf[512];
++ char buf[2048];
+ size_t l = xrecvfrom (server_udp, buf, sizeof (buf), 0,
+ (struct sockaddr *) &addr, &addrlen);
+ buf[l] = '\0';
+@@ -325,7 +391,7 @@ check_syslog_tcp (void (*syslog_send)(int), int options,
+
+ int client_tcp = xaccept (server_tcp, NULL, NULL);
+
+- char buf[512], *rb = buf;
++ char buf[2048], *rb = buf;
+ size_t rbl = sizeof (buf);
+ size_t prl = 0; /* Track the size of the partial record. */
+ int msgnum = 0;
+@@ -393,20 +459,34 @@ check_syslog_console_read (FILE *fp)
+ }
+
+ static void
+-check_syslog_console (void)
++check_syslog_console_read_large (FILE *fp)
++{
++ char buf[2048];
++ TEST_VERIFY (fgets (buf, sizeof (buf), fp) != NULL);
++ struct msg_t msg = parse_syslog_console (buf);
++
++ TEST_COMPARE_STRING (msg.ident, OPENLOG_IDENT ":");
++ TEST_COMPARE_STRING (msg.msg, large_message);
++ TEST_COMPARE (msg.priority, LOG_INFO);
++ TEST_COMPARE (msg.facility, LOG_LOCAL0);
++}
++
++static void
++check_syslog_console (void (*syslog_send)(int),
++ void (*syslog_check)(FILE *fp))
+ {
+ xmkfifo (_PATH_CONSOLE, 0666);
+
+ pid_t sender_pid = xfork ();
+ if (sender_pid == 0)
+ {
+- send_openlog (LOG_CONS);
++ syslog_send (LOG_CONS);
+ _exit (0);
+ }
+
+ {
+ FILE *fp = xfopen (_PATH_CONSOLE, "r+");
+- check_syslog_console_read (fp);
++ syslog_check (fp);
+ xfclose (fp);
+ }
+
+@@ -425,16 +505,28 @@ send_openlog_callback (void *clousure)
+ }
+
+ static void
+-check_syslog_perror (void)
++send_openlog_callback_large (void *clousure)
++{
++ int options = *(int *) clousure;
++ send_openlog_large (options);
++}
++
++static void
++check_syslog_perror (bool large)
+ {
+ struct support_capture_subprocess result;
+- result = support_capture_subprocess (send_openlog_callback,
++ result = support_capture_subprocess (large
++ ? send_openlog_callback_large
++ : send_openlog_callback,
+ &(int){LOG_PERROR});
+
+ FILE *mfp = fmemopen (result.err.buffer, result.err.length, "r");
+ if (mfp == NULL)
+ FAIL_EXIT1 ("fmemopen: %m");
+- check_syslog_console_read (mfp);
++ if (large)
++ check_syslog_console_read_large (mfp);
++ else
++ check_syslog_console_read (mfp);
+ xfclose (mfp);
+
+ support_capture_subprocess_check (&result, "tst-openlog-child", 0,
+@@ -462,10 +554,31 @@ do_test (void)
+ check_syslog_tcp (send_openlog, LOG_PID, check_openlog_message);
+
+ /* Check the LOG_CONS option. */
+- check_syslog_console ();
++ check_syslog_console (send_openlog, check_syslog_console_read);
+
+ /* Check the LOG_PERROR option. */
+- check_syslog_perror ();
++ check_syslog_perror (false);
++
++ /* Similar tests as before, but with a large message to trigger the
++ syslog path that uses dynamically allocated memory. */
++ memset (large_message, 'a', sizeof large_message - 1);
++ large_message[sizeof large_message - 1] = '\0';
++
++ check_syslog_udp (send_syslog_large, 0, check_syslog_message_large);
++ check_syslog_tcp (send_syslog_large, 0, check_syslog_message_large);
++
++ check_syslog_udp (send_vsyslog_large, 0, check_syslog_message_large);
++ check_syslog_tcp (send_vsyslog_large, 0, check_syslog_message_large);
++
++ check_syslog_udp (send_openlog_large, 0, check_openlog_message_large);
++ check_syslog_tcp (send_openlog_large, 0, check_openlog_message_large);
++
++ check_syslog_udp (send_openlog_large, LOG_PID, check_openlog_message_large);
++ check_syslog_tcp (send_openlog_large, LOG_PID, check_openlog_message_large);
++
++ check_syslog_console (send_openlog_large, check_syslog_console_read_large);
++
++ check_syslog_perror (true);
+
+ return 0;
+ }
+diff --git a/nscd/connections.c b/nscd/connections.c
+index 61d1674eb4..531d2e83df 100644
+--- a/nscd/connections.c
++++ b/nscd/connections.c
+@@ -2284,7 +2284,8 @@ main_loop_epoll (int efd)
+ sizeof (buf))) != -1)
+ ;
+
+- __bump_nl_timestamp ();
++ dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP]
++ = __bump_nl_timestamp ();
+ }
+ # endif
+ else
+diff --git a/resolv/Makefile b/resolv/Makefile
+index 5b15321f9b..f8a92c6cff 100644
+--- a/resolv/Makefile
++++ b/resolv/Makefile
+@@ -40,12 +40,16 @@ routines := \
+ inet_pton \
+ ns_makecanon \
+ ns_name_compress \
++ ns_name_length_uncompressed \
+ ns_name_ntop \
+ ns_name_pack \
+ ns_name_pton \
+ ns_name_skip \
+ ns_name_uncompress \
+ ns_name_unpack \
++ ns_rr_cursor_init \
++ ns_rr_cursor_next \
++ ns_samebinaryname \
+ ns_samename \
+ nsap_addr \
+ nss_dns_functions \
+@@ -89,9 +93,12 @@ tests += \
+ tst-ns_name_pton \
+ tst-res_hconf_reorder \
+ tst-res_hnok \
++ tst-resolv-aliases \
+ tst-resolv-basic \
+ tst-resolv-binary \
++ tst-resolv-byaddr \
+ tst-resolv-edns \
++ tst-resolv-invalid-cname \
+ tst-resolv-network \
+ tst-resolv-noaaaa \
+ tst-resolv-nondecimal \
+@@ -104,6 +111,18 @@ tests += \
+ tests-internal += tst-resolv-txnid-collision
+ tests-static += tst-resolv-txnid-collision
+
++# Likewise for __ns_samebinaryname.
++tests-internal += tst-ns_samebinaryname
++tests-static += tst-ns_samebinaryname
++
++# Likewise for __ns_name_length_uncompressed.
++tests-internal += tst-ns_name_length_uncompressed
++tests-static += tst-ns_name_length_uncompressed
++
++# Likewise for struct ns_rr_cursor and its functions.
++tests-internal += tst-ns_rr_cursor
++tests-static += tst-ns_rr_cursor
++
+ # These tests need libdl.
+ ifeq (yes,$(build-shared))
+ tests += \
+@@ -258,8 +277,10 @@ $(objpfx)tst-resolv-ai_idn.out: $(gen-locales)
+ $(objpfx)tst-resolv-ai_idn-latin1.out: $(gen-locales)
+ $(objpfx)tst-resolv-ai_idn-nolibidn2.out: \
+ $(gen-locales) $(objpfx)tst-no-libidn2.so
++$(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library)
++$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so
+@@ -267,6 +288,8 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \
+ $(shared-thread-library)
+ $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \
+ $(shared-thread-library)
++$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \
++ $(shared-thread-library)
+ $(objpfx)tst-resolv-noaaaa: $(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)
+diff --git a/resolv/README b/resolv/README
+index 514e9bb617..2146bc3b27 100644
+--- a/resolv/README
++++ b/resolv/README
+@@ -146,6 +146,3 @@ res_libc.c is home-brewn, although parts of it are taken from res_data.c.
+
+ res_hconf.c and res_hconf.h were contributed by David Mosberger, and
+ do not come from BIND.
+-
+-The files gethnamaddr.c, mapv4v6addr.h and mapv4v6hostent.h are
+-leftovers from BIND 4.9.7.
+diff --git a/resolv/mapv4v6addr.h b/resolv/mapv4v6addr.h
+deleted file mode 100644
+index 7f85f7d5e3..0000000000
+--- a/resolv/mapv4v6addr.h
++++ /dev/null
+@@ -1,69 +0,0 @@
+-/*
+- * ++Copyright++ 1985, 1988, 1993
+- * -
+- * Copyright (c) 1985, 1988, 1993
+- * The Regents of the University of California. All rights reserved.
+- *
+- * Redistribution and use in source and binary forms, with or without
+- * modification, are permitted provided that the following conditions
+- * are met:
+- * 1. Redistributions of source code must retain the above copyright
+- * notice, this list of conditions and the following disclaimer.
+- * 2. Redistributions in binary form must reproduce the above copyright
+- * notice, this list of conditions and the following disclaimer in the
+- * documentation and/or other materials provided with the distribution.
+- * 4. Neither the name of the University nor the names of its contributors
+- * may be used to endorse or promote products derived from this software
+- * without specific prior written permission.
+- *
+- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+- * SUCH DAMAGE.
+- * -
+- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+- *
+- * Permission to use, copy, modify, and distribute this software for any
+- * purpose with or without fee is hereby granted, provided that the above
+- * copyright notice and this permission notice appear in all copies, and that
+- * the name of Digital Equipment Corporation not be used in advertising or
+- * publicity pertaining to distribution of the document or software without
+- * specific, written prior permission.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+- * SOFTWARE.
+- * -
+- * --Copyright--
+- */
+-
+-#include <string.h>
+-#include <arpa/nameser.h>
+-
+-static void
+-map_v4v6_address (const char *src, char *dst)
+-{
+- u_char *p = (u_char *) dst;
+- int i;
+-
+- /* Move the IPv4 part to the right position. */
+- memcpy (dst + 12, src, INADDRSZ);
+-
+- /* Mark this ipv6 addr as a mapped ipv4. */
+- for (i = 0; i < 10; i++)
+- *p++ = 0x00;
+- *p++ = 0xff;
+- *p = 0xff;
+-}
+diff --git a/resolv/mapv4v6hostent.h b/resolv/mapv4v6hostent.h
+deleted file mode 100644
+index c11038adf3..0000000000
+--- a/resolv/mapv4v6hostent.h
++++ /dev/null
+@@ -1,84 +0,0 @@
+-/*
+- * ++Copyright++ 1985, 1988, 1993
+- * -
+- * Copyright (c) 1985, 1988, 1993
+- * The Regents of the University of California. All rights reserved.
+- *
+- * Redistribution and use in source and binary forms, with or without
+- * modification, are permitted provided that the following conditions
+- * are met:
+- * 1. Redistributions of source code must retain the above copyright
+- * notice, this list of conditions and the following disclaimer.
+- * 2. Redistributions in binary form must reproduce the above copyright
+- * notice, this list of conditions and the following disclaimer in the
+- * documentation and/or other materials provided with the distribution.
+- * 4. Neither the name of the University nor the names of its contributors
+- * may be used to endorse or promote products derived from this software
+- * without specific prior written permission.
+- *
+- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+- * SUCH DAMAGE.
+- * -
+- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+- *
+- * Permission to use, copy, modify, and distribute this software for any
+- * purpose with or without fee is hereby granted, provided that the above
+- * copyright notice and this permission notice appear in all copies, and that
+- * the name of Digital Equipment Corporation not be used in advertising or
+- * publicity pertaining to distribution of the document or software without
+- * specific, written prior permission.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+- * SOFTWARE.
+- * -
+- * --Copyright--
+- */
+-
+-#include <arpa/nameser.h>
+-#include <sys/socket.h>
+-
+-typedef union {
+- int32_t al;
+- char ac;
+-} align;
+-
+-static int
+-map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp)
+-{
+- char **ap;
+-
+- if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
+- return 0;
+- hp->h_addrtype = AF_INET6;
+- hp->h_length = IN6ADDRSZ;
+- for (ap = hp->h_addr_list; *ap; ap++)
+- {
+- int i = sizeof (align) - ((u_long) *bpp % sizeof (align));
+-
+- if (*lenp < (i + IN6ADDRSZ))
+- /* Out of memory. */
+- return 1;
+- *bpp += i;
+- *lenp -= i;
+- map_v4v6_address (*ap, *bpp);
+- *ap = *bpp;
+- *bpp += IN6ADDRSZ;
+- *lenp -= IN6ADDRSZ;
+- }
+- return 0;
+-}
+diff --git a/resolv/ns_name_length_uncompressed.c b/resolv/ns_name_length_uncompressed.c
+new file mode 100644
+index 0000000000..51296b47ef
+--- /dev/null
++++ b/resolv/ns_name_length_uncompressed.c
+@@ -0,0 +1,72 @@
++/* Skip over an uncompressed name in wire format.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <errno.h>
++#include <stdbool.h>
++
++int
++__ns_name_length_uncompressed (const unsigned char *p,
++ const unsigned char *eom)
++{
++ const unsigned char *start = p;
++
++ while (true)
++ {
++ if (p == eom)
++ {
++ /* Truncated packet: no room for label length. */
++ __set_errno (EMSGSIZE);
++ return -1;
++ }
++
++ unsigned char b = *p;
++ ++p;
++ if (b == 0)
++ {
++ /* Root label. */
++ size_t length = p - start;
++ if (length > NS_MAXCDNAME)
++ {
++ /* Domain name too long. */
++ __set_errno (EMSGSIZE);
++ return -1;
++ }
++ return length;
++ }
++
++ if (b <= 63)
++ {
++ /* Regular label. */
++ if (b <= eom - p)
++ p += b;
++ else
++ {
++ /* Truncated packet: label incomplete. */
++ __set_errno (EMSGSIZE);
++ return -1;
++ }
++ }
++ else
++ {
++ /* Compression reference or corrupted label length. */
++ __set_errno (EMSGSIZE);
++ return -1;
++ }
++ }
++}
+diff --git a/resolv/ns_rr_cursor_init.c b/resolv/ns_rr_cursor_init.c
+new file mode 100644
+index 0000000000..6ee80b30e9
+--- /dev/null
++++ b/resolv/ns_rr_cursor_init.c
+@@ -0,0 +1,62 @@
++/* Initialize a simple DNS packet parser.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <errno.h>
++#include <stdbool.h>
++#include <string.h>
++
++bool
++__ns_rr_cursor_init (struct ns_rr_cursor *c,
++ const unsigned char *buf, size_t len)
++{
++ c->begin = buf;
++ c->end = buf + len;
++
++ /* Check for header size and 16-bit question count value (it must be 1). */
++ if (len < 12 || buf[4] != 0 || buf[5] != 1)
++ {
++ __set_errno (EMSGSIZE);
++ c->current = c->end;
++ return false;
++ }
++ c->current = buf + 12;
++
++ int consumed = __ns_name_length_uncompressed (c->current, c->end);
++ if (consumed < 0)
++ {
++ __set_errno (EMSGSIZE);
++ c->current = c->end;
++ c->first_rr = NULL;
++ return false;
++ }
++ c->current += consumed;
++
++ /* Ensure there is room for question type and class. */
++ if (c->end - c->current < 4)
++ {
++ __set_errno (EMSGSIZE);
++ c->current = c->end;
++ c->first_rr = NULL;
++ return false;
++ }
++ c->current += 4;
++ c->first_rr = c->current;
++
++ return true;
++}
+diff --git a/resolv/ns_rr_cursor_next.c b/resolv/ns_rr_cursor_next.c
+new file mode 100644
+index 0000000000..33652fc5da
+--- /dev/null
++++ b/resolv/ns_rr_cursor_next.c
+@@ -0,0 +1,74 @@
++/* Simple DNS record parser without textual name decoding.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <errno.h>
++#include <stdbool.h>
++#include <string.h>
++
++bool
++__ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr)
++{
++ rr->rdata = NULL;
++
++ /* Extract the record owner name. */
++ int consumed = __ns_name_unpack (c->begin, c->end, c->current,
++ rr->rname, sizeof (rr->rname));
++ if (consumed < 0)
++ {
++ memset (rr, 0, sizeof (*rr));
++ __set_errno (EMSGSIZE);
++ return false;
++ }
++ c->current += consumed;
++
++ /* Extract the metadata. */
++ struct
++ {
++ uint16_t rtype;
++ uint16_t rclass;
++ uint32_t ttl;
++ uint16_t rdlength;
++ } __attribute__ ((packed)) metadata;
++ _Static_assert (sizeof (metadata) == 10, "sizeof metadata");
++ if (c->end - c->current < sizeof (metadata))
++ {
++ memset (rr, 0, sizeof (*rr));
++ __set_errno (EMSGSIZE);
++ return false;
++ }
++ memcpy (&metadata, c->current, sizeof (metadata));
++ c->current += sizeof (metadata);
++ /* Endianess conversion. */
++ rr->rtype = ntohs (metadata.rtype);
++ rr->rclass = ntohs (metadata.rclass);
++ rr->ttl = ntohl (metadata.ttl);
++ rr->rdlength = ntohs (metadata.rdlength);
++
++ /* Extract record data. */
++ if (c->end - c->current < rr->rdlength)
++ {
++ memset (rr, 0, sizeof (*rr));
++ __set_errno (EMSGSIZE);
++ return false;
++ }
++ rr->rdata = c->current;
++ c->current += rr->rdlength;
++
++ return true;
++}
+diff --git a/resolv/ns_samebinaryname.c b/resolv/ns_samebinaryname.c
+new file mode 100644
+index 0000000000..9a47d8e97a
+--- /dev/null
++++ b/resolv/ns_samebinaryname.c
+@@ -0,0 +1,55 @@
++/* Compare two binary domain names for quality.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <stdbool.h>
++
++/* Convert ASCII letters to upper case. */
++static inline int
++ascii_toupper (unsigned char ch)
++{
++ if (ch >= 'a' && ch <= 'z')
++ return ch - 'a' + 'A';
++ else
++ return ch;
++}
++
++bool
++__ns_samebinaryname (const unsigned char *a, const unsigned char *b)
++{
++ while (*a != 0 && *b != 0)
++ {
++ if (*a != *b)
++ /* Different label length. */
++ return false;
++ int labellen = *a;
++ ++a;
++ ++b;
++ for (int i = 0; i < labellen; ++i)
++ {
++ if (*a != *b && ascii_toupper (*a) != ascii_toupper (*b))
++ /* Different character in label. */
++ return false;
++ ++a;
++ ++b;
++ }
++ }
++
++ /* Match if both names are at the root label. */
++ return *a == 0 && *b == 0;
++}
+diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
+index 544cffbecd..9fa81f23c8 100644
+--- a/resolv/nss_dns/dns-host.c
++++ b/resolv/nss_dns/dns-host.c
+@@ -69,6 +69,7 @@
+ * --Copyright--
+ */
+
++#include <alloc_buffer.h>
+ #include <assert.h>
+ #include <ctype.h>
+ #include <errno.h>
+@@ -86,10 +87,6 @@
+ #include <resolv/resolv-internal.h>
+ #include <resolv/resolv_context.h>
+
+-/* Get implementations of some internal functions. */
+-#include <resolv/mapv4v6addr.h>
+-#include <resolv/mapv4v6hostent.h>
+-
+ #define RESOLVSORT
+
+ #if PACKETSZ > 65536
+@@ -103,32 +100,36 @@
+ #endif
+ #define MAXHOSTNAMELEN 256
+
+-/* We need this time later. */
+-typedef union querybuf
+-{
+- HEADER hdr;
+- u_char buf[MAXPACKET];
+-} querybuf;
+-
+-static enum nss_status getanswer_r (struct resolv_context *ctx,
+- const querybuf *answer, int anslen,
+- const char *qname, int qtype,
+- struct hostent *result, char *buffer,
+- size_t buflen, int *errnop, int *h_errnop,
+- int map, int32_t *ttlp, char **canonp);
+-
+-static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
+- const querybuf *answer2, int anslen2,
+- const char *qname,
++/* For historic reasons, pointers to IP addresses are char *, so use a
++ single list type for addresses and host names. */
++#define DYNARRAY_STRUCT ptrlist
++#define DYNARRAY_ELEMENT char *
++#define DYNARRAY_PREFIX ptrlist_
++#include <malloc/dynarray-skeleton.c>
++
++static enum nss_status getanswer_r (unsigned char *packet, size_t packetlen,
++ uint16_t qtype, struct alloc_buffer *abuf,
++ struct ptrlist *addresses,
++ struct ptrlist *aliases,
++ int *errnop, int *h_errnop, int32_t *ttlp);
++static void addrsort (struct resolv_context *ctx, char **ap, int num);
++static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen,
++ struct alloc_buffer *abuf,
++ char **hnamep, int *errnop,
++ int *h_errnop, int32_t *ttlp);
++
++static enum nss_status gaih_getanswer (unsigned char *packet1,
++ size_t packet1len,
++ unsigned char *packet2,
++ size_t packet2len,
++ struct alloc_buffer *abuf,
+ struct gaih_addrtuple **pat,
+- char *buffer, size_t buflen,
+ int *errnop, int *h_errnop,
+ int32_t *ttlp);
+-static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1,
+- int anslen1,
+- const char *qname,
++static enum nss_status gaih_getanswer_noaaaa (unsigned char *packet,
++ size_t packetlen,
++ struct alloc_buffer *abuf,
+ struct gaih_addrtuple **pat,
+- char *buffer, size_t buflen,
+ int *errnop, int *h_errnop,
+ int32_t *ttlp);
+
+@@ -183,16 +184,9 @@ gethostbyname3_context (struct resolv_context *ctx,
+ char *buffer, size_t buflen, int *errnop,
+ int *h_errnop, int32_t *ttlp, char **canonp)
+ {
+- union
+- {
+- querybuf *buf;
+- u_char *ptr;
+- } host_buffer;
+- querybuf *orig_host_buffer;
+ char tmp[NS_MAXDNAME];
+ int size, type, n;
+ const char *cp;
+- int map = 0;
+ int olderr = errno;
+ enum nss_status status;
+
+@@ -223,10 +217,12 @@ gethostbyname3_context (struct resolv_context *ctx,
+ && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL)
+ name = cp;
+
+- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
++ unsigned char dns_packet_buffer[1024];
++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
+
+- n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf,
+- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
++ n = __res_context_search (ctx, name, C_IN, type,
++ dns_packet_buffer, sizeof (dns_packet_buffer),
++ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL);
+ if (n < 0)
+ {
+ switch (errno)
+@@ -253,34 +249,79 @@ gethostbyname3_context (struct resolv_context *ctx,
+ *errnop = EAGAIN;
+ else
+ __set_errno (olderr);
++ }
++ else
++ {
++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
+
+- /* If we are looking for an IPv6 address and mapping is enabled
+- by having the RES_USE_INET6 bit in _res.options set, we try
+- another lookup. */
+- if (af == AF_INET6 && res_use_inet6 ())
+- n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf,
+- host_buffer.buf != orig_host_buffer
+- ? MAXPACKET : 1024, &host_buffer.ptr,
+- NULL, NULL, NULL, NULL);
++ struct ptrlist addresses;
++ ptrlist_init (&addresses);
++ struct ptrlist aliases;
++ ptrlist_init (&aliases);
+
+- if (n < 0)
++ status = getanswer_r (alt_dns_packet_buffer, n, type,
++ &abuf, &addresses, &aliases,
++ errnop, h_errnop, ttlp);
++ if (status == NSS_STATUS_SUCCESS)
+ {
+- if (host_buffer.buf != orig_host_buffer)
+- free (host_buffer.buf);
+- return status;
+- }
++ if (ptrlist_has_failed (&addresses)
++ || ptrlist_has_failed (&aliases))
++ {
++ /* malloc failure. Do not retry using the ERANGE protocol. */
++ *errnop = ENOMEM;
++ *h_errnop = NETDB_INTERNAL;
++ status = NSS_STATUS_UNAVAIL;
++ }
+
+- map = 1;
++ /* Reserve the address and alias arrays in the result
++ buffer. Both are NULL-terminated, but the first element
++ of the alias array is stored in h_name, so no extra space
++ for the NULL terminator is needed there. */
++ result->h_addr_list
++ = alloc_buffer_alloc_array (&abuf, char *,
++ ptrlist_size (&addresses) + 1);
++ result->h_aliases
++ = alloc_buffer_alloc_array (&abuf, char *,
++ ptrlist_size (&aliases));
++ if (alloc_buffer_has_failed (&abuf))
++ {
++ /* Retry using the ERANGE protocol. */
++ *errnop = ERANGE;
++ *h_errnop = NETDB_INTERNAL;
++ status = NSS_STATUS_TRYAGAIN;
++ }
++ else
++ {
++ /* Copy the address list and NULL-terminate it. */
++ memcpy (result->h_addr_list, ptrlist_begin (&addresses),
++ ptrlist_size (&addresses) * sizeof (char *));
++ result->h_addr_list[ptrlist_size (&addresses)] = NULL;
++
++ /* Sort the address list if requested. */
++ if (type == T_A && __resolv_context_sort_count (ctx) > 0)
++ addrsort (ctx, result->h_addr_list, ptrlist_size (&addresses));
+
+- result->h_addrtype = AF_INET;
+- result->h_length = INADDRSZ;
++ /* Copy the aliases, excluding the last one. */
++ memcpy (result->h_aliases, ptrlist_begin (&aliases),
++ (ptrlist_size (&aliases) - 1) * sizeof (char *));
++ result->h_aliases[ptrlist_size (&aliases) - 1] = NULL;
++
++ /* The last alias goes into h_name. */
++ assert (ptrlist_size (&aliases) >= 1);
++ result->h_name = ptrlist_end (&aliases)[-1];
++
++ /* This is also the canonical name. */
++ if (canonp != NULL)
++ *canonp = result->h_name;
++ }
++ }
++
++ ptrlist_free (&aliases);
++ ptrlist_free (&addresses);
+ }
+
+- status = getanswer_r
+- (ctx, host_buffer.buf, n, name, type, result, buffer, buflen,
+- errnop, h_errnop, map, ttlp, canonp);
+- if (host_buffer.buf != orig_host_buffer)
+- free (host_buffer.buf);
++ if (alt_dns_packet_buffer != dns_packet_buffer)
++ free (alt_dns_packet_buffer);
+ return status;
+ }
+
+@@ -324,13 +365,8 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
+ *h_errnop = NETDB_INTERNAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+- status = NSS_STATUS_NOTFOUND;
+- if (res_use_inet6 ())
+- status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer,
+- buflen, errnop, h_errnop, NULL, NULL);
+- if (status == NSS_STATUS_NOTFOUND)
+- status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
+- buflen, errnop, h_errnop, NULL, NULL);
++ status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
++ buflen, errnop, h_errnop, NULL, NULL);
+ __resolv_context_put (ctx);
+ return status;
+ }
+@@ -365,17 +401,13 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
+ name = cp;
+ }
+
+- union
+- {
+- querybuf *buf;
+- u_char *ptr;
+- } host_buffer;
+- querybuf *orig_host_buffer;
+- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
++ unsigned char dns_packet_buffer[2048];
++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
+ u_char *ans2p = NULL;
+ int nans2p = 0;
+ int resplen2 = 0;
+ int ans2p_malloced = 0;
++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
+
+
+ int olderr = errno;
+@@ -384,22 +416,21 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
+ if ((ctx->resp->options & RES_NOAAAA) == 0)
+ {
+ n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
+- host_buffer.buf->buf, 2048, &host_buffer.ptr,
+- &ans2p, &nans2p, &resplen2, &ans2p_malloced);
++ dns_packet_buffer, sizeof (dns_packet_buffer),
++ &alt_dns_packet_buffer, &ans2p, &nans2p,
++ &resplen2, &ans2p_malloced);
+ if (n >= 0)
+- status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
+- resplen2, name, pat, buffer, buflen,
+- errnop, herrnop, ttlp);
++ status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2,
++ &abuf, pat, errnop, herrnop, ttlp);
+ }
+ else
+ {
+ n = __res_context_search (ctx, name, C_IN, T_A,
+- host_buffer.buf->buf, 2048, NULL,
+- NULL, NULL, NULL, NULL);
++ dns_packet_buffer, sizeof (dns_packet_buffer),
++ NULL, NULL, NULL, NULL, NULL);
+ if (n >= 0)
+- status = gaih_getanswer_noaaaa (host_buffer.buf, n,
+- name, pat, buffer, buflen,
+- errnop, herrnop, ttlp);
++ status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n,
++ &abuf, pat, errnop, herrnop, ttlp);
+ }
+ if (n < 0)
+ {
+@@ -430,12 +461,20 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
+ __set_errno (olderr);
+ }
+
++ /* Implement the buffer resizing protocol. */
++ if (alloc_buffer_has_failed (&abuf))
++ {
++ *errnop = ERANGE;
++ *herrnop = NETDB_INTERNAL;
++ status = NSS_STATUS_TRYAGAIN;
++ }
++
+ /* Check whether ans2p was separately allocated. */
+ if (ans2p_malloced)
+ free (ans2p);
+
+- if (host_buffer.buf != orig_host_buffer)
+- free (host_buffer.buf);
++ if (alt_dns_packet_buffer != dns_packet_buffer)
++ free (alt_dns_packet_buffer);
+
+ __resolv_context_put (ctx);
+ return status;
+@@ -451,36 +490,21 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
+ static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+ static const u_char v6local[] = { 0,0, 0,1 };
+ const u_char *uaddr = (const u_char *)addr;
+- struct host_data
+- {
+- char *aliases[MAX_NR_ALIASES];
+- unsigned char host_addr[16]; /* IPv4 or IPv6 */
+- char *h_addr_ptrs[MAX_NR_ADDRS + 1];
+- char linebuffer[0];
+- } *host_data = (struct host_data *) buffer;
+- union
+- {
+- querybuf *buf;
+- u_char *ptr;
+- } host_buffer;
+- querybuf *orig_host_buffer;
+ char qbuf[MAXDNAME+1], *qp = NULL;
+ size_t size;
+ int n, status;
+ int olderr = errno;
+
+- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
+- buffer += pad;
+- buflen = buflen > pad ? buflen - pad : 0;
+-
+- if (__glibc_unlikely (buflen < sizeof (struct host_data)))
+- {
+- *errnop = ERANGE;
+- *h_errnop = NETDB_INTERNAL;
+- return NSS_STATUS_TRYAGAIN;
+- }
+-
+- host_data = (struct host_data *) buffer;
++ /* Prepare the allocation buffer. Store the pointer array first, to
++ benefit from buffer alignment. */
++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
++ char **address_array = alloc_buffer_alloc_array (&abuf, char *, 2);
++ if (address_array == NULL)
++ {
++ *errnop = ERANGE;
++ *h_errnop = NETDB_INTERNAL;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+ struct resolv_context *ctx = __resolv_context_get ();
+ if (ctx == NULL)
+@@ -524,8 +548,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
+-
+ switch (af)
+ {
+ case AF_INET:
+@@ -549,36 +571,52 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
+ break;
+ }
+
+- n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
+- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
++ unsigned char dns_packet_buffer[1024];
++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
++ n = __res_context_query (ctx, qbuf, C_IN, T_PTR,
++ dns_packet_buffer, sizeof (dns_packet_buffer),
++ &alt_dns_packet_buffer,
++ NULL, NULL, NULL, NULL);
+ if (n < 0)
+ {
+ *h_errnop = h_errno;
+ __set_errno (olderr);
+- if (host_buffer.buf != orig_host_buffer)
+- free (host_buffer.buf);
++ if (alt_dns_packet_buffer != dns_packet_buffer)
++ free (alt_dns_packet_buffer);
+ __resolv_context_put (ctx);
+ return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
+ }
+
+- status = getanswer_r
+- (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
+- errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
+- if (host_buffer.buf != orig_host_buffer)
+- free (host_buffer.buf);
++ status = getanswer_ptr (alt_dns_packet_buffer, n,
++ &abuf, &result->h_name, errnop, h_errnop, ttlp);
++
++ if (alt_dns_packet_buffer != dns_packet_buffer)
++ free (alt_dns_packet_buffer);
++ __resolv_context_put (ctx);
++
+ if (status != NSS_STATUS_SUCCESS)
+- {
+- __resolv_context_put (ctx);
+- return status;
+- }
++ return status;
+
++ /* result->h_name has already been set by getanswer_ptr. */
+ result->h_addrtype = af;
+ result->h_length = len;
+- memcpy (host_data->host_addr, addr, len);
+- host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
+- host_data->h_addr_ptrs[1] = NULL;
++ /* Increase the alignment to 4, in case there are applications out
++ there that expect at least this level of address alignment. */
++ address_array[0] = (char *) alloc_buffer_next (&abuf, uint32_t);
++ alloc_buffer_copy_bytes (&abuf, uaddr, len);
++ address_array[1] = NULL;
++
++ /* This check also covers allocation failure in getanswer_ptr. */
++ if (alloc_buffer_has_failed (&abuf))
++ {
++ *errnop = ERANGE;
++ *h_errnop = NETDB_INTERNAL;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ result->h_addr_list = address_array;
++ result->h_aliases = &address_array[1]; /* Points to NULL. */
++
+ *h_errnop = NETDB_SUCCESS;
+- __resolv_context_put (ctx);
+ return NSS_STATUS_SUCCESS;
+ }
+ libc_hidden_def (_nss_dns_gethostbyaddr2_r)
+@@ -640,650 +678,362 @@ addrsort (struct resolv_context *ctx, char **ap, int num)
+ break;
+ }
+
+-static enum nss_status
+-getanswer_r (struct resolv_context *ctx,
+- const querybuf *answer, int anslen, const char *qname, int qtype,
+- struct hostent *result, char *buffer, size_t buflen,
+- int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
++/* Convert the uncompressed, binary domain name CDNAME into its
++ textual representation and add it to the end of ALIASES, allocating
++ space for a copy of the name from ABUF. Skip adding the name if it
++ is not a valid host name, and return false in that case, otherwise
++ true. */
++static bool
++getanswer_r_store_alias (const unsigned char *cdname,
++ struct alloc_buffer *abuf,
++ struct ptrlist *aliases)
+ {
+- struct host_data
+- {
+- char *aliases[MAX_NR_ALIASES];
+- unsigned char host_addr[16]; /* IPv4 or IPv6 */
+- char *h_addr_ptrs[0];
+- } *host_data;
+- int linebuflen;
+- const HEADER *hp;
+- const u_char *end_of_message, *cp;
+- int n, ancount, qdcount;
+- int haveanswer, had_error;
+- char *bp, **ap, **hap;
+- char tbuf[MAXDNAME];
+- const char *tname;
+- int (*name_ok) (const char *);
+- u_char packtmp[NS_MAXCDNAME];
+- int have_to_map = 0;
+- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
+- buffer += pad;
+- buflen = buflen > pad ? buflen - pad : 0;
+- if (__glibc_unlikely (buflen < sizeof (struct host_data)))
+- {
+- /* The buffer is too small. */
+- too_small:
+- *errnop = ERANGE;
+- *h_errnop = NETDB_INTERNAL;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- host_data = (struct host_data *) buffer;
+- linebuflen = buflen - sizeof (struct host_data);
+- if (buflen - sizeof (struct host_data) != linebuflen)
+- linebuflen = INT_MAX;
+-
+- tname = qname;
+- result->h_name = NULL;
+- end_of_message = answer->buf + anslen;
+- switch (qtype)
+- {
+- case T_A:
+- case T_AAAA:
+- name_ok = __libc_res_hnok;
+- break;
+- case T_PTR:
+- name_ok = __libc_res_dnok;
+- break;
+- default:
+- *errnop = ENOENT;
+- return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */
+- }
++ /* Filter out domain names that are not host names. */
++ if (!__res_binary_hnok (cdname))
++ return false;
++
++ /* Note: Not NS_MAXCDNAME, so that __ns_name_ntop implicitly checks
++ for length. */
++ char dname[MAXHOSTNAMELEN + 1];
++ if (__ns_name_ntop (cdname, dname, sizeof (dname)) < 0)
++ return false;
++ /* Do not report an error on allocation failure, instead store NULL
++ or do nothing. getanswer_r's caller will see NSS_STATUS_SUCCESS
++ and detect the memory allocation failure or buffer space
++ exhaustion, and report it accordingly. */
++ ptrlist_add (aliases, alloc_buffer_copy_string (abuf, dname));
++ return true;
++}
+
+- /*
+- * find first satisfactory answer
+- */
+- hp = &answer->hdr;
+- ancount = ntohs (hp->ancount);
+- qdcount = ntohs (hp->qdcount);
+- cp = answer->buf + HFIXEDSZ;
+- if (__glibc_unlikely (qdcount != 1))
++static enum nss_status __attribute__ ((noinline))
++getanswer_r (unsigned char *packet, size_t packetlen, uint16_t qtype,
++ struct alloc_buffer *abuf,
++ struct ptrlist *addresses, struct ptrlist *aliases,
++ int *errnop, int *h_errnop, int32_t *ttlp)
++{
++ struct ns_rr_cursor c;
++ if (!__ns_rr_cursor_init (&c, packet, packetlen))
+ {
++ /* This should not happen because __res_context_query already
++ perfroms response validation. */
+ *h_errnop = NO_RECOVERY;
+ return NSS_STATUS_UNAVAIL;
+ }
+- if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen)
+- goto too_small;
+- bp = (char *) &host_data->h_addr_ptrs[ancount + 1];
+- linebuflen -= (ancount + 1) * sizeof (char *);
+-
+- n = __ns_name_unpack (answer->buf, end_of_message, cp,
+- packtmp, sizeof packtmp);
+- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
+- {
+- if (__glibc_unlikely (errno == EMSGSIZE))
+- goto too_small;
+
+- n = -1;
+- }
+-
+- if (__glibc_unlikely (n < 0))
++ /* Treat the QNAME just like an alias. Error out if it is not a
++ valid host name. */
++ if (ns_rr_cursor_rcode (&c) == NXDOMAIN
++ || !getanswer_r_store_alias (ns_rr_cursor_qname (&c), abuf, aliases))
+ {
+- *errnop = errno;
+- *h_errnop = NO_RECOVERY;
+- return NSS_STATUS_UNAVAIL;
+- }
+- if (__glibc_unlikely (name_ok (bp) == 0))
+- {
+- errno = EBADMSG;
+- *errnop = EBADMSG;
+- *h_errnop = NO_RECOVERY;
+- return NSS_STATUS_UNAVAIL;
++ if (ttlp != NULL)
++ /* No negative caching. */
++ *ttlp = 0;
++ *h_errnop = HOST_NOT_FOUND;
++ *errnop = ENOENT;
++ return NSS_STATUS_NOTFOUND;
+ }
+- cp += n + QFIXEDSZ;
+
+- if (qtype == T_A || qtype == T_AAAA)
++ int ancount = ns_rr_cursor_ancount (&c);
++ const unsigned char *expected_name = ns_rr_cursor_qname (&c);
++ /* expected_name may be updated to point into this buffer. */
++ unsigned char name_buffer[NS_MAXCDNAME];
++
++ for (; ancount > 0; --ancount)
+ {
+- /* res_send() has already verified that the query name is the
+- * same as the one we sent; this just gets the expanded name
+- * (i.e., with the succeeding search-domain tacked on).
+- */
+- n = strlen (bp) + 1; /* for the \0 */
+- if (n >= MAXHOSTNAMELEN)
++ struct ns_rr_wire rr;
++ if (!__ns_rr_cursor_next (&c, &rr))
+ {
+ *h_errnop = NO_RECOVERY;
+- *errnop = ENOENT;
+- return NSS_STATUS_TRYAGAIN;
++ return NSS_STATUS_UNAVAIL;
+ }
+- result->h_name = bp;
+- bp += n;
+- linebuflen -= n;
+- if (linebuflen < 0)
+- goto too_small;
+- /* The qname can be abbreviated, but h_name is now absolute. */
+- qname = result->h_name;
+- }
+
+- ap = host_data->aliases;
+- *ap = NULL;
+- result->h_aliases = host_data->aliases;
+- hap = host_data->h_addr_ptrs;
+- *hap = NULL;
+- result->h_addr_list = host_data->h_addr_ptrs;
+- haveanswer = 0;
+- had_error = 0;
++ /* Skip over records with the wrong class. */
++ if (rr.rclass != C_IN)
++ continue;
+
+- while (ancount-- > 0 && cp < end_of_message && had_error == 0)
+- {
+- int type, class;
++ /* Update TTL for recognized record types. */
++ if ((rr.rtype == T_CNAME || rr.rtype == qtype)
++ && ttlp != NULL && *ttlp > rr.ttl)
++ *ttlp = rr.ttl;
+
+- n = __ns_name_unpack (answer->buf, end_of_message, cp,
+- packtmp, sizeof packtmp);
+- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
++ if (rr.rtype == T_CNAME)
+ {
+- if (__glibc_unlikely (errno == EMSGSIZE))
+- goto too_small;
+-
+- n = -1;
++ /* NB: No check for owner name match, based on historic
++ precedent. Record the CNAME target as the new expected
++ name. */
++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
++ name_buffer, sizeof (name_buffer));
++ if (n < 0)
++ {
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
++ }
++ /* And store the new name as an alias. */
++ getanswer_r_store_alias (name_buffer, abuf, aliases);
++ expected_name = name_buffer;
+ }
+-
+- if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0))
++ else if (rr.rtype == qtype
++ && __ns_samebinaryname (rr.rname, expected_name)
++ && rr.rdlength == rrtype_to_rdata_length (qtype))
+ {
+- ++had_error;
+- continue;
++ /* Make a copy of the address and store it. Increase the
++ alignment to 4, in case there are applications out there
++ that expect at least this level of address alignment. */
++ ptrlist_add (addresses, (char *) alloc_buffer_next (abuf, uint32_t));
++ alloc_buffer_copy_bytes (abuf, rr.rdata, rr.rdlength);
+ }
+- cp += n; /* name */
++ }
+
+- if (__glibc_unlikely (cp + 10 > end_of_message))
+- {
+- ++had_error;
+- continue;
+- }
++ if (ptrlist_size (addresses) == 0)
++ {
++ /* No address record found. */
++ if (ttlp != NULL)
++ /* No caching of negative responses. */
++ *ttlp = 0;
+
+- NS_GET16 (type, cp);
+- NS_GET16 (class, cp);
+- int32_t ttl;
+- NS_GET32 (ttl, cp);
+- NS_GET16 (n, cp); /* RDATA length. */
++ *h_errnop = NO_RECOVERY;
++ *errnop = ENOENT;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ else
++ {
++ *h_errnop = NETDB_SUCCESS;
++ return NSS_STATUS_SUCCESS;
++ }
++}
+
+- if (end_of_message - cp < n)
+- {
+- /* RDATA extends beyond the end of the packet. */
+- ++had_error;
+- continue;
+- }
++static enum nss_status
++getanswer_ptr (unsigned char *packet, size_t packetlen,
++ struct alloc_buffer *abuf, char **hnamep,
++ int *errnop, int *h_errnop, int32_t *ttlp)
++{
++ struct ns_rr_cursor c;
++ if (!__ns_rr_cursor_init (&c, packet, packetlen))
++ {
++ /* This should not happen because __res_context_query already
++ perfroms response validation. */
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
++ }
++ int ancount = ns_rr_cursor_ancount (&c);
++ const unsigned char *expected_name = ns_rr_cursor_qname (&c);
++ /* expected_name may be updated to point into this buffer. */
++ unsigned char name_buffer[NS_MAXCDNAME];
+
+- if (__glibc_unlikely (class != C_IN))
++ while (ancount > 0)
++ {
++ struct ns_rr_wire rr;
++ if (!__ns_rr_cursor_next (&c, &rr))
+ {
+- /* XXX - debug? syslog? */
+- cp += n;
+- continue; /* XXX - had_error++ ? */
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
+ }
+
+- if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
+- {
+- /* A CNAME could also have a TTL entry. */
+- if (ttlp != NULL && ttl < *ttlp)
+- *ttlp = ttl;
+-
+- if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
+- continue;
+- n = __libc_dn_expand (answer->buf, end_of_message, cp,
+- tbuf, sizeof tbuf);
+- if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0))
+- {
+- ++had_error;
+- continue;
+- }
+- cp += n;
+- /* Store alias. */
+- *ap++ = bp;
+- n = strlen (bp) + 1; /* For the \0. */
+- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
+- {
+- ++had_error;
+- continue;
+- }
+- bp += n;
+- linebuflen -= n;
+- /* Get canonical name. */
+- n = strlen (tbuf) + 1; /* For the \0. */
+- if (__glibc_unlikely (n > linebuflen))
+- goto too_small;
+- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
+- {
+- ++had_error;
+- continue;
+- }
+- result->h_name = bp;
+- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
+- linebuflen -= n;
+- continue;
+- }
++ /* Skip over records with the wrong class. */
++ if (rr.rclass != C_IN)
++ continue;
+
+- if (qtype == T_PTR && type == T_CNAME)
+- {
+- /* A CNAME could also have a TTL entry. */
+- if (ttlp != NULL && ttl < *ttlp)
+- *ttlp = ttl;
++ /* Update TTL for known record types. */
++ if ((rr.rtype == T_CNAME || rr.rtype == T_PTR)
++ && ttlp != NULL && *ttlp > rr.ttl)
++ *ttlp = rr.ttl;
+
+- n = __libc_dn_expand (answer->buf, end_of_message, cp,
+- tbuf, sizeof tbuf);
+- if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0))
+- {
+- ++had_error;
+- continue;
+- }
+- cp += n;
+- /* Get canonical name. */
+- n = strlen (tbuf) + 1; /* For the \0. */
+- if (__glibc_unlikely (n > linebuflen))
+- goto too_small;
+- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
++ if (rr.rtype == T_CNAME)
++ {
++ /* NB: No check for owner name match, based on historic
++ precedent. Record the CNAME target as the new expected
++ name. */
++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
++ name_buffer, sizeof (name_buffer));
++ if (n < 0)
+ {
+- ++had_error;
+- continue;
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
+ }
+- tname = bp;
+- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
+- linebuflen -= n;
+- continue;
++ expected_name = name_buffer;
+ }
+-
+- if (type == T_A && qtype == T_AAAA && map)
+- have_to_map = 1;
+- else if (__glibc_unlikely (type != qtype))
++ else if (rr.rtype == T_PTR
++ && __ns_samebinaryname (rr.rname, expected_name))
+ {
+- cp += n;
+- continue; /* XXX - had_error++ ? */
+- }
+-
+- switch (type)
+- {
+- case T_PTR:
+- if (__glibc_unlikely (__strcasecmp (tname, bp) != 0))
++ /* Decompress the target of the PTR record. This is the
++ host name we are looking for. We can only use it if it
++ is syntactically valid. Historically, only one host name
++ is returned here. If the recursive resolver performs DNS
++ record rotation, the returned host name is essentially
++ random, which is why multiple PTR records are rarely
++ used. Use MAXHOSTNAMELEN instead of NS_MAXCDNAME for
++ additional length checking. */
++ char hname[MAXHOSTNAMELEN + 1];
++ if (__ns_name_unpack (c.begin, c.end, rr.rdata,
++ name_buffer, sizeof (name_buffer)) < 0
++ || !__res_binary_hnok (expected_name)
++ || __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0)
+ {
+- cp += n;
+- continue; /* XXX - had_error++ ? */
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
+ }
+-
+- n = __ns_name_unpack (answer->buf, end_of_message, cp,
+- packtmp, sizeof packtmp);
+- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
+- {
+- if (__glibc_unlikely (errno == EMSGSIZE))
+- goto too_small;
+-
+- n = -1;
+- }
+-
+- if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0))
+- {
+- ++had_error;
+- break;
+- }
+- if (ttlp != NULL && ttl < *ttlp)
+- *ttlp = ttl;
+- /* bind would put multiple PTR records as aliases, but we don't do
+- that. */
+- result->h_name = bp;
+- *h_errnop = NETDB_SUCCESS;
++ /* Successful allocation is checked by the caller. */
++ *hnamep = alloc_buffer_copy_string (abuf, hname);
+ return NSS_STATUS_SUCCESS;
+- case T_A:
+- case T_AAAA:
+- if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0))
+- {
+- cp += n;
+- continue; /* XXX - had_error++ ? */
+- }
+-
+- /* Stop parsing at a record whose length is incorrect. */
+- if (n != rrtype_to_rdata_length (type))
+- {
+- ++had_error;
+- break;
+- }
+-
+- /* Skip records of the wrong type. */
+- if (n != result->h_length)
+- {
+- cp += n;
+- continue;
+- }
+- if (!haveanswer)
+- {
+- int nn;
+-
+- /* We compose a single hostent out of the entire chain of
+- entries, so the TTL of the hostent is essentially the lowest
+- TTL in the chain. */
+- if (ttlp != NULL && ttl < *ttlp)
+- *ttlp = ttl;
+- if (canonp != NULL)
+- *canonp = bp;
+- result->h_name = bp;
+- nn = strlen (bp) + 1; /* for the \0 */
+- bp += nn;
+- linebuflen -= nn;
+- }
+-
+- /* Provide sufficient alignment for both address
+- families. */
+- enum { align = 4 };
+- _Static_assert ((align % __alignof__ (struct in_addr)) == 0,
+- "struct in_addr alignment");
+- _Static_assert ((align % __alignof__ (struct in6_addr)) == 0,
+- "struct in6_addr alignment");
+- {
+- char *new_bp = PTR_ALIGN_UP (bp, align);
+- linebuflen -= new_bp - bp;
+- bp = new_bp;
+- }
+-
+- if (__glibc_unlikely (n > linebuflen))
+- goto too_small;
+- bp = __mempcpy (*hap++ = bp, cp, n);
+- cp += n;
+- linebuflen -= n;
+- break;
+- default:
+- abort ();
+ }
+- if (had_error == 0)
+- ++haveanswer;
+ }
+
+- if (haveanswer > 0)
+- {
+- *ap = NULL;
+- *hap = NULL;
+- /*
+- * Note: we sort even if host can take only one address
+- * in its return structures - should give it the "best"
+- * address in that case, not some random one
+- */
+- if (haveanswer > 1 && qtype == T_A
+- && __resolv_context_sort_count (ctx) > 0)
+- addrsort (ctx, host_data->h_addr_ptrs, haveanswer);
+-
+- if (result->h_name == NULL)
+- {
+- n = strlen (qname) + 1; /* For the \0. */
+- if (n > linebuflen)
+- goto too_small;
+- if (n >= MAXHOSTNAMELEN)
+- goto no_recovery;
+- result->h_name = bp;
+- bp = __mempcpy (bp, qname, n); /* Cannot overflow. */
+- linebuflen -= n;
+- }
++ /* No PTR record found. */
++ if (ttlp != NULL)
++ /* No caching of negative responses. */
++ *ttlp = 0;
+
+- if (have_to_map)
+- if (map_v4v6_hostent (result, &bp, &linebuflen))
+- goto too_small;
+- *h_errnop = NETDB_SUCCESS;
+- return NSS_STATUS_SUCCESS;
+- }
+- no_recovery:
+ *h_errnop = NO_RECOVERY;
+ *errnop = ENOENT;
+- /* Special case here: if the resolver sent a result but it only
+- contains a CNAME while we are looking for a T_A or T_AAAA record,
+- we fail with NOTFOUND instead of TRYAGAIN. */
+- return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
+- ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
++ return NSS_STATUS_TRYAGAIN;
+ }
+
+-
++/* Parses DNS data found in PACKETLEN bytes at PACKET in struct
++ gaih_addrtuple address tuples. The new address tuples are linked
++ from **TAILP, with backing store allocated from ABUF, and *TAILP is
++ updated to point where the next tuple pointer should be stored. If
++ TTLP is not null, *TTLP is updated to reflect the minimum TTL. If
++ STORE_CANON is true, the canonical name is stored as part of the
++ first address tuple being written. */
+ static enum nss_status
+-gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
+- struct gaih_addrtuple ***patp,
+- char **bufferp, size_t *buflenp,
+- int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
++gaih_getanswer_slice (unsigned char *packet, size_t packetlen,
++ struct alloc_buffer *abuf,
++ struct gaih_addrtuple ***tailp,
++ int *errnop, int *h_errnop, int32_t *ttlp,
++ bool store_canon)
+ {
+- char *buffer = *bufferp;
+- size_t buflen = *buflenp;
+-
+- struct gaih_addrtuple **pat = *patp;
+- const HEADER *hp = &answer->hdr;
+- int ancount = ntohs (hp->ancount);
+- int qdcount = ntohs (hp->qdcount);
+- const u_char *cp = answer->buf + HFIXEDSZ;
+- const u_char *end_of_message = answer->buf + anslen;
+- if (__glibc_unlikely (qdcount != 1))
+- {
+- *h_errnop = NO_RECOVERY;
+- return NSS_STATUS_UNAVAIL;
+- }
+-
+- u_char packtmp[NS_MAXCDNAME];
+- int n = __ns_name_unpack (answer->buf, end_of_message, cp,
+- packtmp, sizeof packtmp);
+- /* We unpack the name to check it for validity. But we do not need
+- it later. */
+- if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
+- {
+- if (__glibc_unlikely (errno == EMSGSIZE))
+- {
+- too_small:
+- *errnop = ERANGE;
+- *h_errnop = NETDB_INTERNAL;
+- return NSS_STATUS_TRYAGAIN;
+- }
+-
+- n = -1;
+- }
+-
+- if (__glibc_unlikely (n < 0))
++ struct ns_rr_cursor c;
++ if (!__ns_rr_cursor_init (&c, packet, packetlen))
+ {
+- *errnop = errno;
++ /* This should not happen because __res_context_query already
++ perfroms response validation. */
+ *h_errnop = NO_RECOVERY;
+ return NSS_STATUS_UNAVAIL;
+ }
+- if (__glibc_unlikely (__libc_res_hnok (buffer) == 0))
+- {
+- errno = EBADMSG;
+- *errnop = EBADMSG;
+- *h_errnop = NO_RECOVERY;
+- return NSS_STATUS_UNAVAIL;
+- }
+- cp += n + QFIXEDSZ;
+-
+- int haveanswer = 0;
+- int had_error = 0;
+- char *canon = NULL;
+- char *h_name = NULL;
+- int h_namelen = 0;
+-
+- if (ancount == 0)
++ bool haveanswer = false; /* Set to true if at least one address. */
++ uint16_t qtype = ns_rr_cursor_qtype (&c);
++ int ancount = ns_rr_cursor_ancount (&c);
++ const unsigned char *expected_name = ns_rr_cursor_qname (&c);
++ /* expected_name may be updated to point into this buffer. */
++ unsigned char name_buffer[NS_MAXCDNAME];
++
++ /* This is a pointer to a possibly-compressed name in the packet.
++ Eventually it is equivalent to the canonical name. If needed, it
++ is uncompressed and translated to text form when the first
++ address tuple is encountered. */
++ const unsigned char *compressed_alias_name = expected_name;
++
++ if (ancount == 0 || !__res_binary_hnok (compressed_alias_name))
+ {
+ *h_errnop = HOST_NOT_FOUND;
+ return NSS_STATUS_NOTFOUND;
+ }
+
+- while (ancount-- > 0 && cp < end_of_message && had_error == 0)
++ for (; ancount > -0; --ancount)
+ {
+- n = __ns_name_unpack (answer->buf, end_of_message, cp,
+- packtmp, sizeof packtmp);
+- if (n != -1 &&
+- (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
++ struct ns_rr_wire rr;
++ if (!__ns_rr_cursor_next (&c, &rr))
+ {
+- if (__glibc_unlikely (errno == EMSGSIZE))
+- goto too_small;
+-
+- n = -1;
+- }
+- if (__glibc_unlikely (n < 0 || __libc_res_hnok (buffer) == 0))
+- {
+- ++had_error;
+- continue;
+- }
+- if (*firstp && canon == NULL)
+- {
+- h_name = buffer;
+- buffer += h_namelen;
+- buflen -= h_namelen;
+- }
+-
+- cp += n; /* name */
+-
+- if (__glibc_unlikely (cp + 10 > end_of_message))
+- {
+- ++had_error;
+- continue;
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
+ }
+
+- uint16_t type;
+- NS_GET16 (type, cp);
+- uint16_t class;
+- NS_GET16 (class, cp);
+- int32_t ttl;
+- NS_GET32 (ttl, cp);
+- NS_GET16 (n, cp); /* RDATA length. */
++ /* Update TTL for known record types. */
++ if ((rr.rtype == T_CNAME || rr.rtype == qtype)
++ && ttlp != NULL && *ttlp > rr.ttl)
++ *ttlp = rr.ttl;
+
+- if (end_of_message - cp < n)
++ if (rr.rtype == T_CNAME)
+ {
+- /* RDATA extends beyond the end of the packet. */
+- ++had_error;
+- continue;
+- }
+-
+- if (class != C_IN)
+- {
+- cp += n;
+- continue;
+- }
+-
+- if (type == T_CNAME)
+- {
+- char tbuf[MAXDNAME];
+-
+- /* A CNAME could also have a TTL entry. */
+- if (ttlp != NULL && ttl < *ttlp)
+- *ttlp = ttl;
+-
+- n = __libc_dn_expand (answer->buf, end_of_message, cp,
+- tbuf, sizeof tbuf);
+- if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0))
++ /* NB: No check for owner name match, based on historic
++ precedent. Record the CNAME target as the new expected
++ name. */
++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
++ name_buffer, sizeof (name_buffer));
++ if (n < 0)
+ {
+- ++had_error;
+- continue;
+- }
+- cp += n;
+-
+- if (*firstp)
+- {
+- /* Reclaim buffer space. */
+- if (h_name + h_namelen == buffer)
+- {
+- buffer = h_name;
+- buflen += h_namelen;
+- }
+-
+- n = strlen (tbuf) + 1;
+- if (__glibc_unlikely (n > buflen))
+- goto too_small;
+- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
+- {
+- ++had_error;
+- continue;
+- }
+-
+- canon = buffer;
+- buffer = __mempcpy (buffer, tbuf, n);
+- buflen -= n;
+- h_namelen = 0;
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
+ }
+- continue;
++ expected_name = name_buffer;
++ if (store_canon && __res_binary_hnok (name_buffer))
++ /* This name can be used as a canonical name. Do not
++ translate to text form here to conserve buffer space.
++ Point to the compressed name because name_buffer can be
++ overwritten with an unusable name later. */
++ compressed_alias_name = rr.rdata;
+ }
+-
+- /* Stop parsing if we encounter a record with incorrect RDATA
+- length. */
+- if (type == T_A || type == T_AAAA)
++ else if (rr.rtype == qtype
++ && __ns_samebinaryname (rr.rname, expected_name)
++ && rr.rdlength == rrtype_to_rdata_length (qtype))
+ {
+- if (n != rrtype_to_rdata_length (type))
++ struct gaih_addrtuple *ntup
++ = alloc_buffer_alloc (abuf, struct gaih_addrtuple);
++ /* Delay error reporting to the callers (they implement the
++ ERANGE buffer resizing handshake). */
++ if (ntup != NULL)
+ {
+- ++had_error;
+- continue;
++ ntup->next = NULL;
++ if (store_canon && compressed_alias_name != NULL)
++ {
++ /* This assumes that all the CNAME records come
++ first. Use MAXHOSTNAMELEN instead of
++ NS_MAXCDNAME for additional length checking.
++ However, these checks are not expected to fail
++ because all size NS_MAXCDNAME names should into
++ the hname buffer because no escaping is
++ needed. */
++ char unsigned nbuf[NS_MAXCDNAME];
++ char hname[MAXHOSTNAMELEN + 1];
++ if (__ns_name_unpack (c.begin, c.end,
++ compressed_alias_name,
++ nbuf, sizeof (nbuf)) >= 0
++ && __ns_name_ntop (nbuf, hname, sizeof (hname)) >= 0)
++ /* Space checking is performed by the callers. */
++ ntup->name = alloc_buffer_copy_string (abuf, hname);
++ store_canon = false;
++ }
++ else
++ ntup->name = NULL;
++ if (rr.rdlength == 4)
++ ntup->family = AF_INET;
++ else
++ ntup->family = AF_INET6;
++ memcpy (ntup->addr, rr.rdata, rr.rdlength);
++ ntup->scopeid = 0;
++
++ /* Link in the new tuple, and update the tail pointer to
++ point to its next field. */
++ **tailp = ntup;
++ *tailp = &ntup->next;
++
++ haveanswer = true;
+ }
+ }
+- else
+- {
+- /* Skip unknown records. */
+- cp += n;
+- continue;
+- }
+-
+- assert (type == T_A || type == T_AAAA);
+- if (*pat == NULL)
+- {
+- uintptr_t pad = (-(uintptr_t) buffer
+- % __alignof__ (struct gaih_addrtuple));
+- buffer += pad;
+- buflen = buflen > pad ? buflen - pad : 0;
+-
+- if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple)))
+- goto too_small;
+-
+- *pat = (struct gaih_addrtuple *) buffer;
+- buffer += sizeof (struct gaih_addrtuple);
+- buflen -= sizeof (struct gaih_addrtuple);
+- }
+-
+- (*pat)->name = NULL;
+- (*pat)->next = NULL;
+-
+- if (*firstp)
+- {
+- /* We compose a single hostent out of the entire chain of
+- entries, so the TTL of the hostent is essentially the lowest
+- TTL in the chain. */
+- if (ttlp != NULL && ttl < *ttlp)
+- *ttlp = ttl;
+-
+- (*pat)->name = canon ?: h_name;
+-
+- *firstp = 0;
+- }
+-
+- (*pat)->family = type == T_A ? AF_INET : AF_INET6;
+- memcpy ((*pat)->addr, cp, n);
+- cp += n;
+- (*pat)->scopeid = 0;
+-
+- pat = &((*pat)->next);
+-
+- haveanswer = 1;
+ }
+
+ if (haveanswer)
+ {
+- *patp = pat;
+- *bufferp = buffer;
+- *buflenp = buflen;
+-
+ *h_errnop = NETDB_SUCCESS;
+ return NSS_STATUS_SUCCESS;
+ }
+-
+- /* Special case here: if the resolver sent a result but it only
+- contains a CNAME while we are looking for a T_A or T_AAAA record,
+- we fail with NOTFOUND instead of TRYAGAIN. */
+- if (canon != NULL)
++ else
+ {
++ /* Special case here: if the resolver sent a result but it only
++ contains a CNAME while we are looking for a T_A or T_AAAA
++ record, we fail with NOTFOUND. */
+ *h_errnop = HOST_NOT_FOUND;
+ return NSS_STATUS_NOTFOUND;
+ }
+-
+- *h_errnop = NETDB_INTERNAL;
+- return NSS_STATUS_TRYAGAIN;
+ }
+
+
+ static enum nss_status
+-gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
+- int anslen2, const char *qname,
+- struct gaih_addrtuple **pat, char *buffer, size_t buflen,
++gaih_getanswer (unsigned char *packet1, size_t packet1len,
++ unsigned char *packet2, size_t packet2len,
++ struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
+ int *errnop, int *h_errnop, int32_t *ttlp)
+ {
+- int first = 1;
+-
+ enum nss_status status = NSS_STATUS_NOTFOUND;
+
+ /* Combining the NSS status of two distinct queries requires some
+@@ -1295,7 +1045,10 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
+ between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
+ A recoverable TRYAGAIN is almost always due to buffer size issues
+ and returns ERANGE in errno and the caller is expected to retry
+- with a larger buffer.
++ with a larger buffer. (The caller, _nss_dns_gethostbyname4_r,
++ ignores the return status if it detects that the result buffer
++ has been exhausted and generates a TRYAGAIN failure with an
++ ERANGE code.)
+
+ Lastly, you may be tempted to make significant changes to the
+ conditions in this code to bring about symmetry between responses.
+@@ -1375,36 +1128,30 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
+ is a recoverable error we now return TRYAGIN even if the first
+ response was SUCCESS. */
+
+- if (anslen1 > 0)
+- status = gaih_getanswer_slice(answer1, anslen1, qname,
+- &pat, &buffer, &buflen,
+- errnop, h_errnop, ttlp,
+- &first);
+-
+- if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
+- || (status == NSS_STATUS_TRYAGAIN
+- /* We want to look at the second answer in case of an
+- NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e.
+- *h_errnop is NO_RECOVERY. If not, and if the failure was due to
+- an insufficient buffer (ERANGE), then we need to drop the results
+- and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can
+- repeat the query with a larger buffer. */
+- && (*errnop != ERANGE || *h_errnop == NO_RECOVERY)))
+- && answer2 != NULL && anslen2 > 0)
++ if (packet1len > 0)
+ {
+- enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
+- &pat, &buffer, &buflen,
+- errnop, h_errnop, ttlp,
+- &first);
++ status = gaih_getanswer_slice (packet1, packet1len,
++ abuf, &pat, errnop, h_errnop, ttlp, true);
++ if (alloc_buffer_has_failed (abuf))
++ /* Do not try parsing the second packet if a larger result
++ buffer is needed. The caller implements the resizing
++ protocol because *abuf has been exhausted. */
++ return NSS_STATUS_TRYAGAIN; /* Ignored by the caller. */
++ }
++
++ if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
++ && packet2 != NULL && packet2len > 0)
++ {
++ enum nss_status status2
++ = gaih_getanswer_slice (packet2, packet2len,
++ abuf, &pat, errnop, h_errnop, ttlp,
++ /* Success means that data with a
++ canonical name has already been
++ stored. Do not store the name again. */
++ status != NSS_STATUS_SUCCESS);
+ /* Use the second response status in some cases. */
+ if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
+ status = status2;
+- /* Do not return a truncated second response (unless it was
+- unavoidable e.g. unrecoverable TRYAGAIN). */
+- if (status == NSS_STATUS_SUCCESS
+- && (status2 == NSS_STATUS_TRYAGAIN
+- && *errnop == ERANGE && *h_errnop != NO_RECOVERY))
+- status = NSS_STATUS_TRYAGAIN;
+ }
+
+ return status;
+@@ -1412,18 +1159,13 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
+
+ /* Variant of gaih_getanswer without a second (AAAA) response. */
+ static enum nss_status
+-gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname,
+- struct gaih_addrtuple **pat,
+- char *buffer, size_t buflen,
++gaih_getanswer_noaaaa (unsigned char *packet, size_t packetlen,
++ struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
+ int *errnop, int *h_errnop, int32_t *ttlp)
+ {
+- int first = 1;
+-
+ enum nss_status status = NSS_STATUS_NOTFOUND;
+- if (anslen1 > 0)
+- status = gaih_getanswer_slice (answer1, anslen1, qname,
+- &pat, &buffer, &buflen,
+- errnop, h_errnop, ttlp,
+- &first);
++ if (packetlen > 0)
++ status = gaih_getanswer_slice (packet, packetlen,
++ abuf, &pat, errnop, h_errnop, ttlp, true);
+ return status;
+ }
+diff --git a/resolv/res-name-checking.c b/resolv/res-name-checking.c
+index 07a412d8ff..213edceaf3 100644
+--- a/resolv/res-name-checking.c
++++ b/resolv/res-name-checking.c
+@@ -138,6 +138,12 @@ binary_leading_dash (const unsigned char *dn)
+ return dn[0] > 0 && dn[1] == '-';
+ }
+
++bool
++__res_binary_hnok (const unsigned char *dn)
++{
++ return !binary_leading_dash (dn) && binary_hnok (dn);
++}
++
+ /* Return 1 if res_hnok is a valid host name. Labels must only
+ contain [0-9a-zA-Z_-] characters, and the name must not start with
+ a '-'. The latter is to avoid confusion with program options. */
+@@ -145,11 +151,9 @@ int
+ ___res_hnok (const char *dn)
+ {
+ unsigned char buf[NS_MAXCDNAME];
+- if (!printable_string (dn)
+- || __ns_name_pton (dn, buf, sizeof (buf)) < 0
+- || binary_leading_dash (buf))
+- return 0;
+- return binary_hnok (buf);
++ return (printable_string (dn)
++ && __ns_name_pton (dn, buf, sizeof (buf)) >= 0
++ && __res_binary_hnok (buf));
+ }
+ versioned_symbol (libc, ___res_hnok, res_hnok, GLIBC_2_34);
+ versioned_symbol (libc, ___res_hnok, __libc_res_hnok, GLIBC_PRIVATE);
+diff --git a/resolv/tst-ns_name_length_uncompressed.c b/resolv/tst-ns_name_length_uncompressed.c
+new file mode 100644
+index 0000000000..c4a2904db7
+--- /dev/null
++++ b/resolv/tst-ns_name_length_uncompressed.c
+@@ -0,0 +1,135 @@
++/* Test __ns_name_length_uncompressed.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <array_length.h>
++#include <errno.h>
++#include <stdio.h>
++#include <support/check.h>
++#include <support/next_to_fault.h>
++
++/* Reference implementation based on other building blocks. */
++static int
++reference_length (const unsigned char *p, const unsigned char *eom)
++{
++ unsigned char buf[NS_MAXCDNAME];
++ int n = __ns_name_unpack (p, eom, p, buf, sizeof (buf));
++ if (n < 0)
++ return n;
++ const unsigned char *q = buf;
++ if (__ns_name_skip (&q, array_end (buf)) < 0)
++ return -1;
++ if (q - buf != n)
++ /* Compressed name. */
++ return -1;
++ return n;
++}
++
++static int
++do_test (void)
++{
++ {
++ unsigned char buf[] = { 3, 'w', 'w', 'w', 0, 0, 0 };
++ TEST_COMPARE (reference_length (buf, array_end (buf)), sizeof (buf) - 2);
++ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)),
++ sizeof (buf) - 2);
++ TEST_COMPARE (reference_length (array_end (buf) - 1, array_end (buf)), 1);
++ TEST_COMPARE (__ns_name_length_uncompressed (array_end (buf) - 1,
++ array_end (buf)), 1);
++ buf[4] = 0xc0; /* Forward compression reference. */
++ buf[5] = 0x06;
++ TEST_COMPARE (reference_length (buf, array_end (buf)), -1);
++ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), -1);
++ }
++
++ struct support_next_to_fault ntf = support_next_to_fault_allocate (300);
++
++ /* Buffer region with all possible bytes at start and end. */
++ for (int length = 1; length <= 300; ++length)
++ {
++ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length;
++ unsigned char *start = end - length;
++ memset (start, 'X', length);
++ for (int first = 0; first <= 255; ++first)
++ {
++ *start = first;
++ for (int last = 0; last <= 255; ++last)
++ {
++ start[length - 1] = last;
++ TEST_COMPARE (reference_length (start, end),
++ __ns_name_length_uncompressed (start, end));
++ }
++ }
++ }
++
++ /* Poor man's fuzz testing: patch two bytes. */
++ {
++ unsigned char ref[] =
++ {
++ 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'n', 'e', 't', 0, 0, 0
++ };
++ TEST_COMPARE (reference_length (ref, array_end (ref)), 13);
++ TEST_COMPARE (__ns_name_length_uncompressed (ref, array_end (ref)), 13);
++
++ int good = 0;
++ int bad = 0;
++ for (int length = 1; length <= sizeof (ref); ++length)
++ {
++ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length;
++ unsigned char *start = end - length;
++ memcpy (start, ref, length);
++
++ for (int patch1_pos = 0; patch1_pos < length; ++patch1_pos)
++ {
++ for (int patch1_value = 0; patch1_value <= 255; ++patch1_value)
++ {
++ start[patch1_pos] = patch1_value;
++ for (int patch2_pos = 0; patch2_pos < length; ++patch2_pos)
++ {
++ for (int patch2_value = 0; patch2_value <= 255;
++ ++patch2_value)
++ {
++ start[patch2_pos] = patch2_value;
++ int expected = reference_length (start, end);
++ errno = EINVAL;
++ int actual
++ = __ns_name_length_uncompressed (start, end);
++ if (actual > 0)
++ ++good;
++ else
++ {
++ TEST_COMPARE (errno, EMSGSIZE);
++ ++bad;
++ }
++ TEST_COMPARE (expected, actual);
++ }
++ start[patch2_pos] = ref[patch2_pos];
++ }
++ }
++ start[patch1_pos] = ref[patch1_pos];
++ }
++ }
++ printf ("info: patched inputs with success: %d\n", good);
++ printf ("info: patched inputs with failure: %d\n", bad);
++ }
++
++ support_next_to_fault_free (&ntf);
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/resolv/tst-ns_rr_cursor.c b/resolv/tst-ns_rr_cursor.c
+new file mode 100644
+index 0000000000..c3c0908905
+--- /dev/null
++++ b/resolv/tst-ns_rr_cursor.c
+@@ -0,0 +1,227 @@
++/* Tests for resource record parsing.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/next_to_fault.h>
++
++/* Reference packet for packet parsing. */
++static const unsigned char valid_packet[] =
++ { 0x11, 0x12, 0x13, 0x14,
++ 0x00, 0x01, /* Question count. */
++ 0x00, 0x02, /* Answer count. */
++ 0x21, 0x22, 0x23, 0x24, /* Other counts (not actually in packet). */
++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0,
++ 0x00, 0x1c, /* Question type: AAAA. */
++ 0x00, 0x01, /* Question class: IN. */
++ 0xc0, 0x0c, /* Compression reference to QNAME. */
++ 0x00, 0x1c, /* Record type: AAAA. */
++ 0x00, 0x01, /* Record class: IN. */
++ 0x12, 0x34, 0x56, 0x78, /* Record TTL. */
++ 0x00, 0x10, /* Record data length (16 bytes). */
++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* IPv6 address. */
++ 0xc0, 0x0c, /* Compression reference to QNAME. */
++ 0x00, 0x1c, /* Record type: AAAA. */
++ 0x00, 0x01, /* Record class: IN. */
++ 0x11, 0x33, 0x55, 0x77, /* Record TTL. */
++ 0x00, 0x10, /* Record data length (16 bytes). */
++ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
++ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* IPv6 address. */
++ };
++
++/* Special offsets in valid_packet. */
++enum
++ {
++ offset_of_first_record = 29,
++ offset_of_second_record = 57,
++ };
++
++/* Check that parsing valid_packet succeeds. */
++static void
++test_valid (void)
++{
++ struct ns_rr_cursor c;
++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, valid_packet,
++ sizeof (valid_packet)));
++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
++ TEST_COMPARE (c.current - valid_packet, offset_of_first_record);
++
++ struct ns_rr_wire r;
++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
++ TEST_COMPARE (r.rtype, T_AAAA);
++ TEST_COMPARE (r.rclass, C_IN);
++ TEST_COMPARE (r.ttl, 0x12345678);
++ TEST_COMPARE_BLOB (r.rdata, r.rdlength,
++ "\x90\x91\x92\x93\x94\x95\x96\x97"
++ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16);
++ TEST_COMPARE (c.current - valid_packet, offset_of_second_record);
++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
++ TEST_COMPARE (r.rtype, T_AAAA);
++ TEST_COMPARE (r.rclass, C_IN);
++ TEST_COMPARE (r.ttl, 0x11335577);
++ TEST_COMPARE_BLOB (r.rdata, r.rdlength,
++ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
++ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 16);
++ TEST_VERIFY (c.current == c.end);
++}
++
++/* Check that trying to parse a packet with a compressed QNAME fails. */
++static void
++test_compressed_qname (void)
++{
++ static const unsigned char packet[] =
++ { 0x11, 0x12, 0x13, 0x14,
++ 0x00, 0x01, /* Question count. */
++ 0x00, 0x00, /* Answer count. */
++ 0x00, 0x00, 0x00, 0x00, /* Other counts. */
++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
++ 0x00, 0x01, /* Question type: A. */
++ 0x00, 0x01, /* Question class: IN. */
++ };
++
++ struct ns_rr_cursor c;
++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet)));
++}
++
++/* Check that trying to parse a packet with two questions fails. */
++static void
++test_two_questions (void)
++{
++ static const unsigned char packet[] =
++ { 0x11, 0x12, 0x13, 0x14,
++ 0x00, 0x02, /* Question count. */
++ 0x00, 0x00, /* Answer count. */
++ 0x00, 0x00, 0x00, 0x00, /* Other counts. */
++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
++ 0x00, 0x01, /* Question type: A. */
++ 0x00, 0x01, /* Question class: IN. */
++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
++ 0x00, 0x1c, /* Question type: AAAA. */
++ 0x00, 0x01, /* Question class: IN. */
++ };
++
++ struct ns_rr_cursor c;
++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet)));
++}
++
++/* Used to check that parsing truncated packets does not over-read. */
++static struct support_next_to_fault ntf;
++
++/* Truncated packet in the second resource record. */
++static void
++test_truncated_one_rr (size_t length)
++{
++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
++ unsigned char *start = end - length;
++
++ /* Produce the truncated packet. */
++ memcpy (start, valid_packet, length);
++
++ struct ns_rr_cursor c;
++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length));
++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
++ TEST_COMPARE (c.current - start, offset_of_first_record);
++
++ struct ns_rr_wire r;
++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
++ TEST_COMPARE (r.rtype, T_AAAA);
++ TEST_COMPARE (r.rclass, C_IN);
++ TEST_COMPARE (r.ttl, 0x12345678);
++ TEST_COMPARE_BLOB (r.rdata, r.rdlength,
++ "\x90\x91\x92\x93\x94\x95\x96\x97"
++ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16);
++ TEST_COMPARE (c.current - start, offset_of_second_record);
++ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r));
++}
++
++/* Truncated packet in the first resource record. */
++static void
++test_truncated_no_rr (size_t length)
++{
++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
++ unsigned char *start = end - length;
++
++ /* Produce the truncated packet. */
++ memcpy (start, valid_packet, length);
++
++ struct ns_rr_cursor c;
++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length));
++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
++ TEST_COMPARE (c.current - start, offset_of_first_record);
++
++ struct ns_rr_wire r;
++ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r));
++}
++
++/* Truncated packet before first resource record. */
++static void
++test_truncated_before_rr (size_t length)
++{
++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
++ unsigned char *start = end - length;
++
++ /* Produce the truncated packet. */
++ memcpy (start, valid_packet, length);
++
++ struct ns_rr_cursor c;
++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, start, length));
++}
++
++static int
++do_test (void)
++{
++ ntf = support_next_to_fault_allocate (sizeof (valid_packet));
++
++ test_valid ();
++ test_compressed_qname ();
++ test_two_questions ();
++
++ for (int length = offset_of_second_record; length < sizeof (valid_packet);
++ ++length)
++ test_truncated_one_rr (length);
++ for (int length = offset_of_first_record; length < offset_of_second_record;
++ ++length)
++ test_truncated_no_rr (length);
++ for (int length = 0; length < offset_of_first_record; ++length)
++ test_truncated_before_rr (length);
++
++ support_next_to_fault_free (&ntf);
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/resolv/tst-ns_samebinaryname.c b/resolv/tst-ns_samebinaryname.c
+new file mode 100644
+index 0000000000..b06ac610b4
+--- /dev/null
++++ b/resolv/tst-ns_samebinaryname.c
+@@ -0,0 +1,62 @@
++/* Test the __ns_samebinaryname function.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <array_length.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <support/check.h>
++
++/* First character denotes the comparison group: All names with the
++ same first character are expected to compare equal. */
++static const char *const cases[] =
++ {
++ " ",
++ "1\001a", "1\001A",
++ "2\002ab", "2\002aB", "2\002Ab", "2\002AB",
++ "3\001a\002ab", "3\001A\002ab",
++ "w\003www\007example\003com", "w\003Www\007Example\003Com",
++ "w\003WWW\007EXAMPLE\003COM",
++ "W\003WWW", "W\003www",
++ };
++
++static int
++do_test (void)
++{
++ for (int i = 0; i < array_length (cases); ++i)
++ for (int j = 0; j < array_length (cases); ++j)
++ {
++ unsigned char *a = (unsigned char *) &cases[i][1];
++ unsigned char *b = (unsigned char *) &cases[j][1];
++ bool actual = __ns_samebinaryname (a, b);
++ bool expected = cases[i][0] == cases[j][0];
++ if (actual != expected)
++ {
++ char a1[NS_MAXDNAME];
++ TEST_VERIFY (ns_name_ntop (a, a1, sizeof (a1)) > 0);
++ char b1[NS_MAXDNAME];
++ TEST_VERIFY (ns_name_ntop (b, b1, sizeof (b1)) > 0);
++ printf ("error: \"%s\" \"%s\": expected %s\n",
++ a1, b1, expected ? "equal" : "unqueal");
++ support_record_failure ();
++ }
++ }
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/resolv/tst-resolv-aliases.c b/resolv/tst-resolv-aliases.c
+new file mode 100644
+index 0000000000..b212823aa0
+--- /dev/null
++++ b/resolv/tst-resolv-aliases.c
+@@ -0,0 +1,254 @@
++/* Test alias handling (mainly for gethostbyname).
++ Copyright (C) 2022 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 <array_length.h>
++#include <arpa/inet.h>
++#include <netdb.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/check_nss.h>
++#include <support/resolv_test.h>
++#include <support/support.h>
++
++#include "tst-resolv-maybe_insert_sig.h"
++
++/* QNAME format:
++
++ aADDRESSES-cCNAMES.example.net
++
++ CNAMES is the length of the CNAME chain, ADDRESSES is the number of
++ addresses in the response. The special value 255 means that there
++ are no addresses, and the RCODE is NXDOMAIN. */
++static void
++response (const struct resolv_response_context *ctx,
++ struct resolv_response_builder *b,
++ const char *qname, uint16_t qclass, uint16_t qtype)
++{
++ TEST_COMPARE (qclass, C_IN);
++ if (qtype != T_A)
++ TEST_COMPARE (qtype, T_AAAA);
++
++ unsigned int addresses, cnames;
++ char *tail;
++ if (sscanf (qname, "a%u-c%u%ms", &addresses, &cnames, &tail) == 3)
++ {
++ if (strcmp (tail, ".example.com") == 0
++ || strcmp (tail, ".example.net.example.net") == 0
++ || strcmp (tail, ".example.net.example.com") == 0)
++ /* These only happen after NXDOMAIN. */
++ TEST_VERIFY (addresses == 255);
++ else if (strcmp (tail, ".example.net") != 0)
++ FAIL_EXIT1 ("invalid QNAME: %s", qname);
++ }
++ free (tail);
++
++ int rcode;
++ if (addresses == 255)
++ {
++ /* Special case: Use no addresses with NXDOMAIN response. */
++ rcode = ns_r_nxdomain;
++ addresses = 0;
++ }
++ else
++ rcode = 0;
++
++ struct resolv_response_flags flags = { .rcode = rcode };
++ resolv_response_init (b, flags);
++ resolv_response_add_question (b, qname, qclass, qtype);
++ resolv_response_section (b, ns_s_an);
++ maybe_insert_sig (b, qname);
++
++ /* Provide the requested number of CNAME records. */
++ char *previous_name = (char *) qname;
++ for (int unique = 0; unique < cnames; ++unique)
++ {
++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
++ char *new_name = xasprintf ("%d.alias.example", unique);
++ resolv_response_add_name (b, new_name);
++ resolv_response_close_record (b);
++
++ maybe_insert_sig (b, qname);
++
++ if (previous_name != qname)
++ free (previous_name);
++ previous_name = new_name;
++ }
++
++ for (int unique = 0; unique < addresses; ++unique)
++ {
++ resolv_response_open_record (b, previous_name, qclass, qtype, 60);
++
++ if (qtype == T_A)
++ {
++ char ipv4[4] = {192, 0, 2, 1 + unique};
++ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
++ }
++ else if (qtype == T_AAAA)
++ {
++ char ipv6[16] =
++ {
++ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 1 + unique
++ };
++ resolv_response_add_data (b, &ipv6, sizeof (ipv6));
++ }
++ resolv_response_close_record (b);
++ }
++
++ if (previous_name != qname)
++ free (previous_name);
++}
++
++static char *
++make_qname (bool do_search, int cnames, int addresses)
++{
++ return xasprintf ("a%d-c%d%s",
++ addresses, cnames, do_search ? "" : ".example.net");
++}
++
++static void
++check_cnames_failure (int af, bool do_search, int cnames, int addresses)
++{
++ char *qname = make_qname (do_search, cnames, addresses);
++
++ struct hostent *e;
++ if (af == AF_UNSPEC)
++ e = gethostbyname (qname);
++ else
++ e = gethostbyname2 (qname, af);
++
++ if (addresses == 0)
++ check_hostent (qname, e, "error: NO_RECOVERY\n");
++ else
++ check_hostent (qname, e, "error: HOST_NOT_FOUND\n");
++
++ free (qname);
++}
++
++static void
++check (int af, bool do_search, int cnames, int addresses)
++{
++ char *qname = make_qname (do_search, cnames, addresses);
++ char *fqdn = make_qname (false, cnames, addresses);
++
++ struct hostent *e;
++ if (af == AF_UNSPEC)
++ e = gethostbyname (qname);
++ else
++ e = gethostbyname2 (qname, af);
++ if (e == NULL)
++ FAIL_EXIT1 ("unexpected failure for %d, %d, %d", af, cnames, addresses);
++
++ if (af == AF_UNSPEC || af == AF_INET)
++ {
++ TEST_COMPARE (e->h_addrtype, AF_INET);
++ TEST_COMPARE (e->h_length, 4);
++ }
++ else
++ {
++ TEST_COMPARE (e->h_addrtype, AF_INET6);
++ TEST_COMPARE (e->h_length, 16);
++ }
++
++ for (int i = 0; i < addresses; ++i)
++ {
++ char ipv4[4] = {192, 0, 2, 1 + i};
++ char ipv6[16] =
++ { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + i };
++ char *expected = e->h_addrtype == AF_INET ? ipv4 : ipv6;
++ TEST_COMPARE_BLOB (e->h_addr_list[i], e->h_length,
++ expected, e->h_length);
++ }
++ TEST_VERIFY (e->h_addr_list[addresses] == NULL);
++
++
++ if (cnames == 0)
++ {
++ /* QNAME is fully qualified. */
++ TEST_COMPARE_STRING (e->h_name, fqdn);
++ TEST_VERIFY (e->h_aliases[0] == NULL);
++ }
++ else
++ {
++ /* Fully-qualified QNAME is demoted to an aliases. */
++ TEST_COMPARE_STRING (e->h_aliases[0], fqdn);
++
++ for (int i = 1; i <= cnames; ++i)
++ {
++ char *expected = xasprintf ("%d.alias.example", i - 1);
++ if (i == cnames)
++ TEST_COMPARE_STRING (e->h_name, expected);
++ else
++ TEST_COMPARE_STRING (e->h_aliases[i], expected);
++ free (expected);
++ }
++ TEST_VERIFY (e->h_aliases[cnames] == NULL);
++ }
++
++ free (fqdn);
++ free (qname);
++}
++
++static int
++do_test (void)
++{
++ struct resolv_test *obj = resolv_test_start
++ ((struct resolv_redirect_config)
++ {
++ .response_callback = response,
++ .search = { "example.net", "example.com" },
++ });
++
++ static const int families[] = { AF_UNSPEC, AF_INET, AF_INET6 };
++
++ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig)
++ {
++ insert_sig = do_insert_sig;
++
++ /* If do_search is true, a bare host name (for example, a1-c1)
++ is used. This exercises search path processing and FQDN
++ qualification. */
++ for (int do_search = 0; do_search < 2; ++do_search)
++ for (const int *paf = families; paf != array_end (families); ++paf)
++ {
++ for (int cnames = 0; cnames <= 100; ++cnames)
++ {
++ check_cnames_failure (*paf, do_search, cnames, 0);
++ /* Now with NXDOMAIN responses. */
++ check_cnames_failure (*paf, do_search, cnames, 255);
++ }
++
++ for (int cnames = 0; cnames <= 10; ++cnames)
++ for (int addresses = 1; addresses <= 10; ++addresses)
++ check (*paf, do_search, cnames, addresses);
++
++ /* The current implementation is limited to 47 aliases.
++ Addresses do not have such a limit. */
++ check (*paf, do_search, 47, 60);
++ }
++ }
++
++ resolv_test_end (obj);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/resolv/tst-resolv-byaddr.c b/resolv/tst-resolv-byaddr.c
+new file mode 100644
+index 0000000000..6299e89837
+--- /dev/null
++++ b/resolv/tst-resolv-byaddr.c
+@@ -0,0 +1,326 @@
++/* Test reverse DNS lookup.
++ Copyright (C) 2022 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 <arpa/inet.h>
++#include <errno.h>
++#include <netdb.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/check_nss.h>
++#include <support/next_to_fault.h>
++#include <support/resolv_test.h>
++#include <support/support.h>
++
++#include "tst-resolv-maybe_insert_sig.h"
++
++/* QNAME format:
++
++ ADDRESSES.CNAMES...(lots of 0s)...8.b.d.0.1.0.0.2.ip6.arpa.
++ CNAMES|ADDRESSES.2.0.192.in-addr-arpa.
++
++ For the IPv4 reverse lookup, the address count is in the lower
++ bits.
++
++ CNAMES is the length of the CNAME chain, ADDRESSES is the number of
++ addresses in the response. The special value 15 means that there
++ are no addresses, and the RCODE is NXDOMAIN. */
++static void
++response (const struct resolv_response_context *ctx,
++ struct resolv_response_builder *b,
++ const char *qname, uint16_t qclass, uint16_t qtype)
++{
++ TEST_COMPARE (qclass, C_IN);
++ TEST_COMPARE (qtype, T_PTR);
++
++ unsigned int addresses, cnames, bits;
++ char *tail;
++ if (strstr (qname, "ip6.arpa") != NULL
++ && sscanf (qname, "%x.%x.%ms", &addresses, &cnames, &tail) == 3)
++ TEST_COMPARE_STRING (tail, "\
++0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
++ else if (sscanf (qname, "%u.%ms", &bits, &tail) == 2)
++ {
++ TEST_COMPARE_STRING (tail, "2.0.192.in-addr.arpa");
++ addresses = bits & 0x0f;
++ cnames = bits >> 4;
++ }
++ else
++ FAIL_EXIT1 ("invalid QNAME: %s", qname);
++ free (tail);
++
++ int rcode;
++ if (addresses == 15)
++ {
++ /* Special case: Use no addresses with NXDOMAIN response. */
++ rcode = ns_r_nxdomain;
++ addresses = 0;
++ }
++ else
++ rcode = 0;
++
++ struct resolv_response_flags flags = { .rcode = rcode };
++ resolv_response_init (b, flags);
++ resolv_response_add_question (b, qname, qclass, qtype);
++ resolv_response_section (b, ns_s_an);
++ maybe_insert_sig (b, qname);
++
++ /* Provide the requested number of CNAME records. */
++ char *previous_name = (char *) qname;
++ for (int unique = 0; unique < cnames; ++unique)
++ {
++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
++ char *new_name = xasprintf ("%d.alias.example", unique);
++ resolv_response_add_name (b, new_name);
++ resolv_response_close_record (b);
++
++ maybe_insert_sig (b, qname);
++
++ if (previous_name != qname)
++ free (previous_name);
++ previous_name = new_name;
++ }
++
++ for (int unique = 0; unique < addresses; ++unique)
++ {
++ resolv_response_open_record (b, previous_name, qclass, T_PTR, 60);
++ char *ptr = xasprintf ("unique-%d.cnames-%u.addresses-%u.example",
++ unique, cnames, addresses);
++ resolv_response_add_name (b, ptr);
++ free (ptr);
++ resolv_response_close_record (b);
++ }
++
++ if (previous_name != qname)
++ free (previous_name);
++}
++
++/* Used to check that gethostbyaddr_r does not write past the buffer
++ end. */
++static struct support_next_to_fault ntf;
++
++/* Perform a gethostbyaddr call and check the result. */
++static void
++check_gethostbyaddr (const char *address, const char *expected)
++{
++ unsigned char bytes[16];
++ unsigned int byteslen;
++ int family;
++ if (strchr (address, ':') != NULL)
++ {
++ family = AF_INET6;
++ byteslen = 16;
++ }
++ else
++ {
++ family = AF_INET;
++ byteslen = 4;
++ }
++ TEST_COMPARE (inet_pton (family, address, bytes), 1);
++
++ struct hostent *e = gethostbyaddr (bytes, byteslen, family);
++ check_hostent (address, e, expected);
++
++ if (e == NULL)
++ return;
++
++ /* Try gethostbyaddr_r with increasing sizes until success. First
++ compute a reasonable minimum buffer size, to avoid many pointless
++ attempts. */
++ size_t minimum_size = strlen (e->h_name);
++ for (int i = 0; e->h_addr_list[i] != NULL; ++i)
++ minimum_size += e->h_length + sizeof (char *);
++ for (int i = 0; e->h_aliases[i] != NULL; ++i)
++ minimum_size += strlen (e->h_aliases[i]) + 1 + sizeof (char *);
++
++ /* Gradually increase the size until success. */
++ for (size_t size = minimum_size; size < ntf.length; ++size)
++ {
++ struct hostent result;
++ int herrno;
++ int ret = gethostbyaddr_r (bytes, byteslen, family, &result,
++ ntf.buffer + ntf.length - size, size,
++ &e, &herrno);
++ if (ret == ERANGE)
++ /* Retry with larger size. */
++ TEST_COMPARE (herrno, NETDB_INTERNAL);
++ else if (ret == 0)
++ {
++ TEST_VERIFY (size > minimum_size);
++ check_hostent (address, e, expected);
++ return;
++ }
++ else
++ FAIL_EXIT1 ("Unexpected gethostbyaddr_r failure: %d", ret);
++ }
++
++ FAIL_EXIT1 ("gethostbyaddr_r always failed for: %s", address);
++}
++
++/* Perform a getnameinfo call and check the result. */
++static void
++check_getnameinfo (const char *address, const char *expected)
++{
++ struct sockaddr_in sin = { };
++ struct sockaddr_in6 sin6 = { };
++ void *sa;
++ socklen_t salen;
++ if (strchr (address, ':') != NULL)
++ {
++ sin6.sin6_family = AF_INET6;
++ TEST_COMPARE (inet_pton (AF_INET6, address, &sin6.sin6_addr), 1);
++ sin6.sin6_port = htons (80);
++ sa = &sin6;
++ salen = sizeof (sin6);
++ }
++ else
++ {
++ sin.sin_family = AF_INET;
++ TEST_COMPARE (inet_pton (AF_INET, address, &sin.sin_addr), 1);
++ sin.sin_port = htons (80);
++ sa = &sin;
++ salen = sizeof (sin);
++ }
++
++ char host[64];
++ char service[64];
++ int ret = getnameinfo (sa, salen, host,
++ sizeof (host), service, sizeof (service),
++ NI_NAMEREQD | NI_NUMERICSERV);
++ switch (ret)
++ {
++ case 0:
++ TEST_COMPARE_STRING (host, expected);
++ TEST_COMPARE_STRING (service, "80");
++ break;
++ case EAI_SYSTEM:
++ TEST_COMPARE_STRING (strerror (errno), expected);
++ break;
++ default:
++ TEST_COMPARE_STRING (gai_strerror (ret), expected);
++ }
++}
++
++static int
++do_test (void)
++{
++ /* Some reasonably upper bound for the maximum response size. */
++ ntf = support_next_to_fault_allocate (4096);
++
++ struct resolv_test *obj = resolv_test_start
++ ((struct resolv_redirect_config)
++ {
++ .response_callback = response
++ });
++
++ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig)
++ {
++ insert_sig = do_insert_sig;
++
++ /* No PTR record, RCODE=0. */
++ check_gethostbyaddr ("192.0.2.0", "error: NO_RECOVERY\n");
++ check_getnameinfo ("192.0.2.0", "Name or service not known");
++ check_gethostbyaddr ("192.0.2.16", "error: NO_RECOVERY\n");
++ check_getnameinfo ("192.0.2.16", "Name or service not known");
++ check_gethostbyaddr ("192.0.2.32", "error: NO_RECOVERY\n");
++ check_getnameinfo ("192.0.2.32", "Name or service not known");
++ check_gethostbyaddr ("2001:db8::", "error: NO_RECOVERY\n");
++ check_getnameinfo ("2001:db8::", "Name or service not known");
++ check_gethostbyaddr ("2001:db8::10", "error: NO_RECOVERY\n");
++ check_getnameinfo ("2001:db8::10", "Name or service not known");
++ check_gethostbyaddr ("2001:db8::20", "error: NO_RECOVERY\n");
++ check_getnameinfo ("2001:db8::20", "Name or service not known");
++
++ /* No PTR record, NXDOMAIN. */
++ check_gethostbyaddr ("192.0.2.15", "error: HOST_NOT_FOUND\n");
++ check_getnameinfo ("192.0.2.15", "Name or service not known");
++ check_gethostbyaddr ("192.0.2.31", "error: HOST_NOT_FOUND\n");
++ check_getnameinfo ("192.0.2.31", "Name or service not known");
++ check_gethostbyaddr ("192.0.2.47", "error: HOST_NOT_FOUND\n");
++ check_getnameinfo ("192.0.2.47", "Name or service not known");
++ check_gethostbyaddr ("2001:db8::f", "error: HOST_NOT_FOUND\n");
++ check_getnameinfo ("2001:db8::f", "Name or service not known");
++ check_gethostbyaddr ("2001:db8::1f", "error: HOST_NOT_FOUND\n");
++ check_getnameinfo ("2001:db8::1f", "Name or service not known");
++ check_gethostbyaddr ("2001:db8::2f", "error: HOST_NOT_FOUND\n");
++ check_getnameinfo ("2001:db8::2f", "Name or service not known");
++
++ /* Actual response data. Only the first PTR record is returned. */
++ check_gethostbyaddr ("192.0.2.1",
++ "name: unique-0.cnames-0.addresses-1.example\n"
++ "address: 192.0.2.1\n");
++ check_getnameinfo ("192.0.2.1",
++ "unique-0.cnames-0.addresses-1.example");
++ check_gethostbyaddr ("192.0.2.17",
++ "name: unique-0.cnames-1.addresses-1.example\n"
++ "address: 192.0.2.17\n");
++ check_getnameinfo ("192.0.2.17",
++ "unique-0.cnames-1.addresses-1.example");
++ check_gethostbyaddr ("192.0.2.18",
++ "name: unique-0.cnames-1.addresses-2.example\n"
++ "address: 192.0.2.18\n");
++ check_getnameinfo ("192.0.2.18",
++ "unique-0.cnames-1.addresses-2.example");
++ check_gethostbyaddr ("192.0.2.33",
++ "name: unique-0.cnames-2.addresses-1.example\n"
++ "address: 192.0.2.33\n");
++ check_getnameinfo ("192.0.2.33",
++ "unique-0.cnames-2.addresses-1.example");
++ check_gethostbyaddr ("192.0.2.34",
++ "name: unique-0.cnames-2.addresses-2.example\n"
++ "address: 192.0.2.34\n");
++ check_getnameinfo ("192.0.2.34",
++ "unique-0.cnames-2.addresses-2.example");
++
++ /* Same for IPv6 addresses. */
++ check_gethostbyaddr ("2001:db8::1",
++ "name: unique-0.cnames-0.addresses-1.example\n"
++ "address: 2001:db8::1\n");
++ check_getnameinfo ("2001:db8::1",
++ "unique-0.cnames-0.addresses-1.example");
++ check_gethostbyaddr ("2001:db8::11",
++ "name: unique-0.cnames-1.addresses-1.example\n"
++ "address: 2001:db8::11\n");
++ check_getnameinfo ("2001:db8::11",
++ "unique-0.cnames-1.addresses-1.example");
++ check_gethostbyaddr ("2001:db8::12",
++ "name: unique-0.cnames-1.addresses-2.example\n"
++ "address: 2001:db8::12\n");
++ check_getnameinfo ("2001:db8::12",
++ "unique-0.cnames-1.addresses-2.example");
++ check_gethostbyaddr ("2001:db8::21",
++ "name: unique-0.cnames-2.addresses-1.example\n"
++ "address: 2001:db8::21\n");
++ check_getnameinfo ("2001:db8::21",
++ "unique-0.cnames-2.addresses-1.example");
++ check_gethostbyaddr ("2001:db8::22",
++ "name: unique-0.cnames-2.addresses-2.example\n"
++ "address: 2001:db8::22\n");
++ check_getnameinfo ("2001:db8::22",
++ "unique-0.cnames-2.addresses-2.example");
++ }
++
++ resolv_test_end (obj);
++
++ support_next_to_fault_free (&ntf);
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/resolv/tst-resolv-invalid-cname.c b/resolv/tst-resolv-invalid-cname.c
+new file mode 100644
+index 0000000000..63dac90e02
+--- /dev/null
++++ b/resolv/tst-resolv-invalid-cname.c
+@@ -0,0 +1,406 @@
++/* Test handling of CNAMEs with non-host domain names (bug 12154).
++ Copyright (C) 2022 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 <stdlib.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/check_nss.h>
++#include <support/resolv_test.h>
++#include <support/support.h>
++#include <support/xmemstream.h>
++
++/* Query strings describe the CNAME chain in the response. They have
++ the format "bitsBITS.countCOUNT.example.", where BITS and COUNT are
++ replaced by unsigned decimal numbers. COUNT is the number of CNAME
++ records in the response. BITS has two bits for each CNAME record,
++ describing a special prefix that is added to that CNAME.
++
++ 0: No special leading label.
++ 1: Starting with "*.".
++ 2: Starting with "-x.".
++ 3: Starting with "star.*.".
++
++ The first CNAME in the response using the two least significant
++ bits.
++
++ For PTR queries, the QNAME format is different, it is either
++ COUNT.BITS.168.192.in-addr.arpa. (with BITS and COUNT still
++ decimal), or:
++
++COUNT.BITS0.BITS1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
++
++ where BITS and COUNT are hexadecimal. */
++
++static void
++response (const struct resolv_response_context *ctx,
++ struct resolv_response_builder *b,
++ const char *qname, uint16_t qclass, uint16_t qtype)
++{
++ TEST_COMPARE (qclass, C_IN);
++
++ /* The only other query type besides A is PTR. */
++ if (qtype != T_A && qtype != T_AAAA)
++ TEST_COMPARE (qtype, T_PTR);
++
++ unsigned int bits, bits1, count;
++ char *tail = NULL;
++ if (sscanf (qname, "bits%u.count%u.%ms", &bits, &count, &tail) == 3)
++ TEST_COMPARE_STRING (tail, "example");
++ else if (strstr (qname, "in-addr.arpa") != NULL
++ && sscanf (qname, "%u.%u.%ms", &bits, &count, &tail) == 3)
++ TEST_COMPARE_STRING (tail, "168.192.in-addr.arpa");
++ else if (sscanf (qname, "%x.%x.%x.%ms", &bits, &bits1, &count, &tail) == 4)
++ {
++ TEST_COMPARE_STRING (tail, "\
++0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
++ bits |= bits1 << 4;
++ }
++ else
++ FAIL_EXIT1 ("invalid QNAME: %s\n", qname);
++ free (tail);
++
++ 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);
++
++ /* Provide the requested number of CNAME records. */
++ char *previous_name = (char *) qname;
++ unsigned int original_bits = bits;
++ for (int unique = 0; unique < count; ++unique)
++ {
++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
++
++ static const char bits_to_prefix[4][8] = { "", "*.", "-x.", "star.*." };
++ char *new_name = xasprintf ("%sunique%d.example",
++ bits_to_prefix[bits & 3], unique);
++ bits >>= 2;
++ resolv_response_add_name (b, new_name);
++ resolv_response_close_record (b);
++
++ if (previous_name != qname)
++ free (previous_name);
++ previous_name = new_name;
++ }
++
++ /* Actual answer record. */
++ resolv_response_open_record (b, previous_name, qclass, qtype, 60);
++ switch (qtype)
++ {
++ case T_A:
++ {
++ char ipv4[4] = {192, 168, count, original_bits};
++ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
++ }
++ break;
++ case T_AAAA:
++ {
++ char ipv6[16] =
++ {
++ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ count, original_bits
++ };
++ resolv_response_add_data (b, &ipv6, sizeof (ipv6));
++ }
++ break;
++
++ case T_PTR:
++ {
++ char *name = xasprintf ("bits%u.count%u.example",
++ original_bits, count);
++ resolv_response_add_name (b, name);
++ free (name);
++ }
++ break;
++ }
++ resolv_response_close_record (b);
++
++ if (previous_name != qname)
++ free (previous_name);
++}
++
++/* Controls which name resolution function is invoked. */
++enum test_mode
++ {
++ byname, /* gethostbyname. */
++ byname2, /* gethostbyname2. */
++ gai, /* getaddrinfo without AI_CANONNAME. */
++ gai_canon, /* getaddrinfo with AI_CANONNAME. */
++
++ test_mode_num /* Number of enum values. */
++ };
++
++static const char *
++test_mode_to_string (enum test_mode mode)
++{
++ switch (mode)
++ {
++ case byname:
++ return "byname";
++ case byname2:
++ return "byname2";
++ case gai:
++ return "gai";
++ case gai_canon:
++ return "gai_canon";
++ case test_mode_num:
++ break; /* Report error below. */
++ }
++ FAIL_EXIT1 ("invalid test_mode: %d", mode);
++}
++
++/* Append the name and aliases to OUT. */
++static void
++append_names (FILE *out, const char *qname, int bits, int count,
++ enum test_mode mode)
++{
++ /* Largest valid index which has a corresponding zero in bits
++ (meaning a syntactically valid CNAME). */
++ int last_valid_cname = -1;
++
++ for (int i = 0; i < count; ++i)
++ if ((bits & (3 << (i * 2))) == 0)
++ last_valid_cname = i;
++
++ if (mode != gai)
++ {
++ const char *label;
++ if (mode == gai_canon)
++ label = "canonname";
++ else
++ label = "name";
++ if (last_valid_cname >= 0)
++ fprintf (out, "%s: unique%d.example\n", label, last_valid_cname);
++ else
++ fprintf (out, "%s: %s\n", label, qname);
++ }
++
++ if (mode == byname || mode == byname2)
++ {
++ if (last_valid_cname >= 0)
++ fprintf (out, "alias: %s\n", qname);
++ for (int i = 0; i < count; ++i)
++ {
++ if ((bits & (3 << (i * 2))) == 0 && i != last_valid_cname)
++ fprintf (out, "alias: unique%d.example\n", i);
++ }
++ }
++}
++
++/* Append the address information to OUT. */
++static void
++append_addresses (FILE *out, int af, int bits, int count, enum test_mode mode)
++{
++ int last = count * 256 + bits;
++ if (mode == gai || mode == gai_canon)
++ {
++ if (af == AF_INET || af == AF_UNSPEC)
++ fprintf (out, "address: STREAM/TCP 192.168.%d.%d 80\n", count, bits);
++ if (af == AF_INET6 || af == AF_UNSPEC)
++ {
++ if (last == 0)
++ fprintf (out, "address: STREAM/TCP 2001:db8:: 80\n");
++ else
++ fprintf (out, "address: STREAM/TCP 2001:db8::%x 80\n", last);
++ }
++ }
++ else
++ {
++ TEST_VERIFY (af != AF_UNSPEC);
++ if (af == AF_INET)
++ fprintf (out, "address: 192.168.%d.%d\n", count, bits);
++ if (af == AF_INET6)
++ {
++ if (last == 0)
++ fprintf (out, "address: 2001:db8::\n");
++ else
++ fprintf (out, "address: 2001:db8::%x\n", last);
++ }
++ }
++}
++
++/* Perform one test using a forward lookup. */
++static void
++check_forward (int af, int bits, int count, enum test_mode mode)
++{
++ char *qname = xasprintf ("bits%d.count%d.example", bits, count);
++ char *label = xasprintf ("af=%d bits=%d count=%d mode=%s qname=%s",
++ af, bits, count, test_mode_to_string (mode), qname);
++
++ struct xmemstream expected;
++ xopen_memstream (&expected);
++ if (mode == gai_canon)
++ fprintf (expected.out, "flags: AI_CANONNAME\n");
++ append_names (expected.out, qname, bits, count, mode);
++ append_addresses (expected.out, af, bits, count, mode);
++ xfclose_memstream (&expected);
++
++ if (mode == gai || mode == gai_canon)
++ {
++ struct addrinfo *ai;
++ struct addrinfo hints =
++ {
++ .ai_family = af,
++ .ai_socktype = SOCK_STREAM,
++ };
++ if (mode == gai_canon)
++ hints.ai_flags |= AI_CANONNAME;
++ int ret = getaddrinfo (qname, "80", &hints, &ai);
++ check_addrinfo (label, ai, ret, expected.buffer);
++ if (ret == 0)
++ freeaddrinfo (ai);
++ }
++ else
++ {
++ struct hostent *e;
++ if (mode == gai)
++ {
++ TEST_COMPARE (af, AF_INET);
++ e = gethostbyname (qname);
++ }
++ else
++ {
++ if (af != AF_INET)
++ TEST_COMPARE (af, AF_INET6);
++ e = gethostbyname2 (qname, af);
++ }
++ check_hostent (label, e, expected.buffer);
++ }
++
++ free (expected.buffer);
++ free (label);
++ free (qname);
++}
++
++/* Perform one check using a reverse lookup. */
++
++static void
++check_reverse (int af, int bits, int count)
++{
++ TEST_VERIFY (af == AF_INET || af == AF_INET6);
++
++ char *label = xasprintf ("af=%d bits=%d count=%d", af, bits, count);
++ char *fqdn = xasprintf ("bits%d.count%d.example", bits, count);
++
++ struct xmemstream expected;
++ xopen_memstream (&expected);
++ fprintf (expected.out, "name: %s\n", fqdn);
++ append_addresses (expected.out, af, bits, count, byname);
++ xfclose_memstream (&expected);
++
++ char addr[16] = { 0 };
++ socklen_t addrlen;
++ if (af == AF_INET)
++ {
++ addr[0] = 192;
++ addr[1] = 168;
++ addr[2] = count;
++ addr[3] = bits;
++ addrlen = 4;
++ }
++ else
++ {
++ addr[0] = 0x20;
++ addr[1] = 0x01;
++ addr[2] = 0x0d;
++ addr[3] = 0xb8;
++ addr[14] = count;
++ addr[15] = bits;
++ addrlen = 16;
++ }
++
++ struct hostent *e = gethostbyaddr (addr, addrlen, af);
++ check_hostent (label, e, expected.buffer);
++
++ /* getnameinfo check is different. There is no generic check_*
++ function for it. */
++ {
++ struct sockaddr_in sin = { };
++ struct sockaddr_in6 sin6 = { };
++ void *sa;
++ socklen_t salen;
++ if (af == AF_INET)
++ {
++ sin.sin_family = AF_INET;
++ memcpy (&sin.sin_addr, addr, addrlen);
++ sin.sin_port = htons (80);
++ sa = &sin;
++ salen = sizeof (sin);
++ }
++ else
++ {
++ sin6.sin6_family = AF_INET6;
++ memcpy (&sin6.sin6_addr, addr, addrlen);
++ sin6.sin6_port = htons (80);
++ sa = &sin6;
++ salen = sizeof (sin6);
++ }
++
++ char host[64];
++ char service[64];
++ int ret = getnameinfo (sa, salen, host,
++ sizeof (host), service, sizeof (service),
++ NI_NAMEREQD | NI_NUMERICSERV);
++ TEST_COMPARE (ret, 0);
++ TEST_COMPARE_STRING (host, fqdn);
++ TEST_COMPARE_STRING (service, "80");
++ }
++
++ free (expected.buffer);
++ free (fqdn);
++ free (label);
++}
++
++static int
++do_test (void)
++{
++ struct resolv_test *obj = resolv_test_start
++ ((struct resolv_redirect_config)
++ {
++ .response_callback = response
++ });
++
++ for (int count = 0; count <= 3; ++count)
++ for (int bits = 0; bits <= 1 << (count * 2); ++bits)
++ {
++ if (count > 0 && bits == count)
++ /* The last bits value is only checked if count == 0. */
++ continue;
++
++ for (enum test_mode mode = 0; mode < test_mode_num; ++mode)
++ {
++ check_forward (AF_INET, bits, count, mode);
++ if (mode != byname)
++ check_forward (AF_INET6, bits, count, mode);
++ if (mode == gai || mode == gai_canon)
++ check_forward (AF_UNSPEC, bits, count, mode);
++ }
++
++ check_reverse (AF_INET, bits, count);
++ check_reverse (AF_INET6, bits, count);
++ }
++
++ resolv_test_end (obj);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/resolv/tst-resolv-maybe_insert_sig.h b/resolv/tst-resolv-maybe_insert_sig.h
+new file mode 100644
+index 0000000000..05725225af
+--- /dev/null
++++ b/resolv/tst-resolv-maybe_insert_sig.h
+@@ -0,0 +1,32 @@
++/* Code snippet for optionally inserting ignored SIG records in resolver tests.
++ Copyright (C) 2022 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/>. */
++
++/* Set to true for an alternative pass that inserts (ignored) SIG
++ records. This does not alter the response, so this property is not
++ encoded in the QNAME. The variable needs to be volatile because
++ leaf attributes tell GCC that the response function is not
++ called. */
++static volatile bool insert_sig;
++
++static void
++maybe_insert_sig (struct resolv_response_builder *b, const char *owner)
++{
++ resolv_response_open_record (b, owner, C_IN, T_SIG, 60);
++ resolv_response_add_data (b, "", 1);
++ resolv_response_close_record (b);
++}
+diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
+index 2dd6bfda18..b87cf2f809 100644
+--- a/scripts/dso-ordering-test.py
++++ b/scripts/dso-ordering-test.py
+@@ -707,13 +707,12 @@ def process_testcase(t):
+ "\t$(compile.c) $(OUTPUT_OPTION)\n")
+ makefile.write (rule)
+
+- not_depended_objs = find_objs_not_depended_on(test_descr)
+- if not_depended_objs:
+- depstr = ""
+- for dep in not_depended_objs:
+- depstr += (" $(objpfx)" + test_subdir + "/"
+- + test_name + "-" + dep + ".so")
+- makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr))
++ # Ensure that all shared objects are built before running the
++ # test, whether there link-time dependencies or not.
++ depobjs = ["$(objpfx){}/{}-{}.so".format(test_subdir, test_name, dep)
++ for dep in test_descr.objs]
++ makefile.write("$(objpfx){}.out: {}\n".format(
++ base_test_name, " ".join(depobjs)))
+
+ # Add main executable to test-srcs
+ makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name))
+diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
+index 43ab58ffe2..36d204c9b0 100644
+--- a/scripts/glibcextract.py
++++ b/scripts/glibcextract.py
+@@ -17,6 +17,7 @@
+ # License along with the GNU C Library; if not, see
+ # <https://www.gnu.org/licenses/>.
+
++import collections
+ import os.path
+ import re
+ import subprocess
+@@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None,
+ if not allow_extra_2:
+ ret = 1
+ return ret
++
++CompileResult = collections.namedtuple("CompileResult", "returncode output")
++
++def compile_c_snippet(snippet, cc, extra_cc_args=''):
++ """Compile and return whether the SNIPPET can be build with CC along
++ EXTRA_CC_ARGS compiler flags. Return a CompileResult with RETURNCODE
++ being 0 for success, or the failure value and the compiler output.
++ """
++ with tempfile.TemporaryDirectory() as temp_dir:
++ c_file_name = os.path.join(temp_dir, 'test.c')
++ obj_file_name = os.path.join(temp_dir, 'test.o')
++ with open(c_file_name, 'w') as c_file:
++ c_file.write(snippet + '\n')
++ cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name,
++ c_file_name]
++ r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE,
++ stderr=subprocess.STDOUT)
++ return CompileResult(r.returncode, r.stdout)
+diff --git a/socket/Makefile b/socket/Makefile
+index 156eec6c85..2bde78387f 100644
+--- a/socket/Makefile
++++ b/socket/Makefile
+@@ -34,6 +34,7 @@ routines := accept bind connect getpeername getsockname getsockopt \
+ tests := \
+ tst-accept4 \
+ tst-sockopt \
++ tst-cmsghdr \
+ # tests
+
+ tests-internal := \
+diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c
+new file mode 100644
+index 0000000000..4c6898569b
+--- /dev/null
++++ b/socket/tst-cmsghdr-skeleton.c
+@@ -0,0 +1,92 @@
++/* Test ancillary data header creation.
++ Copyright (C) 2022 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/>. */
++
++/* We use the preprocessor to generate the function/macro tests instead of
++ using indirection because having all the macro expansions alongside
++ each other lets the compiler warn us about suspicious pointer
++ arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions. */
++
++#include <stdint.h>
++
++#define RUN_TEST_CONCAT(suffix) run_test_##suffix
++#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix)
++
++static void
++RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void)
++{
++ struct msghdr m = {0};
++ struct cmsghdr *cmsg;
++ char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0};
++
++ m.msg_control = cmsgbuf;
++ m.msg_controllen = sizeof (cmsgbuf);
++
++ /* First header should point to the start of the buffer. */
++ cmsg = CMSG_FIRSTHDR (&m);
++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
++
++ /* If the first header length consumes the entire buffer, there is no
++ space remaining for additional headers. */
++ cmsg->cmsg_len = sizeof (cmsgbuf);
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg == NULL);
++
++ /* The first header length is so big, using it would cause an overflow. */
++ cmsg = CMSG_FIRSTHDR (&m);
++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
++ cmsg->cmsg_len = SIZE_MAX;
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg == NULL);
++
++ /* The first header leaves just enough space to hold another header. */
++ cmsg = CMSG_FIRSTHDR (&m);
++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
++ cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr);
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg != NULL);
++
++ /* The first header leaves space but not enough for another header. */
++ cmsg = CMSG_FIRSTHDR (&m);
++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
++ cmsg->cmsg_len ++;
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg == NULL);
++
++ /* The second header leaves just enough space to hold another header. */
++ cmsg = CMSG_FIRSTHDR (&m);
++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
++ cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD));
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg != NULL);
++ cmsg->cmsg_len = sizeof (cmsgbuf)
++ - CMSG_SPACE (sizeof (PAYLOAD)) /* First header. */
++ - sizeof (struct cmsghdr);
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg != NULL);
++
++ /* The second header leaves space but not enough for another header. */
++ cmsg = CMSG_FIRSTHDR (&m);
++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg != NULL);
++ cmsg->cmsg_len ++;
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg == NULL);
++
++ return;
++}
+diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c
+new file mode 100644
+index 0000000000..68c96d3c9d
+--- /dev/null
++++ b/socket/tst-cmsghdr.c
+@@ -0,0 +1,56 @@
++/* Test ancillary data header creation.
++ Copyright (C) 2022 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 <sys/socket.h>
++#include <gnu/lib-names.h>
++#include <support/xdlfcn.h>
++#include <support/check.h>
++
++#define PAYLOAD "Hello, World!"
++
++/* CMSG_NXTHDR is a macro that calls an inline function defined in
++ bits/socket.h. In case the function cannot be inlined, libc.so carries
++ a copy. Both versions need to be tested. */
++
++#define CMSG_NXTHDR_IMPL CMSG_NXTHDR
++#include "tst-cmsghdr-skeleton.c"
++#undef CMSG_NXTHDR_IMPL
++
++static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *);
++
++#define CMSG_NXTHDR_IMPL cmsg_nxthdr
++#include "tst-cmsghdr-skeleton.c"
++#undef CMSG_NXTHDR_IMPL
++
++static int
++do_test (void)
++{
++ static void *handle;
++
++ run_test_CMSG_NXTHDR ();
++
++ handle = xdlopen (LIBC_SO, RTLD_LAZY);
++ cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *))
++ xdlsym (handle, "__cmsg_nxthdr");
++
++ run_test_cmsg_nxthdr ();
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/stdlib/arc4random.c b/stdlib/arc4random.c
+index e417ef624d..960a38f295 100644
+--- a/stdlib/arc4random.c
++++ b/stdlib/arc4random.c
+@@ -34,7 +34,7 @@ void
+ __arc4random_buf (void *p, size_t n)
+ {
+ static int seen_initialized;
+- size_t l;
++ ssize_t l;
+ int fd;
+
+ if (n == 0)
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 050a3032de..6b256b8388 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -1048,9 +1048,11 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv,
+ initializer functions have completed. */
+ extern void _dl_fini (void) attribute_hidden;
+
+-/* Sort array MAPS according to dependencies of the contained objects. */
++/* Sort array MAPS according to dependencies of the contained objects.
++ If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies
++ say otherwise. */
+ extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
+- unsigned int skip, bool for_fini) attribute_hidden;
++ bool force_first, bool for_fini) attribute_hidden;
+
+ /* The dynamic linker calls this function before and having changing
+ any shared object mappings. The `r_state' member of `struct r_debug'
+diff --git a/sysdeps/generic/libc-lock-arch.h b/sysdeps/generic/libc-lock-arch.h
+new file mode 100644
+index 0000000000..4713b30a8a
+--- /dev/null
++++ b/sysdeps/generic/libc-lock-arch.h
+@@ -0,0 +1,25 @@
++/* Private libc-internal arch-specific definitions. Generic version.
++ Copyright (C) 2022 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; see the file COPYING.LIB. If
++ not, see <https://www.gnu.org/licenses/>. */
++
++#ifndef _LIBC_LOCK_ARCH_H
++#define _LIBC_LOCK_ARCH_H
++
++/* The default definition uses the natural alignment from the lock type. */
++#define __LIBC_LOCK_ALIGNMENT
++
++#endif
+diff --git a/sysdeps/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h
+index 5b35ea81ec..70fce4fb27 100644
+--- a/sysdeps/mach/hurd/bits/socket.h
++++ b/sysdeps/mach/hurd/bits/socket.h
+@@ -249,6 +249,12 @@ struct cmsghdr
+ + CMSG_ALIGN (sizeof (struct cmsghdr)))
+ #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
+
++/* Given a length, return the additional padding necessary such that
++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
++#define __CMSG_PADDING(len) ((sizeof (size_t) \
++ - ((len) & (sizeof (size_t) - 1))) \
++ & (sizeof (size_t) - 1))
++
+ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+ struct cmsghdr *__cmsg) __THROW;
+ #ifdef __USE_EXTERN_INLINES
+@@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+ _EXTERN_INLINE struct cmsghdr *
+ __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
+ {
++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
++ __mhdr->msg_controllen because the user is required to obtain the first
++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
++ trust the value of __cmsg->cmsg_len and therefore do not use it in any
++ pointer arithmetic until we check its value. */
++
++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
++
++ size_t __size_needed = sizeof (struct cmsghdr)
++ + __CMSG_PADDING (__cmsg->cmsg_len);
++
++ /* The current header is malformed, too small to be a full header. */
+ if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
+- /* The kernel header does this so there may be a reason. */
+ return (struct cmsghdr *) 0;
+
++ /* There isn't enough space between __cmsg and the end of the buffer to
++ hold the current cmsg *and* the next one. */
++ if (((size_t)
++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
++ < __size_needed)
++ || ((size_t)
++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
++ - __size_needed)
++ < __cmsg->cmsg_len))
++
++ return (struct cmsghdr *) 0;
++
++ /* Now, we trust cmsg_len and can use it to find the next header. */
+ __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
+ + CMSG_ALIGN (__cmsg->cmsg_len));
+- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
+- + __mhdr->msg_controllen)
+- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
+- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
+- /* No more entries. */
+- return (struct cmsghdr *) 0;
+ return __cmsg;
+ }
+ #endif /* Use `extern inline'. */
+diff --git a/sysdeps/nptl/libc-lock.h b/sysdeps/nptl/libc-lock.h
+index 5af476c48b..63b3f3d75c 100644
+--- a/sysdeps/nptl/libc-lock.h
++++ b/sysdeps/nptl/libc-lock.h
+@@ -22,6 +22,7 @@
+ #include <pthread.h>
+ #define __need_NULL
+ #include <stddef.h>
++#include <libc-lock-arch.h>
+
+
+ /* Mutex type. */
+@@ -29,7 +30,12 @@
+ # if (!IS_IN (libc) && !IS_IN (libpthread)) || !defined _LIBC
+ typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t;
+ # else
+-typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t;
++typedef struct
++{
++ int lock __LIBC_LOCK_ALIGNMENT;
++ int cnt;
++ void *owner;
++} __libc_lock_recursive_t;
+ # endif
+ #else
+ typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t;
+diff --git a/sysdeps/nptl/libc-lockP.h b/sysdeps/nptl/libc-lockP.h
+index d3a6837fd2..425f514c5c 100644
+--- a/sysdeps/nptl/libc-lockP.h
++++ b/sysdeps/nptl/libc-lockP.h
+@@ -32,9 +32,10 @@
+ ld.so might be used on old kernels with a different libc.so. */
+ #include <lowlevellock.h>
+ #include <tls.h>
++#include <libc-lock-arch.h>
+
+ /* Mutex type. */
+-typedef int __libc_lock_t;
++typedef int __libc_lock_t __LIBC_LOCK_ALIGNMENT;
+ typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t;
+ typedef pthread_rwlock_t __libc_rwlock_t;
+
+diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
+index bcff909b2f..5cda9bb072 100644
+--- a/sysdeps/posix/getaddrinfo.c
++++ b/sysdeps/posix/getaddrinfo.c
+@@ -540,11 +540,11 @@ get_nscd_addresses (const char *name, const struct addrinfo *req,
+ at[count].addr[2] = htonl (0xffff);
+ }
+ else if (req->ai_family == AF_UNSPEC
+- || air->family[count] == req->ai_family)
++ || air->family[i] == req->ai_family)
+ {
+- at[count].family = air->family[count];
++ at[count].family = air->family[i];
+ memcpy (at[count].addr, addrs, size);
+- if (air->family[count] == AF_INET6)
++ if (air->family[i] == AF_INET6)
+ res->got_ipv6 = true;
+ }
+ at[count].next = at + count + 1;
+diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
+index a139a16532..3ceda9fdbf 100644
+--- a/sysdeps/unix/sysv/linux/Makefile
++++ b/sysdeps/unix/sysv/linux/Makefile
+@@ -265,6 +265,14 @@ $(objpfx)tst-mount-consts.out: ../sysdeps/unix/sysv/linux/tst-mount-consts.py
+ < /dev/null > $@ 2>&1; $(evaluate-test)
+ $(objpfx)tst-mount-consts.out: $(sysdeps-linux-python-deps)
+
++tests-special += $(objpfx)tst-mount-compile.out
++$(objpfx)tst-mount-compile.out: ../sysdeps/unix/sysv/linux/tst-mount-compile.py
++ $(sysdeps-linux-python) \
++ ../sysdeps/unix/sysv/linux/tst-mount-compile.py \
++ $(sysdeps-linux-python-cc) \
++ < /dev/null > $@ 2>&1; $(evaluate-test)
++$(objpfx)tst-mount-compile.out: $(sysdeps-linux-python-deps)
++
+ tst-rseq-disable-ENV = GLIBC_TUNABLES=glibc.pthread.rseq=0
+
+ endif # $(subdir) == misc
+diff --git a/sysdeps/unix/sysv/linux/alpha/brk_call.h b/sysdeps/unix/sysv/linux/alpha/brk_call.h
+index b8088cf13f..0b851b6c86 100644
+--- a/sysdeps/unix/sysv/linux/alpha/brk_call.h
++++ b/sysdeps/unix/sysv/linux/alpha/brk_call.h
+@@ -21,8 +21,7 @@ __brk_call (void *addr)
+ {
+ unsigned long int result = INTERNAL_SYSCALL_CALL (brk, addr);
+ if (result == -ENOMEM)
+- /* Mimic the default error reporting behavior. */
+- return addr;
+- else
+- return (void *) result;
++ /* Mimic the generic error reporting behavior. */
++ result = INTERNAL_SYSCALL_CALL (brk, 0);
++ return (void *) result;
+ }
+diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h
+index 4f1f810ea1..539b8d7716 100644
+--- a/sysdeps/unix/sysv/linux/bits/socket.h
++++ b/sysdeps/unix/sysv/linux/bits/socket.h
+@@ -307,6 +307,12 @@ struct cmsghdr
+ + CMSG_ALIGN (sizeof (struct cmsghdr)))
+ #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
+
++/* Given a length, return the additional padding necessary such that
++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
++#define __CMSG_PADDING(len) ((sizeof (size_t) \
++ - ((len) & (sizeof (size_t) - 1))) \
++ & (sizeof (size_t) - 1))
++
+ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+ struct cmsghdr *__cmsg) __THROW;
+ #ifdef __USE_EXTERN_INLINES
+@@ -316,18 +322,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+ _EXTERN_INLINE struct cmsghdr *
+ __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
+ {
++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
++ __mhdr->msg_controllen because the user is required to obtain the first
++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
++ trust the value of __cmsg->cmsg_len and therefore do not use it in any
++ pointer arithmetic until we check its value. */
++
++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
++
++ size_t __size_needed = sizeof (struct cmsghdr)
++ + __CMSG_PADDING (__cmsg->cmsg_len);
++
++ /* The current header is malformed, too small to be a full header. */
+ if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
+- /* The kernel header does this so there may be a reason. */
+ return (struct cmsghdr *) 0;
+
++ /* There isn't enough space between __cmsg and the end of the buffer to
++ hold the current cmsg *and* the next one. */
++ if (((size_t)
++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
++ < __size_needed)
++ || ((size_t)
++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
++ - __size_needed)
++ < __cmsg->cmsg_len))
++
++ return (struct cmsghdr *) 0;
++
++ /* Now, we trust cmsg_len and can use it to find the next header. */
+ __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
+ + CMSG_ALIGN (__cmsg->cmsg_len));
+- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
+- + __mhdr->msg_controllen)
+- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
+- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
+- /* No more entries. */
+- return (struct cmsghdr *) 0;
+ return __cmsg;
+ }
+ #endif /* Use `extern inline'. */
+diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
+index 15b7a3a925..24f72b797a 100644
+--- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
++++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
+@@ -23,18 +23,38 @@
+ struct cmsghdr *
+ __cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg)
+ {
++ /* We may safely assume that cmsg lies between mhdr->msg_control and
++ mhdr->msg_controllen because the user is required to obtain the first
++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
++ trust the value of cmsg->cmsg_len and therefore do not use it in any
++ pointer arithmetic until we check its value. */
++
++ unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control;
++ unsigned char * cmsg_ptr = (unsigned char *) cmsg;
++
++ size_t size_needed = sizeof (struct cmsghdr)
++ + __CMSG_PADDING (cmsg->cmsg_len);
++
++ /* The current header is malformed, too small to be a full header. */
+ if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr))
+- /* The kernel header does this so there may be a reason. */
+- return NULL;
++ return (struct cmsghdr *) 0;
++
++ /* There isn't enough space between cmsg and the end of the buffer to
++ hold the current cmsg *and* the next one. */
++ if (((size_t)
++ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr)
++ < size_needed)
++ || ((size_t)
++ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr
++ - size_needed)
++ < cmsg->cmsg_len))
++
++ return (struct cmsghdr *) 0;
+
++ /* Now, we trust cmsg_len and can use it to find the next header. */
+ cmsg = (struct cmsghdr *) ((unsigned char *) cmsg
+ + CMSG_ALIGN (cmsg->cmsg_len));
+- if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control
+- + mhdr->msg_controllen)
+- || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len)
+- > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen)))
+- /* No more entries. */
+- return NULL;
+ return cmsg;
+ }
+ libc_hidden_def (__cmsg_nxthdr)
+diff --git a/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h
+new file mode 100644
+index 0000000000..1844bbaf6f
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h
+@@ -0,0 +1,25 @@
++/* Private libc-internal arch-specific definitions. m68k version.
++ Copyright (C) 2022 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; see the file COPYING.LIB. If
++ not, see <https://www.gnu.org/licenses/>. */
++
++#ifndef _LIBC_LOCK_ARCH_H
++#define _LIBC_LOCK_ARCH_H
++
++/* Linux enforces 4-bytes alignment on futex inputs. */
++#define __LIBC_LOCK_ALIGNMENT __attribute__ ((__aligned__ (4)))
++
++#endif
+diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h
+index a263d294b1..cf35c8bfc9 100644
+--- a/sysdeps/unix/sysv/linux/not-cancel.h
++++ b/sysdeps/unix/sysv/linux/not-cancel.h
+@@ -68,7 +68,7 @@ __writev_nocancel_nostatus (int fd, const struct iovec *iov, int iovcnt)
+ INTERNAL_SYSCALL_CALL (writev, fd, iov, iovcnt);
+ }
+
+-static inline int
++static inline ssize_t
+ __getrandom_nocancel (void *buf, size_t buflen, unsigned int flags)
+ {
+ return INLINE_SYSCALL_CALL (getrandom, buf, buflen, flags);
+diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
+index bf4be80f8d..202520ee25 100644
+--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
+@@ -122,6 +122,7 @@
+ #define __NR_mbind 235
+ #define __NR_membarrier 283
+ #define __NR_memfd_create 279
++#define __NR_memfd_secret 447
+ #define __NR_migrate_pages 238
+ #define __NR_mincore 232
+ #define __NR_mkdirat 34
+diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
+index d656aedcc2..4e65f337d4 100644
+--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
+@@ -127,6 +127,7 @@
+ #define __NR_mbind 235
+ #define __NR_membarrier 283
+ #define __NR_memfd_create 279
++#define __NR_memfd_secret 447
+ #define __NR_migrate_pages 238
+ #define __NR_mincore 232
+ #define __NR_mkdirat 34
+diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h
+index f965986ba8..19841d0738 100644
+--- a/sysdeps/unix/sysv/linux/sys/mount.h
++++ b/sysdeps/unix/sysv/linux/sys/mount.h
+@@ -27,77 +27,113 @@
+ #include <stddef.h>
+ #include <sys/ioctl.h>
+
+-#define BLOCK_SIZE 1024
++#ifdef __has_include
++# if __has_include ("linux/mount.h")
++# include "linux/mount.h"
++# endif
++#endif
++
++
+ #define BLOCK_SIZE_BITS 10
++#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
+
+
+ /* These are the fs-independent mount-flags: up to 16 flags are
+ supported */
+ enum
+ {
++#undef MS_RDONLY
+ MS_RDONLY = 1, /* Mount read-only. */
+ #define MS_RDONLY MS_RDONLY
++#undef MS_NOSUID
+ MS_NOSUID = 2, /* Ignore suid and sgid bits. */
+ #define MS_NOSUID MS_NOSUID
++#undef MS_NODEV
+ MS_NODEV = 4, /* Disallow access to device special files. */
+ #define MS_NODEV MS_NODEV
++#undef MS_NOEXEC
+ MS_NOEXEC = 8, /* Disallow program execution. */
+ #define MS_NOEXEC MS_NOEXEC
++#undef MS_SYNCHRONOUS
+ MS_SYNCHRONOUS = 16, /* Writes are synced at once. */
+ #define MS_SYNCHRONOUS MS_SYNCHRONOUS
++#undef MS_REMOUNT
+ MS_REMOUNT = 32, /* Alter flags of a mounted FS. */
+ #define MS_REMOUNT MS_REMOUNT
++#undef MS_MANDLOCK
+ MS_MANDLOCK = 64, /* Allow mandatory locks on an FS. */
+ #define MS_MANDLOCK MS_MANDLOCK
++#undef MS_DIRSYNC
+ MS_DIRSYNC = 128, /* Directory modifications are synchronous. */
+ #define MS_DIRSYNC MS_DIRSYNC
++#undef MS_NOSYMFOLLOW
+ MS_NOSYMFOLLOW = 256, /* Do not follow symlinks. */
+ #define MS_NOSYMFOLLOW MS_NOSYMFOLLOW
++#undef MS_NOATIME
+ MS_NOATIME = 1024, /* Do not update access times. */
+ #define MS_NOATIME MS_NOATIME
++#undef MS_NODIRATIME
+ MS_NODIRATIME = 2048, /* Do not update directory access times. */
+ #define MS_NODIRATIME MS_NODIRATIME
++#undef MS_BIND
+ MS_BIND = 4096, /* Bind directory at different place. */
+ #define MS_BIND MS_BIND
++#undef MS_MOVE
+ MS_MOVE = 8192,
+ #define MS_MOVE MS_MOVE
++#undef MS_REC
+ MS_REC = 16384,
+ #define MS_REC MS_REC
++#undef MS_SILENT
+ MS_SILENT = 32768,
+ #define MS_SILENT MS_SILENT
++#undef MS_POSIXACL
+ MS_POSIXACL = 1 << 16, /* VFS does not apply the umask. */
+ #define MS_POSIXACL MS_POSIXACL
++#undef MS_UNBINDABLE
+ MS_UNBINDABLE = 1 << 17, /* Change to unbindable. */
+ #define MS_UNBINDABLE MS_UNBINDABLE
++#undef MS_PRIVATE
+ MS_PRIVATE = 1 << 18, /* Change to private. */
+ #define MS_PRIVATE MS_PRIVATE
++#undef MS_SLAVE
+ MS_SLAVE = 1 << 19, /* Change to slave. */
+ #define MS_SLAVE MS_SLAVE
++#undef MS_SHARED
+ MS_SHARED = 1 << 20, /* Change to shared. */
+ #define MS_SHARED MS_SHARED
++#undef MS_RELATIME
+ MS_RELATIME = 1 << 21, /* Update atime relative to mtime/ctime. */
+ #define MS_RELATIME MS_RELATIME
++#undef MS_KERNMOUNT
+ MS_KERNMOUNT = 1 << 22, /* This is a kern_mount call. */
+ #define MS_KERNMOUNT MS_KERNMOUNT
++#undef MS_I_VERSION
+ MS_I_VERSION = 1 << 23, /* Update inode I_version field. */
+ #define MS_I_VERSION MS_I_VERSION
++#undef MS_STRICTATIME
+ MS_STRICTATIME = 1 << 24, /* Always perform atime updates. */
+ #define MS_STRICTATIME MS_STRICTATIME
++#undef MS_LAZYTIME
+ MS_LAZYTIME = 1 << 25, /* Update the on-disk [acm]times lazily. */
+ #define MS_LAZYTIME MS_LAZYTIME
++#undef MS_ACTIVE
+ MS_ACTIVE = 1 << 30,
+ #define MS_ACTIVE MS_ACTIVE
++#undef MS_NOUSER
+ MS_NOUSER = 1 << 31
+ #define MS_NOUSER MS_NOUSER
+ };
+
+ /* Flags that can be altered by MS_REMOUNT */
++#undef MS_RMT_MASK
+ #define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION \
+ |MS_LAZYTIME)
+
+
+ /* Magic mount flag number. Has to be or-ed to the flag values. */
+
++#undef MS_MGC_VAL
+ #define MS_MGC_VAL 0xc0ed0000 /* Magic flag number to indicate "new" flags */
+ #define MS_MGC_MSK 0xffff0000 /* Magic flag number mask */
+
+@@ -106,20 +142,35 @@ enum
+ is probably as bad and I don't want to create yet another include
+ file. */
+
++#undef BLKROSET
+ #define BLKROSET _IO(0x12, 93) /* Set device read-only (0 = read-write). */
++#undef BLKROGET
+ #define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */
++#undef BLKRRPART
+ #define BLKRRPART _IO(0x12, 95) /* Re-read partition table. */
++#undef BLKGETSIZE
+ #define BLKGETSIZE _IO(0x12, 96) /* Return device size. */
++#undef BLKFLSBUF
+ #define BLKFLSBUF _IO(0x12, 97) /* Flush buffer cache. */
++#undef BLKRASET
+ #define BLKRASET _IO(0x12, 98) /* Set read ahead for block device. */
++#undef BLKRAGET
+ #define BLKRAGET _IO(0x12, 99) /* Get current read ahead setting. */
++#undef BLKFRASET
+ #define BLKFRASET _IO(0x12,100) /* Set filesystem read-ahead. */
++#undef BLKFRAGET
+ #define BLKFRAGET _IO(0x12,101) /* Get filesystem read-ahead. */
++#undef BLKSECTSET
+ #define BLKSECTSET _IO(0x12,102) /* Set max sectors per request. */
++#undef BLKSECTGET
+ #define BLKSECTGET _IO(0x12,103) /* Get max sectors per request. */
++#undef BLKSSZGET
+ #define BLKSSZGET _IO(0x12,104) /* Get block device sector size. */
++#undef BLKBSZGET
+ #define BLKBSZGET _IOR(0x12,112,size_t)
++#undef BLKBSZSET
+ #define BLKBSZSET _IOW(0x12,113,size_t)
++#undef BLKGETSIZE64
+ #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size. */
+
+
+@@ -137,9 +188,6 @@ enum
+ };
+
+
+-/* fsopen flags. */
+-#define FSOPEN_CLOEXEC 0x00000001
+-
+ /* fsmount flags. */
+ #define FSMOUNT_CLOEXEC 0x00000001
+
+@@ -157,6 +205,7 @@ enum
+ #define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 /* Do not follow symlinks. */
+
+
++#ifndef MOUNT_ATTR_SIZE_VER0
+ /* For mount_setattr. */
+ struct mount_attr
+ {
+@@ -165,6 +214,7 @@ struct mount_attr
+ uint64_t propagation;
+ uint64_t userns_fd;
+ };
++#endif
+
+ #define MOUNT_ATTR_SIZE_VER0 32 /* sizeof first published struct */
+
+@@ -185,26 +235,31 @@ struct mount_attr
+ #define FSPICK_EMPTY_PATH 0x00000008
+
+
++#ifndef FSOPEN_CLOEXEC
+ /* The type of fsconfig call made. */
+ enum fsconfig_command
+ {
+ FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */
+-#define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
++# define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
+ FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */
+-#define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
++# define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
+ FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */
+-#define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
++# define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
+ FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */
+-#define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
++# define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
+ FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */
+-#define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
++# define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
+ FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */
+-#define FSCONFIG_SET_FD FSCONFIG_SET_FD
++# define FSCONFIG_SET_FD FSCONFIG_SET_FD
+ FSCONFIG_CMD_CREATE = 6, /* Invoke superblock creation */
+-#define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
++# define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
+ FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */
+-#define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
++# define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
+ };
++#endif
++
++/* fsopen flags. */
++#define FSOPEN_CLOEXEC 0x00000001
+
+ /* open_tree flags. */
+ #define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
+diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
+index 6c7b2f7011..028ad3107a 100644
+--- a/sysdeps/unix/sysv/linux/syscall-names.list
++++ b/sysdeps/unix/sysv/linux/syscall-names.list
+@@ -21,8 +21,8 @@
+ # This file can list all potential system calls. The names are only
+ # used if the installed kernel headers also provide them.
+
+-# The list of system calls is current as of Linux 5.18.
+-kernel 5.18
++# The list of system calls is current as of Linux 5.19.
++kernel 5.19
+
+ FAST_atomic_update
+ FAST_cmpxchg
+diff --git a/sysdeps/unix/sysv/linux/tst-mount-compile.py b/sysdeps/unix/sysv/linux/tst-mount-compile.py
+new file mode 100755
+index 0000000000..0ec74d4e0b
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/tst-mount-compile.py
+@@ -0,0 +1,66 @@
++#!/usr/bin/python3
++# Check if glibc provided sys/mount.h can be used along related kernel
++# headers.
++# Copyright (C) 2022 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/>.
++
++import argparse
++import sys
++
++import glibcextract
++
++
++def main():
++ """The main entry point."""
++ parser = argparse.ArgumentParser(
++ description='Check if glibc provided sys/mount.h can be '
++ ' used along related kernel headers.')
++ parser.add_argument('--cc', metavar='CC',
++ help='C compiler (including options) to use')
++ args = parser.parse_args()
++
++ if glibcextract.compile_c_snippet(
++ '#include <linux/mount.h>',
++ args.cc).returncode != 0:
++ sys.exit (77)
++
++ def check(testname, snippet):
++ # Add -Werror to catch macro redefinitions and _ISOMAC to avoid
++ # internal glibc definitions.
++ r = glibcextract.compile_c_snippet(snippet, args.cc,
++ '-Werror -D_ISOMAC')
++ if r.returncode != 0:
++ print('error: test {}:\n{}'.format(testname, r.output.decode()))
++ return r.returncode
++
++ status = max(
++ check("sys/mount.h + linux/mount.h",
++ "#include <sys/mount.h>\n"
++ "#include <linux/mount.h>"),
++ check("sys/mount.h + linux/fs.h",
++ "#include <sys/mount.h>\n"
++ "#include <linux/fs.h>"),
++ check("linux/mount.h + sys/mount.h",
++ "#include <linux/mount.h>\n"
++ "#include <sys/mount.h>"),
++ check("linux/fs.h + sys/mount.h",
++ "#include <linux/fs.h>\n"
++ "#include <sys/mount.h>"))
++ sys.exit(status)
++
++if __name__ == '__main__':
++ main()
+diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py
+index a62f803123..be2ef2daf1 100755
+--- a/sysdeps/unix/sysv/linux/tst-mount-consts.py
++++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py
+@@ -33,6 +33,11 @@ def main():
+ help='C compiler (including options) to use')
+ args = parser.parse_args()
+
++ if glibcextract.compile_c_snippet(
++ '#include <linux/mount.h>',
++ args.cc).returncode != 0:
++ sys.exit (77)
++
+ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+ # Constants in glibc were updated to match Linux v5.16. When glibc
+ # constants are updated this value should be updated to match the
+diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
+index 90cbb9be64..d732173abd 100644
+--- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
++++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
+@@ -33,11 +33,13 @@ def main():
+ help='C compiler (including options) to use')
+ args = parser.parse_args()
+
+- linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+- # Linux started to provide pidfd.h with 5.10.
+- if linux_version_headers < (5, 10):
++ if glibcextract.compile_c_snippet(
++ '#include <linux/pidfd.h>',
++ args.cc).returncode != 0:
+ sys.exit (77)
+- linux_version_glibc = (5, 18)
++
++ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
++ linux_version_glibc = (5, 19)
+ sys.exit(glibcextract.compare_macro_consts(
+ '#include <sys/pidfd.h>\n',
+ '#include <asm/fcntl.h>\n'
+diff --git a/sysdeps/unix/sysv/linux/tst-pidfd.c b/sysdeps/unix/sysv/linux/tst-pidfd.c
+index 037af22290..5711d1c312 100644
+--- a/sysdeps/unix/sysv/linux/tst-pidfd.c
++++ b/sysdeps/unix/sysv/linux/tst-pidfd.c
+@@ -147,8 +147,11 @@ do_test (void)
+ may be denied if the process doesn't have CAP_SYS_PTRACE or
+ if a LSM security_ptrace_access_check denies access. */
+ if (fd == -1 && errno == EPERM)
+- FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
+- "skipping test");
++ {
++ TEST_COMPARE (pidfd_send_signal (pidfd, SIGKILL, NULL, 0), 0);
++ FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
++ "skipping test");
++ }
+ TEST_VERIFY (fd > 0);
+
+ char *path = xasprintf ("/proc/%d/fd/%d", pid, remote_fd);
+diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
+index e6b9e8743a..4af102a3f6 100644
+--- a/wcsmbs/Makefile
++++ b/wcsmbs/Makefile
+@@ -22,8 +22,9 @@ subdir := wcsmbs
+
+ include ../Makeconfig
+
+-headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h \
+- bits/types/__mbstate_t.h bits/types/mbstate_t.h bits/types/wint_t.h
++headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar2-decl.h \
++ bits/wchar-ldbl.h uchar.h bits/types/__mbstate_t.h \
++ bits/types/mbstate_t.h bits/types/wint_t.h
+
+ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
+ wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \
+@@ -73,6 +74,8 @@ $(objpfx)tst-wcstol-locale.out: $(gen-locales)
+ $(objpfx)tst-wcstod-nan-locale.out: $(gen-locales)
+ $(objpfx)tst-c16-surrogate.out: $(gen-locales)
+ $(objpfx)tst-c32-state.out: $(gen-locales)
++$(objpfx)test-c8rtomb.out: $(gen-locales)
++$(objpfx)test-mbrtoc8.out: $(gen-locales)
+ endif
+
+ $(objpfx)tst-wcstod-round: $(libm)
+diff --git a/wcsmbs/bits/wchar2-decl.h b/wcsmbs/bits/wchar2-decl.h
+new file mode 100644
+index 0000000000..8e1735c33b
+--- /dev/null
++++ b/wcsmbs/bits/wchar2-decl.h
+@@ -0,0 +1,124 @@
++/* Checking macros for wchar functions. Declarations only.
++ Copyright (C) 2004-2022 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/>. */
++
++#ifndef _BITS_WCHAR2_DECL_H
++#define _BITS_WCHAR2_DECL_H 1
++
++#ifndef _WCHAR_H
++# error "Never include <bits/wchar2-decl.h> directly; use <wchar.h> instead."
++#endif
++
++
++extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1,
++ const wchar_t *__restrict __s2, size_t __n,
++ size_t __ns1) __THROW;
++extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2,
++ size_t __n, size_t __ns1) __THROW;
++
++
++#ifdef __USE_GNU
++
++extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1,
++ const wchar_t *__restrict __s2, size_t __n,
++ size_t __ns1) __THROW;
++
++#endif
++
++
++extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n,
++ size_t __ns) __THROW;
++extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest,
++ const wchar_t *__restrict __src,
++ size_t __n) __THROW;
++extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest,
++ const wchar_t *__restrict __src,
++ size_t __destlen) __THROW;
++extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest,
++ const wchar_t *__restrict __src, size_t __n,
++ size_t __destlen) __THROW;
++extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest,
++ const wchar_t *__restrict __src, size_t __n,
++ size_t __destlen) __THROW;
++extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest,
++ const wchar_t *__restrict __src,
++ size_t __destlen) __THROW;
++extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest,
++ const wchar_t *__restrict __src,
++ size_t __n, size_t __destlen) __THROW;
++extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n,
++ int __flag, size_t __s_len,
++ const wchar_t *__restrict __format, ...)
++ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */;
++extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
++ int __flag, size_t __s_len,
++ const wchar_t *__restrict __format,
++ __gnuc_va_list __arg)
++ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
++
++#if __USE_FORTIFY_LEVEL > 1
++
++extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag,
++ const wchar_t *__restrict __format, ...);
++extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format,
++ ...);
++extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag,
++ const wchar_t *__restrict __format,
++ __gnuc_va_list __ap);
++extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format,
++ __gnuc_va_list __ap);
++
++#endif
++
++extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n,
++ __FILE *__restrict __stream) __wur;
++
++#ifdef __USE_GNU
++
++extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size,
++ int __n, __FILE *__restrict __stream)
++ __wur;
++
++#endif
++
++extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar,
++ mbstate_t *__restrict __p,
++ size_t __buflen) __THROW __wur;
++extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst,
++ const char **__restrict __src,
++ size_t __len, mbstate_t *__restrict __ps,
++ size_t __dstlen) __THROW;
++extern size_t __wcsrtombs_chk (char *__restrict __dst,
++ const wchar_t **__restrict __src,
++ size_t __len, mbstate_t *__restrict __ps,
++ size_t __dstlen) __THROW;
++
++#ifdef __USE_XOPEN2K8
++
++extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst,
++ const char **__restrict __src, size_t __nmc,
++ size_t __len, mbstate_t *__restrict __ps,
++ size_t __dstlen) __THROW;
++extern size_t __wcsnrtombs_chk (char *__restrict __dst,
++ const wchar_t **__restrict __src,
++ size_t __nwc, size_t __len,
++ mbstate_t *__restrict __ps, size_t __dstlen)
++ __THROW;
++
++#endif
++
++#endif /* bits/wchar2-decl.h. */
+diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
+index 0e017f458b..3f110efe57 100644
+--- a/wcsmbs/bits/wchar2.h
++++ b/wcsmbs/bits/wchar2.h
+@@ -21,9 +21,6 @@
+ #endif
+
+
+-extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1,
+- const wchar_t *__restrict __s2, size_t __n,
+- size_t __ns1) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wmemcpy_alias,
+ (wchar_t *__restrict __s1,
+ const wchar_t *__restrict __s2, size_t __n),
+@@ -45,8 +42,6 @@ __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
+ }
+
+
+-extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2,
+- size_t __n, size_t __ns1) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wmemmove_alias, (wchar_t *__s1,
+ const wchar_t *__s2,
+ size_t __n), wmemmove);
+@@ -66,9 +61,6 @@ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
+
+
+ #ifdef __USE_GNU
+-extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1,
+- const wchar_t *__restrict __s2, size_t __n,
+- size_t __ns1) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wmempcpy_alias,
+ (wchar_t *__restrict __s1,
+ const wchar_t *__restrict __s2,
+@@ -91,8 +83,6 @@ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
+ #endif
+
+
+-extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n,
+- size_t __ns) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wmemset_alias, (wchar_t *__s, wchar_t __c,
+ size_t __n), wmemset);
+ extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn,
+@@ -110,9 +100,6 @@ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n))
+ }
+
+
+-extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest,
+- const wchar_t *__restrict __src,
+- size_t __n) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wcscpy_alias,
+ (wchar_t *__restrict __dest,
+ const wchar_t *__restrict __src), wcscpy);
+@@ -127,9 +114,6 @@ __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+ }
+
+
+-extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest,
+- const wchar_t *__restrict __src,
+- size_t __destlen) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias,
+ (wchar_t *__restrict __dest,
+ const wchar_t *__restrict __src), wcpcpy);
+@@ -144,9 +128,6 @@ __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+ }
+
+
+-extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest,
+- const wchar_t *__restrict __src, size_t __n,
+- size_t __destlen) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wcsncpy_alias,
+ (wchar_t *__restrict __dest,
+ const wchar_t *__restrict __src,
+@@ -168,9 +149,6 @@ __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
+ }
+
+
+-extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest,
+- const wchar_t *__restrict __src, size_t __n,
+- size_t __destlen) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wcpncpy_alias,
+ (wchar_t *__restrict __dest,
+ const wchar_t *__restrict __src,
+@@ -192,9 +170,6 @@ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
+ }
+
+
+-extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest,
+- const wchar_t *__restrict __src,
+- size_t __destlen) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wcscat_alias,
+ (wchar_t *__restrict __dest,
+ const wchar_t *__restrict __src), wcscat);
+@@ -209,9 +184,6 @@ __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+ }
+
+
+-extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest,
+- const wchar_t *__restrict __src,
+- size_t __n, size_t __destlen) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wcsncat_alias,
+ (wchar_t *__restrict __dest,
+ const wchar_t *__restrict __src,
+@@ -228,10 +200,6 @@ __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
+ }
+
+
+-extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n,
+- int __flag, size_t __s_len,
+- const wchar_t *__restrict __format, ...)
+- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */;
+
+ extern int __REDIRECT_NTH_LDBL (__swprintf_alias,
+ (wchar_t *__restrict __s, size_t __n,
+@@ -258,11 +226,6 @@ __NTH (swprintf (wchar_t *__restrict __s, size_t __n,
+ : swprintf (s, n, __VA_ARGS__))
+ #endif
+
+-extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
+- int __flag, size_t __s_len,
+- const wchar_t *__restrict __format,
+- __gnuc_va_list __arg)
+- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
+
+ extern int __REDIRECT_NTH_LDBL (__vswprintf_alias,
+ (wchar_t *__restrict __s, size_t __n,
+@@ -283,16 +246,6 @@ __NTH (vswprintf (wchar_t *__restrict __s, size_t __n,
+
+ #if __USE_FORTIFY_LEVEL > 1
+
+-extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag,
+- const wchar_t *__restrict __format, ...);
+-extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format,
+- ...);
+-extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag,
+- const wchar_t *__restrict __format,
+- __gnuc_va_list __ap);
+-extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format,
+- __gnuc_va_list __ap);
+-
+ # ifdef __va_arg_pack
+ __fortify_function int
+ wprintf (const wchar_t *__restrict __fmt, ...)
+@@ -328,8 +281,6 @@ vfwprintf (__FILE *__restrict __stream,
+
+ #endif
+
+-extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n,
+- __FILE *__restrict __stream) __wur;
+ extern wchar_t *__REDIRECT (__fgetws_alias,
+ (wchar_t *__restrict __s, int __n,
+ __FILE *__restrict __stream), fgetws) __wur;
+@@ -351,9 +302,6 @@ fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
+ }
+
+ #ifdef __USE_GNU
+-extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size,
+- int __n, __FILE *__restrict __stream)
+- __wur;
+ extern wchar_t *__REDIRECT (__fgetws_unlocked_alias,
+ (wchar_t *__restrict __s, int __n,
+ __FILE *__restrict __stream), fgetws_unlocked)
+@@ -379,9 +327,6 @@ fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
+ #endif
+
+
+-extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar,
+- mbstate_t *__restrict __p,
+- size_t __buflen) __THROW __wur;
+ extern size_t __REDIRECT_NTH (__wcrtomb_alias,
+ (char *__restrict __s, wchar_t __wchar,
+ mbstate_t *__restrict __ps), wcrtomb) __wur;
+@@ -404,10 +349,6 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar,
+ }
+
+
+-extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst,
+- const char **__restrict __src,
+- size_t __len, mbstate_t *__restrict __ps,
+- size_t __dstlen) __THROW;
+ extern size_t __REDIRECT_NTH (__mbsrtowcs_alias,
+ (wchar_t *__restrict __dst,
+ const char **__restrict __src,
+@@ -431,10 +372,6 @@ __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
+ }
+
+
+-extern size_t __wcsrtombs_chk (char *__restrict __dst,
+- const wchar_t **__restrict __src,
+- size_t __len, mbstate_t *__restrict __ps,
+- size_t __dstlen) __THROW;
+ extern size_t __REDIRECT_NTH (__wcsrtombs_alias,
+ (char *__restrict __dst,
+ const wchar_t **__restrict __src,
+@@ -458,10 +395,6 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
+
+
+ #ifdef __USE_XOPEN2K8
+-extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst,
+- const char **__restrict __src, size_t __nmc,
+- size_t __len, mbstate_t *__restrict __ps,
+- size_t __dstlen) __THROW;
+ extern size_t __REDIRECT_NTH (__mbsnrtowcs_alias,
+ (wchar_t *__restrict __dst,
+ const char **__restrict __src, size_t __nmc,
+@@ -485,11 +418,6 @@ __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
+ }
+
+
+-extern size_t __wcsnrtombs_chk (char *__restrict __dst,
+- const wchar_t **__restrict __src,
+- size_t __nwc, size_t __len,
+- mbstate_t *__restrict __ps, size_t __dstlen)
+- __THROW;
+ extern size_t __REDIRECT_NTH (__wcsnrtombs_alias,
+ (char *__restrict __dst,
+ const wchar_t **__restrict __src,
+diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
+index c37e8619a0..5f7139f279 100644
+--- a/wcsmbs/uchar.h
++++ b/wcsmbs/uchar.h
+@@ -34,8 +34,16 @@
+ /* Declare the C2x char8_t typedef in C2x modes, but only if the C++
+ __cpp_char8_t feature test macro is not defined. */
+ #if __GLIBC_USE (ISOC2X) && !defined __cpp_char8_t
++#if __GNUC_PREREQ (10, 0) && defined __cplusplus
++/* Suppress the diagnostic regarding char8_t being a keyword in C++20. */
++# pragma GCC diagnostic push
++# pragma GCC diagnostic ignored "-Wc++20-compat"
++#endif
+ /* Define the 8-bit character type. */
+ typedef unsigned char char8_t;
++#if __GNUC_PREREQ (10, 0) && defined __cplusplus
++# pragma GCC diagnostic pop
++#endif
+ #endif
+
+ #ifndef __USE_ISOCXX11
+diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h
+index 5d6a40853d..c1321c7518 100644
+--- a/wcsmbs/wchar.h
++++ b/wcsmbs/wchar.h
+@@ -864,14 +864,21 @@ extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize,
+
+ /* Define some macros helping to catch buffer overflows. */
+ #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
+-# include <bits/wchar2.h>
++/* Declare all functions from bits/wchar2-decl.h first. */
++# include <bits/wchar2-decl.h>
+ #endif
+
+-#include <bits/floatn.h>
++/* The following headers provide asm redirections. These redirections must
++ appear before the first usage of these functions, e.g. in bits/wchar.h. */
+ #if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
+ # include <bits/wchar-ldbl.h>
+ #endif
+
++#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
++/* Now include the function definitions and redirects too. */
++# include <bits/wchar2.h>
++#endif
++
+ __END_DECLS
+
+ #endif /* wchar.h */
1
0
01 Oct '22
commit 656cf29b4210a536a3f48ca24b5ecc98254d3cc7
Author: Tim Biermann <tbier(a)posteo.de>
Date: Sat Oct 1 16:18:30 2022 +0200
[notify] glibc: upstream fixes for CVE-2022-39046
diff --git a/glibc/.footprint b/glibc/.footprint
index 5e2b8500..39d4d0d2 100644
--- a/glibc/.footprint
+++ b/glibc/.footprint
@@ -392,6 +392,7 @@ drwxr-xr-x root/root usr/include/bits/types/
-rw-r--r-- root/root usr/include/bits/waitstatus.h
-rw-r--r-- root/root usr/include/bits/wchar-ldbl.h
-rw-r--r-- root/root usr/include/bits/wchar.h
+-rw-r--r-- root/root usr/include/bits/wchar2-decl.h
-rw-r--r-- root/root usr/include/bits/wchar2.h
-rw-r--r-- root/root usr/include/bits/wctype-wchar.h
-rw-r--r-- root/root usr/include/bits/wordsize.h
diff --git a/glibc/.signature b/glibc/.signature
index 7ffbe06e..b3abdd0a 100644
--- a/glibc/.signature
+++ b/glibc/.signature
@@ -1,10 +1,10 @@
untrusted comment: verify with /etc/ports/core.pub
-RWRJc1FUaeVeqkxOnwc5iLM9nx9NtANOUXrU0QXTmG0NVy87nmVgZTkXM6+Dje7epyFVHtzkAcADD84bKf8MEfJh2M/5L8xC5AE=
-SHA256 (Pkgfile) = 79237a932d21c7b4ef43e8a56d9cd489939c3216b4ec0d32448acdc3443ab11d
-SHA256 (.footprint) = d6c55451befafd731c0b3de1b5eff63c4dcafae7ad4ae9ac0baaeb5a055ab80b
+RWRJc1FUaeVeqrmrz2ViAruXlKqsVUyY0s4wOV9V57xNFpcNs0uEx69eoAV6cdIb5CPz4TLUb9cFZHSbf5/zMbyswITGX7cFeAc=
+SHA256 (Pkgfile) = 944636ff0f2c0ba67246d6cd86ebcea5a2a9cb3705c9c00e99e9ddc8017aca99
+SHA256 (.footprint) = 9eff4b9e8478995dd0aceacfe9301a250827c8b27cb1d4605c696ac55eec873c
SHA256 (glibc-2.36.tar.xz) = 1c959fea240906226062cb4b1e7ebce71a9f0e3c0836c09e7e3423d434fcfe75
SHA256 (linux-5.15.55.tar.xz) = 1ef6bd508b6c3af3bef2d5b337e4477254dba284c79e329aa38f9763ae3bfdcc
-SHA256 (glibc-2.36-1.patch) = 6245087ab20402836cbd32b52ba944d31aeafc961ba597bcec0fa3727db79eee
+SHA256 (glibc-2.36-2.patch) = 4760e63dc0539952673bae08f3380608b53c74c9726e7f3137979f0f776d2a80
SHA256 (hosts) = 5c02b256c105f1d4a12fb738d71c1bab9eb126533074d7a0c8a14b92670c9431
SHA256 (resolv.conf) = 72ccb58768a72a771ec37142bc361a18478a07ec9de6e925a20760794389bf51
SHA256 (nsswitch.conf) = 859b8984e5e90aff3cce8f9779996ae4033b280d2122840e9411e2f44a1c2e61
diff --git a/glibc/Pkgfile b/glibc/Pkgfile
index 4101e393..74cc10b2 100644
--- a/glibc/Pkgfile
+++ b/glibc/Pkgfile
@@ -4,12 +4,12 @@
name=glibc
version=2.36
-release=1
+release=2
_kernel_version=5.15.55
source=(https://ftp.gnu.org/gnu/glibc/glibc-$version.tar.xz
https://www.kernel.org/pub/linux/kernel/v5.x/linux-$_kernel_version.tar.xz
- glibc-$version-1.patch
+ glibc-$version-2.patch
hosts resolv.conf nsswitch.conf host.conf ld.so.conf
locale-gen locale.gen.in)
@@ -20,12 +20,16 @@ build() {
make -C $SRC/linux-$_kernel_version INSTALL_HDR_PATH=$PKG/usr headers_install
chown root:root $PKG/usr
- patch -p1 -d $SRC/$name-${version:0:4} -i $SRC/$name-$version-1.patch
+ patch -p1 -d $SRC/$name-${version:0:4} -i $SRC/$name-$version-2.patch
mkdir $SRC/build
cd $SRC/build
+
+ export libc_cv_slibdir=/lib
+
$SRC/$name-$version/configure \
--prefix=/usr \
+ --libdir=/usr/lib \
--libexecdir=/usr/lib \
--with-headers=$PKG/usr/include \
--enable-kernel=4.9 \
diff --git a/glibc/glibc-2.36-1.patch b/glibc/glibc-2.36-1.patch
deleted file mode 100644
index 36bf0075..00000000
--- a/glibc/glibc-2.36-1.patch
+++ /dev/null
@@ -1,985 +0,0 @@
-diff --git a/NEWS b/NEWS
-index f61e521fc8..ae30900bbc 100644
---- a/NEWS
-+++ b/NEWS
-@@ -4,6 +4,16 @@ See the end for copying conditions.
-
- Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
- using `glibc' in the "product" field.
-+
-+Version 2.36.1
-+
-+The following bugs are resolved with this release:
-+
-+ [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning
-+ [29446] _dlopen now ignores dl_caller argument in static mode
-+ [29485] Linux: Terminate subprocess on late failure in tst-pidfd
-+ [29490] alpha: New __brk_call implementation is broken
-+
-
- Version 2.36
-
-diff --git a/bits/socket.h b/bits/socket.h
-index 2b99dea33b..aac8c49b00 100644
---- a/bits/socket.h
-+++ b/bits/socket.h
-@@ -245,6 +245,12 @@ struct cmsghdr
- + CMSG_ALIGN (sizeof (struct cmsghdr)))
- #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
-
-+/* Given a length, return the additional padding necessary such that
-+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
-+#define __CMSG_PADDING(len) ((sizeof (size_t) \
-+ - ((len) & (sizeof (size_t) - 1))) \
-+ & (sizeof (size_t) - 1))
-+
- extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
- struct cmsghdr *__cmsg) __THROW;
- #ifdef __USE_EXTERN_INLINES
-@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
- _EXTERN_INLINE struct cmsghdr *
- __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
- {
-+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
-+ __mhdr->msg_controllen because the user is required to obtain the first
-+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
-+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
-+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
-+ pointer arithmetic until we check its value. */
-+
-+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
-+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
-+
-+ size_t __size_needed = sizeof (struct cmsghdr)
-+ + __CMSG_PADDING (__cmsg->cmsg_len);
-+
-+ /* The current header is malformed, too small to be a full header. */
- if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
-- /* The kernel header does this so there may be a reason. */
- return (struct cmsghdr *) 0;
-
-+ /* There isn't enough space between __cmsg and the end of the buffer to
-+ hold the current cmsg *and* the next one. */
-+ if (((size_t)
-+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
-+ < __size_needed)
-+ || ((size_t)
-+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
-+ - __size_needed)
-+ < __cmsg->cmsg_len))
-+
-+ return (struct cmsghdr *) 0;
-+
-+ /* Now, we trust cmsg_len and can use it to find the next header. */
- __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
- + CMSG_ALIGN (__cmsg->cmsg_len));
-- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
-- + __mhdr->msg_controllen)
-- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
-- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
-- /* No more entries. */
-- return (struct cmsghdr *) 0;
- return __cmsg;
- }
- #endif /* Use `extern inline'. */
-diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c
-index 2696dde4b1..9b07b4e132 100644
---- a/dlfcn/dlopen.c
-+++ b/dlfcn/dlopen.c
-@@ -90,7 +90,7 @@ compat_symbol (libdl, ___dlopen, dlopen, GLIBC_2_1);
- void *
- __dlopen (const char *file, int mode, void *dl_caller)
- {
-- return dlopen_implementation (file, mode, RETURN_ADDRESS (0));
-+ return dlopen_implementation (file, mode, dl_caller);
- }
-
- void *
-diff --git a/elf/dl-cache.c b/elf/dl-cache.c
-index 8bbf110d02..b97c17b3a9 100644
---- a/elf/dl-cache.c
-+++ b/elf/dl-cache.c
-@@ -509,8 +509,9 @@ _dl_load_cache_lookup (const char *name)
- we are accessing. Therefore we must make the copy of the
- mapping data without using malloc. */
- char *temp;
-- temp = alloca (strlen (best) + 1);
-- strcpy (temp, best);
-+ size_t best_len = strlen (best) + 1;
-+ temp = alloca (best_len);
-+ memcpy (temp, best, best_len);
- return __strdup (temp);
- }
-
-diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
-index 43ab58ffe2..36d204c9b0 100644
---- a/scripts/glibcextract.py
-+++ b/scripts/glibcextract.py
-@@ -17,6 +17,7 @@
- # License along with the GNU C Library; if not, see
- # <https://www.gnu.org/licenses/>.
-
-+import collections
- import os.path
- import re
- import subprocess
-@@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None,
- if not allow_extra_2:
- ret = 1
- return ret
-+
-+CompileResult = collections.namedtuple("CompileResult", "returncode output")
-+
-+def compile_c_snippet(snippet, cc, extra_cc_args=''):
-+ """Compile and return whether the SNIPPET can be build with CC along
-+ EXTRA_CC_ARGS compiler flags. Return a CompileResult with RETURNCODE
-+ being 0 for success, or the failure value and the compiler output.
-+ """
-+ with tempfile.TemporaryDirectory() as temp_dir:
-+ c_file_name = os.path.join(temp_dir, 'test.c')
-+ obj_file_name = os.path.join(temp_dir, 'test.o')
-+ with open(c_file_name, 'w') as c_file:
-+ c_file.write(snippet + '\n')
-+ cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name,
-+ c_file_name]
-+ r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE,
-+ stderr=subprocess.STDOUT)
-+ return CompileResult(r.returncode, r.stdout)
-diff --git a/socket/Makefile b/socket/Makefile
-index 156eec6c85..2bde78387f 100644
---- a/socket/Makefile
-+++ b/socket/Makefile
-@@ -34,6 +34,7 @@ routines := accept bind connect getpeername getsockname getsockopt \
- tests := \
- tst-accept4 \
- tst-sockopt \
-+ tst-cmsghdr \
- # tests
-
- tests-internal := \
-diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c
-new file mode 100644
-index 0000000000..4c6898569b
---- /dev/null
-+++ b/socket/tst-cmsghdr-skeleton.c
-@@ -0,0 +1,92 @@
-+/* Test ancillary data header creation.
-+ Copyright (C) 2022 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/>. */
-+
-+/* We use the preprocessor to generate the function/macro tests instead of
-+ using indirection because having all the macro expansions alongside
-+ each other lets the compiler warn us about suspicious pointer
-+ arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions. */
-+
-+#include <stdint.h>
-+
-+#define RUN_TEST_CONCAT(suffix) run_test_##suffix
-+#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix)
-+
-+static void
-+RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void)
-+{
-+ struct msghdr m = {0};
-+ struct cmsghdr *cmsg;
-+ char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0};
-+
-+ m.msg_control = cmsgbuf;
-+ m.msg_controllen = sizeof (cmsgbuf);
-+
-+ /* First header should point to the start of the buffer. */
-+ cmsg = CMSG_FIRSTHDR (&m);
-+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
-+
-+ /* If the first header length consumes the entire buffer, there is no
-+ space remaining for additional headers. */
-+ cmsg->cmsg_len = sizeof (cmsgbuf);
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg == NULL);
-+
-+ /* The first header length is so big, using it would cause an overflow. */
-+ cmsg = CMSG_FIRSTHDR (&m);
-+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
-+ cmsg->cmsg_len = SIZE_MAX;
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg == NULL);
-+
-+ /* The first header leaves just enough space to hold another header. */
-+ cmsg = CMSG_FIRSTHDR (&m);
-+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
-+ cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr);
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg != NULL);
-+
-+ /* The first header leaves space but not enough for another header. */
-+ cmsg = CMSG_FIRSTHDR (&m);
-+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
-+ cmsg->cmsg_len ++;
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg == NULL);
-+
-+ /* The second header leaves just enough space to hold another header. */
-+ cmsg = CMSG_FIRSTHDR (&m);
-+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
-+ cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD));
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg != NULL);
-+ cmsg->cmsg_len = sizeof (cmsgbuf)
-+ - CMSG_SPACE (sizeof (PAYLOAD)) /* First header. */
-+ - sizeof (struct cmsghdr);
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg != NULL);
-+
-+ /* The second header leaves space but not enough for another header. */
-+ cmsg = CMSG_FIRSTHDR (&m);
-+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg != NULL);
-+ cmsg->cmsg_len ++;
-+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
-+ TEST_VERIFY_EXIT (cmsg == NULL);
-+
-+ return;
-+}
-diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c
-new file mode 100644
-index 0000000000..68c96d3c9d
---- /dev/null
-+++ b/socket/tst-cmsghdr.c
-@@ -0,0 +1,56 @@
-+/* Test ancillary data header creation.
-+ Copyright (C) 2022 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 <sys/socket.h>
-+#include <gnu/lib-names.h>
-+#include <support/xdlfcn.h>
-+#include <support/check.h>
-+
-+#define PAYLOAD "Hello, World!"
-+
-+/* CMSG_NXTHDR is a macro that calls an inline function defined in
-+ bits/socket.h. In case the function cannot be inlined, libc.so carries
-+ a copy. Both versions need to be tested. */
-+
-+#define CMSG_NXTHDR_IMPL CMSG_NXTHDR
-+#include "tst-cmsghdr-skeleton.c"
-+#undef CMSG_NXTHDR_IMPL
-+
-+static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *);
-+
-+#define CMSG_NXTHDR_IMPL cmsg_nxthdr
-+#include "tst-cmsghdr-skeleton.c"
-+#undef CMSG_NXTHDR_IMPL
-+
-+static int
-+do_test (void)
-+{
-+ static void *handle;
-+
-+ run_test_CMSG_NXTHDR ();
-+
-+ handle = xdlopen (LIBC_SO, RTLD_LAZY);
-+ cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *))
-+ xdlsym (handle, "__cmsg_nxthdr");
-+
-+ run_test_cmsg_nxthdr ();
-+
-+ return 0;
-+}
-+
-+#include <support/test-driver.c>
-diff --git a/sysdeps/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h
-index 5b35ea81ec..70fce4fb27 100644
---- a/sysdeps/mach/hurd/bits/socket.h
-+++ b/sysdeps/mach/hurd/bits/socket.h
-@@ -249,6 +249,12 @@ struct cmsghdr
- + CMSG_ALIGN (sizeof (struct cmsghdr)))
- #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
-
-+/* Given a length, return the additional padding necessary such that
-+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
-+#define __CMSG_PADDING(len) ((sizeof (size_t) \
-+ - ((len) & (sizeof (size_t) - 1))) \
-+ & (sizeof (size_t) - 1))
-+
- extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
- struct cmsghdr *__cmsg) __THROW;
- #ifdef __USE_EXTERN_INLINES
-@@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
- _EXTERN_INLINE struct cmsghdr *
- __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
- {
-+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
-+ __mhdr->msg_controllen because the user is required to obtain the first
-+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
-+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
-+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
-+ pointer arithmetic until we check its value. */
-+
-+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
-+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
-+
-+ size_t __size_needed = sizeof (struct cmsghdr)
-+ + __CMSG_PADDING (__cmsg->cmsg_len);
-+
-+ /* The current header is malformed, too small to be a full header. */
- if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
-- /* The kernel header does this so there may be a reason. */
- return (struct cmsghdr *) 0;
-
-+ /* There isn't enough space between __cmsg and the end of the buffer to
-+ hold the current cmsg *and* the next one. */
-+ if (((size_t)
-+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
-+ < __size_needed)
-+ || ((size_t)
-+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
-+ - __size_needed)
-+ < __cmsg->cmsg_len))
-+
-+ return (struct cmsghdr *) 0;
-+
-+ /* Now, we trust cmsg_len and can use it to find the next header. */
- __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
- + CMSG_ALIGN (__cmsg->cmsg_len));
-- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
-- + __mhdr->msg_controllen)
-- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
-- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
-- /* No more entries. */
-- return (struct cmsghdr *) 0;
- return __cmsg;
- }
- #endif /* Use `extern inline'. */
-diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
-index a139a16532..3ceda9fdbf 100644
---- a/sysdeps/unix/sysv/linux/Makefile
-+++ b/sysdeps/unix/sysv/linux/Makefile
-@@ -265,6 +265,14 @@ $(objpfx)tst-mount-consts.out: ../sysdeps/unix/sysv/linux/tst-mount-consts.py
- < /dev/null > $@ 2>&1; $(evaluate-test)
- $(objpfx)tst-mount-consts.out: $(sysdeps-linux-python-deps)
-
-+tests-special += $(objpfx)tst-mount-compile.out
-+$(objpfx)tst-mount-compile.out: ../sysdeps/unix/sysv/linux/tst-mount-compile.py
-+ $(sysdeps-linux-python) \
-+ ../sysdeps/unix/sysv/linux/tst-mount-compile.py \
-+ $(sysdeps-linux-python-cc) \
-+ < /dev/null > $@ 2>&1; $(evaluate-test)
-+$(objpfx)tst-mount-compile.out: $(sysdeps-linux-python-deps)
-+
- tst-rseq-disable-ENV = GLIBC_TUNABLES=glibc.pthread.rseq=0
-
- endif # $(subdir) == misc
-diff --git a/sysdeps/unix/sysv/linux/alpha/brk_call.h b/sysdeps/unix/sysv/linux/alpha/brk_call.h
-index b8088cf13f..0b851b6c86 100644
---- a/sysdeps/unix/sysv/linux/alpha/brk_call.h
-+++ b/sysdeps/unix/sysv/linux/alpha/brk_call.h
-@@ -21,8 +21,7 @@ __brk_call (void *addr)
- {
- unsigned long int result = INTERNAL_SYSCALL_CALL (brk, addr);
- if (result == -ENOMEM)
-- /* Mimic the default error reporting behavior. */
-- return addr;
-- else
-- return (void *) result;
-+ /* Mimic the generic error reporting behavior. */
-+ result = INTERNAL_SYSCALL_CALL (brk, 0);
-+ return (void *) result;
- }
-diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h
-index 4f1f810ea1..539b8d7716 100644
---- a/sysdeps/unix/sysv/linux/bits/socket.h
-+++ b/sysdeps/unix/sysv/linux/bits/socket.h
-@@ -307,6 +307,12 @@ struct cmsghdr
- + CMSG_ALIGN (sizeof (struct cmsghdr)))
- #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
-
-+/* Given a length, return the additional padding necessary such that
-+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
-+#define __CMSG_PADDING(len) ((sizeof (size_t) \
-+ - ((len) & (sizeof (size_t) - 1))) \
-+ & (sizeof (size_t) - 1))
-+
- extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
- struct cmsghdr *__cmsg) __THROW;
- #ifdef __USE_EXTERN_INLINES
-@@ -316,18 +322,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
- _EXTERN_INLINE struct cmsghdr *
- __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
- {
-+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
-+ __mhdr->msg_controllen because the user is required to obtain the first
-+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
-+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
-+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
-+ pointer arithmetic until we check its value. */
-+
-+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
-+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
-+
-+ size_t __size_needed = sizeof (struct cmsghdr)
-+ + __CMSG_PADDING (__cmsg->cmsg_len);
-+
-+ /* The current header is malformed, too small to be a full header. */
- if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
-- /* The kernel header does this so there may be a reason. */
- return (struct cmsghdr *) 0;
-
-+ /* There isn't enough space between __cmsg and the end of the buffer to
-+ hold the current cmsg *and* the next one. */
-+ if (((size_t)
-+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
-+ < __size_needed)
-+ || ((size_t)
-+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
-+ - __size_needed)
-+ < __cmsg->cmsg_len))
-+
-+ return (struct cmsghdr *) 0;
-+
-+ /* Now, we trust cmsg_len and can use it to find the next header. */
- __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
- + CMSG_ALIGN (__cmsg->cmsg_len));
-- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
-- + __mhdr->msg_controllen)
-- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
-- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
-- /* No more entries. */
-- return (struct cmsghdr *) 0;
- return __cmsg;
- }
- #endif /* Use `extern inline'. */
-diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
-index 15b7a3a925..24f72b797a 100644
---- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
-+++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
-@@ -23,18 +23,38 @@
- struct cmsghdr *
- __cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg)
- {
-+ /* We may safely assume that cmsg lies between mhdr->msg_control and
-+ mhdr->msg_controllen because the user is required to obtain the first
-+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
-+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
-+ trust the value of cmsg->cmsg_len and therefore do not use it in any
-+ pointer arithmetic until we check its value. */
-+
-+ unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control;
-+ unsigned char * cmsg_ptr = (unsigned char *) cmsg;
-+
-+ size_t size_needed = sizeof (struct cmsghdr)
-+ + __CMSG_PADDING (cmsg->cmsg_len);
-+
-+ /* The current header is malformed, too small to be a full header. */
- if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr))
-- /* The kernel header does this so there may be a reason. */
-- return NULL;
-+ return (struct cmsghdr *) 0;
-+
-+ /* There isn't enough space between cmsg and the end of the buffer to
-+ hold the current cmsg *and* the next one. */
-+ if (((size_t)
-+ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr)
-+ < size_needed)
-+ || ((size_t)
-+ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr
-+ - size_needed)
-+ < cmsg->cmsg_len))
-+
-+ return (struct cmsghdr *) 0;
-
-+ /* Now, we trust cmsg_len and can use it to find the next header. */
- cmsg = (struct cmsghdr *) ((unsigned char *) cmsg
- + CMSG_ALIGN (cmsg->cmsg_len));
-- if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control
-- + mhdr->msg_controllen)
-- || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len)
-- > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen)))
-- /* No more entries. */
-- return NULL;
- return cmsg;
- }
- libc_hidden_def (__cmsg_nxthdr)
-diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
-index bf4be80f8d..202520ee25 100644
---- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
-+++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
-@@ -122,6 +122,7 @@
- #define __NR_mbind 235
- #define __NR_membarrier 283
- #define __NR_memfd_create 279
-+#define __NR_memfd_secret 447
- #define __NR_migrate_pages 238
- #define __NR_mincore 232
- #define __NR_mkdirat 34
-diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
-index d656aedcc2..4e65f337d4 100644
---- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
-+++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
-@@ -127,6 +127,7 @@
- #define __NR_mbind 235
- #define __NR_membarrier 283
- #define __NR_memfd_create 279
-+#define __NR_memfd_secret 447
- #define __NR_migrate_pages 238
- #define __NR_mincore 232
- #define __NR_mkdirat 34
-diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h
-index f965986ba8..19841d0738 100644
---- a/sysdeps/unix/sysv/linux/sys/mount.h
-+++ b/sysdeps/unix/sysv/linux/sys/mount.h
-@@ -27,77 +27,113 @@
- #include <stddef.h>
- #include <sys/ioctl.h>
-
--#define BLOCK_SIZE 1024
-+#ifdef __has_include
-+# if __has_include ("linux/mount.h")
-+# include "linux/mount.h"
-+# endif
-+#endif
-+
-+
- #define BLOCK_SIZE_BITS 10
-+#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
-
-
- /* These are the fs-independent mount-flags: up to 16 flags are
- supported */
- enum
- {
-+#undef MS_RDONLY
- MS_RDONLY = 1, /* Mount read-only. */
- #define MS_RDONLY MS_RDONLY
-+#undef MS_NOSUID
- MS_NOSUID = 2, /* Ignore suid and sgid bits. */
- #define MS_NOSUID MS_NOSUID
-+#undef MS_NODEV
- MS_NODEV = 4, /* Disallow access to device special files. */
- #define MS_NODEV MS_NODEV
-+#undef MS_NOEXEC
- MS_NOEXEC = 8, /* Disallow program execution. */
- #define MS_NOEXEC MS_NOEXEC
-+#undef MS_SYNCHRONOUS
- MS_SYNCHRONOUS = 16, /* Writes are synced at once. */
- #define MS_SYNCHRONOUS MS_SYNCHRONOUS
-+#undef MS_REMOUNT
- MS_REMOUNT = 32, /* Alter flags of a mounted FS. */
- #define MS_REMOUNT MS_REMOUNT
-+#undef MS_MANDLOCK
- MS_MANDLOCK = 64, /* Allow mandatory locks on an FS. */
- #define MS_MANDLOCK MS_MANDLOCK
-+#undef MS_DIRSYNC
- MS_DIRSYNC = 128, /* Directory modifications are synchronous. */
- #define MS_DIRSYNC MS_DIRSYNC
-+#undef MS_NOSYMFOLLOW
- MS_NOSYMFOLLOW = 256, /* Do not follow symlinks. */
- #define MS_NOSYMFOLLOW MS_NOSYMFOLLOW
-+#undef MS_NOATIME
- MS_NOATIME = 1024, /* Do not update access times. */
- #define MS_NOATIME MS_NOATIME
-+#undef MS_NODIRATIME
- MS_NODIRATIME = 2048, /* Do not update directory access times. */
- #define MS_NODIRATIME MS_NODIRATIME
-+#undef MS_BIND
- MS_BIND = 4096, /* Bind directory at different place. */
- #define MS_BIND MS_BIND
-+#undef MS_MOVE
- MS_MOVE = 8192,
- #define MS_MOVE MS_MOVE
-+#undef MS_REC
- MS_REC = 16384,
- #define MS_REC MS_REC
-+#undef MS_SILENT
- MS_SILENT = 32768,
- #define MS_SILENT MS_SILENT
-+#undef MS_POSIXACL
- MS_POSIXACL = 1 << 16, /* VFS does not apply the umask. */
- #define MS_POSIXACL MS_POSIXACL
-+#undef MS_UNBINDABLE
- MS_UNBINDABLE = 1 << 17, /* Change to unbindable. */
- #define MS_UNBINDABLE MS_UNBINDABLE
-+#undef MS_PRIVATE
- MS_PRIVATE = 1 << 18, /* Change to private. */
- #define MS_PRIVATE MS_PRIVATE
-+#undef MS_SLAVE
- MS_SLAVE = 1 << 19, /* Change to slave. */
- #define MS_SLAVE MS_SLAVE
-+#undef MS_SHARED
- MS_SHARED = 1 << 20, /* Change to shared. */
- #define MS_SHARED MS_SHARED
-+#undef MS_RELATIME
- MS_RELATIME = 1 << 21, /* Update atime relative to mtime/ctime. */
- #define MS_RELATIME MS_RELATIME
-+#undef MS_KERNMOUNT
- MS_KERNMOUNT = 1 << 22, /* This is a kern_mount call. */
- #define MS_KERNMOUNT MS_KERNMOUNT
-+#undef MS_I_VERSION
- MS_I_VERSION = 1 << 23, /* Update inode I_version field. */
- #define MS_I_VERSION MS_I_VERSION
-+#undef MS_STRICTATIME
- MS_STRICTATIME = 1 << 24, /* Always perform atime updates. */
- #define MS_STRICTATIME MS_STRICTATIME
-+#undef MS_LAZYTIME
- MS_LAZYTIME = 1 << 25, /* Update the on-disk [acm]times lazily. */
- #define MS_LAZYTIME MS_LAZYTIME
-+#undef MS_ACTIVE
- MS_ACTIVE = 1 << 30,
- #define MS_ACTIVE MS_ACTIVE
-+#undef MS_NOUSER
- MS_NOUSER = 1 << 31
- #define MS_NOUSER MS_NOUSER
- };
-
- /* Flags that can be altered by MS_REMOUNT */
-+#undef MS_RMT_MASK
- #define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION \
- |MS_LAZYTIME)
-
-
- /* Magic mount flag number. Has to be or-ed to the flag values. */
-
-+#undef MS_MGC_VAL
- #define MS_MGC_VAL 0xc0ed0000 /* Magic flag number to indicate "new" flags */
- #define MS_MGC_MSK 0xffff0000 /* Magic flag number mask */
-
-@@ -106,20 +142,35 @@ enum
- is probably as bad and I don't want to create yet another include
- file. */
-
-+#undef BLKROSET
- #define BLKROSET _IO(0x12, 93) /* Set device read-only (0 = read-write). */
-+#undef BLKROGET
- #define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */
-+#undef BLKRRPART
- #define BLKRRPART _IO(0x12, 95) /* Re-read partition table. */
-+#undef BLKGETSIZE
- #define BLKGETSIZE _IO(0x12, 96) /* Return device size. */
-+#undef BLKFLSBUF
- #define BLKFLSBUF _IO(0x12, 97) /* Flush buffer cache. */
-+#undef BLKRASET
- #define BLKRASET _IO(0x12, 98) /* Set read ahead for block device. */
-+#undef BLKRAGET
- #define BLKRAGET _IO(0x12, 99) /* Get current read ahead setting. */
-+#undef BLKFRASET
- #define BLKFRASET _IO(0x12,100) /* Set filesystem read-ahead. */
-+#undef BLKFRAGET
- #define BLKFRAGET _IO(0x12,101) /* Get filesystem read-ahead. */
-+#undef BLKSECTSET
- #define BLKSECTSET _IO(0x12,102) /* Set max sectors per request. */
-+#undef BLKSECTGET
- #define BLKSECTGET _IO(0x12,103) /* Get max sectors per request. */
-+#undef BLKSSZGET
- #define BLKSSZGET _IO(0x12,104) /* Get block device sector size. */
-+#undef BLKBSZGET
- #define BLKBSZGET _IOR(0x12,112,size_t)
-+#undef BLKBSZSET
- #define BLKBSZSET _IOW(0x12,113,size_t)
-+#undef BLKGETSIZE64
- #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size. */
-
-
-@@ -137,9 +188,6 @@ enum
- };
-
-
--/* fsopen flags. */
--#define FSOPEN_CLOEXEC 0x00000001
--
- /* fsmount flags. */
- #define FSMOUNT_CLOEXEC 0x00000001
-
-@@ -157,6 +205,7 @@ enum
- #define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 /* Do not follow symlinks. */
-
-
-+#ifndef MOUNT_ATTR_SIZE_VER0
- /* For mount_setattr. */
- struct mount_attr
- {
-@@ -165,6 +214,7 @@ struct mount_attr
- uint64_t propagation;
- uint64_t userns_fd;
- };
-+#endif
-
- #define MOUNT_ATTR_SIZE_VER0 32 /* sizeof first published struct */
-
-@@ -185,26 +235,31 @@ struct mount_attr
- #define FSPICK_EMPTY_PATH 0x00000008
-
-
-+#ifndef FSOPEN_CLOEXEC
- /* The type of fsconfig call made. */
- enum fsconfig_command
- {
- FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */
--#define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
-+# define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
- FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */
--#define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
-+# define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
- FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */
--#define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
-+# define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
- FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */
--#define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
-+# define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
- FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */
--#define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
-+# define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
- FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */
--#define FSCONFIG_SET_FD FSCONFIG_SET_FD
-+# define FSCONFIG_SET_FD FSCONFIG_SET_FD
- FSCONFIG_CMD_CREATE = 6, /* Invoke superblock creation */
--#define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
-+# define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
- FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */
--#define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
-+# define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
- };
-+#endif
-+
-+/* fsopen flags. */
-+#define FSOPEN_CLOEXEC 0x00000001
-
- /* open_tree flags. */
- #define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
-diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
-index 6c7b2f7011..028ad3107a 100644
---- a/sysdeps/unix/sysv/linux/syscall-names.list
-+++ b/sysdeps/unix/sysv/linux/syscall-names.list
-@@ -21,8 +21,8 @@
- # This file can list all potential system calls. The names are only
- # used if the installed kernel headers also provide them.
-
--# The list of system calls is current as of Linux 5.18.
--kernel 5.18
-+# The list of system calls is current as of Linux 5.19.
-+kernel 5.19
-
- FAST_atomic_update
- FAST_cmpxchg
-diff --git a/sysdeps/unix/sysv/linux/tst-mount-compile.py b/sysdeps/unix/sysv/linux/tst-mount-compile.py
-new file mode 100755
-index 0000000000..0ec74d4e0b
---- /dev/null
-+++ b/sysdeps/unix/sysv/linux/tst-mount-compile.py
-@@ -0,0 +1,66 @@
-+#!/usr/bin/python3
-+# Check if glibc provided sys/mount.h can be used along related kernel
-+# headers.
-+# Copyright (C) 2022 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/>.
-+
-+import argparse
-+import sys
-+
-+import glibcextract
-+
-+
-+def main():
-+ """The main entry point."""
-+ parser = argparse.ArgumentParser(
-+ description='Check if glibc provided sys/mount.h can be '
-+ ' used along related kernel headers.')
-+ parser.add_argument('--cc', metavar='CC',
-+ help='C compiler (including options) to use')
-+ args = parser.parse_args()
-+
-+ if glibcextract.compile_c_snippet(
-+ '#include <linux/mount.h>',
-+ args.cc).returncode != 0:
-+ sys.exit (77)
-+
-+ def check(testname, snippet):
-+ # Add -Werror to catch macro redefinitions and _ISOMAC to avoid
-+ # internal glibc definitions.
-+ r = glibcextract.compile_c_snippet(snippet, args.cc,
-+ '-Werror -D_ISOMAC')
-+ if r.returncode != 0:
-+ print('error: test {}:\n{}'.format(testname, r.output.decode()))
-+ return r.returncode
-+
-+ status = max(
-+ check("sys/mount.h + linux/mount.h",
-+ "#include <sys/mount.h>\n"
-+ "#include <linux/mount.h>"),
-+ check("sys/mount.h + linux/fs.h",
-+ "#include <sys/mount.h>\n"
-+ "#include <linux/fs.h>"),
-+ check("linux/mount.h + sys/mount.h",
-+ "#include <linux/mount.h>\n"
-+ "#include <sys/mount.h>"),
-+ check("linux/fs.h + sys/mount.h",
-+ "#include <linux/fs.h>\n"
-+ "#include <sys/mount.h>"))
-+ sys.exit(status)
-+
-+if __name__ == '__main__':
-+ main()
-diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py
-index a62f803123..be2ef2daf1 100755
---- a/sysdeps/unix/sysv/linux/tst-mount-consts.py
-+++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py
-@@ -33,6 +33,11 @@ def main():
- help='C compiler (including options) to use')
- args = parser.parse_args()
-
-+ if glibcextract.compile_c_snippet(
-+ '#include <linux/mount.h>',
-+ args.cc).returncode != 0:
-+ sys.exit (77)
-+
- linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
- # Constants in glibc were updated to match Linux v5.16. When glibc
- # constants are updated this value should be updated to match the
-diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
-index 90cbb9be64..d732173abd 100644
---- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
-+++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
-@@ -33,11 +33,13 @@ def main():
- help='C compiler (including options) to use')
- args = parser.parse_args()
-
-- linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
-- # Linux started to provide pidfd.h with 5.10.
-- if linux_version_headers < (5, 10):
-+ if glibcextract.compile_c_snippet(
-+ '#include <linux/pidfd.h>',
-+ args.cc).returncode != 0:
- sys.exit (77)
-- linux_version_glibc = (5, 18)
-+
-+ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
-+ linux_version_glibc = (5, 19)
- sys.exit(glibcextract.compare_macro_consts(
- '#include <sys/pidfd.h>\n',
- '#include <asm/fcntl.h>\n'
-diff --git a/sysdeps/unix/sysv/linux/tst-pidfd.c b/sysdeps/unix/sysv/linux/tst-pidfd.c
-index 037af22290..5711d1c312 100644
---- a/sysdeps/unix/sysv/linux/tst-pidfd.c
-+++ b/sysdeps/unix/sysv/linux/tst-pidfd.c
-@@ -147,8 +147,11 @@ do_test (void)
- may be denied if the process doesn't have CAP_SYS_PTRACE or
- if a LSM security_ptrace_access_check denies access. */
- if (fd == -1 && errno == EPERM)
-- FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
-- "skipping test");
-+ {
-+ TEST_COMPARE (pidfd_send_signal (pidfd, SIGKILL, NULL, 0), 0);
-+ FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
-+ "skipping test");
-+ }
- TEST_VERIFY (fd > 0);
-
- char *path = xasprintf ("/proc/%d/fd/%d", pid, remote_fd);
-diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
-index e6b9e8743a..3d19d5556f 100644
---- a/wcsmbs/Makefile
-+++ b/wcsmbs/Makefile
-@@ -73,6 +73,8 @@ $(objpfx)tst-wcstol-locale.out: $(gen-locales)
- $(objpfx)tst-wcstod-nan-locale.out: $(gen-locales)
- $(objpfx)tst-c16-surrogate.out: $(gen-locales)
- $(objpfx)tst-c32-state.out: $(gen-locales)
-+$(objpfx)test-c8rtomb.out: $(gen-locales)
-+$(objpfx)test-mbrtoc8.out: $(gen-locales)
- endif
-
- $(objpfx)tst-wcstod-round: $(libm)
-diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
-index c37e8619a0..5f7139f279 100644
---- a/wcsmbs/uchar.h
-+++ b/wcsmbs/uchar.h
-@@ -34,8 +34,16 @@
- /* Declare the C2x char8_t typedef in C2x modes, but only if the C++
- __cpp_char8_t feature test macro is not defined. */
- #if __GLIBC_USE (ISOC2X) && !defined __cpp_char8_t
-+#if __GNUC_PREREQ (10, 0) && defined __cplusplus
-+/* Suppress the diagnostic regarding char8_t being a keyword in C++20. */
-+# pragma GCC diagnostic push
-+# pragma GCC diagnostic ignored "-Wc++20-compat"
-+#endif
- /* Define the 8-bit character type. */
- typedef unsigned char char8_t;
-+#if __GNUC_PREREQ (10, 0) && defined __cplusplus
-+# pragma GCC diagnostic pop
-+#endif
- #endif
-
- #ifndef __USE_ISOCXX11
-diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure
---- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:02:32.741186019 +1000
-+++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:03:05.314302356 +1000
-@@ -4,10 +4,10 @@
- test -n "$libc_cv_slibdir" ||
- case "$prefix" in
- /usr | /usr/)
-- libc_cv_slibdir='/lib64'
-- libc_cv_rtlddir='/lib64'
-+ libc_cv_slibdir='/lib'
-+ libc_cv_rtlddir='/lib'
- if test "$libdir" = '${exec_prefix}/lib'; then
-- libdir='${exec_prefix}/lib64';
-+ libdir='${exec_prefix}/lib';
- # Locale data can be shared between 32-bit and 64-bit libraries.
- libc_cv_complocaledir='${exec_prefix}/lib/locale'
- fi
-diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h
---- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:02:32.742186053 +1000
-+++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:03:05.314302356 +1000
-@@ -18,9 +18,9 @@
- #include <sysdeps/generic/ldconfig.h>
-
- #define SYSDEP_KNOWN_INTERPRETER_NAMES \
-- { "/lib/ld-linux.so.2", FLAG_ELF_LIBC6 }, \
-+ { "/lib32/ld-linux.so.2", FLAG_ELF_LIBC6 }, \
- { "/libx32/ld-linux-x32.so.2", FLAG_ELF_LIBC6 }, \
-- { "/lib64/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 },
-+ { "/lib/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 },
- #define SYSDEP_KNOWN_LIBRARY_NAMES \
- { "libc.so.6", FLAG_ELF_LIBC6 }, \
- { "libm.so.6", FLAG_ELF_LIBC6 },
diff --git a/glibc/glibc-2.36-2.patch b/glibc/glibc-2.36-2.patch
new file mode 100644
index 00000000..b810e453
--- /dev/null
+++ b/glibc/glibc-2.36-2.patch
@@ -0,0 +1,6002 @@
+diff --git a/NEWS b/NEWS
+index f61e521fc8..91bcfeb7a6 100644
+--- a/NEWS
++++ b/NEWS
+@@ -5,6 +5,31 @@ See the end for copying conditions.
+ Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
+ using `glibc' in the "product" field.
+
++Version 2.36.1
++
++Security related changes:
++
++ CVE-2022-39046: When the syslog function is passed a crafted input
++ string larger than 1024 bytes, it reads uninitialized memory from the
++ heap and prints it to the target log file, potentially revealing a
++ portion of the contents of the heap.
++
++The following bugs are resolved with this release:
++
++ [12154] Do not fail DNS resolution for CNAMEs which are not host names
++ [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning
++ [29305] Conserve NSS buffer space during DNS packet parsing
++ [29415] nscd: Fix netlink cache invalidation if epoll is used
++ [28937] New DSO dependency sorter does not put new map first if in a cycle
++ [29446] _dlopen now ignores dl_caller argument in static mode
++ [29485] Linux: Terminate subprocess on late failure in tst-pidfd
++ [29490] alpha: New __brk_call implementation is broken
++ [29528] elf: Call __libc_early_init for reused namespaces
++ [29537] libc: [2.34 regression]: Alignment issue on m68k when using
++ [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are
++ [29583] Use 64-bit interfaces in gconv_parseconfdir
++ [29638] libc: stdlib: arc4random fallback is never used
++
+ Version 2.36
+
+ Major new features:
+diff --git a/bits/socket.h b/bits/socket.h
+index 2b99dea33b..aac8c49b00 100644
+--- a/bits/socket.h
++++ b/bits/socket.h
+@@ -245,6 +245,12 @@ struct cmsghdr
+ + CMSG_ALIGN (sizeof (struct cmsghdr)))
+ #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
+
++/* Given a length, return the additional padding necessary such that
++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
++#define __CMSG_PADDING(len) ((sizeof (size_t) \
++ - ((len) & (sizeof (size_t) - 1))) \
++ & (sizeof (size_t) - 1))
++
+ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+ struct cmsghdr *__cmsg) __THROW;
+ #ifdef __USE_EXTERN_INLINES
+@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+ _EXTERN_INLINE struct cmsghdr *
+ __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
+ {
++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
++ __mhdr->msg_controllen because the user is required to obtain the first
++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
++ trust the value of __cmsg->cmsg_len and therefore do not use it in any
++ pointer arithmetic until we check its value. */
++
++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
++
++ size_t __size_needed = sizeof (struct cmsghdr)
++ + __CMSG_PADDING (__cmsg->cmsg_len);
++
++ /* The current header is malformed, too small to be a full header. */
+ if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
+- /* The kernel header does this so there may be a reason. */
+ return (struct cmsghdr *) 0;
+
++ /* There isn't enough space between __cmsg and the end of the buffer to
++ hold the current cmsg *and* the next one. */
++ if (((size_t)
++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
++ < __size_needed)
++ || ((size_t)
++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
++ - __size_needed)
++ < __cmsg->cmsg_len))
++
++ return (struct cmsghdr *) 0;
++
++ /* Now, we trust cmsg_len and can use it to find the next header. */
+ __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
+ + CMSG_ALIGN (__cmsg->cmsg_len));
+- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
+- + __mhdr->msg_controllen)
+- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
+- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
+- /* No more entries. */
+- return (struct cmsghdr *) 0;
+ return __cmsg;
+ }
+ #endif /* Use `extern inline'. */
+diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c
+index 2696dde4b1..9b07b4e132 100644
+--- a/dlfcn/dlopen.c
++++ b/dlfcn/dlopen.c
+@@ -90,7 +90,7 @@ compat_symbol (libdl, ___dlopen, dlopen, GLIBC_2_1);
+ void *
+ __dlopen (const char *file, int mode, void *dl_caller)
+ {
+- return dlopen_implementation (file, mode, RETURN_ADDRESS (0));
++ return dlopen_implementation (file, mode, dl_caller);
+ }
+
+ void *
+diff --git a/elf/Makefile b/elf/Makefile
+index fd77d0c7c8..72178d33ff 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -374,6 +374,8 @@ tests += \
+ tst-align \
+ tst-align2 \
+ tst-align3 \
++ tst-audit-tlsdesc \
++ tst-audit-tlsdesc-dlopen \
+ tst-audit1 \
+ tst-audit2 \
+ tst-audit8 \
+@@ -408,6 +410,7 @@ tests += \
+ tst-dlmopen4 \
+ tst-dlmopen-dlerror \
+ tst-dlmopen-gethostbyname \
++ tst-dlmopen-twice \
+ tst-dlopenfail \
+ tst-dlopenfail-2 \
+ tst-dlopenrpath \
+@@ -765,6 +768,8 @@ modules-names += \
+ tst-alignmod3 \
+ tst-array2dep \
+ tst-array5dep \
++ tst-audit-tlsdesc-mod1 \
++ tst-audit-tlsdesc-mod2 \
+ tst-audit11mod1 \
+ tst-audit11mod2 \
+ tst-audit12mod1 \
+@@ -798,6 +803,7 @@ modules-names += \
+ tst-auditmanymod7 \
+ tst-auditmanymod8 \
+ tst-auditmanymod9 \
++ tst-auditmod-tlsdesc \
+ tst-auditmod1 \
+ tst-auditmod9a \
+ tst-auditmod9b \
+@@ -834,6 +840,8 @@ modules-names += \
+ tst-dlmopen1mod \
+ tst-dlmopen-dlerror-mod \
+ tst-dlmopen-gethostbyname-mod \
++ tst-dlmopen-twice-mod1 \
++ tst-dlmopen-twice-mod2 \
+ tst-dlopenfaillinkmod \
+ tst-dlopenfailmod1 \
+ tst-dlopenfailmod2 \
+@@ -990,23 +998,8 @@ modules-names += tst-gnu2-tls1mod
+ $(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so
+ tst-gnu2-tls1mod.so-no-z-defs = yes
+ CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2
++endif # $(have-mtls-dialect-gnu2)
+
+-tests += tst-audit-tlsdesc tst-audit-tlsdesc-dlopen
+-modules-names += tst-audit-tlsdesc-mod1 tst-audit-tlsdesc-mod2 tst-auditmod-tlsdesc
+-$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
+- $(objpfx)tst-audit-tlsdesc-mod2.so \
+- $(shared-thread-library)
+-CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2
+-CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2
+-$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library)
+-$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \
+- $(objpfx)tst-audit-tlsdesc-mod2.so
+-$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so
+-$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
+-tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
+-$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
+-tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
+-endif
+ ifeq (yes,$(have-protected-data))
+ modules-names += tst-protected1moda tst-protected1modb
+ tests += tst-protected1a tst-protected1b
+@@ -2967,3 +2960,25 @@ $(objpfx)tst-tls-allocation-failure-static-patched.out: \
+ grep -q '^Fatal glibc error: Cannot allocate TLS block$$' $@ \
+ && grep -q '^status: 127$$' $@; \
+ $(evaluate-test)
++
++$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
++ $(objpfx)tst-audit-tlsdesc-mod2.so \
++ $(shared-thread-library)
++ifeq (yes,$(have-mtls-dialect-gnu2))
++# The test is valid for all TLS types, but we want to exercise GNU2
++# TLS if possible.
++CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2
++CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2
++endif
++$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library)
++$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \
++ $(objpfx)tst-audit-tlsdesc-mod2.so
++$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so
++$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
++tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
++$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
++tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
++
++$(objpfx)tst-dlmopen-twice.out: \
++ $(objpfx)tst-dlmopen-twice-mod1.so \
++ $(objpfx)tst-dlmopen-twice-mod2.so
+diff --git a/elf/dl-cache.c b/elf/dl-cache.c
+index 8bbf110d02..b97c17b3a9 100644
+--- a/elf/dl-cache.c
++++ b/elf/dl-cache.c
+@@ -509,8 +509,9 @@ _dl_load_cache_lookup (const char *name)
+ we are accessing. Therefore we must make the copy of the
+ mapping data without using malloc. */
+ char *temp;
+- temp = alloca (strlen (best) + 1);
+- strcpy (temp, best);
++ size_t best_len = strlen (best) + 1;
++ temp = alloca (best_len);
++ memcpy (temp, best, best_len);
+ return __strdup (temp);
+ }
+
+diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
+index 6f161f6ad5..92eb53790e 100644
+--- a/elf/dl-hwcaps.c
++++ b/elf/dl-hwcaps.c
+@@ -193,7 +193,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
+ /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix
+ and a "/" suffix once stored in the result. */
+ hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1;
+- size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
++ size_t hwcaps_sz = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
+ + hwcaps_counts.total_length);
+
+ /* Count the number of bits set in the masked value. */
+@@ -229,11 +229,12 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
+ assert (m == cnt);
+
+ /* Determine the total size of all strings together. */
++ size_t total;
+ if (cnt == 1)
+- total += temp[0].len + 1;
++ total = temp[0].len + 1;
+ else
+ {
+- total += temp[0].len + temp[cnt - 1].len + 2;
++ total = temp[0].len + temp[cnt - 1].len + 2;
+ if (cnt > 2)
+ {
+ total <<= 1;
+@@ -255,6 +256,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
+ /* This is the overall result, including both glibc-hwcaps
+ subdirectories and the legacy hwcaps subdirectories using the
+ power set construction. */
++ total += hwcaps_sz;
+ struct r_strlenpair *overall_result
+ = malloc (*sz * sizeof (*result) + total);
+ if (overall_result == NULL)
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index a23e65926b..46e8066fd8 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -844,11 +844,14 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
+ _dl_signal_error (EINVAL, file, NULL, N_("\
+ no more namespaces available for dlmopen()"));
+ }
+- else if (nsid == GL(dl_nns))
+- {
+- __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
+- ++GL(dl_nns);
+- }
++
++ if (nsid == GL(dl_nns))
++ ++GL(dl_nns);
++
++ /* Initialize the new namespace. Most members are
++ zero-initialized, only the lock needs special treatment. */
++ memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid]));
++ __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
+
+ _dl_debug_update (nsid)->r_state = RT_CONSISTENT;
+ }
+diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
+index 96638d7ed1..3e2a6a584e 100644
+--- a/elf/dl-sort-maps.c
++++ b/elf/dl-sort-maps.c
+@@ -27,12 +27,12 @@
+ If FOR_FINI is true, this is called for finishing an object. */
+ static void
+ _dl_sort_maps_original (struct link_map **maps, unsigned int nmaps,
+- unsigned int skip, bool for_fini)
++ bool force_first, bool for_fini)
+ {
+ /* Allows caller to do the common optimization of skipping the first map,
+ usually the main binary. */
+- maps += skip;
+- nmaps -= skip;
++ maps += force_first;
++ nmaps -= force_first;
+
+ /* A list of one element need not be sorted. */
+ if (nmaps <= 1)
+@@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map,
+
+ static void
+ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
+- unsigned int skip __attribute__ ((unused)), bool for_fini)
++ bool force_first, bool for_fini)
+ {
++ struct link_map *first_map = maps[0];
+ for (int i = nmaps - 1; i >= 0; i--)
+ maps[i]->l_visited = 0;
+
+@@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
+ Adjusting the order so that maps[0] is last traversed naturally avoids
+ this problem.
+
+- Further, the old "optimization" of skipping the main object at maps[0]
+- from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general
+- no longer valid, since traversing along object dependency-links
+- may "find" the main object even when it is not included in the initial
+- order (e.g. a dlopen()'ed shared object can have circular dependencies
+- linked back to itself). In such a case, traversing N-1 objects will
+- create a N-object result, and raise problems.
+-
+ To summarize, just passing in the full list, and iterating from back
+ to front makes things much more straightforward. */
+
+@@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
+ }
+
+ memcpy (maps, rpo, sizeof (struct link_map *) * nmaps);
++
++ /* Skipping the first object at maps[0] is not valid in general,
++ since traversing along object dependency-links may "find" that
++ first object even when it is not included in the initial order
++ (e.g., a dlopen'ed shared object can have circular dependencies
++ linked back to itself). In such a case, traversing N-1 objects
++ will create a N-object result, and raise problems. Instead,
++ force the object back into first place after sorting. This naive
++ approach may introduce further dependency ordering violations
++ compared to rotating the cycle until the first map is again in
++ the first position, but as there is a cycle, at least one
++ violation is already present. */
++ if (force_first && maps[0] != first_map)
++ {
++ int i;
++ for (i = 0; maps[i] != first_map; ++i)
++ ;
++ assert (i < nmaps);
++ memmove (&maps[1], maps, i * sizeof (maps[0]));
++ maps[0] = first_map;
++ }
+ }
+
+ void
+@@ -286,7 +300,7 @@ _dl_sort_maps_init (void)
+
+ void
+ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
+- unsigned int skip, bool for_fini)
++ bool force_first, bool for_fini)
+ {
+ /* It can be tempting to use a static function pointer to store and call
+ the current selected sorting algorithm routine, but experimentation
+@@ -296,9 +310,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
+ input cases. A simple if-case with direct function calls appears to
+ be the fastest. */
+ if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
+- _dl_sort_maps_original (maps, nmaps, skip, for_fini);
++ _dl_sort_maps_original (maps, nmaps, force_first, for_fini);
+ else
+- _dl_sort_maps_dfs (maps, nmaps, skip, for_fini);
++ _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini);
+ }
+
+ #endif /* HAVE_TUNABLES. */
+diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def
+index 5f7f18ef27..4bf9052db1 100644
+--- a/elf/dso-sort-tests-1.def
++++ b/elf/dso-sort-tests-1.def
+@@ -64,3 +64,10 @@ output: b>a>{}<a<b
+ tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c
+ output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
+ output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
++
++# Test that even in the presence of dependency loops involving dlopen'ed
++# object, that object is initialized last (and not unloaded prematurely).
++# Final destructor order is indeterminate due to the cycle.
++tst-bz28937: {+a;+b;-b;+c;%c};a->a1;a->a2;a2->a;b->b1;c->a1;c=>a1
++output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a<a2<c<a1
++output(glibc.rtld.dynamic_sort=2): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a2<a<c<a1
+diff --git a/elf/rtld.c b/elf/rtld.c
+index cbbaf4a331..3e771a93d8 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -2122,6 +2122,12 @@ dl_main (const ElfW(Phdr) *phdr,
+ if (l->l_faked)
+ /* The library was not found. */
+ _dl_printf ("\t%s => not found\n", l->l_libname->name);
++ else if (strcmp (l->l_libname->name, l->l_name) == 0)
++ /* Print vDSO like libraries without duplicate name. Some
++ consumers depend of this format. */
++ _dl_printf ("\t%s (0x%0*Zx)\n", l->l_libname->name,
++ (int) sizeof l->l_map_start * 2,
++ (size_t) l->l_map_start);
+ else
+ _dl_printf ("\t%s => %s (0x%0*Zx)\n",
+ DSO_FILENAME (l->l_libname->name),
+diff --git a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c
+new file mode 100644
+index 0000000000..0eaf04948c
+--- /dev/null
++++ b/elf/tst-dlmopen-twice-mod1.c
+@@ -0,0 +1,37 @@
++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 1.
++ Copyright (C) 2022 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 <stdio.h>
++
++static void __attribute__ ((constructor))
++init (void)
++{
++ puts ("info: tst-dlmopen-twice-mod1.so loaded");
++ fflush (stdout);
++}
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++ puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded");
++ fflush (stdout);
++}
++
++/* Large allocation. The second module does not have this, so it
++ should load libc at a different address. */
++char large_allocate[16 * 1024 * 1024];
+diff --git a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c
+new file mode 100644
+index 0000000000..40c6c01f96
+--- /dev/null
++++ b/elf/tst-dlmopen-twice-mod2.c
+@@ -0,0 +1,50 @@
++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 2.
++ Copyright (C) 2022 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 <ctype.h>
++#include <stdio.h>
++
++static void __attribute__ ((constructor))
++init (void)
++{
++ puts ("info: tst-dlmopen-twice-mod2.so loaded");
++ fflush (stdout);
++}
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++ puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded");
++ fflush (stdout);
++}
++
++int
++run_check (void)
++{
++ puts ("info: about to call isalpha");
++ fflush (stdout);
++
++ volatile char ch = 'a';
++ if (!isalpha (ch))
++ {
++ puts ("error: isalpha ('a') is not true");
++ fflush (stdout);
++ return 1;
++ }
++ return 0;
++}
+diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c
+new file mode 100644
+index 0000000000..449f3c8fa9
+--- /dev/null
++++ b/elf/tst-dlmopen-twice.c
+@@ -0,0 +1,34 @@
++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Main.
++ Copyright (C) 2022 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 <support/xdlfcn.h>
++#include <support/check.h>
++
++static int
++do_test (void)
++{
++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", RTLD_NOW);
++ xdlclose (handle);
++ handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW);
++ int (*run_check) (void) = xdlsym (handle, "run_check");
++ TEST_COMPARE (run_check (), 0);
++ xdlclose (handle);
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
+index debb96b322..b72933b526 100644
+--- a/iconv/gconv_parseconfdir.h
++++ b/iconv/gconv_parseconfdir.h
+@@ -29,14 +29,14 @@
+ # define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr)
+ # define asprintf __asprintf
+ # define opendir __opendir
+-# define readdir __readdir
++# define readdir64 __readdir64
+ # define closedir __closedir
+ # define mempcpy __mempcpy
+-# define struct_stat struct __stat64_t64
+-# define lstat __lstat64_time64
++# define struct_stat64 struct __stat64_t64
++# define lstat64 __lstat64_time64
+ # define feof_unlocked __feof_unlocked
+ #else
+-# define struct_stat struct stat
++# define struct_stat64 struct stat64
+ #endif
+
+ /* Name of the file containing the module information in the directories
+@@ -148,8 +148,8 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
+ DIR *confdir = opendir (buf);
+ if (confdir != NULL)
+ {
+- struct dirent *ent;
+- while ((ent = readdir (confdir)) != NULL)
++ struct dirent64 *ent;
++ while ((ent = readdir64 (confdir)) != NULL)
+ {
+ if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN)
+ continue;
+@@ -161,12 +161,12 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
+ && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
+ {
+ char *conf;
+- struct_stat st;
++ struct_stat64 st;
+ if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
+ continue;
+
+ if (ent->d_type != DT_UNKNOWN
+- || (lstat (conf, &st) != -1 && S_ISREG (st.st_mode)))
++ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode)))
+ found |= read_conf_file (conf, dir, dir_len);
+
+ free (conf);
+diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h
+index 53f1dbc7c3..c27e7886b7 100644
+--- a/include/arpa/nameser.h
++++ b/include/arpa/nameser.h
+@@ -55,6 +55,12 @@ int __ns_name_ntop (const unsigned char *, char *, size_t) __THROW;
+ int __ns_name_unpack (const unsigned char *, const unsigned char *,
+ const unsigned char *, unsigned char *, size_t) __THROW;
+
++/* Like ns_samename, but for uncompressed binary names. Return true
++ if the two arguments compare are equal as case-insensitive domain
++ names. */
++_Bool __ns_samebinaryname (const unsigned char *, const unsigned char *)
++ attribute_hidden;
++
+ #define ns_msg_getflag(handle, flag) \
+ (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift)
+
+@@ -89,5 +95,105 @@ libc_hidden_proto (__ns_name_unpack)
+ extern __typeof (ns_samename) __libc_ns_samename;
+ libc_hidden_proto (__libc_ns_samename)
+
++/* Packet parser helper functions. */
++
++/* Verify that P points to an uncompressed domain name in wire format.
++ On success, return the length of the encoded name, including the
++ terminating null byte. On failure, return -1 and set errno. EOM
++ must point one past the last byte in the packet. */
++int __ns_name_length_uncompressed (const unsigned char *p,
++ const unsigned char *eom) attribute_hidden;
++
++/* Iterator over the resource records in a DNS packet. */
++struct ns_rr_cursor
++{
++ /* These members are not changed after initialization. */
++ const unsigned char *begin; /* First byte of packet. */
++ const unsigned char *end; /* One past the last byte of the packet. */
++ const unsigned char *first_rr; /* First resource record (or packet end). */
++
++ /* Advanced towards the end while reading the packet. */
++ const unsigned char *current;
++};
++
++/* Returns the RCODE field from the DNS header. */
++static inline int
++ns_rr_cursor_rcode (const struct ns_rr_cursor *c)
++{
++ return c->begin[3] & 0x0f; /* Lower 4 bits at offset 3. */
++}
++
++/* Returns the length of the answer section according to the DNS header. */
++static inline int
++ns_rr_cursor_ancount (const struct ns_rr_cursor *c)
++{
++ return c->begin[6] * 256 + c->begin[7]; /* 16 bits at offset 6. */
++}
++
++/* Returns the length of the authority (name server) section according
++ to the DNS header. */
++static inline int
++ns_rr_cursor_nscount (const struct ns_rr_cursor *c)
++{
++ return c->begin[8] * 256 + c->begin[9]; /* 16 bits at offset 8. */
++}
++
++/* Returns the length of the additional data section according to the
++ DNS header. */
++static inline int
++ns_rr_cursor_adcount (const struct ns_rr_cursor *c)
++{
++ return c->begin[10] * 256 + c->begin[11]; /* 16 bits at offset 10. */
++}
++
++/* Returns a pointer to the uncompressed question name in wire
++ format. */
++static inline const unsigned char *
++ns_rr_cursor_qname (const struct ns_rr_cursor *c)
++{
++ return c->begin + 12; /* QNAME starts right after the header. */
++}
++
++/* Returns the question type of the first and only question. */
++static inline const int
++ns_rr_cursor_qtype (const struct ns_rr_cursor *c)
++{
++ /* 16 bits 4 bytes back from the first RR header start. */
++ return c->first_rr[-4] * 256 + c->first_rr[-3];
++}
++
++/* Returns the clss of the first and only question (usally C_IN). */
++static inline const int
++ns_rr_cursor_qclass (const struct ns_rr_cursor *c)
++{
++ /* 16 bits 2 bytes back from the first RR header start. */
++ return c->first_rr[-2] * 256 + c->first_rr[-1];
++}
++
++/* Initializes *C to cover the packet [BUF, BUF+LEN). Returns false
++ if LEN is less than sizeof (*HD), if the packet does not contain a
++ full (uncompressed) question, or if the question count is not 1. */
++_Bool __ns_rr_cursor_init (struct ns_rr_cursor *c,
++ const unsigned char *buf, size_t len)
++ attribute_hidden;
++
++/* Like ns_rr, but the record owner name is not decoded into text format. */
++struct ns_rr_wire
++{
++ unsigned char rname[NS_MAXCDNAME]; /* Owner name of the record. */
++ uint16_t rtype; /* Resource record type (T_*). */
++ uint16_t rclass; /* Resource record class (C_*). */
++ uint32_t ttl; /* Time-to-live field. */
++ const unsigned char *rdata; /* Start of resource record data. */
++ uint16_t rdlength; /* Length of the data at rdata, in bytes. */
++};
++
++/* Attempts to parse the record at C into *RR. On success, return
++ true, and C is advanced past the record, and RR->rdata points to
++ the record data. On failure, errno is set to EMSGSIZE, and false
++ is returned. */
++_Bool __ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr)
++ attribute_hidden;
++
+ # endif /* !_ISOMAC */
+ #endif
+diff --git a/include/bits/wchar2-decl.h b/include/bits/wchar2-decl.h
+new file mode 100644
+index 0000000000..00b1b93342
+--- /dev/null
++++ b/include/bits/wchar2-decl.h
+@@ -0,0 +1 @@
++#include <wcsmbs/bits/wchar2-decl.h>
+diff --git a/include/resolv.h b/include/resolv.h
+index 3590b6f496..4dbbac3800 100644
+--- a/include/resolv.h
++++ b/include/resolv.h
+@@ -70,5 +70,8 @@ libc_hidden_proto (__libc_res_nameinquery)
+ extern __typeof (__res_queriesmatch) __libc_res_queriesmatch;
+ libc_hidden_proto (__libc_res_queriesmatch)
+
++/* Variant of res_hnok which operates on binary (but uncompressed) names. */
++bool __res_binary_hnok (const unsigned char *dn) attribute_hidden;
++
+ # endif /* _RESOLV_H_ && !_ISOMAC */
+ #endif
+diff --git a/misc/syslog.c b/misc/syslog.c
+index 554089bfc4..f67d4b58a4 100644
+--- a/misc/syslog.c
++++ b/misc/syslog.c
+@@ -167,7 +167,7 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
+ _nl_C_locobj_ptr);
+
+ #define SYSLOG_HEADER(__pri, __timestamp, __msgoff, pid) \
+- "<%d>%s %n%s%s%.0d%s: ", \
++ "<%d>%s%n%s%s%.0d%s: ", \
+ __pri, __timestamp, __msgoff, \
+ LogTag == NULL ? __progname : LogTag, \
+ "[" + (pid == 0), pid, "]" + (pid == 0)
+@@ -193,28 +193,32 @@ __vsyslog_internal (int pri, const char *fmt, va_list 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;
+- }
++ buf = bufs;
++ bufsize = l + vl;
+
+ va_end (apc);
+ }
+
+ if (buf == NULL)
+ {
+- buf = malloc (l * sizeof (char));
++ buf = malloc ((bufsize + 1) * sizeof (char));
+ if (buf != NULL)
+ {
+ /* Tell the cancellation handler to free this buffer. */
+ clarg.buf = buf;
+
+ if (has_ts)
+- __snprintf (bufs, sizeof bufs,
++ __snprintf (buf, l + 1,
+ SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
+ else
+- __snprintf (bufs, sizeof bufs,
++ __snprintf (buf, l + 1,
+ SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
++
++ va_list apc;
++ va_copy (apc, ap);
++ __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc,
++ mode_flags);
++ va_end (apc);
+ }
+ else
+ {
+diff --git a/misc/tst-syslog.c b/misc/tst-syslog.c
+index e550d15796..3560b518a2 100644
+--- a/misc/tst-syslog.c
++++ b/misc/tst-syslog.c
+@@ -68,21 +68,19 @@ static const int priorities[] =
+ LOG_DEBUG
+ };
+
+-enum
+- {
+- ident_length = 64,
+- msg_length = 64
+- };
++#define IDENT_LENGTH 64
++#define MSG_LENGTH 1024
+
+ #define SYSLOG_MSG_BASE "syslog_message"
+ #define OPENLOG_IDENT "openlog_ident"
++static char large_message[MSG_LENGTH];
+
+ struct msg_t
+ {
+ int priority;
+ int facility;
+- char ident[ident_length];
+- char msg[msg_length];
++ char ident[IDENT_LENGTH];
++ char msg[MSG_LENGTH];
+ pid_t pid;
+ };
+
+@@ -147,6 +145,37 @@ check_syslog_message (const struct msg_t *msg, int msgnum, int options,
+ return true;
+ }
+
++static void
++send_syslog_large (int options)
++{
++ int facility = LOG_USER;
++ int priority = LOG_INFO;
++
++ syslog (facility | priority, "%s %d %d", large_message, facility,
++ priority);
++}
++
++static void
++send_vsyslog_large (int options)
++{
++ int facility = LOG_USER;
++ int priority = LOG_INFO;
++
++ call_vsyslog (facility | priority, "%s %d %d", large_message, facility,
++ priority);
++}
++
++static bool
++check_syslog_message_large (const struct msg_t *msg, int msgnum, int options,
++ pid_t pid)
++{
++ TEST_COMPARE (msg->facility, LOG_USER);
++ TEST_COMPARE (msg->priority, LOG_INFO);
++ TEST_COMPARE_STRING (msg->msg, large_message);
++
++ return false;
++}
++
+ static void
+ send_openlog (int options)
+ {
+@@ -179,6 +208,17 @@ send_openlog (int options)
+ closelog ();
+ }
+
++static void
++send_openlog_large (int options)
++{
++ /* Define a non-default IDENT and a not default facility. */
++ openlog (OPENLOG_IDENT, options, LOG_LOCAL0);
++
++ syslog (LOG_INFO, "%s %d %d", large_message, LOG_LOCAL0, LOG_INFO);
++
++ closelog ();
++}
++
+ static bool
+ check_openlog_message (const struct msg_t *msg, int msgnum,
+ int options, pid_t pid)
+@@ -189,7 +229,7 @@ check_openlog_message (const struct msg_t *msg, int msgnum,
+ int expected_priority = priorities[msgnum % array_length (priorities)];
+ TEST_COMPARE (msg->priority, expected_priority);
+
+- char expected_ident[ident_length];
++ char expected_ident[IDENT_LENGTH];
+ snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:",
+ OPENLOG_IDENT,
+ options & LOG_PID ? "[" : "",
+@@ -211,17 +251,43 @@ check_openlog_message (const struct msg_t *msg, int msgnum,
+ return true;
+ }
+
++static bool
++check_openlog_message_large (const struct msg_t *msg, int msgnum,
++ int options, pid_t pid)
++{
++ char expected_ident[IDENT_LENGTH];
++ snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:",
++ OPENLOG_IDENT,
++ options & LOG_PID ? "[" : "",
++ options & LOG_PID ? pid : 0,
++ options & LOG_PID ? "]" : "");
++
++ TEST_COMPARE_STRING (msg->ident, expected_ident);
++ TEST_COMPARE_STRING (msg->msg, large_message);
++ TEST_COMPARE (msg->priority, LOG_INFO);
++ TEST_COMPARE (msg->facility, LOG_LOCAL0);
++
++ return false;
++}
++
+ static struct msg_t
+ parse_syslog_msg (const char *msg)
+ {
+ struct msg_t r = { .pid = -1 };
+ int number;
++ int wsb, wsa;
++
++#define STRINPUT(size) XSTRINPUT(size)
++#define XSTRINPUT(size) "%" # size "s"
+
+ /* The message in the form:
+- <179>Apr 8 14:51:19 tst-syslog: syslog message 176 3 */
+- int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d %32s %64s %*d %*d",
+- &number, r.ident, r.msg);
++ <179>Apr 8 14:51:19 tst-syslog: message 176 3 */
++ int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d%n %n" STRINPUT(IDENT_LENGTH)
++ " " STRINPUT(MSG_LENGTH) " %*d %*d",
++ &number, &wsb, &wsa, r.ident, r.msg);
+ TEST_COMPARE (n, 3);
++ /* It should only one space between timestamp and message. */
++ TEST_COMPARE (wsa - wsb, 1);
+
+ r.facility = number & LOG_FACMASK;
+ r.priority = number & LOG_PRIMASK;
+@@ -246,7 +312,7 @@ parse_syslog_console (const char *msg)
+
+ /* The message in the form:
+ openlog_ident: syslog_message 128 0 */
+- int n = sscanf (msg, "%32s %64s %d %d",
++ int n = sscanf (msg, STRINPUT(IDENT_LENGTH) " " STRINPUT(MSG_LENGTH) " %d %d",
+ r.ident, r.msg, &facility, &priority);
+ TEST_COMPARE (n, 4);
+
+@@ -281,7 +347,7 @@ check_syslog_udp (void (*syslog_send)(int), int options,
+ int msgnum = 0;
+ while (1)
+ {
+- char buf[512];
++ char buf[2048];
+ size_t l = xrecvfrom (server_udp, buf, sizeof (buf), 0,
+ (struct sockaddr *) &addr, &addrlen);
+ buf[l] = '\0';
+@@ -325,7 +391,7 @@ check_syslog_tcp (void (*syslog_send)(int), int options,
+
+ int client_tcp = xaccept (server_tcp, NULL, NULL);
+
+- char buf[512], *rb = buf;
++ char buf[2048], *rb = buf;
+ size_t rbl = sizeof (buf);
+ size_t prl = 0; /* Track the size of the partial record. */
+ int msgnum = 0;
+@@ -393,20 +459,34 @@ check_syslog_console_read (FILE *fp)
+ }
+
+ static void
+-check_syslog_console (void)
++check_syslog_console_read_large (FILE *fp)
++{
++ char buf[2048];
++ TEST_VERIFY (fgets (buf, sizeof (buf), fp) != NULL);
++ struct msg_t msg = parse_syslog_console (buf);
++
++ TEST_COMPARE_STRING (msg.ident, OPENLOG_IDENT ":");
++ TEST_COMPARE_STRING (msg.msg, large_message);
++ TEST_COMPARE (msg.priority, LOG_INFO);
++ TEST_COMPARE (msg.facility, LOG_LOCAL0);
++}
++
++static void
++check_syslog_console (void (*syslog_send)(int),
++ void (*syslog_check)(FILE *fp))
+ {
+ xmkfifo (_PATH_CONSOLE, 0666);
+
+ pid_t sender_pid = xfork ();
+ if (sender_pid == 0)
+ {
+- send_openlog (LOG_CONS);
++ syslog_send (LOG_CONS);
+ _exit (0);
+ }
+
+ {
+ FILE *fp = xfopen (_PATH_CONSOLE, "r+");
+- check_syslog_console_read (fp);
++ syslog_check (fp);
+ xfclose (fp);
+ }
+
+@@ -425,16 +505,28 @@ send_openlog_callback (void *clousure)
+ }
+
+ static void
+-check_syslog_perror (void)
++send_openlog_callback_large (void *clousure)
++{
++ int options = *(int *) clousure;
++ send_openlog_large (options);
++}
++
++static void
++check_syslog_perror (bool large)
+ {
+ struct support_capture_subprocess result;
+- result = support_capture_subprocess (send_openlog_callback,
++ result = support_capture_subprocess (large
++ ? send_openlog_callback_large
++ : send_openlog_callback,
+ &(int){LOG_PERROR});
+
+ FILE *mfp = fmemopen (result.err.buffer, result.err.length, "r");
+ if (mfp == NULL)
+ FAIL_EXIT1 ("fmemopen: %m");
+- check_syslog_console_read (mfp);
++ if (large)
++ check_syslog_console_read_large (mfp);
++ else
++ check_syslog_console_read (mfp);
+ xfclose (mfp);
+
+ support_capture_subprocess_check (&result, "tst-openlog-child", 0,
+@@ -462,10 +554,31 @@ do_test (void)
+ check_syslog_tcp (send_openlog, LOG_PID, check_openlog_message);
+
+ /* Check the LOG_CONS option. */
+- check_syslog_console ();
++ check_syslog_console (send_openlog, check_syslog_console_read);
+
+ /* Check the LOG_PERROR option. */
+- check_syslog_perror ();
++ check_syslog_perror (false);
++
++ /* Similar tests as before, but with a large message to trigger the
++ syslog path that uses dynamically allocated memory. */
++ memset (large_message, 'a', sizeof large_message - 1);
++ large_message[sizeof large_message - 1] = '\0';
++
++ check_syslog_udp (send_syslog_large, 0, check_syslog_message_large);
++ check_syslog_tcp (send_syslog_large, 0, check_syslog_message_large);
++
++ check_syslog_udp (send_vsyslog_large, 0, check_syslog_message_large);
++ check_syslog_tcp (send_vsyslog_large, 0, check_syslog_message_large);
++
++ check_syslog_udp (send_openlog_large, 0, check_openlog_message_large);
++ check_syslog_tcp (send_openlog_large, 0, check_openlog_message_large);
++
++ check_syslog_udp (send_openlog_large, LOG_PID, check_openlog_message_large);
++ check_syslog_tcp (send_openlog_large, LOG_PID, check_openlog_message_large);
++
++ check_syslog_console (send_openlog_large, check_syslog_console_read_large);
++
++ check_syslog_perror (true);
+
+ return 0;
+ }
+diff --git a/nscd/connections.c b/nscd/connections.c
+index 61d1674eb4..531d2e83df 100644
+--- a/nscd/connections.c
++++ b/nscd/connections.c
+@@ -2284,7 +2284,8 @@ main_loop_epoll (int efd)
+ sizeof (buf))) != -1)
+ ;
+
+- __bump_nl_timestamp ();
++ dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP]
++ = __bump_nl_timestamp ();
+ }
+ # endif
+ else
+diff --git a/resolv/Makefile b/resolv/Makefile
+index 5b15321f9b..f8a92c6cff 100644
+--- a/resolv/Makefile
++++ b/resolv/Makefile
+@@ -40,12 +40,16 @@ routines := \
+ inet_pton \
+ ns_makecanon \
+ ns_name_compress \
++ ns_name_length_uncompressed \
+ ns_name_ntop \
+ ns_name_pack \
+ ns_name_pton \
+ ns_name_skip \
+ ns_name_uncompress \
+ ns_name_unpack \
++ ns_rr_cursor_init \
++ ns_rr_cursor_next \
++ ns_samebinaryname \
+ ns_samename \
+ nsap_addr \
+ nss_dns_functions \
+@@ -89,9 +93,12 @@ tests += \
+ tst-ns_name_pton \
+ tst-res_hconf_reorder \
+ tst-res_hnok \
++ tst-resolv-aliases \
+ tst-resolv-basic \
+ tst-resolv-binary \
++ tst-resolv-byaddr \
+ tst-resolv-edns \
++ tst-resolv-invalid-cname \
+ tst-resolv-network \
+ tst-resolv-noaaaa \
+ tst-resolv-nondecimal \
+@@ -104,6 +111,18 @@ tests += \
+ tests-internal += tst-resolv-txnid-collision
+ tests-static += tst-resolv-txnid-collision
+
++# Likewise for __ns_samebinaryname.
++tests-internal += tst-ns_samebinaryname
++tests-static += tst-ns_samebinaryname
++
++# Likewise for __ns_name_length_uncompressed.
++tests-internal += tst-ns_name_length_uncompressed
++tests-static += tst-ns_name_length_uncompressed
++
++# Likewise for struct ns_rr_cursor and its functions.
++tests-internal += tst-ns_rr_cursor
++tests-static += tst-ns_rr_cursor
++
+ # These tests need libdl.
+ ifeq (yes,$(build-shared))
+ tests += \
+@@ -258,8 +277,10 @@ $(objpfx)tst-resolv-ai_idn.out: $(gen-locales)
+ $(objpfx)tst-resolv-ai_idn-latin1.out: $(gen-locales)
+ $(objpfx)tst-resolv-ai_idn-nolibidn2.out: \
+ $(gen-locales) $(objpfx)tst-no-libidn2.so
++$(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library)
++$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so
+@@ -267,6 +288,8 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \
+ $(shared-thread-library)
+ $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \
+ $(shared-thread-library)
++$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \
++ $(shared-thread-library)
+ $(objpfx)tst-resolv-noaaaa: $(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)
+diff --git a/resolv/README b/resolv/README
+index 514e9bb617..2146bc3b27 100644
+--- a/resolv/README
++++ b/resolv/README
+@@ -146,6 +146,3 @@ res_libc.c is home-brewn, although parts of it are taken from res_data.c.
+
+ res_hconf.c and res_hconf.h were contributed by David Mosberger, and
+ do not come from BIND.
+-
+-The files gethnamaddr.c, mapv4v6addr.h and mapv4v6hostent.h are
+-leftovers from BIND 4.9.7.
+diff --git a/resolv/mapv4v6addr.h b/resolv/mapv4v6addr.h
+deleted file mode 100644
+index 7f85f7d5e3..0000000000
+--- a/resolv/mapv4v6addr.h
++++ /dev/null
+@@ -1,69 +0,0 @@
+-/*
+- * ++Copyright++ 1985, 1988, 1993
+- * -
+- * Copyright (c) 1985, 1988, 1993
+- * The Regents of the University of California. All rights reserved.
+- *
+- * Redistribution and use in source and binary forms, with or without
+- * modification, are permitted provided that the following conditions
+- * are met:
+- * 1. Redistributions of source code must retain the above copyright
+- * notice, this list of conditions and the following disclaimer.
+- * 2. Redistributions in binary form must reproduce the above copyright
+- * notice, this list of conditions and the following disclaimer in the
+- * documentation and/or other materials provided with the distribution.
+- * 4. Neither the name of the University nor the names of its contributors
+- * may be used to endorse or promote products derived from this software
+- * without specific prior written permission.
+- *
+- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+- * SUCH DAMAGE.
+- * -
+- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+- *
+- * Permission to use, copy, modify, and distribute this software for any
+- * purpose with or without fee is hereby granted, provided that the above
+- * copyright notice and this permission notice appear in all copies, and that
+- * the name of Digital Equipment Corporation not be used in advertising or
+- * publicity pertaining to distribution of the document or software without
+- * specific, written prior permission.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+- * SOFTWARE.
+- * -
+- * --Copyright--
+- */
+-
+-#include <string.h>
+-#include <arpa/nameser.h>
+-
+-static void
+-map_v4v6_address (const char *src, char *dst)
+-{
+- u_char *p = (u_char *) dst;
+- int i;
+-
+- /* Move the IPv4 part to the right position. */
+- memcpy (dst + 12, src, INADDRSZ);
+-
+- /* Mark this ipv6 addr as a mapped ipv4. */
+- for (i = 0; i < 10; i++)
+- *p++ = 0x00;
+- *p++ = 0xff;
+- *p = 0xff;
+-}
+diff --git a/resolv/mapv4v6hostent.h b/resolv/mapv4v6hostent.h
+deleted file mode 100644
+index c11038adf3..0000000000
+--- a/resolv/mapv4v6hostent.h
++++ /dev/null
+@@ -1,84 +0,0 @@
+-/*
+- * ++Copyright++ 1985, 1988, 1993
+- * -
+- * Copyright (c) 1985, 1988, 1993
+- * The Regents of the University of California. All rights reserved.
+- *
+- * Redistribution and use in source and binary forms, with or without
+- * modification, are permitted provided that the following conditions
+- * are met:
+- * 1. Redistributions of source code must retain the above copyright
+- * notice, this list of conditions and the following disclaimer.
+- * 2. Redistributions in binary form must reproduce the above copyright
+- * notice, this list of conditions and the following disclaimer in the
+- * documentation and/or other materials provided with the distribution.
+- * 4. Neither the name of the University nor the names of its contributors
+- * may be used to endorse or promote products derived from this software
+- * without specific prior written permission.
+- *
+- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+- * SUCH DAMAGE.
+- * -
+- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+- *
+- * Permission to use, copy, modify, and distribute this software for any
+- * purpose with or without fee is hereby granted, provided that the above
+- * copyright notice and this permission notice appear in all copies, and that
+- * the name of Digital Equipment Corporation not be used in advertising or
+- * publicity pertaining to distribution of the document or software without
+- * specific, written prior permission.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+- * SOFTWARE.
+- * -
+- * --Copyright--
+- */
+-
+-#include <arpa/nameser.h>
+-#include <sys/socket.h>
+-
+-typedef union {
+- int32_t al;
+- char ac;
+-} align;
+-
+-static int
+-map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp)
+-{
+- char **ap;
+-
+- if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
+- return 0;
+- hp->h_addrtype = AF_INET6;
+- hp->h_length = IN6ADDRSZ;
+- for (ap = hp->h_addr_list; *ap; ap++)
+- {
+- int i = sizeof (align) - ((u_long) *bpp % sizeof (align));
+-
+- if (*lenp < (i + IN6ADDRSZ))
+- /* Out of memory. */
+- return 1;
+- *bpp += i;
+- *lenp -= i;
+- map_v4v6_address (*ap, *bpp);
+- *ap = *bpp;
+- *bpp += IN6ADDRSZ;
+- *lenp -= IN6ADDRSZ;
+- }
+- return 0;
+-}
+diff --git a/resolv/ns_name_length_uncompressed.c b/resolv/ns_name_length_uncompressed.c
+new file mode 100644
+index 0000000000..51296b47ef
+--- /dev/null
++++ b/resolv/ns_name_length_uncompressed.c
+@@ -0,0 +1,72 @@
++/* Skip over an uncompressed name in wire format.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <errno.h>
++#include <stdbool.h>
++
++int
++__ns_name_length_uncompressed (const unsigned char *p,
++ const unsigned char *eom)
++{
++ const unsigned char *start = p;
++
++ while (true)
++ {
++ if (p == eom)
++ {
++ /* Truncated packet: no room for label length. */
++ __set_errno (EMSGSIZE);
++ return -1;
++ }
++
++ unsigned char b = *p;
++ ++p;
++ if (b == 0)
++ {
++ /* Root label. */
++ size_t length = p - start;
++ if (length > NS_MAXCDNAME)
++ {
++ /* Domain name too long. */
++ __set_errno (EMSGSIZE);
++ return -1;
++ }
++ return length;
++ }
++
++ if (b <= 63)
++ {
++ /* Regular label. */
++ if (b <= eom - p)
++ p += b;
++ else
++ {
++ /* Truncated packet: label incomplete. */
++ __set_errno (EMSGSIZE);
++ return -1;
++ }
++ }
++ else
++ {
++ /* Compression reference or corrupted label length. */
++ __set_errno (EMSGSIZE);
++ return -1;
++ }
++ }
++}
+diff --git a/resolv/ns_rr_cursor_init.c b/resolv/ns_rr_cursor_init.c
+new file mode 100644
+index 0000000000..6ee80b30e9
+--- /dev/null
++++ b/resolv/ns_rr_cursor_init.c
+@@ -0,0 +1,62 @@
++/* Initialize a simple DNS packet parser.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <errno.h>
++#include <stdbool.h>
++#include <string.h>
++
++bool
++__ns_rr_cursor_init (struct ns_rr_cursor *c,
++ const unsigned char *buf, size_t len)
++{
++ c->begin = buf;
++ c->end = buf + len;
++
++ /* Check for header size and 16-bit question count value (it must be 1). */
++ if (len < 12 || buf[4] != 0 || buf[5] != 1)
++ {
++ __set_errno (EMSGSIZE);
++ c->current = c->end;
++ return false;
++ }
++ c->current = buf + 12;
++
++ int consumed = __ns_name_length_uncompressed (c->current, c->end);
++ if (consumed < 0)
++ {
++ __set_errno (EMSGSIZE);
++ c->current = c->end;
++ c->first_rr = NULL;
++ return false;
++ }
++ c->current += consumed;
++
++ /* Ensure there is room for question type and class. */
++ if (c->end - c->current < 4)
++ {
++ __set_errno (EMSGSIZE);
++ c->current = c->end;
++ c->first_rr = NULL;
++ return false;
++ }
++ c->current += 4;
++ c->first_rr = c->current;
++
++ return true;
++}
+diff --git a/resolv/ns_rr_cursor_next.c b/resolv/ns_rr_cursor_next.c
+new file mode 100644
+index 0000000000..33652fc5da
+--- /dev/null
++++ b/resolv/ns_rr_cursor_next.c
+@@ -0,0 +1,74 @@
++/* Simple DNS record parser without textual name decoding.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <errno.h>
++#include <stdbool.h>
++#include <string.h>
++
++bool
++__ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr)
++{
++ rr->rdata = NULL;
++
++ /* Extract the record owner name. */
++ int consumed = __ns_name_unpack (c->begin, c->end, c->current,
++ rr->rname, sizeof (rr->rname));
++ if (consumed < 0)
++ {
++ memset (rr, 0, sizeof (*rr));
++ __set_errno (EMSGSIZE);
++ return false;
++ }
++ c->current += consumed;
++
++ /* Extract the metadata. */
++ struct
++ {
++ uint16_t rtype;
++ uint16_t rclass;
++ uint32_t ttl;
++ uint16_t rdlength;
++ } __attribute__ ((packed)) metadata;
++ _Static_assert (sizeof (metadata) == 10, "sizeof metadata");
++ if (c->end - c->current < sizeof (metadata))
++ {
++ memset (rr, 0, sizeof (*rr));
++ __set_errno (EMSGSIZE);
++ return false;
++ }
++ memcpy (&metadata, c->current, sizeof (metadata));
++ c->current += sizeof (metadata);
++ /* Endianess conversion. */
++ rr->rtype = ntohs (metadata.rtype);
++ rr->rclass = ntohs (metadata.rclass);
++ rr->ttl = ntohl (metadata.ttl);
++ rr->rdlength = ntohs (metadata.rdlength);
++
++ /* Extract record data. */
++ if (c->end - c->current < rr->rdlength)
++ {
++ memset (rr, 0, sizeof (*rr));
++ __set_errno (EMSGSIZE);
++ return false;
++ }
++ rr->rdata = c->current;
++ c->current += rr->rdlength;
++
++ return true;
++}
+diff --git a/resolv/ns_samebinaryname.c b/resolv/ns_samebinaryname.c
+new file mode 100644
+index 0000000000..9a47d8e97a
+--- /dev/null
++++ b/resolv/ns_samebinaryname.c
+@@ -0,0 +1,55 @@
++/* Compare two binary domain names for quality.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <stdbool.h>
++
++/* Convert ASCII letters to upper case. */
++static inline int
++ascii_toupper (unsigned char ch)
++{
++ if (ch >= 'a' && ch <= 'z')
++ return ch - 'a' + 'A';
++ else
++ return ch;
++}
++
++bool
++__ns_samebinaryname (const unsigned char *a, const unsigned char *b)
++{
++ while (*a != 0 && *b != 0)
++ {
++ if (*a != *b)
++ /* Different label length. */
++ return false;
++ int labellen = *a;
++ ++a;
++ ++b;
++ for (int i = 0; i < labellen; ++i)
++ {
++ if (*a != *b && ascii_toupper (*a) != ascii_toupper (*b))
++ /* Different character in label. */
++ return false;
++ ++a;
++ ++b;
++ }
++ }
++
++ /* Match if both names are at the root label. */
++ return *a == 0 && *b == 0;
++}
+diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
+index 544cffbecd..9fa81f23c8 100644
+--- a/resolv/nss_dns/dns-host.c
++++ b/resolv/nss_dns/dns-host.c
+@@ -69,6 +69,7 @@
+ * --Copyright--
+ */
+
++#include <alloc_buffer.h>
+ #include <assert.h>
+ #include <ctype.h>
+ #include <errno.h>
+@@ -86,10 +87,6 @@
+ #include <resolv/resolv-internal.h>
+ #include <resolv/resolv_context.h>
+
+-/* Get implementations of some internal functions. */
+-#include <resolv/mapv4v6addr.h>
+-#include <resolv/mapv4v6hostent.h>
+-
+ #define RESOLVSORT
+
+ #if PACKETSZ > 65536
+@@ -103,32 +100,36 @@
+ #endif
+ #define MAXHOSTNAMELEN 256
+
+-/* We need this time later. */
+-typedef union querybuf
+-{
+- HEADER hdr;
+- u_char buf[MAXPACKET];
+-} querybuf;
+-
+-static enum nss_status getanswer_r (struct resolv_context *ctx,
+- const querybuf *answer, int anslen,
+- const char *qname, int qtype,
+- struct hostent *result, char *buffer,
+- size_t buflen, int *errnop, int *h_errnop,
+- int map, int32_t *ttlp, char **canonp);
+-
+-static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
+- const querybuf *answer2, int anslen2,
+- const char *qname,
++/* For historic reasons, pointers to IP addresses are char *, so use a
++ single list type for addresses and host names. */
++#define DYNARRAY_STRUCT ptrlist
++#define DYNARRAY_ELEMENT char *
++#define DYNARRAY_PREFIX ptrlist_
++#include <malloc/dynarray-skeleton.c>
++
++static enum nss_status getanswer_r (unsigned char *packet, size_t packetlen,
++ uint16_t qtype, struct alloc_buffer *abuf,
++ struct ptrlist *addresses,
++ struct ptrlist *aliases,
++ int *errnop, int *h_errnop, int32_t *ttlp);
++static void addrsort (struct resolv_context *ctx, char **ap, int num);
++static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen,
++ struct alloc_buffer *abuf,
++ char **hnamep, int *errnop,
++ int *h_errnop, int32_t *ttlp);
++
++static enum nss_status gaih_getanswer (unsigned char *packet1,
++ size_t packet1len,
++ unsigned char *packet2,
++ size_t packet2len,
++ struct alloc_buffer *abuf,
+ struct gaih_addrtuple **pat,
+- char *buffer, size_t buflen,
+ int *errnop, int *h_errnop,
+ int32_t *ttlp);
+-static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1,
+- int anslen1,
+- const char *qname,
++static enum nss_status gaih_getanswer_noaaaa (unsigned char *packet,
++ size_t packetlen,
++ struct alloc_buffer *abuf,
+ struct gaih_addrtuple **pat,
+- char *buffer, size_t buflen,
+ int *errnop, int *h_errnop,
+ int32_t *ttlp);
+
+@@ -183,16 +184,9 @@ gethostbyname3_context (struct resolv_context *ctx,
+ char *buffer, size_t buflen, int *errnop,
+ int *h_errnop, int32_t *ttlp, char **canonp)
+ {
+- union
+- {
+- querybuf *buf;
+- u_char *ptr;
+- } host_buffer;
+- querybuf *orig_host_buffer;
+ char tmp[NS_MAXDNAME];
+ int size, type, n;
+ const char *cp;
+- int map = 0;
+ int olderr = errno;
+ enum nss_status status;
+
+@@ -223,10 +217,12 @@ gethostbyname3_context (struct resolv_context *ctx,
+ && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL)
+ name = cp;
+
+- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
++ unsigned char dns_packet_buffer[1024];
++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
+
+- n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf,
+- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
++ n = __res_context_search (ctx, name, C_IN, type,
++ dns_packet_buffer, sizeof (dns_packet_buffer),
++ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL);
+ if (n < 0)
+ {
+ switch (errno)
+@@ -253,34 +249,79 @@ gethostbyname3_context (struct resolv_context *ctx,
+ *errnop = EAGAIN;
+ else
+ __set_errno (olderr);
++ }
++ else
++ {
++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
+
+- /* If we are looking for an IPv6 address and mapping is enabled
+- by having the RES_USE_INET6 bit in _res.options set, we try
+- another lookup. */
+- if (af == AF_INET6 && res_use_inet6 ())
+- n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf,
+- host_buffer.buf != orig_host_buffer
+- ? MAXPACKET : 1024, &host_buffer.ptr,
+- NULL, NULL, NULL, NULL);
++ struct ptrlist addresses;
++ ptrlist_init (&addresses);
++ struct ptrlist aliases;
++ ptrlist_init (&aliases);
+
+- if (n < 0)
++ status = getanswer_r (alt_dns_packet_buffer, n, type,
++ &abuf, &addresses, &aliases,
++ errnop, h_errnop, ttlp);
++ if (status == NSS_STATUS_SUCCESS)
+ {
+- if (host_buffer.buf != orig_host_buffer)
+- free (host_buffer.buf);
+- return status;
+- }
++ if (ptrlist_has_failed (&addresses)
++ || ptrlist_has_failed (&aliases))
++ {
++ /* malloc failure. Do not retry using the ERANGE protocol. */
++ *errnop = ENOMEM;
++ *h_errnop = NETDB_INTERNAL;
++ status = NSS_STATUS_UNAVAIL;
++ }
+
+- map = 1;
++ /* Reserve the address and alias arrays in the result
++ buffer. Both are NULL-terminated, but the first element
++ of the alias array is stored in h_name, so no extra space
++ for the NULL terminator is needed there. */
++ result->h_addr_list
++ = alloc_buffer_alloc_array (&abuf, char *,
++ ptrlist_size (&addresses) + 1);
++ result->h_aliases
++ = alloc_buffer_alloc_array (&abuf, char *,
++ ptrlist_size (&aliases));
++ if (alloc_buffer_has_failed (&abuf))
++ {
++ /* Retry using the ERANGE protocol. */
++ *errnop = ERANGE;
++ *h_errnop = NETDB_INTERNAL;
++ status = NSS_STATUS_TRYAGAIN;
++ }
++ else
++ {
++ /* Copy the address list and NULL-terminate it. */
++ memcpy (result->h_addr_list, ptrlist_begin (&addresses),
++ ptrlist_size (&addresses) * sizeof (char *));
++ result->h_addr_list[ptrlist_size (&addresses)] = NULL;
++
++ /* Sort the address list if requested. */
++ if (type == T_A && __resolv_context_sort_count (ctx) > 0)
++ addrsort (ctx, result->h_addr_list, ptrlist_size (&addresses));
+
+- result->h_addrtype = AF_INET;
+- result->h_length = INADDRSZ;
++ /* Copy the aliases, excluding the last one. */
++ memcpy (result->h_aliases, ptrlist_begin (&aliases),
++ (ptrlist_size (&aliases) - 1) * sizeof (char *));
++ result->h_aliases[ptrlist_size (&aliases) - 1] = NULL;
++
++ /* The last alias goes into h_name. */
++ assert (ptrlist_size (&aliases) >= 1);
++ result->h_name = ptrlist_end (&aliases)[-1];
++
++ /* This is also the canonical name. */
++ if (canonp != NULL)
++ *canonp = result->h_name;
++ }
++ }
++
++ ptrlist_free (&aliases);
++ ptrlist_free (&addresses);
+ }
+
+- status = getanswer_r
+- (ctx, host_buffer.buf, n, name, type, result, buffer, buflen,
+- errnop, h_errnop, map, ttlp, canonp);
+- if (host_buffer.buf != orig_host_buffer)
+- free (host_buffer.buf);
++ if (alt_dns_packet_buffer != dns_packet_buffer)
++ free (alt_dns_packet_buffer);
+ return status;
+ }
+
+@@ -324,13 +365,8 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
+ *h_errnop = NETDB_INTERNAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+- status = NSS_STATUS_NOTFOUND;
+- if (res_use_inet6 ())
+- status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer,
+- buflen, errnop, h_errnop, NULL, NULL);
+- if (status == NSS_STATUS_NOTFOUND)
+- status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
+- buflen, errnop, h_errnop, NULL, NULL);
++ status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
++ buflen, errnop, h_errnop, NULL, NULL);
+ __resolv_context_put (ctx);
+ return status;
+ }
+@@ -365,17 +401,13 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
+ name = cp;
+ }
+
+- union
+- {
+- querybuf *buf;
+- u_char *ptr;
+- } host_buffer;
+- querybuf *orig_host_buffer;
+- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
++ unsigned char dns_packet_buffer[2048];
++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
+ u_char *ans2p = NULL;
+ int nans2p = 0;
+ int resplen2 = 0;
+ int ans2p_malloced = 0;
++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
+
+
+ int olderr = errno;
+@@ -384,22 +416,21 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
+ if ((ctx->resp->options & RES_NOAAAA) == 0)
+ {
+ n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
+- host_buffer.buf->buf, 2048, &host_buffer.ptr,
+- &ans2p, &nans2p, &resplen2, &ans2p_malloced);
++ dns_packet_buffer, sizeof (dns_packet_buffer),
++ &alt_dns_packet_buffer, &ans2p, &nans2p,
++ &resplen2, &ans2p_malloced);
+ if (n >= 0)
+- status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
+- resplen2, name, pat, buffer, buflen,
+- errnop, herrnop, ttlp);
++ status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2,
++ &abuf, pat, errnop, herrnop, ttlp);
+ }
+ else
+ {
+ n = __res_context_search (ctx, name, C_IN, T_A,
+- host_buffer.buf->buf, 2048, NULL,
+- NULL, NULL, NULL, NULL);
++ dns_packet_buffer, sizeof (dns_packet_buffer),
++ NULL, NULL, NULL, NULL, NULL);
+ if (n >= 0)
+- status = gaih_getanswer_noaaaa (host_buffer.buf, n,
+- name, pat, buffer, buflen,
+- errnop, herrnop, ttlp);
++ status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n,
++ &abuf, pat, errnop, herrnop, ttlp);
+ }
+ if (n < 0)
+ {
+@@ -430,12 +461,20 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
+ __set_errno (olderr);
+ }
+
++ /* Implement the buffer resizing protocol. */
++ if (alloc_buffer_has_failed (&abuf))
++ {
++ *errnop = ERANGE;
++ *herrnop = NETDB_INTERNAL;
++ status = NSS_STATUS_TRYAGAIN;
++ }
++
+ /* Check whether ans2p was separately allocated. */
+ if (ans2p_malloced)
+ free (ans2p);
+
+- if (host_buffer.buf != orig_host_buffer)
+- free (host_buffer.buf);
++ if (alt_dns_packet_buffer != dns_packet_buffer)
++ free (alt_dns_packet_buffer);
+
+ __resolv_context_put (ctx);
+ return status;
+@@ -451,36 +490,21 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
+ static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+ static const u_char v6local[] = { 0,0, 0,1 };
+ const u_char *uaddr = (const u_char *)addr;
+- struct host_data
+- {
+- char *aliases[MAX_NR_ALIASES];
+- unsigned char host_addr[16]; /* IPv4 or IPv6 */
+- char *h_addr_ptrs[MAX_NR_ADDRS + 1];
+- char linebuffer[0];
+- } *host_data = (struct host_data *) buffer;
+- union
+- {
+- querybuf *buf;
+- u_char *ptr;
+- } host_buffer;
+- querybuf *orig_host_buffer;
+ char qbuf[MAXDNAME+1], *qp = NULL;
+ size_t size;
+ int n, status;
+ int olderr = errno;
+
+- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
+- buffer += pad;
+- buflen = buflen > pad ? buflen - pad : 0;
+-
+- if (__glibc_unlikely (buflen < sizeof (struct host_data)))
+- {
+- *errnop = ERANGE;
+- *h_errnop = NETDB_INTERNAL;
+- return NSS_STATUS_TRYAGAIN;
+- }
+-
+- host_data = (struct host_data *) buffer;
++ /* Prepare the allocation buffer. Store the pointer array first, to
++ benefit from buffer alignment. */
++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
++ char **address_array = alloc_buffer_alloc_array (&abuf, char *, 2);
++ if (address_array == NULL)
++ {
++ *errnop = ERANGE;
++ *h_errnop = NETDB_INTERNAL;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+ struct resolv_context *ctx = __resolv_context_get ();
+ if (ctx == NULL)
+@@ -524,8 +548,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
+-
+ switch (af)
+ {
+ case AF_INET:
+@@ -549,36 +571,52 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
+ break;
+ }
+
+- n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
+- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
++ unsigned char dns_packet_buffer[1024];
++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
++ n = __res_context_query (ctx, qbuf, C_IN, T_PTR,
++ dns_packet_buffer, sizeof (dns_packet_buffer),
++ &alt_dns_packet_buffer,
++ NULL, NULL, NULL, NULL);
+ if (n < 0)
+ {
+ *h_errnop = h_errno;
+ __set_errno (olderr);
+- if (host_buffer.buf != orig_host_buffer)
+- free (host_buffer.buf);
++ if (alt_dns_packet_buffer != dns_packet_buffer)
++ free (alt_dns_packet_buffer);
+ __resolv_context_put (ctx);
+ return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
+ }
+
+- status = getanswer_r
+- (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
+- errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
+- if (host_buffer.buf != orig_host_buffer)
+- free (host_buffer.buf);
++ status = getanswer_ptr (alt_dns_packet_buffer, n,
++ &abuf, &result->h_name, errnop, h_errnop, ttlp);
++
++ if (alt_dns_packet_buffer != dns_packet_buffer)
++ free (alt_dns_packet_buffer);
++ __resolv_context_put (ctx);
++
+ if (status != NSS_STATUS_SUCCESS)
+- {
+- __resolv_context_put (ctx);
+- return status;
+- }
++ return status;
+
++ /* result->h_name has already been set by getanswer_ptr. */
+ result->h_addrtype = af;
+ result->h_length = len;
+- memcpy (host_data->host_addr, addr, len);
+- host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
+- host_data->h_addr_ptrs[1] = NULL;
++ /* Increase the alignment to 4, in case there are applications out
++ there that expect at least this level of address alignment. */
++ address_array[0] = (char *) alloc_buffer_next (&abuf, uint32_t);
++ alloc_buffer_copy_bytes (&abuf, uaddr, len);
++ address_array[1] = NULL;
++
++ /* This check also covers allocation failure in getanswer_ptr. */
++ if (alloc_buffer_has_failed (&abuf))
++ {
++ *errnop = ERANGE;
++ *h_errnop = NETDB_INTERNAL;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ result->h_addr_list = address_array;
++ result->h_aliases = &address_array[1]; /* Points to NULL. */
++
+ *h_errnop = NETDB_SUCCESS;
+- __resolv_context_put (ctx);
+ return NSS_STATUS_SUCCESS;
+ }
+ libc_hidden_def (_nss_dns_gethostbyaddr2_r)
+@@ -640,650 +678,362 @@ addrsort (struct resolv_context *ctx, char **ap, int num)
+ break;
+ }
+
+-static enum nss_status
+-getanswer_r (struct resolv_context *ctx,
+- const querybuf *answer, int anslen, const char *qname, int qtype,
+- struct hostent *result, char *buffer, size_t buflen,
+- int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
++/* Convert the uncompressed, binary domain name CDNAME into its
++ textual representation and add it to the end of ALIASES, allocating
++ space for a copy of the name from ABUF. Skip adding the name if it
++ is not a valid host name, and return false in that case, otherwise
++ true. */
++static bool
++getanswer_r_store_alias (const unsigned char *cdname,
++ struct alloc_buffer *abuf,
++ struct ptrlist *aliases)
+ {
+- struct host_data
+- {
+- char *aliases[MAX_NR_ALIASES];
+- unsigned char host_addr[16]; /* IPv4 or IPv6 */
+- char *h_addr_ptrs[0];
+- } *host_data;
+- int linebuflen;
+- const HEADER *hp;
+- const u_char *end_of_message, *cp;
+- int n, ancount, qdcount;
+- int haveanswer, had_error;
+- char *bp, **ap, **hap;
+- char tbuf[MAXDNAME];
+- const char *tname;
+- int (*name_ok) (const char *);
+- u_char packtmp[NS_MAXCDNAME];
+- int have_to_map = 0;
+- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
+- buffer += pad;
+- buflen = buflen > pad ? buflen - pad : 0;
+- if (__glibc_unlikely (buflen < sizeof (struct host_data)))
+- {
+- /* The buffer is too small. */
+- too_small:
+- *errnop = ERANGE;
+- *h_errnop = NETDB_INTERNAL;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- host_data = (struct host_data *) buffer;
+- linebuflen = buflen - sizeof (struct host_data);
+- if (buflen - sizeof (struct host_data) != linebuflen)
+- linebuflen = INT_MAX;
+-
+- tname = qname;
+- result->h_name = NULL;
+- end_of_message = answer->buf + anslen;
+- switch (qtype)
+- {
+- case T_A:
+- case T_AAAA:
+- name_ok = __libc_res_hnok;
+- break;
+- case T_PTR:
+- name_ok = __libc_res_dnok;
+- break;
+- default:
+- *errnop = ENOENT;
+- return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */
+- }
++ /* Filter out domain names that are not host names. */
++ if (!__res_binary_hnok (cdname))
++ return false;
++
++ /* Note: Not NS_MAXCDNAME, so that __ns_name_ntop implicitly checks
++ for length. */
++ char dname[MAXHOSTNAMELEN + 1];
++ if (__ns_name_ntop (cdname, dname, sizeof (dname)) < 0)
++ return false;
++ /* Do not report an error on allocation failure, instead store NULL
++ or do nothing. getanswer_r's caller will see NSS_STATUS_SUCCESS
++ and detect the memory allocation failure or buffer space
++ exhaustion, and report it accordingly. */
++ ptrlist_add (aliases, alloc_buffer_copy_string (abuf, dname));
++ return true;
++}
+
+- /*
+- * find first satisfactory answer
+- */
+- hp = &answer->hdr;
+- ancount = ntohs (hp->ancount);
+- qdcount = ntohs (hp->qdcount);
+- cp = answer->buf + HFIXEDSZ;
+- if (__glibc_unlikely (qdcount != 1))
++static enum nss_status __attribute__ ((noinline))
++getanswer_r (unsigned char *packet, size_t packetlen, uint16_t qtype,
++ struct alloc_buffer *abuf,
++ struct ptrlist *addresses, struct ptrlist *aliases,
++ int *errnop, int *h_errnop, int32_t *ttlp)
++{
++ struct ns_rr_cursor c;
++ if (!__ns_rr_cursor_init (&c, packet, packetlen))
+ {
++ /* This should not happen because __res_context_query already
++ perfroms response validation. */
+ *h_errnop = NO_RECOVERY;
+ return NSS_STATUS_UNAVAIL;
+ }
+- if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen)
+- goto too_small;
+- bp = (char *) &host_data->h_addr_ptrs[ancount + 1];
+- linebuflen -= (ancount + 1) * sizeof (char *);
+-
+- n = __ns_name_unpack (answer->buf, end_of_message, cp,
+- packtmp, sizeof packtmp);
+- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
+- {
+- if (__glibc_unlikely (errno == EMSGSIZE))
+- goto too_small;
+
+- n = -1;
+- }
+-
+- if (__glibc_unlikely (n < 0))
++ /* Treat the QNAME just like an alias. Error out if it is not a
++ valid host name. */
++ if (ns_rr_cursor_rcode (&c) == NXDOMAIN
++ || !getanswer_r_store_alias (ns_rr_cursor_qname (&c), abuf, aliases))
+ {
+- *errnop = errno;
+- *h_errnop = NO_RECOVERY;
+- return NSS_STATUS_UNAVAIL;
+- }
+- if (__glibc_unlikely (name_ok (bp) == 0))
+- {
+- errno = EBADMSG;
+- *errnop = EBADMSG;
+- *h_errnop = NO_RECOVERY;
+- return NSS_STATUS_UNAVAIL;
++ if (ttlp != NULL)
++ /* No negative caching. */
++ *ttlp = 0;
++ *h_errnop = HOST_NOT_FOUND;
++ *errnop = ENOENT;
++ return NSS_STATUS_NOTFOUND;
+ }
+- cp += n + QFIXEDSZ;
+
+- if (qtype == T_A || qtype == T_AAAA)
++ int ancount = ns_rr_cursor_ancount (&c);
++ const unsigned char *expected_name = ns_rr_cursor_qname (&c);
++ /* expected_name may be updated to point into this buffer. */
++ unsigned char name_buffer[NS_MAXCDNAME];
++
++ for (; ancount > 0; --ancount)
+ {
+- /* res_send() has already verified that the query name is the
+- * same as the one we sent; this just gets the expanded name
+- * (i.e., with the succeeding search-domain tacked on).
+- */
+- n = strlen (bp) + 1; /* for the \0 */
+- if (n >= MAXHOSTNAMELEN)
++ struct ns_rr_wire rr;
++ if (!__ns_rr_cursor_next (&c, &rr))
+ {
+ *h_errnop = NO_RECOVERY;
+- *errnop = ENOENT;
+- return NSS_STATUS_TRYAGAIN;
++ return NSS_STATUS_UNAVAIL;
+ }
+- result->h_name = bp;
+- bp += n;
+- linebuflen -= n;
+- if (linebuflen < 0)
+- goto too_small;
+- /* The qname can be abbreviated, but h_name is now absolute. */
+- qname = result->h_name;
+- }
+
+- ap = host_data->aliases;
+- *ap = NULL;
+- result->h_aliases = host_data->aliases;
+- hap = host_data->h_addr_ptrs;
+- *hap = NULL;
+- result->h_addr_list = host_data->h_addr_ptrs;
+- haveanswer = 0;
+- had_error = 0;
++ /* Skip over records with the wrong class. */
++ if (rr.rclass != C_IN)
++ continue;
+
+- while (ancount-- > 0 && cp < end_of_message && had_error == 0)
+- {
+- int type, class;
++ /* Update TTL for recognized record types. */
++ if ((rr.rtype == T_CNAME || rr.rtype == qtype)
++ && ttlp != NULL && *ttlp > rr.ttl)
++ *ttlp = rr.ttl;
+
+- n = __ns_name_unpack (answer->buf, end_of_message, cp,
+- packtmp, sizeof packtmp);
+- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
++ if (rr.rtype == T_CNAME)
+ {
+- if (__glibc_unlikely (errno == EMSGSIZE))
+- goto too_small;
+-
+- n = -1;
++ /* NB: No check for owner name match, based on historic
++ precedent. Record the CNAME target as the new expected
++ name. */
++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
++ name_buffer, sizeof (name_buffer));
++ if (n < 0)
++ {
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
++ }
++ /* And store the new name as an alias. */
++ getanswer_r_store_alias (name_buffer, abuf, aliases);
++ expected_name = name_buffer;
+ }
+-
+- if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0))
++ else if (rr.rtype == qtype
++ && __ns_samebinaryname (rr.rname, expected_name)
++ && rr.rdlength == rrtype_to_rdata_length (qtype))
+ {
+- ++had_error;
+- continue;
++ /* Make a copy of the address and store it. Increase the
++ alignment to 4, in case there are applications out there
++ that expect at least this level of address alignment. */
++ ptrlist_add (addresses, (char *) alloc_buffer_next (abuf, uint32_t));
++ alloc_buffer_copy_bytes (abuf, rr.rdata, rr.rdlength);
+ }
+- cp += n; /* name */
++ }
+
+- if (__glibc_unlikely (cp + 10 > end_of_message))
+- {
+- ++had_error;
+- continue;
+- }
++ if (ptrlist_size (addresses) == 0)
++ {
++ /* No address record found. */
++ if (ttlp != NULL)
++ /* No caching of negative responses. */
++ *ttlp = 0;
+
+- NS_GET16 (type, cp);
+- NS_GET16 (class, cp);
+- int32_t ttl;
+- NS_GET32 (ttl, cp);
+- NS_GET16 (n, cp); /* RDATA length. */
++ *h_errnop = NO_RECOVERY;
++ *errnop = ENOENT;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ else
++ {
++ *h_errnop = NETDB_SUCCESS;
++ return NSS_STATUS_SUCCESS;
++ }
++}
+
+- if (end_of_message - cp < n)
+- {
+- /* RDATA extends beyond the end of the packet. */
+- ++had_error;
+- continue;
+- }
++static enum nss_status
++getanswer_ptr (unsigned char *packet, size_t packetlen,
++ struct alloc_buffer *abuf, char **hnamep,
++ int *errnop, int *h_errnop, int32_t *ttlp)
++{
++ struct ns_rr_cursor c;
++ if (!__ns_rr_cursor_init (&c, packet, packetlen))
++ {
++ /* This should not happen because __res_context_query already
++ perfroms response validation. */
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
++ }
++ int ancount = ns_rr_cursor_ancount (&c);
++ const unsigned char *expected_name = ns_rr_cursor_qname (&c);
++ /* expected_name may be updated to point into this buffer. */
++ unsigned char name_buffer[NS_MAXCDNAME];
+
+- if (__glibc_unlikely (class != C_IN))
++ while (ancount > 0)
++ {
++ struct ns_rr_wire rr;
++ if (!__ns_rr_cursor_next (&c, &rr))
+ {
+- /* XXX - debug? syslog? */
+- cp += n;
+- continue; /* XXX - had_error++ ? */
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
+ }
+
+- if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
+- {
+- /* A CNAME could also have a TTL entry. */
+- if (ttlp != NULL && ttl < *ttlp)
+- *ttlp = ttl;
+-
+- if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
+- continue;
+- n = __libc_dn_expand (answer->buf, end_of_message, cp,
+- tbuf, sizeof tbuf);
+- if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0))
+- {
+- ++had_error;
+- continue;
+- }
+- cp += n;
+- /* Store alias. */
+- *ap++ = bp;
+- n = strlen (bp) + 1; /* For the \0. */
+- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
+- {
+- ++had_error;
+- continue;
+- }
+- bp += n;
+- linebuflen -= n;
+- /* Get canonical name. */
+- n = strlen (tbuf) + 1; /* For the \0. */
+- if (__glibc_unlikely (n > linebuflen))
+- goto too_small;
+- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
+- {
+- ++had_error;
+- continue;
+- }
+- result->h_name = bp;
+- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
+- linebuflen -= n;
+- continue;
+- }
++ /* Skip over records with the wrong class. */
++ if (rr.rclass != C_IN)
++ continue;
+
+- if (qtype == T_PTR && type == T_CNAME)
+- {
+- /* A CNAME could also have a TTL entry. */
+- if (ttlp != NULL && ttl < *ttlp)
+- *ttlp = ttl;
++ /* Update TTL for known record types. */
++ if ((rr.rtype == T_CNAME || rr.rtype == T_PTR)
++ && ttlp != NULL && *ttlp > rr.ttl)
++ *ttlp = rr.ttl;
+
+- n = __libc_dn_expand (answer->buf, end_of_message, cp,
+- tbuf, sizeof tbuf);
+- if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0))
+- {
+- ++had_error;
+- continue;
+- }
+- cp += n;
+- /* Get canonical name. */
+- n = strlen (tbuf) + 1; /* For the \0. */
+- if (__glibc_unlikely (n > linebuflen))
+- goto too_small;
+- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
++ if (rr.rtype == T_CNAME)
++ {
++ /* NB: No check for owner name match, based on historic
++ precedent. Record the CNAME target as the new expected
++ name. */
++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
++ name_buffer, sizeof (name_buffer));
++ if (n < 0)
+ {
+- ++had_error;
+- continue;
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
+ }
+- tname = bp;
+- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
+- linebuflen -= n;
+- continue;
++ expected_name = name_buffer;
+ }
+-
+- if (type == T_A && qtype == T_AAAA && map)
+- have_to_map = 1;
+- else if (__glibc_unlikely (type != qtype))
++ else if (rr.rtype == T_PTR
++ && __ns_samebinaryname (rr.rname, expected_name))
+ {
+- cp += n;
+- continue; /* XXX - had_error++ ? */
+- }
+-
+- switch (type)
+- {
+- case T_PTR:
+- if (__glibc_unlikely (__strcasecmp (tname, bp) != 0))
++ /* Decompress the target of the PTR record. This is the
++ host name we are looking for. We can only use it if it
++ is syntactically valid. Historically, only one host name
++ is returned here. If the recursive resolver performs DNS
++ record rotation, the returned host name is essentially
++ random, which is why multiple PTR records are rarely
++ used. Use MAXHOSTNAMELEN instead of NS_MAXCDNAME for
++ additional length checking. */
++ char hname[MAXHOSTNAMELEN + 1];
++ if (__ns_name_unpack (c.begin, c.end, rr.rdata,
++ name_buffer, sizeof (name_buffer)) < 0
++ || !__res_binary_hnok (expected_name)
++ || __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0)
+ {
+- cp += n;
+- continue; /* XXX - had_error++ ? */
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
+ }
+-
+- n = __ns_name_unpack (answer->buf, end_of_message, cp,
+- packtmp, sizeof packtmp);
+- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
+- {
+- if (__glibc_unlikely (errno == EMSGSIZE))
+- goto too_small;
+-
+- n = -1;
+- }
+-
+- if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0))
+- {
+- ++had_error;
+- break;
+- }
+- if (ttlp != NULL && ttl < *ttlp)
+- *ttlp = ttl;
+- /* bind would put multiple PTR records as aliases, but we don't do
+- that. */
+- result->h_name = bp;
+- *h_errnop = NETDB_SUCCESS;
++ /* Successful allocation is checked by the caller. */
++ *hnamep = alloc_buffer_copy_string (abuf, hname);
+ return NSS_STATUS_SUCCESS;
+- case T_A:
+- case T_AAAA:
+- if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0))
+- {
+- cp += n;
+- continue; /* XXX - had_error++ ? */
+- }
+-
+- /* Stop parsing at a record whose length is incorrect. */
+- if (n != rrtype_to_rdata_length (type))
+- {
+- ++had_error;
+- break;
+- }
+-
+- /* Skip records of the wrong type. */
+- if (n != result->h_length)
+- {
+- cp += n;
+- continue;
+- }
+- if (!haveanswer)
+- {
+- int nn;
+-
+- /* We compose a single hostent out of the entire chain of
+- entries, so the TTL of the hostent is essentially the lowest
+- TTL in the chain. */
+- if (ttlp != NULL && ttl < *ttlp)
+- *ttlp = ttl;
+- if (canonp != NULL)
+- *canonp = bp;
+- result->h_name = bp;
+- nn = strlen (bp) + 1; /* for the \0 */
+- bp += nn;
+- linebuflen -= nn;
+- }
+-
+- /* Provide sufficient alignment for both address
+- families. */
+- enum { align = 4 };
+- _Static_assert ((align % __alignof__ (struct in_addr)) == 0,
+- "struct in_addr alignment");
+- _Static_assert ((align % __alignof__ (struct in6_addr)) == 0,
+- "struct in6_addr alignment");
+- {
+- char *new_bp = PTR_ALIGN_UP (bp, align);
+- linebuflen -= new_bp - bp;
+- bp = new_bp;
+- }
+-
+- if (__glibc_unlikely (n > linebuflen))
+- goto too_small;
+- bp = __mempcpy (*hap++ = bp, cp, n);
+- cp += n;
+- linebuflen -= n;
+- break;
+- default:
+- abort ();
+ }
+- if (had_error == 0)
+- ++haveanswer;
+ }
+
+- if (haveanswer > 0)
+- {
+- *ap = NULL;
+- *hap = NULL;
+- /*
+- * Note: we sort even if host can take only one address
+- * in its return structures - should give it the "best"
+- * address in that case, not some random one
+- */
+- if (haveanswer > 1 && qtype == T_A
+- && __resolv_context_sort_count (ctx) > 0)
+- addrsort (ctx, host_data->h_addr_ptrs, haveanswer);
+-
+- if (result->h_name == NULL)
+- {
+- n = strlen (qname) + 1; /* For the \0. */
+- if (n > linebuflen)
+- goto too_small;
+- if (n >= MAXHOSTNAMELEN)
+- goto no_recovery;
+- result->h_name = bp;
+- bp = __mempcpy (bp, qname, n); /* Cannot overflow. */
+- linebuflen -= n;
+- }
++ /* No PTR record found. */
++ if (ttlp != NULL)
++ /* No caching of negative responses. */
++ *ttlp = 0;
+
+- if (have_to_map)
+- if (map_v4v6_hostent (result, &bp, &linebuflen))
+- goto too_small;
+- *h_errnop = NETDB_SUCCESS;
+- return NSS_STATUS_SUCCESS;
+- }
+- no_recovery:
+ *h_errnop = NO_RECOVERY;
+ *errnop = ENOENT;
+- /* Special case here: if the resolver sent a result but it only
+- contains a CNAME while we are looking for a T_A or T_AAAA record,
+- we fail with NOTFOUND instead of TRYAGAIN. */
+- return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
+- ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
++ return NSS_STATUS_TRYAGAIN;
+ }
+
+-
++/* Parses DNS data found in PACKETLEN bytes at PACKET in struct
++ gaih_addrtuple address tuples. The new address tuples are linked
++ from **TAILP, with backing store allocated from ABUF, and *TAILP is
++ updated to point where the next tuple pointer should be stored. If
++ TTLP is not null, *TTLP is updated to reflect the minimum TTL. If
++ STORE_CANON is true, the canonical name is stored as part of the
++ first address tuple being written. */
+ static enum nss_status
+-gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
+- struct gaih_addrtuple ***patp,
+- char **bufferp, size_t *buflenp,
+- int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
++gaih_getanswer_slice (unsigned char *packet, size_t packetlen,
++ struct alloc_buffer *abuf,
++ struct gaih_addrtuple ***tailp,
++ int *errnop, int *h_errnop, int32_t *ttlp,
++ bool store_canon)
+ {
+- char *buffer = *bufferp;
+- size_t buflen = *buflenp;
+-
+- struct gaih_addrtuple **pat = *patp;
+- const HEADER *hp = &answer->hdr;
+- int ancount = ntohs (hp->ancount);
+- int qdcount = ntohs (hp->qdcount);
+- const u_char *cp = answer->buf + HFIXEDSZ;
+- const u_char *end_of_message = answer->buf + anslen;
+- if (__glibc_unlikely (qdcount != 1))
+- {
+- *h_errnop = NO_RECOVERY;
+- return NSS_STATUS_UNAVAIL;
+- }
+-
+- u_char packtmp[NS_MAXCDNAME];
+- int n = __ns_name_unpack (answer->buf, end_of_message, cp,
+- packtmp, sizeof packtmp);
+- /* We unpack the name to check it for validity. But we do not need
+- it later. */
+- if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
+- {
+- if (__glibc_unlikely (errno == EMSGSIZE))
+- {
+- too_small:
+- *errnop = ERANGE;
+- *h_errnop = NETDB_INTERNAL;
+- return NSS_STATUS_TRYAGAIN;
+- }
+-
+- n = -1;
+- }
+-
+- if (__glibc_unlikely (n < 0))
++ struct ns_rr_cursor c;
++ if (!__ns_rr_cursor_init (&c, packet, packetlen))
+ {
+- *errnop = errno;
++ /* This should not happen because __res_context_query already
++ perfroms response validation. */
+ *h_errnop = NO_RECOVERY;
+ return NSS_STATUS_UNAVAIL;
+ }
+- if (__glibc_unlikely (__libc_res_hnok (buffer) == 0))
+- {
+- errno = EBADMSG;
+- *errnop = EBADMSG;
+- *h_errnop = NO_RECOVERY;
+- return NSS_STATUS_UNAVAIL;
+- }
+- cp += n + QFIXEDSZ;
+-
+- int haveanswer = 0;
+- int had_error = 0;
+- char *canon = NULL;
+- char *h_name = NULL;
+- int h_namelen = 0;
+-
+- if (ancount == 0)
++ bool haveanswer = false; /* Set to true if at least one address. */
++ uint16_t qtype = ns_rr_cursor_qtype (&c);
++ int ancount = ns_rr_cursor_ancount (&c);
++ const unsigned char *expected_name = ns_rr_cursor_qname (&c);
++ /* expected_name may be updated to point into this buffer. */
++ unsigned char name_buffer[NS_MAXCDNAME];
++
++ /* This is a pointer to a possibly-compressed name in the packet.
++ Eventually it is equivalent to the canonical name. If needed, it
++ is uncompressed and translated to text form when the first
++ address tuple is encountered. */
++ const unsigned char *compressed_alias_name = expected_name;
++
++ if (ancount == 0 || !__res_binary_hnok (compressed_alias_name))
+ {
+ *h_errnop = HOST_NOT_FOUND;
+ return NSS_STATUS_NOTFOUND;
+ }
+
+- while (ancount-- > 0 && cp < end_of_message && had_error == 0)
++ for (; ancount > -0; --ancount)
+ {
+- n = __ns_name_unpack (answer->buf, end_of_message, cp,
+- packtmp, sizeof packtmp);
+- if (n != -1 &&
+- (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
++ struct ns_rr_wire rr;
++ if (!__ns_rr_cursor_next (&c, &rr))
+ {
+- if (__glibc_unlikely (errno == EMSGSIZE))
+- goto too_small;
+-
+- n = -1;
+- }
+- if (__glibc_unlikely (n < 0 || __libc_res_hnok (buffer) == 0))
+- {
+- ++had_error;
+- continue;
+- }
+- if (*firstp && canon == NULL)
+- {
+- h_name = buffer;
+- buffer += h_namelen;
+- buflen -= h_namelen;
+- }
+-
+- cp += n; /* name */
+-
+- if (__glibc_unlikely (cp + 10 > end_of_message))
+- {
+- ++had_error;
+- continue;
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
+ }
+
+- uint16_t type;
+- NS_GET16 (type, cp);
+- uint16_t class;
+- NS_GET16 (class, cp);
+- int32_t ttl;
+- NS_GET32 (ttl, cp);
+- NS_GET16 (n, cp); /* RDATA length. */
++ /* Update TTL for known record types. */
++ if ((rr.rtype == T_CNAME || rr.rtype == qtype)
++ && ttlp != NULL && *ttlp > rr.ttl)
++ *ttlp = rr.ttl;
+
+- if (end_of_message - cp < n)
++ if (rr.rtype == T_CNAME)
+ {
+- /* RDATA extends beyond the end of the packet. */
+- ++had_error;
+- continue;
+- }
+-
+- if (class != C_IN)
+- {
+- cp += n;
+- continue;
+- }
+-
+- if (type == T_CNAME)
+- {
+- char tbuf[MAXDNAME];
+-
+- /* A CNAME could also have a TTL entry. */
+- if (ttlp != NULL && ttl < *ttlp)
+- *ttlp = ttl;
+-
+- n = __libc_dn_expand (answer->buf, end_of_message, cp,
+- tbuf, sizeof tbuf);
+- if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0))
++ /* NB: No check for owner name match, based on historic
++ precedent. Record the CNAME target as the new expected
++ name. */
++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
++ name_buffer, sizeof (name_buffer));
++ if (n < 0)
+ {
+- ++had_error;
+- continue;
+- }
+- cp += n;
+-
+- if (*firstp)
+- {
+- /* Reclaim buffer space. */
+- if (h_name + h_namelen == buffer)
+- {
+- buffer = h_name;
+- buflen += h_namelen;
+- }
+-
+- n = strlen (tbuf) + 1;
+- if (__glibc_unlikely (n > buflen))
+- goto too_small;
+- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
+- {
+- ++had_error;
+- continue;
+- }
+-
+- canon = buffer;
+- buffer = __mempcpy (buffer, tbuf, n);
+- buflen -= n;
+- h_namelen = 0;
++ *h_errnop = NO_RECOVERY;
++ return NSS_STATUS_UNAVAIL;
+ }
+- continue;
++ expected_name = name_buffer;
++ if (store_canon && __res_binary_hnok (name_buffer))
++ /* This name can be used as a canonical name. Do not
++ translate to text form here to conserve buffer space.
++ Point to the compressed name because name_buffer can be
++ overwritten with an unusable name later. */
++ compressed_alias_name = rr.rdata;
+ }
+-
+- /* Stop parsing if we encounter a record with incorrect RDATA
+- length. */
+- if (type == T_A || type == T_AAAA)
++ else if (rr.rtype == qtype
++ && __ns_samebinaryname (rr.rname, expected_name)
++ && rr.rdlength == rrtype_to_rdata_length (qtype))
+ {
+- if (n != rrtype_to_rdata_length (type))
++ struct gaih_addrtuple *ntup
++ = alloc_buffer_alloc (abuf, struct gaih_addrtuple);
++ /* Delay error reporting to the callers (they implement the
++ ERANGE buffer resizing handshake). */
++ if (ntup != NULL)
+ {
+- ++had_error;
+- continue;
++ ntup->next = NULL;
++ if (store_canon && compressed_alias_name != NULL)
++ {
++ /* This assumes that all the CNAME records come
++ first. Use MAXHOSTNAMELEN instead of
++ NS_MAXCDNAME for additional length checking.
++ However, these checks are not expected to fail
++ because all size NS_MAXCDNAME names should into
++ the hname buffer because no escaping is
++ needed. */
++ char unsigned nbuf[NS_MAXCDNAME];
++ char hname[MAXHOSTNAMELEN + 1];
++ if (__ns_name_unpack (c.begin, c.end,
++ compressed_alias_name,
++ nbuf, sizeof (nbuf)) >= 0
++ && __ns_name_ntop (nbuf, hname, sizeof (hname)) >= 0)
++ /* Space checking is performed by the callers. */
++ ntup->name = alloc_buffer_copy_string (abuf, hname);
++ store_canon = false;
++ }
++ else
++ ntup->name = NULL;
++ if (rr.rdlength == 4)
++ ntup->family = AF_INET;
++ else
++ ntup->family = AF_INET6;
++ memcpy (ntup->addr, rr.rdata, rr.rdlength);
++ ntup->scopeid = 0;
++
++ /* Link in the new tuple, and update the tail pointer to
++ point to its next field. */
++ **tailp = ntup;
++ *tailp = &ntup->next;
++
++ haveanswer = true;
+ }
+ }
+- else
+- {
+- /* Skip unknown records. */
+- cp += n;
+- continue;
+- }
+-
+- assert (type == T_A || type == T_AAAA);
+- if (*pat == NULL)
+- {
+- uintptr_t pad = (-(uintptr_t) buffer
+- % __alignof__ (struct gaih_addrtuple));
+- buffer += pad;
+- buflen = buflen > pad ? buflen - pad : 0;
+-
+- if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple)))
+- goto too_small;
+-
+- *pat = (struct gaih_addrtuple *) buffer;
+- buffer += sizeof (struct gaih_addrtuple);
+- buflen -= sizeof (struct gaih_addrtuple);
+- }
+-
+- (*pat)->name = NULL;
+- (*pat)->next = NULL;
+-
+- if (*firstp)
+- {
+- /* We compose a single hostent out of the entire chain of
+- entries, so the TTL of the hostent is essentially the lowest
+- TTL in the chain. */
+- if (ttlp != NULL && ttl < *ttlp)
+- *ttlp = ttl;
+-
+- (*pat)->name = canon ?: h_name;
+-
+- *firstp = 0;
+- }
+-
+- (*pat)->family = type == T_A ? AF_INET : AF_INET6;
+- memcpy ((*pat)->addr, cp, n);
+- cp += n;
+- (*pat)->scopeid = 0;
+-
+- pat = &((*pat)->next);
+-
+- haveanswer = 1;
+ }
+
+ if (haveanswer)
+ {
+- *patp = pat;
+- *bufferp = buffer;
+- *buflenp = buflen;
+-
+ *h_errnop = NETDB_SUCCESS;
+ return NSS_STATUS_SUCCESS;
+ }
+-
+- /* Special case here: if the resolver sent a result but it only
+- contains a CNAME while we are looking for a T_A or T_AAAA record,
+- we fail with NOTFOUND instead of TRYAGAIN. */
+- if (canon != NULL)
++ else
+ {
++ /* Special case here: if the resolver sent a result but it only
++ contains a CNAME while we are looking for a T_A or T_AAAA
++ record, we fail with NOTFOUND. */
+ *h_errnop = HOST_NOT_FOUND;
+ return NSS_STATUS_NOTFOUND;
+ }
+-
+- *h_errnop = NETDB_INTERNAL;
+- return NSS_STATUS_TRYAGAIN;
+ }
+
+
+ static enum nss_status
+-gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
+- int anslen2, const char *qname,
+- struct gaih_addrtuple **pat, char *buffer, size_t buflen,
++gaih_getanswer (unsigned char *packet1, size_t packet1len,
++ unsigned char *packet2, size_t packet2len,
++ struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
+ int *errnop, int *h_errnop, int32_t *ttlp)
+ {
+- int first = 1;
+-
+ enum nss_status status = NSS_STATUS_NOTFOUND;
+
+ /* Combining the NSS status of two distinct queries requires some
+@@ -1295,7 +1045,10 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
+ between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
+ A recoverable TRYAGAIN is almost always due to buffer size issues
+ and returns ERANGE in errno and the caller is expected to retry
+- with a larger buffer.
++ with a larger buffer. (The caller, _nss_dns_gethostbyname4_r,
++ ignores the return status if it detects that the result buffer
++ has been exhausted and generates a TRYAGAIN failure with an
++ ERANGE code.)
+
+ Lastly, you may be tempted to make significant changes to the
+ conditions in this code to bring about symmetry between responses.
+@@ -1375,36 +1128,30 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
+ is a recoverable error we now return TRYAGIN even if the first
+ response was SUCCESS. */
+
+- if (anslen1 > 0)
+- status = gaih_getanswer_slice(answer1, anslen1, qname,
+- &pat, &buffer, &buflen,
+- errnop, h_errnop, ttlp,
+- &first);
+-
+- if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
+- || (status == NSS_STATUS_TRYAGAIN
+- /* We want to look at the second answer in case of an
+- NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e.
+- *h_errnop is NO_RECOVERY. If not, and if the failure was due to
+- an insufficient buffer (ERANGE), then we need to drop the results
+- and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can
+- repeat the query with a larger buffer. */
+- && (*errnop != ERANGE || *h_errnop == NO_RECOVERY)))
+- && answer2 != NULL && anslen2 > 0)
++ if (packet1len > 0)
+ {
+- enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
+- &pat, &buffer, &buflen,
+- errnop, h_errnop, ttlp,
+- &first);
++ status = gaih_getanswer_slice (packet1, packet1len,
++ abuf, &pat, errnop, h_errnop, ttlp, true);
++ if (alloc_buffer_has_failed (abuf))
++ /* Do not try parsing the second packet if a larger result
++ buffer is needed. The caller implements the resizing
++ protocol because *abuf has been exhausted. */
++ return NSS_STATUS_TRYAGAIN; /* Ignored by the caller. */
++ }
++
++ if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
++ && packet2 != NULL && packet2len > 0)
++ {
++ enum nss_status status2
++ = gaih_getanswer_slice (packet2, packet2len,
++ abuf, &pat, errnop, h_errnop, ttlp,
++ /* Success means that data with a
++ canonical name has already been
++ stored. Do not store the name again. */
++ status != NSS_STATUS_SUCCESS);
+ /* Use the second response status in some cases. */
+ if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
+ status = status2;
+- /* Do not return a truncated second response (unless it was
+- unavoidable e.g. unrecoverable TRYAGAIN). */
+- if (status == NSS_STATUS_SUCCESS
+- && (status2 == NSS_STATUS_TRYAGAIN
+- && *errnop == ERANGE && *h_errnop != NO_RECOVERY))
+- status = NSS_STATUS_TRYAGAIN;
+ }
+
+ return status;
+@@ -1412,18 +1159,13 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
+
+ /* Variant of gaih_getanswer without a second (AAAA) response. */
+ static enum nss_status
+-gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname,
+- struct gaih_addrtuple **pat,
+- char *buffer, size_t buflen,
++gaih_getanswer_noaaaa (unsigned char *packet, size_t packetlen,
++ struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
+ int *errnop, int *h_errnop, int32_t *ttlp)
+ {
+- int first = 1;
+-
+ enum nss_status status = NSS_STATUS_NOTFOUND;
+- if (anslen1 > 0)
+- status = gaih_getanswer_slice (answer1, anslen1, qname,
+- &pat, &buffer, &buflen,
+- errnop, h_errnop, ttlp,
+- &first);
++ if (packetlen > 0)
++ status = gaih_getanswer_slice (packet, packetlen,
++ abuf, &pat, errnop, h_errnop, ttlp, true);
+ return status;
+ }
+diff --git a/resolv/res-name-checking.c b/resolv/res-name-checking.c
+index 07a412d8ff..213edceaf3 100644
+--- a/resolv/res-name-checking.c
++++ b/resolv/res-name-checking.c
+@@ -138,6 +138,12 @@ binary_leading_dash (const unsigned char *dn)
+ return dn[0] > 0 && dn[1] == '-';
+ }
+
++bool
++__res_binary_hnok (const unsigned char *dn)
++{
++ return !binary_leading_dash (dn) && binary_hnok (dn);
++}
++
+ /* Return 1 if res_hnok is a valid host name. Labels must only
+ contain [0-9a-zA-Z_-] characters, and the name must not start with
+ a '-'. The latter is to avoid confusion with program options. */
+@@ -145,11 +151,9 @@ int
+ ___res_hnok (const char *dn)
+ {
+ unsigned char buf[NS_MAXCDNAME];
+- if (!printable_string (dn)
+- || __ns_name_pton (dn, buf, sizeof (buf)) < 0
+- || binary_leading_dash (buf))
+- return 0;
+- return binary_hnok (buf);
++ return (printable_string (dn)
++ && __ns_name_pton (dn, buf, sizeof (buf)) >= 0
++ && __res_binary_hnok (buf));
+ }
+ versioned_symbol (libc, ___res_hnok, res_hnok, GLIBC_2_34);
+ versioned_symbol (libc, ___res_hnok, __libc_res_hnok, GLIBC_PRIVATE);
+diff --git a/resolv/tst-ns_name_length_uncompressed.c b/resolv/tst-ns_name_length_uncompressed.c
+new file mode 100644
+index 0000000000..c4a2904db7
+--- /dev/null
++++ b/resolv/tst-ns_name_length_uncompressed.c
+@@ -0,0 +1,135 @@
++/* Test __ns_name_length_uncompressed.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <array_length.h>
++#include <errno.h>
++#include <stdio.h>
++#include <support/check.h>
++#include <support/next_to_fault.h>
++
++/* Reference implementation based on other building blocks. */
++static int
++reference_length (const unsigned char *p, const unsigned char *eom)
++{
++ unsigned char buf[NS_MAXCDNAME];
++ int n = __ns_name_unpack (p, eom, p, buf, sizeof (buf));
++ if (n < 0)
++ return n;
++ const unsigned char *q = buf;
++ if (__ns_name_skip (&q, array_end (buf)) < 0)
++ return -1;
++ if (q - buf != n)
++ /* Compressed name. */
++ return -1;
++ return n;
++}
++
++static int
++do_test (void)
++{
++ {
++ unsigned char buf[] = { 3, 'w', 'w', 'w', 0, 0, 0 };
++ TEST_COMPARE (reference_length (buf, array_end (buf)), sizeof (buf) - 2);
++ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)),
++ sizeof (buf) - 2);
++ TEST_COMPARE (reference_length (array_end (buf) - 1, array_end (buf)), 1);
++ TEST_COMPARE (__ns_name_length_uncompressed (array_end (buf) - 1,
++ array_end (buf)), 1);
++ buf[4] = 0xc0; /* Forward compression reference. */
++ buf[5] = 0x06;
++ TEST_COMPARE (reference_length (buf, array_end (buf)), -1);
++ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), -1);
++ }
++
++ struct support_next_to_fault ntf = support_next_to_fault_allocate (300);
++
++ /* Buffer region with all possible bytes at start and end. */
++ for (int length = 1; length <= 300; ++length)
++ {
++ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length;
++ unsigned char *start = end - length;
++ memset (start, 'X', length);
++ for (int first = 0; first <= 255; ++first)
++ {
++ *start = first;
++ for (int last = 0; last <= 255; ++last)
++ {
++ start[length - 1] = last;
++ TEST_COMPARE (reference_length (start, end),
++ __ns_name_length_uncompressed (start, end));
++ }
++ }
++ }
++
++ /* Poor man's fuzz testing: patch two bytes. */
++ {
++ unsigned char ref[] =
++ {
++ 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'n', 'e', 't', 0, 0, 0
++ };
++ TEST_COMPARE (reference_length (ref, array_end (ref)), 13);
++ TEST_COMPARE (__ns_name_length_uncompressed (ref, array_end (ref)), 13);
++
++ int good = 0;
++ int bad = 0;
++ for (int length = 1; length <= sizeof (ref); ++length)
++ {
++ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length;
++ unsigned char *start = end - length;
++ memcpy (start, ref, length);
++
++ for (int patch1_pos = 0; patch1_pos < length; ++patch1_pos)
++ {
++ for (int patch1_value = 0; patch1_value <= 255; ++patch1_value)
++ {
++ start[patch1_pos] = patch1_value;
++ for (int patch2_pos = 0; patch2_pos < length; ++patch2_pos)
++ {
++ for (int patch2_value = 0; patch2_value <= 255;
++ ++patch2_value)
++ {
++ start[patch2_pos] = patch2_value;
++ int expected = reference_length (start, end);
++ errno = EINVAL;
++ int actual
++ = __ns_name_length_uncompressed (start, end);
++ if (actual > 0)
++ ++good;
++ else
++ {
++ TEST_COMPARE (errno, EMSGSIZE);
++ ++bad;
++ }
++ TEST_COMPARE (expected, actual);
++ }
++ start[patch2_pos] = ref[patch2_pos];
++ }
++ }
++ start[patch1_pos] = ref[patch1_pos];
++ }
++ }
++ printf ("info: patched inputs with success: %d\n", good);
++ printf ("info: patched inputs with failure: %d\n", bad);
++ }
++
++ support_next_to_fault_free (&ntf);
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/resolv/tst-ns_rr_cursor.c b/resolv/tst-ns_rr_cursor.c
+new file mode 100644
+index 0000000000..c3c0908905
+--- /dev/null
++++ b/resolv/tst-ns_rr_cursor.c
+@@ -0,0 +1,227 @@
++/* Tests for resource record parsing.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/next_to_fault.h>
++
++/* Reference packet for packet parsing. */
++static const unsigned char valid_packet[] =
++ { 0x11, 0x12, 0x13, 0x14,
++ 0x00, 0x01, /* Question count. */
++ 0x00, 0x02, /* Answer count. */
++ 0x21, 0x22, 0x23, 0x24, /* Other counts (not actually in packet). */
++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0,
++ 0x00, 0x1c, /* Question type: AAAA. */
++ 0x00, 0x01, /* Question class: IN. */
++ 0xc0, 0x0c, /* Compression reference to QNAME. */
++ 0x00, 0x1c, /* Record type: AAAA. */
++ 0x00, 0x01, /* Record class: IN. */
++ 0x12, 0x34, 0x56, 0x78, /* Record TTL. */
++ 0x00, 0x10, /* Record data length (16 bytes). */
++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* IPv6 address. */
++ 0xc0, 0x0c, /* Compression reference to QNAME. */
++ 0x00, 0x1c, /* Record type: AAAA. */
++ 0x00, 0x01, /* Record class: IN. */
++ 0x11, 0x33, 0x55, 0x77, /* Record TTL. */
++ 0x00, 0x10, /* Record data length (16 bytes). */
++ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
++ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* IPv6 address. */
++ };
++
++/* Special offsets in valid_packet. */
++enum
++ {
++ offset_of_first_record = 29,
++ offset_of_second_record = 57,
++ };
++
++/* Check that parsing valid_packet succeeds. */
++static void
++test_valid (void)
++{
++ struct ns_rr_cursor c;
++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, valid_packet,
++ sizeof (valid_packet)));
++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
++ TEST_COMPARE (c.current - valid_packet, offset_of_first_record);
++
++ struct ns_rr_wire r;
++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
++ TEST_COMPARE (r.rtype, T_AAAA);
++ TEST_COMPARE (r.rclass, C_IN);
++ TEST_COMPARE (r.ttl, 0x12345678);
++ TEST_COMPARE_BLOB (r.rdata, r.rdlength,
++ "\x90\x91\x92\x93\x94\x95\x96\x97"
++ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16);
++ TEST_COMPARE (c.current - valid_packet, offset_of_second_record);
++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
++ TEST_COMPARE (r.rtype, T_AAAA);
++ TEST_COMPARE (r.rclass, C_IN);
++ TEST_COMPARE (r.ttl, 0x11335577);
++ TEST_COMPARE_BLOB (r.rdata, r.rdlength,
++ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
++ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 16);
++ TEST_VERIFY (c.current == c.end);
++}
++
++/* Check that trying to parse a packet with a compressed QNAME fails. */
++static void
++test_compressed_qname (void)
++{
++ static const unsigned char packet[] =
++ { 0x11, 0x12, 0x13, 0x14,
++ 0x00, 0x01, /* Question count. */
++ 0x00, 0x00, /* Answer count. */
++ 0x00, 0x00, 0x00, 0x00, /* Other counts. */
++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
++ 0x00, 0x01, /* Question type: A. */
++ 0x00, 0x01, /* Question class: IN. */
++ };
++
++ struct ns_rr_cursor c;
++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet)));
++}
++
++/* Check that trying to parse a packet with two questions fails. */
++static void
++test_two_questions (void)
++{
++ static const unsigned char packet[] =
++ { 0x11, 0x12, 0x13, 0x14,
++ 0x00, 0x02, /* Question count. */
++ 0x00, 0x00, /* Answer count. */
++ 0x00, 0x00, 0x00, 0x00, /* Other counts. */
++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
++ 0x00, 0x01, /* Question type: A. */
++ 0x00, 0x01, /* Question class: IN. */
++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
++ 0x00, 0x1c, /* Question type: AAAA. */
++ 0x00, 0x01, /* Question class: IN. */
++ };
++
++ struct ns_rr_cursor c;
++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet)));
++}
++
++/* Used to check that parsing truncated packets does not over-read. */
++static struct support_next_to_fault ntf;
++
++/* Truncated packet in the second resource record. */
++static void
++test_truncated_one_rr (size_t length)
++{
++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
++ unsigned char *start = end - length;
++
++ /* Produce the truncated packet. */
++ memcpy (start, valid_packet, length);
++
++ struct ns_rr_cursor c;
++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length));
++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
++ TEST_COMPARE (c.current - start, offset_of_first_record);
++
++ struct ns_rr_wire r;
++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
++ TEST_COMPARE (r.rtype, T_AAAA);
++ TEST_COMPARE (r.rclass, C_IN);
++ TEST_COMPARE (r.ttl, 0x12345678);
++ TEST_COMPARE_BLOB (r.rdata, r.rdlength,
++ "\x90\x91\x92\x93\x94\x95\x96\x97"
++ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16);
++ TEST_COMPARE (c.current - start, offset_of_second_record);
++ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r));
++}
++
++/* Truncated packet in the first resource record. */
++static void
++test_truncated_no_rr (size_t length)
++{
++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
++ unsigned char *start = end - length;
++
++ /* Produce the truncated packet. */
++ memcpy (start, valid_packet, length);
++
++ struct ns_rr_cursor c;
++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length));
++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
++ TEST_COMPARE (c.current - start, offset_of_first_record);
++
++ struct ns_rr_wire r;
++ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r));
++}
++
++/* Truncated packet before first resource record. */
++static void
++test_truncated_before_rr (size_t length)
++{
++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
++ unsigned char *start = end - length;
++
++ /* Produce the truncated packet. */
++ memcpy (start, valid_packet, length);
++
++ struct ns_rr_cursor c;
++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, start, length));
++}
++
++static int
++do_test (void)
++{
++ ntf = support_next_to_fault_allocate (sizeof (valid_packet));
++
++ test_valid ();
++ test_compressed_qname ();
++ test_two_questions ();
++
++ for (int length = offset_of_second_record; length < sizeof (valid_packet);
++ ++length)
++ test_truncated_one_rr (length);
++ for (int length = offset_of_first_record; length < offset_of_second_record;
++ ++length)
++ test_truncated_no_rr (length);
++ for (int length = 0; length < offset_of_first_record; ++length)
++ test_truncated_before_rr (length);
++
++ support_next_to_fault_free (&ntf);
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/resolv/tst-ns_samebinaryname.c b/resolv/tst-ns_samebinaryname.c
+new file mode 100644
+index 0000000000..b06ac610b4
+--- /dev/null
++++ b/resolv/tst-ns_samebinaryname.c
+@@ -0,0 +1,62 @@
++/* Test the __ns_samebinaryname function.
++ Copyright (C) 2022 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 <arpa/nameser.h>
++#include <array_length.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <support/check.h>
++
++/* First character denotes the comparison group: All names with the
++ same first character are expected to compare equal. */
++static const char *const cases[] =
++ {
++ " ",
++ "1\001a", "1\001A",
++ "2\002ab", "2\002aB", "2\002Ab", "2\002AB",
++ "3\001a\002ab", "3\001A\002ab",
++ "w\003www\007example\003com", "w\003Www\007Example\003Com",
++ "w\003WWW\007EXAMPLE\003COM",
++ "W\003WWW", "W\003www",
++ };
++
++static int
++do_test (void)
++{
++ for (int i = 0; i < array_length (cases); ++i)
++ for (int j = 0; j < array_length (cases); ++j)
++ {
++ unsigned char *a = (unsigned char *) &cases[i][1];
++ unsigned char *b = (unsigned char *) &cases[j][1];
++ bool actual = __ns_samebinaryname (a, b);
++ bool expected = cases[i][0] == cases[j][0];
++ if (actual != expected)
++ {
++ char a1[NS_MAXDNAME];
++ TEST_VERIFY (ns_name_ntop (a, a1, sizeof (a1)) > 0);
++ char b1[NS_MAXDNAME];
++ TEST_VERIFY (ns_name_ntop (b, b1, sizeof (b1)) > 0);
++ printf ("error: \"%s\" \"%s\": expected %s\n",
++ a1, b1, expected ? "equal" : "unqueal");
++ support_record_failure ();
++ }
++ }
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/resolv/tst-resolv-aliases.c b/resolv/tst-resolv-aliases.c
+new file mode 100644
+index 0000000000..b212823aa0
+--- /dev/null
++++ b/resolv/tst-resolv-aliases.c
+@@ -0,0 +1,254 @@
++/* Test alias handling (mainly for gethostbyname).
++ Copyright (C) 2022 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 <array_length.h>
++#include <arpa/inet.h>
++#include <netdb.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/check_nss.h>
++#include <support/resolv_test.h>
++#include <support/support.h>
++
++#include "tst-resolv-maybe_insert_sig.h"
++
++/* QNAME format:
++
++ aADDRESSES-cCNAMES.example.net
++
++ CNAMES is the length of the CNAME chain, ADDRESSES is the number of
++ addresses in the response. The special value 255 means that there
++ are no addresses, and the RCODE is NXDOMAIN. */
++static void
++response (const struct resolv_response_context *ctx,
++ struct resolv_response_builder *b,
++ const char *qname, uint16_t qclass, uint16_t qtype)
++{
++ TEST_COMPARE (qclass, C_IN);
++ if (qtype != T_A)
++ TEST_COMPARE (qtype, T_AAAA);
++
++ unsigned int addresses, cnames;
++ char *tail;
++ if (sscanf (qname, "a%u-c%u%ms", &addresses, &cnames, &tail) == 3)
++ {
++ if (strcmp (tail, ".example.com") == 0
++ || strcmp (tail, ".example.net.example.net") == 0
++ || strcmp (tail, ".example.net.example.com") == 0)
++ /* These only happen after NXDOMAIN. */
++ TEST_VERIFY (addresses == 255);
++ else if (strcmp (tail, ".example.net") != 0)
++ FAIL_EXIT1 ("invalid QNAME: %s", qname);
++ }
++ free (tail);
++
++ int rcode;
++ if (addresses == 255)
++ {
++ /* Special case: Use no addresses with NXDOMAIN response. */
++ rcode = ns_r_nxdomain;
++ addresses = 0;
++ }
++ else
++ rcode = 0;
++
++ struct resolv_response_flags flags = { .rcode = rcode };
++ resolv_response_init (b, flags);
++ resolv_response_add_question (b, qname, qclass, qtype);
++ resolv_response_section (b, ns_s_an);
++ maybe_insert_sig (b, qname);
++
++ /* Provide the requested number of CNAME records. */
++ char *previous_name = (char *) qname;
++ for (int unique = 0; unique < cnames; ++unique)
++ {
++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
++ char *new_name = xasprintf ("%d.alias.example", unique);
++ resolv_response_add_name (b, new_name);
++ resolv_response_close_record (b);
++
++ maybe_insert_sig (b, qname);
++
++ if (previous_name != qname)
++ free (previous_name);
++ previous_name = new_name;
++ }
++
++ for (int unique = 0; unique < addresses; ++unique)
++ {
++ resolv_response_open_record (b, previous_name, qclass, qtype, 60);
++
++ if (qtype == T_A)
++ {
++ char ipv4[4] = {192, 0, 2, 1 + unique};
++ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
++ }
++ else if (qtype == T_AAAA)
++ {
++ char ipv6[16] =
++ {
++ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 1 + unique
++ };
++ resolv_response_add_data (b, &ipv6, sizeof (ipv6));
++ }
++ resolv_response_close_record (b);
++ }
++
++ if (previous_name != qname)
++ free (previous_name);
++}
++
++static char *
++make_qname (bool do_search, int cnames, int addresses)
++{
++ return xasprintf ("a%d-c%d%s",
++ addresses, cnames, do_search ? "" : ".example.net");
++}
++
++static void
++check_cnames_failure (int af, bool do_search, int cnames, int addresses)
++{
++ char *qname = make_qname (do_search, cnames, addresses);
++
++ struct hostent *e;
++ if (af == AF_UNSPEC)
++ e = gethostbyname (qname);
++ else
++ e = gethostbyname2 (qname, af);
++
++ if (addresses == 0)
++ check_hostent (qname, e, "error: NO_RECOVERY\n");
++ else
++ check_hostent (qname, e, "error: HOST_NOT_FOUND\n");
++
++ free (qname);
++}
++
++static void
++check (int af, bool do_search, int cnames, int addresses)
++{
++ char *qname = make_qname (do_search, cnames, addresses);
++ char *fqdn = make_qname (false, cnames, addresses);
++
++ struct hostent *e;
++ if (af == AF_UNSPEC)
++ e = gethostbyname (qname);
++ else
++ e = gethostbyname2 (qname, af);
++ if (e == NULL)
++ FAIL_EXIT1 ("unexpected failure for %d, %d, %d", af, cnames, addresses);
++
++ if (af == AF_UNSPEC || af == AF_INET)
++ {
++ TEST_COMPARE (e->h_addrtype, AF_INET);
++ TEST_COMPARE (e->h_length, 4);
++ }
++ else
++ {
++ TEST_COMPARE (e->h_addrtype, AF_INET6);
++ TEST_COMPARE (e->h_length, 16);
++ }
++
++ for (int i = 0; i < addresses; ++i)
++ {
++ char ipv4[4] = {192, 0, 2, 1 + i};
++ char ipv6[16] =
++ { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + i };
++ char *expected = e->h_addrtype == AF_INET ? ipv4 : ipv6;
++ TEST_COMPARE_BLOB (e->h_addr_list[i], e->h_length,
++ expected, e->h_length);
++ }
++ TEST_VERIFY (e->h_addr_list[addresses] == NULL);
++
++
++ if (cnames == 0)
++ {
++ /* QNAME is fully qualified. */
++ TEST_COMPARE_STRING (e->h_name, fqdn);
++ TEST_VERIFY (e->h_aliases[0] == NULL);
++ }
++ else
++ {
++ /* Fully-qualified QNAME is demoted to an aliases. */
++ TEST_COMPARE_STRING (e->h_aliases[0], fqdn);
++
++ for (int i = 1; i <= cnames; ++i)
++ {
++ char *expected = xasprintf ("%d.alias.example", i - 1);
++ if (i == cnames)
++ TEST_COMPARE_STRING (e->h_name, expected);
++ else
++ TEST_COMPARE_STRING (e->h_aliases[i], expected);
++ free (expected);
++ }
++ TEST_VERIFY (e->h_aliases[cnames] == NULL);
++ }
++
++ free (fqdn);
++ free (qname);
++}
++
++static int
++do_test (void)
++{
++ struct resolv_test *obj = resolv_test_start
++ ((struct resolv_redirect_config)
++ {
++ .response_callback = response,
++ .search = { "example.net", "example.com" },
++ });
++
++ static const int families[] = { AF_UNSPEC, AF_INET, AF_INET6 };
++
++ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig)
++ {
++ insert_sig = do_insert_sig;
++
++ /* If do_search is true, a bare host name (for example, a1-c1)
++ is used. This exercises search path processing and FQDN
++ qualification. */
++ for (int do_search = 0; do_search < 2; ++do_search)
++ for (const int *paf = families; paf != array_end (families); ++paf)
++ {
++ for (int cnames = 0; cnames <= 100; ++cnames)
++ {
++ check_cnames_failure (*paf, do_search, cnames, 0);
++ /* Now with NXDOMAIN responses. */
++ check_cnames_failure (*paf, do_search, cnames, 255);
++ }
++
++ for (int cnames = 0; cnames <= 10; ++cnames)
++ for (int addresses = 1; addresses <= 10; ++addresses)
++ check (*paf, do_search, cnames, addresses);
++
++ /* The current implementation is limited to 47 aliases.
++ Addresses do not have such a limit. */
++ check (*paf, do_search, 47, 60);
++ }
++ }
++
++ resolv_test_end (obj);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/resolv/tst-resolv-byaddr.c b/resolv/tst-resolv-byaddr.c
+new file mode 100644
+index 0000000000..6299e89837
+--- /dev/null
++++ b/resolv/tst-resolv-byaddr.c
+@@ -0,0 +1,326 @@
++/* Test reverse DNS lookup.
++ Copyright (C) 2022 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 <arpa/inet.h>
++#include <errno.h>
++#include <netdb.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/check_nss.h>
++#include <support/next_to_fault.h>
++#include <support/resolv_test.h>
++#include <support/support.h>
++
++#include "tst-resolv-maybe_insert_sig.h"
++
++/* QNAME format:
++
++ ADDRESSES.CNAMES...(lots of 0s)...8.b.d.0.1.0.0.2.ip6.arpa.
++ CNAMES|ADDRESSES.2.0.192.in-addr-arpa.
++
++ For the IPv4 reverse lookup, the address count is in the lower
++ bits.
++
++ CNAMES is the length of the CNAME chain, ADDRESSES is the number of
++ addresses in the response. The special value 15 means that there
++ are no addresses, and the RCODE is NXDOMAIN. */
++static void
++response (const struct resolv_response_context *ctx,
++ struct resolv_response_builder *b,
++ const char *qname, uint16_t qclass, uint16_t qtype)
++{
++ TEST_COMPARE (qclass, C_IN);
++ TEST_COMPARE (qtype, T_PTR);
++
++ unsigned int addresses, cnames, bits;
++ char *tail;
++ if (strstr (qname, "ip6.arpa") != NULL
++ && sscanf (qname, "%x.%x.%ms", &addresses, &cnames, &tail) == 3)
++ TEST_COMPARE_STRING (tail, "\
++0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
++ else if (sscanf (qname, "%u.%ms", &bits, &tail) == 2)
++ {
++ TEST_COMPARE_STRING (tail, "2.0.192.in-addr.arpa");
++ addresses = bits & 0x0f;
++ cnames = bits >> 4;
++ }
++ else
++ FAIL_EXIT1 ("invalid QNAME: %s", qname);
++ free (tail);
++
++ int rcode;
++ if (addresses == 15)
++ {
++ /* Special case: Use no addresses with NXDOMAIN response. */
++ rcode = ns_r_nxdomain;
++ addresses = 0;
++ }
++ else
++ rcode = 0;
++
++ struct resolv_response_flags flags = { .rcode = rcode };
++ resolv_response_init (b, flags);
++ resolv_response_add_question (b, qname, qclass, qtype);
++ resolv_response_section (b, ns_s_an);
++ maybe_insert_sig (b, qname);
++
++ /* Provide the requested number of CNAME records. */
++ char *previous_name = (char *) qname;
++ for (int unique = 0; unique < cnames; ++unique)
++ {
++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
++ char *new_name = xasprintf ("%d.alias.example", unique);
++ resolv_response_add_name (b, new_name);
++ resolv_response_close_record (b);
++
++ maybe_insert_sig (b, qname);
++
++ if (previous_name != qname)
++ free (previous_name);
++ previous_name = new_name;
++ }
++
++ for (int unique = 0; unique < addresses; ++unique)
++ {
++ resolv_response_open_record (b, previous_name, qclass, T_PTR, 60);
++ char *ptr = xasprintf ("unique-%d.cnames-%u.addresses-%u.example",
++ unique, cnames, addresses);
++ resolv_response_add_name (b, ptr);
++ free (ptr);
++ resolv_response_close_record (b);
++ }
++
++ if (previous_name != qname)
++ free (previous_name);
++}
++
++/* Used to check that gethostbyaddr_r does not write past the buffer
++ end. */
++static struct support_next_to_fault ntf;
++
++/* Perform a gethostbyaddr call and check the result. */
++static void
++check_gethostbyaddr (const char *address, const char *expected)
++{
++ unsigned char bytes[16];
++ unsigned int byteslen;
++ int family;
++ if (strchr (address, ':') != NULL)
++ {
++ family = AF_INET6;
++ byteslen = 16;
++ }
++ else
++ {
++ family = AF_INET;
++ byteslen = 4;
++ }
++ TEST_COMPARE (inet_pton (family, address, bytes), 1);
++
++ struct hostent *e = gethostbyaddr (bytes, byteslen, family);
++ check_hostent (address, e, expected);
++
++ if (e == NULL)
++ return;
++
++ /* Try gethostbyaddr_r with increasing sizes until success. First
++ compute a reasonable minimum buffer size, to avoid many pointless
++ attempts. */
++ size_t minimum_size = strlen (e->h_name);
++ for (int i = 0; e->h_addr_list[i] != NULL; ++i)
++ minimum_size += e->h_length + sizeof (char *);
++ for (int i = 0; e->h_aliases[i] != NULL; ++i)
++ minimum_size += strlen (e->h_aliases[i]) + 1 + sizeof (char *);
++
++ /* Gradually increase the size until success. */
++ for (size_t size = minimum_size; size < ntf.length; ++size)
++ {
++ struct hostent result;
++ int herrno;
++ int ret = gethostbyaddr_r (bytes, byteslen, family, &result,
++ ntf.buffer + ntf.length - size, size,
++ &e, &herrno);
++ if (ret == ERANGE)
++ /* Retry with larger size. */
++ TEST_COMPARE (herrno, NETDB_INTERNAL);
++ else if (ret == 0)
++ {
++ TEST_VERIFY (size > minimum_size);
++ check_hostent (address, e, expected);
++ return;
++ }
++ else
++ FAIL_EXIT1 ("Unexpected gethostbyaddr_r failure: %d", ret);
++ }
++
++ FAIL_EXIT1 ("gethostbyaddr_r always failed for: %s", address);
++}
++
++/* Perform a getnameinfo call and check the result. */
++static void
++check_getnameinfo (const char *address, const char *expected)
++{
++ struct sockaddr_in sin = { };
++ struct sockaddr_in6 sin6 = { };
++ void *sa;
++ socklen_t salen;
++ if (strchr (address, ':') != NULL)
++ {
++ sin6.sin6_family = AF_INET6;
++ TEST_COMPARE (inet_pton (AF_INET6, address, &sin6.sin6_addr), 1);
++ sin6.sin6_port = htons (80);
++ sa = &sin6;
++ salen = sizeof (sin6);
++ }
++ else
++ {
++ sin.sin_family = AF_INET;
++ TEST_COMPARE (inet_pton (AF_INET, address, &sin.sin_addr), 1);
++ sin.sin_port = htons (80);
++ sa = &sin;
++ salen = sizeof (sin);
++ }
++
++ char host[64];
++ char service[64];
++ int ret = getnameinfo (sa, salen, host,
++ sizeof (host), service, sizeof (service),
++ NI_NAMEREQD | NI_NUMERICSERV);
++ switch (ret)
++ {
++ case 0:
++ TEST_COMPARE_STRING (host, expected);
++ TEST_COMPARE_STRING (service, "80");
++ break;
++ case EAI_SYSTEM:
++ TEST_COMPARE_STRING (strerror (errno), expected);
++ break;
++ default:
++ TEST_COMPARE_STRING (gai_strerror (ret), expected);
++ }
++}
++
++static int
++do_test (void)
++{
++ /* Some reasonably upper bound for the maximum response size. */
++ ntf = support_next_to_fault_allocate (4096);
++
++ struct resolv_test *obj = resolv_test_start
++ ((struct resolv_redirect_config)
++ {
++ .response_callback = response
++ });
++
++ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig)
++ {
++ insert_sig = do_insert_sig;
++
++ /* No PTR record, RCODE=0. */
++ check_gethostbyaddr ("192.0.2.0", "error: NO_RECOVERY\n");
++ check_getnameinfo ("192.0.2.0", "Name or service not known");
++ check_gethostbyaddr ("192.0.2.16", "error: NO_RECOVERY\n");
++ check_getnameinfo ("192.0.2.16", "Name or service not known");
++ check_gethostbyaddr ("192.0.2.32", "error: NO_RECOVERY\n");
++ check_getnameinfo ("192.0.2.32", "Name or service not known");
++ check_gethostbyaddr ("2001:db8::", "error: NO_RECOVERY\n");
++ check_getnameinfo ("2001:db8::", "Name or service not known");
++ check_gethostbyaddr ("2001:db8::10", "error: NO_RECOVERY\n");
++ check_getnameinfo ("2001:db8::10", "Name or service not known");
++ check_gethostbyaddr ("2001:db8::20", "error: NO_RECOVERY\n");
++ check_getnameinfo ("2001:db8::20", "Name or service not known");
++
++ /* No PTR record, NXDOMAIN. */
++ check_gethostbyaddr ("192.0.2.15", "error: HOST_NOT_FOUND\n");
++ check_getnameinfo ("192.0.2.15", "Name or service not known");
++ check_gethostbyaddr ("192.0.2.31", "error: HOST_NOT_FOUND\n");
++ check_getnameinfo ("192.0.2.31", "Name or service not known");
++ check_gethostbyaddr ("192.0.2.47", "error: HOST_NOT_FOUND\n");
++ check_getnameinfo ("192.0.2.47", "Name or service not known");
++ check_gethostbyaddr ("2001:db8::f", "error: HOST_NOT_FOUND\n");
++ check_getnameinfo ("2001:db8::f", "Name or service not known");
++ check_gethostbyaddr ("2001:db8::1f", "error: HOST_NOT_FOUND\n");
++ check_getnameinfo ("2001:db8::1f", "Name or service not known");
++ check_gethostbyaddr ("2001:db8::2f", "error: HOST_NOT_FOUND\n");
++ check_getnameinfo ("2001:db8::2f", "Name or service not known");
++
++ /* Actual response data. Only the first PTR record is returned. */
++ check_gethostbyaddr ("192.0.2.1",
++ "name: unique-0.cnames-0.addresses-1.example\n"
++ "address: 192.0.2.1\n");
++ check_getnameinfo ("192.0.2.1",
++ "unique-0.cnames-0.addresses-1.example");
++ check_gethostbyaddr ("192.0.2.17",
++ "name: unique-0.cnames-1.addresses-1.example\n"
++ "address: 192.0.2.17\n");
++ check_getnameinfo ("192.0.2.17",
++ "unique-0.cnames-1.addresses-1.example");
++ check_gethostbyaddr ("192.0.2.18",
++ "name: unique-0.cnames-1.addresses-2.example\n"
++ "address: 192.0.2.18\n");
++ check_getnameinfo ("192.0.2.18",
++ "unique-0.cnames-1.addresses-2.example");
++ check_gethostbyaddr ("192.0.2.33",
++ "name: unique-0.cnames-2.addresses-1.example\n"
++ "address: 192.0.2.33\n");
++ check_getnameinfo ("192.0.2.33",
++ "unique-0.cnames-2.addresses-1.example");
++ check_gethostbyaddr ("192.0.2.34",
++ "name: unique-0.cnames-2.addresses-2.example\n"
++ "address: 192.0.2.34\n");
++ check_getnameinfo ("192.0.2.34",
++ "unique-0.cnames-2.addresses-2.example");
++
++ /* Same for IPv6 addresses. */
++ check_gethostbyaddr ("2001:db8::1",
++ "name: unique-0.cnames-0.addresses-1.example\n"
++ "address: 2001:db8::1\n");
++ check_getnameinfo ("2001:db8::1",
++ "unique-0.cnames-0.addresses-1.example");
++ check_gethostbyaddr ("2001:db8::11",
++ "name: unique-0.cnames-1.addresses-1.example\n"
++ "address: 2001:db8::11\n");
++ check_getnameinfo ("2001:db8::11",
++ "unique-0.cnames-1.addresses-1.example");
++ check_gethostbyaddr ("2001:db8::12",
++ "name: unique-0.cnames-1.addresses-2.example\n"
++ "address: 2001:db8::12\n");
++ check_getnameinfo ("2001:db8::12",
++ "unique-0.cnames-1.addresses-2.example");
++ check_gethostbyaddr ("2001:db8::21",
++ "name: unique-0.cnames-2.addresses-1.example\n"
++ "address: 2001:db8::21\n");
++ check_getnameinfo ("2001:db8::21",
++ "unique-0.cnames-2.addresses-1.example");
++ check_gethostbyaddr ("2001:db8::22",
++ "name: unique-0.cnames-2.addresses-2.example\n"
++ "address: 2001:db8::22\n");
++ check_getnameinfo ("2001:db8::22",
++ "unique-0.cnames-2.addresses-2.example");
++ }
++
++ resolv_test_end (obj);
++
++ support_next_to_fault_free (&ntf);
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/resolv/tst-resolv-invalid-cname.c b/resolv/tst-resolv-invalid-cname.c
+new file mode 100644
+index 0000000000..63dac90e02
+--- /dev/null
++++ b/resolv/tst-resolv-invalid-cname.c
+@@ -0,0 +1,406 @@
++/* Test handling of CNAMEs with non-host domain names (bug 12154).
++ Copyright (C) 2022 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 <stdlib.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/check_nss.h>
++#include <support/resolv_test.h>
++#include <support/support.h>
++#include <support/xmemstream.h>
++
++/* Query strings describe the CNAME chain in the response. They have
++ the format "bitsBITS.countCOUNT.example.", where BITS and COUNT are
++ replaced by unsigned decimal numbers. COUNT is the number of CNAME
++ records in the response. BITS has two bits for each CNAME record,
++ describing a special prefix that is added to that CNAME.
++
++ 0: No special leading label.
++ 1: Starting with "*.".
++ 2: Starting with "-x.".
++ 3: Starting with "star.*.".
++
++ The first CNAME in the response using the two least significant
++ bits.
++
++ For PTR queries, the QNAME format is different, it is either
++ COUNT.BITS.168.192.in-addr.arpa. (with BITS and COUNT still
++ decimal), or:
++
++COUNT.BITS0.BITS1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
++
++ where BITS and COUNT are hexadecimal. */
++
++static void
++response (const struct resolv_response_context *ctx,
++ struct resolv_response_builder *b,
++ const char *qname, uint16_t qclass, uint16_t qtype)
++{
++ TEST_COMPARE (qclass, C_IN);
++
++ /* The only other query type besides A is PTR. */
++ if (qtype != T_A && qtype != T_AAAA)
++ TEST_COMPARE (qtype, T_PTR);
++
++ unsigned int bits, bits1, count;
++ char *tail = NULL;
++ if (sscanf (qname, "bits%u.count%u.%ms", &bits, &count, &tail) == 3)
++ TEST_COMPARE_STRING (tail, "example");
++ else if (strstr (qname, "in-addr.arpa") != NULL
++ && sscanf (qname, "%u.%u.%ms", &bits, &count, &tail) == 3)
++ TEST_COMPARE_STRING (tail, "168.192.in-addr.arpa");
++ else if (sscanf (qname, "%x.%x.%x.%ms", &bits, &bits1, &count, &tail) == 4)
++ {
++ TEST_COMPARE_STRING (tail, "\
++0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
++ bits |= bits1 << 4;
++ }
++ else
++ FAIL_EXIT1 ("invalid QNAME: %s\n", qname);
++ free (tail);
++
++ 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);
++
++ /* Provide the requested number of CNAME records. */
++ char *previous_name = (char *) qname;
++ unsigned int original_bits = bits;
++ for (int unique = 0; unique < count; ++unique)
++ {
++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
++
++ static const char bits_to_prefix[4][8] = { "", "*.", "-x.", "star.*." };
++ char *new_name = xasprintf ("%sunique%d.example",
++ bits_to_prefix[bits & 3], unique);
++ bits >>= 2;
++ resolv_response_add_name (b, new_name);
++ resolv_response_close_record (b);
++
++ if (previous_name != qname)
++ free (previous_name);
++ previous_name = new_name;
++ }
++
++ /* Actual answer record. */
++ resolv_response_open_record (b, previous_name, qclass, qtype, 60);
++ switch (qtype)
++ {
++ case T_A:
++ {
++ char ipv4[4] = {192, 168, count, original_bits};
++ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
++ }
++ break;
++ case T_AAAA:
++ {
++ char ipv6[16] =
++ {
++ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ count, original_bits
++ };
++ resolv_response_add_data (b, &ipv6, sizeof (ipv6));
++ }
++ break;
++
++ case T_PTR:
++ {
++ char *name = xasprintf ("bits%u.count%u.example",
++ original_bits, count);
++ resolv_response_add_name (b, name);
++ free (name);
++ }
++ break;
++ }
++ resolv_response_close_record (b);
++
++ if (previous_name != qname)
++ free (previous_name);
++}
++
++/* Controls which name resolution function is invoked. */
++enum test_mode
++ {
++ byname, /* gethostbyname. */
++ byname2, /* gethostbyname2. */
++ gai, /* getaddrinfo without AI_CANONNAME. */
++ gai_canon, /* getaddrinfo with AI_CANONNAME. */
++
++ test_mode_num /* Number of enum values. */
++ };
++
++static const char *
++test_mode_to_string (enum test_mode mode)
++{
++ switch (mode)
++ {
++ case byname:
++ return "byname";
++ case byname2:
++ return "byname2";
++ case gai:
++ return "gai";
++ case gai_canon:
++ return "gai_canon";
++ case test_mode_num:
++ break; /* Report error below. */
++ }
++ FAIL_EXIT1 ("invalid test_mode: %d", mode);
++}
++
++/* Append the name and aliases to OUT. */
++static void
++append_names (FILE *out, const char *qname, int bits, int count,
++ enum test_mode mode)
++{
++ /* Largest valid index which has a corresponding zero in bits
++ (meaning a syntactically valid CNAME). */
++ int last_valid_cname = -1;
++
++ for (int i = 0; i < count; ++i)
++ if ((bits & (3 << (i * 2))) == 0)
++ last_valid_cname = i;
++
++ if (mode != gai)
++ {
++ const char *label;
++ if (mode == gai_canon)
++ label = "canonname";
++ else
++ label = "name";
++ if (last_valid_cname >= 0)
++ fprintf (out, "%s: unique%d.example\n", label, last_valid_cname);
++ else
++ fprintf (out, "%s: %s\n", label, qname);
++ }
++
++ if (mode == byname || mode == byname2)
++ {
++ if (last_valid_cname >= 0)
++ fprintf (out, "alias: %s\n", qname);
++ for (int i = 0; i < count; ++i)
++ {
++ if ((bits & (3 << (i * 2))) == 0 && i != last_valid_cname)
++ fprintf (out, "alias: unique%d.example\n", i);
++ }
++ }
++}
++
++/* Append the address information to OUT. */
++static void
++append_addresses (FILE *out, int af, int bits, int count, enum test_mode mode)
++{
++ int last = count * 256 + bits;
++ if (mode == gai || mode == gai_canon)
++ {
++ if (af == AF_INET || af == AF_UNSPEC)
++ fprintf (out, "address: STREAM/TCP 192.168.%d.%d 80\n", count, bits);
++ if (af == AF_INET6 || af == AF_UNSPEC)
++ {
++ if (last == 0)
++ fprintf (out, "address: STREAM/TCP 2001:db8:: 80\n");
++ else
++ fprintf (out, "address: STREAM/TCP 2001:db8::%x 80\n", last);
++ }
++ }
++ else
++ {
++ TEST_VERIFY (af != AF_UNSPEC);
++ if (af == AF_INET)
++ fprintf (out, "address: 192.168.%d.%d\n", count, bits);
++ if (af == AF_INET6)
++ {
++ if (last == 0)
++ fprintf (out, "address: 2001:db8::\n");
++ else
++ fprintf (out, "address: 2001:db8::%x\n", last);
++ }
++ }
++}
++
++/* Perform one test using a forward lookup. */
++static void
++check_forward (int af, int bits, int count, enum test_mode mode)
++{
++ char *qname = xasprintf ("bits%d.count%d.example", bits, count);
++ char *label = xasprintf ("af=%d bits=%d count=%d mode=%s qname=%s",
++ af, bits, count, test_mode_to_string (mode), qname);
++
++ struct xmemstream expected;
++ xopen_memstream (&expected);
++ if (mode == gai_canon)
++ fprintf (expected.out, "flags: AI_CANONNAME\n");
++ append_names (expected.out, qname, bits, count, mode);
++ append_addresses (expected.out, af, bits, count, mode);
++ xfclose_memstream (&expected);
++
++ if (mode == gai || mode == gai_canon)
++ {
++ struct addrinfo *ai;
++ struct addrinfo hints =
++ {
++ .ai_family = af,
++ .ai_socktype = SOCK_STREAM,
++ };
++ if (mode == gai_canon)
++ hints.ai_flags |= AI_CANONNAME;
++ int ret = getaddrinfo (qname, "80", &hints, &ai);
++ check_addrinfo (label, ai, ret, expected.buffer);
++ if (ret == 0)
++ freeaddrinfo (ai);
++ }
++ else
++ {
++ struct hostent *e;
++ if (mode == gai)
++ {
++ TEST_COMPARE (af, AF_INET);
++ e = gethostbyname (qname);
++ }
++ else
++ {
++ if (af != AF_INET)
++ TEST_COMPARE (af, AF_INET6);
++ e = gethostbyname2 (qname, af);
++ }
++ check_hostent (label, e, expected.buffer);
++ }
++
++ free (expected.buffer);
++ free (label);
++ free (qname);
++}
++
++/* Perform one check using a reverse lookup. */
++
++static void
++check_reverse (int af, int bits, int count)
++{
++ TEST_VERIFY (af == AF_INET || af == AF_INET6);
++
++ char *label = xasprintf ("af=%d bits=%d count=%d", af, bits, count);
++ char *fqdn = xasprintf ("bits%d.count%d.example", bits, count);
++
++ struct xmemstream expected;
++ xopen_memstream (&expected);
++ fprintf (expected.out, "name: %s\n", fqdn);
++ append_addresses (expected.out, af, bits, count, byname);
++ xfclose_memstream (&expected);
++
++ char addr[16] = { 0 };
++ socklen_t addrlen;
++ if (af == AF_INET)
++ {
++ addr[0] = 192;
++ addr[1] = 168;
++ addr[2] = count;
++ addr[3] = bits;
++ addrlen = 4;
++ }
++ else
++ {
++ addr[0] = 0x20;
++ addr[1] = 0x01;
++ addr[2] = 0x0d;
++ addr[3] = 0xb8;
++ addr[14] = count;
++ addr[15] = bits;
++ addrlen = 16;
++ }
++
++ struct hostent *e = gethostbyaddr (addr, addrlen, af);
++ check_hostent (label, e, expected.buffer);
++
++ /* getnameinfo check is different. There is no generic check_*
++ function for it. */
++ {
++ struct sockaddr_in sin = { };
++ struct sockaddr_in6 sin6 = { };
++ void *sa;
++ socklen_t salen;
++ if (af == AF_INET)
++ {
++ sin.sin_family = AF_INET;
++ memcpy (&sin.sin_addr, addr, addrlen);
++ sin.sin_port = htons (80);
++ sa = &sin;
++ salen = sizeof (sin);
++ }
++ else
++ {
++ sin6.sin6_family = AF_INET6;
++ memcpy (&sin6.sin6_addr, addr, addrlen);
++ sin6.sin6_port = htons (80);
++ sa = &sin6;
++ salen = sizeof (sin6);
++ }
++
++ char host[64];
++ char service[64];
++ int ret = getnameinfo (sa, salen, host,
++ sizeof (host), service, sizeof (service),
++ NI_NAMEREQD | NI_NUMERICSERV);
++ TEST_COMPARE (ret, 0);
++ TEST_COMPARE_STRING (host, fqdn);
++ TEST_COMPARE_STRING (service, "80");
++ }
++
++ free (expected.buffer);
++ free (fqdn);
++ free (label);
++}
++
++static int
++do_test (void)
++{
++ struct resolv_test *obj = resolv_test_start
++ ((struct resolv_redirect_config)
++ {
++ .response_callback = response
++ });
++
++ for (int count = 0; count <= 3; ++count)
++ for (int bits = 0; bits <= 1 << (count * 2); ++bits)
++ {
++ if (count > 0 && bits == count)
++ /* The last bits value is only checked if count == 0. */
++ continue;
++
++ for (enum test_mode mode = 0; mode < test_mode_num; ++mode)
++ {
++ check_forward (AF_INET, bits, count, mode);
++ if (mode != byname)
++ check_forward (AF_INET6, bits, count, mode);
++ if (mode == gai || mode == gai_canon)
++ check_forward (AF_UNSPEC, bits, count, mode);
++ }
++
++ check_reverse (AF_INET, bits, count);
++ check_reverse (AF_INET6, bits, count);
++ }
++
++ resolv_test_end (obj);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/resolv/tst-resolv-maybe_insert_sig.h b/resolv/tst-resolv-maybe_insert_sig.h
+new file mode 100644
+index 0000000000..05725225af
+--- /dev/null
++++ b/resolv/tst-resolv-maybe_insert_sig.h
+@@ -0,0 +1,32 @@
++/* Code snippet for optionally inserting ignored SIG records in resolver tests.
++ Copyright (C) 2022 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/>. */
++
++/* Set to true for an alternative pass that inserts (ignored) SIG
++ records. This does not alter the response, so this property is not
++ encoded in the QNAME. The variable needs to be volatile because
++ leaf attributes tell GCC that the response function is not
++ called. */
++static volatile bool insert_sig;
++
++static void
++maybe_insert_sig (struct resolv_response_builder *b, const char *owner)
++{
++ resolv_response_open_record (b, owner, C_IN, T_SIG, 60);
++ resolv_response_add_data (b, "", 1);
++ resolv_response_close_record (b);
++}
+diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
+index 2dd6bfda18..b87cf2f809 100644
+--- a/scripts/dso-ordering-test.py
++++ b/scripts/dso-ordering-test.py
+@@ -707,13 +707,12 @@ def process_testcase(t):
+ "\t$(compile.c) $(OUTPUT_OPTION)\n")
+ makefile.write (rule)
+
+- not_depended_objs = find_objs_not_depended_on(test_descr)
+- if not_depended_objs:
+- depstr = ""
+- for dep in not_depended_objs:
+- depstr += (" $(objpfx)" + test_subdir + "/"
+- + test_name + "-" + dep + ".so")
+- makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr))
++ # Ensure that all shared objects are built before running the
++ # test, whether there link-time dependencies or not.
++ depobjs = ["$(objpfx){}/{}-{}.so".format(test_subdir, test_name, dep)
++ for dep in test_descr.objs]
++ makefile.write("$(objpfx){}.out: {}\n".format(
++ base_test_name, " ".join(depobjs)))
+
+ # Add main executable to test-srcs
+ makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name))
+diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
+index 43ab58ffe2..36d204c9b0 100644
+--- a/scripts/glibcextract.py
++++ b/scripts/glibcextract.py
+@@ -17,6 +17,7 @@
+ # License along with the GNU C Library; if not, see
+ # <https://www.gnu.org/licenses/>.
+
++import collections
+ import os.path
+ import re
+ import subprocess
+@@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None,
+ if not allow_extra_2:
+ ret = 1
+ return ret
++
++CompileResult = collections.namedtuple("CompileResult", "returncode output")
++
++def compile_c_snippet(snippet, cc, extra_cc_args=''):
++ """Compile and return whether the SNIPPET can be build with CC along
++ EXTRA_CC_ARGS compiler flags. Return a CompileResult with RETURNCODE
++ being 0 for success, or the failure value and the compiler output.
++ """
++ with tempfile.TemporaryDirectory() as temp_dir:
++ c_file_name = os.path.join(temp_dir, 'test.c')
++ obj_file_name = os.path.join(temp_dir, 'test.o')
++ with open(c_file_name, 'w') as c_file:
++ c_file.write(snippet + '\n')
++ cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name,
++ c_file_name]
++ r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE,
++ stderr=subprocess.STDOUT)
++ return CompileResult(r.returncode, r.stdout)
+diff --git a/socket/Makefile b/socket/Makefile
+index 156eec6c85..2bde78387f 100644
+--- a/socket/Makefile
++++ b/socket/Makefile
+@@ -34,6 +34,7 @@ routines := accept bind connect getpeername getsockname getsockopt \
+ tests := \
+ tst-accept4 \
+ tst-sockopt \
++ tst-cmsghdr \
+ # tests
+
+ tests-internal := \
+diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c
+new file mode 100644
+index 0000000000..4c6898569b
+--- /dev/null
++++ b/socket/tst-cmsghdr-skeleton.c
+@@ -0,0 +1,92 @@
++/* Test ancillary data header creation.
++ Copyright (C) 2022 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/>. */
++
++/* We use the preprocessor to generate the function/macro tests instead of
++ using indirection because having all the macro expansions alongside
++ each other lets the compiler warn us about suspicious pointer
++ arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions. */
++
++#include <stdint.h>
++
++#define RUN_TEST_CONCAT(suffix) run_test_##suffix
++#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix)
++
++static void
++RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void)
++{
++ struct msghdr m = {0};
++ struct cmsghdr *cmsg;
++ char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0};
++
++ m.msg_control = cmsgbuf;
++ m.msg_controllen = sizeof (cmsgbuf);
++
++ /* First header should point to the start of the buffer. */
++ cmsg = CMSG_FIRSTHDR (&m);
++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
++
++ /* If the first header length consumes the entire buffer, there is no
++ space remaining for additional headers. */
++ cmsg->cmsg_len = sizeof (cmsgbuf);
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg == NULL);
++
++ /* The first header length is so big, using it would cause an overflow. */
++ cmsg = CMSG_FIRSTHDR (&m);
++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
++ cmsg->cmsg_len = SIZE_MAX;
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg == NULL);
++
++ /* The first header leaves just enough space to hold another header. */
++ cmsg = CMSG_FIRSTHDR (&m);
++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
++ cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr);
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg != NULL);
++
++ /* The first header leaves space but not enough for another header. */
++ cmsg = CMSG_FIRSTHDR (&m);
++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
++ cmsg->cmsg_len ++;
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg == NULL);
++
++ /* The second header leaves just enough space to hold another header. */
++ cmsg = CMSG_FIRSTHDR (&m);
++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
++ cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD));
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg != NULL);
++ cmsg->cmsg_len = sizeof (cmsgbuf)
++ - CMSG_SPACE (sizeof (PAYLOAD)) /* First header. */
++ - sizeof (struct cmsghdr);
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg != NULL);
++
++ /* The second header leaves space but not enough for another header. */
++ cmsg = CMSG_FIRSTHDR (&m);
++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg != NULL);
++ cmsg->cmsg_len ++;
++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
++ TEST_VERIFY_EXIT (cmsg == NULL);
++
++ return;
++}
+diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c
+new file mode 100644
+index 0000000000..68c96d3c9d
+--- /dev/null
++++ b/socket/tst-cmsghdr.c
+@@ -0,0 +1,56 @@
++/* Test ancillary data header creation.
++ Copyright (C) 2022 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 <sys/socket.h>
++#include <gnu/lib-names.h>
++#include <support/xdlfcn.h>
++#include <support/check.h>
++
++#define PAYLOAD "Hello, World!"
++
++/* CMSG_NXTHDR is a macro that calls an inline function defined in
++ bits/socket.h. In case the function cannot be inlined, libc.so carries
++ a copy. Both versions need to be tested. */
++
++#define CMSG_NXTHDR_IMPL CMSG_NXTHDR
++#include "tst-cmsghdr-skeleton.c"
++#undef CMSG_NXTHDR_IMPL
++
++static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *);
++
++#define CMSG_NXTHDR_IMPL cmsg_nxthdr
++#include "tst-cmsghdr-skeleton.c"
++#undef CMSG_NXTHDR_IMPL
++
++static int
++do_test (void)
++{
++ static void *handle;
++
++ run_test_CMSG_NXTHDR ();
++
++ handle = xdlopen (LIBC_SO, RTLD_LAZY);
++ cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *))
++ xdlsym (handle, "__cmsg_nxthdr");
++
++ run_test_cmsg_nxthdr ();
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/stdlib/arc4random.c b/stdlib/arc4random.c
+index e417ef624d..960a38f295 100644
+--- a/stdlib/arc4random.c
++++ b/stdlib/arc4random.c
+@@ -34,7 +34,7 @@ void
+ __arc4random_buf (void *p, size_t n)
+ {
+ static int seen_initialized;
+- size_t l;
++ ssize_t l;
+ int fd;
+
+ if (n == 0)
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 050a3032de..6b256b8388 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -1048,9 +1048,11 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv,
+ initializer functions have completed. */
+ extern void _dl_fini (void) attribute_hidden;
+
+-/* Sort array MAPS according to dependencies of the contained objects. */
++/* Sort array MAPS according to dependencies of the contained objects.
++ If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies
++ say otherwise. */
+ extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
+- unsigned int skip, bool for_fini) attribute_hidden;
++ bool force_first, bool for_fini) attribute_hidden;
+
+ /* The dynamic linker calls this function before and having changing
+ any shared object mappings. The `r_state' member of `struct r_debug'
+diff --git a/sysdeps/generic/libc-lock-arch.h b/sysdeps/generic/libc-lock-arch.h
+new file mode 100644
+index 0000000000..4713b30a8a
+--- /dev/null
++++ b/sysdeps/generic/libc-lock-arch.h
+@@ -0,0 +1,25 @@
++/* Private libc-internal arch-specific definitions. Generic version.
++ Copyright (C) 2022 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; see the file COPYING.LIB. If
++ not, see <https://www.gnu.org/licenses/>. */
++
++#ifndef _LIBC_LOCK_ARCH_H
++#define _LIBC_LOCK_ARCH_H
++
++/* The default definition uses the natural alignment from the lock type. */
++#define __LIBC_LOCK_ALIGNMENT
++
++#endif
+diff --git a/sysdeps/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h
+index 5b35ea81ec..70fce4fb27 100644
+--- a/sysdeps/mach/hurd/bits/socket.h
++++ b/sysdeps/mach/hurd/bits/socket.h
+@@ -249,6 +249,12 @@ struct cmsghdr
+ + CMSG_ALIGN (sizeof (struct cmsghdr)))
+ #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
+
++/* Given a length, return the additional padding necessary such that
++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
++#define __CMSG_PADDING(len) ((sizeof (size_t) \
++ - ((len) & (sizeof (size_t) - 1))) \
++ & (sizeof (size_t) - 1))
++
+ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+ struct cmsghdr *__cmsg) __THROW;
+ #ifdef __USE_EXTERN_INLINES
+@@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+ _EXTERN_INLINE struct cmsghdr *
+ __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
+ {
++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
++ __mhdr->msg_controllen because the user is required to obtain the first
++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
++ trust the value of __cmsg->cmsg_len and therefore do not use it in any
++ pointer arithmetic until we check its value. */
++
++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
++
++ size_t __size_needed = sizeof (struct cmsghdr)
++ + __CMSG_PADDING (__cmsg->cmsg_len);
++
++ /* The current header is malformed, too small to be a full header. */
+ if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
+- /* The kernel header does this so there may be a reason. */
+ return (struct cmsghdr *) 0;
+
++ /* There isn't enough space between __cmsg and the end of the buffer to
++ hold the current cmsg *and* the next one. */
++ if (((size_t)
++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
++ < __size_needed)
++ || ((size_t)
++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
++ - __size_needed)
++ < __cmsg->cmsg_len))
++
++ return (struct cmsghdr *) 0;
++
++ /* Now, we trust cmsg_len and can use it to find the next header. */
+ __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
+ + CMSG_ALIGN (__cmsg->cmsg_len));
+- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
+- + __mhdr->msg_controllen)
+- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
+- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
+- /* No more entries. */
+- return (struct cmsghdr *) 0;
+ return __cmsg;
+ }
+ #endif /* Use `extern inline'. */
+diff --git a/sysdeps/nptl/libc-lock.h b/sysdeps/nptl/libc-lock.h
+index 5af476c48b..63b3f3d75c 100644
+--- a/sysdeps/nptl/libc-lock.h
++++ b/sysdeps/nptl/libc-lock.h
+@@ -22,6 +22,7 @@
+ #include <pthread.h>
+ #define __need_NULL
+ #include <stddef.h>
++#include <libc-lock-arch.h>
+
+
+ /* Mutex type. */
+@@ -29,7 +30,12 @@
+ # if (!IS_IN (libc) && !IS_IN (libpthread)) || !defined _LIBC
+ typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t;
+ # else
+-typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t;
++typedef struct
++{
++ int lock __LIBC_LOCK_ALIGNMENT;
++ int cnt;
++ void *owner;
++} __libc_lock_recursive_t;
+ # endif
+ #else
+ typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t;
+diff --git a/sysdeps/nptl/libc-lockP.h b/sysdeps/nptl/libc-lockP.h
+index d3a6837fd2..425f514c5c 100644
+--- a/sysdeps/nptl/libc-lockP.h
++++ b/sysdeps/nptl/libc-lockP.h
+@@ -32,9 +32,10 @@
+ ld.so might be used on old kernels with a different libc.so. */
+ #include <lowlevellock.h>
+ #include <tls.h>
++#include <libc-lock-arch.h>
+
+ /* Mutex type. */
+-typedef int __libc_lock_t;
++typedef int __libc_lock_t __LIBC_LOCK_ALIGNMENT;
+ typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t;
+ typedef pthread_rwlock_t __libc_rwlock_t;
+
+diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
+index bcff909b2f..5cda9bb072 100644
+--- a/sysdeps/posix/getaddrinfo.c
++++ b/sysdeps/posix/getaddrinfo.c
+@@ -540,11 +540,11 @@ get_nscd_addresses (const char *name, const struct addrinfo *req,
+ at[count].addr[2] = htonl (0xffff);
+ }
+ else if (req->ai_family == AF_UNSPEC
+- || air->family[count] == req->ai_family)
++ || air->family[i] == req->ai_family)
+ {
+- at[count].family = air->family[count];
++ at[count].family = air->family[i];
+ memcpy (at[count].addr, addrs, size);
+- if (air->family[count] == AF_INET6)
++ if (air->family[i] == AF_INET6)
+ res->got_ipv6 = true;
+ }
+ at[count].next = at + count + 1;
+diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
+index a139a16532..3ceda9fdbf 100644
+--- a/sysdeps/unix/sysv/linux/Makefile
++++ b/sysdeps/unix/sysv/linux/Makefile
+@@ -265,6 +265,14 @@ $(objpfx)tst-mount-consts.out: ../sysdeps/unix/sysv/linux/tst-mount-consts.py
+ < /dev/null > $@ 2>&1; $(evaluate-test)
+ $(objpfx)tst-mount-consts.out: $(sysdeps-linux-python-deps)
+
++tests-special += $(objpfx)tst-mount-compile.out
++$(objpfx)tst-mount-compile.out: ../sysdeps/unix/sysv/linux/tst-mount-compile.py
++ $(sysdeps-linux-python) \
++ ../sysdeps/unix/sysv/linux/tst-mount-compile.py \
++ $(sysdeps-linux-python-cc) \
++ < /dev/null > $@ 2>&1; $(evaluate-test)
++$(objpfx)tst-mount-compile.out: $(sysdeps-linux-python-deps)
++
+ tst-rseq-disable-ENV = GLIBC_TUNABLES=glibc.pthread.rseq=0
+
+ endif # $(subdir) == misc
+diff --git a/sysdeps/unix/sysv/linux/alpha/brk_call.h b/sysdeps/unix/sysv/linux/alpha/brk_call.h
+index b8088cf13f..0b851b6c86 100644
+--- a/sysdeps/unix/sysv/linux/alpha/brk_call.h
++++ b/sysdeps/unix/sysv/linux/alpha/brk_call.h
+@@ -21,8 +21,7 @@ __brk_call (void *addr)
+ {
+ unsigned long int result = INTERNAL_SYSCALL_CALL (brk, addr);
+ if (result == -ENOMEM)
+- /* Mimic the default error reporting behavior. */
+- return addr;
+- else
+- return (void *) result;
++ /* Mimic the generic error reporting behavior. */
++ result = INTERNAL_SYSCALL_CALL (brk, 0);
++ return (void *) result;
+ }
+diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h
+index 4f1f810ea1..539b8d7716 100644
+--- a/sysdeps/unix/sysv/linux/bits/socket.h
++++ b/sysdeps/unix/sysv/linux/bits/socket.h
+@@ -307,6 +307,12 @@ struct cmsghdr
+ + CMSG_ALIGN (sizeof (struct cmsghdr)))
+ #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
+
++/* Given a length, return the additional padding necessary such that
++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
++#define __CMSG_PADDING(len) ((sizeof (size_t) \
++ - ((len) & (sizeof (size_t) - 1))) \
++ & (sizeof (size_t) - 1))
++
+ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+ struct cmsghdr *__cmsg) __THROW;
+ #ifdef __USE_EXTERN_INLINES
+@@ -316,18 +322,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+ _EXTERN_INLINE struct cmsghdr *
+ __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
+ {
++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
++ __mhdr->msg_controllen because the user is required to obtain the first
++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
++ trust the value of __cmsg->cmsg_len and therefore do not use it in any
++ pointer arithmetic until we check its value. */
++
++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
++
++ size_t __size_needed = sizeof (struct cmsghdr)
++ + __CMSG_PADDING (__cmsg->cmsg_len);
++
++ /* The current header is malformed, too small to be a full header. */
+ if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
+- /* The kernel header does this so there may be a reason. */
+ return (struct cmsghdr *) 0;
+
++ /* There isn't enough space between __cmsg and the end of the buffer to
++ hold the current cmsg *and* the next one. */
++ if (((size_t)
++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
++ < __size_needed)
++ || ((size_t)
++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
++ - __size_needed)
++ < __cmsg->cmsg_len))
++
++ return (struct cmsghdr *) 0;
++
++ /* Now, we trust cmsg_len and can use it to find the next header. */
+ __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
+ + CMSG_ALIGN (__cmsg->cmsg_len));
+- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
+- + __mhdr->msg_controllen)
+- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
+- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
+- /* No more entries. */
+- return (struct cmsghdr *) 0;
+ return __cmsg;
+ }
+ #endif /* Use `extern inline'. */
+diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
+index 15b7a3a925..24f72b797a 100644
+--- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
++++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
+@@ -23,18 +23,38 @@
+ struct cmsghdr *
+ __cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg)
+ {
++ /* We may safely assume that cmsg lies between mhdr->msg_control and
++ mhdr->msg_controllen because the user is required to obtain the first
++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
++ trust the value of cmsg->cmsg_len and therefore do not use it in any
++ pointer arithmetic until we check its value. */
++
++ unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control;
++ unsigned char * cmsg_ptr = (unsigned char *) cmsg;
++
++ size_t size_needed = sizeof (struct cmsghdr)
++ + __CMSG_PADDING (cmsg->cmsg_len);
++
++ /* The current header is malformed, too small to be a full header. */
+ if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr))
+- /* The kernel header does this so there may be a reason. */
+- return NULL;
++ return (struct cmsghdr *) 0;
++
++ /* There isn't enough space between cmsg and the end of the buffer to
++ hold the current cmsg *and* the next one. */
++ if (((size_t)
++ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr)
++ < size_needed)
++ || ((size_t)
++ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr
++ - size_needed)
++ < cmsg->cmsg_len))
++
++ return (struct cmsghdr *) 0;
+
++ /* Now, we trust cmsg_len and can use it to find the next header. */
+ cmsg = (struct cmsghdr *) ((unsigned char *) cmsg
+ + CMSG_ALIGN (cmsg->cmsg_len));
+- if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control
+- + mhdr->msg_controllen)
+- || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len)
+- > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen)))
+- /* No more entries. */
+- return NULL;
+ return cmsg;
+ }
+ libc_hidden_def (__cmsg_nxthdr)
+diff --git a/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h
+new file mode 100644
+index 0000000000..1844bbaf6f
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h
+@@ -0,0 +1,25 @@
++/* Private libc-internal arch-specific definitions. m68k version.
++ Copyright (C) 2022 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; see the file COPYING.LIB. If
++ not, see <https://www.gnu.org/licenses/>. */
++
++#ifndef _LIBC_LOCK_ARCH_H
++#define _LIBC_LOCK_ARCH_H
++
++/* Linux enforces 4-bytes alignment on futex inputs. */
++#define __LIBC_LOCK_ALIGNMENT __attribute__ ((__aligned__ (4)))
++
++#endif
+diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h
+index a263d294b1..cf35c8bfc9 100644
+--- a/sysdeps/unix/sysv/linux/not-cancel.h
++++ b/sysdeps/unix/sysv/linux/not-cancel.h
+@@ -68,7 +68,7 @@ __writev_nocancel_nostatus (int fd, const struct iovec *iov, int iovcnt)
+ INTERNAL_SYSCALL_CALL (writev, fd, iov, iovcnt);
+ }
+
+-static inline int
++static inline ssize_t
+ __getrandom_nocancel (void *buf, size_t buflen, unsigned int flags)
+ {
+ return INLINE_SYSCALL_CALL (getrandom, buf, buflen, flags);
+diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
+index bf4be80f8d..202520ee25 100644
+--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
+@@ -122,6 +122,7 @@
+ #define __NR_mbind 235
+ #define __NR_membarrier 283
+ #define __NR_memfd_create 279
++#define __NR_memfd_secret 447
+ #define __NR_migrate_pages 238
+ #define __NR_mincore 232
+ #define __NR_mkdirat 34
+diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
+index d656aedcc2..4e65f337d4 100644
+--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
+@@ -127,6 +127,7 @@
+ #define __NR_mbind 235
+ #define __NR_membarrier 283
+ #define __NR_memfd_create 279
++#define __NR_memfd_secret 447
+ #define __NR_migrate_pages 238
+ #define __NR_mincore 232
+ #define __NR_mkdirat 34
+diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h
+index f965986ba8..19841d0738 100644
+--- a/sysdeps/unix/sysv/linux/sys/mount.h
++++ b/sysdeps/unix/sysv/linux/sys/mount.h
+@@ -27,77 +27,113 @@
+ #include <stddef.h>
+ #include <sys/ioctl.h>
+
+-#define BLOCK_SIZE 1024
++#ifdef __has_include
++# if __has_include ("linux/mount.h")
++# include "linux/mount.h"
++# endif
++#endif
++
++
+ #define BLOCK_SIZE_BITS 10
++#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
+
+
+ /* These are the fs-independent mount-flags: up to 16 flags are
+ supported */
+ enum
+ {
++#undef MS_RDONLY
+ MS_RDONLY = 1, /* Mount read-only. */
+ #define MS_RDONLY MS_RDONLY
++#undef MS_NOSUID
+ MS_NOSUID = 2, /* Ignore suid and sgid bits. */
+ #define MS_NOSUID MS_NOSUID
++#undef MS_NODEV
+ MS_NODEV = 4, /* Disallow access to device special files. */
+ #define MS_NODEV MS_NODEV
++#undef MS_NOEXEC
+ MS_NOEXEC = 8, /* Disallow program execution. */
+ #define MS_NOEXEC MS_NOEXEC
++#undef MS_SYNCHRONOUS
+ MS_SYNCHRONOUS = 16, /* Writes are synced at once. */
+ #define MS_SYNCHRONOUS MS_SYNCHRONOUS
++#undef MS_REMOUNT
+ MS_REMOUNT = 32, /* Alter flags of a mounted FS. */
+ #define MS_REMOUNT MS_REMOUNT
++#undef MS_MANDLOCK
+ MS_MANDLOCK = 64, /* Allow mandatory locks on an FS. */
+ #define MS_MANDLOCK MS_MANDLOCK
++#undef MS_DIRSYNC
+ MS_DIRSYNC = 128, /* Directory modifications are synchronous. */
+ #define MS_DIRSYNC MS_DIRSYNC
++#undef MS_NOSYMFOLLOW
+ MS_NOSYMFOLLOW = 256, /* Do not follow symlinks. */
+ #define MS_NOSYMFOLLOW MS_NOSYMFOLLOW
++#undef MS_NOATIME
+ MS_NOATIME = 1024, /* Do not update access times. */
+ #define MS_NOATIME MS_NOATIME
++#undef MS_NODIRATIME
+ MS_NODIRATIME = 2048, /* Do not update directory access times. */
+ #define MS_NODIRATIME MS_NODIRATIME
++#undef MS_BIND
+ MS_BIND = 4096, /* Bind directory at different place. */
+ #define MS_BIND MS_BIND
++#undef MS_MOVE
+ MS_MOVE = 8192,
+ #define MS_MOVE MS_MOVE
++#undef MS_REC
+ MS_REC = 16384,
+ #define MS_REC MS_REC
++#undef MS_SILENT
+ MS_SILENT = 32768,
+ #define MS_SILENT MS_SILENT
++#undef MS_POSIXACL
+ MS_POSIXACL = 1 << 16, /* VFS does not apply the umask. */
+ #define MS_POSIXACL MS_POSIXACL
++#undef MS_UNBINDABLE
+ MS_UNBINDABLE = 1 << 17, /* Change to unbindable. */
+ #define MS_UNBINDABLE MS_UNBINDABLE
++#undef MS_PRIVATE
+ MS_PRIVATE = 1 << 18, /* Change to private. */
+ #define MS_PRIVATE MS_PRIVATE
++#undef MS_SLAVE
+ MS_SLAVE = 1 << 19, /* Change to slave. */
+ #define MS_SLAVE MS_SLAVE
++#undef MS_SHARED
+ MS_SHARED = 1 << 20, /* Change to shared. */
+ #define MS_SHARED MS_SHARED
++#undef MS_RELATIME
+ MS_RELATIME = 1 << 21, /* Update atime relative to mtime/ctime. */
+ #define MS_RELATIME MS_RELATIME
++#undef MS_KERNMOUNT
+ MS_KERNMOUNT = 1 << 22, /* This is a kern_mount call. */
+ #define MS_KERNMOUNT MS_KERNMOUNT
++#undef MS_I_VERSION
+ MS_I_VERSION = 1 << 23, /* Update inode I_version field. */
+ #define MS_I_VERSION MS_I_VERSION
++#undef MS_STRICTATIME
+ MS_STRICTATIME = 1 << 24, /* Always perform atime updates. */
+ #define MS_STRICTATIME MS_STRICTATIME
++#undef MS_LAZYTIME
+ MS_LAZYTIME = 1 << 25, /* Update the on-disk [acm]times lazily. */
+ #define MS_LAZYTIME MS_LAZYTIME
++#undef MS_ACTIVE
+ MS_ACTIVE = 1 << 30,
+ #define MS_ACTIVE MS_ACTIVE
++#undef MS_NOUSER
+ MS_NOUSER = 1 << 31
+ #define MS_NOUSER MS_NOUSER
+ };
+
+ /* Flags that can be altered by MS_REMOUNT */
++#undef MS_RMT_MASK
+ #define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION \
+ |MS_LAZYTIME)
+
+
+ /* Magic mount flag number. Has to be or-ed to the flag values. */
+
++#undef MS_MGC_VAL
+ #define MS_MGC_VAL 0xc0ed0000 /* Magic flag number to indicate "new" flags */
+ #define MS_MGC_MSK 0xffff0000 /* Magic flag number mask */
+
+@@ -106,20 +142,35 @@ enum
+ is probably as bad and I don't want to create yet another include
+ file. */
+
++#undef BLKROSET
+ #define BLKROSET _IO(0x12, 93) /* Set device read-only (0 = read-write). */
++#undef BLKROGET
+ #define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */
++#undef BLKRRPART
+ #define BLKRRPART _IO(0x12, 95) /* Re-read partition table. */
++#undef BLKGETSIZE
+ #define BLKGETSIZE _IO(0x12, 96) /* Return device size. */
++#undef BLKFLSBUF
+ #define BLKFLSBUF _IO(0x12, 97) /* Flush buffer cache. */
++#undef BLKRASET
+ #define BLKRASET _IO(0x12, 98) /* Set read ahead for block device. */
++#undef BLKRAGET
+ #define BLKRAGET _IO(0x12, 99) /* Get current read ahead setting. */
++#undef BLKFRASET
+ #define BLKFRASET _IO(0x12,100) /* Set filesystem read-ahead. */
++#undef BLKFRAGET
+ #define BLKFRAGET _IO(0x12,101) /* Get filesystem read-ahead. */
++#undef BLKSECTSET
+ #define BLKSECTSET _IO(0x12,102) /* Set max sectors per request. */
++#undef BLKSECTGET
+ #define BLKSECTGET _IO(0x12,103) /* Get max sectors per request. */
++#undef BLKSSZGET
+ #define BLKSSZGET _IO(0x12,104) /* Get block device sector size. */
++#undef BLKBSZGET
+ #define BLKBSZGET _IOR(0x12,112,size_t)
++#undef BLKBSZSET
+ #define BLKBSZSET _IOW(0x12,113,size_t)
++#undef BLKGETSIZE64
+ #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size. */
+
+
+@@ -137,9 +188,6 @@ enum
+ };
+
+
+-/* fsopen flags. */
+-#define FSOPEN_CLOEXEC 0x00000001
+-
+ /* fsmount flags. */
+ #define FSMOUNT_CLOEXEC 0x00000001
+
+@@ -157,6 +205,7 @@ enum
+ #define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 /* Do not follow symlinks. */
+
+
++#ifndef MOUNT_ATTR_SIZE_VER0
+ /* For mount_setattr. */
+ struct mount_attr
+ {
+@@ -165,6 +214,7 @@ struct mount_attr
+ uint64_t propagation;
+ uint64_t userns_fd;
+ };
++#endif
+
+ #define MOUNT_ATTR_SIZE_VER0 32 /* sizeof first published struct */
+
+@@ -185,26 +235,31 @@ struct mount_attr
+ #define FSPICK_EMPTY_PATH 0x00000008
+
+
++#ifndef FSOPEN_CLOEXEC
+ /* The type of fsconfig call made. */
+ enum fsconfig_command
+ {
+ FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */
+-#define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
++# define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
+ FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */
+-#define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
++# define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
+ FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */
+-#define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
++# define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
+ FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */
+-#define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
++# define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
+ FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */
+-#define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
++# define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
+ FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */
+-#define FSCONFIG_SET_FD FSCONFIG_SET_FD
++# define FSCONFIG_SET_FD FSCONFIG_SET_FD
+ FSCONFIG_CMD_CREATE = 6, /* Invoke superblock creation */
+-#define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
++# define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
+ FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */
+-#define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
++# define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
+ };
++#endif
++
++/* fsopen flags. */
++#define FSOPEN_CLOEXEC 0x00000001
+
+ /* open_tree flags. */
+ #define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
+diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
+index 6c7b2f7011..028ad3107a 100644
+--- a/sysdeps/unix/sysv/linux/syscall-names.list
++++ b/sysdeps/unix/sysv/linux/syscall-names.list
+@@ -21,8 +21,8 @@
+ # This file can list all potential system calls. The names are only
+ # used if the installed kernel headers also provide them.
+
+-# The list of system calls is current as of Linux 5.18.
+-kernel 5.18
++# The list of system calls is current as of Linux 5.19.
++kernel 5.19
+
+ FAST_atomic_update
+ FAST_cmpxchg
+diff --git a/sysdeps/unix/sysv/linux/tst-mount-compile.py b/sysdeps/unix/sysv/linux/tst-mount-compile.py
+new file mode 100755
+index 0000000000..0ec74d4e0b
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/tst-mount-compile.py
+@@ -0,0 +1,66 @@
++#!/usr/bin/python3
++# Check if glibc provided sys/mount.h can be used along related kernel
++# headers.
++# Copyright (C) 2022 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/>.
++
++import argparse
++import sys
++
++import glibcextract
++
++
++def main():
++ """The main entry point."""
++ parser = argparse.ArgumentParser(
++ description='Check if glibc provided sys/mount.h can be '
++ ' used along related kernel headers.')
++ parser.add_argument('--cc', metavar='CC',
++ help='C compiler (including options) to use')
++ args = parser.parse_args()
++
++ if glibcextract.compile_c_snippet(
++ '#include <linux/mount.h>',
++ args.cc).returncode != 0:
++ sys.exit (77)
++
++ def check(testname, snippet):
++ # Add -Werror to catch macro redefinitions and _ISOMAC to avoid
++ # internal glibc definitions.
++ r = glibcextract.compile_c_snippet(snippet, args.cc,
++ '-Werror -D_ISOMAC')
++ if r.returncode != 0:
++ print('error: test {}:\n{}'.format(testname, r.output.decode()))
++ return r.returncode
++
++ status = max(
++ check("sys/mount.h + linux/mount.h",
++ "#include <sys/mount.h>\n"
++ "#include <linux/mount.h>"),
++ check("sys/mount.h + linux/fs.h",
++ "#include <sys/mount.h>\n"
++ "#include <linux/fs.h>"),
++ check("linux/mount.h + sys/mount.h",
++ "#include <linux/mount.h>\n"
++ "#include <sys/mount.h>"),
++ check("linux/fs.h + sys/mount.h",
++ "#include <linux/fs.h>\n"
++ "#include <sys/mount.h>"))
++ sys.exit(status)
++
++if __name__ == '__main__':
++ main()
+diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py
+index a62f803123..be2ef2daf1 100755
+--- a/sysdeps/unix/sysv/linux/tst-mount-consts.py
++++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py
+@@ -33,6 +33,11 @@ def main():
+ help='C compiler (including options) to use')
+ args = parser.parse_args()
+
++ if glibcextract.compile_c_snippet(
++ '#include <linux/mount.h>',
++ args.cc).returncode != 0:
++ sys.exit (77)
++
+ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+ # Constants in glibc were updated to match Linux v5.16. When glibc
+ # constants are updated this value should be updated to match the
+diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
+index 90cbb9be64..d732173abd 100644
+--- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
++++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
+@@ -33,11 +33,13 @@ def main():
+ help='C compiler (including options) to use')
+ args = parser.parse_args()
+
+- linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+- # Linux started to provide pidfd.h with 5.10.
+- if linux_version_headers < (5, 10):
++ if glibcextract.compile_c_snippet(
++ '#include <linux/pidfd.h>',
++ args.cc).returncode != 0:
+ sys.exit (77)
+- linux_version_glibc = (5, 18)
++
++ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
++ linux_version_glibc = (5, 19)
+ sys.exit(glibcextract.compare_macro_consts(
+ '#include <sys/pidfd.h>\n',
+ '#include <asm/fcntl.h>\n'
+diff --git a/sysdeps/unix/sysv/linux/tst-pidfd.c b/sysdeps/unix/sysv/linux/tst-pidfd.c
+index 037af22290..5711d1c312 100644
+--- a/sysdeps/unix/sysv/linux/tst-pidfd.c
++++ b/sysdeps/unix/sysv/linux/tst-pidfd.c
+@@ -147,8 +147,11 @@ do_test (void)
+ may be denied if the process doesn't have CAP_SYS_PTRACE or
+ if a LSM security_ptrace_access_check denies access. */
+ if (fd == -1 && errno == EPERM)
+- FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
+- "skipping test");
++ {
++ TEST_COMPARE (pidfd_send_signal (pidfd, SIGKILL, NULL, 0), 0);
++ FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
++ "skipping test");
++ }
+ TEST_VERIFY (fd > 0);
+
+ char *path = xasprintf ("/proc/%d/fd/%d", pid, remote_fd);
+diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
+index e6b9e8743a..4af102a3f6 100644
+--- a/wcsmbs/Makefile
++++ b/wcsmbs/Makefile
+@@ -22,8 +22,9 @@ subdir := wcsmbs
+
+ include ../Makeconfig
+
+-headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h \
+- bits/types/__mbstate_t.h bits/types/mbstate_t.h bits/types/wint_t.h
++headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar2-decl.h \
++ bits/wchar-ldbl.h uchar.h bits/types/__mbstate_t.h \
++ bits/types/mbstate_t.h bits/types/wint_t.h
+
+ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
+ wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \
+@@ -73,6 +74,8 @@ $(objpfx)tst-wcstol-locale.out: $(gen-locales)
+ $(objpfx)tst-wcstod-nan-locale.out: $(gen-locales)
+ $(objpfx)tst-c16-surrogate.out: $(gen-locales)
+ $(objpfx)tst-c32-state.out: $(gen-locales)
++$(objpfx)test-c8rtomb.out: $(gen-locales)
++$(objpfx)test-mbrtoc8.out: $(gen-locales)
+ endif
+
+ $(objpfx)tst-wcstod-round: $(libm)
+diff --git a/wcsmbs/bits/wchar2-decl.h b/wcsmbs/bits/wchar2-decl.h
+new file mode 100644
+index 0000000000..8e1735c33b
+--- /dev/null
++++ b/wcsmbs/bits/wchar2-decl.h
+@@ -0,0 +1,124 @@
++/* Checking macros for wchar functions. Declarations only.
++ Copyright (C) 2004-2022 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/>. */
++
++#ifndef _BITS_WCHAR2_DECL_H
++#define _BITS_WCHAR2_DECL_H 1
++
++#ifndef _WCHAR_H
++# error "Never include <bits/wchar2-decl.h> directly; use <wchar.h> instead."
++#endif
++
++
++extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1,
++ const wchar_t *__restrict __s2, size_t __n,
++ size_t __ns1) __THROW;
++extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2,
++ size_t __n, size_t __ns1) __THROW;
++
++
++#ifdef __USE_GNU
++
++extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1,
++ const wchar_t *__restrict __s2, size_t __n,
++ size_t __ns1) __THROW;
++
++#endif
++
++
++extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n,
++ size_t __ns) __THROW;
++extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest,
++ const wchar_t *__restrict __src,
++ size_t __n) __THROW;
++extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest,
++ const wchar_t *__restrict __src,
++ size_t __destlen) __THROW;
++extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest,
++ const wchar_t *__restrict __src, size_t __n,
++ size_t __destlen) __THROW;
++extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest,
++ const wchar_t *__restrict __src, size_t __n,
++ size_t __destlen) __THROW;
++extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest,
++ const wchar_t *__restrict __src,
++ size_t __destlen) __THROW;
++extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest,
++ const wchar_t *__restrict __src,
++ size_t __n, size_t __destlen) __THROW;
++extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n,
++ int __flag, size_t __s_len,
++ const wchar_t *__restrict __format, ...)
++ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */;
++extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
++ int __flag, size_t __s_len,
++ const wchar_t *__restrict __format,
++ __gnuc_va_list __arg)
++ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
++
++#if __USE_FORTIFY_LEVEL > 1
++
++extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag,
++ const wchar_t *__restrict __format, ...);
++extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format,
++ ...);
++extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag,
++ const wchar_t *__restrict __format,
++ __gnuc_va_list __ap);
++extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format,
++ __gnuc_va_list __ap);
++
++#endif
++
++extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n,
++ __FILE *__restrict __stream) __wur;
++
++#ifdef __USE_GNU
++
++extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size,
++ int __n, __FILE *__restrict __stream)
++ __wur;
++
++#endif
++
++extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar,
++ mbstate_t *__restrict __p,
++ size_t __buflen) __THROW __wur;
++extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst,
++ const char **__restrict __src,
++ size_t __len, mbstate_t *__restrict __ps,
++ size_t __dstlen) __THROW;
++extern size_t __wcsrtombs_chk (char *__restrict __dst,
++ const wchar_t **__restrict __src,
++ size_t __len, mbstate_t *__restrict __ps,
++ size_t __dstlen) __THROW;
++
++#ifdef __USE_XOPEN2K8
++
++extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst,
++ const char **__restrict __src, size_t __nmc,
++ size_t __len, mbstate_t *__restrict __ps,
++ size_t __dstlen) __THROW;
++extern size_t __wcsnrtombs_chk (char *__restrict __dst,
++ const wchar_t **__restrict __src,
++ size_t __nwc, size_t __len,
++ mbstate_t *__restrict __ps, size_t __dstlen)
++ __THROW;
++
++#endif
++
++#endif /* bits/wchar2-decl.h. */
+diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
+index 0e017f458b..3f110efe57 100644
+--- a/wcsmbs/bits/wchar2.h
++++ b/wcsmbs/bits/wchar2.h
+@@ -21,9 +21,6 @@
+ #endif
+
+
+-extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1,
+- const wchar_t *__restrict __s2, size_t __n,
+- size_t __ns1) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wmemcpy_alias,
+ (wchar_t *__restrict __s1,
+ const wchar_t *__restrict __s2, size_t __n),
+@@ -45,8 +42,6 @@ __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
+ }
+
+
+-extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2,
+- size_t __n, size_t __ns1) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wmemmove_alias, (wchar_t *__s1,
+ const wchar_t *__s2,
+ size_t __n), wmemmove);
+@@ -66,9 +61,6 @@ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
+
+
+ #ifdef __USE_GNU
+-extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1,
+- const wchar_t *__restrict __s2, size_t __n,
+- size_t __ns1) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wmempcpy_alias,
+ (wchar_t *__restrict __s1,
+ const wchar_t *__restrict __s2,
+@@ -91,8 +83,6 @@ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
+ #endif
+
+
+-extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n,
+- size_t __ns) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wmemset_alias, (wchar_t *__s, wchar_t __c,
+ size_t __n), wmemset);
+ extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn,
+@@ -110,9 +100,6 @@ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n))
+ }
+
+
+-extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest,
+- const wchar_t *__restrict __src,
+- size_t __n) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wcscpy_alias,
+ (wchar_t *__restrict __dest,
+ const wchar_t *__restrict __src), wcscpy);
+@@ -127,9 +114,6 @@ __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+ }
+
+
+-extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest,
+- const wchar_t *__restrict __src,
+- size_t __destlen) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias,
+ (wchar_t *__restrict __dest,
+ const wchar_t *__restrict __src), wcpcpy);
+@@ -144,9 +128,6 @@ __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+ }
+
+
+-extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest,
+- const wchar_t *__restrict __src, size_t __n,
+- size_t __destlen) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wcsncpy_alias,
+ (wchar_t *__restrict __dest,
+ const wchar_t *__restrict __src,
+@@ -168,9 +149,6 @@ __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
+ }
+
+
+-extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest,
+- const wchar_t *__restrict __src, size_t __n,
+- size_t __destlen) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wcpncpy_alias,
+ (wchar_t *__restrict __dest,
+ const wchar_t *__restrict __src,
+@@ -192,9 +170,6 @@ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
+ }
+
+
+-extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest,
+- const wchar_t *__restrict __src,
+- size_t __destlen) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wcscat_alias,
+ (wchar_t *__restrict __dest,
+ const wchar_t *__restrict __src), wcscat);
+@@ -209,9 +184,6 @@ __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+ }
+
+
+-extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest,
+- const wchar_t *__restrict __src,
+- size_t __n, size_t __destlen) __THROW;
+ extern wchar_t *__REDIRECT_NTH (__wcsncat_alias,
+ (wchar_t *__restrict __dest,
+ const wchar_t *__restrict __src,
+@@ -228,10 +200,6 @@ __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
+ }
+
+
+-extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n,
+- int __flag, size_t __s_len,
+- const wchar_t *__restrict __format, ...)
+- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */;
+
+ extern int __REDIRECT_NTH_LDBL (__swprintf_alias,
+ (wchar_t *__restrict __s, size_t __n,
+@@ -258,11 +226,6 @@ __NTH (swprintf (wchar_t *__restrict __s, size_t __n,
+ : swprintf (s, n, __VA_ARGS__))
+ #endif
+
+-extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
+- int __flag, size_t __s_len,
+- const wchar_t *__restrict __format,
+- __gnuc_va_list __arg)
+- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
+
+ extern int __REDIRECT_NTH_LDBL (__vswprintf_alias,
+ (wchar_t *__restrict __s, size_t __n,
+@@ -283,16 +246,6 @@ __NTH (vswprintf (wchar_t *__restrict __s, size_t __n,
+
+ #if __USE_FORTIFY_LEVEL > 1
+
+-extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag,
+- const wchar_t *__restrict __format, ...);
+-extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format,
+- ...);
+-extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag,
+- const wchar_t *__restrict __format,
+- __gnuc_va_list __ap);
+-extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format,
+- __gnuc_va_list __ap);
+-
+ # ifdef __va_arg_pack
+ __fortify_function int
+ wprintf (const wchar_t *__restrict __fmt, ...)
+@@ -328,8 +281,6 @@ vfwprintf (__FILE *__restrict __stream,
+
+ #endif
+
+-extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n,
+- __FILE *__restrict __stream) __wur;
+ extern wchar_t *__REDIRECT (__fgetws_alias,
+ (wchar_t *__restrict __s, int __n,
+ __FILE *__restrict __stream), fgetws) __wur;
+@@ -351,9 +302,6 @@ fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
+ }
+
+ #ifdef __USE_GNU
+-extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size,
+- int __n, __FILE *__restrict __stream)
+- __wur;
+ extern wchar_t *__REDIRECT (__fgetws_unlocked_alias,
+ (wchar_t *__restrict __s, int __n,
+ __FILE *__restrict __stream), fgetws_unlocked)
+@@ -379,9 +327,6 @@ fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
+ #endif
+
+
+-extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar,
+- mbstate_t *__restrict __p,
+- size_t __buflen) __THROW __wur;
+ extern size_t __REDIRECT_NTH (__wcrtomb_alias,
+ (char *__restrict __s, wchar_t __wchar,
+ mbstate_t *__restrict __ps), wcrtomb) __wur;
+@@ -404,10 +349,6 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar,
+ }
+
+
+-extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst,
+- const char **__restrict __src,
+- size_t __len, mbstate_t *__restrict __ps,
+- size_t __dstlen) __THROW;
+ extern size_t __REDIRECT_NTH (__mbsrtowcs_alias,
+ (wchar_t *__restrict __dst,
+ const char **__restrict __src,
+@@ -431,10 +372,6 @@ __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
+ }
+
+
+-extern size_t __wcsrtombs_chk (char *__restrict __dst,
+- const wchar_t **__restrict __src,
+- size_t __len, mbstate_t *__restrict __ps,
+- size_t __dstlen) __THROW;
+ extern size_t __REDIRECT_NTH (__wcsrtombs_alias,
+ (char *__restrict __dst,
+ const wchar_t **__restrict __src,
+@@ -458,10 +395,6 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
+
+
+ #ifdef __USE_XOPEN2K8
+-extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst,
+- const char **__restrict __src, size_t __nmc,
+- size_t __len, mbstate_t *__restrict __ps,
+- size_t __dstlen) __THROW;
+ extern size_t __REDIRECT_NTH (__mbsnrtowcs_alias,
+ (wchar_t *__restrict __dst,
+ const char **__restrict __src, size_t __nmc,
+@@ -485,11 +418,6 @@ __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
+ }
+
+
+-extern size_t __wcsnrtombs_chk (char *__restrict __dst,
+- const wchar_t **__restrict __src,
+- size_t __nwc, size_t __len,
+- mbstate_t *__restrict __ps, size_t __dstlen)
+- __THROW;
+ extern size_t __REDIRECT_NTH (__wcsnrtombs_alias,
+ (char *__restrict __dst,
+ const wchar_t **__restrict __src,
+diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
+index c37e8619a0..5f7139f279 100644
+--- a/wcsmbs/uchar.h
++++ b/wcsmbs/uchar.h
+@@ -34,8 +34,16 @@
+ /* Declare the C2x char8_t typedef in C2x modes, but only if the C++
+ __cpp_char8_t feature test macro is not defined. */
+ #if __GLIBC_USE (ISOC2X) && !defined __cpp_char8_t
++#if __GNUC_PREREQ (10, 0) && defined __cplusplus
++/* Suppress the diagnostic regarding char8_t being a keyword in C++20. */
++# pragma GCC diagnostic push
++# pragma GCC diagnostic ignored "-Wc++20-compat"
++#endif
+ /* Define the 8-bit character type. */
+ typedef unsigned char char8_t;
++#if __GNUC_PREREQ (10, 0) && defined __cplusplus
++# pragma GCC diagnostic pop
++#endif
+ #endif
+
+ #ifndef __USE_ISOCXX11
+diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h
+index 5d6a40853d..c1321c7518 100644
+--- a/wcsmbs/wchar.h
++++ b/wcsmbs/wchar.h
+@@ -864,14 +864,21 @@ extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize,
+
+ /* Define some macros helping to catch buffer overflows. */
+ #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
+-# include <bits/wchar2.h>
++/* Declare all functions from bits/wchar2-decl.h first. */
++# include <bits/wchar2-decl.h>
+ #endif
+
+-#include <bits/floatn.h>
++/* The following headers provide asm redirections. These redirections must
++ appear before the first usage of these functions, e.g. in bits/wchar.h. */
+ #if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
+ # include <bits/wchar-ldbl.h>
+ #endif
+
++#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
++/* Now include the function definitions and redirects too. */
++# include <bits/wchar2.h>
++#endif
++
+ __END_DECLS
+
+ #endif /* wchar.h */
1
0
commit 4a44067267f268468b4068051fd138cfd268515b
Author: Tim Biermann <tbier(a)posteo.de>
Date: Sat Oct 1 14:44:04 2022 +0200
libcap-32: 2.65 -> 2.66
diff --git a/libcap-32/.footprint b/libcap-32/.footprint
index 9cb7e04..8c043ed 100644
--- a/libcap-32/.footprint
+++ b/libcap-32/.footprint
@@ -2,12 +2,12 @@ drwxr-xr-x root/root usr/
drwxr-xr-x root/root usr/lib32/
-rw-r--r-- root/root usr/lib32/libcap.a
lrwxrwxrwx root/root usr/lib32/libcap.so -> libcap.so.2
-lrwxrwxrwx root/root usr/lib32/libcap.so.2 -> libcap.so.2.65
--rwxr-xr-x root/root usr/lib32/libcap.so.2.65
+lrwxrwxrwx root/root usr/lib32/libcap.so.2 -> libcap.so.2.66
+-rwxr-xr-x root/root usr/lib32/libcap.so.2.66
-rw-r--r-- root/root usr/lib32/libpsx.a
lrwxrwxrwx root/root usr/lib32/libpsx.so -> libpsx.so.2
-lrwxrwxrwx root/root usr/lib32/libpsx.so.2 -> libpsx.so.2.65
--rwxr-xr-x root/root usr/lib32/libpsx.so.2.65
+lrwxrwxrwx root/root usr/lib32/libpsx.so.2 -> libpsx.so.2.66
+-rwxr-xr-x root/root usr/lib32/libpsx.so.2.66
drwxr-xr-x root/root usr/lib32/pkgconfig/
-rw-r--r-- root/root usr/lib32/pkgconfig/libcap.pc
-rw-r--r-- root/root usr/lib32/pkgconfig/libpsx.pc
diff --git a/libcap-32/.signature b/libcap-32/.signature
index 279f786..fbf30a4 100644
--- a/libcap-32/.signature
+++ b/libcap-32/.signature
@@ -1,5 +1,5 @@
untrusted comment: verify with /etc/ports/compat-32.pub
-RWSwxGo/zH7eXTIiZ3vdjzElprSr9rcluz1anQ/lWtoS2quQui/KGZ8gYiilhdOhZcmauXN21qsrzkSV2Nl8Cu/Quvg4PBwx2As=
-SHA256 (Pkgfile) = d426375fb8180c3b94ce1cc6bf345bf8e298eebf5ded19b378a2f9d1aaa0db08
-SHA256 (.footprint) = e8d94267182e07b8ede4ae7dbf3407055f042131e060cc21737206e0d3a41eb7
-SHA256 (libcap-2.65.tar.xz) = 73e350020cc31fe15360879d19384ffa3395a825f065fcf6bda3a5cdf965bebd
+RWSwxGo/zH7eXR6kpKlYJEsJxy5TRPOjNFvYsWDI4auRzmRDfT3ZGTDyI3GvDm5M7ehmhejWZeckMOmCemWtSt9xMj24n41TPwM=
+SHA256 (Pkgfile) = c64607a2609fbdb90ef6572e03916f914607fa19764ed8e357af91c87c00d390
+SHA256 (.footprint) = 63450bf794b0d6b4b3164f59ba117942644423dcf9f5887074a90d799ec3f1c5
+SHA256 (libcap-2.66.tar.xz) = 15c40ededb3003d70a283fe587a36b7d19c8b3b554e33f86129c059a4bb466b2
diff --git a/libcap-32/Pkgfile b/libcap-32/Pkgfile
index 1f8ffcd..a97df2b 100644
--- a/libcap-32/Pkgfile
+++ b/libcap-32/Pkgfile
@@ -4,7 +4,7 @@
# Depends on: attr-32
name=libcap-32
-version=2.65
+version=2.66
release=1
source=(https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/…
1
0
commit 904bfa0f4bd6d6f1761fbf412881e0da4c4e565b
Author: Tim Biermann <tbier(a)posteo.de>
Date: Sat Oct 1 14:43:14 2022 +0200
readline-32: 8.1.2 -> 8.2
diff --git a/readline-32/.footprint b/readline-32/.footprint
index d81ff8a..15fdf3b 100644
--- a/readline-32/.footprint
+++ b/readline-32/.footprint
@@ -1,13 +1,14 @@
drwxr-xr-x root/root lib32/
--rwxr-xr-x root/root lib32/libhistory.so.8.1
-lrwxrwxrwx root/root lib32/libhistory.so.8 -> libhistory.so.8.1
--rwxr-xr-x root/root lib32/libreadline.so.8.1
-lrwxrwxrwx root/root lib32/libreadline.so.8 -> libreadline.so.8.1
+lrwxrwxrwx root/root lib32/libhistory.so.8 -> libhistory.so.8.2
+-rwxr-xr-x root/root lib32/libhistory.so.8.2
+lrwxrwxrwx root/root lib32/libreadline.so.8 -> libreadline.so.8.2
+-rwxr-xr-x root/root lib32/libreadline.so.8.2
drwxr-xr-x root/root usr/
drwxr-xr-x root/root usr/lib32/
-rw-r--r-- root/root usr/lib32/libhistory.a
-lrwxrwxrwx root/root usr/lib32/libhistory.so -> ../../lib32/libhistory.so.8.1
+lrwxrwxrwx root/root usr/lib32/libhistory.so -> ../../lib32/libhistory.so.8.2
-rw-r--r-- root/root usr/lib32/libreadline.a
-lrwxrwxrwx root/root usr/lib32/libreadline.so -> ../../lib32/libreadline.so.8.1
+lrwxrwxrwx root/root usr/lib32/libreadline.so -> ../../lib32/libreadline.so.8.2
drwxr-xr-x root/root usr/lib32/pkgconfig/
+-rw-r--r-- root/root usr/lib32/pkgconfig/history.pc
-rw-r--r-- root/root usr/lib32/pkgconfig/readline.pc
diff --git a/readline-32/.signature b/readline-32/.signature
index 2f71aba..d36838b 100644
--- a/readline-32/.signature
+++ b/readline-32/.signature
@@ -1,5 +1,5 @@
untrusted comment: verify with /etc/ports/compat-32.pub
-RWSwxGo/zH7eXVM+ZInlrb2bGQmjQ8FmOTh5FB2U1GE/D3ApQ65Y1z1zFQ9y6++UC8lKvxa39rTUUHUqqq+GGqRs3X3FGQu0Tww=
-SHA256 (Pkgfile) = ac6743eb3154f6a441e6056f6e255ffabc8215519c7fc9e03162716b91768716
-SHA256 (.footprint) = 751df7cc7364353ba6cc9e48dc5fd4fc605e761bd8b0e2ba10f276a376ef094f
-SHA256 (readline-8.1.tar.gz) = f8ceb4ee131e3232226a17f51b164afc46cd0b9e6cef344be87c65962cb82b02
+RWSwxGo/zH7eXW9fF54c7gGbWtK68rxW7qApCFxnWgs3KlSFYjwaBPRmsR7J0VI9yV3fm/dM8pgue6m6+y2FN9BNXoLaNphZnQc=
+SHA256 (Pkgfile) = 869e7ff7cf58c80f246f86cdf49069c55e7951293bc1115d5ea91bfa9cf64e9f
+SHA256 (.footprint) = 4bc692d5b2c19d40dd913fd03e82fd86fac4c27163b7873952e5aecdb0a4a628
+SHA256 (readline-8.2.tar.gz) = 3feb7171f16a84ee82ca18a36d7b9be109a52c04f492a053331d7d1095007c35
diff --git a/readline-32/Pkgfile b/readline-32/Pkgfile
index eb276c8..1cf3acc 100644
--- a/readline-32/Pkgfile
+++ b/readline-32/Pkgfile
@@ -4,7 +4,7 @@
# Depends on: ncurses-32
name=readline-32
-version=8.1.2
+version=8.2
release=1
source=(https://ftp.gnu.org/gnu/${name%-*}/${name%-*}-${version:0:3}.tar.gz)
1
0
commit 3b7d92b97753e16cf78dd19cc0a533dc4602a3ff
Author: Tim Biermann <tbier(a)posteo.de>
Date: Sat Oct 1 14:41:00 2022 +0200
curl-32: 7.84.0 -> 7.85.0
diff --git a/curl-32/.signature b/curl-32/.signature
index 2ace6b2..0e2af53 100644
--- a/curl-32/.signature
+++ b/curl-32/.signature
@@ -1,5 +1,5 @@
untrusted comment: verify with /etc/ports/compat-32.pub
-RWSwxGo/zH7eXdbupMdF+nfnaZlC5xGdIBcfbWbX4maziaSO4Dr2U/ZOEsjiVe7tnYskPKgRsCJtV6aKMt3W3h3qBtK9UhO1SwE=
-SHA256 (Pkgfile) = bcb9dc66816669cd989ef5b5d8757627748451ed79c0f13a21a766707deb9b2f
+RWSwxGo/zH7eXWR015CMcM0sXN+Z6aeurWjgUtKNyADEfw5ELhwv7BOu9TN6h0TT4E3wasp6LESzn9WrX53B/4blxpBZZ34z3Ac=
+SHA256 (Pkgfile) = 22f3edd73097231ee042243c3c9c02210c2e02c5deec7618c11aab73ac572687
SHA256 (.footprint) = 1f49d30883c63da2e3d72a616a65fa40806923dd3c80aa299aebe1ceb544379b
-SHA256 (curl-7.84.0.tar.xz) = 2d118b43f547bfe5bae806d8d47b4e596ea5b25a6c1f080aef49fbcd817c5db8
+SHA256 (curl-7.85.0.tar.xz) = 88b54a6d4b9a48cb4d873c7056dcba997ddd5b7be5a2d537a4acb55c20b04be6
diff --git a/curl-32/Pkgfile b/curl-32/Pkgfile
index 13644ec..efd5007 100644
--- a/curl-32/Pkgfile
+++ b/curl-32/Pkgfile
@@ -5,7 +5,7 @@
# Optional: brotli-32
name=curl-32
-version=7.84.0
+version=7.85.0
release=1
source=(https://curl.se/download/${name%-*}-$version.tar.xz)
@@ -22,7 +22,6 @@ build() {
--enable-ipv6 \
--without-libidn2 \
--with-openssl \
- --without-cyassl \
--enable-threaded-resolver \
--with-ca-bundle=/etc/ssl/cert.pem
make
1
0
commit 700afa9fab70b01a319f29ab7515585c323b71e4
Author: Tim Biermann <tbier(a)posteo.de>
Date: Sat Oct 1 14:39:43 2022 +0200
dbus-32: 1.14.0 -> 1.14.2
diff --git a/dbus-32/.signature b/dbus-32/.signature
index 8af087e..c1bc88b 100644
--- a/dbus-32/.signature
+++ b/dbus-32/.signature
@@ -1,5 +1,5 @@
untrusted comment: verify with /etc/ports/compat-32.pub
-RWSwxGo/zH7eXbCIa3u4Wzl3Qvg+OF3gYH1hTHMe1mMfoFb+K7oobLHKu8mZPI4P9W3IRD5vUmz4+r5XrGRlV7WjsJR/ysmwOQY=
-SHA256 (Pkgfile) = 75c1aa01de07b07b638e2991283b5e484f2fb74450336d9fb82338e38bdd455e
+RWSwxGo/zH7eXTpsRVfJQYgGmTqB4B2WYJa12Zr8lPLzfkt1wOfIjrgC+2ON2p3/7VFDBITfsWrNeSBKbt37zkY/aopapSotQAo=
+SHA256 (Pkgfile) = 7992937391b96dbcbb82ee432fef8881cac767fc1c27b402750b8a74eaf63255
SHA256 (.footprint) = db07afcc0141fab1dc3788203d1d040a971175dac58920d67daecef40678fa1a
-SHA256 (dbus-1.14.0.tar.xz) = ccd7cce37596e0a19558fd6648d1272ab43f011d80c8635aea8fd0bad58aebd4
+SHA256 (dbus-1.14.2.tar.xz) = 07351839a36b3c833b3afe405c4420e7ee367f2ecf57c7ac3633e53110d799fa
diff --git a/dbus-32/Pkgfile b/dbus-32/Pkgfile
index 94d2ff6..686b016 100644
--- a/dbus-32/Pkgfile
+++ b/dbus-32/Pkgfile
@@ -4,7 +4,7 @@
# Depends on: dbus expat-32
name=dbus-32
-version=1.14.0
+version=1.14.2
release=1
source=(https://dbus.freedesktop.org/releases/dbus/dbus-$version.tar.xz)
1
0
commit 48623414caa3de97b4044556c12d1ec2659d237a
Author: Tim Biermann <tbier(a)posteo.de>
Date: Sat Oct 1 14:38:55 2022 +0200
libffi-32: 3.4.2 -> 3.4.3
diff --git a/libffi-32/.footprint b/libffi-32/.footprint
index f1b4f6c..6077233 100644
--- a/libffi-32/.footprint
+++ b/libffi-32/.footprint
@@ -2,8 +2,8 @@ drwxr-xr-x root/root usr/
drwxr-xr-x root/root usr/lib32/
-rw-r--r-- root/root usr/lib32/libffi.a
-rwxr-xr-x root/root usr/lib32/libffi.la
-lrwxrwxrwx root/root usr/lib32/libffi.so -> libffi.so.8.1.0
-lrwxrwxrwx root/root usr/lib32/libffi.so.8 -> libffi.so.8.1.0
--rwxr-xr-x root/root usr/lib32/libffi.so.8.1.0
+lrwxrwxrwx root/root usr/lib32/libffi.so -> libffi.so.8.1.1
+lrwxrwxrwx root/root usr/lib32/libffi.so.8 -> libffi.so.8.1.1
+-rwxr-xr-x root/root usr/lib32/libffi.so.8.1.1
drwxr-xr-x root/root usr/lib32/pkgconfig/
-rw-r--r-- root/root usr/lib32/pkgconfig/libffi.pc
diff --git a/libffi-32/.signature b/libffi-32/.signature
index 7509abe..1f5e4c2 100644
--- a/libffi-32/.signature
+++ b/libffi-32/.signature
@@ -1,5 +1,5 @@
untrusted comment: verify with /etc/ports/compat-32.pub
-RWSwxGo/zH7eXWOH5QptYroHtUGcXS4LRuIjKTeeRN52xUVzkKndtC775LvudqJev78UYUAImcLhqhamJgPkocpidcb0brCtxwA=
-SHA256 (Pkgfile) = 298209b34b21474866b44800fb5f4833f70b2591cf8b9a701ff77301d6c218aa
-SHA256 (.footprint) = f3e3a93357af9b6afe0502ff0bfd6757ea99cd11a5f9c1cea16345d58e73c33e
-SHA256 (libffi-3.4.2.tar.gz) = 540fb721619a6aba3bdeef7d940d8e9e0e6d2c193595bc243241b77ff9e93620
+RWSwxGo/zH7eXY+lj+rpTfn6HMX9RbXMih8MEIH2VT5gi+lox1jqcGHMmCusEV5Se7ys5fmJbo/e1/5nIovhjCXVTo9X0QntEgI=
+SHA256 (Pkgfile) = dc9de0da32f6e1a3c35801ab0bce5d655da1f8cc58872f835147f60d53e82fb6
+SHA256 (.footprint) = a2bbbd9494d06fd265d3c9e7300ad95fc664960c5fcf30172c4b3fbdd76caeee
+SHA256 (libffi-3.4.3.tar.gz) = 4416dd92b6ae8fcb5b10421e711c4d3cb31203d77521a77d85d0102311e6c3b8
diff --git a/libffi-32/Pkgfile b/libffi-32/Pkgfile
index d2a376c..72a0f2c 100644
--- a/libffi-32/Pkgfile
+++ b/libffi-32/Pkgfile
@@ -4,7 +4,7 @@
# Depends on: libffi
name=libffi-32
-version=3.4.2
+version=3.4.3
release=1
source=(https://github.com/libffi/libffi/releases/download/v$version/libffi…
1
0
commit 342c90439080bcb02c3161b688b2f099269bf0be
Author: Tim Biermann <tbier(a)posteo.de>
Date: Sat Oct 1 14:38:10 2022 +0200
nvidia-32: 510.60.02 -> 515.76
diff --git a/nvidia-32/.footprint b/nvidia-32/.footprint
index 8d5aa2f..7d45252 100644
--- a/nvidia-32/.footprint
+++ b/nvidia-32/.footprint
@@ -1,37 +1,37 @@
drwxr-xr-x root/root usr/
drwxr-xr-x root/root usr/lib32/
-lrwxrwxrwx root/root usr/lib32/libEGL_nvidia.so.0 -> libEGL_nvidia.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libEGL_nvidia.so.510.60.02
-lrwxrwxrwx root/root usr/lib32/libGLESv1_CM_nvidia.so.1 -> libGLESv1_CM_nvidia.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libGLESv1_CM_nvidia.so.510.60.02
-lrwxrwxrwx root/root usr/lib32/libGLESv2_nvidia.so.2 -> libGLESv2_nvidia.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libGLESv2_nvidia.so.510.60.02
-lrwxrwxrwx root/root usr/lib32/libGLX_nvidia.so.0 -> libGLX_nvidia.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libGLX_nvidia.so.510.60.02
+lrwxrwxrwx root/root usr/lib32/libEGL_nvidia.so.0 -> libEGL_nvidia.so.515.76
+-rwxr-xr-x root/root usr/lib32/libEGL_nvidia.so.515.76
+lrwxrwxrwx root/root usr/lib32/libGLESv1_CM_nvidia.so.1 -> libGLESv1_CM_nvidia.so.515.76
+-rwxr-xr-x root/root usr/lib32/libGLESv1_CM_nvidia.so.515.76
+lrwxrwxrwx root/root usr/lib32/libGLESv2_nvidia.so.2 -> libGLESv2_nvidia.so.515.76
+-rwxr-xr-x root/root usr/lib32/libGLESv2_nvidia.so.515.76
+lrwxrwxrwx root/root usr/lib32/libGLX_nvidia.so.0 -> libGLX_nvidia.so.515.76
+-rwxr-xr-x root/root usr/lib32/libGLX_nvidia.so.515.76
-rwxr-xr-x root/root usr/lib32/libOpenCL.so.1.0.0
-lrwxrwxrwx root/root usr/lib32/libcuda.so -> libcuda.so.510.60.02
-lrwxrwxrwx root/root usr/lib32/libcuda.so.1 -> libcuda.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libcuda.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvcuvid.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvidia-compiler.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvidia-eglcore.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvidia-encode.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvidia-fbc.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvidia-glcore.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvidia-glsi.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvidia-glvkspirv.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvidia-ml.so.510.60.02
-lrwxrwxrwx root/root usr/lib32/libnvidia-opencl.so -> libnvidia-opencl.so.510.60.02
-lrwxrwxrwx root/root usr/lib32/libnvidia-opencl.so.1 -> libnvidia-opencl.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvidia-opencl.so.510.60.02
-lrwxrwxrwx root/root usr/lib32/libnvidia-opticalflow.so -> libnvidia-opticalflow.so.510.60.02
-lrwxrwxrwx root/root usr/lib32/libnvidia-opticalflow.so.1 -> libnvidia-opticalflow.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvidia-opticalflow.so.510.60.02
-lrwxrwxrwx root/root usr/lib32/libnvidia-ptxjitcompiler.so -> libnvidia-ptxjitcompiler.so.510.60.02
-lrwxrwxrwx root/root usr/lib32/libnvidia-ptxjitcompiler.so.1 -> libnvidia-ptxjitcompiler.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvidia-ptxjitcompiler.so.510.60.02
--rwxr-xr-x root/root usr/lib32/libnvidia-tls.so.510.60.02
+lrwxrwxrwx root/root usr/lib32/libcuda.so -> libcuda.so.515.76
+lrwxrwxrwx root/root usr/lib32/libcuda.so.1 -> libcuda.so.515.76
+-rwxr-xr-x root/root usr/lib32/libcuda.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvcuvid.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvidia-compiler.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvidia-eglcore.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvidia-encode.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvidia-fbc.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvidia-glcore.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvidia-glsi.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvidia-glvkspirv.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvidia-ml.so.515.76
+lrwxrwxrwx root/root usr/lib32/libnvidia-opencl.so -> libnvidia-opencl.so.515.76
+lrwxrwxrwx root/root usr/lib32/libnvidia-opencl.so.1 -> libnvidia-opencl.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvidia-opencl.so.515.76
+lrwxrwxrwx root/root usr/lib32/libnvidia-opticalflow.so -> libnvidia-opticalflow.so.515.76
+lrwxrwxrwx root/root usr/lib32/libnvidia-opticalflow.so.1 -> libnvidia-opticalflow.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvidia-opticalflow.so.515.76
+lrwxrwxrwx root/root usr/lib32/libnvidia-ptxjitcompiler.so -> libnvidia-ptxjitcompiler.so.515.76
+lrwxrwxrwx root/root usr/lib32/libnvidia-ptxjitcompiler.so.1 -> libnvidia-ptxjitcompiler.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvidia-ptxjitcompiler.so.515.76
+-rwxr-xr-x root/root usr/lib32/libnvidia-tls.so.515.76
drwxr-xr-x root/root usr/lib32/vdpau/
-lrwxrwxrwx root/root usr/lib32/vdpau/libvdpau_nvidia.so -> libvdpau_nvidia.so.510.60.02
-lrwxrwxrwx root/root usr/lib32/vdpau/libvdpau_nvidia.so.1 -> libvdpau_nvidia.so.510.60.02
--rwxr-xr-x root/root usr/lib32/vdpau/libvdpau_nvidia.so.510.60.02
+lrwxrwxrwx root/root usr/lib32/vdpau/libvdpau_nvidia.so -> libvdpau_nvidia.so.515.76
+lrwxrwxrwx root/root usr/lib32/vdpau/libvdpau_nvidia.so.1 -> libvdpau_nvidia.so.515.76
+-rwxr-xr-x root/root usr/lib32/vdpau/libvdpau_nvidia.so.515.76
diff --git a/nvidia-32/.signature b/nvidia-32/.signature
index 3813cc8..0d532bc 100644
--- a/nvidia-32/.signature
+++ b/nvidia-32/.signature
@@ -1,5 +1,5 @@
untrusted comment: verify with /etc/ports/compat-32.pub
-RWSwxGo/zH7eXT943W9YXEYrgFAfee7VQVKoXU6MMBmWCXBTarA7+lOQOEHdNekxwdDQKjrtvvgopIaLx+OqiFSn0A2gIJa8tA4=
-SHA256 (Pkgfile) = fab5e3193bad4f3d04e50d893776f5817c7a5ba358fd081166d608a47f91a217
-SHA256 (.footprint) = e9b0980f839ad3b6191e4aaeb184ffaf2f14fa1ee6f76c355c80237610460b65
-SHA256 (NVIDIA-Linux-x86_64-510.60.02.run) = a800dfc0549078fd8c6e8e6780efb8eee87872e6055c7f5f386a4768ce07e003
+RWSwxGo/zH7eXc+zXeGnc/ye9A1Tym/2AdNqD6XJhKT4eVUus+Bs38bak189elNYCCpQq9wL65ptTT7QJkojsaPv4QgJs35A8QQ=
+SHA256 (Pkgfile) = 9c822df393b0aa445b7afe5f805803f54623592759033c9ffdb461284c13a10a
+SHA256 (.footprint) = 9a5881d0a98618fc19f723636a85868efa3f8163b54c5af8d18c13faaf2f2de8
+SHA256 (NVIDIA-Linux-x86_64-515.76.run) = c6a2a18ceb965f4980bce4e5cea36fd622cdc1a5f31a0eb1bbd359a9e9f6bf44
diff --git a/nvidia-32/Pkgfile b/nvidia-32/Pkgfile
index e9a95df..1ced512 100644
--- a/nvidia-32/Pkgfile
+++ b/nvidia-32/Pkgfile
@@ -4,7 +4,7 @@
# Depends on: libglvnd-32
name=nvidia-32
-version=510.60.02
+version=515.76
release=1
source=(http://us.download.nvidia.com/XFree86/Linux-x86_64/$version/NVIDIA-…
1
0
commit dbee83a7935367eb6d68999f1fccc17e6f98774f
Author: Tim Biermann <tbier(a)posteo.de>
Date: Sat Oct 1 14:35:00 2022 +0200
pipewire-32: 0.3.58 -> 0.3.59
diff --git a/pipewire-32/.footprint b/pipewire-32/.footprint
index 849561f..b4e5e6e 100644
--- a/pipewire-32/.footprint
+++ b/pipewire-32/.footprint
@@ -4,19 +4,19 @@ drwxr-xr-x root/root usr/lib32/alsa-lib/
-rwxr-xr-x root/root usr/lib32/alsa-lib/libasound_module_ctl_pipewire.so
-rwxr-xr-x root/root usr/lib32/alsa-lib/libasound_module_pcm_pipewire.so
lrwxrwxrwx root/root usr/lib32/libpipewire-0.3.so -> libpipewire-0.3.so.0
-lrwxrwxrwx root/root usr/lib32/libpipewire-0.3.so.0 -> libpipewire-0.3.so.0.358.0
--rwxr-xr-x root/root usr/lib32/libpipewire-0.3.so.0.358.0
+lrwxrwxrwx root/root usr/lib32/libpipewire-0.3.so.0 -> libpipewire-0.3.so.0.359.0
+-rwxr-xr-x root/root usr/lib32/libpipewire-0.3.so.0.359.0
drwxr-xr-x root/root usr/lib32/pipewire-0.3/
drwxr-xr-x root/root usr/lib32/pipewire-0.3/jack/
lrwxrwxrwx root/root usr/lib32/pipewire-0.3/jack/libjack.so -> libjack.so.0
-lrwxrwxrwx root/root usr/lib32/pipewire-0.3/jack/libjack.so.0 -> libjack.so.0.358.0
--rwxr-xr-x root/root usr/lib32/pipewire-0.3/jack/libjack.so.0.358.0
+lrwxrwxrwx root/root usr/lib32/pipewire-0.3/jack/libjack.so.0 -> libjack.so.0.359.0
+-rwxr-xr-x root/root usr/lib32/pipewire-0.3/jack/libjack.so.0.359.0
lrwxrwxrwx root/root usr/lib32/pipewire-0.3/jack/libjacknet.so -> libjacknet.so.0
-lrwxrwxrwx root/root usr/lib32/pipewire-0.3/jack/libjacknet.so.0 -> libjacknet.so.0.358.0
--rwxr-xr-x root/root usr/lib32/pipewire-0.3/jack/libjacknet.so.0.358.0
+lrwxrwxrwx root/root usr/lib32/pipewire-0.3/jack/libjacknet.so.0 -> libjacknet.so.0.359.0
+-rwxr-xr-x root/root usr/lib32/pipewire-0.3/jack/libjacknet.so.0.359.0
lrwxrwxrwx root/root usr/lib32/pipewire-0.3/jack/libjackserver.so -> libjackserver.so.0
-lrwxrwxrwx root/root usr/lib32/pipewire-0.3/jack/libjackserver.so.0 -> libjackserver.so.0.358.0
--rwxr-xr-x root/root usr/lib32/pipewire-0.3/jack/libjackserver.so.0.358.0
+lrwxrwxrwx root/root usr/lib32/pipewire-0.3/jack/libjackserver.so.0 -> libjackserver.so.0.359.0
+-rwxr-xr-x root/root usr/lib32/pipewire-0.3/jack/libjackserver.so.0.359.0
-rwxr-xr-x root/root usr/lib32/pipewire-0.3/libpipewire-module-access.so
-rwxr-xr-x root/root usr/lib32/pipewire-0.3/libpipewire-module-adapter.so
-rwxr-xr-x root/root usr/lib32/pipewire-0.3/libpipewire-module-client-device.so
diff --git a/pipewire-32/.signature b/pipewire-32/.signature
index 752fdbc..07e6ae3 100644
--- a/pipewire-32/.signature
+++ b/pipewire-32/.signature
@@ -1,5 +1,5 @@
untrusted comment: verify with /etc/ports/compat-32.pub
-RWSwxGo/zH7eXQdw2hAxlGNcnfP472KGoCmTlj7AP8CnzScGcRJ26q0h1YV5M0JEZvxsg+fX7nNp/A1E0Us+TQTgO9qkX3Csvww=
-SHA256 (Pkgfile) = 068a51c3a88c3adb112955fca4bb2ba14bdb62cbc215fc94a5f2a8ffdf721bd8
-SHA256 (.footprint) = 72102673d0619075a221124bfeebf290a2c916fe9d575904aac0408cbac7d63c
-SHA256 (pipewire-0.3.58.tar.gz) = 5cb73bf27b8b80e37804d7829c5ad8fa5510835f449bbb7e4773f188584771ad
+RWSwxGo/zH7eXfAYLqoRekVhuFfF8T1EdoLZRQq11SZ/y/wRRP3X1lm1ssEYEj4iMpYSi9CjlsoHMr57US1hTmLbE40ibkZ5Dgk=
+SHA256 (Pkgfile) = ba705c0fbc9754cc60cfc26f068bca3bde96d3f52972d27b3ace76265e6b76e3
+SHA256 (.footprint) = 79e750527189b58fcbef3a23cb7fb1b53a6f5a6e10fc982fa3556c6569f6db07
+SHA256 (pipewire-0.3.59.tar.gz) = fd07b7cb8f509da3b5d2730be6748509454b3ec0b17282b9bc594e571b144920
diff --git a/pipewire-32/Pkgfile b/pipewire-32/Pkgfile
index e484297..b44fd35 100644
--- a/pipewire-32/Pkgfile
+++ b/pipewire-32/Pkgfile
@@ -5,7 +5,7 @@
# Optional: avahi-32 jack-32 libsdl2-32 libsndfile-32 pulseaudio-32 vulkan-loader-32
name=pipewire-32
-version=0.3.58
+version=0.3.59
release=1
source=(https://github.com/PipeWire/pipewire/archive/$version/pipewire-$ver…
1
0
commit 76e5ccc60376c9b3288b03b25b389576898475d9
Author: Tim Biermann <tbier(a)posteo.de>
Date: Sat Oct 1 13:49:54 2022 +0200
clang-distcc-bindings: 14 -> 15
diff --git a/clang-distcc-bindings/.footprint b/clang-distcc-bindings/.footprint
index e0648f5f1..c8cfdb897 100644
--- a/clang-distcc-bindings/.footprint
+++ b/clang-distcc-bindings/.footprint
@@ -3,5 +3,5 @@ drwxr-xr-x root/root usr/lib/
drwxr-xr-x root/root usr/lib/distcc/
lrwxrwxrwx root/root usr/lib/distcc/clang -> ../../bin/distcc
lrwxrwxrwx root/root usr/lib/distcc/clang++ -> ../../bin/distcc
-lrwxrwxrwx root/root usr/lib/distcc/clang-14 -> ../../bin/distcc
-lrwxrwxrwx root/root usr/lib/distcc/clang-14.0 -> ../../bin/distcc
+lrwxrwxrwx root/root usr/lib/distcc/clang-15 -> ../../bin/distcc
+lrwxrwxrwx root/root usr/lib/distcc/clang-15.0 -> ../../bin/distcc
diff --git a/clang-distcc-bindings/.signature b/clang-distcc-bindings/.signature
index 9dda917c5..af7f10b50 100644
--- a/clang-distcc-bindings/.signature
+++ b/clang-distcc-bindings/.signature
@@ -1,4 +1,4 @@
untrusted comment: verify with /etc/ports/opt.pub
-RWSE3ohX2g5d/VHGN6pQFGFCP0f6Sk/UW6o8+We7F9sbER3TwspU/f2F5tFVahmQ613om4FwwwPUcaEaQZMGCHheA34XeYnQrAM=
-SHA256 (Pkgfile) = 81f5e6cd439de303f762d81d5cdde1cdebd746d0e8eeb5728384e9e5eac1b8be
-SHA256 (.footprint) = d504fa73a0ad0601392a130cc4feb3ec264834609d737f4cff45ff454132cabb
+RWSE3ohX2g5d/c6ZGdzoYGZwP2x+b4BS/7gFjLehEsuZzi8MGy3oIZbg5w8U+JMn6g6Q9EfOvVdveQZHvvLzrxVStHPpGh354g4=
+SHA256 (Pkgfile) = 89c4313c75f6ea11f9d8b8038f9f26058c1f51c0c939601fc16f05c63d84e619
+SHA256 (.footprint) = 1ac84b53bf0e75e72f64b024e7f2bf35746034e9667ad07322b171e1be58b2b8
diff --git a/clang-distcc-bindings/Pkgfile b/clang-distcc-bindings/Pkgfile
index aaf9780cc..fb81cac82 100644
--- a/clang-distcc-bindings/Pkgfile
+++ b/clang-distcc-bindings/Pkgfile
@@ -4,7 +4,7 @@
# Depends on: clang distcc
name=clang-distcc-bindings
-version=14
+version=15
release=1
source=()
1
0