diff --git a/.glibc.checksum b/.glibc.checksum
index 7cd1c021559097b64a987229e10514a31f59115e..b2bb7bf8b04ad2e4348735cb32f8d793b4d70012 100644
--- a/.glibc.checksum
+++ b/.glibc.checksum
@@ -1 +1 @@
-47d07b4a70ac512d0b3fdd4d1509f57e3ff217311b97e11797e66cf6caedf904
+2b94f9a8aa1e58f22a74e77fdc07e383bdb6346b64961bbf6ceceb839fb39fa8
diff --git a/SOURCES/glibc-RHEL-36147-1.patch b/SOURCES/glibc-RHEL-36147-1.patch
new file mode 100644
index 0000000000000000000000000000000000000000..9b66168ded71b758f14558c611a550e93850e4e9
--- /dev/null
+++ b/SOURCES/glibc-RHEL-36147-1.patch
@@ -0,0 +1,88 @@
+commit fe06fb313bddf7e4530056897d4a706606e49377
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Aug 1 23:31:23 2024 +0200
+
+    elf: Clarify and invert second argument of _dl_allocate_tls_init
+    
+    Also remove an outdated comment: _dl_allocate_tls_init is
+    called as part of pthread_create.
+    
+    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+
+diff -Nrup a/elf/dl-tls.c b/elf/dl-tls.c
+--- a/elf/dl-tls.c	2024-08-09 20:22:18.516110414 -0400
++++ b/elf/dl-tls.c	2024-08-09 20:23:26.182493188 -0400
+@@ -553,9 +553,14 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_m
+ /* Allocate initial TLS.  RESULT should be a non-NULL pointer to storage
+    for the TLS space.  The DTV may be resized, and so this function may
+    call malloc to allocate that space.  The loader's GL(dl_load_tls_lock)
+-   is taken when manipulating global TLS-related data in the loader.  */
++   is taken when manipulating global TLS-related data in the loader.
++
++   If MAIN_THREAD, this is the first call during process
++   initialization.  In this case, TLS initialization for secondary
++   (audit) namespaces is skipped because that has already been handled
++   by dlopen.  */
+ void *
+-_dl_allocate_tls_init (void *result, bool init_tls)
++_dl_allocate_tls_init (void *result, bool main_thread)
+ {
+   if (result == NULL)
+     /* The memory allocation failed.  */
+@@ -634,7 +639,7 @@ _dl_allocate_tls_init (void *result, boo
+ 	     because it would already be set by the audit setup.  However,
+ 	     subsequent thread creation would need to follow the default
+ 	     behaviour.   */
+-	  if (map->l_ns != LM_ID_BASE && !init_tls)
++	  if (map->l_ns != LM_ID_BASE && main_thread)
+ 	    continue;
+ 	  memset (__mempcpy (dest, map->l_tls_initimage,
+ 			     map->l_tls_initimage_size), '\0',
+@@ -662,7 +667,7 @@ _dl_allocate_tls (void *mem)
+ {
+   return _dl_allocate_tls_init (mem == NULL
+ 				? _dl_allocate_tls_storage ()
+-				: allocate_dtv (mem), true);
++				: allocate_dtv (mem), false);
+ }
+ rtld_hidden_def (_dl_allocate_tls)
+ 
+diff -Nrup a/elf/rtld.c b/elf/rtld.c
+--- a/elf/rtld.c	2024-08-09 20:22:18.516110414 -0400
++++ b/elf/rtld.c	2024-08-09 20:24:17.584783701 -0400
+@@ -2478,7 +2478,7 @@ ERROR: '%s': cannot process note segment
+      into the main thread's TLS area, which we allocated above.
+      Note: thread-local variables must only be accessed after completing
+      the next step.  */
+-  _dl_allocate_tls_init (tcbp, false);
++  _dl_allocate_tls_init (tcbp, true);
+ 
+   /* And finally install it for the main thread.  */
+   if (! tls_init_tp_called)
+diff -Nrup a/nptl/allocatestack.c b/nptl/allocatestack.c
+--- a/nptl/allocatestack.c	2024-08-09 20:22:17.808106408 -0400
++++ b/nptl/allocatestack.c	2024-08-09 20:25:49.436302396 -0400
+@@ -244,7 +244,7 @@ get_cached_stack (size_t *sizep, void **
+   memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
+ 
+   /* Re-initialize the TLS.  */
+-  _dl_allocate_tls_init (TLS_TPADJ (result), true);
++  _dl_allocate_tls_init (TLS_TPADJ (result), false);
+ 
+   return result;
+ }
+diff -Nrup a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+--- a/sysdeps/generic/ldsodefs.h	2024-08-09 20:22:18.517110419 -0400
++++ b/sysdeps/generic/ldsodefs.h	2024-08-09 20:34:20.093186159 -0400
+@@ -1185,10 +1185,8 @@ extern void _dl_get_tls_static_info (siz
+ 
+ extern void _dl_allocate_static_tls (struct link_map *map) attribute_hidden;
+ 
+-/* These are internal entry points to the two halves of _dl_allocate_tls,
+-   only used within rtld.c itself at startup time.  */
+ extern void *_dl_allocate_tls_storage (void) attribute_hidden;
+-extern void *_dl_allocate_tls_init (void *, bool);
++extern void *_dl_allocate_tls_init (void *result, bool main_thread);
+ rtld_hidden_proto (_dl_allocate_tls_init)
+ 
+ /* Deallocate memory allocated with _dl_allocate_tls.  */
diff --git a/SOURCES/glibc-RHEL-36147-2.patch b/SOURCES/glibc-RHEL-36147-2.patch
new file mode 100644
index 0000000000000000000000000000000000000000..7c4014032edcd167b6d4207a974bd6147f254879
--- /dev/null
+++ b/SOURCES/glibc-RHEL-36147-2.patch
@@ -0,0 +1,526 @@
+commit 5097cd344fd243fb8deb6dec96e8073753f962f9
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Aug 1 23:31:30 2024 +0200
+
+    elf: Avoid re-initializing already allocated TLS in dlopen (bug 31717)
+    
+    The old code used l_init_called as an indicator for whether TLS
+    initialization was complete.  However, it is possible that
+    TLS for an object is initialized, written to, and then dlopen
+    for this object is called again, and l_init_called is not true at
+    this point.  Previously, this resulted in TLS being initialized
+    twice, discarding any interim writes (technically introducing a
+    use-after-free bug even).
+    
+    This commit introduces an explicit per-object flag, l_tls_in_slotinfo.
+    It indicates whether _dl_add_to_slotinfo has been called for this
+    object.  This flag is used to avoid double-initialization of TLS.
+    In update_tls_slotinfo, the first_static_tls micro-optimization
+    is removed because preserving the initalization flag for subsequent
+    use by the second loop for static TLS is a bit complicated, and
+    another per-object flag does not seem to be worth it.  Furthermore,
+    the l_init_called flag is dropped from the second loop (for static
+    TLS initialization) because l_need_tls_init on its own prevents
+    double-initialization.
+    
+    The remaining l_init_called usage in resize_scopes and update_scopes
+    is just an optimization due to the use of scope_has_map, so it is
+    not changed in this commit.
+    
+    The isupper check ensures that libc.so.6 is TLS is not reverted.
+    Such a revert happens if l_need_tls_init is not cleared in
+    _dl_allocate_tls_init for the main_thread case, now that
+    l_init_called is not checked anymore in update_tls_slotinfo
+    in elf/dl-open.c.
+    
+    Reported-by: Jonathon Anderson <janderson@rice.edu>
+    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+
+    Conflicts:
+	elf/Makefile - tests and module-names differences
+	elf/Makefile - add $(libdl) where needed
+
+diff -Nrup a/elf/Makefile b/elf/Makefile
+--- a/elf/Makefile	2024-08-09 21:34:38.159713929 -0400
++++ b/elf/Makefile	2024-08-16 13:22:32.268485608 -0400
+@@ -369,6 +369,10 @@ tests += \
+   tst-dlmopen-dlerror \
+   tst-dlmopen-gethostbyname \
+   tst-dlmopen-twice \
++  tst-dlopen-tlsreinit1 \
++  tst-dlopen-tlsreinit2 \
++  tst-dlopen-tlsreinit3 \
++  tst-dlopen-tlsreinit4 \
+   tst-dlopenfail \
+   tst-dlopenfail-2 \
+   tst-dlopenrpath \
+@@ -720,6 +724,9 @@ modules-names = \
+   tst-dlmopen-gethostbyname-mod \
+   tst-dlmopen-twice-mod1 \
+   tst-dlmopen-twice-mod2 \
++  tst-dlopen-tlsreinitmod1 \
++  tst-dlopen-tlsreinitmod2 \
++  tst-dlopen-tlsreinitmod3 \
+   tst-dlopenfaillinkmod \
+   tst-dlopenfailmod1 \
+   tst-dlopenfailmod2 \
+@@ -2775,3 +2782,30 @@ $(objpfx)tst-recursive-tls.out: \
+     0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
+ $(objpfx)tst-recursive-tlsmod%.os: tst-recursive-tlsmodN.c
+ 	$(compile-command.c) -DVAR=thread_$* -DFUNC=get_threadvar_$*
++
++# Order matters here.  The test needs the constructor for
++# tst-dlopen-tlsreinitmod2.so to be called first.
++$(objpfx)tst-dlopen-tlsreinitmod3.so: $(libdl)
++$(objpfx)tst-dlopen-tlsreinit3: $(libdl)
++$(objpfx)tst-dlopen-tlsreinitmod1.so: $(libdl)
++$(objpfx)tst-dlopen-tlsreinit1: $(libdl)
++LDFLAGS-tst-dlopen-tlsreinitmod1.so = -Wl,--no-as-needed
++$(objpfx)tst-dlopen-tlsreinitmod1.so: \
++  $(objpfx)tst-dlopen-tlsreinitmod3.so $(objpfx)tst-dlopen-tlsreinitmod2.so
++LDFLAGS-tst-dlopen-tlsreinit2 = -Wl,--no-as-needed
++$(objpfx)tst-dlopen-tlsreinit2: \
++  $(objpfx)tst-dlopen-tlsreinitmod3.so $(objpfx)tst-dlopen-tlsreinitmod2.so
++LDFLAGS-tst-dlopen-tlsreinit4 = -Wl,--no-as-needed
++$(objpfx)tst-dlopen-tlsreinit4: \
++  $(objpfx)tst-dlopen-tlsreinitmod3.so $(objpfx)tst-dlopen-tlsreinitmod2.so
++# tst-dlopen-tlsreinitmod2.so is underlinked and refers to
++# tst-dlopen-tlsreinitmod3.so.  The dependency is provided via
++# $(objpfx)tst-dlopen-tlsreinitmod1.so.
++tst-dlopen-tlsreinitmod2.so-no-z-defs = yes
++$(objpfx)tst-dlopen-tlsreinit.out: $(objpfx)tst-dlopen-tlsreinitmod1.so \
++  $(objpfx)tst-dlopen-tlsreinitmod2.so $(objpfx)tst-dlopen-tlsreinitmod3.so
++# Reuse an audit module which provides ample debug logging.
++$(objpfx)tst-dlopen-tlsreinit3.out: $(objpfx)tst-auditmod1.so
++tst-dlopen-tlsreinit3-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
++$(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so
++tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+diff -Nrup a/elf/dl-open.c b/elf/dl-open.c
+--- a/elf/dl-open.c	2024-08-09 21:34:37.782711770 -0400
++++ b/elf/dl-open.c	2024-08-13 16:18:12.501292054 -0400
+@@ -361,17 +361,8 @@ resize_tls_slotinfo (struct link_map *ne
+ {
+   bool any_tls = false;
+   for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
+-    {
+-      struct link_map *imap = new->l_searchlist.r_list[i];
+-
+-      /* Only add TLS memory if this object is loaded now and
+-	 therefore is not yet initialized.  */
+-      if (! imap->l_init_called && imap->l_tls_blocksize > 0)
+-	{
+-	  _dl_add_to_slotinfo (imap, false);
+-	  any_tls = true;
+-	}
+-    }
++    if (_dl_add_to_slotinfo (new->l_searchlist.r_list[i], false))
++      any_tls = true;
+   return any_tls;
+ }
+ 
+@@ -381,22 +372,8 @@ resize_tls_slotinfo (struct link_map *ne
+ static void
+ update_tls_slotinfo (struct link_map *new)
+ {
+-  unsigned int first_static_tls = new->l_searchlist.r_nlist;
+   for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
+-    {
+-      struct link_map *imap = new->l_searchlist.r_list[i];
+-
+-      /* Only add TLS memory if this object is loaded now and
+-	 therefore is not yet initialized.  */
+-      if (! imap->l_init_called && imap->l_tls_blocksize > 0)
+-	{
+-	  _dl_add_to_slotinfo (imap, true);
+-
+-	  if (imap->l_need_tls_init
+-	      && first_static_tls == new->l_searchlist.r_nlist)
+-	    first_static_tls = i;
+-	}
+-    }
++    _dl_add_to_slotinfo (new->l_searchlist.r_list[i], true);
+ 
+   size_t newgen = GL(dl_tls_generation) + 1;
+   if (__glibc_unlikely (newgen == 0))
+@@ -408,13 +385,11 @@ TLS generation counter wrapped!  Please
+   /* We need a second pass for static tls data, because
+      _dl_update_slotinfo must not be run while calls to
+      _dl_add_to_slotinfo are still pending.  */
+-  for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i)
++  for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
+     {
+       struct link_map *imap = new->l_searchlist.r_list[i];
+ 
+-      if (imap->l_need_tls_init
+-	  && ! imap->l_init_called
+-	  && imap->l_tls_blocksize > 0)
++      if (imap->l_need_tls_init && imap->l_tls_blocksize > 0)
+ 	{
+ 	  /* For static TLS we have to allocate the memory here and
+ 	     now, but we can delay updating the DTV.  */
+diff -Nrup a/elf/dl-tls.c b/elf/dl-tls.c
+--- a/elf/dl-tls.c	2024-08-09 21:34:38.162713946 -0400
++++ b/elf/dl-tls.c	2024-08-13 16:23:19.819877383 -0400
+@@ -633,17 +633,21 @@ _dl_allocate_tls_init (void *result, boo
+ 	     some platforms use in static programs requires it.  */
+ 	  dtv[map->l_tls_modid].pointer.val = dest;
+ 
+-	  /* Copy the initialization image and clear the BSS part.  For
+-	     audit modules or dependencies with initial-exec TLS, we can not
+-	     set the initial TLS image on default loader initialization
+-	     because it would already be set by the audit setup.  However,
+-	     subsequent thread creation would need to follow the default
+-	     behaviour.   */
++	  /* Copy the initialization image and clear the BSS part.
++	     For audit modules or dependencies with initial-exec TLS,
++	     we can not set the initial TLS image on default loader
++	     initialization because it would already be set by the
++	     audit setup, which uses the dlopen code and already
++	     clears l_need_tls_init.  Calls with !main_thread from
++	     pthread_create need to initialze TLS for the current
++	     thread regardless of namespace.  */
+ 	  if (map->l_ns != LM_ID_BASE && main_thread)
+ 	    continue;
+ 	  memset (__mempcpy (dest, map->l_tls_initimage,
+ 			     map->l_tls_initimage_size), '\0',
+ 		  map->l_tls_blocksize - map->l_tls_initimage_size);
++	  if (main_thread)
++	    map->l_need_tls_init = 0;
+ 	}
+ 
+       total += cnt;
+@@ -1100,9 +1104,32 @@ _dl_tls_initial_modid_limit_setup (void)
+ }
+ 
+ 
+-void
++/* Add module to slot information data.  If DO_ADD is false, only the
++   required memory is allocated.  Must be called with
++   GL (dl_load_tls_lock) acquired.  If the function has already been
++   called for the link map L with !DO_ADD, then this function will not
++   raise an exception, otherwise it is possible that it encounters a
++   memory allocation failure.
++
++   Return false if L has already been added to the slotinfo data, or
++   if L has no TLS data.  If the returned value is true, L has been
++   added with this call (DO_ADD), or has been added in a previous call
++   (!DO_ADD).
++
++   The expected usage is as follows: Call _dl_add_to_slotinfo for
++   several link maps with DO_ADD set to false, and record if any calls
++   result in a true result.  If there was a true result, call
++   _dl_add_to_slotinfo again, this time with DO_ADD set to true.  (For
++   simplicity, it's possible to call the function for link maps where
++   the previous result was false.)  The return value from the second
++   round of calls can be ignored.  If there was true result initially,
++   call _dl_update_slotinfo to update the TLS generation counter.  */
++bool
+ _dl_add_to_slotinfo (struct link_map *l, bool do_add)
+ {
++  if (l->l_tls_blocksize == 0 || l->l_tls_in_slotinfo)
++    return false;
++	
+   /* Now that we know the object is loaded successfully add
+      modules containing TLS data to the dtv info table.  We
+      might have to increase its size.  */
+@@ -1158,5 +1185,8 @@ cannot create TLS data structures"));
+       atomic_store_relaxed (&listp->slotinfo[idx].map, l);
+       atomic_store_relaxed (&listp->slotinfo[idx].gen,
+ 			    GL(dl_tls_generation) + 1);
++      l->l_tls_in_slotinfo = true;
+     }
++
++  return true;
+ }
+diff -Nrup a/elf/tst-dlopen-tlsreinit1.c b/elf/tst-dlopen-tlsreinit1.c
+--- a/elf/tst-dlopen-tlsreinit1.c	1969-12-31 19:00:00.000000000 -0500
++++ b/elf/tst-dlopen-tlsreinit1.c	2024-08-09 21:57:01.495424018 -0400
+@@ -0,0 +1,40 @@
++/* Test that dlopen preserves already accessed TLS (bug 31717).
++   Copyright (C) 2024 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 <stdbool.h>
++#include <support/check.h>
++#include <support/xdlfcn.h>
++#include <ctype.h>
++
++static int
++do_test (void)
++{
++  void *handle = xdlopen ("tst-dlopen-tlsreinitmod1.so", RTLD_NOW);
++
++  bool *tlsreinitmod3_tested = xdlsym (handle, "tlsreinitmod3_tested");
++  TEST_VERIFY (*tlsreinitmod3_tested);
++
++  xdlclose (handle);
++
++  /* This crashes if the libc.so.6 TLS image has been reverted.  */
++  TEST_VERIFY (!isupper ('@'));
++
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff -Nrup a/elf/tst-dlopen-tlsreinit2.c b/elf/tst-dlopen-tlsreinit2.c
+--- a/elf/tst-dlopen-tlsreinit2.c	1969-12-31 19:00:00.000000000 -0500
++++ b/elf/tst-dlopen-tlsreinit2.c	2024-08-09 21:59:14.657192089 -0400
+@@ -0,0 +1,39 @@
++/* Test that dlopen preserves already accessed TLS (bug 31717).
++   Variant with initially-linked modules.
++   Copyright (C) 2024 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++#include <ctype.h>
++#include <stdbool.h>
++#include <support/check.h>
++#include <support/xdlfcn.h>
++
++
++static int
++do_test (void)
++{
++  /* Defined in tst-dlopen-tlsreinitmod3.so.  */
++  extern bool tlsreinitmod3_tested;
++  TEST_VERIFY (tlsreinitmod3_tested);
++
++  /* This crashes if the libc.so.6 TLS image has been reverted.  */
++  TEST_VERIFY (!isupper ('@'));
++
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff -Nrup a/elf/tst-dlopen-tlsreinit3.c b/elf/tst-dlopen-tlsreinit3.c
+--- a/elf/tst-dlopen-tlsreinit3.c	1969-12-31 19:00:00.000000000 -0500
++++ b/elf/tst-dlopen-tlsreinit3.c	2024-08-09 22:00:43.985707332 -0400
+@@ -0,0 +1,2 @@
++/* Same code, but run with LD_AUDIT=tst-auditmod1.so.  */
++#include "tst-dlopen-tlsreinit1.c"
+diff -Nrup a/elf/tst-dlopen-tlsreinit4.c b/elf/tst-dlopen-tlsreinit4.c
+--- a/elf/tst-dlopen-tlsreinit4.c	1969-12-31 19:00:00.000000000 -0500
++++ b/elf/tst-dlopen-tlsreinit4.c	2024-08-09 22:01:30.058973079 -0400
+@@ -0,0 +1,2 @@
++/* Same code, but run with LD_AUDIT=tst-auditmod1.so.  */
++#include "tst-dlopen-tlsreinit2.c"
+diff -Nrup a/elf/tst-dlopen-tlsreinitmod1.c b/elf/tst-dlopen-tlsreinitmod1.c
+--- a/elf/tst-dlopen-tlsreinitmod1.c	1969-12-31 19:00:00.000000000 -0500
++++ b/elf/tst-dlopen-tlsreinitmod1.c	2024-08-09 22:02:42.337389978 -0400
+@@ -0,0 +1,20 @@
++/* Test that dlopen preserves already accessed TLS (bug 31717), module 1.
++   Copyright (C) 2024 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/>.  */
++
++/* This module triggers loading of tst-dlopen-tlsreinitmod2.so and
++   tst-dlopen-tlsreinitmod3.so.  */
+diff -Nrup a/elf/tst-dlopen-tlsreinitmod2.c b/elf/tst-dlopen-tlsreinitmod2.c
+--- a/elf/tst-dlopen-tlsreinitmod2.c	1969-12-31 19:00:00.000000000 -0500
++++ b/elf/tst-dlopen-tlsreinitmod2.c	2024-08-09 22:03:54.322805189 -0400
+@@ -0,0 +1,30 @@
++/* Test that dlopen preserves already accessed TLS (bug 31717), module 2.
++   Copyright (C) 2024 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++#include <stdio.h>
++
++/* Defined in tst-dlopen-tlsreinitmod3.so.  This an underlinked symbol
++   dependency.  */
++extern void call_tlsreinitmod3 (void);
++
++static void __attribute__ ((constructor))
++tlsreinitmod2_init (void)
++{
++  puts ("info: constructor of tst-dlopen-tlsreinitmod2.so invoked");
++  call_tlsreinitmod3 ();
++}
+diff -Nrup a/elf/tst-dlopen-tlsreinitmod3.c b/elf/tst-dlopen-tlsreinitmod3.c
+--- a/elf/tst-dlopen-tlsreinitmod3.c	1969-12-31 19:00:00.000000000 -0500
++++ b/elf/tst-dlopen-tlsreinitmod3.c	2024-08-09 22:07:26.980031781 -0400
+@@ -0,0 +1,102 @@
++/* Test that dlopen preserves already accessed TLS (bug 31717), module 3.
++   Copyright (C) 2024 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 <dlfcn.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <unistd.h>
++
++/* Used to verify from the main program that the test ran.  */
++bool tlsreinitmod3_tested;
++
++/* This TLS variable must not revert back to the initial state after
++   dlopen.  */
++static __thread int tlsreinitmod3_state = 1;
++
++/* Set from the ELF constructor during dlopen.  */
++static bool tlsreinitmod3_constructed;
++
++/* Second half of test, behind a compiler barrier.  The compiler
++   barrier is necessary to prevent carrying over TLS address
++   information from call_tlsreinitmod3 to call_tlsreinitmod3_tail.  */
++void call_tlsreinitmod3_tail (void *self) __attribute__ ((weak));
++
++/* Called from tst-dlopen-tlsreinitmod2.so.  */
++void
++call_tlsreinitmod3 (void)
++{
++  printf ("info: call_tlsreinitmod3 invoked (state=%d)\n",
++          tlsreinitmod3_state);
++
++  if (tlsreinitmod3_constructed)
++    {
++      puts ("error: call_tlsreinitmod3 called after ELF constructor");
++      fflush (stdout);
++      /* Cannot rely on test harness due to dynamic linking.  */
++      _exit (1);
++    }
++
++  tlsreinitmod3_state = 2;
++
++  /* Self-dlopen.  This will run the ELF constructor.   */
++  void *self = dlopen ("tst-dlopen-tlsreinitmod3.so", RTLD_NOW);
++  if (self == NULL)
++    {
++      printf ("error: dlopen: %s\n", dlerror ());
++      fflush (stdout);
++      /* Cannot rely on test harness due to dynamic linking.  */
++      _exit (1);
++    }
++
++  call_tlsreinitmod3_tail (self);
++}
++
++void
++call_tlsreinitmod3_tail (void *self)
++{
++  printf ("info: dlopen returned in tlsreinitmod3 (state=%d)\n",
++          tlsreinitmod3_state);
++
++  if (!tlsreinitmod3_constructed)
++    {
++      puts ("error: dlopen did not call tlsreinitmod3 ELF constructor");
++      fflush (stdout);
++      /* Cannot rely on test harness due to dynamic linking.  */
++      _exit (1);
++    }
++
++  if (tlsreinitmod3_state != 2)
++    {
++      puts ("error: TLS state reverted in tlsreinitmod3");
++      fflush (stdout);
++      /* Cannot rely on test harness due to dynamic linking.  */
++      _exit (1);
++    }
++
++  dlclose (self);
++
++  /* Signal test completion to the main program.  */
++  tlsreinitmod3_tested = true;
++}
++
++static void __attribute__ ((constructor))
++tlsreinitmod3_init (void)
++{
++  puts ("info: constructor of tst-dlopen-tlsreinitmod3.so invoked");
++  tlsreinitmod3_constructed = true;
++}
+diff -Nrup a/include/link.h b/include/link.h
+--- a/include/link.h	2024-08-09 21:34:37.642710968 -0400
++++ b/include/link.h	2024-08-09 22:09:03.764585534 -0400
+@@ -210,6 +210,7 @@ struct link_map
+     unsigned int l_free_initfini:1; /* Nonzero if l_initfini can be
+ 				       freed, ie. not allocated with
+ 				       the dummy malloc in ld.so.  */
++    unsigned int l_tls_in_slotinfo:1; /* TLS slotinfo updated in dlopen.  */
+ 
+     /* NODELETE status of the map.  Only valid for maps of type
+        lt_loaded.  Lazy binding sets l_nodelete_active directly,
+diff -Nrup a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+--- a/sysdeps/generic/ldsodefs.h	2024-08-09 21:34:38.164713958 -0400
++++ b/sysdeps/generic/ldsodefs.h	2024-08-13 16:41:52.398600434 -0400
+@@ -1218,13 +1218,7 @@ extern void *_dl_open (const char *name,
+ extern int _dl_scope_free (void *) attribute_hidden;
+ 
+ 
+-/* Add module to slot information data.  If DO_ADD is false, only the
+-   required memory is allocated.  Must be called with GL
+-   (dl_load_tls_lock) acquired.  If the function has already been called
+-   for the link map L with !do_add, then this function will not raise
+-   an exception, otherwise it is possible that it encounters a memory
+-   allocation failure.  */
+-extern void _dl_add_to_slotinfo (struct link_map *l, bool do_add)
++extern bool _dl_add_to_slotinfo (struct link_map *l, bool do_add)
+   attribute_hidden;
+ 
+ /* Update slot information data for at least the generation of the
diff --git a/SOURCES/glibc-RHEL-36147-3.patch b/SOURCES/glibc-RHEL-36147-3.patch
new file mode 100644
index 0000000000000000000000000000000000000000..a2b3e7699e1d831d5db812fc03561f55542bf34d
--- /dev/null
+++ b/SOURCES/glibc-RHEL-36147-3.patch
@@ -0,0 +1,16 @@
+Author: Patsy Griffin <patsy@redhat.com>
+  
+    Fix a typo in naming tst-dlopen-tlsreinit1.out
+
+diff -Nrup a/elf/Makefile b/elf/Makefile
+--- a/elf/Makefile	2024-08-16 13:27:00.700921146 -0400
++++ b/elf/Makefile	2024-08-16 13:29:12.951628406 -0400
+@@ -2802,7 +2802,7 @@ $(objpfx)tst-dlopen-tlsreinit4: \
+ # tst-dlopen-tlsreinitmod3.so.  The dependency is provided via
+ # $(objpfx)tst-dlopen-tlsreinitmod1.so.
+ tst-dlopen-tlsreinitmod2.so-no-z-defs = yes
+-$(objpfx)tst-dlopen-tlsreinit.out: $(objpfx)tst-dlopen-tlsreinitmod1.so \
++$(objpfx)tst-dlopen-tlsreinit1.out: $(objpfx)tst-dlopen-tlsreinitmod1.so \
+   $(objpfx)tst-dlopen-tlsreinitmod2.so $(objpfx)tst-dlopen-tlsreinitmod3.so
+ # Reuse an audit module which provides ample debug logging.
+ $(objpfx)tst-dlopen-tlsreinit3.out: $(objpfx)tst-auditmod1.so
diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec
index c458920b37f21ab6321ba3f4393d545a99ff455b..e80d62fabfdf56fb622e58f0a0a03c3ddbf86221 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}.4
+Release: %{glibcrelease}.5
 
 # In general, GPLv2+ is used by programs, LGPLv2+ is used for
 # libraries.
@@ -1192,6 +1192,9 @@ Patch1004: glibc-RHEL-52428-1.patch
 Patch1005: glibc-RHEL-52428-2.patch
 Patch1006: glibc-RHEL-39994-1.patch
 Patch1007: glibc-RHEL-39994-2.patch
+Patch1008: glibc-RHEL-36147-1.patch
+Patch1009: glibc-RHEL-36147-2.patch
+Patch1010: glibc-RHEL-36147-3.patch
 
 ##############################################################################
 # Continued list of core "glibc" package information:
@@ -3023,6 +3026,10 @@ fi
 %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
 
 %changelog
+* Fri Aug 16 2024 Patsy Griffin <patsy@redhat.com> - 2.28-251.5
+- elf: Clarify and invert second argument of _dl_allocate_tls_init
+- elf: Avoid re-initializing already allocated TLS in dlopen (RHEL-36147)
+
 * Thu Aug  8 2024 Patsy Griffin <patsy@redhat.com> - 2.28-251.4
 - elf: Avoid some free (NULL) calls in _dl_update_slotinfo
 - elf: Support recursive use of dynamic TLS in interposed malloc (RHEL-39994)