diff --git a/SOURCES/glibc-RHEL-2423.patch b/SOURCES/glibc-RHEL-2423.patch
new file mode 100644
index 0000000..476ea12
--- /dev/null
+++ b/SOURCES/glibc-RHEL-2423.patch
@@ -0,0 +1,347 @@
+Avoid UAF in getcanonname (CVE-2023-4806)
+
+When an NSS plugin only implements the _gethostbyname2_r and
+_getcanonname_r callbacks, getaddrinfo could use memory that was freed
+during tmpbuf resizing, through h_name in a previous query response.
+
+The backing store for res->at->name when doing a query with
+gethostbyname3_r or gethostbyname2_r is tmpbuf, which is reallocated in
+gethosts during the query.  For AF_INET6 lookup with AI_ALL |
+AI_V4MAPPED, gethosts gets called twice, once for a v6 lookup and second
+for a v4 lookup.  In this case, if the first call reallocates tmpbuf
+enough number of times, resulting in a malloc, th->h_name (that
+res->at->name refers to) ends up on a heap allocated storage in tmpbuf.
+Now if the second call to gethosts also causes the plugin callback to
+return NSS_STATUS_TRYAGAIN, tmpbuf will get freed, resulting in a UAF
+reference in res->at->name.  This then gets dereferenced in the
+getcanonname_r plugin call, resulting in the use after free.
+
+Fix this by copying h_name over and freeing it at the end.  This
+resolves BZ #30843, which is assigned CVE-2023-4806.  This is a minimal
+RHEL-8-specific fix.  Test case differences from upstream:
+
+- The test module needs to explicitly link against libnss_files on
+  RHEL-8; upstream libnss_files is built into libc.so.
+
+- Test module code was adapted to not use the upstream NSS module
+  convenience macros.
+
+This change is adapted from the following commit from upstream:
+
+commit 973fe93a5675c42798b2161c6f29c01b0e243994
+Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
+Date:   Fri Sep 15 13:51:12 2023 -0400
+
+    getaddrinfo: Fix use after free in getcanonname (CVE-2023-4806)
+    
+    When an NSS plugin only implements the _gethostbyname2_r and
+    _getcanonname_r callbacks, getaddrinfo could use memory that was freed
+    during tmpbuf resizing, through h_name in a previous query response.
+    
+    The backing store for res->at->name when doing a query with
+    gethostbyname3_r or gethostbyname2_r is tmpbuf, which is reallocated in
+    gethosts during the query.  For AF_INET6 lookup with AI_ALL |
+    AI_V4MAPPED, gethosts gets called twice, once for a v6 lookup and second
+    for a v4 lookup.  In this case, if the first call reallocates tmpbuf
+    enough number of times, resulting in a malloc, th->h_name (that
+    res->at->name refers to) ends up on a heap allocated storage in tmpbuf.
+    Now if the second call to gethosts also causes the plugin callback to
+    return NSS_STATUS_TRYAGAIN, tmpbuf will get freed, resulting in a UAF
+    reference in res->at->name.  This then gets dereferenced in the
+    getcanonname_r plugin call, resulting in the use after free.
+    
+    Fix this by copying h_name over and freeing it at the end.  This
+    resolves BZ #30843, which is assigned CVE-2023-4806.
+    
+    Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
+
+diff --git a/nss/Makefile b/nss/Makefile
+index cfb255c6e7a3a4de..5829a2539306ddb5 100644
+--- a/nss/Makefile
++++ b/nss/Makefile
+@@ -66,7 +66,8 @@ xtests			= bug-erange
+ tests-container = \
+ 			  tst-nss-db-endpwent \
+ 			  tst-nss-db-endgrent \
+-			  tst-nss-gai-actions
++			  tst-nss-gai-actions \
++			  tst-nss-gai-hv2-canonname
+ 
+ # Tests which need libdl
+ ifeq (yes,$(build-shared))
+@@ -132,7 +133,8 @@ routines                += $(libnss_files-routines)
+ static-only-routines    += $(libnss_files-routines)
+ tests-static		+= tst-nss-static
+ endif
+-extra-test-objs		+= nss_test1.os nss_test2.os nss_test_errno.os
++extra-test-objs		+= nss_test1.os nss_test2.os nss_test_errno.os \
++			   nss_test_gai_hv2_canonname.os
+ 
+ include ../Rules
+ 
+@@ -169,12 +171,17 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver
+ libof-nss_test1 = extramodules
+ libof-nss_test2 = extramodules
+ libof-nss_test_errno = extramodules
++libof-nss_test_gai_hv2_canonname = extramodules
+ $(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps)
+ 	$(build-module)
+ $(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps)
+ 	$(build-module)
+ $(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps)
+ 	$(build-module)
++$(objpfx)/libnss_test_gai_hv2_canonname.so: \
++  $(objpfx)nss_test_gai_hv2_canonname.os $(link-libc-deps) \
++  $(objpfx)/libnss_files.so
++	$(build-module)
+ $(objpfx)nss_test2.os : nss_test1.c
+ ifdef libnss_test1.so-version
+ $(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so
+@@ -187,10 +194,14 @@ endif
+ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \
+   $(objpfx)/libnss_test_errno.so
+ 	$(make-link)
++$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version): \
++  $(objpfx)/libnss_test_gai_hv2_canonname.so
++	$(make-link)
+ $(patsubst %,$(objpfx)%.out,$(tests)) : \
+ 	$(objpfx)/libnss_test1.so$(libnss_test1.so-version) \
+ 	$(objpfx)/libnss_test2.so$(libnss_test2.so-version) \
+-	$(objpfx)/libnss_test_errno.so$(libnss_files.so-version)
++	$(objpfx)/libnss_test_errno.so$(libnss_files.so-version) \
++	$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version)
+ 
+ ifeq (yes,$(have-thread-library))
+ $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library)
+diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c
+new file mode 100644
+index 0000000000000000..4195d7d24fdd5f6d
+--- /dev/null
++++ b/nss/nss_test_gai_hv2_canonname.c
+@@ -0,0 +1,64 @@
++/* NSS service provider that only provides gethostbyname2_r.
++   Copyright The GNU Toolchain Authors.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++#include <netdb.h>
++#include <nss.h>
++#include <stdlib.h>
++#include <string.h>
++#include "nss/tst-nss-gai-hv2-canonname.h"
++
++/* Catch misnamed and functions.  */
++#pragma GCC diagnostic error "-Wmissing-prototypes"
++
++extern enum nss_status _nss_files_gethostbyname2_r (const char *, int,
++						    struct hostent *, char *,
++						    size_t, int *, int *);
++
++enum nss_status
++_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *, int, struct hostent
++					      *, char *, size_t, int *, int *);
++
++enum nss_status
++_nss_test_gai_hv2_canonname_getcanonname_r (const char *, char *, size_t, char
++					    **, int *, int *);
++
++enum nss_status
++_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af,
++					      struct hostent *result,
++					      char *buffer, size_t buflen,
++					      int *errnop, int *herrnop)
++{
++  return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop,
++				      herrnop);
++}
++
++enum nss_status
++_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer,
++					    size_t buflen, char **result,
++					    int *errnop, int *h_errnop)
++{
++  /* We expect QUERYNAME, which is a small enough string that it shouldn't fail
++     the test.  */
++  if (memcmp (QUERYNAME, name, sizeof (QUERYNAME))
++      || buflen < sizeof (QUERYNAME))
++    abort ();
++
++  strncpy (buffer, name, buflen);
++  *result = buffer;
++  return NSS_STATUS_SUCCESS;
++}
+diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c
+new file mode 100644
+index 0000000000000000..d5f10c07d6a90773
+--- /dev/null
++++ b/nss/tst-nss-gai-hv2-canonname.c
+@@ -0,0 +1,63 @@
++/* Test NSS query path for plugins that only implement gethostbyname2
++   (#30843).
++   Copyright The GNU Toolchain Authors.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++#include <nss.h>
++#include <netdb.h>
++#include <stdlib.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/xstdio.h>
++#include "nss/tst-nss-gai-hv2-canonname.h"
++
++#define PREPARE do_prepare
++
++static void do_prepare (int a, char **av)
++{
++  FILE *hosts = xfopen ("/etc/hosts", "w");
++  for (unsigned i = 2; i < 255; i++)
++    {
++      fprintf (hosts, "ff01::ff02:ff03:%u:2\ttest.example.com\n", i);
++      fprintf (hosts, "192.168.0.%u\ttest.example.com\n", i);
++    }
++  xfclose (hosts);
++}
++
++static int
++do_test (void)
++{
++  __nss_configure_lookup ("hosts", "test_gai_hv2_canonname");
++
++  struct addrinfo hints = {};
++  struct addrinfo *result = NULL;
++
++  hints.ai_family = AF_INET6;
++  hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_CANONNAME;
++
++  int ret = getaddrinfo (QUERYNAME, NULL, &hints, &result);
++
++  if (ret != 0)
++    FAIL_EXIT1 ("getaddrinfo failed: %s\n", gai_strerror (ret));
++
++  TEST_COMPARE_STRING (result->ai_canonname, QUERYNAME);
++
++  freeaddrinfo(result);
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h
+new file mode 100644
+index 0000000000000000..14f2a9cb0867dff9
+--- /dev/null
++++ b/nss/tst-nss-gai-hv2-canonname.h
+@@ -0,0 +1 @@
++#define QUERYNAME "test.example.com"
+diff --git a/nss/tst-nss-gai-hv2-canonname.root/postclean.req b/nss/tst-nss-gai-hv2-canonname.root/postclean.req
+new file mode 100644
+index 0000000000000000..e69de29bb2d1d643
+diff --git a/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
+new file mode 100644
+index 0000000000000000..31848b4a28524af6
+--- /dev/null
++++ b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
+@@ -0,0 +1,2 @@
++cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2
++su
+diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
+index 4fa963644af8b7d5..46046504a6858f2e 100644
+--- a/sysdeps/posix/getaddrinfo.c
++++ b/sysdeps/posix/getaddrinfo.c
+@@ -233,7 +233,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
+ 	}
+       array[i].next = array + i + 1;
+     }
+-  array[0].name = h->h_name;
+   array[count - 1].next = NULL;
+ 
+   *result = array;
+@@ -287,6 +286,18 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
+ 	}								      \
+       *pat = addrmem;							      \
+ 									      \
++      /* Store h_name so that it survives accidental deallocation when	      \
++	 gethosts is called again and tmpbuf gets reallocated.  */	      \
++      if (h_name == NULL && th.h_name != NULL)				      \
++        {								      \
++	  h_name = __strdup (th.h_name);				      \
++	  if (h_name == NULL)						      \
++	    {								      \
++	      __resolv_context_put (res_ctx);				      \
++	      result = -EAI_SYSTEM;					      \
++	      goto free_and_return;					      \
++	    }								      \
++	}								      \
+       if (localcanon != NULL && canon == NULL)				      \
+ 	{								      \
+ 	  canonbuf = __strdup (localcanon);				      \
+@@ -323,15 +334,15 @@ typedef enum nss_status (*nss_getcanonname_r)
+    memory allocation failure.  The returned string is allocated on the
+    heap; the caller has to free it.  */
+ static char *
+-getcanonname (service_user *nip, struct gaih_addrtuple *at, const char *name)
++getcanonname (service_user *nip, const char *hname, const char *name)
+ {
+   nss_getcanonname_r cfct = __nss_lookup_function (nip, "getcanonname_r");
+   char *s = (char *) name;
+   if (cfct != NULL)
+     {
+       char buf[256];
+-      if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf),
+-			      &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS)
++      if (DL_CALL_FCT (cfct, (hname ?: name, buf, sizeof (buf), &s, &errno,
++			      &h_errno)) != NSS_STATUS_SUCCESS)
+ 	/* If the canonical name cannot be determined, use the passed
+ 	   string.  */
+ 	s = (char *) name;
+@@ -349,6 +360,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
+   struct gaih_addrtuple *at = NULL;
+   bool got_ipv6 = false;
+   const char *canon = NULL;
++  char *h_name = NULL;
+   const char *orig_name = name;
+ 
+   /* Reserve stack memory for the scratch buffer in the getaddrinfo
+@@ -919,7 +931,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 			  if ((req->ai_flags & AI_CANONNAME) != 0
+ 			      && canon == NULL)
+ 			    {
+-			      canonbuf = getcanonname (nip, at, name);
++			      canonbuf = getcanonname (nip, h_name, name);
+ 			      if (canonbuf == NULL)
+ 				{
+ 				  __resolv_context_enable_inet6
+@@ -1169,6 +1181,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
+     free ((char *) name);
+   free (addrmem);
+   free (canonbuf);
++  free (h_name);
+ 
+   return result;
+ }
diff --git a/SOURCES/glibc-RHEL-2435-2.patch b/SOURCES/glibc-RHEL-2435-2.patch
new file mode 100644
index 0000000..8d2a8de
--- /dev/null
+++ b/SOURCES/glibc-RHEL-2435-2.patch
@@ -0,0 +1,22 @@
+Work around in the test case, the fact that RHEL-8 NSS modules
+infrastructure incorrectly allows merging in the hosts database.  This
+is a RHEL-8 only fix.
+
+diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
+index efca6cd1837a172a..c35e752896eceb2a 100644
+--- a/nss/tst-nss-gai-actions.c
++++ b/nss/tst-nss-gai-actions.c
+@@ -87,6 +87,13 @@ do_one_test (int action, int family, bool canon)
+     case ACTION_MERGE:
+       if (ret == 0)
+ 	{
++	  if (hints.ai_flags == 0 && hints.ai_family == AF_INET)
++	    {
++	      printf ("*****      RHEL-8 limitation: "
++		      "NSS modules infrastructure incorrectly allows MERGE\n");
++	      return;
++	    }
++
+ 	  char *formatted = support_format_addrinfo (ai, ret);
+ 
+ 	  printf ("merge unexpectedly succeeded:\n %s\n", formatted);
diff --git a/SOURCES/glibc-RHEL-2435.patch b/SOURCES/glibc-RHEL-2435.patch
new file mode 100644
index 0000000..721cbff
--- /dev/null
+++ b/SOURCES/glibc-RHEL-2435.patch
@@ -0,0 +1,979 @@
+commit 228cdb00a045ae3b68a91b35c7548bab6029446e
+Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
+Date:   Thu Mar 17 11:44:34 2022 +0530
+
+    Simplify allocations and fix merge and continue actions [BZ #28931]
+    
+    Allocations for address tuples is currently a bit confusing because of
+    the pointer chasing through PAT, making it hard to observe the sequence
+    in which allocations have been made.  Narrow scope of the pointer
+    chasing through PAT so that it is only used where necessary.
+    
+    This also tightens actions behaviour with the hosts database in
+    getaddrinfo to comply with the manual text.  The "continue" action
+    discards previous results and the "merge" action results in an immedate
+    lookup failure.  Consequently, chaining of allocations across modules is
+    no longer necessary, thus opening up cleanup opportunities.
+    
+    A test has been added that checks some combinations to ensure that they
+    work correctly.
+    
+    Resolves: BZ #28931
+    
+    Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
+    Reviewed-by: DJ Delorie <dj@redhat.com>
+    (cherry picked from commit 1c37b8022e8763fedbb3f79c02e05c6acfe5a215)
+
+Conflicts:
+	nss/Makefile
+	(Missing test cases)
+	sysdeps/posix/getaddrinfo.c
+	(RES_USE_INET6 still present in RHEL-8 and NSS module traversal rewrite
+	not in RHEL-8)
+
+diff --git a/nss/Makefile b/nss/Makefile
+index e8a7d9c7b3cefcdf..cfb255c6e7a3a4de 100644
+--- a/nss/Makefile
++++ b/nss/Makefile
+@@ -65,7 +65,8 @@ xtests			= bug-erange
+ 
+ tests-container = \
+ 			  tst-nss-db-endpwent \
+-			  tst-nss-db-endgrent
++			  tst-nss-db-endgrent \
++			  tst-nss-gai-actions
+ 
+ # Tests which need libdl
+ ifeq (yes,$(build-shared))
+diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
+new file mode 100644
+index 0000000000000000..efca6cd1837a172a
+--- /dev/null
++++ b/nss/tst-nss-gai-actions.c
+@@ -0,0 +1,149 @@
++/* Test continue and merge NSS actions for getaddrinfo.
++   Copyright The GNU Toolchain Authors.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++#include <dlfcn.h>
++#include <gnu/lib-names.h>
++#include <nss.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include <support/check.h>
++#include <support/format_nss.h>
++#include <support/support.h>
++#include <support/xstdio.h>
++#include <support/xunistd.h>
++
++enum
++{
++  ACTION_MERGE = 0,
++  ACTION_CONTINUE,
++};
++
++static const char *
++family_str (int family)
++{
++  switch (family)
++    {
++    case AF_UNSPEC:
++      return "AF_UNSPEC";
++    case AF_INET:
++      return "AF_INET";
++    default:
++      __builtin_unreachable ();
++    }
++}
++
++static const char *
++action_str (int action)
++{
++  switch (action)
++    {
++    case ACTION_MERGE:
++      return "merge";
++    case ACTION_CONTINUE:
++      return "continue";
++    default:
++      __builtin_unreachable ();
++    }
++}
++
++static void
++do_one_test (int action, int family, bool canon)
++{
++  struct addrinfo hints =
++    {
++      .ai_family = family,
++    };
++
++  struct addrinfo *ai;
++
++  if (canon)
++    hints.ai_flags = AI_CANONNAME;
++
++  printf ("***** Testing \"files [SUCCESS=%s] files\" for family %s, %s\n",
++	  action_str (action), family_str (family),
++	  canon ? "AI_CANONNAME" : "");
++
++  int ret = getaddrinfo ("example.org", "80", &hints, &ai);
++
++  switch (action)
++    {
++    case ACTION_MERGE:
++      if (ret == 0)
++	{
++	  char *formatted = support_format_addrinfo (ai, ret);
++
++	  printf ("merge unexpectedly succeeded:\n %s\n", formatted);
++	  support_record_failure ();
++	  free (formatted);
++	}
++      else
++	return;
++    case ACTION_CONTINUE:
++	{
++	  char *formatted = support_format_addrinfo (ai, ret);
++
++	  /* Verify that the result appears exactly once.  */
++	  const char *expected = "address: STREAM/TCP 192.0.0.1 80\n"
++	    "address: DGRAM/UDP 192.0.0.1 80\n"
++	    "address: RAW/IP 192.0.0.1 80\n";
++
++	  const char *contains = strstr (formatted, expected);
++	  const char *contains2 = NULL;
++
++	  if (contains != NULL)
++	    contains2 = strstr (contains + strlen (expected), expected);
++
++	  if (contains == NULL || contains2 != NULL)
++	    {
++	      printf ("continue failed:\n%s\n", formatted);
++	      support_record_failure ();
++	    }
++
++	  free (formatted);
++	  break;
++	}
++    default:
++      __builtin_unreachable ();
++    }
++}
++
++static void
++do_one_test_set (int action)
++{
++  char buf[32];
++
++  snprintf (buf, sizeof (buf), "files [SUCCESS=%s] files",
++	    action_str (action));
++  __nss_configure_lookup ("hosts", buf);
++
++  do_one_test (action, AF_UNSPEC, false);
++  do_one_test (action, AF_INET, false);
++  do_one_test (action, AF_INET, true);
++}
++
++static int
++do_test (void)
++{
++  do_one_test_set (ACTION_CONTINUE);
++  do_one_test_set (ACTION_MERGE);
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/nss/tst-nss-gai-actions.root/etc/host.conf b/nss/tst-nss-gai-actions.root/etc/host.conf
+new file mode 100644
+index 0000000000000000..d1a59f73a90f2993
+--- /dev/null
++++ b/nss/tst-nss-gai-actions.root/etc/host.conf
+@@ -0,0 +1 @@
++multi on
+diff --git a/nss/tst-nss-gai-actions.root/etc/hosts b/nss/tst-nss-gai-actions.root/etc/hosts
+new file mode 100644
+index 0000000000000000..50ce9774dc2c21d9
+--- /dev/null
++++ b/nss/tst-nss-gai-actions.root/etc/hosts
+@@ -0,0 +1,508 @@
++192.0.0.1	example.org
++192.0.0.2	example.org
++192.0.0.3	example.org
++192.0.0.4	example.org
++192.0.0.5	example.org
++192.0.0.6	example.org
++192.0.0.7	example.org
++192.0.0.8	example.org
++192.0.0.9	example.org
++192.0.0.10	example.org
++192.0.0.11	example.org
++192.0.0.12	example.org
++192.0.0.13	example.org
++192.0.0.14	example.org
++192.0.0.15	example.org
++192.0.0.16	example.org
++192.0.0.17	example.org
++192.0.0.18	example.org
++192.0.0.19	example.org
++192.0.0.20	example.org
++192.0.0.21	example.org
++192.0.0.22	example.org
++192.0.0.23	example.org
++192.0.0.24	example.org
++192.0.0.25	example.org
++192.0.0.26	example.org
++192.0.0.27	example.org
++192.0.0.28	example.org
++192.0.0.29	example.org
++192.0.0.30	example.org
++192.0.0.31	example.org
++192.0.0.32	example.org
++192.0.0.33	example.org
++192.0.0.34	example.org
++192.0.0.35	example.org
++192.0.0.36	example.org
++192.0.0.37	example.org
++192.0.0.38	example.org
++192.0.0.39	example.org
++192.0.0.40	example.org
++192.0.0.41	example.org
++192.0.0.42	example.org
++192.0.0.43	example.org
++192.0.0.44	example.org
++192.0.0.45	example.org
++192.0.0.46	example.org
++192.0.0.47	example.org
++192.0.0.48	example.org
++192.0.0.49	example.org
++192.0.0.50	example.org
++192.0.0.51	example.org
++192.0.0.52	example.org
++192.0.0.53	example.org
++192.0.0.54	example.org
++192.0.0.55	example.org
++192.0.0.56	example.org
++192.0.0.57	example.org
++192.0.0.58	example.org
++192.0.0.59	example.org
++192.0.0.60	example.org
++192.0.0.61	example.org
++192.0.0.62	example.org
++192.0.0.63	example.org
++192.0.0.64	example.org
++192.0.0.65	example.org
++192.0.0.66	example.org
++192.0.0.67	example.org
++192.0.0.68	example.org
++192.0.0.69	example.org
++192.0.0.70	example.org
++192.0.0.71	example.org
++192.0.0.72	example.org
++192.0.0.73	example.org
++192.0.0.74	example.org
++192.0.0.75	example.org
++192.0.0.76	example.org
++192.0.0.77	example.org
++192.0.0.78	example.org
++192.0.0.79	example.org
++192.0.0.80	example.org
++192.0.0.81	example.org
++192.0.0.82	example.org
++192.0.0.83	example.org
++192.0.0.84	example.org
++192.0.0.85	example.org
++192.0.0.86	example.org
++192.0.0.87	example.org
++192.0.0.88	example.org
++192.0.0.89	example.org
++192.0.0.90	example.org
++192.0.0.91	example.org
++192.0.0.92	example.org
++192.0.0.93	example.org
++192.0.0.94	example.org
++192.0.0.95	example.org
++192.0.0.96	example.org
++192.0.0.97	example.org
++192.0.0.98	example.org
++192.0.0.99	example.org
++192.0.0.100	example.org
++192.0.0.101	example.org
++192.0.0.102	example.org
++192.0.0.103	example.org
++192.0.0.104	example.org
++192.0.0.105	example.org
++192.0.0.106	example.org
++192.0.0.107	example.org
++192.0.0.108	example.org
++192.0.0.109	example.org
++192.0.0.110	example.org
++192.0.0.111	example.org
++192.0.0.112	example.org
++192.0.0.113	example.org
++192.0.0.114	example.org
++192.0.0.115	example.org
++192.0.0.116	example.org
++192.0.0.117	example.org
++192.0.0.118	example.org
++192.0.0.119	example.org
++192.0.0.120	example.org
++192.0.0.121	example.org
++192.0.0.122	example.org
++192.0.0.123	example.org
++192.0.0.124	example.org
++192.0.0.125	example.org
++192.0.0.126	example.org
++192.0.0.127	example.org
++192.0.0.128	example.org
++192.0.0.129	example.org
++192.0.0.130	example.org
++192.0.0.131	example.org
++192.0.0.132	example.org
++192.0.0.133	example.org
++192.0.0.134	example.org
++192.0.0.135	example.org
++192.0.0.136	example.org
++192.0.0.137	example.org
++192.0.0.138	example.org
++192.0.0.139	example.org
++192.0.0.140	example.org
++192.0.0.141	example.org
++192.0.0.142	example.org
++192.0.0.143	example.org
++192.0.0.144	example.org
++192.0.0.145	example.org
++192.0.0.146	example.org
++192.0.0.147	example.org
++192.0.0.148	example.org
++192.0.0.149	example.org
++192.0.0.150	example.org
++192.0.0.151	example.org
++192.0.0.152	example.org
++192.0.0.153	example.org
++192.0.0.154	example.org
++192.0.0.155	example.org
++192.0.0.156	example.org
++192.0.0.157	example.org
++192.0.0.158	example.org
++192.0.0.159	example.org
++192.0.0.160	example.org
++192.0.0.161	example.org
++192.0.0.162	example.org
++192.0.0.163	example.org
++192.0.0.164	example.org
++192.0.0.165	example.org
++192.0.0.166	example.org
++192.0.0.167	example.org
++192.0.0.168	example.org
++192.0.0.169	example.org
++192.0.0.170	example.org
++192.0.0.171	example.org
++192.0.0.172	example.org
++192.0.0.173	example.org
++192.0.0.174	example.org
++192.0.0.175	example.org
++192.0.0.176	example.org
++192.0.0.177	example.org
++192.0.0.178	example.org
++192.0.0.179	example.org
++192.0.0.180	example.org
++192.0.0.181	example.org
++192.0.0.182	example.org
++192.0.0.183	example.org
++192.0.0.184	example.org
++192.0.0.185	example.org
++192.0.0.186	example.org
++192.0.0.187	example.org
++192.0.0.188	example.org
++192.0.0.189	example.org
++192.0.0.190	example.org
++192.0.0.191	example.org
++192.0.0.192	example.org
++192.0.0.193	example.org
++192.0.0.194	example.org
++192.0.0.195	example.org
++192.0.0.196	example.org
++192.0.0.197	example.org
++192.0.0.198	example.org
++192.0.0.199	example.org
++192.0.0.200	example.org
++192.0.0.201	example.org
++192.0.0.202	example.org
++192.0.0.203	example.org
++192.0.0.204	example.org
++192.0.0.205	example.org
++192.0.0.206	example.org
++192.0.0.207	example.org
++192.0.0.208	example.org
++192.0.0.209	example.org
++192.0.0.210	example.org
++192.0.0.211	example.org
++192.0.0.212	example.org
++192.0.0.213	example.org
++192.0.0.214	example.org
++192.0.0.215	example.org
++192.0.0.216	example.org
++192.0.0.217	example.org
++192.0.0.218	example.org
++192.0.0.219	example.org
++192.0.0.220	example.org
++192.0.0.221	example.org
++192.0.0.222	example.org
++192.0.0.223	example.org
++192.0.0.224	example.org
++192.0.0.225	example.org
++192.0.0.226	example.org
++192.0.0.227	example.org
++192.0.0.228	example.org
++192.0.0.229	example.org
++192.0.0.230	example.org
++192.0.0.231	example.org
++192.0.0.232	example.org
++192.0.0.233	example.org
++192.0.0.234	example.org
++192.0.0.235	example.org
++192.0.0.236	example.org
++192.0.0.237	example.org
++192.0.0.238	example.org
++192.0.0.239	example.org
++192.0.0.240	example.org
++192.0.0.241	example.org
++192.0.0.242	example.org
++192.0.0.243	example.org
++192.0.0.244	example.org
++192.0.0.245	example.org
++192.0.0.246	example.org
++192.0.0.247	example.org
++192.0.0.248	example.org
++192.0.0.249	example.org
++192.0.0.250	example.org
++192.0.0.251	example.org
++192.0.0.252	example.org
++192.0.0.253	example.org
++192.0.0.254	example.org
++192.0.1.1	example.org
++192.0.1.2	example.org
++192.0.1.3	example.org
++192.0.1.4	example.org
++192.0.1.5	example.org
++192.0.1.6	example.org
++192.0.1.7	example.org
++192.0.1.8	example.org
++192.0.1.9	example.org
++192.0.1.10	example.org
++192.0.1.11	example.org
++192.0.1.12	example.org
++192.0.1.13	example.org
++192.0.1.14	example.org
++192.0.1.15	example.org
++192.0.1.16	example.org
++192.0.1.17	example.org
++192.0.1.18	example.org
++192.0.1.19	example.org
++192.0.1.20	example.org
++192.0.1.21	example.org
++192.0.1.22	example.org
++192.0.1.23	example.org
++192.0.1.24	example.org
++192.0.1.25	example.org
++192.0.1.26	example.org
++192.0.1.27	example.org
++192.0.1.28	example.org
++192.0.1.29	example.org
++192.0.1.30	example.org
++192.0.1.31	example.org
++192.0.1.32	example.org
++192.0.1.33	example.org
++192.0.1.34	example.org
++192.0.1.35	example.org
++192.0.1.36	example.org
++192.0.1.37	example.org
++192.0.1.38	example.org
++192.0.1.39	example.org
++192.0.1.40	example.org
++192.0.1.41	example.org
++192.0.1.42	example.org
++192.0.1.43	example.org
++192.0.1.44	example.org
++192.0.1.45	example.org
++192.0.1.46	example.org
++192.0.1.47	example.org
++192.0.1.48	example.org
++192.0.1.49	example.org
++192.0.1.50	example.org
++192.0.1.51	example.org
++192.0.1.52	example.org
++192.0.1.53	example.org
++192.0.1.54	example.org
++192.0.1.55	example.org
++192.0.1.56	example.org
++192.0.1.57	example.org
++192.0.1.58	example.org
++192.0.1.59	example.org
++192.0.1.60	example.org
++192.0.1.61	example.org
++192.0.1.62	example.org
++192.0.1.63	example.org
++192.0.1.64	example.org
++192.0.1.65	example.org
++192.0.1.66	example.org
++192.0.1.67	example.org
++192.0.1.68	example.org
++192.0.1.69	example.org
++192.0.1.70	example.org
++192.0.1.71	example.org
++192.0.1.72	example.org
++192.0.1.73	example.org
++192.0.1.74	example.org
++192.0.1.75	example.org
++192.0.1.76	example.org
++192.0.1.77	example.org
++192.0.1.78	example.org
++192.0.1.79	example.org
++192.0.1.80	example.org
++192.0.1.81	example.org
++192.0.1.82	example.org
++192.0.1.83	example.org
++192.0.1.84	example.org
++192.0.1.85	example.org
++192.0.1.86	example.org
++192.0.1.87	example.org
++192.0.1.88	example.org
++192.0.1.89	example.org
++192.0.1.90	example.org
++192.0.1.91	example.org
++192.0.1.92	example.org
++192.0.1.93	example.org
++192.0.1.94	example.org
++192.0.1.95	example.org
++192.0.1.96	example.org
++192.0.1.97	example.org
++192.0.1.98	example.org
++192.0.1.99	example.org
++192.0.1.100	example.org
++192.0.1.101	example.org
++192.0.1.102	example.org
++192.0.1.103	example.org
++192.0.1.104	example.org
++192.0.1.105	example.org
++192.0.1.106	example.org
++192.0.1.107	example.org
++192.0.1.108	example.org
++192.0.1.109	example.org
++192.0.1.110	example.org
++192.0.1.111	example.org
++192.0.1.112	example.org
++192.0.1.113	example.org
++192.0.1.114	example.org
++192.0.1.115	example.org
++192.0.1.116	example.org
++192.0.1.117	example.org
++192.0.1.118	example.org
++192.0.1.119	example.org
++192.0.1.120	example.org
++192.0.1.121	example.org
++192.0.1.122	example.org
++192.0.1.123	example.org
++192.0.1.124	example.org
++192.0.1.125	example.org
++192.0.1.126	example.org
++192.0.1.127	example.org
++192.0.1.128	example.org
++192.0.1.129	example.org
++192.0.1.130	example.org
++192.0.1.131	example.org
++192.0.1.132	example.org
++192.0.1.133	example.org
++192.0.1.134	example.org
++192.0.1.135	example.org
++192.0.1.136	example.org
++192.0.1.137	example.org
++192.0.1.138	example.org
++192.0.1.139	example.org
++192.0.1.140	example.org
++192.0.1.141	example.org
++192.0.1.142	example.org
++192.0.1.143	example.org
++192.0.1.144	example.org
++192.0.1.145	example.org
++192.0.1.146	example.org
++192.0.1.147	example.org
++192.0.1.148	example.org
++192.0.1.149	example.org
++192.0.1.150	example.org
++192.0.1.151	example.org
++192.0.1.152	example.org
++192.0.1.153	example.org
++192.0.1.154	example.org
++192.0.1.155	example.org
++192.0.1.156	example.org
++192.0.1.157	example.org
++192.0.1.158	example.org
++192.0.1.159	example.org
++192.0.1.160	example.org
++192.0.1.161	example.org
++192.0.1.162	example.org
++192.0.1.163	example.org
++192.0.1.164	example.org
++192.0.1.165	example.org
++192.0.1.166	example.org
++192.0.1.167	example.org
++192.0.1.168	example.org
++192.0.1.169	example.org
++192.0.1.170	example.org
++192.0.1.171	example.org
++192.0.1.172	example.org
++192.0.1.173	example.org
++192.0.1.174	example.org
++192.0.1.175	example.org
++192.0.1.176	example.org
++192.0.1.177	example.org
++192.0.1.178	example.org
++192.0.1.179	example.org
++192.0.1.180	example.org
++192.0.1.181	example.org
++192.0.1.182	example.org
++192.0.1.183	example.org
++192.0.1.184	example.org
++192.0.1.185	example.org
++192.0.1.186	example.org
++192.0.1.187	example.org
++192.0.1.188	example.org
++192.0.1.189	example.org
++192.0.1.190	example.org
++192.0.1.191	example.org
++192.0.1.192	example.org
++192.0.1.193	example.org
++192.0.1.194	example.org
++192.0.1.195	example.org
++192.0.1.196	example.org
++192.0.1.197	example.org
++192.0.1.198	example.org
++192.0.1.199	example.org
++192.0.1.200	example.org
++192.0.1.201	example.org
++192.0.1.202	example.org
++192.0.1.203	example.org
++192.0.1.204	example.org
++192.0.1.205	example.org
++192.0.1.206	example.org
++192.0.1.207	example.org
++192.0.1.208	example.org
++192.0.1.209	example.org
++192.0.1.210	example.org
++192.0.1.211	example.org
++192.0.1.212	example.org
++192.0.1.213	example.org
++192.0.1.214	example.org
++192.0.1.215	example.org
++192.0.1.216	example.org
++192.0.1.217	example.org
++192.0.1.218	example.org
++192.0.1.219	example.org
++192.0.1.220	example.org
++192.0.1.221	example.org
++192.0.1.222	example.org
++192.0.1.223	example.org
++192.0.1.224	example.org
++192.0.1.225	example.org
++192.0.1.226	example.org
++192.0.1.227	example.org
++192.0.1.228	example.org
++192.0.1.229	example.org
++192.0.1.230	example.org
++192.0.1.231	example.org
++192.0.1.232	example.org
++192.0.1.233	example.org
++192.0.1.234	example.org
++192.0.1.235	example.org
++192.0.1.236	example.org
++192.0.1.237	example.org
++192.0.1.238	example.org
++192.0.1.239	example.org
++192.0.1.240	example.org
++192.0.1.241	example.org
++192.0.1.242	example.org
++192.0.1.243	example.org
++192.0.1.244	example.org
++192.0.1.245	example.org
++192.0.1.246	example.org
++192.0.1.247	example.org
++192.0.1.248	example.org
++192.0.1.249	example.org
++192.0.1.250	example.org
++192.0.1.251	example.org
++192.0.1.252	example.org
++192.0.1.253	example.org
++192.0.1.254	example.org
+diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
+index fae3dea81f19dba6..4fa963644af8b7d5 100644
+--- a/sysdeps/posix/getaddrinfo.c
++++ b/sysdeps/posix/getaddrinfo.c
+@@ -474,11 +474,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 
+   if (name != NULL)
+     {
+-      at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
+-      at->family = AF_UNSPEC;
+-      at->scopeid = 0;
+-      at->next = NULL;
+-
+       if (req->ai_flags & AI_IDN)
+ 	{
+ 	  char *out;
+@@ -489,13 +484,21 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 	  malloc_name = true;
+ 	}
+ 
+-      if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
++      uint32_t addr[4];
++      if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
+ 	{
++	  at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
++	  at->scopeid = 0;
++	  at->next = NULL;
++
+ 	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
+-	    at->family = AF_INET;
++	    {
++	      memcpy (at->addr, addr, sizeof (at->addr));
++	      at->family = AF_INET;
++	    }
+ 	  else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
+ 	    {
+-	      at->addr[3] = at->addr[0];
++	      at->addr[3] = addr[0];
+ 	      at->addr[2] = htonl (0xffff);
+ 	      at->addr[1] = 0;
+ 	      at->addr[0] = 0;
+@@ -509,49 +512,62 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 
+ 	  if (req->ai_flags & AI_CANONNAME)
+ 	    canon = name;
++
++	  goto process_list;
+ 	}
+-      else if (at->family == AF_UNSPEC)
++
++      char *scope_delim = strchr (name, SCOPE_DELIMITER);
++      int e;
++
++      if (scope_delim == NULL)
++	e = inet_pton (AF_INET6, name, addr);
++      else
++	e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
++
++      if (e > 0)
+ 	{
+-	  char *scope_delim = strchr (name, SCOPE_DELIMITER);
+-	  int e;
+-	  if (scope_delim == NULL)
+-	    e = inet_pton (AF_INET6, name, at->addr);
++	  at = alloca_account (sizeof (struct gaih_addrtuple),
++			       alloca_used);
++	  at->scopeid = 0;
++	  at->next = NULL;
++
++	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
++	    {
++	      memcpy (at->addr, addr, sizeof (at->addr));
++	      at->family = AF_INET6;
++	    }
++	  else if (req->ai_family == AF_INET
++		   && IN6_IS_ADDR_V4MAPPED (addr))
++	    {
++	      at->addr[0] = addr[3];
++	      at->addr[1] = addr[1];
++	      at->addr[2] = addr[2];
++	      at->addr[3] = addr[3];
++	      at->family = AF_INET;
++	    }
+ 	  else
+-	    e = __inet_pton_length (AF_INET6, name, scope_delim - name,
+-				    at->addr);
+-	  if (e > 0)
+ 	    {
+-	      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+-		at->family = AF_INET6;
+-	      else if (req->ai_family == AF_INET
+-		       && IN6_IS_ADDR_V4MAPPED (at->addr))
+-		{
+-		  at->addr[0] = at->addr[3];
+-		  at->family = AF_INET;
+-		}
+-	      else
+-		{
+-		  result = -EAI_ADDRFAMILY;
+-		  goto free_and_return;
+-		}
+-
+-	      if (scope_delim != NULL
+-		  && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
+-					   scope_delim + 1,
+-					   &at->scopeid) != 0)
+-		{
+-		  result = -EAI_NONAME;
+-		  goto free_and_return;
+-		}
++	      result = -EAI_ADDRFAMILY;
++	      goto free_and_return;
++	    }
+ 
+-	      if (req->ai_flags & AI_CANONNAME)
+-		canon = name;
++	  if (scope_delim != NULL
++	      && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
++				       scope_delim + 1,
++				       &at->scopeid) != 0)
++	    {
++	      result = -EAI_NONAME;
++	      goto free_and_return;
+ 	    }
++
++	  if (req->ai_flags & AI_CANONNAME)
++	    canon = name;
++
++	  goto process_list;
+ 	}
+ 
+-      if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
++      if ((req->ai_flags & AI_NUMERICHOST) == 0)
+ 	{
+-	  struct gaih_addrtuple **pat = &at;
+ 	  int no_data = 0;
+ 	  int no_inet6_data = 0;
+ 	  service_user *nip;
+@@ -560,6 +576,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 	  int no_more;
+ 	  struct resolv_context *res_ctx = NULL;
+ 	  bool res_enable_inet6 = false;
++	  bool do_merge = false;
+ 
+ 	  /* If we do not have to look for IPv6 addresses or the canonical
+ 	     name, use the simple, old functions, which do not support
+@@ -596,7 +613,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 			  result = -EAI_MEMORY;
+ 			  goto free_and_return;
+ 			}
+-		      *pat = addrmem;
++		      at = addrmem;
+ 		    }
+ 		  else
+ 		    {
+@@ -649,6 +666,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 		    }
+ 
+ 		  struct gaih_addrtuple *addrfree = addrmem;
++		  struct gaih_addrtuple **pat = &at;
++
+ 		  for (int i = 0; i < air->naddrs; ++i)
+ 		    {
+ 		      socklen_t size = (air->family[i] == AF_INET
+@@ -712,12 +731,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 
+ 		  free (air);
+ 
+-		  if (at->family == AF_UNSPEC)
+-		    {
+-		      result = -EAI_NONAME;
+-		      goto free_and_return;
+-		    }
+-
+ 		  goto process_list;
+ 		}
+ 	      else if (err == 0)
+@@ -756,6 +769,22 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 
+ 	  while (!no_more)
+ 	    {
++	      /* Always start afresh; continue should discard previous results
++		 and the hosts database does not support merge.  */
++	      at = NULL;
++	      free (canonbuf);
++	      free (addrmem);
++	      canon = canonbuf = NULL;
++	      addrmem = NULL;
++	      got_ipv6 = false;
++
++	      if (do_merge)
++		{
++		  __set_h_errno (NETDB_INTERNAL);
++		  __set_errno (EBUSY);
++		  break;
++		}
++
+ 	      no_data = 0;
+ 	      nss_gethostbyname4_r fct4 = NULL;
+ 
+@@ -768,12 +797,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 		{
+ 		  while (1)
+ 		    {
+-		      status = DL_CALL_FCT (fct4, (name, pat,
++		      status = DL_CALL_FCT (fct4, (name, &at,
+ 						   tmpbuf->data, tmpbuf->length,
+ 						   &errno, &h_errno,
+ 						   NULL));
+ 		      if (status == NSS_STATUS_SUCCESS)
+ 			break;
++		      /* gethostbyname4_r may write into AT, so reset it.  */
++		      at = NULL;
+ 		      if (status != NSS_STATUS_TRYAGAIN
+ 			  || errno != ERANGE || h_errno != NETDB_INTERNAL)
+ 			{
+@@ -800,7 +831,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 		      no_data = 1;
+ 
+ 		      if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
+-			canon = (*pat)->name;
++			canon = at->name;
++
++		      struct gaih_addrtuple **pat = &at;
+ 
+ 		      while (*pat != NULL)
+ 			{
+@@ -852,6 +885,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 
+ 		  if (fct != NULL)
+ 		    {
++		      struct gaih_addrtuple **pat = &at;
++
+ 		      if (req->ai_family == AF_INET6
+ 			  || req->ai_family == AF_UNSPEC)
+ 			{
+@@ -927,6 +962,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 	      if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
+ 		break;
+ 
++	      /* The hosts database does not support MERGE.  */
++	      if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
++		do_merge = true;
++
+ 	      if (nip->next == NULL)
+ 		no_more = -1;
+ 	      else
+@@ -960,7 +999,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
+ 	}
+ 
+     process_list:
+-      if (at->family == AF_UNSPEC)
++      if (at == NULL)
+ 	{
+ 	  result = -EAI_NONAME;
+ 	  goto free_and_return;
diff --git a/SOURCES/glibc-rh2233338-1.patch b/SOURCES/glibc-rh2233338-1.patch
deleted file mode 100644
index b865e85..0000000
--- a/SOURCES/glibc-rh2233338-1.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-commit 7b5bfe77836442b9aeb75cc520f0d1eb7f82be67
-Author: Florian Weimer <fweimer@redhat.com>
-Date:   Mon May 18 15:21:04 2020 +0200
-
-    elf: Assert that objects are relocated before their constructors run
-    
-    If we try to run constructors before relocation, this is always
-    a dynamic linker bug.  An assert is easier to notice than a call
-    via an invalid function pointer (which may not even produce a valid
-    call stack).
-    
-    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
-
-diff --git a/elf/dl-init.c b/elf/dl-init.c
-index 45405cd0563845b4..99ce531d7b326f5f 100644
---- a/elf/dl-init.c
-+++ b/elf/dl-init.c
-@@ -16,6 +16,7 @@
-    License along with the GNU C Library; if not, see
-    <http://www.gnu.org/licenses/>.  */
- 
-+#include <assert.h>
- #include <stddef.h>
- #include <ldsodefs.h>
- 
-@@ -27,6 +28,11 @@ typedef void (*init_t) (int, char **, char **);
- static void
- call_init (struct link_map *l, int argc, char **argv, char **env)
- {
-+  /* If the object has not been relocated, this is a bug.  The
-+     function pointers are invalid in this case.  (Executables do not
-+     need relocation, and neither do proxy objects.)  */
-+  assert (l->l_real->l_relocated || l->l_real->l_type == lt_executable);
-+
-   if (l->l_init_called)
-     /* This object is all done.  */
-     return;
diff --git a/SOURCES/glibc-rh2233338-2.patch b/SOURCES/glibc-rh2233338-2.patch
deleted file mode 100644
index 84e10da..0000000
--- a/SOURCES/glibc-rh2233338-2.patch
+++ /dev/null
@@ -1,237 +0,0 @@
-commit 6f360366f7f76b158a0f4bf20d42f2854ad56264
-Author: Florian Weimer <fweimer@redhat.com>
-Date:   Thu Oct 27 11:36:44 2022 +0200
-
-    elf: Introduce to _dl_call_fini
-    
-    This consolidates the destructor invocations from _dl_fini and
-    dlclose.  Remove the micro-optimization that avoids
-    calling _dl_call_fini if they are no destructors (as dlclose is quite
-    expensive anyway).  The debug log message is now printed
-    unconditionally.
-    
-    Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
-
-Conflicts:
-	elf/dl-fini.c
-	  (Missing ELF_INITFINI support downstream.)
-	sysdeps/generic/ldsodefs.h
-	  (Missing dl_init_t declaration downstream.)
-
-diff --git a/elf/Makefile b/elf/Makefile
-index 634c3113227d64a6..040d82e243a80c0f 100644
---- a/elf/Makefile
-+++ b/elf/Makefile
-@@ -50,6 +50,7 @@ routines = \
- # profiled libraries.
- dl-routines = \
-   dl-call-libc-early-init \
-+  dl-call_fini \
-   dl-close \
-   dl-debug \
-   dl-deps \
-diff --git a/elf/dl-call_fini.c b/elf/dl-call_fini.c
-new file mode 100644
-index 0000000000000000..9e7ba10fa2a4df77
---- /dev/null
-+++ b/elf/dl-call_fini.c
-@@ -0,0 +1,50 @@
-+/* Invoke DT_FINI and DT_FINI_ARRAY callbacks.
-+   Copyright (C) 1996-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 <ldsodefs.h>
-+#include <sysdep.h>
-+
-+void
-+_dl_call_fini (void *closure_map)
-+{
-+  struct link_map *map = closure_map;
-+
-+  /* When debugging print a message first.  */
-+  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
-+    _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", map->l_name, map->l_ns);
-+
-+  /* Make sure nothing happens if we are called twice.  */
-+  map->l_init_called = 0;
-+
-+  ElfW(Dyn) *fini_array = map->l_info[DT_FINI_ARRAY];
-+  if (fini_array != NULL)
-+    {
-+      ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr
-+                                          + fini_array->d_un.d_ptr);
-+      size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
-+                   / sizeof (ElfW(Addr)));
-+
-+      while (sz-- > 0)
-+        ((fini_t) array[sz]) ();
-+    }
-+
-+  /* Next try the old-style destructor.  */
-+  ElfW(Dyn) *fini = map->l_info[DT_FINI];
-+  if (fini != NULL)
-+    DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr));
-+}
-diff --git a/elf/dl-close.c b/elf/dl-close.c
-index 22225efb3226c3e1..26ea51dfbadc5b85 100644
---- a/elf/dl-close.c
-+++ b/elf/dl-close.c
-@@ -35,11 +35,6 @@
- 
- #include <dl-unmap-segments.h>
- 
--
--/* Type of the constructor functions.  */
--typedef void (*fini_t) (void);
--
--
- /* Special l_idx value used to indicate which objects remain loaded.  */
- #define IDX_STILL_USED -1
- 
-@@ -109,31 +104,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
-   return false;
- }
- 
--/* Invoke dstructors for CLOSURE (a struct link_map *).  Called with
--   exception handling temporarily disabled, to make errors fatal.  */
--static void
--call_destructors (void *closure)
--{
--  struct link_map *map = closure;
--
--  if (map->l_info[DT_FINI_ARRAY] != NULL)
--    {
--      ElfW(Addr) *array =
--	(ElfW(Addr) *) (map->l_addr
--			+ map->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
--      unsigned int sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
--			 / sizeof (ElfW(Addr)));
--
--      while (sz-- > 0)
--	((fini_t) array[sz]) ();
--    }
--
--  /* Next try the old-style destructor.  */
--  if (map->l_info[DT_FINI] != NULL)
--    DL_CALL_DT_FINI (map, ((void *) map->l_addr
--			   + map->l_info[DT_FINI]->d_un.d_ptr));
--}
--
- void
- _dl_close_worker (struct link_map *map, bool force)
- {
-@@ -279,17 +249,7 @@ _dl_close_worker (struct link_map *map, bool force)
- 	     half-cooked objects.  Temporarily disable exception
- 	     handling, so that errors are fatal.  */
- 	  if (imap->l_init_called)
--	    {
--	      /* When debugging print a message first.  */
--	      if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
--				    0))
--		_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
--				  imap->l_name, nsid);
--
--	      if (imap->l_info[DT_FINI_ARRAY] != NULL
--		  || imap->l_info[DT_FINI] != NULL)
--		_dl_catch_exception (NULL, call_destructors, imap);
--	    }
-+	    _dl_catch_exception (NULL, _dl_call_fini, imap);
- 
- #ifdef SHARED
- 	  /* Auditing checkpoint: we remove an object.  */
-diff --git a/elf/dl-fini.c b/elf/dl-fini.c
-index e14259a3c8806e0d..2d34658d4c3a470c 100644
---- a/elf/dl-fini.c
-+++ b/elf/dl-fini.c
-@@ -20,11 +20,6 @@
- #include <string.h>
- #include <ldsodefs.h>
- 
--
--/* Type of the constructor functions.  */
--typedef void (*fini_t) (void);
--
--
- void
- _dl_fini (void)
- {
-@@ -115,38 +110,7 @@ _dl_fini (void)
- 
- 	      if (l->l_init_called)
- 		{
--		  /* Make sure nothing happens if we are called twice.  */
--		  l->l_init_called = 0;
--
--		  /* Is there a destructor function?  */
--		  if (l->l_info[DT_FINI_ARRAY] != NULL
--		      || l->l_info[DT_FINI] != NULL)
--		    {
--		      /* When debugging print a message first.  */
--		      if (__builtin_expect (GLRO(dl_debug_mask)
--					    & DL_DEBUG_IMPCALLS, 0))
--			_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
--					  DSO_FILENAME (l->l_name),
--					  ns);
--
--		      /* First see whether an array is given.  */
--		      if (l->l_info[DT_FINI_ARRAY] != NULL)
--			{
--			  ElfW(Addr) *array =
--			    (ElfW(Addr) *) (l->l_addr
--					    + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
--			  unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
--					    / sizeof (ElfW(Addr)));
--			  while (i-- > 0)
--			    ((fini_t) array[i]) ();
--			}
--
--		      /* Next try the old-style destructor.  */
--		      if (l->l_info[DT_FINI] != NULL)
--			DL_CALL_DT_FINI
--			  (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr);
--		    }
--
-+		  _dl_call_fini (l);
- #ifdef SHARED
- 		  /* Auditing checkpoint: another object closed.  */
- 		  _dl_audit_objclose (l);
-diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
-index 29bbde3e83e37d7e..0bad34d44a5685d9 100644
---- a/sysdeps/generic/ldsodefs.h
-+++ b/sysdeps/generic/ldsodefs.h
-@@ -93,6 +93,9 @@ typedef struct link_map *lookup_t;
-    : (__glibc_unlikely ((ref)->st_shndx == SHN_ABS) ? 0			\
-       : LOOKUP_VALUE_ADDRESS (map, map_set)) + (ref)->st_value)
- 
-+/* Type of a constructor function, in DT_FINI, DT_FINI_ARRAY.  */
-+typedef void (*fini_t) (void);
-+
- /* On some architectures a pointer to a function is not just a pointer
-    to the actual code of the function but rather an architecture
-    specific descriptor. */
-@@ -1047,6 +1050,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;
- 
-+/* Invoke the DT_FINI_ARRAY and DT_FINI destructors for MAP, which
-+   must be a struct link_map *.  Can be used as an argument to
-+   _dl_catch_exception.  */
-+void _dl_call_fini (void *map) attribute_hidden;
-+
- /* Sort array MAPS according to dependencies of the contained objects.
-    If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies
-    say otherwise.  */
diff --git a/SOURCES/glibc-rh2233338-3.patch b/SOURCES/glibc-rh2233338-3.patch
deleted file mode 100644
index 1627d06..0000000
--- a/SOURCES/glibc-rh2233338-3.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-commit f6c8204fd7fabf0cf4162eaf10ccf23258e4d10e
-Author: Florian Weimer <fweimer@redhat.com>
-Date:   Tue Aug 22 13:56:25 2023 +0200
-
-    elf: Do not run constructors for proxy objects
-    
-    Otherwise, the ld.so constructor runs for each audit namespace
-    and each dlmopen namespace.
-
-diff --git a/elf/dl-init.c b/elf/dl-init.c
-index 99ce531d7b326f5f..73c0259fbe6d19af 100644
---- a/elf/dl-init.c
-+++ b/elf/dl-init.c
-@@ -28,10 +28,14 @@ typedef void (*init_t) (int, char **, char **);
- static void
- call_init (struct link_map *l, int argc, char **argv, char **env)
- {
-+  /* Do not run constructors for proxy objects.  */
-+  if (l != l->l_real)
-+    return;
-+
-   /* If the object has not been relocated, this is a bug.  The
-      function pointers are invalid in this case.  (Executables do not
--     need relocation, and neither do proxy objects.)  */
--  assert (l->l_real->l_relocated || l->l_real->l_type == lt_executable);
-+     need relocation.)  */
-+  assert (l->l_relocated || l->l_type == lt_executable);
- 
-   if (l->l_init_called)
-     /* This object is all done.  */
diff --git a/SOURCES/glibc-rh2233338-4.patch b/SOURCES/glibc-rh2233338-4.patch
deleted file mode 100644
index 8db76e4..0000000
--- a/SOURCES/glibc-rh2233338-4.patch
+++ /dev/null
@@ -1,637 +0,0 @@
-commit 6985865bc3ad5b23147ee73466583dd7fdf65892
-Author: Florian Weimer <fweimer@redhat.com>
-Date:   Fri Sep 8 12:32:14 2023 +0200
-
-    elf: Always call destructors in reverse constructor order (bug 30785)
-    
-    The current implementation of dlclose (and process exit) re-sorts the
-    link maps before calling ELF destructors.  Destructor order is not the
-    reverse of the constructor order as a result: The second sort takes
-    relocation dependencies into account, and other differences can result
-    from ambiguous inputs, such as cycles.  (The force_first handling in
-    _dl_sort_maps is not effective for dlclose.)  After the changes in
-    this commit, there is still a required difference due to
-    dlopen/dlclose ordering by the application, but the previous
-    discrepancies went beyond that.
-    
-    A new global (namespace-spanning) list of link maps,
-    _dl_init_called_list, is updated right before ELF constructors are
-    called from _dl_init.
-    
-    In dl_close_worker, the maps variable, an on-stack variable length
-    array, is eliminated.  (VLAs are problematic, and dlclose should not
-    call malloc because it cannot readily deal with malloc failure.)
-    Marking still-used objects uses the namespace list directly, with
-    next and next_idx replacing the done_index variable.
-    
-    After marking, _dl_init_called_list is used to call the destructors
-    of now-unused maps in reverse destructor order.  These destructors
-    can call dlopen.  Previously, new objects do not have l_map_used set.
-    This had to change: There is no copy of the link map list anymore,
-    so processing would cover newly opened (and unmarked) mappings,
-    unloading them.  Now, _dl_init (indirectly) sets l_map_used, too.
-    (dlclose is handled by the existing reentrancy guard.)
-    
-    After _dl_init_called_list traversal, two more loops follow.  The
-    processing order changes to the original link map order in the
-    namespace.  Previously, dependency order was used.  The difference
-    should not matter because relocation dependencies could already
-    reorder link maps in the old code.
-    
-    The changes to _dl_fini remove the sorting step and replace it with
-    a traversal of _dl_init_called_list.  The l_direct_opencount
-    decrement outside the loader lock is removed because it appears
-    incorrect: the counter manipulation could race with other dynamic
-    loader operations.
-    
-    tst-audit23 needs adjustments to the changes in LA_ACT_DELETE
-    notifications.  The new approach for checking la_activity should
-    make it clearer that la_activty calls come in pairs around namespace
-    updates.
-    
-    The dependency sorting test cases need updates because the destructor
-    order is always the opposite order of constructor order, even with
-    relocation dependencies or cycles present.
-    
-    There is a future cleanup opportunity to remove the now-constant
-    force_first and for_fini arguments from the _dl_sort_maps function.
-    
-    Fixes commit 1df71d32fe5f5905ffd5d100e5e9ca8ad62 ("elf: Implement
-    force_first handling in _dl_sort_maps_dfs (bug 28937)").
-    
-    Reviewed-by: DJ Delorie <dj@redhat.com>
-
-diff --git a/elf/dl-close.c b/elf/dl-close.c
-index 26ea51dfbadc5b85..6b134f66628cfc03 100644
---- a/elf/dl-close.c
-+++ b/elf/dl-close.c
-@@ -137,30 +137,31 @@ _dl_close_worker (struct link_map *map, bool force)
- 
-   bool any_tls = false;
-   const unsigned int nloaded = ns->_ns_nloaded;
--  struct link_map *maps[nloaded];
- 
--  /* Run over the list and assign indexes to the link maps and enter
--     them into the MAPS array.  */
-+  /* Run over the list and assign indexes to the link maps.  */
-   int idx = 0;
-   for (struct link_map *l = ns->_ns_loaded; l != NULL; l = l->l_next)
-     {
-       l->l_map_used = 0;
-       l->l_map_done = 0;
-       l->l_idx = idx;
--      maps[idx] = l;
-       ++idx;
-     }
-   assert (idx == nloaded);
- 
--  /* Keep track of the lowest index link map we have covered already.  */
--  int done_index = -1;
--  while (++done_index < nloaded)
-+  /* Keep marking link maps until no new link maps are found.  */
-+  for (struct link_map *l = ns->_ns_loaded; l != NULL; )
-     {
--      struct link_map *l = maps[done_index];
-+      /* next is reset to earlier link maps for remarking.  */
-+      struct link_map *next = l->l_next;
-+      int next_idx = l->l_idx + 1; /* next->l_idx, but covers next == NULL.  */
- 
-       if (l->l_map_done)
--	/* Already handled.  */
--	continue;
-+	{
-+	  /* Already handled.  */
-+	  l = next;
-+	  continue;
-+	}
- 
-       /* Check whether this object is still used.  */
-       if (l->l_type == lt_loaded
-@@ -170,7 +171,10 @@ _dl_close_worker (struct link_map *map, bool force)
- 	     acquire is sufficient and correct.  */
- 	  && atomic_load_acquire (&l->l_tls_dtor_count) == 0
- 	  && !l->l_map_used)
--	continue;
-+	{
-+	  l = next;
-+	  continue;
-+	}
- 
-       /* We need this object and we handle it now.  */
-       l->l_map_used = 1;
-@@ -197,8 +201,11 @@ _dl_close_worker (struct link_map *map, bool force)
- 			 already processed it, then we need to go back
- 			 and process again from that point forward to
- 			 ensure we keep all of its dependencies also.  */
--		      if ((*lp)->l_idx - 1 < done_index)
--			done_index = (*lp)->l_idx - 1;
-+		      if ((*lp)->l_idx < next_idx)
-+			{
-+			  next = *lp;
-+			  next_idx = next->l_idx;
-+			}
- 		    }
- 		}
- 
-@@ -218,44 +225,65 @@ _dl_close_worker (struct link_map *map, bool force)
- 		if (!jmap->l_map_used)
- 		  {
- 		    jmap->l_map_used = 1;
--		    if (jmap->l_idx - 1 < done_index)
--		      done_index = jmap->l_idx - 1;
-+		    if (jmap->l_idx < next_idx)
-+		      {
-+			  next = jmap;
-+			  next_idx = next->l_idx;
-+		      }
- 		  }
- 	      }
- 	  }
--    }
- 
--  /* Sort the entries.  We can skip looking for the binary itself which is
--     at the front of the search list for the main namespace.  */
--  _dl_sort_maps (maps, nloaded, (nsid == LM_ID_BASE), true);
-+      l = next;
-+    }
- 
--  /* Call all termination functions at once.  */
--  bool unload_any = false;
--  bool scope_mem_left = false;
--  unsigned int unload_global = 0;
--  unsigned int first_loaded = ~0;
--  for (unsigned int i = 0; i < nloaded; ++i)
-+  /* Call the destructors in reverse constructor order, and remove the
-+     closed link maps from the list.  */
-+  for (struct link_map **init_called_head = &_dl_init_called_list;
-+       *init_called_head != NULL; )
-     {
--      struct link_map *imap = maps[i];
-+      struct link_map *imap = *init_called_head;
- 
--      /* All elements must be in the same namespace.  */
--      assert (imap->l_ns == nsid);
--
--      if (!imap->l_map_used)
-+      /* _dl_init_called_list is global, to produce a global odering.
-+	 Ignore the other namespaces (and link maps that are still used).  */
-+      if (imap->l_ns != nsid || imap->l_map_used)
-+	init_called_head = &imap->l_init_called_next;
-+      else
- 	{
- 	  assert (imap->l_type == lt_loaded && !imap->l_nodelete_active);
- 
--	  /* Call its termination function.  Do not do it for
--	     half-cooked objects.  Temporarily disable exception
--	     handling, so that errors are fatal.  */
--	  if (imap->l_init_called)
-+	  /* _dl_init_called_list is updated at the same time as
-+	     l_init_called.  */
-+	  assert (imap->l_init_called);
-+
-+	  if (imap->l_info[DT_FINI_ARRAY] != NULL
-+	      || imap->l_info[DT_FINI] != NULL)
- 	    _dl_catch_exception (NULL, _dl_call_fini, imap);
- 
- #ifdef SHARED
- 	  /* Auditing checkpoint: we remove an object.  */
- 	  _dl_audit_objclose (imap);
- #endif
-+	  /* Unlink this link map.  */
-+	  *init_called_head = imap->l_init_called_next;
-+	}
-+    }
-+
-+
-+  bool unload_any = false;
-+  bool scope_mem_left = false;
-+  unsigned int unload_global = 0;
-+
-+  /* For skipping un-unloadable link maps in the second loop.  */
-+  struct link_map *first_loaded = ns->_ns_loaded;
- 
-+  /* Iterate over the namespace to find objects to unload.  Some
-+     unloadable objects may not be on _dl_init_called_list due to
-+     dlopen failure.  */
-+  for (struct link_map *imap = first_loaded; imap != NULL; imap = imap->l_next)
-+    {
-+      if (!imap->l_map_used)
-+	{
- 	  /* This object must not be used anymore.  */
- 	  imap->l_removed = 1;
- 
-@@ -266,8 +294,8 @@ _dl_close_worker (struct link_map *map, bool force)
- 	    ++unload_global;
- 
- 	  /* Remember where the first dynamically loaded object is.  */
--	  if (i < first_loaded)
--	    first_loaded = i;
-+	  if (first_loaded == NULL)
-+	      first_loaded = imap;
- 	}
-       /* Else imap->l_map_used.  */
-       else if (imap->l_type == lt_loaded)
-@@ -403,8 +431,8 @@ _dl_close_worker (struct link_map *map, bool force)
- 	    imap->l_loader = NULL;
- 
- 	  /* Remember where the first dynamically loaded object is.  */
--	  if (i < first_loaded)
--	    first_loaded = i;
-+	  if (first_loaded == NULL)
-+	      first_loaded = imap;
- 	}
-     }
- 
-@@ -475,10 +503,11 @@ _dl_close_worker (struct link_map *map, bool force)
- 
-   /* Check each element of the search list to see if all references to
-      it are gone.  */
--  for (unsigned int i = first_loaded; i < nloaded; ++i)
-+  for (struct link_map *imap = first_loaded; imap != NULL; )
-     {
--      struct link_map *imap = maps[i];
--      if (!imap->l_map_used)
-+      if (imap->l_map_used)
-+	imap = imap->l_next;
-+      else
- 	{
- 	  assert (imap->l_type == lt_loaded);
- 
-@@ -686,7 +715,9 @@ _dl_close_worker (struct link_map *map, bool force)
- 	  if (imap == GL(dl_initfirst))
- 	    GL(dl_initfirst) = NULL;
- 
-+	  struct link_map *next = imap->l_next;
- 	  free (imap);
-+	  imap = next;
- 	}
-     }
- 
-diff --git a/elf/dl-fini.c b/elf/dl-fini.c
-index 2d34658d4c3a470c..25a7767d707721d5 100644
---- a/elf/dl-fini.c
-+++ b/elf/dl-fini.c
-@@ -23,116 +23,68 @@
- void
- _dl_fini (void)
- {
--  /* Lots of fun ahead.  We have to call the destructors for all still
--     loaded objects, in all namespaces.  The problem is that the ELF
--     specification now demands that dependencies between the modules
--     are taken into account.  I.e., the destructor for a module is
--     called before the ones for any of its dependencies.
--
--     To make things more complicated, we cannot simply use the reverse
--     order of the constructors.  Since the user might have loaded objects
--     using `dlopen' there are possibly several other modules with its
--     dependencies to be taken into account.  Therefore we have to start
--     determining the order of the modules once again from the beginning.  */
--
--  /* We run the destructors of the main namespaces last.  As for the
--     other namespaces, we pick run the destructors in them in reverse
--     order of the namespace ID.  */
--#ifdef SHARED
--  int do_audit = 0;
-- again:
--#endif
--  for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns)
--    {
--      /* Protect against concurrent loads and unloads.  */
--      __rtld_lock_lock_recursive (GL(dl_load_lock));
--
--      unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
--      /* No need to do anything for empty namespaces or those used for
--	 auditing DSOs.  */
--      if (nloaded == 0
--#ifdef SHARED
--	  || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
--#endif
--	  )
--	__rtld_lock_unlock_recursive (GL(dl_load_lock));
--      else
--	{
-+  /* Call destructors strictly in the reverse order of constructors.
-+     This causes fewer surprises than some arbitrary reordering based
-+     on new (relocation) dependencies.  None of the objects are
-+     unmapped, so applications can deal with this if their DSOs remain
-+     in a consistent state after destructors have run.  */
-+
-+  /* Protect against concurrent loads and unloads.  */
-+  __rtld_lock_lock_recursive (GL(dl_load_lock));
-+
-+  /* Ignore objects which are opened during shutdown.  */
-+  struct link_map *local_init_called_list = _dl_init_called_list;
-+
-+  for (struct link_map *l = local_init_called_list; l != NULL;
-+       l = l->l_init_called_next)
-+      /* Bump l_direct_opencount of all objects so that they
-+	 are not dlclose()ed from underneath us.  */
-+      ++l->l_direct_opencount;
-+
-+  /* After this point, everything linked from local_init_called_list
-+     cannot be unloaded because of the reference counter update.  */
-+  __rtld_lock_unlock_recursive (GL(dl_load_lock));
-+
-+  /* Perform two passes: One for non-audit modules, one for audit
-+     modules.  This way, audit modules receive unload notifications
-+     for non-audit objects, and the destructors for audit modules
-+     still run.  */
- #ifdef SHARED
--	  _dl_audit_activity_nsid (ns, LA_ACT_DELETE);
-+  int last_pass = GLRO(dl_naudit) > 0;
-+  Lmid_t last_ns = -1;
-+  for (int do_audit = 0; do_audit <= last_pass; ++do_audit)
- #endif
--
--	  /* Now we can allocate an array to hold all the pointers and
--	     copy the pointers in.  */
--	  struct link_map *maps[nloaded];
--
--	  unsigned int i;
--	  struct link_map *l;
--	  assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
--	  for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
--	    /* Do not handle ld.so in secondary namespaces.  */
--	    if (l == l->l_real)
--	      {
--		assert (i < nloaded);
--
--		maps[i] = l;
--		l->l_idx = i;
--		++i;
--
--		/* Bump l_direct_opencount of all objects so that they
--		   are not dlclose()ed from underneath us.  */
--		++l->l_direct_opencount;
--	      }
--	  assert (ns != LM_ID_BASE || i == nloaded);
--	  assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
--	  unsigned int nmaps = i;
--
--	  /* Now we have to do the sorting.  We can skip looking for the
--	     binary itself which is at the front of the search list for
--	     the main namespace.  */
--	  _dl_sort_maps (maps, nmaps, (ns == LM_ID_BASE), true);
--
--	  /* We do not rely on the linked list of loaded object anymore
--	     from this point on.  We have our own list here (maps).  The
--	     various members of this list cannot vanish since the open
--	     count is too high and will be decremented in this loop.  So
--	     we release the lock so that some code which might be called
--	     from a destructor can directly or indirectly access the
--	     lock.  */
--	  __rtld_lock_unlock_recursive (GL(dl_load_lock));
--
--	  /* 'maps' now contains the objects in the right order.  Now
--	     call the destructors.  We have to process this array from
--	     the front.  */
--	  for (i = 0; i < nmaps; ++i)
--	    {
--	      struct link_map *l = maps[i];
--
--	      if (l->l_init_called)
--		{
--		  _dl_call_fini (l);
-+    for (struct link_map *l = local_init_called_list; l != NULL;
-+	 l = l->l_init_called_next)
-+      {
- #ifdef SHARED
--		  /* Auditing checkpoint: another object closed.  */
--		  _dl_audit_objclose (l);
-+	if (GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing != do_audit)
-+	  continue;
-+
-+	/* Avoid back-to-back calls of _dl_audit_activity_nsid for the
-+	   same namespace.  */
-+	if (last_ns != l->l_ns)
-+	  {
-+	    if (last_ns >= 0)
-+	      _dl_audit_activity_nsid (last_ns, LA_ACT_CONSISTENT);
-+	    _dl_audit_activity_nsid (l->l_ns, LA_ACT_DELETE);
-+	    last_ns = l->l_ns;
-+	  }
- #endif
--		}
- 
--	      /* Correct the previous increment.  */
--	      --l->l_direct_opencount;
--	    }
-+	/* There is no need to re-enable exceptions because _dl_fini
-+	   is not called from a context where exceptions are caught.  */
-+	_dl_call_fini (l);
- 
- #ifdef SHARED
--	  _dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT);
-+	/* Auditing checkpoint: another object closed.  */
-+	_dl_audit_objclose (l);
- #endif
--	}
--    }
-+      }
- 
- #ifdef SHARED
--  if (! do_audit && GLRO(dl_naudit) > 0)
--    {
--      do_audit = 1;
--      goto again;
--    }
-+  if (last_ns >= 0)
-+    _dl_audit_activity_nsid (last_ns, LA_ACT_CONSISTENT);
- 
-   if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
-     _dl_debug_printf ("\nruntime linker statistics:\n"
-diff --git a/elf/dl-init.c b/elf/dl-init.c
-index 73c0259fbe6d19af..eb6c83d180c3f1a1 100644
---- a/elf/dl-init.c
-+++ b/elf/dl-init.c
-@@ -24,6 +24,7 @@
- /* Type of the initializer.  */
- typedef void (*init_t) (int, char **, char **);
- 
-+struct link_map *_dl_init_called_list;
- 
- static void
- call_init (struct link_map *l, int argc, char **argv, char **env)
-@@ -45,6 +46,21 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
-      dependency.  */
-   l->l_init_called = 1;
- 
-+  /* Help an already-running dlclose: The just-loaded object must not
-+     be removed during the current pass.  (No effect if no dlclose in
-+     progress.)  */
-+  l->l_map_used = 1;
-+
-+  /* Record execution before starting any initializers.  This way, if
-+     the initializers themselves call dlopen, their ELF destructors
-+     will eventually be run before this object is destructed, matching
-+     that their ELF constructors have run before this object was
-+     constructed.  _dl_fini uses this list for audit callbacks, so
-+     register objects on the list even if they do not have a
-+     constructor.  */
-+  l->l_init_called_next = _dl_init_called_list;
-+  _dl_init_called_list = l;
-+
-   /* Check for object which constructors we do not run here.  */
-   if (__builtin_expect (l->l_name[0], 'a') == '\0'
-       && l->l_type == lt_executable)
-diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def
-index 4bf9052db16fb352..61dc54f8ae06d465 100644
---- a/elf/dso-sort-tests-1.def
-+++ b/elf/dso-sort-tests-1.def
-@@ -53,21 +53,14 @@ tst-dso-ordering10: {}->a->b->c;soname({})=c
- output: b>a>{}<a<b
- 
- # Complex example from Bugzilla #15311, under-linked and with circular
--# relocation(dynamic) dependencies. While this is technically unspecified, the
--# presumed reasonable practical behavior is for the destructor order to respect
--# the static DT_NEEDED links (here this means the a->b->c->d order).
--# The older dynamic_sort=1 algorithm does not achieve this, while the DFS-based
--# dynamic_sort=2 algorithm does, although it is still arguable whether going
--# beyond spec to do this is the right thing to do.
--# The below expected outputs are what the two algorithms currently produce
--# respectively, for regression testing purposes.
-+# relocation(dynamic) dependencies. For both sorting algorithms, the
-+# destruction order is the reverse of the construction order, and
-+# relocation dependencies are not taken into account.
- 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];}
-+output: {+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<e<a<b<c<d];}
- 
- # 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.
-+# Final destructor order is the opposite of constructor order.
- 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
-+output: {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<c<a<a1<a2
-diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c
-index 4904cf1340a97ee1..f40760bd702e87c1 100644
---- a/elf/tst-audit23.c
-+++ b/elf/tst-audit23.c
-@@ -98,6 +98,8 @@ do_test (int argc, char *argv[])
-     char *lname;
-     uintptr_t laddr;
-     Lmid_t lmid;
-+    uintptr_t cookie;
-+    uintptr_t namespace;
-     bool closed;
-   } objs[max_objs] = { [0 ... max_objs-1] = { .closed = false } };
-   size_t nobjs = 0;
-@@ -117,6 +119,9 @@ do_test (int argc, char *argv[])
-   size_t buffer_length = 0;
-   while (xgetline (&buffer, &buffer_length, out))
-     {
-+      *strchrnul (buffer, '\n') = '\0';
-+      printf ("info: subprocess output: %s\n", buffer);
-+
-       if (startswith (buffer, "la_activity: "))
- 	{
- 	  uintptr_t cookie;
-@@ -125,29 +130,26 @@ do_test (int argc, char *argv[])
- 			  &cookie);
- 	  TEST_COMPARE (r, 2);
- 
--	  /* The cookie identifies the object at the head of the link map,
--	     so we only add a new namespace if it changes from the previous
--	     one.  This works since dlmopen is the last in the test body.  */
--	  if (cookie != last_act_cookie && last_act_cookie != -1)
--	    TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
--
- 	  if (this_act == LA_ACT_ADD && acts[nacts] != cookie)
- 	    {
-+	      /* The cookie identifies the object at the head of the
-+		 link map, so we only add a new namespace if it
-+		 changes from the previous one.  This works since
-+		 dlmopen is the last in the test body.  */
-+	      if (cookie != last_act_cookie && last_act_cookie != -1)
-+		TEST_COMPARE (last_act, LA_ACT_CONSISTENT);
-+
- 	      acts[nacts++] = cookie;
- 	      last_act_cookie = cookie;
- 	    }
--	  /* The LA_ACT_DELETE is called in the reverse order of LA_ACT_ADD
--	     at program termination (if the tests adds a dlclose or a library
--	     with extra dependencies this will need to be adapted).  */
-+	  /* LA_ACT_DELETE is called multiple times for each
-+	     namespace, depending on destruction order.  */
- 	  else if (this_act == LA_ACT_DELETE)
--	    {
--	      last_act_cookie = acts[--nacts];
--	      TEST_COMPARE (acts[nacts], cookie);
--	      acts[nacts] = 0;
--	    }
-+	    last_act_cookie = cookie;
- 	  else if (this_act == LA_ACT_CONSISTENT)
- 	    {
- 	      TEST_COMPARE (cookie, last_act_cookie);
-+	      last_act_cookie = -1;
- 
- 	      /* LA_ACT_DELETE must always be followed by an la_objclose.  */
- 	      if (last_act == LA_ACT_DELETE)
-@@ -179,6 +181,8 @@ do_test (int argc, char *argv[])
- 	  objs[nobjs].lname = lname;
- 	  objs[nobjs].laddr = laddr;
- 	  objs[nobjs].lmid = lmid;
-+	  objs[nobjs].cookie = cookie;
-+	  objs[nobjs].namespace = last_act_cookie;
- 	  objs[nobjs].closed = false;
- 	  nobjs++;
- 
-@@ -201,6 +205,12 @@ do_test (int argc, char *argv[])
- 	      if (strcmp (lname, objs[i].lname) == 0 && lmid == objs[i].lmid)
- 		{
- 		  TEST_COMPARE (objs[i].closed, false);
-+		  TEST_COMPARE (objs[i].cookie, cookie);
-+		  if (objs[i].namespace == -1)
-+		    /* No LA_ACT_ADD before the first la_objopen call.  */
-+		    TEST_COMPARE (acts[0], last_act_cookie);
-+		  else
-+		    TEST_COMPARE (objs[i].namespace, last_act_cookie);
- 		  objs[i].closed = true;
- 		  break;
- 		}
-@@ -209,11 +219,7 @@ do_test (int argc, char *argv[])
- 	  /* la_objclose should be called after la_activity(LA_ACT_DELETE) for
- 	     the closed object's namespace.  */
- 	  TEST_COMPARE (last_act, LA_ACT_DELETE);
--	  if (!seen_first_objclose)
--	    {
--	      TEST_COMPARE (last_act_cookie, cookie);
--	      seen_first_objclose = true;
--	    }
-+	  seen_first_objclose = true;
- 	}
-     }
- 
-diff --git a/include/link.h b/include/link.h
-index 041ff5f753a9ee11..a37b2cf3133eefd5 100644
---- a/include/link.h
-+++ b/include/link.h
-@@ -276,6 +276,10 @@ struct link_map
-     /* List of object in order of the init and fini calls.  */
-     struct link_map **l_initfini;
- 
-+    /* Linked list of objects in reverse ELF constructor execution
-+       order.  Head of list is stored in _dl_init_called_list.  */
-+    struct link_map *l_init_called_next;
-+
-     /* List of the dependencies introduced through symbol binding.  */
-     struct link_map_reldeps
-       {
-diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
-index 0bad34d44a5685d9..906447e677a4ca40 100644
---- a/sysdeps/generic/ldsodefs.h
-+++ b/sysdeps/generic/ldsodefs.h
-@@ -1046,6 +1046,10 @@ extern int _dl_check_map_versions (struct link_map *map, int verbose,
- extern void _dl_init (struct link_map *main_map, int argc, char **argv,
- 		      char **env) attribute_hidden;
- 
-+/* List of ELF objects in reverse order of their constructor
-+   invocation.  */
-+extern struct link_map *_dl_init_called_list attribute_hidden;
-+
- /* Call the finalizer functions of all shared objects whose
-    initializer functions have completed.  */
- extern void _dl_fini (void) attribute_hidden;
diff --git a/SOURCES/glibc-rh2233338-5.patch b/SOURCES/glibc-rh2233338-5.patch
deleted file mode 100644
index 1ed6865..0000000
--- a/SOURCES/glibc-rh2233338-5.patch
+++ /dev/null
@@ -1,141 +0,0 @@
-commit 53df2ce6885da3d0e89e87dca7b095622296014f
-Author: Florian Weimer <fweimer@redhat.com>
-Date:   Fri Sep 8 13:02:06 2023 +0200
-
-    elf: Remove unused l_text_end field from struct link_map
-    
-    It is a left-over from commit 52a01100ad011293197637e42b5be1a479a2
-    ("elf: Remove ad-hoc restrictions on dlopen callers [BZ #22787]").
-    
-    When backporting commmit 6985865bc3ad5b23147ee73466583dd7fdf65892
-    ("elf: Always call destructors in reverse constructor order
-    (bug 30785)"), we can move the l_init_called_next field to this
-    place, so that the internal GLIBC_PRIVATE ABI does not change.
-    
-    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
-    Tested-by: Carlos O'Donell <carlos@redhat.com>
-
-Conflicts:
-	elf/dl-load.h
-	  (Missing commit "Avoid "inline" after return type in function
-	  definitions.")
-	elf/rtld.c
-	  (Missing rtld_setup_main_map function.  Re-did the l_text_end
-	  removal from scratch.)
-
-diff --git a/elf/dl-load.c b/elf/dl-load.c
-index 0b45e6e3db31c70d..52dc564af9e95878 100644
---- a/elf/dl-load.c
-+++ b/elf/dl-load.c
-@@ -1176,7 +1176,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
- 
-     /* Now process the load commands and map segments into memory.
-        This is responsible for filling in:
--       l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr
-+       l_map_start, l_map_end, l_addr, l_contiguous, l_phdr
-      */
-     errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds,
- 				  maplength, has_holes, loader);
-diff --git a/elf/dl-load.h b/elf/dl-load.h
-index 66ea2e9237ab6321..ebf2604e044c3bde 100644
---- a/elf/dl-load.h
-+++ b/elf/dl-load.h
-@@ -82,14 +82,11 @@ struct loadcmd
- 
- /* This is a subroutine of _dl_map_segments.  It should be called for each
-    load command, some time after L->l_addr has been set correctly.  It is
--   responsible for setting up the l_text_end and l_phdr fields.  */
--static void __always_inline
-+   responsible for setting the l_phdr fields  */
-+static __always_inline void
- _dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header,
-                          const struct loadcmd *c)
- {
--  if (c->prot & PROT_EXEC)
--    l->l_text_end = l->l_addr + c->mapend;
--
-   if (l->l_phdr == 0
-       && c->mapoff <= header->e_phoff
-       && ((size_t) (c->mapend - c->mapstart + c->mapoff)
-@@ -102,7 +99,7 @@ _dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header,
- 
- /* This is a subroutine of _dl_map_object_from_fd.  It is responsible
-    for filling in several fields in *L: l_map_start, l_map_end, l_addr,
--   l_contiguous, l_text_end, l_phdr.  On successful return, all the
-+   l_contiguous, l_phdr.  On successful return, all the
-    segments are mapped (or copied, or whatever) from the file into their
-    final places in the address space, with the correct page permissions,
-    and any bss-like regions already zeroed.  It returns a null pointer
-diff --git a/elf/rtld.c b/elf/rtld.c
-index cd2cc4024a3581c2..c2edd0bfdc27f207 100644
---- a/elf/rtld.c
-+++ b/elf/rtld.c
-@@ -472,7 +472,6 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
-   GL(dl_rtld_map).l_real = &GL(dl_rtld_map);
-   GL(dl_rtld_map).l_map_start = (ElfW(Addr)) _begin;
-   GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end;
--  GL(dl_rtld_map).l_text_end = (ElfW(Addr)) _etext;
-   /* Copy the TLS related data if necessary.  */
- #ifndef DONT_USE_BOOTSTRAP_MAP
- # if NO_TLS_OFFSET != 0
-@@ -1520,7 +1519,6 @@ dl_main (const ElfW(Phdr) *phdr,
-     }
- 
-   main_map->l_map_end = 0;
--  main_map->l_text_end = 0;
-   /* Perhaps the executable has no PT_LOAD header entries at all.  */
-   main_map->l_map_start = ~0;
-   /* And it was opened directly.  */
-@@ -1591,8 +1589,6 @@ dl_main (const ElfW(Phdr) *phdr,
- 	  allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz;
- 	  if (main_map->l_map_end < allocend)
- 	    main_map->l_map_end = allocend;
--	  if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end)
--	    main_map->l_text_end = allocend;
- 	}
- 	break;
- 
-@@ -1641,8 +1637,6 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
-       = (char *) main_map->l_tls_initimage + main_map->l_addr;
-   if (! main_map->l_map_end)
-     main_map->l_map_end = ~0;
--  if (! main_map->l_text_end)
--    main_map->l_text_end = ~0;
-   if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name)
-     {
-       /* We were invoked directly, so the program might not have a
-diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h
-index d2b35a080b57c183..352e992c578e416f 100644
---- a/elf/setup-vdso.h
-+++ b/elf/setup-vdso.h
-@@ -52,9 +52,6 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
- 		l->l_addr = ph->p_vaddr;
- 	      if (ph->p_vaddr + ph->p_memsz >= l->l_map_end)
- 		l->l_map_end = ph->p_vaddr + ph->p_memsz;
--	      if ((ph->p_flags & PF_X)
--		  && ph->p_vaddr + ph->p_memsz >= l->l_text_end)
--		l->l_text_end = ph->p_vaddr + ph->p_memsz;
- 	    }
- 	  else
- 	    /* There must be no TLS segment.  */
-@@ -63,7 +60,6 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
-       l->l_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso);
-       l->l_addr = l->l_map_start - l->l_addr;
-       l->l_map_end += l->l_addr;
--      l->l_text_end += l->l_addr;
-       l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr);
-       elf_get_dynamic_info (l, dyn_temp);
-       _dl_setup_hash (l);
-diff --git a/include/link.h b/include/link.h
-index a37b2cf3133eefd5..88683e7a747b86e0 100644
---- a/include/link.h
-+++ b/include/link.h
-@@ -251,8 +251,6 @@ struct link_map
-     /* Start and finish of memory map for this object.  l_map_start
-        need not be the same as l_addr.  */
-     ElfW(Addr) l_map_start, l_map_end;
--    /* End of the executable part of the mapping.  */
--    ElfW(Addr) l_text_end;
- 
-     /* Default array for 'l_scope'.  */
-     struct r_scope_elem *l_scope_mem[4];
diff --git a/SOURCES/glibc-rh2233338-6.patch b/SOURCES/glibc-rh2233338-6.patch
deleted file mode 100644
index 74aca35..0000000
--- a/SOURCES/glibc-rh2233338-6.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-commit d3ba6c1333b10680ce5900a628108507d9d4b844
-Author: Florian Weimer <fweimer@redhat.com>
-Date:   Mon Sep 11 09:17:52 2023 +0200
-
-    elf: Move l_init_called_next to old place of l_text_end in link map
-    
-    This preserves all member offsets and the GLIBC_PRIVATE ABI
-    for backporting.
-
-diff --git a/include/link.h b/include/link.h
-index 88683e7a747b86e0..a464dd8e86cf89d0 100644
---- a/include/link.h
-+++ b/include/link.h
-@@ -252,6 +252,10 @@ struct link_map
-        need not be the same as l_addr.  */
-     ElfW(Addr) l_map_start, l_map_end;
- 
-+    /* Linked list of objects in reverse ELF constructor execution
-+       order.  Head of list is stored in _dl_init_called_list.  */
-+    struct link_map *l_init_called_next;
-+
-     /* Default array for 'l_scope'.  */
-     struct r_scope_elem *l_scope_mem[4];
-     /* Size of array allocated for 'l_scope'.  */
-@@ -274,10 +278,6 @@ struct link_map
-     /* List of object in order of the init and fini calls.  */
-     struct link_map **l_initfini;
- 
--    /* Linked list of objects in reverse ELF constructor execution
--       order.  Head of list is stored in _dl_init_called_list.  */
--    struct link_map *l_init_called_next;
--
-     /* List of the dependencies introduced through symbol binding.  */
-     struct link_map_reldeps
-       {
diff --git a/SOURCES/glibc-rh2234714.patch b/SOURCES/glibc-rh2234714.patch
new file mode 100644
index 0000000..999840c
--- /dev/null
+++ b/SOURCES/glibc-rh2234714.patch
@@ -0,0 +1,187 @@
+commit bd77dd7e73e3530203be1c52c8a29d08270cb25d
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Wed Sep 13 14:10:56 2023 +0200
+
+    CVE-2023-4527: Stack read overflow with large TCP responses in no-aaaa mode
+
+    Without passing alt_dns_packet_buffer, __res_context_search can only
+    store 2048 bytes (what fits into dns_packet_buffer).  However,
+    the function returns the total packet size, and the subsequent
+    DNS parsing code in _nss_dns_gethostbyname4_r reads beyond the end
+    of the stack-allocated buffer.
+
+    Fixes commit f282cdbe7f436c75864e5640a4 ("resolv: Implement no-aaaa
+    stub resolver option") and bug 30842.
+
+Conflicts:
+	resolv/nss_dns/dns-host.c
+	  (missing dns_packet_buffer cleanup downstream)
+
+diff --git a/resolv/Makefile b/resolv/Makefile
+index ab8ad49b5318ad41..4f4eaf060443c128 100644
+--- a/resolv/Makefile
++++ b/resolv/Makefile
+@@ -58,6 +58,7 @@ tests += \
+   tst-resolv-edns \
+   tst-resolv-network \
+   tst-resolv-noaaaa \
++  tst-resolv-noaaaa-vc \
+   tst-resolv-nondecimal \
+   tst-resolv-res_init-multi \
+   tst-resolv-search \
+@@ -202,6 +203,7 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \
+ $(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \
+   $(shared-thread-library)
+ $(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
++$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
+ $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library)
+diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
+index ff0a0b6f7f1f4703..f678c7d7caa3a026 100644
+--- a/resolv/nss_dns/dns-host.c
++++ b/resolv/nss_dns/dns-host.c
+@@ -392,7 +392,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
+   else
+     {
+       n = __res_context_search (ctx, name, C_IN, T_A,
+-				host_buffer.buf->buf, 2048, NULL,
++				host_buffer.buf->buf, 2048, &host_buffer.ptr,
+ 				NULL, NULL, NULL, NULL);
+       if (n >= 0)
+ 	status = gaih_getanswer_noaaaa (host_buffer.buf, n,
+diff --git a/resolv/tst-resolv-noaaaa-vc.c b/resolv/tst-resolv-noaaaa-vc.c
+new file mode 100644
+index 0000000000000000..9f5aebd99f2d74a2
+--- /dev/null
++++ b/resolv/tst-resolv-noaaaa-vc.c
+@@ -0,0 +1,129 @@
++/* Test the RES_NOAAAA resolver option with a large response.
++   Copyright (C) 2022-2023 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++#include <errno.h>
++#include <netdb.h>
++#include <resolv.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <support/check.h>
++#include <support/check_nss.h>
++#include <support/resolv_test.h>
++#include <support/support.h>
++#include <support/xmemstream.h>
++
++/* Used to keep track of the number of queries.  */
++static volatile unsigned int queries;
++
++/* If true, add a large TXT record at the start of the answer section.  */
++static volatile bool stuff_txt;
++
++static void
++response (const struct resolv_response_context *ctx,
++          struct resolv_response_builder *b,
++          const char *qname, uint16_t qclass, uint16_t qtype)
++{
++  /* If not using TCP, just force its use.  */
++  if (!ctx->tcp)
++    {
++      struct resolv_response_flags flags = {.tc = true};
++      resolv_response_init (b, flags);
++      resolv_response_add_question (b, qname, qclass, qtype);
++      return;
++    }
++
++  /* The test needs to send four queries, the first three are used to
++     grow the NSS buffer via the ERANGE handshake.  */
++  ++queries;
++  TEST_VERIFY (queries <= 4);
++
++  /* AAAA queries are supposed to be disabled.  */
++  TEST_COMPARE (qtype, T_A);
++  TEST_COMPARE (qclass, C_IN);
++  TEST_COMPARE_STRING (qname, "example.com");
++
++  struct resolv_response_flags flags = {};
++  resolv_response_init (b, flags);
++  resolv_response_add_question (b, qname, qclass, qtype);
++
++  resolv_response_section (b, ns_s_an);
++
++  if (stuff_txt)
++    {
++      resolv_response_open_record (b, qname, qclass, T_TXT, 60);
++      int zero = 0;
++      for (int i = 0; i <= 15000; ++i)
++        resolv_response_add_data (b, &zero, sizeof (zero));
++      resolv_response_close_record (b);
++    }
++
++  for (int i = 0; i < 200; ++i)
++    {
++      resolv_response_open_record (b, qname, qclass, qtype, 60);
++      char ipv4[4] = {192, 0, 2, i + 1};
++      resolv_response_add_data (b, &ipv4, sizeof (ipv4));
++      resolv_response_close_record (b);
++    }
++}
++
++static int
++do_test (void)
++{
++  struct resolv_test *obj = resolv_test_start
++    ((struct resolv_redirect_config)
++     {
++       .response_callback = response
++     });
++
++  _res.options |= RES_NOAAAA;
++
++  for (int do_stuff_txt = 0; do_stuff_txt < 2; ++do_stuff_txt)
++    {
++      queries = 0;
++      stuff_txt = do_stuff_txt;
++
++      struct addrinfo *ai = NULL;
++      int ret;
++      ret = getaddrinfo ("example.com", "80",
++                         &(struct addrinfo)
++                         {
++                           .ai_family = AF_UNSPEC,
++                           .ai_socktype = SOCK_STREAM,
++                         }, &ai);
++
++      char *expected_result;
++      {
++        struct xmemstream mem;
++        xopen_memstream (&mem);
++        for (int i = 0; i < 200; ++i)
++          fprintf (mem.out, "address: STREAM/TCP 192.0.2.%d 80\n", i + 1);
++        xfclose_memstream (&mem);
++        expected_result = mem.buffer;
++      }
++
++      check_addrinfo ("example.com", ai, ret, expected_result);
++
++      free (expected_result);
++      freeaddrinfo (ai);
++    }
++
++  resolv_test_end (obj);
++  return 0;
++}
++
++#include <support/test-driver.c>
diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec
index a829875..91a7cab 100644
--- a/SPECS/glibc.spec
+++ b/SPECS/glibc.spec
@@ -132,7 +132,7 @@ end \
 Summary: The GNU libc libraries
 Name: glibc
 Version: %{glibcversion}
-Release: %{glibcrelease}.1
+Release: %{glibcrelease}.6
 
 # In general, GPLv2+ is used by programs, LGPLv2+ is used for
 # libraries.
@@ -1047,12 +1047,11 @@ Patch854: glibc-rh2180462-1.patch
 Patch855: glibc-rh2180462-2.patch
 Patch856: glibc-rh2180462-3.patch
 Patch857: glibc-rh2180462-4.patch
-Patch858: glibc-rh2233338-1.patch
-Patch859: glibc-rh2233338-2.patch
-Patch860: glibc-rh2233338-3.patch
-Patch861: glibc-rh2233338-4.patch
-Patch862: glibc-rh2233338-5.patch
-Patch863: glibc-rh2233338-6.patch
+# (Reverted fixes for rh2233338 were here.)
+Patch864: glibc-rh2234714.patch
+Patch865: glibc-RHEL-2435.patch
+Patch866: glibc-RHEL-2435-2.patch
+Patch867: glibc-RHEL-2423.patch
 
 # Intel Optimizations
 Patch10001: glibc-sw24097-1.patch
@@ -2998,6 +2997,21 @@ fi
 %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
 
 %changelog
+* Tue Sep 19 2023 Carlos O'Donell <carlos@redhat.com> - 2.28-238.6
+- Revert: Always call destructors in reverse constructor order (#2233338)
+
+* Tue Sep 19 2023 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-238.5
+- CVE-2023-4806 glibc: potential use-after-free in getaddrinfo (RHEL-2423)
+
+* Tue Sep 19 2023 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-238.4
+- CVE-2023-4813: Work around RHEL-8 limitation in test (RHEL-2435)
+
+* Fri Sep 15 2023 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-238.3
+- CVE-2023-4813: potential use-after-free in gaih_inet (RHEL-2435)
+
+* Wed Sep 13 2023 Florian Weimer <fweimer@redhat.com> - 2.28-238.2
+- CVE-2023-4527: Stack read overflow in getaddrinfo in no-aaaa mode (#2234714)
+
 * Mon Sep 11 2023 Florian Weimer <fweimer@redhat.com> - 2.28-238.1
 - Always call destructors in reverse constructor order (#2233338)