diff --git a/SOURCES/glibc-rh1361965.patch b/SOURCES/glibc-rh1361965.patch
new file mode 100644
index 0000000..cfbf09c
--- /dev/null
+++ b/SOURCES/glibc-rh1361965.patch
@@ -0,0 +1,49 @@
+Backport of this Fedora Rawhide commit but split out into a distinct
+patch.
+    
+commit 72195d44855ab96875f117acb75c37f98dcb26a9
+Author: Carlos O'Donell <carlos@redhat.com>
+Date:   Thu Jun 6 23:58:21 2019 -0400
+
+    locale: Fix C.UTF-8 ranges.
+    
+    The ellipsis range support only allows <Uxxxx> or <Uxxxxxxxx> as
+    valid unicode code points, otherwise it treats it as a symbol and
+    since we don't define the symbol the entire range is unused.
+
+diff --git a/localedata/locales/C b/localedata/locales/C
+index b2c2d1dc417cde69..30d9563213b8cb0f 100644
+--- a/localedata/locales/C
++++ b/localedata/locales/C
+@@ -43,21 +43,21 @@ order_start forward
+ <U0000>
+ ..
+ <UFFFF>
+-<U10000>
++<U00010000>
+ ..
+-<U1FFFF>
+-<U20000>
++<U0001FFFF>
++<U00020000>
+ ..
+-<U2FFFF>
+-<UE0000>
++<U0002FFFF>
++<U000E0000>
+ ..
+-<UEFFFF>
+-<UF0000>
++<U000EFFFF>
++<U000F0000>
+ ..
+-<UFFFFF>
+-<U100000>
++<U000FFFFF>
++<U00100000>
+ ..
+-<U10FFFF>
++<U0010FFFF>
+ UNDEFINED
+ order_end
+ END LC_COLLATE
diff --git a/SOURCES/glibc-rh1410154-1.patch b/SOURCES/glibc-rh1410154-1.patch
new file mode 100644
index 0000000..6acd167
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-1.patch
@@ -0,0 +1,185 @@
+commit 96cd0558bcd69481ccc42e1b392f0c0b36fce2b0
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Wed Nov 28 19:59:45 2018 +0100
+
+    support: Add signal support to support_capture_subprocess_check
+    
+    Signal zero does not terminate a process, so it is safe to use negative
+    values for signal numbers.
+    
+    Adjust libio/tst-vtables-common.c to use this new functionality,
+    instead of determining the termination status for a signal indirectly.
+
+diff --git a/libio/tst-vtables-common.c b/libio/tst-vtables-common.c
+index 5e3101206919fa1b..85e246cd1131f8e8 100644
+--- a/libio/tst-vtables-common.c
++++ b/libio/tst-vtables-common.c
+@@ -380,21 +380,6 @@ without_compatibility_fflush (void *closure)
+   _exit (1);
+ }
+ 
+-/* Exit status after abnormal termination.  */
+-static int termination_status;
+-
+-static void
+-init_termination_status (void)
+-{
+-  pid_t pid = xfork ();
+-  if (pid == 0)
+-    abort ();
+-  xwaitpid (pid, &termination_status, 0);
+-
+-  TEST_VERIFY (WIFSIGNALED (termination_status));
+-  TEST_COMPARE (WTERMSIG (termination_status), SIGABRT);
+-}
+-
+ static void
+ check_for_termination (const char *name, void (*callback) (void *))
+ {
+@@ -404,7 +389,7 @@ check_for_termination (const char *name, void (*callback) (void *))
+   shared->calls = 0;
+   struct support_capture_subprocess proc
+     = support_capture_subprocess (callback, NULL);
+-  support_capture_subprocess_check (&proc, name, termination_status,
++  support_capture_subprocess_check (&proc, name, -SIGABRT,
+                                     sc_allow_stderr);
+   const char *message
+     = "Fatal error: glibc detected an invalid stdio handle\n";
+@@ -491,7 +476,6 @@ run_tests (bool initially_disabled)
+ 
+   shared = support_shared_allocate (sizeof (*shared));
+   shared->initially_disabled = initially_disabled;
+-  init_termination_status ();
+ 
+   if (initially_disabled)
+     {
+diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
+index d5eac84d09ae325f..2d2384e73df0d2d0 100644
+--- a/support/capture_subprocess.h
++++ b/support/capture_subprocess.h
+@@ -55,13 +55,16 @@ enum support_capture_allow
+   sc_allow_stderr = 0x04,
+ };
+ 
+-/* Check that the subprocess exited with STATUS and that only the
+-   allowed outputs happened.  ALLOWED is a combination of
+-   support_capture_allow flags.  Report errors under the CONTEXT
+-   message.  */
++/* Check that the subprocess exited and that only the allowed outputs
++   happened.  If STATUS_OR_SIGNAL is nonnegative, it is the expected
++   (decoded) exit status of the process, as returned by WEXITSTATUS.
++   If STATUS_OR_SIGNAL is negative, -STATUS_OR_SIGNAL is the expected
++   termination signal, as returned by WTERMSIG.  ALLOWED is a
++   combination of support_capture_allow flags.  Report errors under
++   the CONTEXT message.  */
+ void support_capture_subprocess_check (struct support_capture_subprocess *,
+-                                       const char *context, int status,
+-                                       int allowed)
++                                       const char *context,
++                                       int status_or_signal, int allowed)
+   __attribute__ ((nonnull (1, 2)));
+ 
+ #endif /* SUPPORT_CAPTURE_SUBPROCESS_H */
+diff --git a/support/support_capture_subprocess_check.c b/support/support_capture_subprocess_check.c
+index ff5ee89fb02599ae..8b4c352c96227b78 100644
+--- a/support/support_capture_subprocess_check.c
++++ b/support/support_capture_subprocess_check.c
+@@ -20,6 +20,7 @@
+ #include <stdio.h>
+ #include <support/capture_subprocess.h>
+ #include <support/check.h>
++#include <sys/wait.h>
+ 
+ static void
+ print_context (const char *context, bool *failed)
+@@ -31,9 +32,22 @@ print_context (const char *context, bool *failed)
+   printf ("error: subprocess failed: %s\n", context);
+ }
+ 
++static void
++print_actual_status (struct support_capture_subprocess *proc)
++{
++  if (WIFEXITED (proc->status))
++    printf ("error:   actual exit status: %d [0x%x]\n",
++            WEXITSTATUS (proc->status), proc->status);
++  else if (WIFSIGNALED (proc->status))
++    printf ("error:   actual termination signal: %d [0x%x]\n",
++            WTERMSIG (proc->status), proc->status);
++  else
++    printf ("error:   actual undecoded exit status: [0x%x]\n", proc->status);
++}
++
+ void
+ support_capture_subprocess_check (struct support_capture_subprocess *proc,
+-                                  const char *context, int status,
++                                  const char *context, int status_or_signal,
+                                   int allowed)
+ {
+   TEST_VERIFY ((allowed & sc_allow_none)
+@@ -44,11 +58,28 @@ support_capture_subprocess_check (struct support_capture_subprocess *proc,
+                      || (allowed & sc_allow_stderr))));
+ 
+   bool failed = false;
+-  if (proc->status != status)
++  if (status_or_signal >= 0)
+     {
+-      print_context (context, &failed);
+-      printf ("error:   expected exit status: %d\n", status);
+-      printf ("error:   actual exit status:   %d\n", proc->status);
++      /* Expect regular termination.  */
++      if (!(WIFEXITED (proc->status)
++            && WEXITSTATUS (proc->status) == status_or_signal))
++        {
++          print_context (context, &failed);
++          printf ("error:   expected exit status: %d\n", status_or_signal);
++          print_actual_status (proc);
++        }
++    }
++  else
++    {
++      /* status_or_signal < 0.  Expect termination by signal.  */
++      if (!(WIFSIGNALED (proc->status)
++            && WTERMSIG (proc->status) == -status_or_signal))
++        {
++          print_context (context, &failed);
++          printf ("error:   expected termination signal: %d\n",
++                  -status_or_signal);
++          print_actual_status (proc);
++        }
+     }
+   if (!(allowed & sc_allow_stdout) && proc->out.length != 0)
+     {
+diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
+index 63b6699622f97fcc..99570879eedd65b1 100644
+--- a/support/tst-support_capture_subprocess.c
++++ b/support/tst-support_capture_subprocess.c
+@@ -285,15 +285,29 @@ do_multiple_tests (enum test_type type)
+ 
+               check_stream ("stdout", &result.out, test.out);
+               check_stream ("stderr", &result.err, test.err);
++
++              /* Allowed output for support_capture_subprocess_check.  */
++              int check_allow = 0;
++              if (lengths[length_idx_stdout] > 0)
++                check_allow |= sc_allow_stdout;
++              if (lengths[length_idx_stderr] > 0)
++                check_allow |= sc_allow_stderr;
++              if (check_allow == 0)
++                check_allow = sc_allow_none;
++
+               if (test.signal != 0)
+                 {
+                   TEST_VERIFY (WIFSIGNALED (result.status));
+                   TEST_VERIFY (WTERMSIG (result.status) == test.signal);
++                  support_capture_subprocess_check (&result, "signal",
++                                                    -SIGTERM, check_allow);
+                 }
+               else
+                 {
+                   TEST_VERIFY (WIFEXITED (result.status));
+                   TEST_VERIFY (WEXITSTATUS (result.status) == test.status);
++                  support_capture_subprocess_check (&result, "exit",
++                                                    test.status, check_allow);
+                 }
+               support_capture_subprocess_free (&result);
+               free (test.out);
diff --git a/SOURCES/glibc-rh1410154-10.patch b/SOURCES/glibc-rh1410154-10.patch
new file mode 100644
index 0000000..9025c9e
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-10.patch
@@ -0,0 +1,42 @@
+commit e37c2cf299b61ce18f62852f6c5624c27829b610
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Oct 31 18:48:43 2019 +0100
+
+    Move _dl_open_check to its original place in dl_open_worker
+    
+    This reverts the non-test change from commit d0093c5cefb7f7a4143f
+    ("Call _dl_open_check after relocation [BZ #24259]"), given that
+    the underlying bug has been fixed properly in commit 61b74477fa7f63
+    ("Remove all loaded objects if dlopen fails, ignoring NODELETE
+    [BZ #20839]").
+    
+    Tested on x86-64-linux-gnu, with and without --enable-cet.
+    
+    Change-Id: I995a6cfb89f25d2b0cf5e606428c2a93eb48fc33
+
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index 25838b073ac1edaf..e13968d4d7c4c83f 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -619,6 +619,8 @@ dl_open_worker (void *a)
+   _dl_debug_state ();
+   LIBC_PROBE (map_complete, 3, args->nsid, r, new);
+ 
++  _dl_open_check (new);
++
+   /* Print scope information.  */
+   if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
+     _dl_show_scope (new, 0);
+@@ -699,12 +701,6 @@ dl_open_worker (void *a)
+ 	_dl_relocate_object (l, l->l_scope, reloc_mode, 0);
+     }
+ 
+-  /* NB: Workaround for [BZ #20839] which doesn't remove the NODELETE
+-     object when _dl_open_check throws an exception.  Move it after
+-     relocation to avoid leaving the NODELETE object mapped without
+-     relocation.  */
+-  _dl_open_check (new);
+-
+   /* This only performs the memory allocations.  The actual update of
+      the scopes happens below, after failure is impossible.  */
+   resize_scopes (new);
diff --git a/SOURCES/glibc-rh1410154-11.patch b/SOURCES/glibc-rh1410154-11.patch
new file mode 100644
index 0000000..c3a16f3
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-11.patch
@@ -0,0 +1,27 @@
+commit 61a7c9df71ee4e6f94b56c20f0d37c6e17d5f284
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Mon Dec 2 14:53:16 2019 +0100
+
+    elf/tst-dlopenfail: Disable --no-as-needed for tst-dlopenfailmod1.so
+    
+    Otherwise, the shared object dependency which triggers the load
+    failure is dropped, invalidating the test.
+
+diff --git a/elf/Makefile b/elf/Makefile
+index bf7c41f38be42184..467e810e784bb96d 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -1543,8 +1543,11 @@ LDFLAGS-tst-finilazyfailmod.so = \
+ $(objpfx)tst-dlopenfail: $(libdl)
+ $(objpfx)tst-dlopenfail.out: \
+   $(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so
+-# Order matters here.  tst-dlopenfaillinkmod.so's soname ensures
+-# a run-time loader failure.
++# Order matters here.  tst-dlopenfaillinkmod.so's soname ensures a
++# run-time loader failure.  --as-needed breaks this test because
++# nothing actually references tst-dlopenfailmod2.so (with its soname
++# tst-dlopenfail-missingmod.so).
++LDFLAGS-tst-dlopenfailmod1.so = -Wl,--no-as-needed
+ $(objpfx)tst-dlopenfailmod1.so: \
+   $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so
+ LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so
diff --git a/SOURCES/glibc-rh1410154-12.patch b/SOURCES/glibc-rh1410154-12.patch
new file mode 100644
index 0000000..48dcfc3
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-12.patch
@@ -0,0 +1,1229 @@
+commit 365624e2d2a342cdb693b4cc35d2312169959e28
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Fri Dec 13 10:18:24 2019 +0100
+
+    dlopen: Fix issues related to NODELETE handling and relocations
+    
+    The assumption behind the assert in activate_nodelete was wrong:
+    
+    Inconsistency detected by ld.so: dl-open.c: 459: activate_nodelete:
+    Assertion `!imap->l_init_called || imap->l_type != lt_loaded' failed! (edit)
+    
+    It can happen that an already-loaded object that is in the local
+    scope is promoted to NODELETE status, via binding to a unique
+    symbol.
+    
+    Similarly, it is possible that such NODELETE promotion occurs to
+    an already-loaded object from the global scope.  This is why the
+    loop in activate_nodelete has to cover all objects in the namespace
+    of the new object.
+    
+    In do_lookup_unique, it could happen that the NODELETE status of
+    an already-loaded object was overwritten with a pending NODELETE
+    status.  As a result, if dlopen fails, this could cause a loss of
+    the NODELETE status of the affected object, eventually resulting
+    in an incorrect unload.
+    
+    Fixes commit f63b73814f74032c0e5d0a83300e3d864ef905e5 ("Remove all
+    loaded objects if dlopen fails, ignoring NODELETE [BZ #20839]").
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 467e810e784bb96d..16a3e8dcda19b4ba 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -185,7 +185,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ 	 tst-audit1 tst-audit2 tst-audit8 tst-audit9 \
+ 	 tst-addr1 tst-thrlock \
+ 	 tst-unique1 tst-unique2 $(if $(CXX),tst-unique3 tst-unique4 \
+-	 tst-nodelete) \
++	 tst-nodelete tst-dlopen-nodelete-reloc) \
+ 	 tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
+ 	 tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \
+ 	 tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
+@@ -266,7 +266,24 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ 		tst-auditmod9a tst-auditmod9b \
+ 		$(if $(CXX),tst-unique3lib tst-unique3lib2 tst-unique4lib \
+ 		  tst-nodelete-uniquemod tst-nodelete-rtldmod \
+-		  tst-nodelete-zmod) \
++		  tst-nodelete-zmod \
++                  tst-dlopen-nodelete-reloc-mod1 \
++		  tst-dlopen-nodelete-reloc-mod2 \
++	          tst-dlopen-nodelete-reloc-mod3 \
++		  tst-dlopen-nodelete-reloc-mod4 \
++		  tst-dlopen-nodelete-reloc-mod5 \
++	          tst-dlopen-nodelete-reloc-mod6 \
++	          tst-dlopen-nodelete-reloc-mod7 \
++	          tst-dlopen-nodelete-reloc-mod8 \
++	          tst-dlopen-nodelete-reloc-mod9 \
++	          tst-dlopen-nodelete-reloc-mod10 \
++	          tst-dlopen-nodelete-reloc-mod11 \
++	          tst-dlopen-nodelete-reloc-mod12 \
++	          tst-dlopen-nodelete-reloc-mod13 \
++	          tst-dlopen-nodelete-reloc-mod14 \
++	          tst-dlopen-nodelete-reloc-mod15 \
++	          tst-dlopen-nodelete-reloc-mod16 \
++		  tst-dlopen-nodelete-reloc-mod17) \
+ 		tst-initordera1 tst-initorderb1 \
+ 		tst-initordera2 tst-initorderb2 \
+ 		tst-initordera3 tst-initordera4 \
+@@ -1552,3 +1569,48 @@ $(objpfx)tst-dlopenfailmod1.so: \
+   $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so
+ LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so
+ $(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library)
++
++$(objpfx)tst-dlopen-nodelete-reloc: $(libdl)
++$(objpfx)tst-dlopen-nodelete-reloc.out: \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod1.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod2.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod3.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod4.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod5.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod6.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod7.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod8.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod9.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod10.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod11.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod12.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod13.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod14.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod15.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod16.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod17.so
++tst-dlopen-nodelete-reloc-mod2.so-no-z-defs = yes
++LDFLAGS-tst-dlopen-nodelete-reloc-mod2.so = -Wl,-z,nodelete
++$(objpfx)tst-dlopen-nodelete-reloc-mod4.so: \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod3.so
++LDFLAGS-tst-dlopen-nodelete-reloc-mod4.so = -Wl,--no-as-needed
++$(objpfx)tst-dlopen-nodelete-reloc-mod5.so: \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod4.so
++LDFLAGS-tst-dlopen-nodelete-reloc-mod5.so = -Wl,-z,nodelete,--no-as-needed
++tst-dlopen-nodelete-reloc-mod5.so-no-z-defs = yes
++tst-dlopen-nodelete-reloc-mod7.so-no-z-defs = yes
++$(objpfx)tst-dlopen-nodelete-reloc-mod8.so: $(libdl)
++$(objpfx)tst-dlopen-nodelete-reloc-mod10.so: $(libdl)
++tst-dlopen-nodelete-reloc-mod11.so-no-z-defs = yes
++$(objpfx)tst-dlopen-nodelete-reloc-mod13.so: \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod12.so
++$(objpfx)tst-dlopen-nodelete-reloc-mod15.so: \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod14.so
++tst-dlopen-nodelete-reloc-mod16.so-no-z-defs = yes
++$(objpfx)tst-dlopen-nodelete-reloc-mod16.so: \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod15.so
++LDFLAGS-tst-dlopen-nodelete-reloc-mod16.so = -Wl,--no-as-needed
++$(objpfx)tst-dlopen-nodelete-reloc-mod17.so: \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod15.so \
++  $(objpfx)tst-dlopen-nodelete-reloc-mod16.so
++LDFLAGS-tst-dlopen-nodelete-reloc-mod17.so = -Wl,--no-as-needed
+diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
+index c5e5857fb1fe2808..35a3f96a6296294a 100644
+--- a/elf/dl-lookup.c
++++ b/elf/dl-lookup.c
+@@ -311,12 +311,12 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
+       enter_unique_sym (entries, size,
+                         new_hash, strtab + sym->st_name, sym, map);
+ 
+-      if (map->l_type == lt_loaded)
++      if (map->l_type == lt_loaded
++	  && map->l_nodelete == link_map_nodelete_inactive)
+ 	{
+ 	  /* Make sure we don't unload this object by
+ 	     setting the appropriate flag.  */
+-	  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
+-	      && map->l_nodelete == link_map_nodelete_inactive)
++	  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS))
+ 	    _dl_debug_printf ("\
+ marking %s [%lu] as NODELETE due to unique symbol\n",
+ 			      map->l_name, map->l_ns);
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index e13968d4d7c4c83f..c7ed85b7ee99a296 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -433,34 +433,21 @@ TLS generation counter wrapped!  Please report this."));
+    after dlopen failure is not possible, so that _dl_close can clean
+    up objects if necessary.  */
+ static void
+-activate_nodelete (struct link_map *new, int mode)
++activate_nodelete (struct link_map *new)
+ {
+-  if (mode & RTLD_NODELETE || new->l_nodelete == link_map_nodelete_pending)
+-    {
+-      if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES))
+-	_dl_debug_printf ("activating NODELETE for %s [%lu]\n",
+-			  new->l_name, new->l_ns);
+-      new->l_nodelete = link_map_nodelete_active;
+-    }
+-
+-  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_nodelete == link_map_nodelete_pending)
+-	{
+-	  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES))
+-	    _dl_debug_printf ("activating NODELETE for %s [%lu]\n",
+-			      imap->l_name, imap->l_ns);
+-
+-	  /* Only new objects should have set
+-	     link_map_nodelete_pending.  Existing objects should not
+-	     have gained any new dependencies and therefore cannot
+-	     reach NODELETE status.  */
+-	  assert (!imap->l_init_called || imap->l_type != lt_loaded);
++  /* It is necessary to traverse the entire namespace.  References to
++     objects in the global scope and unique symbol bindings can force
++     NODELETE status for objects outside the local scope.  */
++  for (struct link_map *l = GL (dl_ns)[new->l_ns]._ns_loaded; l != NULL;
++       l = l->l_next)
++    if (l->l_nodelete == link_map_nodelete_pending)
++      {
++	if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES))
++	  _dl_debug_printf ("activating NODELETE for %s [%lu]\n",
++			    l->l_name, l->l_ns);
+ 
+-	  imap->l_nodelete = link_map_nodelete_active;
+-	}
+-     }
++	l->l_nodelete = link_map_nodelete_active;
++      }
+ }
+ 
+ /* struct dl_init_args and call_dl_init are used to call _dl_init with
+@@ -718,7 +705,7 @@ dl_open_worker (void *a)
+      All memory allocations for new objects must have happened
+      before.  */
+ 
+-  activate_nodelete (new, mode);
++  activate_nodelete (new);
+ 
+   /* Second stage after resize_scopes: Actually perform the scope
+      update.  After this, dlsym and lazy binding can bind to new
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod1.c b/elf/tst-dlopen-nodelete-reloc-mod1.c
+new file mode 100644
+index 0000000000000000..397d60a2d5ea62d9
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod1.c
+@@ -0,0 +1,39 @@
++/* Test propagation of NODELETE to an already-loaded object via relocation.
++   Non-NODELETE helper module.
++   Copyright (C) 2019 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 <stdio.h>
++#include <unistd.h>
++
++/* Globally exported.  Set by the main program to true before
++   termination, and used by tst-dlopen-nodelete-reloc-mod2.so to
++   trigger marking this module as NODELETE (and also for its destructor
++   check).  */
++bool may_finalize_mod1 = false;
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  if (!may_finalize_mod1)
++    {
++      puts ("error: tst-dlopen-nodelete-reloc-mod1.so destructor"
++            " called too early");
++      _exit (1);
++    }
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod10.c b/elf/tst-dlopen-nodelete-reloc-mod10.c
+new file mode 100644
+index 0000000000000000..30748b73ec7daed3
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod10.c
+@@ -0,0 +1,41 @@
++/* Helper module to load tst-dlopen-nodelete-reloc-mod11.so.
++   Copyright (C) 2019 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 <stddef.h>
++#include <stdio.h>
++#include <unistd.h>
++
++static void *handle;
++
++static void __attribute__ ((constructor))
++init (void)
++{
++  handle = dlopen ("tst-dlopen-nodelete-reloc-mod11.so", RTLD_NOW);
++  if (handle == NULL)
++    {
++      printf ("error: dlopen in module 10: %s\n", dlerror ());
++      _exit (1);
++    }
++}
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  dlclose (handle);
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod11.cc b/elf/tst-dlopen-nodelete-reloc-mod11.cc
+new file mode 100644
+index 0000000000000000..48c910403e782c83
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod11.cc
+@@ -0,0 +1,49 @@
++/* Second module defining a unique symbol (loaded indirectly).
++   Copyright (C) 2019 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 "tst-dlopen-nodelete-reloc.h"
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <unistd.h>
++
++/* Just a flag here, not used for NODELETE processing.  */
++bool may_finalize_mod11 = false;
++
++/* Trigger the creation of a unique symbol reference.  This should
++   cause tst-dlopen-nodelete-reloc-mod9.so to be marked as
++   NODELETE.  */
++
++extern template struct unique_symbol<9>;
++
++int
++global_function_mod11 (void)
++{
++  return unique_symbol<9>::value;
++}
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  if (!may_finalize_mod11)
++    {
++      puts ("error: tst-dlopen-nodelete-reloc-mod11.so destructor"
++            " called too early");
++      _exit (1);
++    }
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod12.cc b/elf/tst-dlopen-nodelete-reloc-mod12.cc
+new file mode 100644
+index 0000000000000000..5c093fd02d1fd0c7
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod12.cc
+@@ -0,0 +1,42 @@
++/* First module for NODELETE test defining a unique symbol (with DT_NEEDED).
++   Copyright (C) 2019 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 "tst-dlopen-nodelete-reloc.h"
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <unistd.h>
++
++/* Just a flag here, not used for NODELETE processing.  */
++bool may_finalize_mod12 = false;
++
++/* Explicit instantiation.  This produces a unique symbol definition
++   which is not referenced by the library itself, so the library is
++   not marked NODELETE.  */
++template struct unique_symbol<12>;
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  if (!may_finalize_mod12)
++    {
++      puts ("error: tst-dlopen-nodelete-reloc-mod12.so destructor"
++            " called too early");
++      _exit (1);
++    }
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod13.cc b/elf/tst-dlopen-nodelete-reloc-mod13.cc
+new file mode 100644
+index 0000000000000000..caf4fd1cc9e1c1e1
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod13.cc
+@@ -0,0 +1,48 @@
++/* Second module for NODELETE test defining a unique symbol (with DT_NEEDED).
++   Copyright (C) 2019 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 "tst-dlopen-nodelete-reloc.h"
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <unistd.h>
++
++/* Just a flag here, not used for NODELETE processing.  */
++bool may_finalize_mod13 = false;
++
++extern template struct unique_symbol<12>;
++
++/* Trigger the creation of a unique symbol reference.  This should
++   cause tst-dlopen-nodelete-reloc-mod12.so to be marked as
++   NODELETE.  */
++int
++global_function_mod13 (void)
++{
++  return unique_symbol<12>::value;
++}
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  if (!may_finalize_mod13)
++    {
++      puts ("error: tst-dlopen-nodelete-reloc-mod13.so destructor"
++            " called too early");
++      _exit (1);
++    }
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod13.h b/elf/tst-dlopen-nodelete-reloc-mod13.h
+new file mode 100644
+index 0000000000000000..5d338481a34a5714
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod13.h
+@@ -0,0 +1,24 @@
++/* Inline function which produces a unique symbol.
++   Copyright (C) 2019 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/>.  */
++
++inline char *
++third_function_with_local_static (void)
++{
++  static char local;
++  return &local;
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod14.cc b/elf/tst-dlopen-nodelete-reloc-mod14.cc
+new file mode 100644
+index 0000000000000000..e67621a2a2f8509a
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod14.cc
+@@ -0,0 +1,42 @@
++/* This object must retain NODELETE status after a dlopen failure.
++   Copyright (C) 2019 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 "tst-dlopen-nodelete-reloc.h"
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <unistd.h>
++
++/* Just a flag here, not used for NODELETE processing.  */
++bool may_finalize_mod14 = false;
++
++/* Explicit instantiation.  This produces a unique symbol definition
++   which is not referenced by the library itself, so the library is
++   not marked NODELETE.  */
++template struct unique_symbol<14>;
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  if (!may_finalize_mod14)
++    {
++      puts ("error: tst-dlopen-nodelete-reloc-mod14.so destructor"
++            " called too early");
++      _exit (1);
++    }
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod15.cc b/elf/tst-dlopen-nodelete-reloc-mod15.cc
+new file mode 100644
+index 0000000000000000..ead362bfdbb90eef
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod15.cc
+@@ -0,0 +1,42 @@
++/* Helper object to mark tst-dlopen-nodelete-reloc-mod14.so as NODELETE.
++   Copyright (C) 2019 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 "tst-dlopen-nodelete-reloc.h"
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <unistd.h>
++
++extern template struct unique_symbol<14>;
++
++/* Trigger the creation of a unique symbol reference.  This should
++   cause tst-dlopen-nodelete-reloc-mod14.so to be marked as
++   NODELETE.  */
++int
++global_function_mod15 (void)
++{
++  return unique_symbol<14>::value;
++}
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  /* This object is never loaded completely.  */
++  puts ("error: tst-dlopen-nodelete-reloc-mod15.so destructor invoked");
++  _exit (1);
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod16.c b/elf/tst-dlopen-nodelete-reloc-mod16.c
+new file mode 100644
+index 0000000000000000..fa2ed1461b42c82c
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod16.c
+@@ -0,0 +1,27 @@
++/* Object with an undefined symbol to trigger a relocation failure.
++   Copyright (C) 2019 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/>.  */
++
++/* The reference to undefined_mod16 triggers a relocation failure.  */
++
++extern int undefined_mod16;
++
++int
++global_function_mod16 (void)
++{
++  return undefined_mod16;
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod17.c b/elf/tst-dlopen-nodelete-reloc-mod17.c
+new file mode 100644
+index 0000000000000000..426562edd9a3ffee
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod17.c
+@@ -0,0 +1,19 @@
++/* Top-level object with dependency on an object that fails relocation.
++   Copyright (C) 2019 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/>.  */
++
++/* The dependencies do all the work.  */
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod2.c b/elf/tst-dlopen-nodelete-reloc-mod2.c
+new file mode 100644
+index 0000000000000000..81ea8e5af2d00b93
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod2.c
+@@ -0,0 +1,38 @@
++/* Test propagation of NODELETE to an already-loaded object via relocation.
++   NODELETE helper module.
++   Copyright (C) 2019 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 <stdio.h>
++#include <unistd.h>
++
++/* Defined in tst-dlopen-nodelete-reloc-mod1.so.  This dependency is
++   not expressed via DT_NEEDED, so this reference marks the other
++   object as NODELETE dynamically, during initially relocation.  */
++extern bool may_finalize_mod1;
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  if (!may_finalize_mod1)
++    {
++      puts ("error: tst-dlopen-nodelete-reloc-mod2.so destructor"
++            " called too early");
++      _exit (1);
++    }
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod3.c b/elf/tst-dlopen-nodelete-reloc-mod3.c
+new file mode 100644
+index 0000000000000000..d33f4ec7630c6a1e
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod3.c
+@@ -0,0 +1,38 @@
++/* Test propagation of NODELETE to an already-loaded object via relocation.
++   Non-NODELETE helper module.
++   Copyright (C) 2019 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 <stdio.h>
++#include <unistd.h>
++
++/* Globally exported.  Set by the main program to true before
++   termination, and used by tst-dlopen-nodelete-reloc-mod4.so,
++   tst-dlopen-nodelete-reloc-mod5.so.  */
++bool may_finalize_mod3 = false;
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  if (!may_finalize_mod3)
++    {
++      puts ("error: tst-dlopen-nodelete-reloc-mod3.so destructor"
++            " called too early");
++      _exit (1);
++    }
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod4.c b/elf/tst-dlopen-nodelete-reloc-mod4.c
+new file mode 100644
+index 0000000000000000..7e6633aebb1e2f00
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod4.c
+@@ -0,0 +1,37 @@
++/* Test propagation of NODELETE to an already-loaded object via relocation.
++   Intermediate helper module.
++   Copyright (C) 2019 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 <stdio.h>
++#include <unistd.h>
++
++/* Defined in tst-dlopen-nodelete-reloc-mod3.so.  The dependency is
++   expressed via DT_NEEDED.  */
++extern bool may_finalize_mod3;
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  if (!may_finalize_mod3)
++    {
++      puts ("error: tst-dlopen-nodelete-reloc-mod4.so destructor"
++            " called too early");
++      _exit (1);
++    }
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod5.c b/elf/tst-dlopen-nodelete-reloc-mod5.c
+new file mode 100644
+index 0000000000000000..22aa16f855dc75a8
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod5.c
+@@ -0,0 +1,38 @@
++/* Test propagation of NODELETE to an already-loaded object via relocation.
++   NODELETE helper module.
++   Copyright (C) 2019 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 <stdio.h>
++#include <unistd.h>
++
++/* Defined in tst-dlopen-nodelete-reloc-mod3.so.  The dependency is
++   expressed via DT_NEEDED on the intermediate DSO
++   tst-dlopen-nodelete-reloc-mod3.so.  */
++extern bool may_finalize_mod3;
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  if (!may_finalize_mod3)
++    {
++      puts ("error: tst-dlopen-nodelete-reloc-mod5.so destructor"
++            " called too early");
++      _exit (1);
++    }
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod6.cc b/elf/tst-dlopen-nodelete-reloc-mod6.cc
+new file mode 100644
+index 0000000000000000..180f5b5842f1c2b0
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod6.cc
+@@ -0,0 +1,42 @@
++/* First module for NODELETE test defining a unique symbol.
++   Copyright (C) 2019 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 "tst-dlopen-nodelete-reloc.h"
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <unistd.h>
++
++/* Just a flag here, not used for NODELETE processing.  */
++bool may_finalize_mod6 = false;
++
++/* Explicit instantiation.  This produces a unique symbol definition
++   which is not referenced by the library itself, so the library is
++   not marked NODELETE.  */
++template struct unique_symbol<6>;
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  if (!may_finalize_mod6)
++    {
++      puts ("error: tst-dlopen-nodelete-reloc-mod6.so destructor"
++            " called too early");
++      _exit (1);
++    }
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod7.cc b/elf/tst-dlopen-nodelete-reloc-mod7.cc
+new file mode 100644
+index 0000000000000000..c85e7c991b098bf5
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod7.cc
+@@ -0,0 +1,48 @@
++/* Second module for NODELETE test defining a unique symbol.
++   Copyright (C) 2019 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 "tst-dlopen-nodelete-reloc.h"
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <unistd.h>
++
++/* Just a flag here, not used for NODELETE processing.  */
++bool may_finalize_mod7 = false;
++
++extern template struct unique_symbol<6>;
++
++/* Trigger the creation of a unique symbol reference.  This should
++   cause tst-dlopen-nodelete-reloc-mod6.so to be marked as
++   NODELETE.  */
++int
++global_function_mod7 (void)
++{
++  return unique_symbol<6>::value;
++}
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  if (!may_finalize_mod7)
++    {
++      puts ("error: tst-dlopen-nodelete-reloc-mod7.so destructor"
++            " called too early");
++      _exit (1);
++    }
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod8.c b/elf/tst-dlopen-nodelete-reloc-mod8.c
+new file mode 100644
+index 0000000000000000..ebb1c35fab57e319
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod8.c
+@@ -0,0 +1,41 @@
++/* Helper module to load tst-dlopen-nodelete-reloc-mod9.so.
++   Copyright (C) 2019 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 <stddef.h>
++#include <stdio.h>
++#include <unistd.h>
++
++static void *handle;
++
++static void __attribute__ ((constructor))
++init (void)
++{
++  handle = dlopen ("tst-dlopen-nodelete-reloc-mod9.so", RTLD_NOW);
++  if (handle == NULL)
++    {
++      printf ("error: dlopen in module 8: %s\n", dlerror ());
++      _exit (1);
++    }
++}
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  dlclose (handle);
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc-mod9.cc b/elf/tst-dlopen-nodelete-reloc-mod9.cc
+new file mode 100644
+index 0000000000000000..06fb49cdf753cb41
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc-mod9.cc
+@@ -0,0 +1,42 @@
++/* First module defining a unique symbol (loaded indirectly).
++   Copyright (C) 2019 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 "tst-dlopen-nodelete-reloc.h"
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <unistd.h>
++
++/* Just a flag here, not used for NODELETE processing.  */
++bool may_finalize_mod9 = false;
++
++/* Explicit instantiation.  This produces a unique symbol definition
++   which is not referenced by the library itself, so the library is
++   not marked NODELETE.  */
++template struct unique_symbol<9>;
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  if (!may_finalize_mod9)
++    {
++      puts ("error: tst-dlopen-nodelete-reloc-mod9.so destructor"
++            " called too early");
++      _exit (1);
++    }
++}
+diff --git a/elf/tst-dlopen-nodelete-reloc.c b/elf/tst-dlopen-nodelete-reloc.c
+new file mode 100644
+index 0000000000000000..291ac9eb8385a92e
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc.c
+@@ -0,0 +1,179 @@
++/* Test interactions of dlopen, NODELETE, and relocations.
++   Copyright (C) 2019 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 test exercises NODELETE propagation due to data relocations
++   and unique symbols, and the interaction with already-loaded
++   objects.  Some test objects are written in C++, to produce unique
++   symbol definitions.
++
++   First test: Global scope variant, data relocation as the NODELETE
++   trigger.  mod1 is loaded first with a separate dlopen call.
++
++      mod2 ---(may_finalize_mod1 relocation dependency)---> mod1
++    (NODELETE)                                   (marked as NODELETE)
++
++   Second test: Local scope variant, data relocation.  mod3 is loaded
++   first, then mod5.
++
++      mod5 ---(DT_NEEDED)--->  mod4  ---(DT_NEEDED)---> mod3
++    (NODELETE)           (not NODELETE)                  ^
++        \                                               / (marked as
++         `--(may_finalize_mod3 relocation dependency)--/   NODELETE)
++
++   Third test: Shared local scope with unique symbol.  mod6 is loaded
++   first, then mod7.  No explicit dependencies between the two
++   objects, so first object has to be opened with RTLD_GLOBAL.
++
++      mod7 ---(unique symbol)---> mod6
++                          (marked as NODELETE)
++
++   Forth test: Non-shared scopes with unique symbol.  mod8 and mod10
++   are loaded from the main program.  mod8 loads mod9 from an ELF
++   constructor, mod10 loads mod11.  There are no DT_NEEDED
++   dependencies.  mod9 is promoted to the global scope form the main
++   program.  The unique symbol dependency is:
++
++      mod9 ---(unique symbol)---> mod11
++                          (marked as NODELETE)
++
++   Fifth test: Shared local scope with unique symbol, like test 3, but
++   this time, there is also a DT_NEEDED dependency (so no RTLD_GLOBAL
++   needed):
++
++                 DT_NEEDED
++      mod13 ---(unique symbol)---> mod12
++                          (marked as NODELETE)
++
++   Sixth test: NODELETE status is retained after relocation failure
++   with unique symbol dependency.  The object graph ensures that the
++   unique symbol binding is processed before the dlopen failure.
++
++                                        DT_NEEDED
++     mod17  --(DT_NEEDED)--> mod15 --(unique symbol)--> mod14
++       \                       ^                  (RTLD_NODELETE)
++        \                 (DT_NEEDED)
++         \                     |
++          `---(DT_NEEDED)--> mod16
++                       (fails to relocate)
++
++   mod14 is loaded first, and the loading mod17 is attempted.
++   mod14 must remain NODELETE after opening mod17 failed.  */
++
++#include <stdio.h>
++#include <string.h>
++#include <stdbool.h>
++#include <support/check.h>
++#include <support/xdlfcn.h>
++
++static int
++do_test (void)
++{
++  /* First case: global scope, regular data symbol.  Open the object
++     which is not NODELETE initially.  */
++  void *mod1 = xdlopen ("tst-dlopen-nodelete-reloc-mod1.so",
++                        RTLD_NOW | RTLD_GLOBAL);
++  /* This is used to indicate that the ELF destructor may be
++     called.  */
++  bool *may_finalize_mod1 = xdlsym (mod1, "may_finalize_mod1");
++  /* Open the NODELETE object.  */
++  void *mod2 = xdlopen ("tst-dlopen-nodelete-reloc-mod2.so", RTLD_NOW);
++  /* This has no effect because the DSO is directly marked as
++     NODELETE.  */
++  xdlclose (mod2);
++  /* This has no effect because the DSO has been indirectly marked as
++     NODELETE due to a relocation dependency.  */
++  xdlclose (mod1);
++
++  /* Second case: local scope, regular data symbol.  Open the object
++     which is not NODELETE initially.  */
++  void *mod3 = xdlopen ("tst-dlopen-nodelete-reloc-mod3.so", RTLD_NOW);
++  bool *may_finalize_mod3 = xdlsym (mod3, "may_finalize_mod3");
++  /* Open the NODELETE object.  */
++  void *mod5 = xdlopen ("tst-dlopen-nodelete-reloc-mod5.so", RTLD_NOW);
++  /* Again those have no effect because of NODELETE.  */
++  xdlclose (mod5);
++  xdlclose (mod3);
++
++  /* Third case: Unique symbol.  */
++  void *mod6 = xdlopen ("tst-dlopen-nodelete-reloc-mod6.so",
++                        RTLD_NOW | RTLD_GLOBAL);
++  bool *may_finalize_mod6 = xdlsym (mod6, "may_finalize_mod6");
++  void *mod7 = xdlopen ("tst-dlopen-nodelete-reloc-mod7.so", RTLD_NOW);
++  bool *may_finalize_mod7 = xdlsym (mod7, "may_finalize_mod7");
++  /* This should not have any effect because of the unique symbol and
++     the resulting NODELETE status.  */
++  xdlclose (mod6);
++  /* mod7 is not NODELETE and can be closed.  */
++  *may_finalize_mod7 = true;
++  xdlclose (mod7);
++
++  /* Fourth case: Unique symbol, indirect loading.  */
++  void *mod8 = xdlopen ("tst-dlopen-nodelete-reloc-mod8.so", RTLD_NOW);
++  /* Also promote to global scope.  */
++  void *mod9 = xdlopen ("tst-dlopen-nodelete-reloc-mod9.so",
++                        RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL);
++  bool *may_finalize_mod9 = xdlsym (mod9, "may_finalize_mod9");
++  xdlclose (mod9);              /* Drop mod9 reference.  */
++  void *mod10 = xdlopen ("tst-dlopen-nodelete-reloc-mod10.so", RTLD_NOW);
++  void *mod11 = xdlopen ("tst-dlopen-nodelete-reloc-mod11.so",
++                        RTLD_NOW | RTLD_NOLOAD);
++  bool *may_finalize_mod11 = xdlsym (mod11, "may_finalize_mod11");
++  xdlclose (mod11);              /* Drop mod11 reference.  */
++  /* mod11 is not NODELETE and can be closed.  */
++  *may_finalize_mod11 = true;
++  /* Trigger closing of mod11, too.  */
++  xdlclose (mod10);
++  /* Does not trigger closing of mod9.  */
++  xdlclose (mod8);
++
++  /* Fifth case: Unique symbol, with DT_NEEDED dependency.  */
++  void *mod12 = xdlopen ("tst-dlopen-nodelete-reloc-mod12.so", RTLD_NOW);
++  bool *may_finalize_mod12 = xdlsym (mod12, "may_finalize_mod12");
++  void *mod13 = xdlopen ("tst-dlopen-nodelete-reloc-mod13.so", RTLD_NOW);
++  bool *may_finalize_mod13 = xdlsym (mod13, "may_finalize_mod13");
++  /* This should not have any effect because of the unique symbol. */
++  xdlclose (mod12);
++  /* mod13 is not NODELETE and can be closed.  */
++  *may_finalize_mod13 = true;
++  xdlclose (mod13);
++
++  /* Sixth case: Unique symbol binding must not cause loss of NODELETE
++     status.  */
++  void *mod14 = xdlopen ("tst-dlopen-nodelete-reloc-mod14.so",
++                         RTLD_NOW | RTLD_NODELETE);
++  bool *may_finalize_mod14 = xdlsym (mod14, "may_finalize_mod14");
++  TEST_VERIFY (dlopen ("tst-dlopen-nodelete-reloc-mod17.so", RTLD_NOW)
++               == NULL);
++  const char *message = dlerror ();
++  printf ("info: test 6 message: %s\n", message);
++  /* This must not close the object, it must still be NODELETE.  */
++  xdlclose (mod14);
++  xdlopen ("tst-dlopen-nodelete-reloc-mod14.so", RTLD_NOW | RTLD_NOLOAD);
++
++  /* Prepare for process exit.  Destructors for NODELETE objects will
++     be invoked.  */
++  *may_finalize_mod1 = true;
++  *may_finalize_mod3 = true;
++  *may_finalize_mod6 = true;
++  *may_finalize_mod9 = true;
++  *may_finalize_mod12 = true;
++  *may_finalize_mod14 = true;
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/elf/tst-dlopen-nodelete-reloc.h b/elf/tst-dlopen-nodelete-reloc.h
+new file mode 100644
+index 0000000000000000..8844de622631f575
+--- /dev/null
++++ b/elf/tst-dlopen-nodelete-reloc.h
+@@ -0,0 +1,35 @@
++/* Template to produce unique symbols.
++   Copyright (C) 2019 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 template produces a unique symbol definition for an explicit
++   template instantiation (without also incorporating a reference),
++   and an extern template declaration can be used to reference that
++   symbol from another object.  The modid parameter is just a
++   placeholder to create different symbols (because it affects the
++   name mangling of the static value member).  By convention, it
++   should match the number of the module that contains the
++   definition.  */
++
++template <int modid>
++struct unique_symbol
++{
++  static int value;
++};
++
++template <int modid>
++int unique_symbol<modid>::value;
diff --git a/SOURCES/glibc-rh1410154-13.patch b/SOURCES/glibc-rh1410154-13.patch
new file mode 100644
index 0000000..1ec1768
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-13.patch
@@ -0,0 +1,328 @@
+commit f8ed116aa574435c6e28260f21963233682d3b57
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Fri Dec 13 10:18:46 2019 +0100
+
+    dlopen: Rework handling of pending NODELETE status
+    
+    Commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23 ("Block signals during
+    the initial part of dlopen") was deemed necessary because of
+    read-modify-write operations like the one in  add_dependency in
+    elf/dl-lookup.c.  In the old code, we check for any kind of NODELETE
+    status and bail out:
+    
+          /* Redo the NODELETE check, as when dl_load_lock wasn't held
+             yet this could have changed.  */
+          if (map->l_nodelete != link_map_nodelete_inactive)
+            goto out;
+    
+    And then set pending status (during relocation):
+    
+              if (flags & DL_LOOKUP_FOR_RELOCATE)
+                map->l_nodelete = link_map_nodelete_pending;
+              else
+                map->l_nodelete = link_map_nodelete_active;
+    
+    If a signal arrives during relocation and the signal handler, through
+    lazy binding, adds a global scope dependency on the same map, it will
+    set map->l_nodelete to link_map_nodelete_active.  This will be
+    overwritten with link_map_nodelete_pending by the dlopen relocation
+    code.
+    
+    To avoid such problems in relation to the l_nodelete member, this
+    commit introduces two flags for active NODELETE status (irrevocable)
+    and pending NODELETE status (revocable until activate_nodelete is
+    invoked).  As a result, NODELETE processing in dlopen does not
+    introduce further reasons why lazy binding from signal handlers
+    is unsafe during dlopen, and a subsequent commit can remove signal
+    blocking from dlopen.
+    
+    This does not address pre-existing issues (unrelated to the NODELETE
+    changes) which make lazy binding in a signal handler during dlopen
+    unsafe, such as the use of malloc in both cases.
+    
+    Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
+    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+
+diff --git a/elf/dl-close.c b/elf/dl-close.c
+index 243a028c443173c1..fa7f3e8174576e46 100644
+--- a/elf/dl-close.c
++++ b/elf/dl-close.c
+@@ -197,7 +197,7 @@ _dl_close_worker (struct link_map *map, bool force)
+       /* Check whether this object is still used.  */
+       if (l->l_type == lt_loaded
+ 	  && l->l_direct_opencount == 0
+-	  && l->l_nodelete != link_map_nodelete_active
++	  && !l->l_nodelete_active
+ 	  /* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why
+ 	     acquire is sufficient and correct.  */
+ 	  && atomic_load_acquire (&l->l_tls_dtor_count) == 0
+@@ -279,8 +279,7 @@ _dl_close_worker (struct link_map *map, bool force)
+ 
+       if (!used[i])
+ 	{
+-	  assert (imap->l_type == lt_loaded
+-		  && imap->l_nodelete != link_map_nodelete_active);
++	  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
+@@ -820,7 +819,7 @@ _dl_close (void *_map)
+      before we took the lock. There is no way to detect this (see below)
+      so we proceed assuming this isn't the case.  First see whether we
+      can remove the object at all.  */
+-  if (__glibc_unlikely (map->l_nodelete == link_map_nodelete_active))
++  if (__glibc_unlikely (map->l_nodelete_active))
+     {
+       /* Nope.  Do nothing.  */
+       __rtld_lock_unlock_recursive (GL(dl_load_lock));
+diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
+index 35a3f96a6296294a..01724a54f8840f9f 100644
+--- a/elf/dl-lookup.c
++++ b/elf/dl-lookup.c
+@@ -187,6 +187,28 @@ enter_unique_sym (struct unique_sym *table, size_t size,
+   table[idx].map = map;
+ }
+ 
++/* Mark MAP as NODELETE according to the lookup mode in FLAGS.  During
++   initial relocation, NODELETE state is pending only.  */
++static void
++mark_nodelete (struct link_map *map, int flags)
++{
++  if (flags & DL_LOOKUP_FOR_RELOCATE)
++    map->l_nodelete_pending = true;
++  else
++    map->l_nodelete_active = true;
++}
++
++/* Return true if MAP is marked as NODELETE according to the lookup
++   mode in FLAGS> */
++static bool
++is_nodelete (struct link_map *map, int flags)
++{
++  /* Non-pending NODELETE always counts.  Pending NODELETE only counts
++     during initial relocation processing.  */
++  return map->l_nodelete_active
++    || ((flags & DL_LOOKUP_FOR_RELOCATE) && map->l_nodelete_pending);
++}
++
+ /* Utility function for do_lookup_x. Lookup an STB_GNU_UNIQUE symbol
+    in the unique symbol table, creating a new entry if necessary.
+    Return the matching symbol in RESULT.  */
+@@ -311,8 +333,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
+       enter_unique_sym (entries, size,
+                         new_hash, strtab + sym->st_name, sym, map);
+ 
+-      if (map->l_type == lt_loaded
+-	  && map->l_nodelete == link_map_nodelete_inactive)
++      if (map->l_type == lt_loaded && !is_nodelete (map, flags))
+ 	{
+ 	  /* Make sure we don't unload this object by
+ 	     setting the appropriate flag.  */
+@@ -320,10 +341,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
+ 	    _dl_debug_printf ("\
+ marking %s [%lu] as NODELETE due to unique symbol\n",
+ 			      map->l_name, map->l_ns);
+-	  if (flags & DL_LOOKUP_FOR_RELOCATE)
+-	    map->l_nodelete = link_map_nodelete_pending;
+-	  else
+-	    map->l_nodelete = link_map_nodelete_active;
++	  mark_nodelete (map, flags);
+ 	}
+     }
+   ++tab->n_elements;
+@@ -586,7 +604,7 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
+      dependencies may pick an dependency which can be dlclose'd, but
+      such IFUNC resolvers are undefined anyway.  */
+   assert (map->l_type == lt_loaded);
+-  if (map->l_nodelete != link_map_nodelete_inactive)
++  if (is_nodelete (map, flags))
+     return 0;
+ 
+   struct link_map_reldeps *l_reldeps
+@@ -694,17 +712,16 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
+ 
+       /* Redo the NODELETE check, as when dl_load_lock wasn't held
+ 	 yet this could have changed.  */
+-      if (map->l_nodelete != link_map_nodelete_inactive)
++      if (is_nodelete (map, flags))
+ 	goto out;
+ 
+       /* If the object with the undefined reference cannot be removed ever
+ 	 just make sure the same is true for the object which contains the
+ 	 definition.  */
+-      if (undef_map->l_type != lt_loaded
+-	  || (undef_map->l_nodelete != link_map_nodelete_inactive))
++      if (undef_map->l_type != lt_loaded || is_nodelete (map, flags))
+ 	{
+ 	  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
+-	      && map->l_nodelete == link_map_nodelete_inactive)
++	      && !is_nodelete (map, flags))
+ 	    {
+ 	      if (undef_map->l_name[0] == '\0')
+ 		_dl_debug_printf ("\
+@@ -716,11 +733,7 @@ marking %s [%lu] as NODELETE due to reference to %s [%lu]\n",
+ 				  map->l_name, map->l_ns,
+ 				  undef_map->l_name, undef_map->l_ns);
+ 	    }
+-
+-	  if (flags & DL_LOOKUP_FOR_RELOCATE)
+-	    map->l_nodelete = link_map_nodelete_pending;
+-	  else
+-	    map->l_nodelete = link_map_nodelete_active;
++	  mark_nodelete (map, flags);
+ 	  goto out;
+ 	}
+ 
+@@ -746,17 +759,14 @@ marking %s [%lu] as NODELETE due to reference to %s [%lu]\n",
+ 		 cannot be unloaded.  This is semantically the correct
+ 		 behavior.  */
+ 	      if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
+-		  && map->l_nodelete == link_map_nodelete_inactive)
++		  && !is_nodelete (map, flags))
+ 		_dl_debug_printf ("\
+ marking %s [%lu] as NODELETE due to memory allocation failure\n",
+ 				  map->l_name, map->l_ns);
+-	      if (flags & DL_LOOKUP_FOR_RELOCATE)
+-		/* In case of non-lazy binding, we could actually
+-		   report the memory allocation error, but for now, we
+-		   use the conservative approximation as well. */
+-		map->l_nodelete = link_map_nodelete_pending;
+-	      else
+-		map->l_nodelete = link_map_nodelete_active;
++	      /* In case of non-lazy binding, we could actually report
++		 the memory allocation error, but for now, we use the
++		 conservative approximation as well.  */
++	      mark_nodelete (map, flags);
+ 	      goto out;
+ 	    }
+ 	  else
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index c7ed85b7ee99a296..a382bfae8aa3a2f8 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -440,13 +440,17 @@ activate_nodelete (struct link_map *new)
+      NODELETE status for objects outside the local scope.  */
+   for (struct link_map *l = GL (dl_ns)[new->l_ns]._ns_loaded; l != NULL;
+        l = l->l_next)
+-    if (l->l_nodelete == link_map_nodelete_pending)
++    if (l->l_nodelete_pending)
+       {
+ 	if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES))
+ 	  _dl_debug_printf ("activating NODELETE for %s [%lu]\n",
+ 			    l->l_name, l->l_ns);
+ 
+-	l->l_nodelete = link_map_nodelete_active;
++	l->l_nodelete_active = true;
++
++	/* This is just a debugging aid, to indicate that
++	   activate_nodelete has run for this map.  */
++	l->l_nodelete_pending = false;
+       }
+ }
+ 
+@@ -549,10 +553,10 @@ dl_open_worker (void *a)
+       if (__glibc_unlikely (mode & RTLD_NODELETE))
+ 	{
+ 	  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)
+-	      && new->l_nodelete == link_map_nodelete_inactive)
++	      && !new->l_nodelete_active)
+ 	    _dl_debug_printf ("marking %s [%lu] as NODELETE\n",
+ 			      new->l_name, new->l_ns);
+-	  new->l_nodelete = link_map_nodelete_active;
++	  new->l_nodelete_active = true;
+ 	}
+ 
+       /* Finalize the addition to the global scope.  */
+@@ -568,7 +572,7 @@ dl_open_worker (void *a)
+   /* Schedule NODELETE marking for the directly loaded object if
+      requested.  */
+   if (__glibc_unlikely (mode & RTLD_NODELETE))
+-    new->l_nodelete = link_map_nodelete_pending;
++    new->l_nodelete_pending = true;
+ 
+   /* Load that object's dependencies.  */
+   _dl_map_object_deps (new, NULL, 0, 0,
+@@ -680,7 +684,7 @@ dl_open_worker (void *a)
+ 	      _dl_start_profile ();
+ 
+ 	      /* Prevent unloading the object.  */
+-	      GL(dl_profile_map)->l_nodelete = link_map_nodelete_active;
++	      GL(dl_profile_map)->l_nodelete_active = true;
+ 	    }
+ 	}
+       else
+@@ -879,9 +883,9 @@ no more namespaces available for dlmopen()"));
+ 	     happens inside dl_open_worker.  */
+ 	  __libc_signal_restore_set (&args.original_signal_mask);
+ 
+-	  /* All link_map_nodelete_pending objects should have been
+-	     deleted at this point, which is why it is not necessary
+-	     to reset the flag here.  */
++	  /* All l_nodelete_pending objects should have been deleted
++	     at this point, which is why it is not necessary to reset
++	     the flag here.  */
+ 	}
+       else
+ 	__libc_signal_restore_set (&args.original_signal_mask);
+diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
+index ea286abaea0128d1..78ba7e76db9706cc 100644
+--- a/elf/get-dynamic-info.h
++++ b/elf/get-dynamic-info.h
+@@ -164,7 +164,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
+     {
+       l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val;
+       if (l->l_flags_1 & DF_1_NODELETE)
+-	l->l_nodelete = link_map_nodelete_pending;
++	l->l_nodelete_pending = true;
+ 
+       /* Only DT_1_SUPPORTED_MASK bits are supported, and we would like
+ 	 to assert this, but we can't. Users have been setting
+diff --git a/include/link.h b/include/link.h
+index a277b77cad6b52b1..e90fa79a0b332087 100644
+--- a/include/link.h
++++ b/include/link.h
+@@ -79,22 +79,6 @@ struct r_search_path_struct
+     int malloced;
+   };
+ 
+-/* Type used by the l_nodelete member.  */
+-enum link_map_nodelete
+-{
+- /* This link map can be deallocated.  */
+- link_map_nodelete_inactive = 0, /* Zero-initialized in _dl_new_object.  */
+-
+- /* This link map cannot be deallocated.  */
+- link_map_nodelete_active,
+-
+- /* This link map cannot be deallocated after dlopen has succeded.
+-    dlopen turns this into link_map_nodelete_active.  dlclose treats
+-    this intermediate state as link_map_nodelete_active.  */
+- link_map_nodelete_pending,
+-};
+-
+-
+ /* Structure describing a loaded shared object.  The `l_next' and `l_prev'
+    members form a chain of all the shared objects loaded at startup.
+ 
+@@ -218,10 +202,17 @@ struct link_map
+ 				       freed, ie. not allocated with
+ 				       the dummy malloc in ld.so.  */
+ 
+-    /* Actually of type enum link_map_nodelete.  Separate byte due to
+-       a read in add_dependency in elf/dl-lookup.c outside the loader
+-       lock.  Only valid for l_type == lt_loaded.  */
+-    unsigned char l_nodelete;
++    /* NODELETE status of the map.  Only valid for maps of type
++       lt_loaded.  Lazy binding sets l_nodelete_active directly,
++       potentially from signal handlers.  Initial loading of an
++       DF_1_NODELETE object set l_nodelete_pending.  Relocation may
++       set l_nodelete_pending as well.  l_nodelete_pending maps are
++       promoted to l_nodelete_active status in the final stages of
++       dlopen, prior to calling ELF constructors.  dlclose only
++       refuses to unload l_nodelete_active maps, the pending status is
++       ignored.  */
++    bool l_nodelete_active;
++    bool l_nodelete_pending;
+ 
+ #include <link_map.h>
+ 
diff --git a/SOURCES/glibc-rh1410154-14.patch b/SOURCES/glibc-rh1410154-14.patch
new file mode 100644
index 0000000..ac4d1e2
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-14.patch
@@ -0,0 +1,134 @@
+commit f7649d5780aa4682393b9daedd653e4d9c12784c
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Fri Dec 13 10:23:10 2019 +0100
+
+    dlopen: Do not block signals
+    
+    Blocking signals causes issues with certain anti-malware solutions
+    which rely on an unblocked SIGSYS signal for system calls they
+    intercept.
+    
+    This reverts commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23
+    ("Block signals during the initial part of dlopen") and adds
+    comments related to async signal safety to active_nodelete and
+    its caller.
+    
+    Note that this does not make lazy binding async-signal-safe with regards
+    to dlopen.  It merely avoids introducing new async-signal-safety hazards
+    as part of the NODELETE changes.
+    
+    Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
+    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index a382bfae8aa3a2f8..d834b89754d2b073 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -34,7 +34,6 @@
+ #include <atomic.h>
+ #include <libc-internal.h>
+ #include <array_length.h>
+-#include <internal-signals.h>
+ 
+ #include <dl-dst.h>
+ #include <dl-prop.h>
+@@ -53,10 +52,6 @@ struct dl_open_args
+   /* Namespace ID.  */
+   Lmid_t nsid;
+ 
+-  /* Original signal mask.  Used for unblocking signal handlers before
+-     running ELF constructors.  */
+-  sigset_t original_signal_mask;
+-
+   /* Original value of _ns_global_scope_pending_adds.  Set by
+      dl_open_worker.  Only valid if nsid is a real namespace
+      (non-negative).  */
+@@ -446,6 +441,9 @@ activate_nodelete (struct link_map *new)
+ 	  _dl_debug_printf ("activating NODELETE for %s [%lu]\n",
+ 			    l->l_name, l->l_ns);
+ 
++	/* The flag can already be true at this point, e.g. a signal
++	   handler may have triggered lazy binding and set NODELETE
++	   status immediately.  */
+ 	l->l_nodelete_active = true;
+ 
+ 	/* This is just a debugging aid, to indicate that
+@@ -520,16 +518,12 @@ dl_open_worker (void *a)
+   if (new == NULL)
+     {
+       assert (mode & RTLD_NOLOAD);
+-      __libc_signal_restore_set (&args->original_signal_mask);
+       return;
+     }
+ 
+   if (__glibc_unlikely (mode & __RTLD_SPROF))
+-    {
+-      /* This happens only if we load a DSO for 'sprof'.  */
+-      __libc_signal_restore_set (&args->original_signal_mask);
+-      return;
+-    }
++    /* This happens only if we load a DSO for 'sprof'.  */
++    return;
+ 
+   /* This object is directly loaded.  */
+   ++new->l_direct_opencount;
+@@ -565,7 +559,6 @@ dl_open_worker (void *a)
+ 
+       assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
+ 
+-      __libc_signal_restore_set (&args->original_signal_mask);
+       return;
+     }
+ 
+@@ -709,6 +702,12 @@ dl_open_worker (void *a)
+      All memory allocations for new objects must have happened
+      before.  */
+ 
++  /* Finalize the NODELETE status first.  This comes before
++     update_scopes, so that lazy binding will not see pending NODELETE
++     state for newly loaded objects.  There is a compiler barrier in
++     update_scopes which ensures that the changes from
++     activate_nodelete are visible before new objects show up in the
++     local scope.  */
+   activate_nodelete (new);
+ 
+   /* Second stage after resize_scopes: Actually perform the scope
+@@ -742,10 +741,6 @@ dl_open_worker (void *a)
+   if (mode & RTLD_GLOBAL)
+     add_to_global_resize (new);
+ 
+-  /* Unblock signals.  Data structures are now consistent, and
+-     application code may run.  */
+-  __libc_signal_restore_set (&args->original_signal_mask);
+-
+   /* Run the initializer functions of new objects.  Temporarily
+      disable the exception handler, so that lazy binding failures are
+      fatal.  */
+@@ -835,10 +830,6 @@ no more namespaces available for dlmopen()"));
+   args.argv = argv;
+   args.env = env;
+ 
+-  /* Recursive lazy binding during manipulation of the dynamic loader
+-     structures may result in incorrect behavior.  */
+-  __libc_signal_block_all (&args.original_signal_mask);
+-
+   struct dl_exception exception;
+   int errcode = _dl_catch_exception (&exception, dl_open_worker, &args);
+ 
+@@ -879,16 +870,10 @@ no more namespaces available for dlmopen()"));
+ 
+ 	  _dl_close_worker (args.map, true);
+ 
+-	  /* Restore the signal mask.  In the success case, this
+-	     happens inside dl_open_worker.  */
+-	  __libc_signal_restore_set (&args.original_signal_mask);
+-
+ 	  /* All l_nodelete_pending objects should have been deleted
+ 	     at this point, which is why it is not necessary to reset
+ 	     the flag here.  */
+ 	}
+-      else
+-	__libc_signal_restore_set (&args.original_signal_mask);
+ 
+       assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
+ 
diff --git a/SOURCES/glibc-rh1410154-15.patch b/SOURCES/glibc-rh1410154-15.patch
new file mode 100644
index 0000000..bf58563
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-15.patch
@@ -0,0 +1,27 @@
+commit 5177d85b0c050a2333a0c4165c938dd422013d05
+Author: H.J. Lu <hjl.tools@gmail.com>
+Date:   Thu Jan 16 06:45:36 2020 -0800
+
+    Clear GL(dl_initfirst) when freeing its link_map memory [BZ# 25396]
+    
+    We should clear GL(dl_initfirst) when freeing its link_map memory.
+    
+    Tested on Fedora 31/x86-64 with CET.
+    
+    Reviewed-by: Florian Weimer <fweimer@redhat.com>
+
+diff --git a/elf/dl-close.c b/elf/dl-close.c
+index fa7f3e8174576e46..a9ecdff62dba88fb 100644
+--- a/elf/dl-close.c
++++ b/elf/dl-close.c
+@@ -749,6 +749,10 @@ _dl_close_worker (struct link_map *map, bool force)
+ 	  if (imap->l_runpath_dirs.dirs != (void *) -1)
+ 	    free (imap->l_runpath_dirs.dirs);
+ 
++	  /* Clear GL(dl_initfirst) when freeing its link_map memory.  */
++	  if (imap == GL(dl_initfirst))
++	    GL(dl_initfirst) = NULL;
++
+ 	  free (imap);
+ 	}
+     }
diff --git a/SOURCES/glibc-rh1410154-16.patch b/SOURCES/glibc-rh1410154-16.patch
new file mode 100644
index 0000000..d3e0386
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-16.patch
@@ -0,0 +1,143 @@
+commit a332bd1518af518c984fad73eba6f46dc5b2b2d4
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Jan 16 16:53:58 2020 +0100
+
+    elf: Add elf/tst-dlopenfail-2 [BZ #25396]
+    
+    Without CET, a jump into a newly loaded object through an overwritten
+    link map often does not crash, it just executes some random code.
+    CET detects this in some cases because the function pointer does not
+    point to the start of a function in the replacement shared object,
+    so there is no ENDBR instruction.
+    
+    The new test uses a small shared object and the existing dangling
+    link map to trigger the bug.
+    
+    Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
+
+Conflicts:
+	elf/Makefile
+	  (Test backport differences.)
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 16a3e8dcda19b4ba..f1a16fe8ca594c57 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -192,7 +192,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ 	 tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
+ 	 tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \
+ 	 tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail \
+-	 tst-dlopenfail
++	 tst-dlopenfail tst-dlopenfail-2
+ #	 reldep9
+ tests-internal += loadtest unload unload2 circleload1 \
+ 	 neededtest neededtest2 neededtest3 neededtest4 \
+@@ -301,7 +301,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ 		tst-sonamemove-linkmod1 \
+ 		tst-sonamemove-runmod1 tst-sonamemove-runmod2 \
+ 		tst-initlazyfailmod tst-finilazyfailmod \
+-		tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2
++		tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \
++		tst-dlopenfailmod3
+ 
+ ifeq (yes,$(have-mtls-dialect-gnu2))
+ tests += tst-gnu2-tls1
+@@ -1569,6 +1570,10 @@ $(objpfx)tst-dlopenfailmod1.so: \
+   $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so
+ LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so
+ $(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library)
++$(objpfx)tst-dlopenfail-2: $(libdl)
++$(objpfx)tst-dlopenfail.out: \
++  $(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so \
++  $(objpfx)tst-dlopenfailmod3.so
+ 
+ $(objpfx)tst-dlopen-nodelete-reloc: $(libdl)
+ $(objpfx)tst-dlopen-nodelete-reloc.out: \
+diff --git a/elf/tst-dlopenfail-2.c b/elf/tst-dlopenfail-2.c
+new file mode 100644
+index 0000000000000000..35bbde64abbb6603
+--- /dev/null
++++ b/elf/tst-dlopenfail-2.c
+@@ -0,0 +1,59 @@
++/* Test unrelated dlopen after dlopen failure involving NODELETE.
++   Copyright (C) 2019-2020 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 <errno.h>
++#include <gnu/lib-names.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/xdlfcn.h>
++
++static int
++do_test (void)
++{
++  /* This test uses libpthread as the canonical NODELETE module.  If
++     libpthread is no longer NODELETE because it has been merged into
++     libc, the test needs to be updated.  */
++  TEST_VERIFY (dlsym (NULL, "pthread_create") == NULL);
++
++  /* This is expected to fail because of the missing dependency.  */
++  puts ("info: attempting to load tst-dlopenfailmod1.so");
++  TEST_VERIFY (dlopen ("tst-dlopenfailmod1.so", RTLD_LAZY) == NULL);
++  const char *message = dlerror ();
++  TEST_COMPARE_STRING (message,
++                       "tst-dlopenfail-missingmod.so:"
++                       " cannot open shared object file:"
++                       " No such file or directory");
++
++  /* Open a small shared object.  With a dangling GL (dl_initfirst)
++     pointer, this is likely to crash because there is no longer any
++     mapped text segment there (bug 25396).  */
++
++  puts ("info: attempting to load tst-dlopenfailmod3.so");
++  xdlclose (xdlopen ("tst-dlopenfailmod3.so", RTLD_NOW));
++
++  return 0;
++}
++
++/* Do not perturb the dangling link map.  With M_PERTURB, the link map
++   appears to have l_init_called set, so there are no constructor
++   calls and no crashes.  */
++#define TEST_NO_MALLOPT
++#include <support/test-driver.c>
+diff --git a/elf/tst-dlopenfailmod3.c b/elf/tst-dlopenfailmod3.c
+new file mode 100644
+index 0000000000000000..636e971264292110
+--- /dev/null
++++ b/elf/tst-dlopenfailmod3.c
+@@ -0,0 +1,17 @@
++/* Empty module for the tst-dlopenfail-2 test.
++   Copyright (C) 2020 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/>.  */
diff --git a/SOURCES/glibc-rh1410154-2.patch b/SOURCES/glibc-rh1410154-2.patch
new file mode 100644
index 0000000..84269e7
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-2.patch
@@ -0,0 +1,33 @@
+commit ca136bb0a36d0a7056c926bfe5126873566efe40
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Oct 31 13:28:26 2019 +0100
+
+    Clarify purpose of assert in _dl_lookup_symbol_x
+    
+    Only one of the currently defined flags is incompatible with versioned
+    symbol lookups, so it makes sense to check for that flag and not its
+    complement.
+    
+    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+    Reviewed-by: Gabriel F. T. Gomes <gabrielftg@linux.ibm.com>
+    Change-Id: I3384349cef90cfd91862ebc34a4053f0c0a99404
+
+diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
+index 1d046caf017b582b..efbdb8deb3c0a9d4 100644
+--- a/elf/dl-lookup.c
++++ b/elf/dl-lookup.c
+@@ -792,11 +792,9 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
+ 
+   bump_num_relocations ();
+ 
+-  /* No other flag than DL_LOOKUP_ADD_DEPENDENCY or DL_LOOKUP_GSCOPE_LOCK
+-     is allowed if we look up a versioned symbol.  */
+-  assert (version == NULL
+-	  || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK))
+-	     == 0);
++  /* DL_LOOKUP_RETURN_NEWEST does not make sense for versioned
++     lookups.  */
++  assert (version == NULL || !(flags & DL_LOOKUP_RETURN_NEWEST));
+ 
+   size_t i = 0;
+   if (__glibc_unlikely (skip_map != NULL))
diff --git a/SOURCES/glibc-rh1410154-3.patch b/SOURCES/glibc-rh1410154-3.patch
new file mode 100644
index 0000000..34afb62
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-3.patch
@@ -0,0 +1,54 @@
+commit 2a764c6ee848dfe92cb2921ed3b14085f15d9e79
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Oct 31 13:23:06 2019 +0100
+
+    Enhance _dl_catch_exception to allow disabling exception handling
+    
+    In some cases, it is necessary to introduce noexcept regions
+    where raised dynamic loader exceptions (e.g., from lazy binding)
+    are fatal, despite being nested in a code region with an active
+    exception handler.  This change enhances _dl_catch_exception with
+    to provide such a capability.  The existing function is reused,
+    so that it is not necessary to introduce yet another function with
+    a similar purpose.
+    
+    Change-Id: Iec1bf642ff95a349fdde8040e9baf851ac7b8904
+
+diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c
+index d5f418ab1848f0c4..9cb002ccfed2c7b4 100644
+--- a/elf/dl-error-skeleton.c
++++ b/elf/dl-error-skeleton.c
+@@ -173,6 +173,18 @@ int
+ _dl_catch_exception (struct dl_exception *exception,
+ 		     void (*operate) (void *), void *args)
+ {
++  /* If exception is NULL, temporarily disable exception handling.
++     Exceptions during operate (args) are fatal.  */
++  if (exception == NULL)
++    {
++      struct catch *const old = catch_hook;
++      catch_hook = NULL;
++      operate (args);
++      /* If we get here, the operation was successful.  */
++      catch_hook = old;
++      return 0;
++    }
++
+   /* We need not handle `receiver' since setting a `catch' is handled
+      before it.  */
+ 
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 95dc87519b80e0ec..cc2484033fe0d902 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -852,7 +852,9 @@ libc_hidden_proto (_dl_catch_error)
+ 
+ /* Call OPERATE (ARGS).  If no error occurs, set *EXCEPTION to zero.
+    Otherwise, store a copy of the raised exception in *EXCEPTION,
+-   which has to be freed by _dl_exception_free.  */
++   which has to be freed by _dl_exception_free.  As a special case, if
++   EXCEPTION is null, call OPERATE (ARGS) with exception handling
++   disabled (so that exceptions are fatal).  */
+ int _dl_catch_exception (struct dl_exception *exception,
+ 			 void (*operate) (void *), void *args);
+ libc_hidden_proto (_dl_catch_exception)
diff --git a/SOURCES/glibc-rh1410154-4.patch b/SOURCES/glibc-rh1410154-4.patch
new file mode 100644
index 0000000..fa3cc53
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-4.patch
@@ -0,0 +1,42 @@
+commit fcb04b9aed26a737159ef7be9c5a6ad0994437dc
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Oct 31 13:28:49 2019 +0100
+
+    Introduce DL_LOOKUP_FOR_RELOCATE flag for _dl_lookup_symbol_x
+    
+    This will allow changes in dependency processing during non-lazy
+    binding, for more precise processing of NODELETE objects: During
+    initial relocation in dlopen, the fate of NODELETE objects is still
+    unclear, so objects which are depended upon by NODELETE objects
+    cannot immediately be marked as NODELETE.
+    
+    Change-Id: Ic7b94a3f7c4719a00ca8e6018088567824da0658
+
+diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
+index 053916eeae50467c..afeace4d3e49180c 100644
+--- a/elf/dl-reloc.c
++++ b/elf/dl-reloc.c
+@@ -248,7 +248,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+ 	       v = (version);						      \
+ 	     _lr = _dl_lookup_symbol_x (strtab + (*ref)->st_name, l, (ref),   \
+ 					scope, v, _tc,			      \
+-					DL_LOOKUP_ADD_DEPENDENCY, NULL);      \
++					DL_LOOKUP_ADD_DEPENDENCY	      \
++					| DL_LOOKUP_FOR_RELOCATE, NULL);      \
+ 	     l->l_lookup_cache.ret = (*ref);				      \
+ 	     l->l_lookup_cache.value = _lr; }))				      \
+      : l)
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index cc2484033fe0d902..6c5298a80bff8e96 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -908,6 +908,9 @@ enum
+     DL_LOOKUP_RETURN_NEWEST = 2,
+     /* Set if dl_lookup* called with GSCOPE lock held.  */
+     DL_LOOKUP_GSCOPE_LOCK = 4,
++    /* Set if dl_lookup is called for non-lazy relocation processing
++       from _dl_relocate_object in elf/dl-reloc.c.  */
++    DL_LOOKUP_FOR_RELOCATE = 8,
+   };
+ 
+ /* Lookup versioned symbol.  */
diff --git a/SOURCES/glibc-rh1410154-5.patch b/SOURCES/glibc-rh1410154-5.patch
new file mode 100644
index 0000000..6879fb3
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-5.patch
@@ -0,0 +1,343 @@
+commit 79e0cd7b3c997e211fad44a81fd839dc5b2546e8
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Wed Nov 27 16:20:47 2019 +0100
+
+    Lazy binding failures during dlopen/dlclose must be fatal [BZ #24304]
+    
+    If a lazy binding failure happens during the execution of an ELF
+    constructor or destructor, the dynamic loader catches the error
+    and reports it using the dlerror mechanism.  This is undesirable
+    because there could be other constructors and destructors that
+    need processing (which are skipped), and the process is in an
+    inconsistent state at this point.  Therefore, we have to issue
+    a fatal dynamic loader error error and terminate the process.
+    
+    Note that the _dl_catch_exception in _dl_open is just an inner catch,
+    to roll back some state locally.  If called from dlopen, there is
+    still an outer catch, which is why calling _dl_init via call_dl_init
+    and a no-exception is required and cannot be avoiding by moving the
+    _dl_init call directly into _dl_open.
+    
+    _dl_fini does not need changes because it does not install an error
+    handler, so errors are already fatal there.
+    
+    Change-Id: I6b1addfe2e30f50a1781595f046f44173db9491a
+
+Conflicts:
+	elf/Makefile
+	  (Usual conflicts due to test backport differences.)
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 74a240b3a68ff5e2..b752f6366400d221 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -191,7 +191,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ 	 tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
+ 	 tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
+ 	 tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \
+-	 tst-sonamemove-link tst-sonamemove-dlopen
++	 tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail
+ #	 reldep9
+ tests-internal += loadtest unload unload2 circleload1 \
+ 	 neededtest neededtest2 neededtest3 neededtest4 \
+@@ -281,7 +281,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ 		tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \
+ 		tst-absolute-zero-lib tst-big-note-lib \
+ 		tst-sonamemove-linkmod1 \
+-		tst-sonamemove-runmod1 tst-sonamemove-runmod2
++		tst-sonamemove-runmod1 tst-sonamemove-runmod2 \
++		tst-initlazyfailmod tst-finilazyfailmod
+ 
+ ifeq (yes,$(have-mtls-dialect-gnu2))
+ tests += tst-gnu2-tls1
+@@ -1526,3 +1527,13 @@ tst-libc_dlvsym-static-ENV = \
+ $(objpfx)tst-libc_dlvsym-static.out: $(objpfx)tst-libc_dlvsym-dso.so
+ 
+ $(objpfx)tst-big-note: $(objpfx)tst-big-note-lib.so
++
++$(objpfx)tst-initfinilazyfail: $(libdl)
++$(objpfx)tst-initfinilazyfail.out: \
++  $(objpfx)tst-initlazyfailmod.so $(objpfx)tst-finilazyfailmod.so
++# Override -z defs, so that we can reference an undefined symbol.
++# Force lazy binding for the same reason.
++LDFLAGS-tst-initlazyfailmod.so = \
++  -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all
++LDFLAGS-tst-finilazyfailmod.so = \
++  -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all
+diff --git a/elf/dl-close.c b/elf/dl-close.c
+index ecd6729704ea3294..88aeea25839a34e0 100644
+--- a/elf/dl-close.c
++++ b/elf/dl-close.c
+@@ -106,6 +106,30 @@ 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)
+@@ -267,7 +291,8 @@ _dl_close_worker (struct link_map *map, bool force)
+ 		  && (imap->l_flags_1 & DF_1_NODELETE) == 0);
+ 
+ 	  /* Call its termination function.  Do not do it for
+-	     half-cooked objects.  */
++	     half-cooked objects.  Temporarily disable exception
++	     handling, so that errors are fatal.  */
+ 	  if (imap->l_init_called)
+ 	    {
+ 	      /* When debugging print a message first.  */
+@@ -276,22 +301,9 @@ _dl_close_worker (struct link_map *map, bool force)
+ 		_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
+ 				  imap->l_name, nsid);
+ 
+-	      if (imap->l_info[DT_FINI_ARRAY] != NULL)
+-		{
+-		  ElfW(Addr) *array =
+-		    (ElfW(Addr) *) (imap->l_addr
+-				    + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
+-		  unsigned int sz = (imap->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 (imap->l_info[DT_FINI] != NULL)
+-		DL_CALL_DT_FINI (imap, ((void *) imap->l_addr
+-			 + imap->l_info[DT_FINI]->d_un.d_ptr));
++	      if (imap->l_info[DT_FINI_ARRAY] != NULL
++		  || imap->l_info[DT_FINI] != NULL)
++		_dl_catch_exception (NULL, call_destructors, imap);
+ 	    }
+ 
+ #ifdef SHARED
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index 518a6cad699ec6d0..c9c0254ee74c4f4b 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -177,6 +177,23 @@ _dl_find_dso_for_object (const ElfW(Addr) addr)
+ }
+ rtld_hidden_def (_dl_find_dso_for_object);
+ 
++/* struct dl_init_args and call_dl_init are used to call _dl_init with
++   exception handling disabled.  */
++struct dl_init_args
++{
++  struct link_map *new;
++  int argc;
++  char **argv;
++  char **env;
++};
++
++static void
++call_dl_init (void *closure)
++{
++  struct dl_init_args *args = closure;
++  _dl_init (args->new, args->argc, args->argv, args->env);
++}
++
+ static void
+ dl_open_worker (void *a)
+ {
+@@ -506,8 +523,19 @@ TLS generation counter wrapped!  Please report this."));
+   DL_STATIC_INIT (new);
+ #endif
+ 
+-  /* Run the initializer functions of new objects.  */
+-  _dl_init (new, args->argc, args->argv, args->env);
++  /* Run the initializer functions of new objects.  Temporarily
++     disable the exception handler, so that lazy binding failures are
++     fatal.  */
++  {
++    struct dl_init_args init_args =
++      {
++        .new = new,
++        .argc = args->argc,
++        .argv = args->argv,
++        .env = args->env
++      };
++    _dl_catch_exception (NULL, call_dl_init, &init_args);
++  }
+ 
+   /* Now we can make the new map available in the global scope.  */
+   if (mode & RTLD_GLOBAL)
+diff --git a/elf/tst-finilazyfailmod.c b/elf/tst-finilazyfailmod.c
+new file mode 100644
+index 0000000000000000..2670bd1a9400d0ef
+--- /dev/null
++++ b/elf/tst-finilazyfailmod.c
+@@ -0,0 +1,27 @@
++/* Helper module for tst-initfinilazyfail: lazy binding failure in destructor.
++   Copyright (C) 2019 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/>.  */
++
++/* An undefined function.  Calling it will cause a lazy binding
++   failure.  */
++void undefined_function (void);
++
++static void __attribute__ ((destructor))
++fini (void)
++{
++  undefined_function ();
++}
+diff --git a/elf/tst-initfinilazyfail.c b/elf/tst-initfinilazyfail.c
+new file mode 100644
+index 0000000000000000..9b4a3d0c0ffbb7c6
+--- /dev/null
++++ b/elf/tst-initfinilazyfail.c
+@@ -0,0 +1,84 @@
++/* Test that lazy binding failures in constructors and destructors are fatal.
++   Copyright (C) 2019 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 <string.h>
++#include <support/capture_subprocess.h>
++#include <support/check.h>
++#include <support/xdlfcn.h>
++
++static void
++test_constructor (void *closure)
++{
++  void *handle = dlopen ("tst-initlazyfailmod.so", RTLD_LAZY);
++  if (handle == NULL)
++    FAIL_EXIT (2, "dlopen did not terminate the process: %s", dlerror ());
++  else
++    FAIL_EXIT (2, "dlopen did not terminate the process (%p)", handle);
++}
++
++static void
++test_destructor (void *closure)
++{
++  void *handle = xdlopen ("tst-finilazyfailmod.so", RTLD_LAZY);
++  int ret = dlclose (handle);
++  const char *message = dlerror ();
++  if (message != NULL)
++    FAIL_EXIT (2, "dlclose did not terminate the process: %d, %s",
++               ret, message);
++  else
++    FAIL_EXIT (2, "dlopen did not terminate the process: %d", ret);
++}
++
++static int
++do_test (void)
++{
++  {
++    struct support_capture_subprocess proc
++      = support_capture_subprocess (test_constructor, NULL);
++    support_capture_subprocess_check (&proc, "constructor", 127,
++                                      sc_allow_stderr);
++    printf ("info: constructor failure output: [[%s]]\n", proc.err.buffer);
++    TEST_VERIFY (strstr (proc.err.buffer,
++                         "tst-initfinilazyfail: symbol lookup error: ")
++                 != NULL);
++    TEST_VERIFY (strstr (proc.err.buffer,
++                         "tst-initlazyfailmod.so: undefined symbol:"
++                         " undefined_function\n") != NULL);
++    support_capture_subprocess_free (&proc);
++  }
++
++  {
++    struct support_capture_subprocess proc
++      = support_capture_subprocess (test_destructor, NULL);
++    support_capture_subprocess_check (&proc, "destructor", 127,
++                                      sc_allow_stderr);
++    printf ("info: destructor failure output: [[%s]]\n", proc.err.buffer);
++    TEST_VERIFY (strstr (proc.err.buffer,
++                         "tst-initfinilazyfail: symbol lookup error: ")
++                 != NULL);
++    TEST_VERIFY (strstr (proc.err.buffer,
++                         "tst-finilazyfailmod.so: undefined symbol:"
++                         " undefined_function\n") != NULL);
++    support_capture_subprocess_free (&proc);
++  }
++
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/elf/tst-initlazyfailmod.c b/elf/tst-initlazyfailmod.c
+new file mode 100644
+index 0000000000000000..36348b58d634d2bb
+--- /dev/null
++++ b/elf/tst-initlazyfailmod.c
+@@ -0,0 +1,27 @@
++/* Helper module for tst-initfinilazyfail: lazy binding failure in constructor.
++   Copyright (C) 2019 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/>.  */
++
++/* An undefined function.  Calling it will cause a lazy binding
++   failure.  */
++void undefined_function (void);
++
++static void __attribute__ ((constructor))
++init (void)
++{
++  undefined_function ();
++}
diff --git a/SOURCES/glibc-rh1410154-6.patch b/SOURCES/glibc-rh1410154-6.patch
new file mode 100644
index 0000000..3b05076
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-6.patch
@@ -0,0 +1,308 @@
+commit 440b7f8653e4ed8f6e1425145208050b795e9a6c
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Oct 31 18:25:39 2019 +0100
+
+    Avoid late failure in dlopen in global scope update [BZ #25112]
+    
+    The call to add_to_global in dl_open_worker happens after running ELF
+    constructors for new objects.  At this point, proper recovery from
+    malloc failure would be quite complicated: We would have to run the
+    ELF destructors and close all opened objects, something that we
+    currently do not do.
+    
+    Instead, this change splits add_to_global into two phases,
+    add_to_global_resize (which can raise an exception, called before ELF
+    constructors run), and add_to_global_update (which cannot, called
+    after ELF constructors).  A complication arises due to recursive
+    dlopen: After the inner dlopen consumes some space, the pre-allocation
+    in the outer dlopen may no longer be sufficient.  A new member in the
+    namespace structure, _ns_global_scope_pending_adds keeps track of the
+    maximum number of objects that need to be added to the global scope.
+    This enables the inner add_to_global_resize call to take into account
+    the needs of an outer dlopen.
+    
+    Most code in the dynamic linker assumes that the number of global
+    scope entries fits into an unsigned int (matching the r_nlist member
+    of struct r_scop_elem).  Therefore, change the type of
+    _ns_global_scope_alloc to unsigned int (from size_t), and add overflow
+    checks.
+    
+    Change-Id: Ie08e2f318510d5a6a4bcb1c315f46791b5b77524
+
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index c9c0254ee74c4f4b..85db4f0ecb5f29ce 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -50,22 +50,38 @@ struct dl_open_args
+   struct link_map *map;
+   /* Namespace ID.  */
+   Lmid_t nsid;
++
++  /* Original value of _ns_global_scope_pending_adds.  Set by
++     dl_open_worker.  Only valid if nsid is a real namespace
++     (non-negative).  */
++  unsigned int original_global_scope_pending_adds;
++
+   /* Original parameters to the program and the current environment.  */
+   int argc;
+   char **argv;
+   char **env;
+ };
+ 
++/* Called in case the global scope cannot be extended.  */
++static void __attribute__ ((noreturn))
++add_to_global_resize_failure (struct link_map *new)
++{
++  _dl_signal_error (ENOMEM, new->l_libname->name, NULL,
++		    N_ ("cannot extend global scope"));
++}
+ 
+-static int
+-add_to_global (struct link_map *new)
++/* Grow the global scope array for the namespace, so that all the new
++   global objects can be added later in add_to_global_update, without
++   risk of memory allocation failure.  add_to_global_resize raises
++   exceptions for memory allocation errors.  */
++static void
++add_to_global_resize (struct link_map *new)
+ {
+-  struct link_map **new_global;
+-  unsigned int to_add = 0;
+-  unsigned int cnt;
++  struct link_namespaces *ns = &GL (dl_ns)[new->l_ns];
+ 
+   /* Count the objects we have to put in the global scope.  */
+-  for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
++  unsigned int to_add = 0;
++  for (unsigned int cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
+     if (new->l_searchlist.r_list[cnt]->l_global == 0)
+       ++to_add;
+ 
+@@ -83,47 +99,51 @@ add_to_global (struct link_map *new)
+      in an realloc() call.  Therefore we allocate a completely new
+      array the first time we have to add something to the locale scope.  */
+ 
+-  struct link_namespaces *ns = &GL(dl_ns)[new->l_ns];
++  if (__builtin_add_overflow (ns->_ns_global_scope_pending_adds, to_add,
++			      &ns->_ns_global_scope_pending_adds))
++    add_to_global_resize_failure (new);
++
++  unsigned int new_size = 0; /* 0 means no new allocation.  */
++  void *old_global = NULL; /* Old allocation if free-able.  */
++
++  /* Minimum required element count for resizing.  Adjusted below for
++     an exponential resizing policy.  */
++  size_t required_new_size;
++  if (__builtin_add_overflow (ns->_ns_main_searchlist->r_nlist,
++			      ns->_ns_global_scope_pending_adds,
++			      &required_new_size))
++    add_to_global_resize_failure (new);
++
+   if (ns->_ns_global_scope_alloc == 0)
+     {
+-      /* This is the first dynamic object given global scope.  */
+-      ns->_ns_global_scope_alloc
+-	= ns->_ns_main_searchlist->r_nlist + to_add + 8;
+-      new_global = (struct link_map **)
+-	malloc (ns->_ns_global_scope_alloc * sizeof (struct link_map *));
+-      if (new_global == NULL)
+-	{
+-	  ns->_ns_global_scope_alloc = 0;
+-	nomem:
+-	  _dl_signal_error (ENOMEM, new->l_libname->name, NULL,
+-			    N_("cannot extend global scope"));
+-	  return 1;
+-	}
++      if (__builtin_add_overflow (required_new_size, 8, &new_size))
++	add_to_global_resize_failure (new);
++    }
++  else if (required_new_size > ns->_ns_global_scope_alloc)
++    {
++      if (__builtin_mul_overflow (required_new_size, 2, &new_size))
++	add_to_global_resize_failure (new);
+ 
+-      /* Copy over the old entries.  */
+-      ns->_ns_main_searchlist->r_list
+-	= memcpy (new_global, ns->_ns_main_searchlist->r_list,
+-		  (ns->_ns_main_searchlist->r_nlist
+-		   * sizeof (struct link_map *)));
++      /* The old array was allocated with our malloc, not the minimal
++	 malloc.  */
++      old_global = ns->_ns_main_searchlist->r_list;
+     }
+-  else if (ns->_ns_main_searchlist->r_nlist + to_add
+-	   > ns->_ns_global_scope_alloc)
++
++  if (new_size > 0)
+     {
+-      /* We have to extend the existing array of link maps in the
+-	 main map.  */
+-      struct link_map **old_global
+-	= GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list;
+-      size_t new_nalloc = ((ns->_ns_global_scope_alloc + to_add) * 2);
+-
+-      new_global = (struct link_map **)
+-	malloc (new_nalloc * sizeof (struct link_map *));
++      size_t allocation_size;
++      if (__builtin_mul_overflow (new_size, sizeof (struct link_map *),
++				  &allocation_size))
++	add_to_global_resize_failure (new);
++      struct link_map **new_global = malloc (allocation_size);
+       if (new_global == NULL)
+-	goto nomem;
++	add_to_global_resize_failure (new);
+ 
+-      memcpy (new_global, old_global,
+-	      ns->_ns_global_scope_alloc * sizeof (struct link_map *));
++      /* Copy over the old entries.  */
++      memcpy (new_global, ns->_ns_main_searchlist->r_list,
++	      ns->_ns_main_searchlist->r_nlist * sizeof (struct link_map *));
+ 
+-      ns->_ns_global_scope_alloc = new_nalloc;
++      ns->_ns_global_scope_alloc = new_size;
+       ns->_ns_main_searchlist->r_list = new_global;
+ 
+       if (!RTLD_SINGLE_THREAD_P)
+@@ -131,16 +151,28 @@ add_to_global (struct link_map *new)
+ 
+       free (old_global);
+     }
++}
++
++/* Actually add the new global objects to the global scope.  Must be
++   called after add_to_global_resize.  This function cannot fail.  */
++static void
++add_to_global_update (struct link_map *new)
++{
++  struct link_namespaces *ns = &GL (dl_ns)[new->l_ns];
+ 
+   /* Now add the new entries.  */
+   unsigned int new_nlist = ns->_ns_main_searchlist->r_nlist;
+-  for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
++  for (unsigned int cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
+     {
+       struct link_map *map = new->l_searchlist.r_list[cnt];
+ 
+       if (map->l_global == 0)
+ 	{
+ 	  map->l_global = 1;
++
++	  /* The array has been resized by add_to_global_resize.  */
++	  assert (new_nlist < ns->_ns_global_scope_alloc);
++
+ 	  ns->_ns_main_searchlist->r_list[new_nlist++] = map;
+ 
+ 	  /* We modify the global scope.  Report this.  */
+@@ -149,10 +181,15 @@ add_to_global (struct link_map *new)
+ 			      map->l_name, map->l_ns);
+ 	}
+     }
++
++  /* Some of the pending adds have been performed by the loop above.
++     Adjust the counter accordingly.  */
++  unsigned int added = new_nlist - ns->_ns_main_searchlist->r_nlist;
++  assert (added <= ns->_ns_global_scope_pending_adds);
++  ns->_ns_global_scope_pending_adds -= added;
++
+   atomic_write_barrier ();
+   ns->_ns_main_searchlist->r_nlist = new_nlist;
+-
+-  return 0;
+ }
+ 
+ /* Search link maps in all namespaces for the DSO that contains the object at
+@@ -225,6 +262,10 @@ dl_open_worker (void *a)
+ 	args->nsid = call_map->l_ns;
+     }
+ 
++  /* Retain the old value, so that it can be restored.  */
++  args->original_global_scope_pending_adds
++    = GL (dl_ns)[args->nsid]._ns_global_scope_pending_adds;
++
+   /* One might be tempted to assert that we are RT_CONSISTENT at this point, but that
+      may not be true if this is a recursive call to dlopen.  */
+   _dl_debug_initialize (0, args->nsid);
+@@ -266,7 +307,10 @@ dl_open_worker (void *a)
+       /* If the user requested the object to be in the global namespace
+ 	 but it is not so far, add it now.  */
+       if ((mode & RTLD_GLOBAL) && new->l_global == 0)
+-	(void) add_to_global (new);
++	{
++	  add_to_global_resize (new);
++	  add_to_global_update (new);
++	}
+ 
+       assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
+ 
+@@ -523,6 +567,11 @@ TLS generation counter wrapped!  Please report this."));
+   DL_STATIC_INIT (new);
+ #endif
+ 
++  /* Perform the necessary allocations for adding new global objects
++     to the global scope below, via add_to_global_update.  */
++  if (mode & RTLD_GLOBAL)
++    add_to_global_resize (new);
++
+   /* Run the initializer functions of new objects.  Temporarily
+      disable the exception handler, so that lazy binding failures are
+      fatal.  */
+@@ -539,10 +588,7 @@ TLS generation counter wrapped!  Please report this."));
+ 
+   /* Now we can make the new map available in the global scope.  */
+   if (mode & RTLD_GLOBAL)
+-    /* Move the object in the global namespace.  */
+-    if (add_to_global (new) != 0)
+-      /* It failed.  */
+-      return;
++    add_to_global_update (new);
+ 
+ #ifndef SHARED
+   /* We must be the static _dl_open in libc.a.  A static program that
+@@ -556,7 +602,6 @@ TLS generation counter wrapped!  Please report this."));
+ 		      new->l_name, new->l_ns, new->l_direct_opencount);
+ }
+ 
+-
+ void *
+ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
+ 	  int argc, char *argv[], char *env[])
+@@ -624,6 +669,19 @@ no more namespaces available for dlmopen()"));
+   _dl_unload_cache ();
+ #endif
+ 
++  /* Do this for both the error and success cases.  The old value has
++     only been determined if the namespace ID was assigned (i.e., it
++     is not __LM_ID_CALLER).  In the success case, we actually may
++     have consumed more pending adds than planned (because the local
++     scopes overlap in case of a recursive dlopen, the inner dlopen
++     doing some of the globalization work of the outer dlopen), so the
++     old pending adds value is larger than absolutely necessary.
++     Since it is just a conservative upper bound, this is harmless.
++     The top-level dlopen call will restore the field to zero.  */
++  if (args.nsid >= 0)
++    GL (dl_ns)[args.nsid]._ns_global_scope_pending_adds
++      = args.original_global_scope_pending_adds;
++
+   /* See if an error occurred during loading.  */
+   if (__glibc_unlikely (exception.errstring != NULL))
+     {
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 6c5298a80bff8e96..57fbefea3cb841e9 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -311,7 +311,14 @@ struct rtld_global
+     /* This is zero at program start to signal that the global scope map is
+        allocated by rtld.  Later it keeps the size of the map.  It might be
+        reset if in _dl_close if the last global object is removed.  */
+-    size_t _ns_global_scope_alloc;
++    unsigned int _ns_global_scope_alloc;
++
++    /* During dlopen, this is the number of objects that still need to
++       be added to the global scope map.  It has to be taken into
++       account when resizing the map, for future map additions after
++       recursive dlopen calls from ELF constructors.  */
++    unsigned int _ns_global_scope_pending_adds;
++
+     /* Search table for unique objects.  */
+     struct unique_sym_table
+     {
diff --git a/SOURCES/glibc-rh1410154-7.patch b/SOURCES/glibc-rh1410154-7.patch
new file mode 100644
index 0000000..977a011
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-7.patch
@@ -0,0 +1,490 @@
+commit a509eb117fac1d764b15eba64993f4bdb63d7f3c
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Wed Nov 27 16:37:17 2019 +0100
+
+    Avoid late dlopen failure due to scope, TLS slotinfo updates [BZ #25112]
+    
+    This change splits the scope and TLS slotinfo updates in dlopen into
+    two parts: one to resize the data structures, and one to actually apply
+    the update.  The call to add_to_global_resize in dl_open_worker is moved
+    before the demarcation point at which no further memory allocations are
+    allowed.
+    
+    _dl_add_to_slotinfo is adjusted to make the list update optional.  There
+    is some optimization possibility here because we could grow the slotinfo
+    list of arrays in a single call, one the largest TLS modid is known.
+    
+    This commit does not fix the fatal meory allocation failure in
+    _dl_update_slotinfo.  Ideally, this error during dlopen should be
+    recoverable.
+    
+    The update order of scopes and TLS data structures is retained, although
+    it appears to be more correct to fully initialize TLS first, and then
+    expose symbols in the newly loaded objects via the scope update.
+    
+    Tested on x86_64-linux-gnu.
+    
+    Change-Id: I240c58387dabda3ca1bcab48b02115175fa83d6c
+
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index 85db4f0ecb5f29ce..b330cff7d349224a 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -33,6 +33,7 @@
+ #include <stap-probe.h>
+ #include <atomic.h>
+ #include <libc-internal.h>
++#include <array_length.h>
+ 
+ #include <dl-dst.h>
+ #include <dl-prop.h>
+@@ -214,6 +215,215 @@ _dl_find_dso_for_object (const ElfW(Addr) addr)
+ }
+ rtld_hidden_def (_dl_find_dso_for_object);
+ 
++/* Return true if NEW is found in the scope for MAP.  */
++static size_t
++scope_has_map (struct link_map *map, struct link_map *new)
++{
++  size_t cnt;
++  for (cnt = 0; map->l_scope[cnt] != NULL; ++cnt)
++    if (map->l_scope[cnt] == &new->l_searchlist)
++      return true;
++  return false;
++}
++
++/* Return the length of the scope for MAP.  */
++static size_t
++scope_size (struct link_map *map)
++{
++  size_t cnt;
++  for (cnt = 0; map->l_scope[cnt] != NULL; )
++    ++cnt;
++  return cnt;
++}
++
++/* Resize the scopes of depended-upon objects, so that the new object
++   can be added later without further allocation of memory.  This
++   function can raise an exceptions due to malloc failure.  */
++static void
++resize_scopes (struct link_map *new)
++{
++  /* If the file is not loaded now as a dependency, add the search
++     list of the newly loaded object to the scope.  */
++  for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
++    {
++      struct link_map *imap = new->l_searchlist.r_list[i];
++
++      /* If the initializer has been called already, the object has
++	 not been loaded here and now.  */
++      if (imap->l_init_called && imap->l_type == lt_loaded)
++	{
++	  if (scope_has_map (imap, new))
++	    /* Avoid duplicates.  */
++	    continue;
++
++	  size_t cnt = scope_size (imap);
++	  if (__glibc_unlikely (cnt + 1 >= imap->l_scope_max))
++	    {
++	      /* The l_scope array is too small.  Allocate a new one
++		 dynamically.  */
++	      size_t new_size;
++	      struct r_scope_elem **newp;
++
++	      if (imap->l_scope != imap->l_scope_mem
++		  && imap->l_scope_max < array_length (imap->l_scope_mem))
++		{
++		  /* If the current l_scope memory is not pointing to
++		     the static memory in the structure, but the
++		     static memory in the structure is large enough to
++		     use for cnt + 1 scope entries, then switch to
++		     using the static memory.  */
++		  new_size = array_length (imap->l_scope_mem);
++		  newp = imap->l_scope_mem;
++		}
++	      else
++		{
++		  new_size = imap->l_scope_max * 2;
++		  newp = (struct r_scope_elem **)
++		    malloc (new_size * sizeof (struct r_scope_elem *));
++		  if (newp == NULL)
++		    _dl_signal_error (ENOMEM, "dlopen", NULL,
++				      N_("cannot create scope list"));
++		}
++
++	      /* Copy the array and the terminating NULL.  */
++	      memcpy (newp, imap->l_scope,
++		      (cnt + 1) * sizeof (imap->l_scope[0]));
++	      struct r_scope_elem **old = imap->l_scope;
++
++	      imap->l_scope = newp;
++
++	      if (old != imap->l_scope_mem)
++		_dl_scope_free (old);
++
++	      imap->l_scope_max = new_size;
++	    }
++	}
++    }
++}
++
++/* Second stage of resize_scopes: Add NEW to the scopes.  Also print
++   debugging information about scopes if requested.
++
++   This function cannot raise an exception because all required memory
++   has been allocated by a previous call to resize_scopes.  */
++static void
++update_scopes (struct link_map *new)
++{
++  for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
++    {
++      struct link_map *imap = new->l_searchlist.r_list[i];
++      int from_scope = 0;
++
++      if (imap->l_init_called && imap->l_type == lt_loaded)
++	{
++	  if (scope_has_map (imap, new))
++	    /* Avoid duplicates.  */
++	    continue;
++
++	  size_t cnt = scope_size (imap);
++	  /* Assert that resize_scopes has sufficiently enlarged the
++	     array.  */
++	  assert (cnt + 1 < imap->l_scope_max);
++
++	  /* First terminate the extended list.  Otherwise a thread
++	     might use the new last element and then use the garbage
++	     at offset IDX+1.  */
++	  imap->l_scope[cnt + 1] = NULL;
++	  atomic_write_barrier ();
++	  imap->l_scope[cnt] = &new->l_searchlist;
++
++	  from_scope = cnt;
++	}
++
++      /* Print scope information.  */
++      if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++	_dl_show_scope (imap, from_scope);
++    }
++}
++
++/* Call _dl_add_to_slotinfo with DO_ADD set to false, to allocate
++   space in GL (dl_tls_dtv_slotinfo_list).  This can raise an
++   exception.  The return value is true if any of the new objects use
++   TLS.  */
++static bool
++resize_tls_slotinfo (struct link_map *new)
++{
++  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;
++	}
++    }
++  return any_tls;
++}
++
++/* Second stage of TLS update, after resize_tls_slotinfo.  This
++   function does not raise any exception.  It should only be called if
++   resize_tls_slotinfo returned true.  */
++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;
++	}
++    }
++
++  if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
++    _dl_fatal_printf (N_("\
++TLS generation counter wrapped!  Please report this."));
++
++  /* 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)
++    {
++      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)
++	{
++	  /* For static TLS we have to allocate the memory here and
++	     now, but we can delay updating the DTV.  */
++	  imap->l_need_tls_init = 0;
++#ifdef SHARED
++	  /* Update the slot information data for at least the
++	     generation of the DSO we are allocating data for.  */
++
++	  /* FIXME: This can terminate the process on memory
++	     allocation failure.  It is not possible to raise
++	     exceptions from this context; to fix this bug,
++	     _dl_update_slotinfo would have to be split into two
++	     operations, similar to resize_scopes and update_scopes
++	     above.  This is related to bug 16134.  */
++	  _dl_update_slotinfo (imap->l_tls_modid);
++#endif
++
++	  GL(dl_init_static_tls) (imap);
++	  assert (imap->l_need_tls_init == 0);
++	}
++    }
++}
++
+ /* struct dl_init_args and call_dl_init are used to call _dl_init with
+    exception handling disabled.  */
+ struct dl_init_args
+@@ -431,133 +641,40 @@ dl_open_worker (void *a)
+      relocation.  */
+   _dl_open_check (new);
+ 
+-  /* If the file is not loaded now as a dependency, add the search
+-     list of the newly loaded object to the scope.  */
+-  bool any_tls = false;
+-  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];
+-      int from_scope = 0;
++  /* This only performs the memory allocations.  The actual update of
++     the scopes happens below, after failure is impossible.  */
++  resize_scopes (new);
+ 
+-      /* If the initializer has been called already, the object has
+-	 not been loaded here and now.  */
+-      if (imap->l_init_called && imap->l_type == lt_loaded)
+-	{
+-	  struct r_scope_elem **runp = imap->l_scope;
+-	  size_t cnt = 0;
+-
+-	  while (*runp != NULL)
+-	    {
+-	      if (*runp == &new->l_searchlist)
+-		break;
+-	      ++cnt;
+-	      ++runp;
+-	    }
+-
+-	  if (*runp != NULL)
+-	    /* Avoid duplicates.  */
+-	    continue;
+-
+-	  if (__glibc_unlikely (cnt + 1 >= imap->l_scope_max))
+-	    {
+-	      /* The 'r_scope' array is too small.  Allocate a new one
+-		 dynamically.  */
+-	      size_t new_size;
+-	      struct r_scope_elem **newp;
+-
+-#define SCOPE_ELEMS(imap) \
+-  (sizeof (imap->l_scope_mem) / sizeof (imap->l_scope_mem[0]))
++  /* Increase the size of the GL (dl_tls_dtv_slotinfo_list) data
++     structure.  */
++  bool any_tls = resize_tls_slotinfo (new);
+ 
+-	      if (imap->l_scope != imap->l_scope_mem
+-		  && imap->l_scope_max < SCOPE_ELEMS (imap))
+-		{
+-		  new_size = SCOPE_ELEMS (imap);
+-		  newp = imap->l_scope_mem;
+-		}
+-	      else
+-		{
+-		  new_size = imap->l_scope_max * 2;
+-		  newp = (struct r_scope_elem **)
+-		    malloc (new_size * sizeof (struct r_scope_elem *));
+-		  if (newp == NULL)
+-		    _dl_signal_error (ENOMEM, "dlopen", NULL,
+-				      N_("cannot create scope list"));
+-		}
+-
+-	      memcpy (newp, imap->l_scope, cnt * sizeof (imap->l_scope[0]));
+-	      struct r_scope_elem **old = imap->l_scope;
+-
+-	      imap->l_scope = newp;
+-
+-	      if (old != imap->l_scope_mem)
+-		_dl_scope_free (old);
+-
+-	      imap->l_scope_max = new_size;
+-	    }
+-
+-	  /* First terminate the extended list.  Otherwise a thread
+-	     might use the new last element and then use the garbage
+-	     at offset IDX+1.  */
+-	  imap->l_scope[cnt + 1] = NULL;
+-	  atomic_write_barrier ();
+-	  imap->l_scope[cnt] = &new->l_searchlist;
+-
+-	  /* Print only new scope information.  */
+-	  from_scope = cnt;
+-	}
+-      /* Only add TLS memory if this object is loaded now and
+-	 therefore is not yet initialized.  */
+-      else if (! imap->l_init_called
+-	       /* Only if the module defines thread local data.  */
+-	       && __builtin_expect (imap->l_tls_blocksize > 0, 0))
+-	{
+-	  /* Now that we know the object is loaded successfully add
+-	     modules containing TLS data to the slot info table.  We
+-	     might have to increase its size.  */
+-	  _dl_add_to_slotinfo (imap);
+-
+-	  if (imap->l_need_tls_init
+-	      && first_static_tls == new->l_searchlist.r_nlist)
+-	    first_static_tls = i;
+-
+-	  /* We have to bump the generation counter.  */
+-	  any_tls = true;
+-	}
+-
+-      /* Print scope information.  */
+-      if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
+-	_dl_show_scope (imap, from_scope);
+-    }
+-
+-  /* Bump the generation number if necessary.  */
+-  if (any_tls && __builtin_expect (++GL(dl_tls_generation) == 0, 0))
+-    _dl_fatal_printf (N_("\
+-TLS generation counter wrapped!  Please report this."));
+-
+-  /* 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)
+-    {
+-      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)
+-	{
+-	  /* For static TLS we have to allocate the memory here and
+-	     now, but we can delay updating the DTV.  */
+-	  imap->l_need_tls_init = 0;
+-#ifdef SHARED
+-	  /* Update the slot information data for at least the
+-	     generation of the DSO we are allocating data for.  */
+-	  _dl_update_slotinfo (imap->l_tls_modid);
+-#endif
++  /* Perform the necessary allocations for adding new global objects
++     to the global scope below.  */
++  if (mode & RTLD_GLOBAL)
++    add_to_global_resize (new);
+ 
+-	  GL(dl_init_static_tls) (imap);
+-	  assert (imap->l_need_tls_init == 0);
+-	}
+-    }
++  /* Demarcation point: After this, no recoverable errors are allowed.
++     All memory allocations for new objects must have happened
++     before.  */
++
++  /* Second stage after resize_scopes: Actually perform the scope
++     update.  After this, dlsym and lazy binding can bind to new
++     objects.  */
++  update_scopes (new);
++
++  /* FIXME: It is unclear whether the order here is correct.
++     Shouldn't new objects be made available for binding (and thus
++     execution) only after there TLS data has been set up fully?
++     Fixing bug 16134 will likely make this distinction less
++     important.  */
++
++  /* Second stage after resize_tls_slotinfo: Update the slotinfo data
++     structures.  */
++  if (any_tls)
++    /* FIXME: This calls _dl_update_slotinfo, which aborts the process
++       on memory allocation failure.  See bug 16134.  */
++    update_tls_slotinfo (new);
+ 
+   /* Notify the debugger all new objects have been relocated.  */
+   if (relocation_in_progress)
+diff --git a/elf/dl-tls.c b/elf/dl-tls.c
+index c87caf13d6a97ba4..a2def280b7096960 100644
+--- a/elf/dl-tls.c
++++ b/elf/dl-tls.c
+@@ -883,7 +883,7 @@ _dl_tls_get_addr_soft (struct link_map *l)
+ 
+ 
+ void
+-_dl_add_to_slotinfo (struct link_map *l)
++_dl_add_to_slotinfo (struct link_map *l, bool do_add)
+ {
+   /* Now that we know the object is loaded successfully add
+      modules containing TLS data to the dtv info table.  We
+@@ -939,6 +939,9 @@ cannot create TLS data structures"));
+     }
+ 
+   /* Add the information into the slotinfo data structure.  */
+-  listp->slotinfo[idx].map = l;
+-  listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
++  if (do_add)
++    {
++      listp->slotinfo[idx].map = l;
++      listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
++    }
+ }
+diff --git a/elf/rtld.c b/elf/rtld.c
+index 4ec26a79cbb0aa4f..0aa1a2a19f649e16 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -2167,7 +2167,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+ 
+ 	  /* Add object to slot information data if necessasy.  */
+ 	  if (l->l_tls_blocksize != 0 && tls_init_tp_called)
+-	    _dl_add_to_slotinfo (l);
++	    _dl_add_to_slotinfo (l, true);
+ 	}
+     }
+   else
+@@ -2215,7 +2215,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+ 
+ 	  /* Add object to slot information data if necessasy.  */
+ 	  if (l->l_tls_blocksize != 0 && tls_init_tp_called)
+-	    _dl_add_to_slotinfo (l);
++	    _dl_add_to_slotinfo (l, true);
+ 	}
+       HP_TIMING_NOW (stop);
+ 
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 57fbefea3cb841e9..c6b7e61badbfd513 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -1135,8 +1135,15 @@ extern void *_dl_open (const char *name, int mode, const void *caller,
+    old scope, OLD can't be freed until no thread is using it.  */
+ extern int _dl_scope_free (void *) attribute_hidden;
+ 
+-/* Add module to slot information data.  */
+-extern void _dl_add_to_slotinfo (struct link_map  *l) 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_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)
++  attribute_hidden;
+ 
+ /* Update slot information data for at least the generation of the
+    module with the given index.  */
diff --git a/SOURCES/glibc-rh1410154-8.patch b/SOURCES/glibc-rh1410154-8.patch
new file mode 100644
index 0000000..c22f32a
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-8.patch
@@ -0,0 +1,619 @@
+commit f63b73814f74032c0e5d0a83300e3d864ef905e5
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Wed Nov 13 15:44:56 2019 +0100
+
+    Remove all loaded objects if dlopen fails, ignoring NODELETE [BZ #20839]
+    
+    This introduces a “pending NODELETE” state in the link map, which is
+    flipped to the persistent NODELETE state late in dlopen, via
+    activate_nodelete.    During initial relocation, symbol binding
+    records pending NODELETE state only.  dlclose ignores pending NODELETE
+    state.  Taken together, this results that a partially completed dlopen
+    is rolled back completely because new NODELETE mappings are unloaded.
+    
+    Tested on x86_64-linux-gnu and i386-linux-gnu.
+    
+    Change-Id: Ib2a3d86af6f92d75baca65431d74783ee0dbc292
+
+Conflicts:
+	elf/Makefile
+	  (Usual conflicts due to test backport differences.)
+
+diff --git a/elf/Makefile b/elf/Makefile
+index b752f6366400d221..bf7c41f38be42184 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -191,7 +191,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ 	 tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
+ 	 tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
+ 	 tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \
+-	 tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail
++	 tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail \
++	 tst-dlopenfail
+ #	 reldep9
+ tests-internal += loadtest unload unload2 circleload1 \
+ 	 neededtest neededtest2 neededtest3 neededtest4 \
+@@ -282,7 +283,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ 		tst-absolute-zero-lib tst-big-note-lib \
+ 		tst-sonamemove-linkmod1 \
+ 		tst-sonamemove-runmod1 tst-sonamemove-runmod2 \
+-		tst-initlazyfailmod tst-finilazyfailmod
++		tst-initlazyfailmod tst-finilazyfailmod \
++		tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2
+ 
+ ifeq (yes,$(have-mtls-dialect-gnu2))
+ tests += tst-gnu2-tls1
+@@ -1537,3 +1539,13 @@ LDFLAGS-tst-initlazyfailmod.so = \
+   -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all
+ LDFLAGS-tst-finilazyfailmod.so = \
+   -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all
++
++$(objpfx)tst-dlopenfail: $(libdl)
++$(objpfx)tst-dlopenfail.out: \
++  $(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so
++# Order matters here.  tst-dlopenfaillinkmod.so's soname ensures
++# a run-time loader failure.
++$(objpfx)tst-dlopenfailmod1.so: \
++  $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so
++LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so
++$(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library)
+diff --git a/elf/dl-close.c b/elf/dl-close.c
+index 88aeea25839a34e0..243a028c443173c1 100644
+--- a/elf/dl-close.c
++++ b/elf/dl-close.c
+@@ -168,14 +168,6 @@ _dl_close_worker (struct link_map *map, bool force)
+   char done[nloaded];
+   struct link_map *maps[nloaded];
+ 
+-  /* Clear DF_1_NODELETE to force object deletion.  We don't need to touch
+-     l_tls_dtor_count because forced object deletion only happens when an
+-     error occurs during object load.  Destructor registration for TLS
+-     non-POD objects should not have happened till then for this
+-     object.  */
+-  if (force)
+-    map->l_flags_1 &= ~DF_1_NODELETE;
+-
+   /* Run over the list and assign indexes to the link maps and enter
+      them into the MAPS array.  */
+   int idx = 0;
+@@ -205,7 +197,7 @@ _dl_close_worker (struct link_map *map, bool force)
+       /* Check whether this object is still used.  */
+       if (l->l_type == lt_loaded
+ 	  && l->l_direct_opencount == 0
+-	  && (l->l_flags_1 & DF_1_NODELETE) == 0
++	  && l->l_nodelete != link_map_nodelete_active
+ 	  /* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why
+ 	     acquire is sufficient and correct.  */
+ 	  && atomic_load_acquire (&l->l_tls_dtor_count) == 0
+@@ -288,7 +280,7 @@ _dl_close_worker (struct link_map *map, bool force)
+       if (!used[i])
+ 	{
+ 	  assert (imap->l_type == lt_loaded
+-		  && (imap->l_flags_1 & DF_1_NODELETE) == 0);
++		  && imap->l_nodelete != link_map_nodelete_active);
+ 
+ 	  /* Call its termination function.  Do not do it for
+ 	     half-cooked objects.  Temporarily disable exception
+@@ -828,7 +820,7 @@ _dl_close (void *_map)
+      before we took the lock. There is no way to detect this (see below)
+      so we proceed assuming this isn't the case.  First see whether we
+      can remove the object at all.  */
+-  if (__glibc_unlikely (map->l_flags_1 & DF_1_NODELETE))
++  if (__glibc_unlikely (map->l_nodelete == link_map_nodelete_active))
+     {
+       /* Nope.  Do nothing.  */
+       __rtld_lock_unlock_recursive (GL(dl_load_lock));
+diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
+index efbdb8deb3c0a9d4..c5e5857fb1fe2808 100644
+--- a/elf/dl-lookup.c
++++ b/elf/dl-lookup.c
+@@ -192,9 +192,10 @@ enter_unique_sym (struct unique_sym *table, size_t size,
+    Return the matching symbol in RESULT.  */
+ static void
+ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
+-		  const struct link_map *map, struct sym_val *result,
++		  struct link_map *map, struct sym_val *result,
+ 		  int type_class, const ElfW(Sym) *sym, const char *strtab,
+-		  const ElfW(Sym) *ref, const struct link_map *undef_map)
++		  const ElfW(Sym) *ref, const struct link_map *undef_map,
++		  int flags)
+ {
+   /* We have to determine whether we already found a symbol with this
+      name before.  If not then we have to add it to the search table.
+@@ -222,7 +223,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
+ 		     copy from the copy addressed through the
+ 		     relocation.  */
+ 		  result->s = sym;
+-		  result->m = (struct link_map *) map;
++		  result->m = map;
+ 		}
+ 	      else
+ 		{
+@@ -311,9 +312,19 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
+                         new_hash, strtab + sym->st_name, sym, map);
+ 
+       if (map->l_type == lt_loaded)
+-	/* Make sure we don't unload this object by
+-	   setting the appropriate flag.  */
+-	((struct link_map *) map)->l_flags_1 |= DF_1_NODELETE;
++	{
++	  /* Make sure we don't unload this object by
++	     setting the appropriate flag.  */
++	  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
++	      && map->l_nodelete == link_map_nodelete_inactive)
++	    _dl_debug_printf ("\
++marking %s [%lu] as NODELETE due to unique symbol\n",
++			      map->l_name, map->l_ns);
++	  if (flags & DL_LOOKUP_FOR_RELOCATE)
++	    map->l_nodelete = link_map_nodelete_pending;
++	  else
++	    map->l_nodelete = link_map_nodelete_active;
++	}
+     }
+   ++tab->n_elements;
+ 
+@@ -525,8 +536,9 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
+ 	      return 1;
+ 
+ 	    case STB_GNU_UNIQUE:;
+-	      do_lookup_unique (undef_name, new_hash, map, result, type_class,
+-				sym, strtab, ref, undef_map);
++	      do_lookup_unique (undef_name, new_hash, (struct link_map *) map,
++				result, type_class, sym, strtab, ref,
++				undef_map, flags);
+ 	      return 1;
+ 
+ 	    default:
+@@ -568,9 +580,13 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
+   if (undef_map == map)
+     return 0;
+ 
+-  /* Avoid references to objects which cannot be unloaded anyway.  */
++  /* Avoid references to objects which cannot be unloaded anyway.  We
++     do not need to record dependencies if this object goes away
++     during dlopen failure, either.  IFUNC resolvers with relocation
++     dependencies may pick an dependency which can be dlclose'd, but
++     such IFUNC resolvers are undefined anyway.  */
+   assert (map->l_type == lt_loaded);
+-  if ((map->l_flags_1 & DF_1_NODELETE) != 0)
++  if (map->l_nodelete != link_map_nodelete_inactive)
+     return 0;
+ 
+   struct link_map_reldeps *l_reldeps
+@@ -678,16 +694,33 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
+ 
+       /* Redo the NODELETE check, as when dl_load_lock wasn't held
+ 	 yet this could have changed.  */
+-      if ((map->l_flags_1 & DF_1_NODELETE) != 0)
++      if (map->l_nodelete != link_map_nodelete_inactive)
+ 	goto out;
+ 
+       /* If the object with the undefined reference cannot be removed ever
+ 	 just make sure the same is true for the object which contains the
+ 	 definition.  */
+       if (undef_map->l_type != lt_loaded
+-	  || (undef_map->l_flags_1 & DF_1_NODELETE) != 0)
++	  || (undef_map->l_nodelete != link_map_nodelete_inactive))
+ 	{
+-	  map->l_flags_1 |= DF_1_NODELETE;
++	  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
++	      && map->l_nodelete == link_map_nodelete_inactive)
++	    {
++	      if (undef_map->l_name[0] == '\0')
++		_dl_debug_printf ("\
++marking %s [%lu] as NODELETE due to reference to main program\n",
++				  map->l_name, map->l_ns);
++	      else
++		_dl_debug_printf ("\
++marking %s [%lu] as NODELETE due to reference to %s [%lu]\n",
++				  map->l_name, map->l_ns,
++				  undef_map->l_name, undef_map->l_ns);
++	    }
++
++	  if (flags & DL_LOOKUP_FOR_RELOCATE)
++	    map->l_nodelete = link_map_nodelete_pending;
++	  else
++	    map->l_nodelete = link_map_nodelete_active;
+ 	  goto out;
+ 	}
+ 
+@@ -712,7 +745,18 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
+ 		 no fatal problem.  We simply make sure the referenced object
+ 		 cannot be unloaded.  This is semantically the correct
+ 		 behavior.  */
+-	      map->l_flags_1 |= DF_1_NODELETE;
++	      if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
++		  && map->l_nodelete == link_map_nodelete_inactive)
++		_dl_debug_printf ("\
++marking %s [%lu] as NODELETE due to memory allocation failure\n",
++				  map->l_name, map->l_ns);
++	      if (flags & DL_LOOKUP_FOR_RELOCATE)
++		/* In case of non-lazy binding, we could actually
++		   report the memory allocation error, but for now, we
++		   use the conservative approximation as well. */
++		map->l_nodelete = link_map_nodelete_pending;
++	      else
++		map->l_nodelete = link_map_nodelete_active;
+ 	      goto out;
+ 	    }
+ 	  else
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index b330cff7d349224a..79c6e4c8ed1c9dfa 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -424,6 +424,40 @@ TLS generation counter wrapped!  Please report this."));
+     }
+ }
+ 
++/* Mark the objects as NODELETE if required.  This is delayed until
++   after dlopen failure is not possible, so that _dl_close can clean
++   up objects if necessary.  */
++static void
++activate_nodelete (struct link_map *new, int mode)
++{
++  if (mode & RTLD_NODELETE || new->l_nodelete == link_map_nodelete_pending)
++    {
++      if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES))
++	_dl_debug_printf ("activating NODELETE for %s [%lu]\n",
++			  new->l_name, new->l_ns);
++      new->l_nodelete = link_map_nodelete_active;
++    }
++
++  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_nodelete == link_map_nodelete_pending)
++	{
++	  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES))
++	    _dl_debug_printf ("activating NODELETE for %s [%lu]\n",
++			      imap->l_name, imap->l_ns);
++
++	  /* Only new objects should have set
++	     link_map_nodelete_pending.  Existing objects should not
++	     have gained any new dependencies and therefore cannot
++	     reach NODELETE status.  */
++	  assert (!imap->l_init_called || imap->l_type != lt_loaded);
++
++	  imap->l_nodelete = link_map_nodelete_active;
++	}
++     }
++}
++
+ /* struct dl_init_args and call_dl_init are used to call _dl_init with
+    exception handling disabled.  */
+ struct dl_init_args
+@@ -493,12 +527,6 @@ dl_open_worker (void *a)
+       return;
+     }
+ 
+-  /* Mark the object as not deletable if the RTLD_NODELETE flags was passed.
+-     Do this early so that we don't skip marking the object if it was
+-     already loaded.  */
+-  if (__glibc_unlikely (mode & RTLD_NODELETE))
+-    new->l_flags_1 |= DF_1_NODELETE;
+-
+   if (__glibc_unlikely (mode & __RTLD_SPROF))
+     /* This happens only if we load a DSO for 'sprof'.  */
+     return;
+@@ -514,19 +542,37 @@ dl_open_worker (void *a)
+ 	_dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
+ 			  new->l_name, new->l_ns, new->l_direct_opencount);
+ 
+-      /* If the user requested the object to be in the global namespace
+-	 but it is not so far, add it now.  */
++      /* If the user requested the object to be in the global
++	 namespace but it is not so far, prepare to add it now.  This
++	 can raise an exception to do a malloc failure.  */
+       if ((mode & RTLD_GLOBAL) && new->l_global == 0)
++	add_to_global_resize (new);
++
++      /* Mark the object as not deletable if the RTLD_NODELETE flags
++	 was passed.  */
++      if (__glibc_unlikely (mode & RTLD_NODELETE))
+ 	{
+-	  add_to_global_resize (new);
+-	  add_to_global_update (new);
++	  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)
++	      && new->l_nodelete == link_map_nodelete_inactive)
++	    _dl_debug_printf ("marking %s [%lu] as NODELETE\n",
++			      new->l_name, new->l_ns);
++	  new->l_nodelete = link_map_nodelete_active;
+ 	}
+ 
++      /* Finalize the addition to the global scope.  */
++      if ((mode & RTLD_GLOBAL) && new->l_global == 0)
++	add_to_global_update (new);
++
+       assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
+ 
+       return;
+     }
+ 
++  /* Schedule NODELETE marking for the directly loaded object if
++     requested.  */
++  if (__glibc_unlikely (mode & RTLD_NODELETE))
++    new->l_nodelete = link_map_nodelete_pending;
++
+   /* Load that object's dependencies.  */
+   _dl_map_object_deps (new, NULL, 0, 0,
+ 		       mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT));
+@@ -598,6 +644,14 @@ dl_open_worker (void *a)
+ 
+   int relocation_in_progress = 0;
+ 
++  /* Perform relocation.  This can trigger lazy binding in IFUNC
++     resolvers.  For NODELETE mappings, these dependencies are not
++     recorded because the flag has not been applied to the newly
++     loaded objects.  This means that upon dlopen failure, these
++     NODELETE objects can be unloaded despite existing references to
++     them.  However, such relocation dependencies in IFUNC resolvers
++     are undefined anyway, so this is not a problem.  */
++
+   for (unsigned int i = nmaps; i-- > 0; )
+     {
+       l = maps[i];
+@@ -627,7 +681,7 @@ dl_open_worker (void *a)
+ 	      _dl_start_profile ();
+ 
+ 	      /* Prevent unloading the object.  */
+-	      GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE;
++	      GL(dl_profile_map)->l_nodelete = link_map_nodelete_active;
+ 	    }
+ 	}
+       else
+@@ -658,6 +712,8 @@ dl_open_worker (void *a)
+      All memory allocations for new objects must have happened
+      before.  */
+ 
++  activate_nodelete (new, mode);
++
+   /* Second stage after resize_scopes: Actually perform the scope
+      update.  After this, dlsym and lazy binding can bind to new
+      objects.  */
+@@ -817,6 +873,10 @@ no more namespaces available for dlmopen()"));
+ 	    GL(dl_tls_dtv_gaps) = true;
+ 
+ 	  _dl_close_worker (args.map, true);
++
++	  /* All link_map_nodelete_pending objects should have been
++	     deleted at this point, which is why it is not necessary
++	     to reset the flag here.  */
+ 	}
+ 
+       assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
+diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
+index 4b1ea7c4078ee947..ea286abaea0128d1 100644
+--- a/elf/get-dynamic-info.h
++++ b/elf/get-dynamic-info.h
+@@ -163,6 +163,8 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
+   if (info[VERSYMIDX (DT_FLAGS_1)] != NULL)
+     {
+       l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val;
++      if (l->l_flags_1 & DF_1_NODELETE)
++	l->l_nodelete = link_map_nodelete_pending;
+ 
+       /* Only DT_1_SUPPORTED_MASK bits are supported, and we would like
+ 	 to assert this, but we can't. Users have been setting
+diff --git a/elf/tst-dlopenfail.c b/elf/tst-dlopenfail.c
+new file mode 100644
+index 0000000000000000..ce3140c899562ca8
+--- /dev/null
++++ b/elf/tst-dlopenfail.c
+@@ -0,0 +1,79 @@
++/* Test dlopen rollback after failures involving NODELETE objects (bug 20839).
++   Copyright (C) 2019 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 <errno.h>
++#include <gnu/lib-names.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/xdlfcn.h>
++
++static int
++do_test (void)
++{
++  /* This test uses libpthread as the canonical NODELETE module.  If
++     libpthread is no longer NODELETE because it has been merged into
++     libc, the test needs to be updated.  */
++  TEST_VERIFY (dlsym (NULL, "pthread_create") == NULL);
++
++  /* This is expected to fail because of the missing dependency.  */
++  puts ("info: attempting to load tst-dlopenfailmod1.so");
++  TEST_VERIFY (dlopen ("tst-dlopenfailmod1.so", RTLD_LAZY) == NULL);
++  const char *message = dlerror ();
++  TEST_COMPARE_STRING (message,
++                       "tst-dlopenfail-missingmod.so:"
++                       " cannot open shared object file:"
++                       " No such file or directory");
++
++  /* Do not probe for the presence of libpthread at this point because
++     that might trigger relocation if bug 20839 is present, obscuring
++     a subsequent crash.  */
++
++  /* This is expected to succeed.  */
++  puts ("info: loading tst-dlopenfailmod2.so");
++  void *handle = xdlopen ("tst-dlopenfailmod2.so", RTLD_NOW);
++  xdlclose (handle);
++
++  /* libpthread should remain loaded.  */
++  TEST_VERIFY (dlopen (LIBPTHREAD_SO, RTLD_LAZY | RTLD_NOLOAD) != NULL);
++  TEST_VERIFY (dlsym (NULL, "pthread_create") == NULL);
++
++  /* We can make libpthread global, and then the symbol should become
++     available.  */
++  TEST_VERIFY (dlopen (LIBPTHREAD_SO, RTLD_LAZY | RTLD_GLOBAL) != NULL);
++  TEST_VERIFY (dlsym (NULL, "pthread_create") != NULL);
++
++  /* sem_open is sufficiently complex to depend on relocations.  */
++  void *(*sem_open_ptr) (const char *, int flag, ...)
++    = dlsym (NULL, "sem_open");
++  if (sem_open_ptr == NULL)
++    /* Hurd does not implement sem_open.  */
++    puts ("warning: sem_open not found, further testing not possible");
++  else
++    {
++      errno = 0;
++      TEST_VERIFY (sem_open_ptr ("/", 0) == NULL);
++      TEST_COMPARE (errno, EINVAL);
++    }
++
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/elf/tst-dlopenfaillinkmod.c b/elf/tst-dlopenfaillinkmod.c
+new file mode 100644
+index 0000000000000000..3b14b02bc9a12c0b
+--- /dev/null
++++ b/elf/tst-dlopenfaillinkmod.c
+@@ -0,0 +1,17 @@
++/* Empty module with a soname which is not available at run time.
++   Copyright (C) 2019 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/>.  */
+diff --git a/elf/tst-dlopenfailmod1.c b/elf/tst-dlopenfailmod1.c
+new file mode 100644
+index 0000000000000000..6ef48829899a5a64
+--- /dev/null
++++ b/elf/tst-dlopenfailmod1.c
+@@ -0,0 +1,36 @@
++/* Module which depends on two modules: one NODELETE, one missing.
++   Copyright (C) 2019 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/>.  */
++
++/* Note: Due to the missing second module, this object cannot be
++   loaded at run time.  */
++
++#include <pthread.h>
++#include <stdio.h>
++#include <unistd.h>
++
++/* Force linking against libpthread.  */
++void *pthread_create_reference = pthread_create;
++
++/* The constructor will never be executed because the module cannot be
++   loaded.  */
++static void __attribute__ ((constructor))
++init (void)
++{
++  puts ("tst-dlopenfailmod1 constructor executed");
++  _exit (1);
++}
+diff --git a/elf/tst-dlopenfailmod2.c b/elf/tst-dlopenfailmod2.c
+new file mode 100644
+index 0000000000000000..7d600386c13b98bd
+--- /dev/null
++++ b/elf/tst-dlopenfailmod2.c
+@@ -0,0 +1,29 @@
++/* Module which depends on on a NODELETE module, and can be loaded.
++   Copyright (C) 2019 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 <pthread.h>
++#include <stdio.h>
++
++/* Force linking against libpthread.  */
++void *pthread_create_reference = pthread_create;
++
++static void __attribute__ ((constructor))
++init (void)
++{
++  puts ("info: tst-dlopenfailmod2.so constructor invoked");
++}
+diff --git a/include/link.h b/include/link.h
+index 83b1c34b7b4db8f3..a277b77cad6b52b1 100644
+--- a/include/link.h
++++ b/include/link.h
+@@ -79,6 +79,21 @@ struct r_search_path_struct
+     int malloced;
+   };
+ 
++/* Type used by the l_nodelete member.  */
++enum link_map_nodelete
++{
++ /* This link map can be deallocated.  */
++ link_map_nodelete_inactive = 0, /* Zero-initialized in _dl_new_object.  */
++
++ /* This link map cannot be deallocated.  */
++ link_map_nodelete_active,
++
++ /* This link map cannot be deallocated after dlopen has succeded.
++    dlopen turns this into link_map_nodelete_active.  dlclose treats
++    this intermediate state as link_map_nodelete_active.  */
++ link_map_nodelete_pending,
++};
++
+ 
+ /* Structure describing a loaded shared object.  The `l_next' and `l_prev'
+    members form a chain of all the shared objects loaded at startup.
+@@ -203,6 +218,11 @@ struct link_map
+ 				       freed, ie. not allocated with
+ 				       the dummy malloc in ld.so.  */
+ 
++    /* Actually of type enum link_map_nodelete.  Separate byte due to
++       a read in add_dependency in elf/dl-lookup.c outside the loader
++       lock.  Only valid for l_type == lt_loaded.  */
++    unsigned char l_nodelete;
++
+ #include <link_map.h>
+ 
+     /* Collected information about own RPATH directories.  */
diff --git a/SOURCES/glibc-rh1410154-9.patch b/SOURCES/glibc-rh1410154-9.patch
new file mode 100644
index 0000000..ab5a3df
--- /dev/null
+++ b/SOURCES/glibc-rh1410154-9.patch
@@ -0,0 +1,104 @@
+commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Oct 31 19:30:19 2019 +0100
+
+    Block signals during the initial part of dlopen
+    
+    Lazy binding in a signal handler that interrupts a dlopen sees
+    intermediate dynamic linker state.  This has likely been always
+    unsafe, but with the new pending NODELETE state, this is clearly
+    incorrect.  Other threads are excluded via the loader lock, but the
+    current thread is not.  Blocking signals until right before ELF
+    constructors run is the safe thing to do.
+    
+    Change-Id: Iad079080ebe7442c13313ba11dc2797953faef35
+
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index 79c6e4c8ed1c9dfa..25838b073ac1edaf 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -34,6 +34,7 @@
+ #include <atomic.h>
+ #include <libc-internal.h>
+ #include <array_length.h>
++#include <internal-signals.h>
+ 
+ #include <dl-dst.h>
+ #include <dl-prop.h>
+@@ -52,6 +53,10 @@ struct dl_open_args
+   /* Namespace ID.  */
+   Lmid_t nsid;
+ 
++  /* Original signal mask.  Used for unblocking signal handlers before
++     running ELF constructors.  */
++  sigset_t original_signal_mask;
++
+   /* Original value of _ns_global_scope_pending_adds.  Set by
+      dl_open_worker.  Only valid if nsid is a real namespace
+      (non-negative).  */
+@@ -524,12 +529,16 @@ dl_open_worker (void *a)
+   if (new == NULL)
+     {
+       assert (mode & RTLD_NOLOAD);
++      __libc_signal_restore_set (&args->original_signal_mask);
+       return;
+     }
+ 
+   if (__glibc_unlikely (mode & __RTLD_SPROF))
+-    /* This happens only if we load a DSO for 'sprof'.  */
+-    return;
++    {
++      /* This happens only if we load a DSO for 'sprof'.  */
++      __libc_signal_restore_set (&args->original_signal_mask);
++      return;
++    }
+ 
+   /* This object is directly loaded.  */
+   ++new->l_direct_opencount;
+@@ -565,6 +574,7 @@ dl_open_worker (void *a)
+ 
+       assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
+ 
++      __libc_signal_restore_set (&args->original_signal_mask);
+       return;
+     }
+ 
+@@ -745,6 +755,10 @@ dl_open_worker (void *a)
+   if (mode & RTLD_GLOBAL)
+     add_to_global_resize (new);
+ 
++  /* Unblock signals.  Data structures are now consistent, and
++     application code may run.  */
++  __libc_signal_restore_set (&args->original_signal_mask);
++
+   /* Run the initializer functions of new objects.  Temporarily
+      disable the exception handler, so that lazy binding failures are
+      fatal.  */
+@@ -834,6 +848,10 @@ no more namespaces available for dlmopen()"));
+   args.argv = argv;
+   args.env = env;
+ 
++  /* Recursive lazy binding during manipulation of the dynamic loader
++     structures may result in incorrect behavior.  */
++  __libc_signal_block_all (&args.original_signal_mask);
++
+   struct dl_exception exception;
+   int errcode = _dl_catch_exception (&exception, dl_open_worker, &args);
+ 
+@@ -874,10 +892,16 @@ no more namespaces available for dlmopen()"));
+ 
+ 	  _dl_close_worker (args.map, true);
+ 
++	  /* Restore the signal mask.  In the success case, this
++	     happens inside dl_open_worker.  */
++	  __libc_signal_restore_set (&args.original_signal_mask);
++
+ 	  /* All link_map_nodelete_pending objects should have been
+ 	     deleted at this point, which is why it is not necessary
+ 	     to reset the flag here.  */
+ 	}
++      else
++	__libc_signal_restore_set (&args.original_signal_mask);
+ 
+       assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
+ 
diff --git a/SOURCES/glibc-rh1682954.patch b/SOURCES/glibc-rh1682954.patch
new file mode 100644
index 0000000..4892f52
--- /dev/null
+++ b/SOURCES/glibc-rh1682954.patch
@@ -0,0 +1,545 @@
+From 0d3905b110000463775b3fb189213833acaebf81 Mon Sep 17 00:00:00 2001
+From: "H.J. Lu" <hjl.tools@gmail.com>
+Date: Mon, 1 Jul 2019 12:23:10 -0700
+Subject: Call _dl_open_check after relocation [BZ #24259]
+
+This is a workaround for [BZ #20839] which doesn't remove the NODELETE
+object when _dl_open_check throws an exception.  Move it after relocation
+in dl_open_worker to avoid leaving the NODELETE object mapped without
+relocation.
+
+	[BZ #24259]
+	* elf/dl-open.c (dl_open_worker): Call _dl_open_check after
+	relocation.
+	* sysdeps/x86/Makefile (tests): Add tst-cet-legacy-5a,
+	tst-cet-legacy-5b, tst-cet-legacy-6a and tst-cet-legacy-6b.
+	(modules-names): Add tst-cet-legacy-mod-5a, tst-cet-legacy-mod-5b,
+	tst-cet-legacy-mod-5c, tst-cet-legacy-mod-6a, tst-cet-legacy-mod-6b
+	and tst-cet-legacy-mod-6c.
+	(CFLAGS-tst-cet-legacy-5a.c): New.
+	(CFLAGS-tst-cet-legacy-5b.c): Likewise.
+	(CFLAGS-tst-cet-legacy-mod-5a.c): Likewise.
+	(CFLAGS-tst-cet-legacy-mod-5b.c): Likewise.
+	(CFLAGS-tst-cet-legacy-mod-5c.c): Likewise.
+	(CFLAGS-tst-cet-legacy-6a.c): Likewise.
+	(CFLAGS-tst-cet-legacy-6b.c): Likewise.
+	(CFLAGS-tst-cet-legacy-mod-6a.c): Likewise.
+	(CFLAGS-tst-cet-legacy-mod-6b.c): Likewise.
+	(CFLAGS-tst-cet-legacy-mod-6c.c): Likewise.
+	($(objpfx)tst-cet-legacy-5a): Likewise.
+	($(objpfx)tst-cet-legacy-5a.out): Likewise.
+	($(objpfx)tst-cet-legacy-mod-5a.so): Likewise.
+	($(objpfx)tst-cet-legacy-mod-5b.so): Likewise.
+	($(objpfx)tst-cet-legacy-5b): Likewise.
+	($(objpfx)tst-cet-legacy-5b.out): Likewise.
+	(tst-cet-legacy-5b-ENV): Likewise.
+	($(objpfx)tst-cet-legacy-6a): Likewise.
+	($(objpfx)tst-cet-legacy-6a.out): Likewise.
+	($(objpfx)tst-cet-legacy-mod-6a.so): Likewise.
+	($(objpfx)tst-cet-legacy-mod-6b.so): Likewise.
+	($(objpfx)tst-cet-legacy-6b): Likewise.
+	($(objpfx)tst-cet-legacy-6b.out): Likewise.
+	(tst-cet-legacy-6b-ENV): Likewise.
+	* sysdeps/x86/tst-cet-legacy-5.c: New file.
+	* sysdeps/x86/tst-cet-legacy-5a.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-5b.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-6.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-6a.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-6b.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-5.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-5a.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-5b.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-5c.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-6.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-6a.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-6b.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-6c.c: Likewise.
+
+(cherry picked from commit d0093c5cefb7f7a4143f3bb03743633823229cc6)
+
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index f6c8ef1043..518a6cad69 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -292,8 +292,6 @@ dl_open_worker (void *a)
+   _dl_debug_state ();
+   LIBC_PROBE (map_complete, 3, args->nsid, r, new);
+ 
+-  _dl_open_check (new);
+-
+   /* Print scope information.  */
+   if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
+     _dl_show_scope (new, 0);
+@@ -366,6 +364,12 @@ dl_open_worker (void *a)
+ 	_dl_relocate_object (l, l->l_scope, reloc_mode, 0);
+     }
+ 
++  /* NB: Workaround for [BZ #20839] which doesn't remove the NODELETE
++     object when _dl_open_check throws an exception.  Move it after
++     relocation to avoid leaving the NODELETE object mapped without
++     relocation.  */
++  _dl_open_check (new);
++
+   /* If the file is not loaded now as a dependency, add the search
+      list of the newly loaded object to the scope.  */
+   bool any_tls = false;
+diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
+index 337b0b63dc..43ad4a79ff 100644
+--- a/sysdeps/x86/Makefile
++++ b/sysdeps/x86/Makefile
+@@ -19,12 +19,17 @@ ifeq ($(subdir),elf)
+ sysdep-dl-routines += dl-cet
+ 
+ tests += tst-cet-legacy-1 tst-cet-legacy-2 tst-cet-legacy-2a \
+-	 tst-cet-legacy-3 tst-cet-legacy-4
++	 tst-cet-legacy-3 tst-cet-legacy-4 \
++	 tst-cet-legacy-5a tst-cet-legacy-6a
+ ifneq (no,$(have-tunables))
+-tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c
++tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c \
++	 tst-cet-legacy-5b tst-cet-legacy-6b
+ endif
+ modules-names += tst-cet-legacy-mod-1 tst-cet-legacy-mod-2 \
+-		 tst-cet-legacy-mod-4
++		 tst-cet-legacy-mod-4 tst-cet-legacy-mod-5a \
++		 tst-cet-legacy-mod-5b tst-cet-legacy-mod-5c \
++		 tst-cet-legacy-mod-6a tst-cet-legacy-mod-6b \
++		 tst-cet-legacy-mod-6c
+ 
+ CFLAGS-tst-cet-legacy-2.c += -fcf-protection=branch
+ CFLAGS-tst-cet-legacy-2a.c += -fcf-protection
+@@ -35,6 +40,16 @@ CFLAGS-tst-cet-legacy-4.c += -fcf-protection=branch
+ CFLAGS-tst-cet-legacy-4a.c += -fcf-protection
+ CFLAGS-tst-cet-legacy-4b.c += -fcf-protection
+ CFLAGS-tst-cet-legacy-mod-4.c += -fcf-protection=none
++CFLAGS-tst-cet-legacy-5a.c += -fcf-protection
++CFLAGS-tst-cet-legacy-5b.c += -fcf-protection
++CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=none
++CFLAGS-tst-cet-legacy-mod-5b.c += -fcf-protection
++CFLAGS-tst-cet-legacy-mod-5c.c += -fcf-protection
++CFLAGS-tst-cet-legacy-6a.c += -fcf-protection
++CFLAGS-tst-cet-legacy-6b.c += -fcf-protection
++CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=none
++CFLAGS-tst-cet-legacy-mod-6b.c += -fcf-protection
++CFLAGS-tst-cet-legacy-mod-6c.c += -fcf-protection
+ 
+ $(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \
+ 		       $(objpfx)tst-cet-legacy-mod-2.so
+@@ -44,6 +59,17 @@ $(objpfx)tst-cet-legacy-2a: $(objpfx)tst-cet-legacy-mod-2.so $(libdl)
+ $(objpfx)tst-cet-legacy-2a.out: $(objpfx)tst-cet-legacy-mod-1.so
+ $(objpfx)tst-cet-legacy-4: $(libdl)
+ $(objpfx)tst-cet-legacy-4.out: $(objpfx)tst-cet-legacy-mod-4.so
++$(objpfx)tst-cet-legacy-5a: $(libdl)
++$(objpfx)tst-cet-legacy-5a.out: $(objpfx)tst-cet-legacy-mod-5a.so \
++				$(objpfx)tst-cet-legacy-mod-5b.so
++$(objpfx)tst-cet-legacy-mod-5a.so: $(objpfx)tst-cet-legacy-mod-5c.so
++$(objpfx)tst-cet-legacy-mod-5b.so: $(objpfx)tst-cet-legacy-mod-5c.so
++$(objpfx)tst-cet-legacy-6a: $(libdl)
++$(objpfx)tst-cet-legacy-6a.out: $(objpfx)tst-cet-legacy-mod-6a.so \
++				$(objpfx)tst-cet-legacy-mod-6b.so
++$(objpfx)tst-cet-legacy-mod-6a.so: $(objpfx)tst-cet-legacy-mod-6c.so
++$(objpfx)tst-cet-legacy-mod-6b.so: $(objpfx)tst-cet-legacy-mod-6c.so
++LDFLAGS-tst-cet-legacy-mod-6c.so = -Wl,--enable-new-dtags,-z,nodelete
+ ifneq (no,$(have-tunables))
+ $(objpfx)tst-cet-legacy-4a: $(libdl)
+ $(objpfx)tst-cet-legacy-4a.out: $(objpfx)tst-cet-legacy-mod-4.so
+@@ -54,6 +80,14 @@ tst-cet-legacy-4b-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=on
+ $(objpfx)tst-cet-legacy-4c: $(libdl)
+ $(objpfx)tst-cet-legacy-4c.out: $(objpfx)tst-cet-legacy-mod-4.so
+ tst-cet-legacy-4c-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=off
++$(objpfx)tst-cet-legacy-5b: $(libdl)
++$(objpfx)tst-cet-legacy-5b.out: $(objpfx)tst-cet-legacy-mod-5a.so \
++				$(objpfx)tst-cet-legacy-mod-5b.so
++tst-cet-legacy-5b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off
++$(objpfx)tst-cet-legacy-6b: $(libdl)
++$(objpfx)tst-cet-legacy-6b.out: $(objpfx)tst-cet-legacy-mod-6a.so \
++				$(objpfx)tst-cet-legacy-mod-6b.so
++tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off
+ endif
+ endif
+ 
+diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c
+new file mode 100644
+index 0000000000..fbf640f664
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-5.c
+@@ -0,0 +1,76 @@
++/* Check compatibility of CET-enabled executable with dlopened legacy
++   shared object.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <dlfcn.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdbool.h>
++#include <string.h>
++
++static void
++do_test_1 (const char *modname, bool fail)
++{
++  int (*fp) (void);
++  void *h;
++
++  h = dlopen (modname, RTLD_LAZY);
++  if (h == NULL)
++    {
++      if (fail)
++	{
++	  const char *err = dlerror ();
++	  if (strstr (err, "shadow stack isn't enabled") == NULL)
++	    {
++	      printf ("incorrect dlopen '%s' error: %s\n", modname,
++		      dlerror ());
++	      exit (1);
++	    }
++
++	  return;
++	}
++
++      printf ("cannot open '%s': %s\n", modname, dlerror ());
++      exit (1);
++    }
++
++  fp = dlsym (h, "test");
++  if (fp == NULL)
++    {
++      printf ("cannot get symbol 'test': %s\n", dlerror ());
++      exit (1);
++    }
++
++  if (fp () != 0)
++    {
++      puts ("test () != 0");
++      exit (1);
++    }
++
++  dlclose (h);
++}
++
++static int
++do_test (void)
++{
++  do_test_1 ("tst-cet-legacy-mod-5a.so", true);
++  do_test_1 ("tst-cet-legacy-mod-5b.so", false);
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/sysdeps/x86/tst-cet-legacy-5a.c b/sysdeps/x86/tst-cet-legacy-5a.c
+new file mode 100644
+index 0000000000..fc5a609dff
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-5a.c
+@@ -0,0 +1 @@
++#include "tst-cet-legacy-5.c"
+diff --git a/sysdeps/x86/tst-cet-legacy-5b.c b/sysdeps/x86/tst-cet-legacy-5b.c
+new file mode 100644
+index 0000000000..fc5a609dff
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-5b.c
+@@ -0,0 +1 @@
++#include "tst-cet-legacy-5.c"
+diff --git a/sysdeps/x86/tst-cet-legacy-6.c b/sysdeps/x86/tst-cet-legacy-6.c
+new file mode 100644
+index 0000000000..9151225264
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-6.c
+@@ -0,0 +1,76 @@
++/* Check compatibility of CET-enabled executable with dlopened legacy
++   shared object.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <dlfcn.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdbool.h>
++#include <string.h>
++
++static void
++do_test_1 (const char *modname, bool fail)
++{
++  int (*fp) (void);
++  void *h;
++
++  h = dlopen (modname, RTLD_LAZY);
++  if (h == NULL)
++    {
++      if (fail)
++	{
++	  const char *err = dlerror ();
++	  if (strstr (err, "shadow stack isn't enabled") == NULL)
++	    {
++	      printf ("incorrect dlopen '%s' error: %s\n", modname,
++		      dlerror ());
++	      exit (1);
++	    }
++
++	  return;
++	}
++
++      printf ("cannot open '%s': %s\n", modname, dlerror ());
++      exit (1);
++    }
++
++  fp = dlsym (h, "test");
++  if (fp == NULL)
++    {
++      printf ("cannot get symbol 'test': %s\n", dlerror ());
++      exit (1);
++    }
++
++  if (fp () != 0)
++    {
++      puts ("test () != 0");
++      exit (1);
++    }
++
++  dlclose (h);
++}
++
++static int
++do_test (void)
++{
++  do_test_1 ("tst-cet-legacy-mod-6a.so", true);
++  do_test_1 ("tst-cet-legacy-mod-6b.so", false);
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/sysdeps/x86/tst-cet-legacy-6a.c b/sysdeps/x86/tst-cet-legacy-6a.c
+new file mode 100644
+index 0000000000..2d1546d36b
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-6a.c
+@@ -0,0 +1 @@
++#include "tst-cet-legacy-6.c"
+diff --git a/sysdeps/x86/tst-cet-legacy-6b.c b/sysdeps/x86/tst-cet-legacy-6b.c
+new file mode 100644
+index 0000000000..2d1546d36b
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-6b.c
+@@ -0,0 +1 @@
++#include "tst-cet-legacy-6.c"
+diff --git a/sysdeps/x86/tst-cet-legacy-mod-5.c b/sysdeps/x86/tst-cet-legacy-mod-5.c
+new file mode 100644
+index 0000000000..3c1071c2ef
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-mod-5.c
+@@ -0,0 +1,31 @@
++/* Check compatibility of CET-enabled executable with dlopened legacy
++   shared object.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <error.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++extern void foo (void);
++
++int
++test (void)
++{
++  foo ();
++  return 0;
++}
+diff --git a/sysdeps/x86/tst-cet-legacy-mod-5a.c b/sysdeps/x86/tst-cet-legacy-mod-5a.c
+new file mode 100644
+index 0000000000..daa43e4e8d
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-mod-5a.c
+@@ -0,0 +1 @@
++#include "tst-cet-legacy-mod-5.c"
+diff --git a/sysdeps/x86/tst-cet-legacy-mod-5b.c b/sysdeps/x86/tst-cet-legacy-mod-5b.c
+new file mode 100644
+index 0000000000..daa43e4e8d
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-mod-5b.c
+@@ -0,0 +1 @@
++#include "tst-cet-legacy-mod-5.c"
+diff --git a/sysdeps/x86/tst-cet-legacy-mod-5c.c b/sysdeps/x86/tst-cet-legacy-mod-5c.c
+new file mode 100644
+index 0000000000..e529a42ac0
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-mod-5c.c
+@@ -0,0 +1,36 @@
++/* Check compatibility of CET-enabled executable with dlopened legacy
++   shared object.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <stdlib.h>
++
++static int called = 0;
++
++static void
++__attribute__ ((constructor))
++init (void)
++{
++  called = 1;
++}
++
++void
++foo (void)
++{
++  if (!called)
++    abort ();
++}
+diff --git a/sysdeps/x86/tst-cet-legacy-mod-6.c b/sysdeps/x86/tst-cet-legacy-mod-6.c
+new file mode 100644
+index 0000000000..3c1071c2ef
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-mod-6.c
+@@ -0,0 +1,31 @@
++/* Check compatibility of CET-enabled executable with dlopened legacy
++   shared object.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <error.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++extern void foo (void);
++
++int
++test (void)
++{
++  foo ();
++  return 0;
++}
+diff --git a/sysdeps/x86/tst-cet-legacy-mod-6a.c b/sysdeps/x86/tst-cet-legacy-mod-6a.c
+new file mode 100644
+index 0000000000..c89b8fe8ff
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-mod-6a.c
+@@ -0,0 +1 @@
++#include "tst-cet-legacy-mod-6.c"
+diff --git a/sysdeps/x86/tst-cet-legacy-mod-6b.c b/sysdeps/x86/tst-cet-legacy-mod-6b.c
+new file mode 100644
+index 0000000000..c89b8fe8ff
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-mod-6b.c
+@@ -0,0 +1 @@
++#include "tst-cet-legacy-mod-6.c"
+diff --git a/sysdeps/x86/tst-cet-legacy-mod-6c.c b/sysdeps/x86/tst-cet-legacy-mod-6c.c
+new file mode 100644
+index 0000000000..e529a42ac0
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-mod-6c.c
+@@ -0,0 +1,36 @@
++/* Check compatibility of CET-enabled executable with dlopened legacy
++   shared object.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <stdlib.h>
++
++static int called = 0;
++
++static void
++__attribute__ ((constructor))
++init (void)
++{
++  called = 1;
++}
++
++void
++foo (void)
++{
++  if (!called)
++    abort ();
++}
+diff --git a/sysdeps/x86/tst-cet-legacy-mod-6d.c b/sysdeps/x86/tst-cet-legacy-mod-6d.c
+new file mode 100644
+index 0000000000..eb233a1d10
+--- /dev/null
++++ b/sysdeps/x86/tst-cet-legacy-mod-6d.c
+@@ -0,0 +1 @@
++#include "tst-cet-legacy-mod-6c.c"
diff --git a/SOURCES/glibc-rh1726638-1.patch b/SOURCES/glibc-rh1726638-1.patch
new file mode 100644
index 0000000..96c2b21
--- /dev/null
+++ b/SOURCES/glibc-rh1726638-1.patch
@@ -0,0 +1,35 @@
+commit 55f82d328d2dd1c7c13c1992f4b9bf9c95b57551
+Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
+Date:   Thu Apr 25 15:35:35 2019 +0100
+
+    aarch64: add STO_AARCH64_VARIANT_PCS and DT_AARCH64_VARIANT_PCS
+    
+    STO_AARCH64_VARIANT_PCS is a non-visibility st_other flag for marking
+    symbols that reference functions that may follow a variant PCS with
+    different register usage convention from the base PCS.
+    
+    DT_AARCH64_VARIANT_PCS is a dynamic tag that marks ELF modules that
+    have R_*_JUMP_SLOT relocations for symbols marked with
+    STO_AARCH64_VARIANT_PCS (i.e. have variant PCS calls via a PLT).
+    
+            * elf/elf.h (STO_AARCH64_VARIANT_PCS): Define.
+            (DT_AARCH64_VARIANT_PCS): Define.
+
+diff --git a/elf/elf.h b/elf/elf.h
+index 7e2b072a7f75451c..74f7f479ce817040 100644
+--- a/elf/elf.h
++++ b/elf/elf.h
+@@ -2847,6 +2847,13 @@ enum
+ #define R_AARCH64_TLSDESC      1031	/* TLS Descriptor.  */
+ #define R_AARCH64_IRELATIVE	1032	/* STT_GNU_IFUNC relocation.  */
+ 
++/* AArch64 specific values for the Dyn d_tag field.  */
++#define DT_AARCH64_VARIANT_PCS	(DT_LOPROC + 5)
++#define DT_AARCH64_NUM		6
++
++/* AArch64 specific values for the st_other field.  */
++#define STO_AARCH64_VARIANT_PCS 0x80
++
+ /* ARM relocs.  */
+ 
+ #define R_ARM_NONE		0	/* No reloc */
diff --git a/SOURCES/glibc-rh1726638-2.patch b/SOURCES/glibc-rh1726638-2.patch
new file mode 100644
index 0000000..f321c7a
--- /dev/null
+++ b/SOURCES/glibc-rh1726638-2.patch
@@ -0,0 +1,138 @@
+commit 82bc69c012838a381c4167c156a06f4598f34227
+Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
+Date:   Thu Apr 25 15:35:35 2019 +0100
+
+    aarch64: handle STO_AARCH64_VARIANT_PCS
+    
+    Avoid lazy binding of symbols that may follow a variant PCS with different
+    register usage convention from the base PCS.
+    
+    Currently the lazy binding entry code does not preserve all the registers
+    required for AdvSIMD and SVE vector calls.  Saving and restoring all
+    registers unconditionally may break existing binaries, even if they never
+    use vector calls, because of the larger stack requirement for lazy
+    resolution, which can be significant on an SVE system.
+    
+    The solution is to mark all symbols in the symbol table that may follow
+    a variant PCS so the dynamic linker can handle them specially.  In this
+    patch such symbols are always resolved at load time, not lazily.
+    
+    So currently LD_AUDIT for variant PCS symbols are not supported, for that
+    the _dl_runtime_profile entry needs to be changed e.g. to unconditionally
+    save/restore all registers (but pass down arg and retval registers to
+    pltentry/exit callbacks according to the base PCS).
+    
+    This patch also removes a __builtin_expect from the modified code because
+    the branch prediction hint did not seem useful.
+    
+            * sysdeps/aarch64/dl-dtprocnum.h: New file.
+            * sysdeps/aarch64/dl-machine.h (DT_AARCH64): Define.
+            (elf_machine_runtime_setup): Handle DT_AARCH64_VARIANT_PCS.
+            (elf_machine_lazy_rel): Check STO_AARCH64_VARIANT_PCS and bind such
+            symbols at load time.
+            * sysdeps/aarch64/linkmap.h (struct link_map_machine): Add variant_pcs.
+
+diff --git a/sysdeps/aarch64/dl-dtprocnum.h b/sysdeps/aarch64/dl-dtprocnum.h
+new file mode 100644
+index 0000000000000000..4ac2adf23458e02d
+--- /dev/null
++++ b/sysdeps/aarch64/dl-dtprocnum.h
+@@ -0,0 +1,21 @@
++/* Configuration of lookup functions.  AArch64 version.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++/* Number of extra dynamic section entries for this architecture.  By
++   default there are none.  */
++#define DT_THISPROCNUM	DT_AARCH64_NUM
+diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
+index 4935aa7c543876db..d4494852b32b8783 100644
+--- a/sysdeps/aarch64/dl-machine.h
++++ b/sysdeps/aarch64/dl-machine.h
+@@ -27,6 +27,9 @@
+ #include <dl-irel.h>
+ #include <cpu-features.c>
+ 
++/* Translate a processor specific dynamic tag to the index in l_info array.  */
++#define DT_AARCH64(x) (DT_AARCH64_##x - DT_LOPROC + DT_NUM)
++
+ /* Return nonzero iff ELF header is compatible with the running host.  */
+ static inline int __attribute__ ((unused))
+ elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
+@@ -102,6 +105,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
+ 	}
+     }
+ 
++  /* Check if STO_AARCH64_VARIANT_PCS needs to be handled.  */
++  if (l->l_info[DT_AARCH64 (VARIANT_PCS)])
++    l->l_mach.variant_pcs = 1;
++
+   return lazy;
+ }
+ 
+@@ -388,10 +395,37 @@ elf_machine_lazy_rel (struct link_map *map,
+   /* Check for unexpected PLT reloc type.  */
+   if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1))
+     {
+-      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+-	*reloc_addr += l_addr;
+-      else
+-	*reloc_addr = map->l_mach.plt;
++      if (map->l_mach.plt == 0)
++	{
++	  /* Prelinking.  */
++	  *reloc_addr += l_addr;
++	  return;
++	}
++
++      if (__glibc_unlikely (map->l_mach.variant_pcs))
++	{
++	  /* Check the symbol table for variant PCS symbols.  */
++	  const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
++	  const ElfW (Sym) *symtab =
++	    (const void *)D_PTR (map, l_info[DT_SYMTAB]);
++	  const ElfW (Sym) *sym = &symtab[symndx];
++	  if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS))
++	    {
++	      /* Avoid lazy resolution of variant PCS symbols.  */
++	      const struct r_found_version *version = NULL;
++	      if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
++		{
++		  const ElfW (Half) *vernum =
++		    (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
++		  version = &map->l_versions[vernum[symndx] & 0x7fff];
++		}
++	      elf_machine_rela (map, reloc, sym, version, reloc_addr,
++				skip_ifunc);
++	      return;
++	    }
++	}
++
++      *reloc_addr = map->l_mach.plt;
+     }
+   else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1))
+     {
+diff --git a/sysdeps/aarch64/linkmap.h b/sysdeps/aarch64/linkmap.h
+index 6852f343a1efd150..dd8597470c3d2174 100644
+--- a/sysdeps/aarch64/linkmap.h
++++ b/sysdeps/aarch64/linkmap.h
+@@ -20,4 +20,5 @@ struct link_map_machine
+ {
+   ElfW(Addr) plt;	  /* Address of .plt */
+   void *tlsdesc_table;	  /* Address of TLS descriptor hash table.  */
++  int variant_pcs;	  /* If set, PLT calls may follow a variant PCS.  */
+ };
diff --git a/SOURCES/glibc-rh1726638-3.patch b/SOURCES/glibc-rh1726638-3.patch
new file mode 100644
index 0000000..6c37873
--- /dev/null
+++ b/SOURCES/glibc-rh1726638-3.patch
@@ -0,0 +1,49 @@
+commit 30ba0375464f34e4bf8129f3d3dc14d0c09add17
+Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
+Date:   Tue Jul 9 12:11:39 2019 +0100
+
+    aarch64: simplify the DT_AARCH64_VARIANT_PCS handling code
+    
+    Remove unnecessary variant_pcs field: the dynamic tag can be checked
+    directly.
+    
+            * sysdeps/aarch64/dl-machine.h (elf_machine_runtime_setup): Remove the
+            DT_AARCH64_VARIANT_PCS check.
+            (elf_machine_lazy_rel): Use l_info[DT_AARCH64 (VARIANT_PCS)].
+            * sysdeps/aarch64/linkmap.h (struct link_map_machine): Remove
+            variant_pcs.
+
+diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
+index d4494852b32b8783..b39eae4acf4086ee 100644
+--- a/sysdeps/aarch64/dl-machine.h
++++ b/sysdeps/aarch64/dl-machine.h
+@@ -105,10 +105,6 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
+ 	}
+     }
+ 
+-  /* Check if STO_AARCH64_VARIANT_PCS needs to be handled.  */
+-  if (l->l_info[DT_AARCH64 (VARIANT_PCS)])
+-    l->l_mach.variant_pcs = 1;
+-
+   return lazy;
+ }
+ 
+@@ -402,7 +398,7 @@ elf_machine_lazy_rel (struct link_map *map,
+ 	  return;
+ 	}
+ 
+-      if (__glibc_unlikely (map->l_mach.variant_pcs))
++      if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL))
+ 	{
+ 	  /* Check the symbol table for variant PCS symbols.  */
+ 	  const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
+diff --git a/sysdeps/aarch64/linkmap.h b/sysdeps/aarch64/linkmap.h
+index dd8597470c3d2174..6852f343a1efd150 100644
+--- a/sysdeps/aarch64/linkmap.h
++++ b/sysdeps/aarch64/linkmap.h
+@@ -20,5 +20,4 @@ struct link_map_machine
+ {
+   ElfW(Addr) plt;	  /* Address of .plt */
+   void *tlsdesc_table;	  /* Address of TLS descriptor hash table.  */
+-  int variant_pcs;	  /* If set, PLT calls may follow a variant PCS.  */
+ };
diff --git a/SOURCES/glibc-rh1735747-1.patch b/SOURCES/glibc-rh1735747-1.patch
new file mode 100644
index 0000000..04c4136
--- /dev/null
+++ b/SOURCES/glibc-rh1735747-1.patch
@@ -0,0 +1,25 @@
+commit 6d750b18999b52ec74102c046cd27181f943bda8
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Aug 1 14:06:24 2019 +0200
+
+    malloc: Remove unwanted leading whitespace in malloc_info [BZ #24867]
+    
+    It was introduced in commit 6c8dbf00f536d78b1937b5af6f57be47fd376344
+    ("Reformat malloc to gnu style.").
+    
+    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+    (cherry picked from commit b0f6679bcd738ea244a14acd879d974901e56c8e)
+
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index e6a483d5cf7c4312..4fc7f175fe42d6c6 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -5518,7 +5518,7 @@ __malloc_info (int options, FILE *fp)
+ 
+       for (size_t i = 0; i < nsizes; ++i)
+ 	if (sizes[i].count != 0 && i != NFASTBINS)
+-	  fprintf (fp, "							      \
++	  fprintf (fp, "\
+   <size from=\"%zu\" to=\"%zu\" total=\"%zu\" count=\"%zu\"/>\n",
+ 		   sizes[i].from, sizes[i].to, sizes[i].total, sizes[i].count);
+ 
diff --git a/SOURCES/glibc-rh1735747-2.patch b/SOURCES/glibc-rh1735747-2.patch
new file mode 100644
index 0000000..e2afd28
--- /dev/null
+++ b/SOURCES/glibc-rh1735747-2.patch
@@ -0,0 +1,35 @@
+commit 91d5989356325759503311df67e750b358ef4148
+Author: Niklas Hambüchen <mail@nh2.me>
+Date:   Thu Aug 8 22:02:27 2019 +0200
+
+    malloc: Fix missing accounting of top chunk in malloc_info [BZ #24026]
+    
+    Fixes `<total type="rest" size="..."> incorrectly showing as 0 most
+    of the time.
+    
+    The rest value being wrong is significant because to compute the
+    actual amount of memory handed out via malloc, the user must subtract
+    it from <system type="current" size="...">. That result being wrong
+    makes investigating memory fragmentation issues like
+    <https://bugzilla.redhat.com/show_bug.cgi?id=843478> close to
+    impossible.
+    
+    (cherry picked from commit b6d2c4475d5abc05dd009575b90556bdd3c78ad0)
+
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index 4fc7f175fe42d6c6..fcf480acdaea1b86 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -5433,6 +5433,12 @@ __malloc_info (int options, FILE *fp)
+ 
+       __libc_lock_lock (ar_ptr->mutex);
+ 
++      /* Account for top chunk.  The top-most available chunk is
++	 treated specially and is never in any bin. See "initial_top"
++	 comments.  */
++      avail = chunksize (ar_ptr->top);
++      nblocks = 1;  /* Top always exists.  */
++
+       for (size_t i = 0; i < NFASTBINS; ++i)
+ 	{
+ 	  mchunkptr p = fastbin (ar_ptr, i);
diff --git a/SOURCES/glibc-rh1746928.patch b/SOURCES/glibc-rh1746928.patch
new file mode 100644
index 0000000..c21eb1d
--- /dev/null
+++ b/SOURCES/glibc-rh1746928.patch
@@ -0,0 +1,117 @@
+commit 669ff911e2571f74a2668493e326ac9a505776bd
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Fri Feb 8 12:46:19 2019 +0100
+
+    nptl: Avoid fork handler lock for async-signal-safe fork [BZ #24161]
+    
+    Commit 27761a1042daf01987e7d79636d0c41511c6df3c ("Refactor atfork
+    handlers") introduced a lock, atfork_lock, around fork handler list
+    accesses.  It turns out that this lock occasionally results in
+    self-deadlocks in malloc/tst-mallocfork2:
+    
+    (gdb) bt
+    #0  __lll_lock_wait_private ()
+        at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:63
+    #1  0x00007f160c6f927a in __run_fork_handlers (who=(unknown: 209394016),
+        who@entry=atfork_run_prepare) at register-atfork.c:116
+    #2  0x00007f160c6b7897 in __libc_fork () at ../sysdeps/nptl/fork.c:58
+    #3  0x00000000004027d6 in sigusr1_handler (signo=<optimized out>)
+        at tst-mallocfork2.c:80
+    #4  sigusr1_handler (signo=<optimized out>) at tst-mallocfork2.c:64
+    #5  <signal handler called>
+    #6  0x00007f160c6f92e4 in __run_fork_handlers (who=who@entry=atfork_run_parent)
+        at register-atfork.c:136
+    #7  0x00007f160c6b79a2 in __libc_fork () at ../sysdeps/nptl/fork.c:152
+    #8  0x0000000000402567 in do_test () at tst-mallocfork2.c:156
+    #9  0x0000000000402dd2 in support_test_main (argc=1, argv=0x7ffc81ef1ab0,
+        config=config@entry=0x7ffc81ef1970) at support_test_main.c:350
+    #10 0x0000000000402362 in main (argc=<optimized out>, argv=<optimized out>)
+        at ../support/test-driver.c:168
+    
+    If no locking happens in the single-threaded case (where fork is
+    expected to be async-signal-safe), this deadlock is avoided.
+    (pthread_atfork is not required to be async-signal-safe, so a fork
+    call from a signal handler interrupting pthread_atfork is not
+    a problem.)
+
+diff --git a/nptl/register-atfork.c b/nptl/register-atfork.c
+index bc797b7..80a1bec 100644
+--- a/nptl/register-atfork.c
++++ b/nptl/register-atfork.c
+@@ -107,13 +107,14 @@ __unregister_atfork (void *dso_handle)
+ }
+ 
+ void
+-__run_fork_handlers (enum __run_fork_handler_type who)
++__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking)
+ {
+   struct fork_handler *runp;
+ 
+   if (who == atfork_run_prepare)
+     {
+-      lll_lock (atfork_lock, LLL_PRIVATE);
++      if (do_locking)
++	lll_lock (atfork_lock, LLL_PRIVATE);
+       size_t sl = fork_handler_list_size (&fork_handlers);
+       for (size_t i = sl; i > 0; i--)
+ 	{
+@@ -133,7 +134,8 @@ __run_fork_handlers (enum __run_fork_handler_type who)
+ 	  else if (who == atfork_run_parent && runp->parent_handler)
+ 	    runp->parent_handler ();
+ 	}
+-      lll_unlock (atfork_lock, LLL_PRIVATE);
++      if (do_locking)
++	lll_unlock (atfork_lock, LLL_PRIVATE);
+     }
+ }
+ 
+diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
+index bd68f18..14b69a6 100644
+--- a/sysdeps/nptl/fork.c
++++ b/sysdeps/nptl/fork.c
+@@ -55,7 +55,7 @@ __libc_fork (void)
+      but our current fork implementation is not.  */
+   bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads);
+ 
+-  __run_fork_handlers (atfork_run_prepare);
++  __run_fork_handlers (atfork_run_prepare, multiple_threads);
+ 
+   /* If we are not running multiple threads, we do not have to
+      preserve lock state.  If fork runs from a signal handler, only
+@@ -134,7 +134,7 @@ __libc_fork (void)
+       __rtld_lock_initialize (GL(dl_load_lock));
+ 
+       /* Run the handlers registered for the child.  */
+-      __run_fork_handlers (atfork_run_child);
++      __run_fork_handlers (atfork_run_child, multiple_threads);
+     }
+   else
+     {
+@@ -149,7 +149,7 @@ __libc_fork (void)
+ 	}
+ 
+       /* Run the handlers registered for the parent.  */
+-      __run_fork_handlers (atfork_run_parent);
++      __run_fork_handlers (atfork_run_parent, multiple_threads);
+     }
+ 
+   return pid;
+diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h
+index a1c3b26..99ed760 100644
+--- a/sysdeps/nptl/fork.h
++++ b/sysdeps/nptl/fork.h
+@@ -52,9 +52,11 @@ enum __run_fork_handler_type
+    - atfork_run_child: run all the CHILD_HANDLER and unlocks the internal
+ 		       lock.
+    - atfork_run_parent: run all the PARENT_HANDLER and unlocks the internal
+-			lock.  */
+-extern void __run_fork_handlers (enum __run_fork_handler_type who)
+-  attribute_hidden;
++			lock.
++
++   Perform locking only if DO_LOCKING.  */
++extern void __run_fork_handlers (enum __run_fork_handler_type who,
++				 _Bool do_locking) attribute_hidden;
+ 
+ /* C library side function to register new fork handlers.  */
+ extern int __register_atfork (void (*__prepare) (void),
diff --git a/SOURCES/glibc-rh1746933-1.patch b/SOURCES/glibc-rh1746933-1.patch
new file mode 100644
index 0000000..4697916
--- /dev/null
+++ b/SOURCES/glibc-rh1746933-1.patch
@@ -0,0 +1,60 @@
+commit 58d2672f64176fcb323859d3bd5240fb1cf8f25c
+Author: Wilco Dijkstra <wdijkstr@arm.com>
+Date:   Fri May 10 16:38:21 2019 +0100
+
+    Fix tcache count maximum (BZ #24531)
+    
+    The tcache counts[] array is a char, which has a very small range and thus
+    may overflow.  When setting tcache_count tunable, there is no overflow check.
+    However the tunable must not be larger than the maximum value of the tcache
+    counts[] array, otherwise it can overflow when filling the tcache.
+    
+            [BZ #24531]
+            * malloc/malloc.c (MAX_TCACHE_COUNT): New define.
+            (do_set_tcache_count): Only update if count is small enough.
+            * manual/tunables.texi (glibc.malloc.tcache_count): Document max value.
+    
+    (cherry picked from commit 5ad533e8e65092be962e414e0417112c65d154fb)
+
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index 723d393f529bdb4c..92239b3324584060 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -2919,6 +2919,8 @@ typedef struct tcache_perthread_struct
+   tcache_entry *entries[TCACHE_MAX_BINS];
+ } tcache_perthread_struct;
+ 
++#define MAX_TCACHE_COUNT 127	/* Maximum value of counts[] entries.  */
++
+ static __thread bool tcache_shutting_down = false;
+ static __thread tcache_perthread_struct *tcache = NULL;
+ 
+@@ -5124,8 +5126,11 @@ static inline int
+ __always_inline
+ do_set_tcache_count (size_t value)
+ {
+-  LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
+-  mp_.tcache_count = value;
++  if (value <= MAX_TCACHE_COUNT)
++    {
++      LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
++      mp_.tcache_count = value;
++    }
+   return 1;
+ }
+ 
+diff --git a/manual/tunables.texi b/manual/tunables.texi
+index bb4819bdf1de273e..9dccf2ee7f8eec17 100644
+--- a/manual/tunables.texi
++++ b/manual/tunables.texi
+@@ -188,8 +188,8 @@ per-thread cache.  The default (and maximum) value is 1032 bytes on
+ 
+ @deftp Tunable glibc.malloc.tcache_count
+ The maximum number of chunks of each size to cache. The default is 7.
+-There is no upper limit, other than available system memory.  If set
+-to zero, the per-thread cache is effectively disabled.
++The upper limit is 127.  If set to zero, the per-thread cache is effectively
++disabled.
+ 
+ The approximate maximum overhead of the per-thread cache is thus equal
+ to the number of bins times the chunk count in each bin times the size
diff --git a/SOURCES/glibc-rh1746933-2.patch b/SOURCES/glibc-rh1746933-2.patch
new file mode 100644
index 0000000..97fc261
--- /dev/null
+++ b/SOURCES/glibc-rh1746933-2.patch
@@ -0,0 +1,37 @@
+commit 3640758943c856268bc12a3307838c2a65d2f9ea
+Author: Joseph Myers <joseph@codesourcery.com>
+Date:   Mon Feb 4 23:46:58 2019 +0000
+
+    Fix assertion in malloc.c:tcache_get.
+    
+    One of the warnings that appears with -Wextra is "ordered comparison
+    of pointer with integer zero" in malloc.c:tcache_get, for the
+    assertion:
+    
+      assert (tcache->entries[tc_idx] > 0);
+    
+    Indeed, a "> 0" comparison does not make sense for
+    tcache->entries[tc_idx], which is a pointer.  My guess is that
+    tcache->counts[tc_idx] is what's intended here, and this patch changes
+    the assertion accordingly.
+    
+    Tested for x86_64.
+    
+            * malloc/malloc.c (tcache_get): Compare tcache->counts[tc_idx]
+            with 0, not tcache->entries[tc_idx].
+    
+    (cherry picked from commit 77dc0d8643aa99c92bf671352b0a8adde705896f)
+
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index 92239b3324584060..998879aededf0d7c 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -2948,7 +2948,7 @@ tcache_get (size_t tc_idx)
+ {
+   tcache_entry *e = tcache->entries[tc_idx];
+   assert (tc_idx < TCACHE_MAX_BINS);
+-  assert (tcache->entries[tc_idx] > 0);
++  assert (tcache->counts[tc_idx] > 0);
+   tcache->entries[tc_idx] = e->next;
+   --(tcache->counts[tc_idx]);
+   e->key = NULL;
diff --git a/SOURCES/glibc-rh1746933-3.patch b/SOURCES/glibc-rh1746933-3.patch
new file mode 100644
index 0000000..f4c1c95
--- /dev/null
+++ b/SOURCES/glibc-rh1746933-3.patch
@@ -0,0 +1,92 @@
+commit f88c59f4657ac2e0bab8f51f60022ecbe7f12e2e
+Author: Wilco Dijkstra <wdijkstr@arm.com>
+Date:   Fri May 17 18:16:20 2019 +0100
+
+    Small tcache improvements
+    
+    Change the tcache->counts[] entries to uint16_t - this removes
+    the limit set by char and allows a larger tcache.  Remove a few
+    redundant asserts.
+    
+    bench-malloc-thread with 4 threads is ~15% faster on Cortex-A72.
+    
+    Reviewed-by: DJ Delorie <dj@redhat.com>
+    
+            * malloc/malloc.c (MAX_TCACHE_COUNT): Increase to UINT16_MAX.
+            (tcache_put): Remove redundant assert.
+            (tcache_get): Remove redundant asserts.
+            (__libc_malloc): Check tcache count is not zero.
+            * manual/tunables.texi (glibc.malloc.tcache_count): Update maximum.
+    
+    (cherry picked from commit 1f50f2ad854c84ead522bfc7331b46dbe6057d53)
+
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index 998879aededf0d7c..e6a483d5cf7c4312 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -321,6 +321,10 @@ __malloc_assert (const char *assertion, const char *file, unsigned int line,
+ /* This is another arbitrary limit, which tunables can change.  Each
+    tcache bin will hold at most this number of chunks.  */
+ # define TCACHE_FILL_COUNT 7
++
++/* Maximum chunks in tcache bins for tunables.  This value must fit the range
++   of tcache->counts[] entries, else they may overflow.  */
++# define MAX_TCACHE_COUNT UINT16_MAX
+ #endif
+ 
+ 
+@@ -2915,12 +2919,10 @@ typedef struct tcache_entry
+    time), this is for performance reasons.  */
+ typedef struct tcache_perthread_struct
+ {
+-  char counts[TCACHE_MAX_BINS];
++  uint16_t counts[TCACHE_MAX_BINS];
+   tcache_entry *entries[TCACHE_MAX_BINS];
+ } tcache_perthread_struct;
+ 
+-#define MAX_TCACHE_COUNT 127	/* Maximum value of counts[] entries.  */
+-
+ static __thread bool tcache_shutting_down = false;
+ static __thread tcache_perthread_struct *tcache = NULL;
+ 
+@@ -2930,7 +2932,6 @@ static __always_inline void
+ tcache_put (mchunkptr chunk, size_t tc_idx)
+ {
+   tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
+-  assert (tc_idx < TCACHE_MAX_BINS);
+ 
+   /* Mark this chunk as "in the tcache" so the test in _int_free will
+      detect a double free.  */
+@@ -2947,8 +2948,6 @@ static __always_inline void *
+ tcache_get (size_t tc_idx)
+ {
+   tcache_entry *e = tcache->entries[tc_idx];
+-  assert (tc_idx < TCACHE_MAX_BINS);
+-  assert (tcache->counts[tc_idx] > 0);
+   tcache->entries[tc_idx] = e->next;
+   --(tcache->counts[tc_idx]);
+   e->key = NULL;
+@@ -3053,9 +3052,8 @@ __libc_malloc (size_t bytes)
+ 
+   DIAG_PUSH_NEEDS_COMMENT;
+   if (tc_idx < mp_.tcache_bins
+-      /*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */
+       && tcache
+-      && tcache->entries[tc_idx] != NULL)
++      && tcache->counts[tc_idx] > 0)
+     {
+       return tcache_get (tc_idx);
+     }
+diff --git a/manual/tunables.texi b/manual/tunables.texi
+index 9dccf2ee7f8eec17..f6c49250e3889ddd 100644
+--- a/manual/tunables.texi
++++ b/manual/tunables.texi
+@@ -188,7 +188,7 @@ per-thread cache.  The default (and maximum) value is 1032 bytes on
+ 
+ @deftp Tunable glibc.malloc.tcache_count
+ The maximum number of chunks of each size to cache. The default is 7.
+-The upper limit is 127.  If set to zero, the per-thread cache is effectively
++The upper limit is 65535.  If set to zero, the per-thread cache is effectively
+ disabled.
+ 
+ The approximate maximum overhead of the per-thread cache is thus equal
diff --git a/SOURCES/glibc-rh1747453.patch b/SOURCES/glibc-rh1747453.patch
new file mode 100644
index 0000000..d02b6b2
--- /dev/null
+++ b/SOURCES/glibc-rh1747453.patch
@@ -0,0 +1,156 @@
+commit 8692ebdb1259be60c545fa509d4852b26703777e
+Author: David Newall <glibc@davidnewall.com>
+Date:   Mon Feb 4 13:35:11 2019 +0100
+
+    elf: Implement --preload option for the dynamic linker
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 9cf5cd8dfd..db6a2a0c29 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -354,7 +354,8 @@ endif
+ 
+ ifeq (yes,$(build-shared))
+ ifeq ($(run-built-tests),yes)
+-tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out
++tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out \
++		 $(objpfx)tst-rtld-preload.out
+ endif
+ tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \
+ 		 $(objpfx)check-localplt.out $(objpfx)check-initfini.out
+@@ -883,6 +884,15 @@ $(objpfx)tst-rtld-load-self.out: tst-rtld-load-self.sh $(objpfx)ld.so
+ 	$(SHELL) $^ '$(test-wrapper)' '$(test-wrapper-env)' > $@; \
+ 	$(evaluate-test)
+ 
++tst-rtld-preload-OBJS = $(subst $(empty) ,:,$(strip $(preloadtest-preloads:=.so)))
++$(objpfx)tst-rtld-preload.out: tst-rtld-preload.sh $(objpfx)ld.so \
++			       $(objpfx)preloadtest \
++			       $(preloadtest-preloads:%=$(objpfx)%.so)
++	$(SHELL) $< $(objpfx)ld.so $(objpfx)preloadtest \
++		    '$(test-wrapper)' '$(test-wrapper-env)' '$(run_program_env)' \
++		    '$(rpath-link)' '$(tst-rtld-preload-OBJS)' > $@; \
++	$(evaluate-test)
++
+ $(objpfx)initfirst: $(libdl)
+ $(objpfx)initfirst.out: $(objpfx)firstobj.so
+ 
+diff --git a/elf/rtld.c b/elf/rtld.c
+index 5d97f41b7b..5a90e78ed6 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -826,15 +826,18 @@ static const char *library_path attribute_relro;
+ static const char *preloadlist attribute_relro;
+ /* Nonzero if information about versions has to be printed.  */
+ static int version_info attribute_relro;
++/* The preload list passed as a command argument.  */
++static const char *preloadarg attribute_relro;
+ 
+ /* The LD_PRELOAD environment variable gives list of libraries
+    separated by white space or colons that are loaded before the
+    executable's dependencies and prepended to the global scope list.
+    (If the binary is running setuid all elements containing a '/' are
+    ignored since it is insecure.)  Return the number of preloads
+-   performed.  */
++   performed.   Ditto for --preload command argument.  */
+ unsigned int
+-handle_ld_preload (const char *preloadlist, struct link_map *main_map)
++handle_preload_list (const char *preloadlist, struct link_map *main_map,
++		     const char *where)
+ {
+   unsigned int npreloads = 0;
+   const char *p = preloadlist;
+@@ -858,7 +861,7 @@ handle_ld_preload (const char *preloadlist, struct link_map *main_map)
+ 	++p;
+ 
+       if (dso_name_valid_for_suid (fname))
+-	npreloads += do_preload (fname, main_map, "LD_PRELOAD");
++	npreloads += do_preload (fname, main_map, where);
+     }
+   return npreloads;
+ }
+@@ -974,6 +977,13 @@ dl_main (const ElfW(Phdr) *phdr,
+ 	  {
+ 	    process_dl_audit (_dl_argv[2]);
+ 
++	    _dl_skip_args += 2;
++	    _dl_argc -= 2;
++	    _dl_argv += 2;
++	  }
++	else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2)
++	  {
++	    preloadarg = _dl_argv[2];
+ 	    _dl_skip_args += 2;
+ 	    _dl_argc -= 2;
+ 	    _dl_argv += 2;
+@@ -1006,7 +1016,8 @@ of this helper program; chances are you did not intend to run this program.\n\
+ 			variable LD_LIBRARY_PATH\n\
+   --inhibit-rpath LIST  ignore RUNPATH and RPATH information in object names\n\
+ 			in LIST\n\
+-  --audit LIST          use objects named in LIST as auditors\n");
++  --audit LIST          use objects named in LIST as auditors\n\
++  --preload LIST        preload objects named in LIST\n");
+ 
+       ++_dl_skip_args;
+       --_dl_argc;
+@@ -1620,7 +1631,16 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+   if (__glibc_unlikely (preloadlist != NULL))
+     {
+       HP_TIMING_NOW (start);
+-      npreloads += handle_ld_preload (preloadlist, main_map);
++      npreloads += handle_preload_list (preloadlist, main_map, "LD_PRELOAD");
++      HP_TIMING_NOW (stop);
++      HP_TIMING_DIFF (diff, start, stop);
++      HP_TIMING_ACCUM_NT (load_time, diff);
++    }
++
++  if (__glibc_unlikely (preloadarg != NULL))
++    {
++      HP_TIMING_NOW (start);
++      npreloads += handle_preload_list (preloadarg, main_map, "--preload");
+       HP_TIMING_NOW (stop);
+       HP_TIMING_DIFF (diff, start, stop);
+       HP_TIMING_ACCUM_NT (load_time, diff);
+diff --git a/elf/tst-rtld-preload.sh b/elf/tst-rtld-preload.sh
+new file mode 100755
+index 0000000000..f0c0ca11ba
+--- /dev/null
++++ b/elf/tst-rtld-preload.sh
+@@ -0,0 +1,38 @@
++#!/bin/sh
++# Test --preload argument ld.so.
++# Copyright (C) 2019 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
++# <http://www.gnu.org/licenses/>.
++
++set -e
++
++rtld=$1
++test_program=$2
++test_wrapper=$3
++test_wrapper_env=$4
++run_program_env=$5
++library_path=$6
++preload=$7
++
++echo "# [${test_wrapper}] [$rtld] [--library-path] [$library_path]" \
++     "[--preload] [$preload] [$test_program]"
++${test_wrapper_env} \
++${run_program_env} \
++${test_wrapper} $rtld --library-path "$library_path" \
++  --preload "$preload" $test_program 2>&1 && rc=0 || rc=$?
++echo "# exit status $rc"
++
++exit $rc
diff --git a/SOURCES/glibc-rh1747502-1.patch b/SOURCES/glibc-rh1747502-1.patch
new file mode 100644
index 0000000..b57f046
--- /dev/null
+++ b/SOURCES/glibc-rh1747502-1.patch
@@ -0,0 +1,168 @@
+commit 561b0bec4448f0302cb4915bf67c919bde4a1c57
+Author: DJ Delorie <dj@redhat.com>
+Date:   Fri Jul 6 01:10:41 2018 -0400
+
+    Add test-in-container infrastructure.
+    
+    * Makefile (testroot.pristine): New rules to initialize the
+    test-in-container "testroot".
+    * Makerules (all-testsuite): Add tests-container.
+    * Rules (tests-expected): Add tests-container.
+    (binaries-all-tests): Likewise.
+    (tests-container): New, run these tests in the testroot container.
+    * support/links-dso-program-c.c: New.
+    * support/links-dso-program.cc: New.
+    * support/test-container.c: New.
+    * support/shell-container.c: New.
+    * support/echo-container.c: New.
+    * support/true-container.c: New.
+    * support/xmkdirp.c: New.
+    * support/xsymlink.c: New.
+    * support/support_paths.c: New.
+    * support/support.h: Add support paths prototypes.
+    * support/xunistd.h: Add xmkdirp () and xsymlink ().
+    
+    * nss/tst-nss-test3.c: Convert to test-in-container.
+    * nss/tst-nss-test3.root/: New.
+
+(note: support/ already present, not needed; sample test not included)
+
+diff --git a/Makefile b/Makefile
+index d3f25a5..3df55e6 100644
+--- a/Makefile
++++ b/Makefile
+@@ -340,6 +340,62 @@ define summarize-tests
+ @! egrep -q -v '^(X?PASS|XFAIL|UNSUPPORTED):' $(objpfx)$1
+ endef
+ 
++# The intention here is to do ONE install of our build into the
++# testroot.pristine/ directory, then rsync (internal to
++# support/test-container) that to testroot.root/ at the start of each
++# test.  That way we can promise each test a "clean" install, without
++# having to do the install for each test.
++#
++# In addition, we have to copy some files (which we build) into this
++# root in addition to what glibc installs.  For example, many tests
++# require additional programs including /bin/sh, /bin/true, and
++# /bin/echo, all of which we build below to limit library dependencies
++# to just those things in glibc and language support libraries which
++# we also copy into the into the rootfs.  To determine what language
++# support libraries we need we build a "test" program in either C or
++# (if available) C++ just so we can copy in any shared objects
++# (which we do not build) that GCC-compiled programs depend on.
++
++
++ifeq (,$(CXX))
++LINKS_DSO_PROGRAM = links-dso-program-c
++else
++LINKS_DSO_PROGRAM = links-dso-program
++endif
++
++$(tests-container) $(addsuffix /tests,$(subdirs)) : \
++		$(objpfx)testroot.pristine/install.stamp
++$(objpfx)testroot.pristine/install.stamp :
++	test -d $(objpfx)testroot.pristine || \
++	  mkdir $(objpfx)testroot.pristine
++	# We need a working /bin/sh for some of the tests.
++	test -d $(objpfx)testroot.pristine/bin || \
++	  mkdir $(objpfx)testroot.pristine/bin
++	cp $(objpfx)support/shell-container $(objpfx)testroot.pristine/bin/sh
++	cp $(objpfx)support/echo-container $(objpfx)testroot.pristine/bin/echo
++	cp $(objpfx)support/true-container $(objpfx)testroot.pristine/bin/true
++	# Copy these DSOs first so we can overwrite them with our own.
++	for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1  \
++		$(objpfx)elf/$(rtld-installed-name) \
++		$(objpfx)testroot.pristine/bin/sh \
++	        | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\
++	  do \
++	    test -d `dirname $(objpfx)testroot.pristine$$dso` || \
++	      mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\
++	    $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\
++	  done
++	for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1  \
++		$(objpfx)elf/$(rtld-installed-name) \
++		$(objpfx)support/$(LINKS_DSO_PROGRAM) \
++	        | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\
++	  do \
++	    test -d `dirname $(objpfx)testroot.pristine$$dso` || \
++	      mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\
++	    $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\
++	  done
++	$(MAKE) install DESTDIR=$(objpfx)testroot.pristine
++	touch $(objpfx)testroot.pristine/install.stamp
++
+ tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special))
+ tests: $(tests-special)
+ 	$(..)scripts/merge-test-results.sh -s $(objpfx) "" \
+diff --git a/Makerules b/Makerules
+index a10a0b4..5d6434c 100644
+--- a/Makerules
++++ b/Makerules
+@@ -1369,7 +1369,8 @@ xcheck: xtests
+ # The only difference between MODULE_NAME=testsuite and MODULE_NAME=nonlib is
+ # that almost all internal declarations from config.h, libc-symbols.h, and
+ # include/*.h are not available to 'testsuite' code, but are to 'nonlib' code.
+-all-testsuite := $(strip $(tests) $(xtests) $(test-srcs) $(test-extras))
++all-testsuite := $(strip $(tests) $(xtests) $(test-srcs) $(test-extras) \
++		 $(tests-container))
+ ifneq (,$(all-testsuite))
+ cpp-srcs-left = $(all-testsuite)
+ lib := testsuite
+diff --git a/Rules b/Rules
+index 706c8a7..5abb727 100644
+--- a/Rules
++++ b/Rules
+@@ -130,12 +130,14 @@ others: $(py-const)
+ 
+ ifeq ($(run-built-tests),no)
+ tests: $(addprefix $(objpfx),$(filter-out $(tests-unsupported), \
+-                                          $(tests) $(tests-internal)) \
++                                          $(tests) $(tests-internal) \
++					  $(tests-container)) \
+ 			     $(test-srcs)) $(tests-special) \
+ 			     $(tests-printers-programs)
+ xtests: tests $(xtests-special)
+ else
+ tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \
++       $(tests-container:%=$(objpfx)%.out) \
+        $(tests-special) $(tests-printers-out)
+ xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special)
+ endif
+@@ -145,7 +147,8 @@ xtests-special-notdir = $(patsubst $(objpfx)%, %, $(xtests-special))
+ ifeq ($(run-built-tests),no)
+ tests-expected =
+ else
+-tests-expected = $(tests) $(tests-internal) $(tests-printers)
++tests-expected = $(tests) $(tests-internal) $(tests-printers) \
++	$(tests-container)
+ endif
+ tests:
+ 	$(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \
+@@ -158,7 +161,8 @@ xtests:
+ 
+ ifeq ($(build-programs),yes)
+ binaries-all-notests = $(others) $(sysdep-others)
+-binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs)
++binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs) \
++		     $(tests-container)
+ binaries-all = $(binaries-all-notests) $(binaries-all-tests)
+ binaries-static-notests = $(others-static)
+ binaries-static-tests = $(tests-static) $(xtests-static)
+@@ -248,6 +252,17 @@ $(objpfx)%.out: /dev/null $(objpfx)%	# Make it 2nd arg for canned sequence.
+ 	$(make-test-out) > $@; \
+ 	$(evaluate-test)
+ 
++
++# Any tests that require an isolated container (filesystem, network
++# and pid namespaces) in which to run, should be added to
++# tests-container.
++$(tests-container:%=$(objpfx)%.out): $(objpfx)%.out : $(if $(wildcard $(objpfx)%.files),$(objpfx)%.files,/dev/null) $(objpfx)%
++	$(test-wrapper-env) $(run-program-env) $(run-via-rtld-prefix) \
++	  $(common-objpfx)support/test-container env $(run-program-env) $($*-ENV) \
++	  $(host-test-program-cmd) $($*-ARGS) > $@; \
++	$(evaluate-test)
++
++
+ # tests-unsupported lists tests that we will not try to build at all in
+ # this configuration.  Note this runs every time because it does not
+ # actually create its target.  The dependency on Makefile is meant to
diff --git a/SOURCES/glibc-rh1747502-2.patch b/SOURCES/glibc-rh1747502-2.patch
new file mode 100644
index 0000000..17a53e1
--- /dev/null
+++ b/SOURCES/glibc-rh1747502-2.patch
@@ -0,0 +1,48 @@
+commit bd598da9f454bc1091b4ebe0303b07e6f96ca130
+Author: Joseph Myers <joseph@codesourcery.com>
+Date:   Tue Dec 4 16:52:39 2018 +0000
+
+    Stop test-in-container trying to run other-OS binaries.
+    
+    I noticed that, now that build-many-glibcs.py no longer copies glibc
+    sources, I was getting core dumps in my glibc source directories.  The
+    cause appears to be, from the i686-gnu build:
+    
+    for dso in ` env LD_TRACE_LOADED_OBJECTS=1  \
+            /scratch/jmyers/glibc-bot/build/glibcs/i686-gnu/glibc/elf/ld.so.1 \
+            /scratch/jmyers/glibc-bot/build/glibcs/i686-gnu/glibc/testroot.pristine/bin/sh \
+    [...]
+    Segmentation fault (core dumped)
+    
+    In this case, the x86 architecture means the binary executes, but
+    dumps core rather than actually working.
+    
+    Anything involving running the newly built glibc should only be done
+    ifeq ($(run-built-tests),yes).  This patch conditions the relevant
+    part of the testroot setup accordingly.
+    
+    Tested for x86_64, and with build-many-glibcs.py for i686-gnu.
+    
+    	* Makefile ($(objpfx)testroot.pristine/install.stamp): Do not run
+    	dynamic linker unless [$(run-built-tests) = yes].
+
+diff --git a/Makefile b/Makefile
+index b4703e4..fd73d9b 100644
+--- a/Makefile
++++ b/Makefile
+@@ -374,6 +374,7 @@ $(objpfx)testroot.pristine/install.stamp :
+ 	cp $(objpfx)support/shell-container $(objpfx)testroot.pristine/bin/sh
+ 	cp $(objpfx)support/echo-container $(objpfx)testroot.pristine/bin/echo
+ 	cp $(objpfx)support/true-container $(objpfx)testroot.pristine/bin/true
++ifeq ($(run-built-tests),yes)
+ 	# Copy these DSOs first so we can overwrite them with our own.
+ 	for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1  \
+ 		$(objpfx)elf/$(rtld-installed-name) \
+@@ -393,6 +394,7 @@ $(objpfx)testroot.pristine/install.stamp :
+ 	      mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\
+ 	    $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\
+ 	  done
++endif
+ 	$(MAKE) install DESTDIR=$(objpfx)testroot.pristine
+ 	touch $(objpfx)testroot.pristine/install.stamp
+ 
diff --git a/SOURCES/glibc-rh1747502-3.patch b/SOURCES/glibc-rh1747502-3.patch
new file mode 100644
index 0000000..f0c5027
--- /dev/null
+++ b/SOURCES/glibc-rh1747502-3.patch
@@ -0,0 +1,40 @@
+commit 95da14dac04b494149290d85bc5306226e30839e
+Author: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
+Date:   Mon Jul 22 16:30:45 2019 -0300
+
+    test-container: Avoid copying unintended system libraries
+    
+    Some DSOs are distributed in hardware capability directories, e.g.
+    /usr/lib64/power7/libc.so.6
+    Whenever the processor is able to use one of these hardware-enabled
+    DSOs, testroot.pristine ends up with copies of glibc-provided libraries
+    from the system because it can't overwrite or remove them.
+    
+    This patch avoids the unintended copies by executing ld.so with the same
+    arguments passed to each glibc test.
+    
+    	* Makefile (testroot.pristine/install.stamp): Execute ld.so with
+    	the same arguments used in all tests.
+
+diff --git a/Makefile b/Makefile
+index dc5de7a..a4ed747 100644
+--- a/Makefile
++++ b/Makefile
+@@ -383,7 +383,7 @@ $(objpfx)testroot.pristine/install.stamp :
+ ifeq ($(run-built-tests),yes)
+ 	# Copy these DSOs first so we can overwrite them with our own.
+ 	for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1  \
+-		$(objpfx)elf/$(rtld-installed-name) \
++		$(rtld-prefix) \
+ 		$(objpfx)testroot.pristine/bin/sh \
+ 	        | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\
+ 	  do \
+@@ -392,7 +392,7 @@ ifeq ($(run-built-tests),yes)
+ 	    $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\
+ 	  done
+ 	for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1  \
+-		$(objpfx)elf/$(rtld-installed-name) \
++		$(rtld-prefix) \
+ 		$(objpfx)support/$(LINKS_DSO_PROGRAM) \
+ 	        | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\
+ 	  do \
diff --git a/SOURCES/glibc-rh1747502-4.patch b/SOURCES/glibc-rh1747502-4.patch
new file mode 100644
index 0000000..2e25309
--- /dev/null
+++ b/SOURCES/glibc-rh1747502-4.patch
@@ -0,0 +1,31 @@
+commit 35e038c1d2ccb3a75395662f9c4f28d85a61444f
+Author: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
+Date:   Mon Jul 22 17:34:13 2019 -0300
+
+    test-container: Install with $(all-subdirs) [BZ #24794]
+    
+    Whenever a sub-make is created, it inherits the variable subdirs from its
+    parent.  This is also true when make check is called with a restricted
+    list of subdirs.  In this scenario, make install is executed "partially"
+    and testroot.pristine ends up with an incomplete installation.
+    
+    	[BZ #24794]
+    	* Makefile (testroot.pristine/install.stamp): Pass
+    	subdirs='$(all-subdirs)' to make install.
+    
+    Reviewed-by: DJ Delorie <dj@redhat.com>
+
+diff --git a/Makefile b/Makefile
+index a4ed747..9fbf705 100644
+--- a/Makefile
++++ b/Makefile
+@@ -401,7 +401,8 @@ ifeq ($(run-built-tests),yes)
+ 	    $(test-wrapper) cp $$dso $(objpfx)testroot.pristine$$dso ;\
+ 	  done
+ endif
+-	$(MAKE) install DESTDIR=$(objpfx)testroot.pristine
++	$(MAKE) install DESTDIR=$(objpfx)testroot.pristine \
++	  subdirs='$(all-subdirs)'
+ 	touch $(objpfx)testroot.pristine/install.stamp
+ 
+ tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special))
diff --git a/SOURCES/glibc-rh1747502-5.patch b/SOURCES/glibc-rh1747502-5.patch
new file mode 100644
index 0000000..30dd75e
--- /dev/null
+++ b/SOURCES/glibc-rh1747502-5.patch
@@ -0,0 +1,56 @@
+commit 7db1fe38de21831d53ceab9ae83493d8d1aec601
+Author: Joseph Myers <joseph@codesourcery.com>
+Date:   Tue Oct 22 20:24:10 2019 +0000
+
+    Fix testroot.pristine creation copying dynamic linker.
+    
+    This patch addresses an issue reported in
+    <https://sourceware.org/ml/libc-alpha/2019-07/msg00661.html> where the
+    creation of testroot.pristine, on encountering
+    LD_TRACE_LOADED_OBJECTS=1 of the form
+    
+            libc.so.6 => /scratch/jmyers/glibc/mbs/obj/glibc-8-0-mips64-linux-gnu-x86_64-linux-gnu/default/libc.so.6 (0x772dd000)
+            /lib32/ld.so.1 => /scratch/jmyers/glibc/mbs/obj/glibc-8-0-mips64-linux-gnu-x86_64-linux-gnu/default/elf/ld.so.1 (0x7747b000)
+    
+    tries to copy /lib32/ld.so.1 (which does not exist) into the testroot
+    instead of copying the path on the RHS of "=>", which does exist,
+    because the Makefile logic assumes that the path on such a line with
+    '/' should be copied, when if there are such paths on both the LHS and
+    the RHS of "=>", only the one on the RHS necessarily exists and so
+    only that should be copied.  The patch follows the approach suggested
+    by DJ in <https://sourceware.org/ml/libc-alpha/2019-07/msg00662.html>,
+    with the suggestion from Andreas in
+    <https://sourceware.org/ml/libc-alpha/2019-10/msg00514.html> of a
+    single sed command in place of pipeline of grep and three sed
+    commands.
+    
+    Tested for x86_64, with and without --enable-hardcoded-path-in-tests;
+    a previous version with multiple sed commands, implementing the same
+    logic, also tested for MIPS, with and without
+    --enable-hardcoded-path-in-tests, to confirm it fixes the original
+    problem.
+    
+    Co-authored-by: DJ Delorie <dj@redhat.com>
+
+diff --git a/Makefile b/Makefile
+index d7e4be9..0711b97 100644
+--- a/Makefile
++++ b/Makefile
+@@ -564,7 +564,7 @@ ifeq ($(run-built-tests),yes)
+ 	for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1  \
+ 		$(rtld-prefix) \
+ 		$(objpfx)testroot.pristine/bin/sh \
+-	        | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\
++	        | sed -n '/\//{s@.*=> /@/@;s/^[^/]*//;s/ .*//p;}'` ;\
+ 	  do \
+ 	    test -d `dirname $(objpfx)testroot.pristine$$dso` || \
+ 	      mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\
+@@ -573,7 +573,7 @@ ifeq ($(run-built-tests),yes)
+ 	for dso in `$(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1  \
+ 		$(rtld-prefix) \
+ 		$(objpfx)support/$(LINKS_DSO_PROGRAM) \
+-	        | grep / | sed 's/^[^/]*//' | sed 's/ .*//'` ;\
++	        | sed -n '/\//{s@.*=> /@/@;s/^[^/]*//;s/ .*//p;}'` ;\
+ 	  do \
+ 	    test -d `dirname $(objpfx)testroot.pristine$$dso` || \
+ 	      mkdir -p `dirname $(objpfx)testroot.pristine$$dso` ;\
diff --git a/SOURCES/glibc-rh1747502-6.patch b/SOURCES/glibc-rh1747502-6.patch
new file mode 100644
index 0000000..c84940c
--- /dev/null
+++ b/SOURCES/glibc-rh1747502-6.patch
@@ -0,0 +1,56 @@
+commit c7ac9caaae6f8d02d4e0c7618d4991324a084c66
+Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
+Date:   Mon May 13 13:57:37 2019 -0300
+
+    support: Export bindir path on support_path
+    
+    Checked on x86_64-linux-gnu.
+    
+    	* support/Makefile (CFLAGS-support_paths.c): Add -DBINDIR_PATH.
+    	* support/support.h (support_bindir_prefix): New variable.
+    	* support/support_paths.c [BINDIR_PATH] (support_bindir_prefix):
+    
+    Reviewed-by: DJ Delorie <dj@redhat.com>
+
+diff --git a/support/Makefile b/support/Makefile
+index 64044f6..fe416cd 100644
+--- a/support/Makefile
++++ b/support/Makefile
+@@ -179,7 +179,8 @@ CFLAGS-support_paths.c = \
+ 		-DOBJDIR_PATH=\"`cd $(objpfx)/..; pwd`\" \
+ 		-DOBJDIR_ELF_LDSO_PATH=\"`cd $(objpfx)/..; pwd`/elf/$(rtld-installed-name)\" \
+ 		-DINSTDIR_PATH=\"$(prefix)\" \
+-		-DLIBDIR_PATH=\"$(libdir)\"
++		-DLIBDIR_PATH=\"$(libdir)\" \
++		-DBINDIR_PATH=\"$(bindir)\"
+ 
+ ifeq (,$(CXX))
+ LINKS_DSO_PROGRAM = links-dso-program-c
+diff --git a/support/support.h b/support/support.h
+index 97fef2c..b162491 100644
+--- a/support/support.h
++++ b/support/support.h
+@@ -105,6 +105,8 @@ extern const char support_objdir_elf_ldso[];
+ extern const char support_install_prefix[];
+ /* Corresponds to the install's lib/ or lib64/ directory.  */
+ extern const char support_libdir_prefix[];
++/* Corresponds to the install's bin/ directory.  */
++extern const char support_bindir_prefix[];
+ 
+ extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *,
+ 					size_t, unsigned int);
+diff --git a/support/support_paths.c b/support/support_paths.c
+index 937e6e1..75634aa 100644
+--- a/support/support_paths.c
++++ b/support/support_paths.c
+@@ -57,3 +57,10 @@ const char support_libdir_prefix[] = LIBDIR_PATH;
+ #else
+ # error please -DLIBDIR_PATH=something in the Makefile
+ #endif
++
++#ifdef BINDIR_PATH
++/* Corresponds to the install's bin/ directory.  */
++const char support_bindir_prefix[] = BINDIR_PATH;
++#else
++# error please -DBINDIR_PATH=something in the Makefile
++#endif
diff --git a/SOURCES/glibc-rh1747502-7.patch b/SOURCES/glibc-rh1747502-7.patch
new file mode 100644
index 0000000..fa6a63d
--- /dev/null
+++ b/SOURCES/glibc-rh1747502-7.patch
@@ -0,0 +1,46 @@
+From 354e4c1adddb1da19c1043e3e5db61ee2148d912 Mon Sep 17 00:00:00 2001
+From: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
+Date: Wed, 24 Jul 2019 19:49:00 -0300
+Subject: test-container: Install with $(sorted-subdirs) [BZ #24794]
+
+Commit 35e038c1d2ccb3a75395662f9c4f28d85a61444f started to use an
+incomplete list of subdirs based on $(all-subdirs) causing
+testroot.pristine to miss files from nss.
+
+Tested if the list of files in testroot.pristine remains the same.
+
+	[BZ #24794]
+	* Makeconfig (all-subdirs): Improved source comments.
+	* Makefile (testroot.pristine/install.stamp): Pass
+	subdirs='$(sorted-subdirs)' to make install.
+
+diff --git a/Makeconfig b/Makeconfig
+index 0e386fbc19..fd36c58c04 100644
+--- a/Makeconfig
++++ b/Makeconfig
+@@ -1267,9 +1267,9 @@ else
+ libsupport = $(common-objpfx)support/libsupport.a
+ endif
+ 
+-# These are the subdirectories containing the library source.  The order
+-# is more or less arbitrary.  The sorting step will take care of the
+-# dependencies.
++# This is a partial list of subdirectories containing the library source.
++# The order is more or less arbitrary.  The sorting step will take care of the
++# dependencies and generate sorted-subdirs dynamically.
+ all-subdirs = csu assert ctype locale intl catgets math setjmp signal	    \
+ 	      stdlib stdio-common libio malloc string wcsmbs time dirent    \
+ 	      grp pwd posix io termios resource misc socket sysvipc gmon    \
+diff --git a/Makefile b/Makefile
+index 9fbf705200..ac1125853b 100644
+--- a/Makefile
++++ b/Makefile
+@@ -402,7 +402,7 @@ ifeq ($(run-built-tests),yes)
+ 	  done
+ endif
+ 	$(MAKE) install DESTDIR=$(objpfx)testroot.pristine \
+-	  subdirs='$(all-subdirs)'
++	  subdirs='$(sorted-subdirs)'
+ 	touch $(objpfx)testroot.pristine/install.stamp
+ 
+ tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special))
diff --git a/SOURCES/glibc-rh1747502-8.patch b/SOURCES/glibc-rh1747502-8.patch
new file mode 100644
index 0000000..16f6bf7
--- /dev/null
+++ b/SOURCES/glibc-rh1747502-8.patch
@@ -0,0 +1,50 @@
+commit d50f09181eca10a91fd9035bb90711b265770dc9
+Author: Alexandra Hájková <ahajkova@redhat.com>
+Date:   Mon May 13 19:31:53 2019 +0200
+
+    support: Add support_install_rootsbindir
+    
+    Reviewed by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+diff --git a/support/Makefile b/support/Makefile
+index fe416cd..18d39f5 100644
+--- a/support/Makefile
++++ b/support/Makefile
+@@ -180,7 +180,8 @@ CFLAGS-support_paths.c = \
+ 		-DOBJDIR_ELF_LDSO_PATH=\"`cd $(objpfx)/..; pwd`/elf/$(rtld-installed-name)\" \
+ 		-DINSTDIR_PATH=\"$(prefix)\" \
+ 		-DLIBDIR_PATH=\"$(libdir)\" \
+-		-DBINDIR_PATH=\"$(bindir)\"
++		-DBINDIR_PATH=\"$(bindir)\" \
++		-DROOTSBINDIR_PATH=\"$(rootsbindir)\"
+ 
+ ifeq (,$(CXX))
+ LINKS_DSO_PROGRAM = links-dso-program-c
+diff --git a/support/support.h b/support/support.h
+index b162491..13076b7 100644
+--- a/support/support.h
++++ b/support/support.h
+@@ -107,6 +107,8 @@ extern const char support_install_prefix[];
+ extern const char support_libdir_prefix[];
+ /* Corresponds to the install's bin/ directory.  */
+ extern const char support_bindir_prefix[];
++/* Corresponds to the install's sbin/ directory.  */
++extern const char support_install_rootsbindir[];
+ 
+ extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *,
+ 					size_t, unsigned int);
+diff --git a/support/support_paths.c b/support/support_paths.c
+index 75634aa..1fe3283 100644
+--- a/support/support_paths.c
++++ b/support/support_paths.c
+@@ -64,3 +64,10 @@ const char support_bindir_prefix[] = BINDIR_PATH;
+ #else
+ # error please -DBINDIR_PATH=something in the Makefile
+ #endif
++
++#ifdef ROOTSBINDIR_PATH
++/* Corresponds to the install's sbin/ directory.  */
++const char support_install_rootsbindir[] = ROOTSBINDIR_PATH;
++#else
++# error please -DROOTSBINDIR_PATH=something in the Makefile
++#endif
diff --git a/SOURCES/glibc-rh1747502-9.patch b/SOURCES/glibc-rh1747502-9.patch
new file mode 100644
index 0000000..8bf528d
--- /dev/null
+++ b/SOURCES/glibc-rh1747502-9.patch
@@ -0,0 +1,86 @@
+From 304c61a24f909168c16793ccf7c686237e53d003 Mon Sep 17 00:00:00 2001
+From: DJ Delorie <dj@redhat.com>
+Date: Wed, 5 Dec 2018 12:39:47 -0500
+Subject: test-container: move postclean outside of namespace changes
+
+During postclean.req testing it was found that the fork in the
+parent process (after the unshare syscall) would fail with ENOMEM
+(see recursive_remove() in test-container.c).  While failing with
+ENOMEM is certainly unexpected, it is simply easier to refactor
+the design and have the parent remain outside of the namespace.
+This change moves the postclean.req processing to a distinct
+process (the parent) that then forks the test process (which will
+have to fork once more to complete uid/gid transitions). When the
+test process exists the cleanup process will ensure all files are
+deleted when a post clean is requested.
+
+Signed-off-by: DJ Delorie <dj@redhat.com>
+Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+
+[BZ #23948]
+* support/test-container.c: Move postclean step to before we
+change namespaces.
+
+diff --git a/support/test-container.c b/support/test-container.c
+index df450adfdb..1d1aebeaf3 100644
+--- a/support/test-container.c
++++ b/support/test-container.c
+@@ -921,6 +921,43 @@ main (int argc, char **argv)
+       }
+   }
+ 
++  if (do_postclean)
++    {
++      pid_t pc_pid = fork ();
++
++      if (pc_pid < 0)
++	{
++	  FAIL_EXIT1 ("Can't fork for post-clean");
++	}
++      else if (pc_pid > 0)
++	{
++	  /* Parent.  */
++	  int status;
++	  waitpid (pc_pid, &status, 0);
++
++	  /* Child has exited, we can post-clean the test root.  */
++	  printf("running post-clean rsync\n");
++	  rsync (pristine_root_path, new_root_path, 1);
++
++	  if (WIFEXITED (status))
++	    exit (WEXITSTATUS (status));
++
++	  if (WIFSIGNALED (status))
++	    {
++	      printf ("%%SIGNALLED%%\n");
++	      exit (77);
++	    }
++
++	  printf ("%%EXITERROR%%\n");
++	  exit (78);
++	}
++
++      /* Child continues.  */
++    }
++
++  /* This is the last point in the program where we're still in the
++     "normal" namespace.  */
++
+ #ifdef CLONE_NEWNS
+   /* The unshare here gives us our own spaces and capabilities.  */
+   if (unshare (CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS) < 0)
+@@ -974,14 +1011,6 @@ main (int argc, char **argv)
+       int status;
+       waitpid (child, &status, 0);
+ 
+-      /* There's a bit of magic here, since the buildroot is mounted
+-	 in our space, the paths are still valid, and since the mounts
+-	 aren't recursive, it sees *only* the built root, not anything
+-	 we would normally se if we rsync'd to "/" like mounted /dev
+-	 files.  */
+-      if (do_postclean)
+-	  rsync (pristine_root_path, new_root_path, 1);
+-
+       if (WIFEXITED (status))
+ 	exit (WEXITSTATUS (status));
+ 
diff --git a/SOURCES/glibc-rh1747502.patch b/SOURCES/glibc-rh1747502.patch
new file mode 100644
index 0000000..e28de98
--- /dev/null
+++ b/SOURCES/glibc-rh1747502.patch
@@ -0,0 +1,268 @@
+commit 99135114ba23c3110b7e4e650fabdc5e639746b7
+Author: DJ Delorie <dj@redhat.com>
+Date:   Fri Jun 28 18:30:00 2019 -0500
+
+    nss_db: fix endent wrt NULL mappings [BZ #24695] [BZ #24696]
+    
+    nss_db allows for getpwent et al to be called without a set*ent,
+    but it only works once.  After the last get*ent a set*ent is
+    required to restart, because the end*ent did not properly reset
+    the module.  Resetting it to NULL allows for a proper restart.
+    
+    If the database doesn't exist, however, end*ent erroniously called
+    munmap which set errno.
+    
+    The test case runs "makedb" inside the testroot, so needs selinux
+    DSOs installed.
+
+diff -rupN a/nss/Makefile b/nss/Makefile
+--- a/nss/Makefile	2019-11-04 15:14:16.721221038 -0500
++++ b/nss/Makefile	2019-11-04 15:15:46.447544678 -0500
+@@ -60,6 +60,10 @@ tests			= test-netdb test-digits-dots ts
+ 			  tst-nss-test5
+ xtests			= bug-erange
+ 
++tests-container = \
++			  tst-nss-db-endpwent \
++			  tst-nss-db-endgrent
++
+ # Tests which need libdl
+ ifeq (yes,$(build-shared))
+ tests += tst-nss-files-hosts-erange
+diff -rupN a/nss/nss_db/db-open.c b/nss/nss_db/db-open.c
+--- a/nss/nss_db/db-open.c	2018-08-01 01:10:47.000000000 -0400
++++ b/nss/nss_db/db-open.c	2019-11-04 15:15:10.520213846 -0500
+@@ -63,5 +63,9 @@ internal_setent (const char *file, struc
+ void
+ internal_endent (struct nss_db_map *mapping)
+ {
+-  munmap (mapping->header, mapping->len);
++  if (mapping->header != NULL)
++    {
++      munmap (mapping->header, mapping->len);
++      mapping->header = NULL;
++    }
+ }
+diff -rupN a/nss/tst-nss-db-endgrent.c b/nss/tst-nss-db-endgrent.c
+--- a/nss/tst-nss-db-endgrent.c	1969-12-31 19:00:00.000000000 -0500
++++ b/nss/tst-nss-db-endgrent.c	2019-11-04 15:15:10.526214069 -0500
+@@ -0,0 +1,54 @@
++/* Test for endgrent changing errno for BZ #24696
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <stdlib.h>
++#include <sys/types.h>
++#include <grp.h>
++#include <unistd.h>
++#include <errno.h>
++
++#include <support/check.h>
++#include <support/support.h>
++
++/* The following test verifies that if the db NSS Service is initialized
++   with no database (getgrent), that a subsequent closure (endgrent) does
++   not set errno. In the case of the db service it is not an error to close
++   the service and so it should not set errno.  */
++
++static int
++do_test (void)
++{
++  /* Just make sure it's not there, although usually it won't be.  */
++  unlink ("/var/db/group.db");
++
++  /* This, in conjunction with the testroot's nsswitch.conf, causes
++     the nss_db module to be "connected" and initialized - but the
++     testroot has no group.db, so no mapping will be created.  */
++  getgrent ();
++
++  errno = 0;
++
++  /* Before the fix, this would call munmap (NULL) and set errno.  */
++  endgrent ();
++
++  if (errno != 0)
++    FAIL_EXIT1 ("endgrent set errno to %d\n", errno);
++
++  return 0;
++}
++#include <support/test-driver.c>
+diff -rupN a/nss/tst-nss-db-endgrent.root/etc/nsswitch.conf b/nss/tst-nss-db-endgrent.root/etc/nsswitch.conf
+--- a/nss/tst-nss-db-endgrent.root/etc/nsswitch.conf	1969-12-31 19:00:00.000000000 -0500
++++ b/nss/tst-nss-db-endgrent.root/etc/nsswitch.conf	2019-11-04 15:15:10.539214550 -0500
+@@ -0,0 +1 @@
++group : db files
+diff -rupN a/nss/tst-nss-db-endpwent.c b/nss/tst-nss-db-endpwent.c
+--- a/nss/tst-nss-db-endpwent.c	1969-12-31 19:00:00.000000000 -0500
++++ b/nss/tst-nss-db-endpwent.c	2019-11-04 15:15:10.545214772 -0500
+@@ -0,0 +1,66 @@
++/* Test for endpwent->getpwent crash for BZ #24695
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <stdlib.h>
++#include <string.h>
++#include <sys/types.h>
++#include <pwd.h>
++
++#include <support/support.h>
++#include <support/check.h>
++
++/* It is entirely allowed to start with a getpwent call without
++   resetting the state of the service via a call to setpwent.
++   You can also call getpwent more times than you have entries in
++   the service, and it should not fail.  This test iteratates the
++   database once, gets to the end, and then attempts a second
++   iteration to look for crashes.  */
++
++static void
++try_it (void)
++{
++  struct passwd *pw;
++
++  /* setpwent is intentionally omitted here.  The first call to
++     getpwent detects that it's first and initializes.  The second
++     time try_it is called, this "first call" was not detected before
++     the fix, and getpwent would crash.  */
++
++  while ((pw = getpwent ()) != NULL)
++    ;
++
++  /* We only care if this segfaults or not.  */
++  endpwent ();
++}
++
++static int
++do_test (void)
++{
++  char *cmd;
++
++  cmd = xasprintf ("%s/makedb -o /var/db/passwd.db /var/db/passwd.in",
++		   support_bindir_prefix);
++  system (cmd);
++  free (cmd);
++
++  try_it ();
++  try_it ();
++
++  return 0;
++}
++#include <support/test-driver.c>
+diff -rupN a/nss/tst-nss-db-endpwent.root/etc/nsswitch.conf b/nss/tst-nss-db-endpwent.root/etc/nsswitch.conf
+--- a/nss/tst-nss-db-endpwent.root/etc/nsswitch.conf	1969-12-31 19:00:00.000000000 -0500
++++ b/nss/tst-nss-db-endpwent.root/etc/nsswitch.conf	2019-11-04 15:15:10.556215180 -0500
+@@ -0,0 +1 @@
++passwd: db
+diff -rupN a/nss/tst-nss-db-endpwent.root/var/db/passwd.in b/nss/tst-nss-db-endpwent.root/var/db/passwd.in
+--- a/nss/tst-nss-db-endpwent.root/var/db/passwd.in	1969-12-31 19:00:00.000000000 -0500
++++ b/nss/tst-nss-db-endpwent.root/var/db/passwd.in	2019-11-04 15:15:10.567215588 -0500
+@@ -0,0 +1,4 @@
++.root root:x:0:0:root:/root:/bin/bash
++=0 root:x:0:0:root:/root:/bin/bash
++.bin bin:x:1:1:bin:/bin:/sbin/nologin
++=1 bin:x:1:1:bin:/bin:/sbin/nologin
+diff -rupN a/support/Makefile b/support/Makefile
+--- a/support/Makefile	2019-11-04 15:14:20.416357911 -0500
++++ b/support/Makefile	2019-11-04 15:15:10.574215847 -0500
+@@ -180,6 +180,11 @@ LINKS_DSO_PROGRAM = links-dso-program
+ LDLIBS-links-dso-program = -lstdc++ -lgcc -lgcc_s $(libunwind)
+ endif
+ 
++ifeq (yes,$(have-selinux))
++LDLIBS-$(LINKS_DSO_PROGRAM) += -lselinux
++endif
++
++
+ LDLIBS-test-container = $(libsupport)
+ 
+ others += test-container
+diff -rupN a/support/links-dso-program-c.c b/support/links-dso-program-c.c
+--- a/support/links-dso-program-c.c	2019-11-04 15:14:17.073234077 -0500
++++ b/support/links-dso-program-c.c	2019-11-04 15:15:10.580216069 -0500
+@@ -1,9 +1,26 @@
+ #include <stdio.h>
+ 
++/* makedb needs selinux dso's.  */
++#ifdef HAVE_SELINUX
++# include <selinux/selinux.h>
++#endif
++
++/* The purpose of this file is to indicate to the build system which
++   shared objects need to be copied into the testroot, such as gcc or
++   selinux support libraries.  This program is never executed, only
++   scanned for dependencies on shared objects, so the code below may
++   seem weird - it's written to survive gcc optimization and force
++   such dependencies.
++*/
++
+ int
+ main (int argc, char **argv)
+ {
+   /* Complexity to keep gcc from optimizing this away.  */
+   printf ("This is a test %s.\n", argc > 1 ? argv[1] : "null");
++#ifdef HAVE_SELINUX
++  /* This exists to force libselinux.so to be required.  */
++  printf ("selinux %d\n", is_selinux_enabled ());
++#endif
+   return 0;
+ }
+diff -rupN a/support/links-dso-program.cc b/support/links-dso-program.cc
+--- a/support/links-dso-program.cc	2019-11-04 15:14:17.079234300 -0500
++++ b/support/links-dso-program.cc	2019-11-04 15:15:10.587216328 -0500
+@@ -1,11 +1,28 @@
+ #include <iostream>
+ 
++/* makedb needs selinux dso's.  */
++#ifdef HAVE_SELINUX
++# include <selinux/selinux.h>
++#endif
++
+ using namespace std;
+ 
++/* The purpose of this file is to indicate to the build system which
++   shared objects need to be copied into the testroot, such as gcc or
++   selinux support libraries.  This program is never executed, only
++   scanned for dependencies on shared objects, so the code below may
++   seem weird - it's written to survive gcc optimization and force
++   such dependencies.
++*/
++
+ int
+ main (int argc, char **argv)
+ {
+   /* Complexity to keep gcc from optimizing this away.  */
+   cout << (argc > 1 ? argv[1] : "null");
++#ifdef HAVE_SELINUX
++  /* This exists to force libselinux.so to be required.  */
++  cout << "selinux " << is_selinux_enabled ();
++#endif
+   return 0;
+ }
diff --git a/SOURCES/glibc-rh1747505-1.patch b/SOURCES/glibc-rh1747505-1.patch
new file mode 100644
index 0000000..7569dff
--- /dev/null
+++ b/SOURCES/glibc-rh1747505-1.patch
@@ -0,0 +1,196 @@
+commit 4b7c74179c8928d971d370e1137d202f891a4cf5
+Author: Carlos O'Donell <carlos@redhat.com>
+Date:   Wed Mar 20 12:40:18 2019 -0400
+
+    nss: Make nsswitch.conf more distribution friendly.
+    
+    The current default nsswitch.conf file provided by glibc is not very
+    distribution friendly. The file contains some minimal directives that no
+    real distribution uses. This update aims to provide a rich set of
+    comments which are useful for all distributions, and a broader set of
+    service defines which should work for all distributions.
+    
+    Tested defaults on x86_64 and they work. The nsswitch.conf file more
+    closely matches what we have in Fedora now, and I'll adjust Fedora to
+    use this version with minor changes to enable Fedora-specific service
+    providers.
+    
+    v2
+    - Add missing databases to manual.
+    - Add link to manual from default nsswitch.conf.
+    - Sort nsswitch.conf according to most used database first.
+    
+    v3
+    - Only mention implemented services in 'NSS Basics.'
+    - Mention 'automount' in 'Services in the NSS configuration.'
+    - Sort services in alphabetical order.
+    
+    v4
+    - Project name is 'Samba'.
+    
+    v5
+    - Fix typo in manual/nss.texi.
+    
+    v6
+    - Fix another typo in manual/nss.texi. Ran spell checker this time.
+
+diff --git a/manual/nss.texi b/manual/nss.texi
+index 164ae33246..821469a78a 100644
+--- a/manual/nss.texi
++++ b/manual/nss.texi
+@@ -56,13 +56,17 @@ functions to access the databases.
+ @noindent
+ The databases available in the NSS are
+ 
++@cindex aliases
+ @cindex ethers
+ @cindex group
++@cindex gshadow
+ @cindex hosts
++@cindex initgroups
+ @cindex netgroup
+ @cindex networks
+-@cindex protocols
+ @cindex passwd
++@cindex protocols
++@cindex publickey
+ @cindex rpc
+ @cindex services
+ @cindex shadow
+@@ -75,16 +79,22 @@ Ethernet numbers,
+ @comment @pxref{Ethernet Numbers}.
+ @item group
+ Groups of users, @pxref{Group Database}.
++@item gshadow
++Group passphrase hashes and related information.
+ @item hosts
+ Host names and numbers, @pxref{Host Names}.
++@item initgroups
++Supplementary group access list.
+ @item netgroup
+ Network wide list of host and users, @pxref{Netgroup Database}.
+ @item networks
+ Network names and numbers, @pxref{Networks Database}.
+-@item protocols
+-Network protocols, @pxref{Protocols Database}.
+ @item passwd
+ User identities, @pxref{User Database}.
++@item protocols
++Network protocols, @pxref{Protocols Database}.
++@item publickey
++Public keys for Secure RPC.
+ @item rpc
+ Remote procedure call names and numbers.
+ @comment @pxref{RPC Database}.
+@@ -96,8 +106,8 @@ User passphrase hashes and related information.
+ @end table
+ 
+ @noindent
+-There will be some more added later (@code{automount}, @code{bootparams},
+-@code{netmasks}, and @code{publickey}).
++@c We currently don't implement automount, netmasks, or bootparams.
++More databases may be added later.
+ 
+ @node NSS Configuration File, NSS Module Internals, NSS Basics, Name Service Switch
+ @section The NSS Configuration File
+@@ -159,6 +169,10 @@ these files since they should be placed in a directory where they are
+ found automatically.  Only the names of all available services are
+ important.
+ 
++Lastly, some system software may make use of the NSS configuration file
++to store their own configuration for similar purposes.  Examples of this
++include the @code{automount} service which is used by @code{autofs}.
++
+ @node Actions in the NSS configuration, Notes on NSS Configuration File, Services in the NSS configuration, NSS Configuration File
+ @subsection Actions in the NSS configuration
+ 
+diff --git a/nss/nsswitch.conf b/nss/nsswitch.conf
+index 39ca88bf51..f553588114 100644
+--- a/nss/nsswitch.conf
++++ b/nss/nsswitch.conf
+@@ -1,20 +1,69 @@
++#
+ # /etc/nsswitch.conf
+ #
+-# Example configuration of GNU Name Service Switch functionality.
++# An example Name Service Switch config file. This file should be
++# sorted with the most-used services at the beginning.
+ #
++# Valid databases are: aliases, ethers, group, gshadow, hosts,
++# initgroups, netgroup, networks, passwd, protocols, publickey,
++# rpc, services, and shadow.
++#
++# Valid service provider entries include (in alphabetical order):
++#
++#	compat			Use /etc files plus *_compat pseudo-db
++#	db			Use the pre-processed /var/db files
++#	dns			Use DNS (Domain Name Service)
++#	files			Use the local files in /etc
++#	hesiod			Use Hesiod (DNS) for user lookups
++#	nis			Use NIS (NIS version 2), also called YP
++#	nisplus			Use NIS+ (NIS version 3)
++#
++# See `info libc 'NSS Basics'` for more information.
++#
++# Commonly used alternative service providers (may need installation):
++#
++#	ldap			Use LDAP directory server
++#	myhostname		Use systemd host names
++#	mymachines		Use systemd machine names
++#	mdns*, mdns*_minimal	Use Avahi mDNS/DNS-SD
++#	resolve			Use systemd resolved resolver
++#	sss			Use System Security Services Daemon (sssd)
++#	systemd			Use systemd for dynamic user option
++#	winbind			Use Samba winbind support
++#	wins			Use Samba wins support
++#	wrapper			Use wrapper module for testing
++#
++# Notes:
++#
++# 'sssd' performs its own 'files'-based caching, so it should generally
++# come before 'files'.
++#
++# WARNING: Running nscd with a secondary caching service like sssd may
++# 	   lead to unexpected behaviour, especially with how long
++# 	   entries are cached.
++#
++# Installation instructions:
++#
++# To use 'db', install the appropriate package(s) (provide 'makedb' and
++# libnss_db.so.*), and place the 'db' in front of 'files' for entries
++# you want to be looked up first in the databases, like this:
++#
++# passwd:    db files
++# shadow:    db files
++# group:     db files
+ 
+-passwd:		db files
+-group:		db files
+-initgroups:	db [SUCCESS=continue] files
+-shadow:		db files
+-gshadow:	files
+-
+-hosts:		files dns
+-networks:	files dns
+-
+-protocols:	db files
+-services:	db files
+-ethers:		db files
+-rpc:		db files
+-
+-netgroup:	db files
++# In alphabetical order. Re-order as required to optimize peformance.
++aliases:    files
++ethers:     files
++group:      files
++gshadow:    files
++hosts:      files dns
++initgroups: files
++netgroup:   files
++networks:   files dns
++passwd:     files
++protocols:  files
++publickey:  files
++rpc:        files
++shadow:     files
++services:   files
diff --git a/SOURCES/glibc-rh1747505-2.patch b/SOURCES/glibc-rh1747505-2.patch
new file mode 100644
index 0000000..085c2c3
--- /dev/null
+++ b/SOURCES/glibc-rh1747505-2.patch
@@ -0,0 +1,38 @@
+commit d34d4c80226b3f5a1b51a8e5b005a52fba07d7ba
+Author: Carlos O'Donell <carlos@redhat.com>
+Date:   Wed Mar 20 22:11:32 2019 -0400
+
+    nscd: Improve nscd.conf comments.
+    
+    This change adds a warning to nscd.conf about running multiple caching
+    services together and that it may lead to unexpected behaviours. Also we
+    add a note that enabling the 'shared' option will cause cache hit rates
+    to be misreported (a side effect of the implementation).
+    
+    v2
+    - Rewrite comment to avoid implementation details.
+
+diff --git a/nscd/nscd.conf b/nscd/nscd.conf
+index 39b875912d..487ffe461d 100644
+--- a/nscd/nscd.conf
++++ b/nscd/nscd.conf
+@@ -3,6 +3,9 @@
+ #
+ # An example Name Service Cache config file.  This file is needed by nscd.
+ #
++# WARNING: Running nscd with a secondary caching service like sssd may lead to
++#          unexpected behaviour, especially with how long entries are cached.
++#
+ # Legal entries are:
+ #
+ #	logfile			<file>
+@@ -23,6 +26,9 @@
+ #	check-files		<service> <yes|no>
+ #	persistent		<service> <yes|no>
+ #	shared			<service> <yes|no>
++#	NOTE: Setting 'shared' to a value of 'yes' will accelerate the lookup,
++#	      but those lookups will not be counted as cache hits
++#	      i.e. 'nscd -g' may show '0%'.
+ #	max-db-size		<service> <number bytes>
+ #	auto-propagate		<service> <yes|no>
+ #
diff --git a/SOURCES/glibc-rh1747505-3.patch b/SOURCES/glibc-rh1747505-3.patch
new file mode 100644
index 0000000..01e4959
--- /dev/null
+++ b/SOURCES/glibc-rh1747505-3.patch
@@ -0,0 +1,40 @@
+diff -Nrup a/nss/nsswitch.conf b/nss/nsswitch.conf
+--- a/nss/nsswitch.conf	2019-10-25 12:14:09.255834866 -0400
++++ b/nss/nsswitch.conf	2019-10-25 12:50:08.425769248 -0400
+@@ -1,7 +1,7 @@
+ #
+ # /etc/nsswitch.conf
+ #
+-# An example Name Service Switch config file. This file should be
++# Name Service Switch config file. This file should be
+ # sorted with the most-used services at the beginning.
+ #
+ # Valid databases are: aliases, ethers, group, gshadow, hosts,
+@@ -52,18 +52,20 @@
+ # shadow:    db files
+ # group:     db files
+ 
+-# In alphabetical order. Re-order as required to optimize peformance.
++# In order of likelihood of use to accelerate lookup.
++passwd:     sss files
++shadow:     files sss
++group:      sss files
++hosts:      files dns myhostname
++services:   files sss
++netgroup:   sss
++automount:  files sss
++
+ aliases:    files
+ ethers:     files
+-group:      files
+ gshadow:    files
+-hosts:      files dns
+ initgroups: files
+-netgroup:   files
+ networks:   files dns
+-passwd:     files
+ protocols:  files
+ publickey:  files
+ rpc:        files
+-shadow:     files
+-services:   files
diff --git a/SOURCES/glibc-rh1747505-4.patch b/SOURCES/glibc-rh1747505-4.patch
new file mode 100644
index 0000000..c0a9b7f
--- /dev/null
+++ b/SOURCES/glibc-rh1747505-4.patch
@@ -0,0 +1,27 @@
+commit eed1f6fcdb0526498223ebfe95f91ef5dec2172a
+Author: Carlos O'Donell <carlos@redhat.com>
+Date:   Tue Oct 29 11:58:03 2019 -0400
+
+    Comment out initgroups from example nsswitch.conf (Bug 25146)
+
+    In commit 4b7c74179c8928d971d370e1137d202f891a4cf5 the nsswitch.conf
+    file was harmonized with downstream distributions, but this change
+    included adding "initgroups: files". We should not add initgroups by
+    default, we can have it, but it should be commented out to allow it
+    to inherit the settings for group. The problem is principally that
+    downstream authconfig won't update initgroups and it will get out of
+    sync with the setting for group.
+
+diff -Nrup a/nss/nsswitch.conf b/nss/nsswitch.conf
+--- a/nss/nsswitch.conf	2019-10-29 14:13:15.883199544 -0400
++++ b/nss/nsswitch.conf	2019-10-29 14:15:44.860978858 -0400
+@@ -64,7 +64,8 @@ automount:  files sss
+ aliases:    files
+ ethers:     files
+ gshadow:    files
+-initgroups: files
++# Allow initgroups to default to the setting for group.
++# initgroups: files
+ networks:   files dns
+ protocols:  files
+ publickey:  files
diff --git a/SOURCES/glibc-rh1749439-1.patch b/SOURCES/glibc-rh1749439-1.patch
new file mode 100644
index 0000000..18b7195
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-1.patch
@@ -0,0 +1,512 @@
+commit 1a7fe2ebe52b3c8bf465d1756e69452d05c1c103
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Mon Aug 5 15:54:10 2019 +0200
+
+    login: Remove utmp backend jump tables [BZ #23518]
+    
+    There is just one file-based implementation, so this dispatch
+    mechanism is unnecessary.  Instead of the vtable pointer
+    __libc_utmp_jump_table, use a non-negative file_fd as the indicator
+    that the backend is initialized.
+
+diff --git a/login/getutent_r.c b/login/getutent_r.c
+index 6a244ba6e0b86da7..44239ecb81bacea4 100644
+--- a/login/getutent_r.c
++++ b/login/getutent_r.c
+@@ -23,115 +23,16 @@
+ 
+ #include "utmp-private.h"
+ 
+-
+-/* Functions defined here.  */
+-static int setutent_unknown (void);
+-static int getutent_r_unknown (struct utmp *buffer, struct utmp **result);
+-static int getutid_r_unknown (const struct utmp *line, struct utmp *buffer,
+-			      struct utmp **result);
+-static int getutline_r_unknown (const struct utmp *id, struct utmp *buffer,
+-				struct utmp **result);
+-static struct utmp *pututline_unknown (const struct utmp *data);
+-static void endutent_unknown (void);
+-
+-/* Initial Jump table.  */
+-const struct utfuncs __libc_utmp_unknown_functions =
+-{
+-  setutent_unknown,
+-  getutent_r_unknown,
+-  getutid_r_unknown,
+-  getutline_r_unknown,
+-  pututline_unknown,
+-  endutent_unknown,
+-  NULL
+-};
+-
+-/* Currently selected backend.  */
+-const struct utfuncs *__libc_utmp_jump_table = &__libc_utmp_unknown_functions;
+-
+ /* We need to protect the opening of the file.  */
+ __libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden)
+ 
+ 
+-static int
+-setutent_unknown (void)
+-{
+-  int result;
+-
+-  result = (*__libc_utmp_file_functions.setutent) ();
+-  if (result)
+-    __libc_utmp_jump_table = &__libc_utmp_file_functions;
+-
+-  return result;
+-}
+-
+-
+-static int
+-getutent_r_unknown (struct utmp *buffer, struct utmp **result)
+-{
+-  /* The backend was not yet initialized.  */
+-  if (setutent_unknown ())
+-    return (*__libc_utmp_jump_table->getutent_r) (buffer, result);
+-
+-  /* Not available.  */
+-  *result = NULL;
+-  return -1;
+-}
+-
+-
+-static int
+-getutid_r_unknown (const struct utmp *id, struct utmp *buffer,
+-		   struct utmp **result)
+-{
+-  /* The backend was not yet initialized.  */
+-  if (setutent_unknown ())
+-    return (*__libc_utmp_jump_table->getutid_r) (id, buffer, result);
+-
+-  /* Not available.  */
+-  *result = NULL;
+-  return -1;
+-}
+-
+-
+-static int
+-getutline_r_unknown (const struct utmp *line, struct utmp *buffer,
+-		     struct utmp **result)
+-{
+-  /* The backend was not yet initialized.  */
+-  if (setutent_unknown ())
+-    return (*__libc_utmp_jump_table->getutline_r) (line, buffer, result);
+-
+-  /* Not available.  */
+-  *result = NULL;
+-  return -1;
+-}
+-
+-
+-static struct utmp *
+-pututline_unknown (const struct utmp *data)
+-{
+-  /* The backend was not yet initialized.  */
+-  if (setutent_unknown ())
+-    return (*__libc_utmp_jump_table->pututline) (data);
+-
+-  /* Not available.  */
+-  return NULL;
+-}
+-
+-
+-static void
+-endutent_unknown (void)
+-{
+-  /* Nothing to do.  */
+-}
+-
+-
+ void
+ __setutent (void)
+ {
+   __libc_lock_lock (__libc_utmp_lock);
+ 
+-  (*__libc_utmp_jump_table->setutent) ();
++  __libc_setutent ();
+ 
+   __libc_lock_unlock (__libc_utmp_lock);
+ }
+@@ -145,7 +46,7 @@ __getutent_r (struct utmp *buffer, struct utmp **result)
+ 
+   __libc_lock_lock (__libc_utmp_lock);
+ 
+-  retval = (*__libc_utmp_jump_table->getutent_r) (buffer, result);
++  retval = __libc_getutent_r (buffer, result);
+ 
+   __libc_lock_unlock (__libc_utmp_lock);
+ 
+@@ -162,7 +63,7 @@ __pututline (const struct utmp *data)
+ 
+   __libc_lock_lock (__libc_utmp_lock);
+ 
+-  buffer = (*__libc_utmp_jump_table->pututline) (data);
++  buffer = __libc_pututline (data);
+ 
+   __libc_lock_unlock (__libc_utmp_lock);
+ 
+@@ -177,8 +78,7 @@ __endutent (void)
+ {
+   __libc_lock_lock (__libc_utmp_lock);
+ 
+-  (*__libc_utmp_jump_table->endutent) ();
+-  __libc_utmp_jump_table = &__libc_utmp_unknown_functions;
++  __libc_endutent ();
+ 
+   __libc_lock_unlock (__libc_utmp_lock);
+ }
+diff --git a/login/getutid_r.c b/login/getutid_r.c
+index b7d3dbac75774b0a..8cb6b16d735e8265 100644
+--- a/login/getutid_r.c
++++ b/login/getutid_r.c
+@@ -49,7 +49,7 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
+ 
+   __libc_lock_lock (__libc_utmp_lock);
+ 
+-  retval = (*__libc_utmp_jump_table->getutid_r) (id, buffer, result);
++  retval = __libc_getutid_r (id, buffer, result);
+ 
+   __libc_lock_unlock (__libc_utmp_lock);
+ 
+diff --git a/login/getutline_r.c b/login/getutline_r.c
+index 6996887f76b28816..5607c19ed2e1ca66 100644
+--- a/login/getutline_r.c
++++ b/login/getutline_r.c
+@@ -36,7 +36,7 @@ __getutline_r (const struct utmp *line, struct utmp *buffer,
+ 
+   __libc_lock_lock (__libc_utmp_lock);
+ 
+-  retval = (*__libc_utmp_jump_table->getutline_r) (line, buffer, result);
++  retval = __libc_getutline_r (line, buffer, result);
+ 
+   __libc_lock_unlock (__libc_utmp_lock);
+ 
+diff --git a/login/updwtmp.c b/login/updwtmp.c
+index 56fb41916a776c0a..7ae96224ca789b6d 100644
+--- a/login/updwtmp.c
++++ b/login/updwtmp.c
+@@ -29,7 +29,7 @@ __updwtmp (const char *wtmp_file, const struct utmp *utmp)
+ {
+   const char *file_name = TRANSFORM_UTMP_FILE_NAME (wtmp_file);
+ 
+-  (*__libc_utmp_file_functions.updwtmp) (file_name, utmp);
++  __libc_updwtmp (file_name, utmp);
+ }
+ libc_hidden_def (__updwtmp)
+ weak_alias (__updwtmp, updwtmp)
+diff --git a/login/utmp-private.h b/login/utmp-private.h
+index bd8773984cfc56de..5c2048ee52dc3cee 100644
+--- a/login/utmp-private.h
++++ b/login/utmp-private.h
+@@ -24,24 +24,17 @@
+ #include <utmp.h>
+ #include <libc-lock.h>
+ 
+-/* The structure describing the functions in a backend.  */
+-struct utfuncs
+-{
+-  int (*setutent) (void);
+-  int (*getutent_r) (struct utmp *, struct utmp **);
+-  int (*getutid_r) (const struct utmp *, struct utmp *, struct utmp **);
+-  int (*getutline_r) (const struct utmp *, struct utmp *, struct utmp **);
+-  struct utmp *(*pututline) (const struct utmp *);
+-  void (*endutent) (void);
+-  int (*updwtmp) (const char *, const struct utmp *);
+-};
+-
+-/* The tables from the services.  */
+-extern const struct utfuncs __libc_utmp_file_functions attribute_hidden;
+-extern const struct utfuncs __libc_utmp_unknown_functions attribute_hidden;
+-
+-/* Currently selected backend.  */
+-extern const struct utfuncs *__libc_utmp_jump_table attribute_hidden;
++/* These functions check for initialization, but not perform any
++   locking.  */
++int __libc_setutent (void) attribute_hidden;
++int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden;
++int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **)
++  attribute_hidden;
++int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **)
++  attribute_hidden;
++struct utmp *__libc_pututline (const struct utmp *) attribute_hidden;
++void __libc_endutent (void) attribute_hidden;
++int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden;
+ 
+ /* Current file name.  */
+ extern const char *__libc_utmp_file_name attribute_hidden;
+diff --git a/login/utmp_file.c b/login/utmp_file.c
+index 040a5057116bb69d..069e6d0452e333ad 100644
+--- a/login/utmp_file.c
++++ b/login/utmp_file.c
+@@ -105,37 +105,12 @@ static void timeout_handler (int signum) {};
+     alarm (old_timeout);						      \
+ } while (0)
+ 
+-
+-/* Functions defined here.  */
+-static int setutent_file (void);
+-static int getutent_r_file (struct utmp *buffer, struct utmp **result);
+-static int getutid_r_file (const struct utmp *key, struct utmp *buffer,
+-			   struct utmp **result);
+-static int getutline_r_file (const struct utmp *key, struct utmp *buffer,
+-			     struct utmp **result);
+-static struct utmp *pututline_file (const struct utmp *data);
+-static void endutent_file (void);
+-static int updwtmp_file (const char *file, const struct utmp *utmp);
+-
+-/* Jump table for file functions.  */
+-const struct utfuncs __libc_utmp_file_functions =
+-{
+-  setutent_file,
+-  getutent_r_file,
+-  getutid_r_file,
+-  getutline_r_file,
+-  pututline_file,
+-  endutent_file,
+-  updwtmp_file
+-};
+-
+-
+ #ifndef TRANSFORM_UTMP_FILE_NAME
+ # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name)
+ #endif
+ 
+-static int
+-setutent_file (void)
++int
++__libc_setutent (void)
+ {
+   if (file_fd < 0)
+     {
+@@ -166,15 +141,19 @@ setutent_file (void)
+   return 1;
+ }
+ 
++/* Preform initialization if necessary.  */
++static bool
++maybe_setutent (void)
++{
++  return file_fd >= 0 || __libc_setutent ();
++}
+ 
+-static int
+-getutent_r_file (struct utmp *buffer, struct utmp **result)
++int
++__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+ {
+   ssize_t nbytes;
+ 
+-  assert (file_fd >= 0);
+-
+-  if (file_offset == -1l)
++  if (!maybe_setutent () || file_offset == -1l)
+     {
+       /* Not available.  */
+       *result = NULL;
+@@ -279,13 +258,11 @@ unlock_return:
+ 
+ /* For implementing this function we don't use the getutent_r function
+    because we can avoid the reposition on every new entry this way.  */
+-static int
+-getutid_r_file (const struct utmp *id, struct utmp *buffer,
+-		struct utmp **result)
++int
++__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
++		  struct utmp **result)
+ {
+-  assert (file_fd >= 0);
+-
+-  if (file_offset == -1l)
++  if (!maybe_setutent () || file_offset == -1l)
+     {
+       *result = NULL;
+       return -1;
+@@ -309,13 +286,11 @@ getutid_r_file (const struct utmp *id, struct utmp *buffer,
+ 
+ /* For implementing this function we don't use the getutent_r function
+    because we can avoid the reposition on every new entry this way.  */
+-static int
+-getutline_r_file (const struct utmp *line, struct utmp *buffer,
+-		  struct utmp **result)
++int
++__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
++		    struct utmp **result)
+ {
+-  assert (file_fd >= 0);
+-
+-  if (file_offset == -1l)
++  if (!maybe_setutent () || file_offset == -1l)
+     {
+       *result = NULL;
+       return -1;
+@@ -361,15 +336,16 @@ unlock_return:
+ }
+ 
+ 
+-static struct utmp *
+-pututline_file (const struct utmp *data)
++struct utmp *
++__libc_pututline (const struct utmp *data)
+ {
++  if (!maybe_setutent ())
++    return NULL;
++
+   struct utmp buffer;
+   struct utmp *pbuf;
+   int found;
+ 
+-  assert (file_fd >= 0);
+-
+   if (! file_writable)
+     {
+       /* We must make the file descriptor writable before going on.  */
+@@ -467,18 +443,19 @@ pututline_file (const struct utmp *data)
+ }
+ 
+ 
+-static void
+-endutent_file (void)
++void
++__libc_endutent (void)
+ {
+-  assert (file_fd >= 0);
+-
+-  __close_nocancel_nostatus (file_fd);
+-  file_fd = -1;
++  if (file_fd >= 0)
++    {
++      __close_nocancel_nostatus (file_fd);
++      file_fd = -1;
++    }
+ }
+ 
+ 
+-static int
+-updwtmp_file (const char *file, const struct utmp *utmp)
++int
++__libc_updwtmp (const char *file, const struct utmp *utmp)
+ {
+   int result = -1;
+   off64_t offset;
+diff --git a/login/utmpname.c b/login/utmpname.c
+index 21cb890a1a2fdc92..73b19c33ceab4dd7 100644
+--- a/login/utmpname.c
++++ b/login/utmpname.c
+@@ -42,8 +42,7 @@ __utmpname (const char *file)
+   __libc_lock_lock (__libc_utmp_lock);
+ 
+   /* Close the old file.  */
+-  (*__libc_utmp_jump_table->endutent) ();
+-  __libc_utmp_jump_table = &__libc_utmp_unknown_functions;
++  __libc_endutent ();
+ 
+   if (strcmp (file, __libc_utmp_file_name) != 0)
+     {
+diff --git a/manual/users.texi b/manual/users.texi
+index 4ed79ba26fc8e9d0..a006bb58acfd0568 100644
+--- a/manual/users.texi
++++ b/manual/users.texi
+@@ -894,9 +894,9 @@ The @code{getlogin} function is declared in @file{unistd.h}, while
+ @c   ttyname_r dup @ascuheap @acsmem @acsfd
+ @c   strncpy dup ok
+ @c   libc_lock_lock dup @asulock @aculock
+-@c   *libc_utmp_jump_table->setutent dup @mtasurace:utent @acsfd
+-@c   *libc_utmp_jump_table->getutline_r dup @mtasurace:utent @mtascusig:ALRM @mtascutimer
+-@c   *libc_utmp_jump_table->endutent dup @mtasurace:utent @asulock @aculock
++@c   __libc_setutent dup @mtasurace:utent @acsfd
++@c   __libc_getutline_r dup @mtasurace:utent @mtascusig:ALRM @mtascutimer
++@c   __libc_endutent dup @mtasurace:utent @asulock @aculock
+ @c   libc_lock_unlock dup ok
+ @c   strlen dup ok
+ @c   memcpy dup ok
+@@ -1111,7 +1111,7 @@ compatibility only, @file{utmp.h} defines @code{ut_time} as an alias for
+ 
+ @c setutent @mtasurace:utent @asulock @aculock @acsfd
+ @c  libc_lock_lock dup @asulock @aculock
+-@c  *libc_utmp_jump_table->setutent @mtasurace:utent @acsfd
++@c  __libc_setutent @mtasurace:utent @acsfd
+ @c   setutent_unknown @mtasurace:utent @acsfd
+ @c    *libc_utmp_file_functions.setutent = setutent_file @mtasurace:utent @acsfd
+ @c      open_not_cancel_2 dup @acsfd
+@@ -1152,7 +1152,7 @@ A null pointer is returned in case no further entry is available.
+ @safety{@prelim{}@mtunsafe{@mtasurace{:utent}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
+ @c endutent @mtasurace:utent @asulock @aculock @acsfd
+ @c  libc_lock_lock dup @asulock @aculock
+-@c  *libc_utmp_jump_table->endutent @mtasurace:utent @acsfd
++@c  __libc_endutent @mtasurace:utent @acsfd
+ @c   endutent_unknown ok
+ @c   endutent_file @mtasurace:utent @acsfd
+ @c    close_not_cancel_no_status dup @acsfd
+@@ -1230,7 +1230,7 @@ over again.
+ @safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
+ @c pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd
+ @c  libc_lock_lock dup @asulock @aculock
+-@c  *libc_utmp_jump_table->pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
++@c  __libc_pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
+ @c   pututline_unknown @mtasurace:utent @acsfd
+ @c    setutent_unknown dup @mtasurace:utent @acsfd
+ @c   pututline_file @mtascusig:ALRM @mtascutimer @acsfd
+@@ -1282,7 +1282,7 @@ user-provided buffer.
+ @safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
+ @c getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd
+ @c  libc_lock_lock dup @asulock @aculock
+-@c  *libc_utmp_jump_table->getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
++@c  __libc_getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
+ @c   getutent_r_unknown @mtasurace:utent @acsfd
+ @c    setutent_unknown dup @mtasurace:utent @acsfd
+ @c   getutent_r_file @mtasurace:utent @mtascusig:ALRM @mtascutimer
+@@ -1319,7 +1319,7 @@ This function is a GNU extension.
+ @safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
+ @c getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd
+ @c  libc_lock_lock dup @asulock @aculock
+-@c  *libc_utmp_jump_table->getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
++@c  __libc_getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
+ @c   getutid_r_unknown @mtasurace:utent @acsfd
+ @c    setutent_unknown dup @mtasurace:utent @acsfd
+ @c   getutid_r_file @mtascusig:ALRM @mtascutimer
+@@ -1349,7 +1349,7 @@ This function is a GNU extension.
+ @safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
+ @c getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd
+ @c  libc_lock_lock dup @asulock @aculock
+-@c  *libc_utmp_jump_table->getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
++@c  __libc_getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
+ @c   getutline_r_unknown @mtasurace:utent @acsfd
+ @c    setutent_unknown dup @mtasurace:utent @acsfd
+ @c   getutline_r_file @mtasurace:utent @mtascusig:ALRM @mtascutimer
+@@ -1393,7 +1393,7 @@ be used.
+ @safety{@prelim{}@mtunsafe{@mtasurace{:utent}}@asunsafe{@asulock{} @ascuheap{}}@acunsafe{@aculock{} @acsmem{}}}
+ @c utmpname @mtasurace:utent @asulock @ascuheap @aculock @acsmem
+ @c  libc_lock_lock dup @asulock @aculock
+-@c  *libc_utmp_jump_table->endutent dup @mtasurace:utent
++@c  __libc_endutent dup @mtasurace:utent
+ @c  strcmp dup ok
+ @c  free dup @ascuheap @acsmem
+ @c  strdup dup @ascuheap @acsmem
+diff --git a/sysdeps/unix/getlogin_r.c b/sysdeps/unix/getlogin_r.c
+index 444df7e4d3210cf6..180c0bbca13d0f87 100644
+--- a/sysdeps/unix/getlogin_r.c
++++ b/sysdeps/unix/getlogin_r.c
+@@ -64,8 +64,8 @@ __getlogin_r (char *name, size_t name_len)
+      held so that our search is thread-safe.  */
+ 
+   __libc_lock_lock (__libc_utmp_lock);
+-  (*__libc_utmp_jump_table->setutent) ();
+-  result = (*__libc_utmp_jump_table->getutline_r) (&line, &buffer, &ut);
++  __libc_setutent ();
++  result = __libc_getutline_r (&line, &buffer, &ut);
+   if (result < 0)
+     {
+       if (errno == ESRCH)
+@@ -74,8 +74,7 @@ __getlogin_r (char *name, size_t name_len)
+       else
+ 	result = errno;
+     }
+-  (*__libc_utmp_jump_table->endutent) ();
+-  __libc_utmp_jump_table = &__libc_utmp_unknown_functions;
++  __libc_endutent ();
+   __libc_lock_unlock (__libc_utmp_lock);
+ 
+   if (result == 0)
diff --git a/SOURCES/glibc-rh1749439-10.patch b/SOURCES/glibc-rh1749439-10.patch
new file mode 100644
index 0000000..92741c7
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-10.patch
@@ -0,0 +1,389 @@
+commit be6b16d975683e6cca57852cd4cfe715b2a9d8b1
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Nov 7 18:15:18 2019 +0100
+
+    login: Acquire write lock early in pututline [BZ #24882]
+    
+    It has been reported that due to lack of fairness in POSIX file
+    locking, the current reader-to-writer lock upgrade can result in
+    lack of forward progress.  Acquiring the write lock directly
+    hopefully avoids this issue if there are only writers.
+    
+    This also fixes bug 24882 due to the cache revalidation in
+    __libc_pututline.
+    
+    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+    Change-Id: I57e31ae30719e609a53505a0924dda101d46372e
+
+diff --git a/login/Makefile b/login/Makefile
+index 82132c83fd799357..030cf489b2e037d4 100644
+--- a/login/Makefile
++++ b/login/Makefile
+@@ -44,7 +44,7 @@ subdir-dirs = programs
+ vpath %.c programs
+ 
+ tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
+-  tst-pututxline-lockfail
++  tst-pututxline-lockfail tst-pututxline-cache
+ 
+ # Build the -lutil library with these extra functions.
+ extra-libs      := libutil
+@@ -74,3 +74,4 @@ $(inst_libexecdir)/pt_chown: $(objpfx)pt_chown $(+force)
+ 	-$(INSTALL_PROGRAM) -m 4755 -o root $< $@
+ 
+ $(objpfx)tst-pututxline-lockfail: $(shared-thread-library)
++$(objpfx)tst-pututxline-cache: $(shared-thread-library)
+diff --git a/login/tst-pututxline-cache.c b/login/tst-pututxline-cache.c
+new file mode 100644
+index 0000000000000000..3f30dd1776711769
+--- /dev/null
++++ b/login/tst-pututxline-cache.c
+@@ -0,0 +1,193 @@
++/* Test case for cache invalidation after concurrent write (bug 24882).
++   Copyright (C) 2019 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public License as
++   published by the Free Software Foundation; either version 2.1 of the
++   License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; see the file COPYING.LIB.  If
++   not, see <http://www.gnu.org/licenses/>.  */
++
++/* This test writes an entry to the utmpx file, reads it (so that it
++   is cached) in process1, and overwrites the same entry in process2
++   with something that does not match the search criteria.  At this
++   point, the cache of the first process is stale, and when process1
++   attempts to write a new record which would have gone to the same
++   place (as indicated by the cache), it needs to realize that it has
++   to pick a different slot because the old slot is now used for
++   something else.  */
++
++#include <errno.h>
++#include <stdlib.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/namespace.h>
++#include <support/support.h>
++#include <support/temp_file.h>
++#include <support/xthread.h>
++#include <support/xunistd.h>
++#include <utmp.h>
++#include <utmpx.h>
++
++/* Set to the path of the utmp file.  */
++static char *utmp_file;
++
++/* Used to synchronize the subprocesses.  The barrier itself is
++   allocated in shared memory.  */
++static pthread_barrier_t *barrier;
++
++/* setutxent with error checking.  */
++static void
++xsetutxent (void)
++{
++  errno = 0;
++  setutxent ();
++  TEST_COMPARE (errno, 0);
++}
++
++/* getutxent with error checking.  */
++static struct utmpx *
++xgetutxent (void)
++{
++  errno = 0;
++  struct utmpx *result = getutxent ();
++  if (result == NULL)
++    FAIL_EXIT1 ("getutxent: %m");
++  return result;
++}
++
++static void
++put_entry (const char *id, pid_t pid, const char *user, const char *line)
++{
++  struct utmpx ut =
++    {
++     .ut_type = LOGIN_PROCESS,
++     .ut_pid = pid,
++     .ut_host = "localhost",
++    };
++  strcpy (ut.ut_id, id);
++  strncpy (ut.ut_user, user, sizeof (ut.ut_user));
++  strncpy (ut.ut_line, line, sizeof (ut.ut_line));
++  TEST_VERIFY (pututxline (&ut) != NULL);
++}
++
++/* Use two cooperating subprocesses to avoid issues related to
++   unlock-on-close semantics of POSIX advisory locks.  */
++
++static __attribute__ ((noreturn)) void
++process1 (void)
++{
++  TEST_COMPARE (utmpname (utmp_file), 0);
++
++  /* Create an entry.  */
++  xsetutxent ();
++  put_entry ("1", 101, "root", "process1");
++
++  /* Retrieve the entry.  This will fill the internal cache.  */
++  {
++    errno = 0;
++    setutxent ();
++    TEST_COMPARE (errno, 0);
++    struct utmpx ut =
++      {
++       .ut_type = LOGIN_PROCESS,
++       .ut_line = "process1",
++      };
++    struct utmpx *result = getutxline (&ut);
++    if (result == NULL)
++      FAIL_EXIT1 ("getutxline (\"process1\"): %m");
++    TEST_COMPARE (result->ut_pid, 101);
++  }
++
++  /* Signal the other process to overwrite the entry.  */
++  xpthread_barrier_wait (barrier);
++
++  /* Wait for the other process to complete the write operation.  */
++  xpthread_barrier_wait (barrier);
++
++  /* Add another entry.  Note: This time, there is no setutxent call.  */
++  put_entry ("1", 103, "root", "process1");
++
++  _exit (0);
++}
++
++static void
++process2 (void *closure)
++{
++  /* Wait for the first process to write its entry.  */
++  xpthread_barrier_wait (barrier);
++
++  /* Truncate the file.  The glibc interface does not support
++     re-purposing records, but an external expiration mechanism may
++     trigger this.  */
++  TEST_COMPARE (truncate64 (utmp_file, 0), 0);
++
++  /* Write the replacement entry.  */
++  TEST_COMPARE (utmpname (utmp_file), 0);
++  xsetutxent ();
++  put_entry ("2", 102, "user", "process2");
++
++  /* Signal the other process that the entry has been replaced.  */
++  xpthread_barrier_wait (barrier);
++}
++
++static int
++do_test (void)
++{
++  xclose (create_temp_file ("tst-tumpx-cache-write-", &utmp_file));
++  {
++    pthread_barrierattr_t attr;
++    xpthread_barrierattr_init (&attr);
++    xpthread_barrierattr_setpshared (&attr, PTHREAD_SCOPE_PROCESS);
++    barrier = support_shared_allocate (sizeof (*barrier));
++    xpthread_barrier_init (barrier, &attr, 2);
++  }
++
++  /* Run both subprocesses in parallel.  */
++  {
++    pid_t pid1 = xfork ();
++    if (pid1 == 0)
++      process1 ();
++    support_isolate_in_subprocess (process2, NULL);
++    int status;
++    xwaitpid (pid1, &status, 0);
++    TEST_COMPARE (status, 0);
++  }
++
++  /* Check that the utmpx database contains the expected records.  */
++  {
++    TEST_COMPARE (utmpname (utmp_file), 0);
++    xsetutxent ();
++
++    struct utmpx *ut = xgetutxent ();
++    TEST_COMPARE_STRING (ut->ut_id, "2");
++    TEST_COMPARE (ut->ut_pid, 102);
++    TEST_COMPARE_STRING (ut->ut_user, "user");
++    TEST_COMPARE_STRING (ut->ut_line, "process2");
++
++    ut = xgetutxent ();
++    TEST_COMPARE_STRING (ut->ut_id, "1");
++    TEST_COMPARE (ut->ut_pid, 103);
++    TEST_COMPARE_STRING (ut->ut_user, "root");
++    TEST_COMPARE_STRING (ut->ut_line, "process1");
++
++    if (getutxent () != NULL)
++      FAIL_EXIT1 ("additional utmpx entry");
++  }
++
++  xpthread_barrier_destroy (barrier);
++  support_shared_free (barrier);
++  free (utmp_file);
++
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/login/utmp_file.c b/login/utmp_file.c
+index 9ad80364682bae92..6bba120db9cc574e 100644
+--- a/login/utmp_file.c
++++ b/login/utmp_file.c
+@@ -186,19 +186,11 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
+ 
+ 
+ /* Search for *ID, updating last_entry and file_offset.  Return 0 on
+-   success and -1 on failure.  If the locking operation failed, write
+-   true to *LOCK_FAILED.  */
++   success and -1 on failure.  Does not perform locking; for that see
++   internal_getut_r below.  */
+ static int
+-internal_getut_r (const struct utmp *id, bool *lock_failed)
++internal_getut_nolock (const struct utmp *id)
+ {
+-  int result = -1;
+-
+-  if (try_file_lock (file_fd, F_RDLCK))
+-    {
+-      *lock_failed = true;
+-      return -1;
+-    }
+-
+   if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
+       || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
+     {
+@@ -213,7 +205,7 @@ internal_getut_r (const struct utmp *id, bool *lock_failed)
+ 	    {
+ 	      __set_errno (ESRCH);
+ 	      file_offset = -1l;
+-	      goto unlock_return;
++	      return -1;
+ 	    }
+ 	  file_offset += sizeof (struct utmp);
+ 
+@@ -234,7 +226,7 @@ internal_getut_r (const struct utmp *id, bool *lock_failed)
+ 	    {
+ 	      __set_errno (ESRCH);
+ 	      file_offset = -1l;
+-	      goto unlock_return;
++	      return -1;
+ 	    }
+ 	  file_offset += sizeof (struct utmp);
+ 
+@@ -243,15 +235,26 @@ internal_getut_r (const struct utmp *id, bool *lock_failed)
+ 	}
+     }
+ 
+-  result = 0;
++  return 0;
++}
+ 
+-unlock_return:
+-  file_unlock (file_fd);
++/* Search for *ID, updating last_entry and file_offset.  Return 0 on
++   success and -1 on failure.  If the locking operation failed, write
++   true to *LOCK_FAILED.  */
++static int
++internal_getut_r (const struct utmp *id, bool *lock_failed)
++{
++  if (try_file_lock (file_fd, F_RDLCK))
++    {
++      *lock_failed = true;
++      return -1;
++    }
+ 
++  int result = internal_getut_nolock (id);
++  file_unlock (file_fd);
+   return result;
+ }
+ 
+-
+ /* For implementing this function we don't use the getutent_r function
+    because we can avoid the reposition on every new entry this way.  */
+ int
+@@ -279,7 +282,6 @@ __libc_getutid_r (const struct utmp *id, struct utmp *buffer,
+   return 0;
+ }
+ 
+-
+ /* For implementing this function we don't use the getutent_r function
+    because we can avoid the reposition on every new entry this way.  */
+ int
+@@ -336,7 +338,6 @@ __libc_pututline (const struct utmp *data)
+     return NULL;
+ 
+   struct utmp *pbuf;
+-  int found;
+ 
+   if (! file_writable)
+     {
+@@ -358,7 +359,12 @@ __libc_pututline (const struct utmp *data)
+       file_writable = true;
+     }
+ 
++  /* Exclude other writers before validating the cache.  */
++  if (try_file_lock (file_fd, F_WRLCK))
++    return NULL;
++
+   /* Find the correct place to insert the data.  */
++  bool found = false;
+   if (file_offset > 0
+       && ((last_entry.ut_type == data->ut_type
+ 	   && (last_entry.ut_type == RUN_LVL
+@@ -366,23 +372,30 @@ __libc_pututline (const struct utmp *data)
+ 	       || last_entry.ut_type == OLD_TIME
+ 	       || last_entry.ut_type == NEW_TIME))
+ 	  || __utmp_equal (&last_entry, data)))
+-    found = 1;
+-  else
+     {
+-      bool lock_failed = false;
+-      found = internal_getut_r (data, &lock_failed);
+-
+-      if (__builtin_expect (lock_failed, false))
++      if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0)
+ 	{
+-	  __set_errno (EAGAIN);
++	  file_unlock (file_fd);
+ 	  return NULL;
+ 	}
++      if (__read_nocancel (file_fd, &last_entry, sizeof (last_entry))
++	  != sizeof (last_entry))
++	{
++	  if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0)
++	    {
++	      file_unlock (file_fd);
++	      return NULL;
++	    }
++	  found = false;
++	}
++      else
++	found = __utmp_equal (&last_entry, data);
+     }
+ 
+-  if (try_file_lock (file_fd, F_WRLCK))
+-    return NULL;
++  if (!found)
++    found = internal_getut_nolock (data) >= 0;
+ 
+-  if (found < 0)
++  if (!found)
+     {
+       /* We append the next entry.  */
+       file_offset = __lseek64 (file_fd, 0, SEEK_END);
+@@ -411,7 +424,7 @@ __libc_pututline (const struct utmp *data)
+     {
+       /* If we appended a new record this is only partially written.
+ 	 Remove it.  */
+-      if (found < 0)
++      if (!found)
+ 	(void) __ftruncate64 (file_fd, file_offset);
+       pbuf = NULL;
+     }
diff --git a/SOURCES/glibc-rh1749439-11.patch b/SOURCES/glibc-rh1749439-11.patch
new file mode 100644
index 0000000..d1289d6
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-11.patch
@@ -0,0 +1,138 @@
+commit 76a7c103eb9060f9e3ba01d073ae4621a17d8b46
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Tue Nov 12 12:02:57 2019 +0100
+
+    login: Introduce matches_last_entry to utmp processing
+    
+    This simplifies internal_getut_nolock and fixes a regression,
+    introduced in commit be6b16d975683e6cca57852cd4cfe715b2a9d8b1
+    ("login: Acquire write lock early in pututline [BZ #24882]")
+    in pututxline because __utmp_equal can only compare process-related
+    utmp entries.
+    
+    Fixes: be6b16d975683e6cca57852cd4cfe715b2a9d8b1
+    Change-Id: Ib8a85002f7f87ee41590846d16d7e52bdb82f5a5
+
+diff --git a/login/utmp_file.c b/login/utmp_file.c
+index 6bba120db9cc574e..e653d14967c4fb7a 100644
+--- a/login/utmp_file.c
++++ b/login/utmp_file.c
+@@ -43,6 +43,25 @@ static off64_t file_offset;
+ /* Cache for the last read entry.  */
+ static struct utmp last_entry;
+ 
++/* Returns true if *ENTRY matches last_entry, based on
++   data->ut_type.  */
++static bool
++matches_last_entry (const struct utmp *data)
++{
++  if (file_offset <= 0)
++    /* Nothing has been read.  last_entry is stale and cannot match.  */
++    return false;
++
++  if (data->ut_type == RUN_LVL
++      || data->ut_type == BOOT_TIME
++      || data->ut_type == OLD_TIME
++      || data->ut_type == NEW_TIME)
++    /* For some entry types, only a type match is required.  */
++    return data->ut_type == last_entry.ut_type;
++  else
++    /* For the process-related entries, a full match is needed.  */
++    return __utmp_equal (&last_entry, data);
++}
+ 
+ /* Locking timeout.  */
+ #ifndef TIMEOUT
+@@ -133,9 +152,6 @@ __libc_setutent (void)
+   __lseek64 (file_fd, 0, SEEK_SET);
+   file_offset = 0;
+ 
+-  /* Make sure the entry won't match.  */
+-  last_entry.ut_type = -1;
+-
+   return 1;
+ }
+ 
+@@ -191,48 +207,20 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
+ static int
+ internal_getut_nolock (const struct utmp *id)
+ {
+-  if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
+-      || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
++  while (1)
+     {
+-      /* Search for next entry with type RUN_LVL, BOOT_TIME,
+-	 OLD_TIME, or NEW_TIME.  */
+-
+-      while (1)
++      /* Read the next entry.  */
++      if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp))
++	  != sizeof (struct utmp))
+ 	{
+-	  /* Read the next entry.  */
+-	  if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp))
+-	      != sizeof (struct utmp))
+-	    {
+-	      __set_errno (ESRCH);
+-	      file_offset = -1l;
+-	      return -1;
+-	    }
+-	  file_offset += sizeof (struct utmp);
+-
+-	  if (id->ut_type == last_entry.ut_type)
+-	    break;
++	  __set_errno (ESRCH);
++	  file_offset = -1l;
++	  return -1;
+ 	}
+-    }
+-  else
+-    {
+-      /* Search for the next entry with the specified ID and with type
+-	 INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS.  */
+-
+-      while (1)
+-	{
+-	  /* Read the next entry.  */
+-	  if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp))
+-	      != sizeof (struct utmp))
+-	    {
+-	      __set_errno (ESRCH);
+-	      file_offset = -1l;
+-	      return -1;
+-	    }
+-	  file_offset += sizeof (struct utmp);
++      file_offset += sizeof (struct utmp);
+ 
+-	  if (__utmp_equal (&last_entry, id))
+-	    break;
+-	}
++      if (matches_last_entry (id))
++	break;
+     }
+ 
+   return 0;
+@@ -365,13 +353,7 @@ __libc_pututline (const struct utmp *data)
+ 
+   /* Find the correct place to insert the data.  */
+   bool found = false;
+-  if (file_offset > 0
+-      && ((last_entry.ut_type == data->ut_type
+-	   && (last_entry.ut_type == RUN_LVL
+-	       || last_entry.ut_type == BOOT_TIME
+-	       || last_entry.ut_type == OLD_TIME
+-	       || last_entry.ut_type == NEW_TIME))
+-	  || __utmp_equal (&last_entry, data)))
++  if (matches_last_entry (data))
+     {
+       if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0)
+ 	{
+@@ -389,7 +371,7 @@ __libc_pututline (const struct utmp *data)
+ 	  found = false;
+ 	}
+       else
+-	found = __utmp_equal (&last_entry, data);
++	found = matches_last_entry (data);
+     }
+ 
+   if (!found)
diff --git a/SOURCES/glibc-rh1749439-12.patch b/SOURCES/glibc-rh1749439-12.patch
new file mode 100644
index 0000000..0308708
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-12.patch
@@ -0,0 +1,114 @@
+commit fed33b0fb03d1942a6713286176d42869c0f1580
+Author: Leandro Pereira <leandro.pereira@microsoft.com>
+Date:   Wed Oct 2 12:42:28 2019 -0400
+
+    Add nocancel version of pread64()
+    
+    This is in preparation for changes in the dynamic linker so that
+    pread() is used instead of lseek()+read().
+    
+    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+
+Conflicts:
+	sysdeps/unix/sysv/linux/Makefile
+	  (Textual conflict in routines list.)
+
+diff --git a/sysdeps/generic/not-cancel.h b/sysdeps/generic/not-cancel.h
+index d9f8a75dbda85ed5..260e6e4081f5fe16 100644
+--- a/sysdeps/generic/not-cancel.h
++++ b/sysdeps/generic/not-cancel.h
+@@ -41,6 +41,8 @@
+   (void) __close (fd)
+ #define __read_nocancel(fd, buf, n) \
+   __read (fd, buf, n)
++#define __pread64_nocancel(fd, buf, count, offset) \
++  __pread64 (fd, buf, count, offset)
+ #define __write_nocancel(fd, buf, n) \
+   __write (fd, buf, n)
+ #define __writev_nocancel_nostatus(fd, iov, n) \
+diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
+index 773aaea0e980bdd6..fb4ccd63ddec7eca 100644
+--- a/sysdeps/unix/sysv/linux/Makefile
++++ b/sysdeps/unix/sysv/linux/Makefile
+@@ -174,7 +174,8 @@ sysdep_routines += xstatconv internal_statvfs internal_statvfs64 \
+ 		   close_nocancel fcntl_nocancel nanosleep_nocancel \
+ 		   open_nocancel open64_nocancel \
+ 		   openat_nocancel openat64_nocancel \
+-		   pause_nocancel read_nocancel waitpid_nocancel write_nocancel
++		   pause_nocancel read_nocancel pread64_nocancel \
++		   waitpid_nocancel write_nocancel
+ 
+ sysdep_headers += bits/fcntl-linux.h
+ 
+diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
+index 336c13b57dba727a..95759bead1b0b3ca 100644
+--- a/sysdeps/unix/sysv/linux/Versions
++++ b/sysdeps/unix/sysv/linux/Versions
+@@ -176,6 +176,7 @@ libc {
+     __syscall_rt_sigqueueinfo;
+     __open_nocancel;
+     __read_nocancel;
++    __pread64_nocancel;
+     __close_nocancel;
+     __sigtimedwait;
+     # functions used by nscd
+diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h
+index 09de92dee9437d98..e58db475682a8c6a 100644
+--- a/sysdeps/unix/sysv/linux/not-cancel.h
++++ b/sysdeps/unix/sysv/linux/not-cancel.h
+@@ -43,6 +43,9 @@ __typeof (openat64) __openat64_nocancel;
+ /* Non cancellable read syscall.  */
+ __typeof (__read) __read_nocancel;
+ 
++/* Non cancellable pread syscall (LFS version).  */
++__typeof (__pread64) __pread64_nocancel;
++
+ /* Uncancelable write.  */
+ __typeof (__write) __write_nocancel;
+ 
+@@ -84,6 +87,7 @@ hidden_proto (__open64_nocancel)
+ hidden_proto (__openat_nocancel)
+ hidden_proto (__openat64_nocancel)
+ hidden_proto (__read_nocancel)
++hidden_proto (__pread64_nocancel)
+ hidden_proto (__write_nocancel)
+ hidden_proto (__close_nocancel)
+ hidden_proto (__waitpid_nocancel)
+diff --git a/sysdeps/unix/sysv/linux/pread64_nocancel.c b/sysdeps/unix/sysv/linux/pread64_nocancel.c
+new file mode 100644
+index 0000000000000000..dab61260e5db43b5
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/pread64_nocancel.c
+@@ -0,0 +1,32 @@
++/* Linux pread64() syscall implementation -- non-cancellable.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <unistd.h>
++#include <sysdep-cancel.h>
++#include <not-cancel.h>
++
++#ifndef __NR_pread64
++# define __NR_pread64 __NR_pread
++#endif
++
++ssize_t
++__pread64_nocancel (int fd, void *buf, size_t count, off64_t offset)
++{
++  return INLINE_SYSCALL_CALL (pread64, fd, buf, count, SYSCALL_LL64_PRW (offset));
++}
++hidden_def (__pread64_nocancel)
diff --git a/SOURCES/glibc-rh1749439-13.patch b/SOURCES/glibc-rh1749439-13.patch
new file mode 100644
index 0000000..333f1f6
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-13.patch
@@ -0,0 +1,307 @@
+commit d4625a19fe64f664119a541b317fb83de01bb273
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Tue Nov 12 12:25:49 2019 +0100
+
+    login: Use pread64 in utmp implementation
+    
+    This reduces the possible error scenarios considerably because
+    no longer can file seek fail, leaving the file descriptor in an
+    inconsistent state and out of sync with the cache.
+    
+    As a result, it is possible to avoid setting file_offset to -1
+    to make an error persistent.  Instead, subsequent calls will retry
+    the operation and report any errors returned by the kernel.
+    
+    This change also avoids reading the file from the start if pututline
+    is called multiple times, to work around lock acquisition failures
+    due to timeouts.
+    
+    Change-Id: If21ea0c162c38830a89331ea93cddec14c0974de
+
+diff --git a/login/utmp_file.c b/login/utmp_file.c
+index e653d14967c4fb7a..c828a28ac54c150e 100644
+--- a/login/utmp_file.c
++++ b/login/utmp_file.c
+@@ -162,12 +162,35 @@ maybe_setutent (void)
+   return file_fd >= 0 || __libc_setutent ();
+ }
+ 
++/* Reads the entry at file_offset, storing it in last_entry and
++   updating file_offset on success.  Returns -1 for a read error, 0
++   for EOF, and 1 for a successful read.  last_entry and file_offset
++   are only updated on a successful and complete read.  */
++static ssize_t
++read_last_entry (void)
++{
++  struct utmp buffer;
++  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer),
++				       file_offset);
++  if (nbytes < 0)
++    return -1;
++  else if (nbytes != sizeof (buffer))
++    /* Assume EOF.  */
++    return 0;
++  else
++    {
++      last_entry = buffer;
++      file_offset += sizeof (buffer);
++      return 1;
++    }
++}
++
+ int
+ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
+ {
+-  ssize_t nbytes;
++  int saved_errno = errno;
+ 
+-  if (!maybe_setutent () || file_offset == -1l)
++  if (!maybe_setutent ())
+     {
+       /* Not available.  */
+       *result = NULL;
+@@ -175,25 +198,22 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
+     }
+ 
+   if (try_file_lock (file_fd, F_RDLCK))
+-    nbytes = 0;
+-  else
+-    {
+-      /* Read the next entry.  */
+-      nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp));
+-      file_unlock (file_fd);
+-    }
++    return -1;
+ 
+-  if (nbytes != sizeof (struct utmp))
++  ssize_t nbytes = read_last_entry ();
++  file_unlock (file_fd);
++
++  if (nbytes <= 0)		/* Read error or EOF.  */
+     {
+-      if (nbytes != 0)
+-	file_offset = -1l;
++      if (nbytes == 0)
++	/* errno should be unchanged to indicate success.  A premature
++	   EOF is treated like an EOF (missing complete record at the
++	   end).  */
++	__set_errno (saved_errno);
+       *result = NULL;
+       return -1;
+     }
+ 
+-  /* Update position pointer.  */
+-  file_offset += sizeof (struct utmp);
+-
+   memcpy (buffer, &last_entry, sizeof (struct utmp));
+   *result = buffer;
+ 
+@@ -209,15 +229,15 @@ internal_getut_nolock (const struct utmp *id)
+ {
+   while (1)
+     {
+-      /* Read the next entry.  */
+-      if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp))
+-	  != sizeof (struct utmp))
++      ssize_t nbytes = read_last_entry ();
++      if (nbytes < 0)
++	return -1;
++      if (nbytes == 0)
+ 	{
++	  /* End of file reached.  */
+ 	  __set_errno (ESRCH);
+-	  file_offset = -1l;
+ 	  return -1;
+ 	}
+-      file_offset += sizeof (struct utmp);
+ 
+       if (matches_last_entry (id))
+ 	break;
+@@ -249,7 +269,7 @@ int
+ __libc_getutid_r (const struct utmp *id, struct utmp *buffer,
+ 		  struct utmp **result)
+ {
+-  if (!maybe_setutent () || file_offset == -1l)
++  if (!maybe_setutent ())
+     {
+       *result = NULL;
+       return -1;
+@@ -276,7 +296,7 @@ int
+ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+ 		    struct utmp **result)
+ {
+-  if (!maybe_setutent () || file_offset == -1l)
++  if (!maybe_setutent ())
+     {
+       *result = NULL;
+       return -1;
+@@ -290,16 +310,21 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+ 
+   while (1)
+     {
+-      /* Read the next entry.  */
+-      if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp))
+-	  != sizeof (struct utmp))
++      ssize_t nbytes = read_last_entry ();
++      if (nbytes < 0)
+ 	{
++	  file_unlock (file_fd);
++	  *result = NULL;
++	  return -1;
++	}
++      if (nbytes == 0)
++	{
++	  /* End of file reached.  */
++	  file_unlock (file_fd);
+ 	  __set_errno (ESRCH);
+-	  file_offset = -1l;
+ 	  *result = NULL;
+-	  goto unlock_return;
++	  return -1;
+ 	}
+-      file_offset += sizeof (struct utmp);
+ 
+       /* Stop if we found a user or login entry.  */
+       if ((last_entry.ut_type == USER_PROCESS
+@@ -309,20 +334,18 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+ 	break;
+     }
+ 
++  file_unlock (file_fd);
+   memcpy (buffer, &last_entry, sizeof (struct utmp));
+   *result = buffer;
+ 
+-unlock_return:
+-  file_unlock (file_fd);
+-
+-  return ((*result == NULL) ? -1 : 0);
++  return 0;
+ }
+ 
+ 
+ struct utmp *
+ __libc_pututline (const struct utmp *data)
+ {
+-  if (!maybe_setutent () || file_offset == -1l)
++  if (!maybe_setutent ())
+     return NULL;
+ 
+   struct utmp *pbuf;
+@@ -337,8 +360,7 @@ __libc_pututline (const struct utmp *data)
+       if (new_fd == -1)
+ 	return NULL;
+ 
+-      if (__lseek64 (new_fd, __lseek64 (file_fd, 0, SEEK_CUR), SEEK_SET) == -1
+-	  || __dup2 (new_fd, file_fd) < 0)
++      if (__dup2 (new_fd, file_fd) < 0)
+ 	{
+ 	  __close_nocancel_nostatus (new_fd);
+ 	  return NULL;
+@@ -355,69 +377,70 @@ __libc_pututline (const struct utmp *data)
+   bool found = false;
+   if (matches_last_entry (data))
+     {
+-      if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0)
++      /* Read back the entry under the write lock.  */
++      file_offset -= sizeof (last_entry);
++      ssize_t nbytes = read_last_entry ();
++      if (nbytes < 0)
+ 	{
+ 	  file_unlock (file_fd);
+ 	  return NULL;
+ 	}
+-      if (__read_nocancel (file_fd, &last_entry, sizeof (last_entry))
+-	  != sizeof (last_entry))
+-	{
+-	  if (__lseek64 (file_fd, file_offset, SEEK_SET) < 0)
+-	    {
+-	      file_unlock (file_fd);
+-	      return NULL;
+-	    }
+-	  found = false;
+-	}
++
++      if (nbytes == 0)
++	/* End of file reached.  */
++	found = false;
+       else
+ 	found = matches_last_entry (data);
+     }
+ 
+   if (!found)
++    /* Search forward for the entry.  */
+     found = internal_getut_nolock (data) >= 0;
+ 
++  off64_t write_offset;
+   if (!found)
+     {
+       /* We append the next entry.  */
+-      file_offset = __lseek64 (file_fd, 0, SEEK_END);
+-      if (file_offset % sizeof (struct utmp) != 0)
+-	{
+-	  file_offset -= file_offset % sizeof (struct utmp);
+-	  __ftruncate64 (file_fd, file_offset);
+-
+-	  if (__lseek64 (file_fd, 0, SEEK_END) < 0)
+-	    {
+-	      pbuf = NULL;
+-	      goto unlock_return;
+-	    }
+-	}
++      write_offset = __lseek64 (file_fd, 0, SEEK_END);
++
++      /* Round down to the next multiple of the entry size.  This
++	 ensures any partially-written record is overwritten by the
++	 new record.  */
++      write_offset = (write_offset / sizeof (struct utmp)
++		      * sizeof (struct utmp));
+     }
+   else
++    /* Overwrite last_entry.  */
++    write_offset = file_offset - sizeof (struct utmp);
++
++  /* Write the new data.  */
++  ssize_t nbytes;
++  if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0
++      || (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0)
+     {
+-      /* We replace the just read entry.  */
+-      file_offset -= sizeof (struct utmp);
+-      __lseek64 (file_fd, file_offset, SEEK_SET);
++      /* There is no need to recover the file position because all
++	 reads use pread64, and any future write is preceded by
++	 another seek.  */
++      file_unlock (file_fd);
++      return NULL;
+     }
+ 
+-  /* Write the new data.  */
+-  if (__write_nocancel (file_fd, data, sizeof (struct utmp))
+-      != sizeof (struct utmp))
++  if (nbytes != sizeof (struct utmp))
+     {
+       /* If we appended a new record this is only partially written.
+ 	 Remove it.  */
+       if (!found)
+-	(void) __ftruncate64 (file_fd, file_offset);
+-      pbuf = NULL;
+-    }
+-  else
+-    {
+-      file_offset += sizeof (struct utmp);
+-      pbuf = (struct utmp *) data;
++	(void) __ftruncate64 (file_fd, write_offset);
++      file_unlock (file_fd);
++      /* Assume that the write failure was due to missing disk
++	 space.  */
++      __set_errno (ENOSPC);
++      return NULL;
+     }
+ 
+- unlock_return:
+   file_unlock (file_fd);
++  file_offset = write_offset + sizeof (struct utmp);
++  pbuf = (struct utmp *) data;
+ 
+   return pbuf;
+ }
diff --git a/SOURCES/glibc-rh1749439-2.patch b/SOURCES/glibc-rh1749439-2.patch
new file mode 100644
index 0000000..f00334c
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-2.patch
@@ -0,0 +1,676 @@
+commit a33b817f13170b5c24263b92e7e09880fe797d7e
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Tue Aug 13 12:09:32 2019 +0200
+
+    login: Assume that _HAVE_UT_* constants are true
+    
+    Make the GNU version of bits/utmp.h the generic version because
+    all remaining ports use it (with a sysdeps override for
+    Linux s390/s390x).
+
+Conflicts:
+	bits/utmp.h
+	sysdeps/gnu/bits/utmp.h
+	  (Upstream copyright year change.)
+
+diff --git a/bits/utmp.h b/bits/utmp.h
+index 6e8695fbf072e5f1..3c02dd4f3fe4e99b 100644
+--- a/bits/utmp.h
++++ b/bits/utmp.h
+@@ -1,5 +1,5 @@
+-/* The `struct utmp' type, describing entries in the utmp file.  Generic/BSDish
+-   Copyright (C) 1993-2018 Free Software Foundation, Inc.
++/* The `struct utmp' type, describing entries in the utmp file.
++   Copyright (C) 1993-2019 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
+@@ -21,29 +21,106 @@
+ #endif
+ 
+ #include <paths.h>
+-#include <time.h>
++#include <sys/time.h>
++#include <sys/types.h>
++#include <bits/wordsize.h>
+ 
+ 
+-#define	UT_NAMESIZE	8
+-#define	UT_LINESIZE	8
+-#define	UT_HOSTSIZE	16
++#define UT_LINESIZE	32
++#define UT_NAMESIZE	32
++#define UT_HOSTSIZE	256
+ 
+ 
++/* The structure describing an entry in the database of
++   previous logins.  */
+ struct lastlog
+   {
+-    time_t ll_time;
++#if __WORDSIZE_TIME64_COMPAT32
++    int32_t ll_time;
++#else
++    __time_t ll_time;
++#endif
+     char ll_line[UT_LINESIZE];
+     char ll_host[UT_HOSTSIZE];
+   };
+ 
+-struct utmp
++
++/* The structure describing the status of a terminated process.  This
++   type is used in `struct utmp' below.  */
++struct exit_status
+   {
+-    char ut_line[UT_LINESIZE];
+-    char ut_user[UT_NAMESIZE];
+-#define ut_name ut_user
+-    char ut_host[UT_HOSTSIZE];
+-    long int ut_time;
++    short int e_termination;	/* Process termination status.  */
++    short int e_exit;		/* Process exit status.  */
+   };
+ 
+ 
+-#define _HAVE_UT_HOST 1		/* We have the ut_host field.  */
++/* The structure describing an entry in the user accounting database.  */
++struct utmp
++{
++  short int ut_type;		/* Type of login.  */
++  pid_t ut_pid;			/* Process ID of login process.  */
++  char ut_line[UT_LINESIZE]
++    __attribute_nonstring__;	/* Devicename.  */
++  char ut_id[4];		/* Inittab ID.  */
++  char ut_user[UT_NAMESIZE]
++    __attribute_nonstring__;	/* Username.  */
++  char ut_host[UT_HOSTSIZE]
++    __attribute_nonstring__;	/* Hostname for remote login.  */
++  struct exit_status ut_exit;	/* Exit status of a process marked
++				   as DEAD_PROCESS.  */
++/* The ut_session and ut_tv fields must be the same size when compiled
++   32- and 64-bit.  This allows data files and shared memory to be
++   shared between 32- and 64-bit applications.  */
++#if __WORDSIZE_TIME64_COMPAT32
++  int32_t ut_session;		/* Session ID, used for windowing.  */
++  struct
++  {
++    int32_t tv_sec;		/* Seconds.  */
++    int32_t tv_usec;		/* Microseconds.  */
++  } ut_tv;			/* Time entry was made.  */
++#else
++  long int ut_session;		/* Session ID, used for windowing.  */
++  struct timeval ut_tv;		/* Time entry was made.  */
++#endif
++
++  int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
++  char __glibc_reserved[20];		/* Reserved for future use.  */
++};
++
++/* Backwards compatibility hacks.  */
++#define ut_name		ut_user
++#ifndef _NO_UT_TIME
++/* We have a problem here: `ut_time' is also used otherwise.  Define
++   _NO_UT_TIME if the compiler complains.  */
++# define ut_time	ut_tv.tv_sec
++#endif
++#define ut_xtime	ut_tv.tv_sec
++#define ut_addr		ut_addr_v6[0]
++
++
++/* Values for the `ut_type' field of a `struct utmp'.  */
++#define EMPTY		0	/* No valid user accounting information.  */
++
++#define RUN_LVL		1	/* The system's runlevel.  */
++#define BOOT_TIME	2	/* Time of system boot.  */
++#define NEW_TIME	3	/* Time after system clock changed.  */
++#define OLD_TIME	4	/* Time when system clock changed.  */
++
++#define INIT_PROCESS	5	/* Process spawned by the init process.  */
++#define LOGIN_PROCESS	6	/* Session leader of a logged in user.  */
++#define USER_PROCESS	7	/* Normal process.  */
++#define DEAD_PROCESS	8	/* Terminated process.  */
++
++#define ACCOUNTING	9
++
++/* Old Linux name for the EMPTY type.  */
++#define UT_UNKNOWN	EMPTY
++
++
++/* Tell the user that we have a modern system with UT_HOST, UT_PID,
++   UT_TYPE, UT_ID and UT_TV fields.  */
++#define _HAVE_UT_TYPE	1
++#define _HAVE_UT_PID	1
++#define _HAVE_UT_ID	1
++#define _HAVE_UT_TV	1
++#define _HAVE_UT_HOST	1
+diff --git a/login/getutid_r.c b/login/getutid_r.c
+index 8cb6b16d735e8265..11b288e99be6ee50 100644
+--- a/login/getutid_r.c
++++ b/login/getutid_r.c
+@@ -32,7 +32,6 @@ __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
+ int
+ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
+ {
+-#if (_HAVE_UT_ID - 0) && (_HAVE_UT_TYPE - 0)
+   int retval;
+ 
+   /* Test whether ID has any of the legal types.  */
+@@ -54,10 +53,6 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
+   __libc_lock_unlock (__libc_utmp_lock);
+ 
+   return retval;
+-#else	/* !_HAVE_UT_ID && !_HAVE_UT_TYPE */
+-  __set_errno (ENOSYS);
+-  return -1;
+-#endif
+ }
+ libc_hidden_def (__getutid_r)
+ weak_alias (__getutid_r, getutid_r)
+diff --git a/login/getutmp.c b/login/getutmp.c
+index 481150d5ef5a0bf0..32468ecae699fbf7 100644
+--- a/login/getutmp.c
++++ b/login/getutmp.c
+@@ -23,23 +23,11 @@
+ void
+ getutmp (const struct utmpx *utmpx, struct utmp *utmp)
+ {
+-#if _HAVE_UT_TYPE - 0
+   utmp->ut_type = utmpx->ut_type;
+-#endif
+-#if _HAVE_UT_PID - 0
+   utmp->ut_pid = utmpx->ut_pid;
+-#endif
+   memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line));
+   memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user));
+-#if _HAVE_UT_ID - 0
+   memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id));
+-#endif
+-#if _HAVE_UT_HOST - 0
+   memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host));
+-#endif
+-#if _HAVE_UT_TV - 0
+   utmp->ut_tv = utmpx->ut_tv;
+-#else
+-  utmp->ut_time = utmpx->ut_time;
+-#endif
+ }
+diff --git a/login/getutmpx.c b/login/getutmpx.c
+index 34145fe8db71faf0..92a182698e2be438 100644
+--- a/login/getutmpx.c
++++ b/login/getutmpx.c
+@@ -24,24 +24,11 @@ void
+ getutmpx (const struct utmp *utmp, struct utmpx *utmpx)
+ {
+   memset (utmpx, 0, sizeof (struct utmpx));
+-
+-#if _HAVE_UT_TYPE - 0
+   utmpx->ut_type = utmp->ut_type;
+-#endif
+-#if _HAVE_UT_PID - 0
+   utmpx->ut_pid = utmp->ut_pid;
+-#endif
+   memcpy (utmpx->ut_line, utmp->ut_line, sizeof (utmp->ut_line));
+   memcpy (utmpx->ut_user, utmp->ut_user, sizeof (utmp->ut_user));
+-#if _HAVE_UT_ID - 0
+   memcpy (utmpx->ut_id, utmp->ut_id, sizeof (utmp->ut_id));
+-#endif
+-#if _HAVE_UT_HOST - 0
+   memcpy (utmpx->ut_host, utmp->ut_host, sizeof (utmp->ut_host));
+-#endif
+-#if _HAVE_UT_TV - 0
+   utmpx->ut_tv = utmp->ut_tv;
+-#else
+-  utmpx->ut_time = utmp->ut_time;
+-#endif
+ }
+diff --git a/login/login.c b/login/login.c
+index 5d48cd487f237ca0..1729fc070fcc1e4b 100644
+--- a/login/login.c
++++ b/login/login.c
+@@ -91,12 +91,8 @@ login (const struct utmp *ut)
+   struct utmp copy = *ut;
+ 
+   /* Fill in those fields we supply.  */
+-#if _HAVE_UT_TYPE - 0
+   copy.ut_type = USER_PROCESS;
+-#endif
+-#if _HAVE_UT_PID - 0
+   copy.ut_pid = getpid ();
+-#endif
+ 
+   /* Seek tty.  */
+   found_tty = tty_name (STDIN_FILENO, &tty, sizeof (_tty));
+diff --git a/login/logout.c b/login/logout.c
+index d49bc4ecac9a8379..4d76ecf1b40d306a 100644
+--- a/login/logout.c
++++ b/login/logout.c
+@@ -36,9 +36,7 @@ logout (const char *line)
+   setutent ();
+ 
+   /* Fill in search information.  */
+-#if _HAVE_UT_TYPE - 0
+   tmp.ut_type = USER_PROCESS;
+-#endif
+   strncpy (tmp.ut_line, line, sizeof tmp.ut_line);
+ 
+   /* Read the record.  */
+@@ -46,20 +44,12 @@ logout (const char *line)
+     {
+       /* Clear information about who & from where.  */
+       memset (ut->ut_name, '\0', sizeof ut->ut_name);
+-#if _HAVE_UT_HOST - 0
+       memset (ut->ut_host, '\0', sizeof ut->ut_host);
+-#endif
+-#if _HAVE_UT_TV - 0
+       struct timeval tv;
+       __gettimeofday (&tv, NULL);
+       ut->ut_tv.tv_sec = tv.tv_sec;
+       ut->ut_tv.tv_usec = tv.tv_usec;
+-#else
+-      ut->ut_time = time (NULL);
+-#endif
+-#if _HAVE_UT_TYPE - 0
+       ut->ut_type = DEAD_PROCESS;
+-#endif
+ 
+       if (pututline (ut) != NULL)
+ 	result = 1;
+diff --git a/login/logwtmp.c b/login/logwtmp.c
+index a19da4ab5ef7a624..e0b52b23e3603b7c 100644
+--- a/login/logwtmp.c
++++ b/login/logwtmp.c
+@@ -30,26 +30,16 @@ logwtmp (const char *line, const char *name, const char *host)
+ 
+   /* Set information in new entry.  */
+   memset (&ut, 0, sizeof (ut));
+-#if _HAVE_UT_PID - 0
+   ut.ut_pid = getpid ();
+-#endif
+-#if _HAVE_UT_TYPE - 0
+   ut.ut_type = name[0] ? USER_PROCESS : DEAD_PROCESS;
+-#endif
+   strncpy (ut.ut_line, line, sizeof ut.ut_line);
+   strncpy (ut.ut_name, name, sizeof ut.ut_name);
+-#if _HAVE_UT_HOST - 0
+   strncpy (ut.ut_host, host, sizeof ut.ut_host);
+-#endif
+ 
+-#if _HAVE_UT_TV - 0
+   struct timeval tv;
+   __gettimeofday (&tv, NULL);
+   ut.ut_tv.tv_sec = tv.tv_sec;
+   ut.ut_tv.tv_usec = tv.tv_usec;
+-#else
+-  ut.ut_time = time (NULL);
+-#endif
+ 
+   updwtmp (_PATH_WTMP, &ut);
+ }
+diff --git a/login/programs/utmpdump.c b/login/programs/utmpdump.c
+index dccdb669f5fb9c74..1763e55af2f03d8d 100644
+--- a/login/programs/utmpdump.c
++++ b/login/programs/utmpdump.c
+@@ -37,47 +37,11 @@ print_entry (struct utmp *up)
+   temp_tv.tv_sec = up->ut_tv.tv_sec;
+   temp_tv.tv_usec = up->ut_tv.tv_usec;
+ 
+-  (printf) (
+-	    /* The format string.  */
+-#if _HAVE_UT_TYPE
+-	    "[%d] "
+-#endif
+-#if _HAVE_UT_PID
+-	    "[%05d] "
+-#endif
+-#if _HAVE_UT_ID
+-	    "[%-4.4s] "
+-#endif
+-	    "[%-8.8s] [%-12.12s]"
+-#if _HAVE_UT_HOST
+-	    " [%-16.16s]"
+-#endif
+-	    " [%-15.15s]"
+-#if _HAVE_UT_TV
+-	    " [%ld]"
+-#endif
+-	    "\n"
+-	    /* The arguments.  */
+-#if _HAVE_UT_TYPE
+-	    , up->ut_type
+-#endif
+-#if _HAVE_UT_PID
+-	    , up->ut_pid
+-#endif
+-#if _HAVE_UT_ID
+-	    , up->ut_id
+-#endif
+-	    , up->ut_user, up->ut_line
+-#if _HAVE_UT_HOST
+-	    , up->ut_host
+-#endif
+-#if _HAVE_UT_TV
+-	    , 4 + ctime (&temp_tv.tv_sec)
+-	    , (long int) temp_tv.tv_usec
+-#else
+-	    , 4 + ctime (&up->ut_time)
+-#endif
+-	   );
++  printf ("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-16.16s] [%-15.15s]"
++	  " [%ld]\n",
++	  up->ut_type, up->ut_pid, up->ut_id, up->ut_user, up->ut_line,
++	  up->ut_host, 4 + ctime (&temp_tv.tv_sec),
++	  (long int) temp_tv.tv_usec);
+ }
+ 
+ int
+diff --git a/login/tst-utmp.c b/login/tst-utmp.c
+index 8cc7aafa89c0ea8c..49b0cbda2a719643 100644
+--- a/login/tst-utmp.c
++++ b/login/tst-utmp.c
+@@ -39,8 +39,6 @@
+ #endif
+ 
+ 
+-#if defined UTMPX || _HAVE_UT_TYPE
+-
+ /* Prototype for our test function.  */
+ static int do_test (int argc, char *argv[]);
+ 
+@@ -75,11 +73,7 @@ do_prepare (int argc, char *argv[])
+ 
+ struct utmp entry[] =
+ {
+-#if defined UTMPX || _HAVE_UT_TV
+ #define UT(a)  .ut_tv = { .tv_sec = (a)}
+-#else
+-#define UT(a)  .ut_time = (a)
+-#endif
+ 
+   { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+   { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+@@ -167,11 +161,7 @@ simulate_login (const char *line, const char *user)
+ 	    entry[n].ut_pid = (entry_pid += 27);
+ 	  entry[n].ut_type = USER_PROCESS;
+ 	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+-#if defined UTMPX || _HAVE_UT_TV - 0
+ 	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+-#else
+-          entry[n].ut_time = (entry_time += 1000);
+-#endif
+ 	  setutent ();
+ 
+ 	  if (pututline (&entry[n]) == NULL)
+@@ -201,11 +191,7 @@ simulate_logout (const char *line)
+ 	{
+ 	  entry[n].ut_type = DEAD_PROCESS;
+ 	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+-#if defined UTMPX || _HAVE_UT_TV - 0
+           entry[n].ut_tv.tv_sec = (entry_time += 1000);
+-#else
+-          entry[n].ut_time = (entry_time += 1000);
+-#endif
+ 	  setutent ();
+ 
+ 	  if (pututline (&entry[n]) == NULL)
+@@ -390,14 +376,3 @@ do_test (int argc, char *argv[])
+ 
+   return result;
+ }
+-
+-#else
+-
+-/* No field 'ut_type' in struct utmp.  */
+-int
+-main (void)
+-{
+-  return 0;
+-}
+-
+-#endif
+diff --git a/login/utmp_file.c b/login/utmp_file.c
+index 069e6d0452e333ad..da1baa6948d0eb39 100644
+--- a/login/utmp_file.c
++++ b/login/utmp_file.c
+@@ -129,14 +129,7 @@ __libc_setutent (void)
+   file_offset = 0;
+ 
+   /* Make sure the entry won't match.  */
+-#if _HAVE_UT_TYPE - 0
+   last_entry.ut_type = -1;
+-#else
+-  last_entry.ut_line[0] = '\177';
+-# if _HAVE_UT_ID - 0
+-  last_entry.ut_id[0] = '\0';
+-# endif
+-#endif
+ 
+   return 1;
+ }
+@@ -201,7 +194,6 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer,
+       LOCKING_FAILED ();
+     }
+ 
+-#if _HAVE_UT_TYPE - 0
+   if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
+       || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
+     {
+@@ -225,7 +217,6 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer,
+ 	}
+     }
+   else
+-#endif /* _HAVE_UT_TYPE */
+     {
+       /* Search for the next entry with the specified ID and with type
+ 	 INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS.  */
+@@ -316,13 +307,10 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+       file_offset += sizeof (struct utmp);
+ 
+       /* Stop if we found a user or login entry.  */
+-      if (
+-#if _HAVE_UT_TYPE - 0
+-	  (last_entry.ut_type == USER_PROCESS
++      if ((last_entry.ut_type == USER_PROCESS
+ 	   || last_entry.ut_type == LOGIN_PROCESS)
+-	  &&
+-#endif
+-	  !strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line))
++	  && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)
++	      == 0))
+ 	break;
+     }
+ 
+@@ -368,16 +356,12 @@ __libc_pututline (const struct utmp *data)
+ 
+   /* Find the correct place to insert the data.  */
+   if (file_offset > 0
+-      && (
+-#if _HAVE_UT_TYPE - 0
+-	  (last_entry.ut_type == data->ut_type
++      && ((last_entry.ut_type == data->ut_type
+ 	   && (last_entry.ut_type == RUN_LVL
+ 	       || last_entry.ut_type == BOOT_TIME
+ 	       || last_entry.ut_type == OLD_TIME
+ 	       || last_entry.ut_type == NEW_TIME))
+-	  ||
+-#endif
+-	  __utmp_equal (&last_entry, data)))
++	  || __utmp_equal (&last_entry, data)))
+     found = 1;
+   else
+     {
+diff --git a/sysdeps/generic/utmp-equal.h b/sysdeps/generic/utmp-equal.h
+index 8b5c2e2cd2c4cf95..39993af192ab66ce 100644
+--- a/sysdeps/generic/utmp-equal.h
++++ b/sysdeps/generic/utmp-equal.h
+@@ -27,26 +27,16 @@
+ static int
+ __utmp_equal (const struct utmp *entry, const struct utmp *match)
+ {
+-  return
+-    (
+-#if _HAVE_UT_TYPE - 0
+-     (entry->ut_type == INIT_PROCESS
+-      || entry->ut_type == LOGIN_PROCESS
+-      || entry->ut_type == USER_PROCESS
+-      || entry->ut_type == DEAD_PROCESS)
+-     &&
+-     (match->ut_type == INIT_PROCESS
+-      || match->ut_type == LOGIN_PROCESS
+-      || match->ut_type == USER_PROCESS
+-      || match->ut_type == DEAD_PROCESS)
+-     &&
+-#endif
+-#if _HAVE_UT_ID - 0
+-     (entry->ut_id[0] && match->ut_id[0]
+-      ? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
+-      : strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0)
+-#else
+-     strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
+-#endif
+-     );
++  return (entry->ut_type == INIT_PROCESS
++          || entry->ut_type == LOGIN_PROCESS
++          || entry->ut_type == USER_PROCESS
++          || entry->ut_type == DEAD_PROCESS)
++    && (match->ut_type == INIT_PROCESS
++        || match->ut_type == LOGIN_PROCESS
++        || match->ut_type == USER_PROCESS
++        || match->ut_type == DEAD_PROCESS)
++    && (entry->ut_id[0] && match->ut_id[0]
++        ? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
++        : (strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line)
++           == 0));
+ }
+diff --git a/sysdeps/gnu/bits/utmp.h b/sysdeps/gnu/bits/utmp.h
+deleted file mode 100644
+index 47a6082eacc56b4d..0000000000000000
+--- a/sysdeps/gnu/bits/utmp.h
++++ /dev/null
+@@ -1,126 +0,0 @@
+-/* The `struct utmp' type, describing entries in the utmp file.  GNU version.
+-   Copyright (C) 1993-2018 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
+-   <http://www.gnu.org/licenses/>.  */
+-
+-#ifndef _UTMP_H
+-# error "Never include <bits/utmp.h> directly; use <utmp.h> instead."
+-#endif
+-
+-#include <paths.h>
+-#include <sys/time.h>
+-#include <sys/types.h>
+-#include <bits/wordsize.h>
+-
+-
+-#define UT_LINESIZE	32
+-#define UT_NAMESIZE	32
+-#define UT_HOSTSIZE	256
+-
+-
+-/* The structure describing an entry in the database of
+-   previous logins.  */
+-struct lastlog
+-  {
+-#if __WORDSIZE_TIME64_COMPAT32
+-    int32_t ll_time;
+-#else
+-    __time_t ll_time;
+-#endif
+-    char ll_line[UT_LINESIZE];
+-    char ll_host[UT_HOSTSIZE];
+-  };
+-
+-
+-/* The structure describing the status of a terminated process.  This
+-   type is used in `struct utmp' below.  */
+-struct exit_status
+-  {
+-    short int e_termination;	/* Process termination status.  */
+-    short int e_exit;		/* Process exit status.  */
+-  };
+-
+-
+-/* The structure describing an entry in the user accounting database.  */
+-struct utmp
+-{
+-  short int ut_type;		/* Type of login.  */
+-  pid_t ut_pid;			/* Process ID of login process.  */
+-  char ut_line[UT_LINESIZE]
+-    __attribute_nonstring__;	/* Devicename.  */
+-  char ut_id[4];		/* Inittab ID.  */
+-  char ut_user[UT_NAMESIZE]
+-    __attribute_nonstring__;	/* Username.  */
+-  char ut_host[UT_HOSTSIZE]
+-    __attribute_nonstring__;	/* Hostname for remote login.  */
+-  struct exit_status ut_exit;	/* Exit status of a process marked
+-				   as DEAD_PROCESS.  */
+-/* The ut_session and ut_tv fields must be the same size when compiled
+-   32- and 64-bit.  This allows data files and shared memory to be
+-   shared between 32- and 64-bit applications.  */
+-#if __WORDSIZE_TIME64_COMPAT32
+-  int32_t ut_session;		/* Session ID, used for windowing.  */
+-  struct
+-  {
+-    int32_t tv_sec;		/* Seconds.  */
+-    int32_t tv_usec;		/* Microseconds.  */
+-  } ut_tv;			/* Time entry was made.  */
+-#else
+-  long int ut_session;		/* Session ID, used for windowing.  */
+-  struct timeval ut_tv;		/* Time entry was made.  */
+-#endif
+-
+-  int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
+-  char __glibc_reserved[20];		/* Reserved for future use.  */
+-};
+-
+-/* Backwards compatibility hacks.  */
+-#define ut_name		ut_user
+-#ifndef _NO_UT_TIME
+-/* We have a problem here: `ut_time' is also used otherwise.  Define
+-   _NO_UT_TIME if the compiler complains.  */
+-# define ut_time	ut_tv.tv_sec
+-#endif
+-#define ut_xtime	ut_tv.tv_sec
+-#define ut_addr		ut_addr_v6[0]
+-
+-
+-/* Values for the `ut_type' field of a `struct utmp'.  */
+-#define EMPTY		0	/* No valid user accounting information.  */
+-
+-#define RUN_LVL		1	/* The system's runlevel.  */
+-#define BOOT_TIME	2	/* Time of system boot.  */
+-#define NEW_TIME	3	/* Time after system clock changed.  */
+-#define OLD_TIME	4	/* Time when system clock changed.  */
+-
+-#define INIT_PROCESS	5	/* Process spawned by the init process.  */
+-#define LOGIN_PROCESS	6	/* Session leader of a logged in user.  */
+-#define USER_PROCESS	7	/* Normal process.  */
+-#define DEAD_PROCESS	8	/* Terminated process.  */
+-
+-#define ACCOUNTING	9
+-
+-/* Old Linux name for the EMPTY type.  */
+-#define UT_UNKNOWN	EMPTY
+-
+-
+-/* Tell the user that we have a modern system with UT_HOST, UT_PID,
+-   UT_TYPE, UT_ID and UT_TV fields.  */
+-#define _HAVE_UT_TYPE	1
+-#define _HAVE_UT_PID	1
+-#define _HAVE_UT_ID	1
+-#define _HAVE_UT_TV	1
+-#define _HAVE_UT_HOST	1
diff --git a/SOURCES/glibc-rh1749439-3.patch b/SOURCES/glibc-rh1749439-3.patch
new file mode 100644
index 0000000..7a18d19
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-3.patch
@@ -0,0 +1,260 @@
+commit 5a3afa9738f3dbbaf8c0a35665318c1af782111b
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Tue Aug 13 15:53:19 2019 +0200
+
+    login: Replace macro-based control flow with function calls in utmp
+
+diff --git a/login/utmp_file.c b/login/utmp_file.c
+index da1baa6948d0eb39..812de8fd3d099ce9 100644
+--- a/login/utmp_file.c
++++ b/login/utmp_file.c
+@@ -52,58 +52,71 @@ static struct utmp last_entry;
+ /* Do-nothing handler for locking timeout.  */
+ static void timeout_handler (int signum) {};
+ 
+-/* LOCK_FILE(fd, type) failure_statement
+-     attempts to get a lock on the utmp file referenced by FD.  If it fails,
+-     the failure_statement is executed, otherwise it is skipped.
+-   LOCKING_FAILED()
+-     jumps into the UNLOCK_FILE macro and ensures cleanup of LOCK_FILE.
+-   UNLOCK_FILE(fd)
+-     unlocks the utmp file referenced by FD and performs the cleanup of
+-     LOCK_FILE.
+- */
+-#define LOCK_FILE(fd, type) \
+-{									      \
+-  struct flock fl;							      \
+-  struct sigaction action, old_action;					      \
+-  unsigned int old_timeout;						      \
+-									      \
+-  /* Cancel any existing alarm.  */					      \
+-  old_timeout = alarm (0);						      \
+-									      \
+-  /* Establish signal handler.  */					      \
+-  action.sa_handler = timeout_handler;					      \
+-  __sigemptyset (&action.sa_mask);					      \
+-  action.sa_flags = 0;							      \
+-  __sigaction (SIGALRM, &action, &old_action);				      \
+-									      \
+-  alarm (TIMEOUT);							      \
+-									      \
+-  /* Try to get the lock.  */						      \
+-  memset (&fl, '\0', sizeof (struct flock));				      \
+-  fl.l_type = (type);							      \
+-  fl.l_whence = SEEK_SET;						      \
+-  if (__fcntl64_nocancel ((fd), F_SETLKW, &fl) < 0)
+-
+-#define LOCKING_FAILED() \
+-  goto unalarm_return
+-
+-#define UNLOCK_FILE(fd) \
+-  /* Unlock the file.  */						      \
+-  fl.l_type = F_UNLCK;							      \
+-  __fcntl64_nocancel ((fd), F_SETLKW, &fl);				      \
+-									      \
+- unalarm_return:							      \
+-  /* Reset the signal handler and alarm.  We must reset the alarm	      \
+-     before resetting the handler so our alarm does not generate a	      \
+-     spurious SIGALRM seen by the user.  However, we cannot just set	      \
+-     the user's old alarm before restoring the handler, because then	      \
+-     it's possible our handler could catch the user alarm's SIGARLM	      \
+-     and then the user would never see the signal he expected.  */	      \
+-  alarm (0);								      \
+-  __sigaction (SIGALRM, &old_action, NULL);				      \
+-  if (old_timeout != 0)							      \
+-    alarm (old_timeout);						      \
+-} while (0)
++
++/* try_file_lock (LOCKING, FD, TYPE) returns true if the locking
++   operation failed and recovery needs to be performed.
++   (file_lock_restore (LOCKING) still needs to be called.)
++
++   file_unlock (FD) removes the lock (which must have been
++   acquired).
++
++   file_lock_restore (LOCKING) is needed to clean up in both
++   cases.  */
++
++struct file_locking
++{
++  struct sigaction old_action;
++  unsigned int old_timeout;
++};
++
++static bool
++try_file_lock (struct file_locking *locking, int fd, int type)
++{
++  /* Cancel any existing alarm.  */
++  locking->old_timeout = alarm (0);
++
++  /* Establish signal handler.  */
++  struct sigaction action;
++  action.sa_handler = timeout_handler;
++  __sigemptyset (&action.sa_mask);
++  action.sa_flags = 0;
++  __sigaction (SIGALRM, &action, &locking->old_action);
++
++  alarm (TIMEOUT);
++
++  /* Try to get the lock.  */
++ struct flock fl =
++   {
++    .l_type = type,
++    fl.l_whence = SEEK_SET,
++   };
++ return __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0;
++}
++
++static void
++file_unlock (int fd)
++{
++  struct flock fl =
++    {
++      .l_type = F_UNLCK,
++    };
++  __fcntl64_nocancel (fd, F_SETLKW, &fl);
++}
++
++static void
++file_lock_restore (struct file_locking *locking)
++{
++  /* Reset the signal handler and alarm.  We must reset the alarm
++     before resetting the handler so our alarm does not generate a
++     spurious SIGALRM seen by the user.  However, we cannot just set
++     the user's old alarm before restoring the handler, because then
++     it's possible our handler could catch the user alarm's SIGARLM
++     and then the user would never see the signal he expected.  */
++  alarm (0);
++  __sigaction (SIGALRM, &locking->old_action, NULL);
++  if (locking->old_timeout != 0)
++    alarm (locking->old_timeout);
++}
+ 
+ #ifndef TRANSFORM_UTMP_FILE_NAME
+ # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name)
+@@ -153,16 +166,16 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
+       return -1;
+     }
+ 
+-  LOCK_FILE (file_fd, F_RDLCK)
++  struct file_locking fl;
++  if (try_file_lock (&fl, file_fd, F_RDLCK))
++    nbytes = 0;
++  else
+     {
+-      nbytes = 0;
+-      LOCKING_FAILED ();
++      /* Read the next entry.  */
++      nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp));
++      file_unlock (file_fd);
+     }
+-
+-  /* Read the next entry.  */
+-  nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp));
+-
+-  UNLOCK_FILE (file_fd);
++  file_lock_restore (&fl);
+ 
+   if (nbytes != sizeof (struct utmp))
+     {
+@@ -188,10 +201,12 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer,
+ {
+   int result = -1;
+ 
+-  LOCK_FILE (file_fd, F_RDLCK)
++  struct file_locking fl;
++  if (try_file_lock (&fl, file_fd, F_RDLCK))
+     {
+       *lock_failed = true;
+-      LOCKING_FAILED ();
++      file_lock_restore (&fl);
++      return -1;
+     }
+ 
+   if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
+@@ -241,7 +256,8 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer,
+   result = 0;
+ 
+ unlock_return:
+-  UNLOCK_FILE (file_fd);
++  file_unlock (file_fd);
++  file_lock_restore (&fl);
+ 
+   return result;
+ }
+@@ -287,10 +303,12 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+       return -1;
+     }
+ 
+-  LOCK_FILE (file_fd, F_RDLCK)
++  struct file_locking fl;
++  if (try_file_lock (&fl, file_fd, F_RDLCK))
+     {
+       *result = NULL;
+-      LOCKING_FAILED ();
++      file_lock_restore (&fl);
++      return -1;
+     }
+ 
+   while (1)
+@@ -318,7 +336,8 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+   *result = buffer;
+ 
+ unlock_return:
+-  UNLOCK_FILE (file_fd);
++  file_unlock (file_fd);
++  file_lock_restore (&fl);
+ 
+   return ((*result == NULL) ? -1 : 0);
+ }
+@@ -375,10 +394,11 @@ __libc_pututline (const struct utmp *data)
+ 	}
+     }
+ 
+-  LOCK_FILE (file_fd, F_WRLCK)
++  struct file_locking fl;
++  if (try_file_lock (&fl, file_fd, F_WRLCK))
+     {
+-      pbuf = NULL;
+-      LOCKING_FAILED ();
++      file_lock_restore (&fl);
++      return NULL;
+     }
+ 
+   if (found < 0)
+@@ -421,7 +441,8 @@ __libc_pututline (const struct utmp *data)
+     }
+ 
+  unlock_return:
+-  UNLOCK_FILE (file_fd);
++  file_unlock (file_fd);
++  file_lock_restore (&fl);
+ 
+   return pbuf;
+ }
+@@ -450,8 +471,13 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
+   if (fd < 0)
+     return -1;
+ 
+-  LOCK_FILE (fd, F_WRLCK)
+-    LOCKING_FAILED ();
++  struct file_locking fl;
++  if (try_file_lock (&fl, fd, F_WRLCK))
++    {
++      file_lock_restore (&fl);
++      __close_nocancel_nostatus (fd);
++      return -1;
++    }
+ 
+   /* Remember original size of log file.  */
+   offset = __lseek64 (fd, 0, SEEK_END);
+@@ -477,7 +503,8 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
+   result = 0;
+ 
+ unlock_return:
+-  UNLOCK_FILE (fd);
++  file_unlock (file_fd);
++  file_lock_restore (&fl);
+ 
+   /* Close WTMP file.  */
+   __close_nocancel_nostatus (fd);
diff --git a/SOURCES/glibc-rh1749439-4.patch b/SOURCES/glibc-rh1749439-4.patch
new file mode 100644
index 0000000..b2c7972
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-4.patch
@@ -0,0 +1,155 @@
+commit 341da5b4b6253de9a7581a066f33f89cacb44dec
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Aug 15 10:30:23 2019 +0200
+
+    login: Fix updwtmp, updwtmx unlocking
+    
+    Commit 5a3afa9738f3dbbaf8c0a35665318c1af782111b (login: Replace
+    macro-based control flow with function calls in utmp) introduced
+    a regression because after it, __libc_updwtmp attempts to unlock
+    the wrong file descriptor.
+
+diff --git a/login/Makefile b/login/Makefile
+index 8b31991be835fa8e..81986ab6bd8560ea 100644
+--- a/login/Makefile
++++ b/login/Makefile
+@@ -43,7 +43,7 @@ endif
+ subdir-dirs = programs
+ vpath %.c programs
+ 
+-tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin
++tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx
+ 
+ # Build the -lutil library with these extra functions.
+ extra-libs      := libutil
+diff --git a/login/tst-updwtmpx.c b/login/tst-updwtmpx.c
+new file mode 100644
+index 0000000000000000..0a4a27daeb0440fd
+--- /dev/null
++++ b/login/tst-updwtmpx.c
+@@ -0,0 +1,112 @@
++/* Basic test coverage for updwtmpx.
++   Copyright (C) 2019 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public License as
++   published by the Free Software Foundation; either version 2.1 of the
++   License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; see the file COPYING.LIB.  If
++   not, see <http://www.gnu.org/licenses/>.  */
++
++/* This program runs a series of tests.  Each one calls updwtmpx
++   twice, to write two records, optionally with misalignment in the
++   file, and reads back the results.  */
++
++#include <errno.h>
++#include <stdlib.h>
++#include <support/check.h>
++#include <support/descriptors.h>
++#include <support/support.h>
++#include <support/temp_file.h>
++#include <support/test-driver.h>
++#include <support/xunistd.h>
++#include <unistd.h>
++#include <utmpx.h>
++
++static int
++do_test (void)
++{
++  /* Two entries filled with an arbitrary bit pattern.  */
++  struct utmpx entries[2];
++  unsigned char pad;
++  {
++    unsigned char *p = (unsigned char *) &entries[0];
++    for (size_t i = 0; i < sizeof (entries); ++i)
++      {
++        p[i] = i;
++      }
++    /* Make sure that the first and second entry and the padding are
++       different.  */
++    p[sizeof (struct utmpx)] = p[0] + 1;
++    pad = p[0] + 2;
++  }
++
++  char *path;
++  int fd = create_temp_file ("tst-updwtmpx-", &path);
++
++  /* Used to check that updwtmpx does not leave an open file
++     descriptor around.  */
++  struct support_descriptors *descriptors = support_descriptors_list ();
++
++  /* updwtmpx is expected to remove misalignment.  Optionally insert
++     one byte of misalignment at the start and in the middle (after
++     the first entry).  */
++  for (int misaligned_start = 0; misaligned_start < 2; ++misaligned_start)
++    for (int misaligned_middle = 0; misaligned_middle < 2; ++misaligned_middle)
++      {
++        if (test_verbose > 0)
++          printf ("info: misaligned_start=%d misaligned_middle=%d\n",
++                  misaligned_start, misaligned_middle);
++
++        xftruncate (fd, 0);
++        TEST_COMPARE (pwrite64 (fd, &pad, misaligned_start, 0),
++                      misaligned_start);
++
++        /* Write first entry and check it.  */
++        errno = 0;
++        updwtmpx (path, &entries[0]);
++        TEST_COMPARE (errno, 0);
++        support_descriptors_check (descriptors);
++        TEST_COMPARE (xlseek (fd, 0, SEEK_END), sizeof (struct utmpx));
++        struct utmpx buffer;
++        TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), 0),
++                      sizeof (buffer));
++        TEST_COMPARE_BLOB (&entries[0], sizeof (entries[0]),
++                           &buffer, sizeof (buffer));
++
++        /* Middle mis-alignmet.  */
++        TEST_COMPARE (pwrite64 (fd, &pad, misaligned_middle,
++                                sizeof (struct utmpx)), misaligned_middle);
++
++        /* Write second entry and check both entries.  */
++        errno = 0;
++        updwtmpx (path, &entries[1]);
++        TEST_COMPARE (errno, 0);
++        support_descriptors_check (descriptors);
++        TEST_COMPARE (xlseek (fd, 0, SEEK_END), 2 * sizeof (struct utmpx));
++        TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), 0),
++                      sizeof (buffer));
++        TEST_COMPARE_BLOB (&entries[0], sizeof (entries[0]),
++                           &buffer, sizeof (buffer));
++        TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), sizeof (buffer)),
++                      sizeof (buffer));
++        TEST_COMPARE_BLOB (&entries[1], sizeof (entries[1]),
++                           &buffer, sizeof (buffer));
++      }
++
++  support_descriptors_free (descriptors);
++  free (path);
++  xclose (fd);
++
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/login/utmp_file.c b/login/utmp_file.c
+index 812de8fd3d099ce9..54f424fd6165bae7 100644
+--- a/login/utmp_file.c
++++ b/login/utmp_file.c
+@@ -503,7 +503,7 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
+   result = 0;
+ 
+ unlock_return:
+-  file_unlock (file_fd);
++  file_unlock (fd);
+   file_lock_restore (&fl);
+ 
+   /* Close WTMP file.  */
diff --git a/SOURCES/glibc-rh1749439-5.patch b/SOURCES/glibc-rh1749439-5.patch
new file mode 100644
index 0000000..b9cfe31
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-5.patch
@@ -0,0 +1,33 @@
+commit 0d5b2917530ccaf8ad312dfbb7bce69d569c23ad
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Aug 15 16:09:20 2019 +0200
+
+    login: Use struct flock64 in utmp [BZ #24880]
+    
+    Commit 06ab719d30b01da401150068054d3b8ea93dd12f ("Fix Linux fcntl OFD
+    locks for non-LFS architectures (BZ#20251)") introduced the use of
+    fcntl64 into the utmp implementation.  However, the lock file
+    structure was not updated to struct flock64 at that point.
+
+diff --git a/login/utmp_file.c b/login/utmp_file.c
+index 54f424fd6165bae7..8b6fee96b623fa90 100644
+--- a/login/utmp_file.c
++++ b/login/utmp_file.c
+@@ -85,7 +85,7 @@ try_file_lock (struct file_locking *locking, int fd, int type)
+   alarm (TIMEOUT);
+ 
+   /* Try to get the lock.  */
+- struct flock fl =
++ struct flock64 fl =
+    {
+     .l_type = type,
+     fl.l_whence = SEEK_SET,
+@@ -96,7 +96,7 @@ try_file_lock (struct file_locking *locking, int fd, int type)
+ static void
+ file_unlock (int fd)
+ {
+-  struct flock fl =
++  struct flock64 fl =
+     {
+       .l_type = F_UNLCK,
+     };
diff --git a/SOURCES/glibc-rh1749439-6.patch b/SOURCES/glibc-rh1749439-6.patch
new file mode 100644
index 0000000..3a8ad22
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-6.patch
@@ -0,0 +1,204 @@
+commit 628598be7e1bfaa04f34df71ef6678f2c5103dfd
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Aug 15 16:09:05 2019 +0200
+
+    login: Disarm timer after utmp lock acquisition [BZ #24879]
+    
+    If the file processing takes a long time for some reason, SIGALRM can
+    arrive while the file is still being processed.  At that point, file
+    access will fail with EINTR.  Disarming the timer after lock
+    acquisition avoids that.  (If there was a previous alarm, it is the
+    responsibility of the caller to deal with the EINTR error.)
+
+diff --git a/login/utmp_file.c b/login/utmp_file.c
+index 8b6fee96b623fa90..a736d3d25e005920 100644
+--- a/login/utmp_file.c
++++ b/login/utmp_file.c
+@@ -55,32 +55,23 @@ static void timeout_handler (int signum) {};
+ 
+ /* try_file_lock (LOCKING, FD, TYPE) returns true if the locking
+    operation failed and recovery needs to be performed.
+-   (file_lock_restore (LOCKING) still needs to be called.)
+ 
+    file_unlock (FD) removes the lock (which must have been
+-   acquired).
+-
+-   file_lock_restore (LOCKING) is needed to clean up in both
+-   cases.  */
+-
+-struct file_locking
+-{
+-  struct sigaction old_action;
+-  unsigned int old_timeout;
+-};
++   successfully acquired). */
+ 
+ static bool
+-try_file_lock (struct file_locking *locking, int fd, int type)
++try_file_lock (int fd, int type)
+ {
+   /* Cancel any existing alarm.  */
+-  locking->old_timeout = alarm (0);
++  int old_timeout = alarm (0);
+ 
+   /* Establish signal handler.  */
++  struct sigaction old_action;
+   struct sigaction action;
+   action.sa_handler = timeout_handler;
+   __sigemptyset (&action.sa_mask);
+   action.sa_flags = 0;
+-  __sigaction (SIGALRM, &action, &locking->old_action);
++  __sigaction (SIGALRM, &action, &old_action);
+ 
+   alarm (TIMEOUT);
+ 
+@@ -90,7 +81,23 @@ try_file_lock (struct file_locking *locking, int fd, int type)
+     .l_type = type,
+     fl.l_whence = SEEK_SET,
+    };
+- return __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0;
++
++ bool status = __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0;
++ int saved_errno = errno;
++
++ /* Reset the signal handler and alarm.  We must reset the alarm
++    before resetting the handler so our alarm does not generate a
++    spurious SIGALRM seen by the user.  However, we cannot just set
++    the user's old alarm before restoring the handler, because then
++    it's possible our handler could catch the user alarm's SIGARLM and
++    then the user would never see the signal he expected.  */
++  alarm (0);
++  __sigaction (SIGALRM, &old_action, NULL);
++  if (old_timeout != 0)
++    alarm (old_timeout);
++
++  __set_errno (saved_errno);
++  return status;
+ }
+ 
+ static void
+@@ -103,21 +110,6 @@ file_unlock (int fd)
+   __fcntl64_nocancel (fd, F_SETLKW, &fl);
+ }
+ 
+-static void
+-file_lock_restore (struct file_locking *locking)
+-{
+-  /* Reset the signal handler and alarm.  We must reset the alarm
+-     before resetting the handler so our alarm does not generate a
+-     spurious SIGALRM seen by the user.  However, we cannot just set
+-     the user's old alarm before restoring the handler, because then
+-     it's possible our handler could catch the user alarm's SIGARLM
+-     and then the user would never see the signal he expected.  */
+-  alarm (0);
+-  __sigaction (SIGALRM, &locking->old_action, NULL);
+-  if (locking->old_timeout != 0)
+-    alarm (locking->old_timeout);
+-}
+-
+ #ifndef TRANSFORM_UTMP_FILE_NAME
+ # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name)
+ #endif
+@@ -166,8 +158,7 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
+       return -1;
+     }
+ 
+-  struct file_locking fl;
+-  if (try_file_lock (&fl, file_fd, F_RDLCK))
++  if (try_file_lock (file_fd, F_RDLCK))
+     nbytes = 0;
+   else
+     {
+@@ -175,7 +166,6 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
+       nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp));
+       file_unlock (file_fd);
+     }
+-  file_lock_restore (&fl);
+ 
+   if (nbytes != sizeof (struct utmp))
+     {
+@@ -201,11 +191,9 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer,
+ {
+   int result = -1;
+ 
+-  struct file_locking fl;
+-  if (try_file_lock (&fl, file_fd, F_RDLCK))
++  if (try_file_lock (file_fd, F_RDLCK))
+     {
+       *lock_failed = true;
+-      file_lock_restore (&fl);
+       return -1;
+     }
+ 
+@@ -257,7 +245,6 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer,
+ 
+ unlock_return:
+   file_unlock (file_fd);
+-  file_lock_restore (&fl);
+ 
+   return result;
+ }
+@@ -303,11 +290,9 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+       return -1;
+     }
+ 
+-  struct file_locking fl;
+-  if (try_file_lock (&fl, file_fd, F_RDLCK))
++  if (try_file_lock (file_fd, F_RDLCK))
+     {
+       *result = NULL;
+-      file_lock_restore (&fl);
+       return -1;
+     }
+ 
+@@ -337,7 +322,6 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+ 
+ unlock_return:
+   file_unlock (file_fd);
+-  file_lock_restore (&fl);
+ 
+   return ((*result == NULL) ? -1 : 0);
+ }
+@@ -394,12 +378,8 @@ __libc_pututline (const struct utmp *data)
+ 	}
+     }
+ 
+-  struct file_locking fl;
+-  if (try_file_lock (&fl, file_fd, F_WRLCK))
+-    {
+-      file_lock_restore (&fl);
+-      return NULL;
+-    }
++  if (try_file_lock (file_fd, F_WRLCK))
++    return NULL;
+ 
+   if (found < 0)
+     {
+@@ -442,7 +422,6 @@ __libc_pututline (const struct utmp *data)
+ 
+  unlock_return:
+   file_unlock (file_fd);
+-  file_lock_restore (&fl);
+ 
+   return pbuf;
+ }
+@@ -471,10 +450,8 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
+   if (fd < 0)
+     return -1;
+ 
+-  struct file_locking fl;
+-  if (try_file_lock (&fl, fd, F_WRLCK))
++  if (try_file_lock (fd, F_WRLCK))
+     {
+-      file_lock_restore (&fl);
+       __close_nocancel_nostatus (fd);
+       return -1;
+     }
+@@ -504,7 +481,6 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
+ 
+ unlock_return:
+   file_unlock (fd);
+-  file_lock_restore (&fl);
+ 
+   /* Close WTMP file.  */
+   __close_nocancel_nostatus (fd);
diff --git a/SOURCES/glibc-rh1749439-7.patch b/SOURCES/glibc-rh1749439-7.patch
new file mode 100644
index 0000000..370dab2
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-7.patch
@@ -0,0 +1,309 @@
+commit 61d3db428176d9d0822e4e680305fe34285edff2
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Wed Aug 28 11:59:45 2019 +0200
+
+    login: pututxline could fail to overwrite existing entries [BZ #24902]
+    
+    The internal_getut_r function updates the file_offset variable and
+    therefore must always update last_entry as well.
+    
+    Previously, if pututxline could not upgrade the read lock to a
+    write lock, internal_getut_r would update file_offset only,
+    without updating last_entry, and a subsequent call would not
+    overwrite the existing utmpx entry at file_offset, instead
+    creating a new entry.  This has been observed to cause unbounded
+    file growth in high-load situations.
+    
+    This commit removes the buffer argument to internal_getut_r and
+    updates the last_entry variable directly, along with file_offset.
+    
+    Initially reported and fixed by Ondřej Lysoněk.
+    
+    Reviewed-by: Gabriel F. T. Gomes <gabrielftg@linux.ibm.com>
+
+diff --git a/login/Makefile b/login/Makefile
+index 81986ab6bd8560ea..82132c83fd799357 100644
+--- a/login/Makefile
++++ b/login/Makefile
+@@ -43,7 +43,8 @@ endif
+ subdir-dirs = programs
+ vpath %.c programs
+ 
+-tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx
++tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
++  tst-pututxline-lockfail
+ 
+ # Build the -lutil library with these extra functions.
+ extra-libs      := libutil
+@@ -71,3 +72,5 @@ endif
+ $(inst_libexecdir)/pt_chown: $(objpfx)pt_chown $(+force)
+ 	$(make-target-directory)
+ 	-$(INSTALL_PROGRAM) -m 4755 -o root $< $@
++
++$(objpfx)tst-pututxline-lockfail: $(shared-thread-library)
+diff --git a/login/tst-pututxline-lockfail.c b/login/tst-pututxline-lockfail.c
+new file mode 100644
+index 0000000000000000..47c25dc0658d3c60
+--- /dev/null
++++ b/login/tst-pututxline-lockfail.c
+@@ -0,0 +1,176 @@
++/* Test the lock upgrade path in tst-pututxline.
++   Copyright (C) 2019 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public License as
++   published by the Free Software Foundation; either version 2.1 of the
++   License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; see the file COPYING.LIB.  If
++   not, see <http://www.gnu.org/licenses/>.  */
++
++/* pututxline upgrades the read lock on the file to a write lock.
++   This test verifies that if the lock upgrade fails, the utmp
++   subsystem remains in a consistent state, so that pututxline can be
++   called again.  */
++
++#include <errno.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <support/check.h>
++#include <support/namespace.h>
++#include <support/support.h>
++#include <support/temp_file.h>
++#include <support/xthread.h>
++#include <support/xunistd.h>
++#include <unistd.h>
++#include <utmp.h>
++#include <utmpx.h>
++
++/* Path to the temporary utmp file.   */
++static char *path;
++
++/* Used to synchronize the subprocesses.  The barrier itself is
++   allocated in shared memory.  */
++static pthread_barrier_t *barrier;
++
++/* Use pututxline to write an entry for PID.  */
++static struct utmpx *
++write_entry (pid_t pid)
++{
++  struct utmpx ut =
++    {
++     .ut_type = LOGIN_PROCESS,
++     .ut_id = "1",
++     .ut_user = "root",
++     .ut_pid = pid,
++     .ut_line = "entry",
++     .ut_host = "localhost",
++    };
++  return pututxline (&ut);
++}
++
++/* Create the initial entry in a subprocess, so that the utmp
++   subsystem in the original process is not disturbed.  */
++static void
++subprocess_create_entry (void *closure)
++{
++  TEST_COMPARE (utmpname (path), 0);
++  TEST_VERIFY (write_entry (101) != NULL);
++}
++
++/* Acquire an advisory read lock on PATH.  */
++__attribute__ ((noreturn)) static void
++subprocess_lock_file (void)
++{
++  int fd = xopen (path, O_RDONLY, 0);
++
++  struct flock64 fl =
++    {
++     .l_type = F_RDLCK,
++     fl.l_whence = SEEK_SET,
++    };
++  TEST_COMPARE (fcntl64 (fd, F_SETLKW, &fl), 0);
++
++  /* Signal to the main process that the lock has been acquired.  */
++  xpthread_barrier_wait (barrier);
++
++  /* Wait for the unlock request from the main process.  */
++  xpthread_barrier_wait (barrier);
++
++  /* Implicitly unlock the file.  */
++  xclose (fd);
++
++  /* Overwrite the existing entry.  */
++  TEST_COMPARE (utmpname (path), 0);
++  errno = 0;
++  setutxent ();
++  TEST_COMPARE (errno, 0);
++  TEST_VERIFY (write_entry (102) != NULL);
++  errno = 0;
++  endutxent ();
++  TEST_COMPARE (errno, 0);
++
++  _exit (0);
++}
++
++static int
++do_test (void)
++{
++  xclose (create_temp_file ("tst-pututxline-lockfail-", &path));
++
++  {
++    pthread_barrierattr_t attr;
++    xpthread_barrierattr_init (&attr);
++    xpthread_barrierattr_setpshared (&attr, PTHREAD_SCOPE_PROCESS);
++    barrier = support_shared_allocate (sizeof (*barrier));
++    xpthread_barrier_init (barrier, &attr, 2);
++    xpthread_barrierattr_destroy (&attr);
++  }
++
++  /* Write the initial entry.  */
++  support_isolate_in_subprocess (subprocess_create_entry, NULL);
++
++  pid_t locker_pid = xfork ();
++  if (locker_pid == 0)
++    subprocess_lock_file ();
++
++  /* Wait for the file locking to complete.  */
++  xpthread_barrier_wait (barrier);
++
++  /* Try to add another entry.  This attempt will fail, with EINTR or
++     EAGAIN.  */
++  TEST_COMPARE (utmpname (path), 0);
++  TEST_VERIFY (write_entry (102) == NULL);
++  if (errno != EINTR)
++    TEST_COMPARE (errno, EAGAIN);
++
++  /* Signal the subprocess to overwrite the entry.  */
++  xpthread_barrier_wait (barrier);
++
++  /* Wait for write and unlock to complete.  */
++  {
++    int status;
++    xwaitpid (locker_pid, &status, 0);
++    TEST_COMPARE (status, 0);
++  }
++
++  /* The file is no longer locked, so this operation will succeed.  */
++  TEST_VERIFY (write_entry (103) != NULL);
++  errno = 0;
++  endutxent ();
++  TEST_COMPARE (errno, 0);
++
++  /* Check that there is just one entry with the expected contents.
++     If pututxline becomes desynchronized internally, the entry is not
++     overwritten (bug 24902).  */
++  errno = 0;
++  setutxent ();
++  TEST_COMPARE (errno, 0);
++  struct utmpx *ut = getutxent ();
++  TEST_VERIFY_EXIT (ut != NULL);
++  TEST_COMPARE (ut->ut_type, LOGIN_PROCESS);
++  TEST_COMPARE_STRING (ut->ut_id, "1");
++  TEST_COMPARE_STRING (ut->ut_user, "root");
++  TEST_COMPARE (ut->ut_pid, 103);
++  TEST_COMPARE_STRING (ut->ut_line, "entry");
++  TEST_COMPARE_STRING (ut->ut_host, "localhost");
++  TEST_VERIFY (getutxent () == NULL);
++  errno = 0;
++  endutxent ();
++  TEST_COMPARE (errno, 0);
++
++  xpthread_barrier_destroy (barrier);
++  support_shared_free (barrier);
++  free (path);
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/login/utmp_file.c b/login/utmp_file.c
+index a736d3d25e005920..cbc53d06de280af9 100644
+--- a/login/utmp_file.c
++++ b/login/utmp_file.c
+@@ -185,9 +185,11 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
+ }
+ 
+ 
++/* Search for *ID, updating last_entry and file_offset.  Return 0 on
++   success and -1 on failure.  If the locking operation failed, write
++   true to *LOCK_FAILED.  */
+ static int
+-internal_getut_r (const struct utmp *id, struct utmp *buffer,
+-		  bool *lock_failed)
++internal_getut_r (const struct utmp *id, bool *lock_failed)
+ {
+   int result = -1;
+ 
+@@ -206,7 +208,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer,
+       while (1)
+ 	{
+ 	  /* Read the next entry.  */
+-	  if (__read_nocancel (file_fd, buffer, sizeof (struct utmp))
++	  if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp))
+ 	      != sizeof (struct utmp))
+ 	    {
+ 	      __set_errno (ESRCH);
+@@ -215,7 +217,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer,
+ 	    }
+ 	  file_offset += sizeof (struct utmp);
+ 
+-	  if (id->ut_type == buffer->ut_type)
++	  if (id->ut_type == last_entry.ut_type)
+ 	    break;
+ 	}
+     }
+@@ -227,7 +229,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer,
+       while (1)
+ 	{
+ 	  /* Read the next entry.  */
+-	  if (__read_nocancel (file_fd, buffer, sizeof (struct utmp))
++	  if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp))
+ 	      != sizeof (struct utmp))
+ 	    {
+ 	      __set_errno (ESRCH);
+@@ -236,7 +238,7 @@ internal_getut_r (const struct utmp *id, struct utmp *buffer,
+ 	    }
+ 	  file_offset += sizeof (struct utmp);
+ 
+-	  if (__utmp_equal (buffer, id))
++	  if (__utmp_equal (&last_entry, id))
+ 	    break;
+ 	}
+     }
+@@ -265,7 +267,7 @@ __libc_getutid_r (const struct utmp *id, struct utmp *buffer,
+   /* We don't have to distinguish whether we can lock the file or
+      whether there is no entry.  */
+   bool lock_failed = false;
+-  if (internal_getut_r (id, &last_entry, &lock_failed) < 0)
++  if (internal_getut_r (id, &lock_failed) < 0)
+     {
+       *result = NULL;
+       return -1;
+@@ -330,10 +332,9 @@ unlock_return:
+ struct utmp *
+ __libc_pututline (const struct utmp *data)
+ {
+-  if (!maybe_setutent ())
++  if (!maybe_setutent () || file_offset == -1l)
+     return NULL;
+ 
+-  struct utmp buffer;
+   struct utmp *pbuf;
+   int found;
+ 
+@@ -369,7 +370,7 @@ __libc_pututline (const struct utmp *data)
+   else
+     {
+       bool lock_failed = false;
+-      found = internal_getut_r (data, &buffer, &lock_failed);
++      found = internal_getut_r (data, &lock_failed);
+ 
+       if (__builtin_expect (lock_failed, false))
+ 	{
diff --git a/SOURCES/glibc-rh1749439-8.patch b/SOURCES/glibc-rh1749439-8.patch
new file mode 100644
index 0000000..3fc23cf
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-8.patch
@@ -0,0 +1,86 @@
+commit c2adefbafcdd2519ff43eca6891c77cd7b29ab62
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Aug 15 16:09:43 2019 +0200
+
+    login: Add nonstring attributes to struct utmp, struct utmpx [BZ #24899]
+    
+    Commit 7532837d7b03b3ca5b9a63d77a5bd81dd23f3d9c ("The
+    -Wstringop-truncation option new in GCC 8 detects common misuses")
+    added __attribute_nonstring__ to bits/utmp.h, but it did not update
+    the parallel bits/utmpx.h header.  In struct utmp, the nonstring
+    attribute for ut_id was missing.
+
+diff --git a/bits/utmp.h b/bits/utmp.h
+index 3c02dd4f3fe4e99b..854b342164b785e0 100644
+--- a/bits/utmp.h
++++ b/bits/utmp.h
+@@ -61,7 +61,8 @@ struct utmp
+   pid_t ut_pid;			/* Process ID of login process.  */
+   char ut_line[UT_LINESIZE]
+     __attribute_nonstring__;	/* Devicename.  */
+-  char ut_id[4];		/* Inittab ID.  */
++  char ut_id[4]
++    __attribute_nonstring__;	/* Inittab ID.  */
+   char ut_user[UT_NAMESIZE]
+     __attribute_nonstring__;	/* Username.  */
+   char ut_host[UT_HOSTSIZE]
+diff --git a/sysdeps/gnu/bits/utmpx.h b/sysdeps/gnu/bits/utmpx.h
+index 2a77efc607ae2ac0..71c743ebfcd41194 100644
+--- a/sysdeps/gnu/bits/utmpx.h
++++ b/sysdeps/gnu/bits/utmpx.h
+@@ -56,10 +56,14 @@ struct utmpx
+ {
+   short int ut_type;		/* Type of login.  */
+   __pid_t ut_pid;		/* Process ID of login process.  */
+-  char ut_line[__UT_LINESIZE];	/* Devicename.  */
+-  char ut_id[4];		/* Inittab ID. */
+-  char ut_user[__UT_NAMESIZE];	/* Username.  */
+-  char ut_host[__UT_HOSTSIZE];	/* Hostname for remote login.  */
++  char ut_line[__UT_LINESIZE]
++    __attribute_nonstring__;	/* Devicename.  */
++  char ut_id[4]
++    __attribute_nonstring__;	/* Inittab ID.  */
++  char ut_user[__UT_NAMESIZE]
++    __attribute_nonstring__;	/* Username.  */
++  char ut_host[__UT_HOSTSIZE]
++    __attribute_nonstring__;	/* Hostname for remote login.  */
+   struct __exit_status ut_exit;	/* Exit status of a process marked
+ 				   as DEAD_PROCESS.  */
+ 
+diff --git a/sysdeps/unix/sysv/linux/s390/bits/utmp.h b/sysdeps/unix/sysv/linux/s390/bits/utmp.h
+index b3fa362f478ae6fe..82e8d17e2e8cc031 100644
+--- a/sysdeps/unix/sysv/linux/s390/bits/utmp.h
++++ b/sysdeps/unix/sysv/linux/s390/bits/utmp.h
+@@ -61,7 +61,8 @@ struct utmp
+   pid_t ut_pid;			/* Process ID of login process.  */
+   char ut_line[UT_LINESIZE]
+      __attribute_nonstring__;	/* Devicename.  */
+-  char ut_id[4];		/* Inittab ID.  */
++  char ut_id[4]
++    __attribute_nonstring__;	/* Inittab ID.  */
+   char ut_user[UT_NAMESIZE]
+      __attribute_nonstring__;	/* Username.  */
+   char ut_host[UT_HOSTSIZE]
+diff --git a/sysdeps/unix/sysv/linux/s390/bits/utmpx.h b/sysdeps/unix/sysv/linux/s390/bits/utmpx.h
+index 3d3036c3b91e6f57..3818ed3aa4df1e65 100644
+--- a/sysdeps/unix/sysv/linux/s390/bits/utmpx.h
++++ b/sysdeps/unix/sysv/linux/s390/bits/utmpx.h
+@@ -56,10 +56,14 @@ struct utmpx
+ {
+   short int ut_type;		/* Type of login.  */
+   __pid_t ut_pid;		/* Process ID of login process.  */
+-  char ut_line[__UT_LINESIZE];	/* Devicename.  */
+-  char ut_id[4];		/* Inittab ID. */
+-  char ut_user[__UT_NAMESIZE];	/* Username.  */
+-  char ut_host[__UT_HOSTSIZE];	/* Hostname for remote login.  */
++  char ut_line[__UT_LINESIZE]
++    __attribute_nonstring__;	/* Devicename.  */
++  char ut_id[4]
++    __attribute_nonstring__;	/* Inittab ID.  */
++  char ut_user[__UT_NAMESIZE]
++    __attribute_nonstring__;	/* Username.  */
++  char ut_host[__UT_HOSTSIZE]
++    __attribute_nonstring__;	/* Hostname for remote login.  */
+   struct __exit_status ut_exit;	/* Exit status of a process marked
+ 				   as DEAD_PROCESS.  */
+ 
diff --git a/SOURCES/glibc-rh1749439-9.patch b/SOURCES/glibc-rh1749439-9.patch
new file mode 100644
index 0000000..0a8470b
--- /dev/null
+++ b/SOURCES/glibc-rh1749439-9.patch
@@ -0,0 +1,26 @@
+commit b0a83ae71b2588bd2a9e6b40f95191602940e01e
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Nov 7 09:53:41 2019 +0100
+
+    login: Remove double-assignment of fl.l_whence in try_file_lock
+    
+    Since l_whence is the second member of struct flock, it is written
+    twice.  The double-assignment is technically undefined behavior due to
+    the lack of a sequence point.
+    
+    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+    Change-Id: I2baf9e70690e723c61051b25ccbd510aec15976c
+
+diff --git a/login/utmp_file.c b/login/utmp_file.c
+index cbc53d06de280af9..9ad80364682bae92 100644
+--- a/login/utmp_file.c
++++ b/login/utmp_file.c
+@@ -79,7 +79,7 @@ try_file_lock (int fd, int type)
+  struct flock64 fl =
+    {
+     .l_type = type,
+-    fl.l_whence = SEEK_SET,
++    .l_whence = SEEK_SET,
+    };
+ 
+  bool status = __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0;
diff --git a/SOURCES/glibc-rh1764214.patch b/SOURCES/glibc-rh1764214.patch
new file mode 100644
index 0000000..fb7703c
--- /dev/null
+++ b/SOURCES/glibc-rh1764214.patch
@@ -0,0 +1,305 @@
+commit bc79db3fd487daea36e7c130f943cfb9826a41b4
+Author: Stefan Liebler <stli@linux.ibm.com>
+Date:   Wed Feb 6 09:06:34 2019 +0100
+
+    Fix alignment of TLS variables for tls variant TLS_TCB_AT_TP [BZ #23403]
+    
+    The alignment of TLS variables is wrong if accessed from within a thread
+    for architectures with tls variant TLS_TCB_AT_TP.
+    For the main thread the static tls data is properly aligned.
+    For other threads the alignment depends on the alignment of the thread
+    pointer as the static tls data is located relative to this pointer.
+    
+    This patch adds this alignment for TLS_TCB_AT_TP variants in the same way
+    as it is already done for TLS_DTV_AT_TP. The thread pointer is also already
+    properly aligned if the user provides its own stack for the new thread.
+    
+    This patch extends the testcase nptl/tst-tls1.c in order to check the
+    alignment of the tls variables and it adds a pthread_create invocation
+    with a user provided stack.
+    The test itself is migrated from test-skeleton.c to test-driver.c
+    and the missing support functions xpthread_attr_setstack and xposix_memalign
+    are added.
+    
+    ChangeLog:
+    
+            [BZ #23403]
+            * nptl/allocatestack.c (allocate_stack): Align pointer pd for
+            TLS_TCB_AT_TP tls variant.
+            * nptl/tst-tls1.c: Migrate to support/test-driver.c.
+            Add alignment checks.
+            * support/Makefile (libsupport-routines): Add xposix_memalign and
+            xpthread_setstack.
+            * support/support.h: Add xposix_memalign.
+            * support/xthread.h: Add xpthread_attr_setstack.
+            * support/xposix_memalign.c: New File.
+            * support/xpthread_attr_setstack.c: Likewise.
+
+diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
+index 670cb8ffe6..590350647b 100644
+--- a/nptl/allocatestack.c
++++ b/nptl/allocatestack.c
+@@ -572,7 +572,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
+ 
+ 	  /* Place the thread descriptor at the end of the stack.  */
+ #if TLS_TCB_AT_TP
+-	  pd = (struct pthread *) ((char *) mem + size) - 1;
++	  pd = (struct pthread *) ((((uintptr_t) mem + size)
++				    - TLS_TCB_SIZE)
++				   & ~__static_tls_align_m1);
+ #elif TLS_DTV_AT_TP
+ 	  pd = (struct pthread *) ((((uintptr_t) mem + size
+ 				    - __static_tls_size)
+diff --git a/nptl/tst-tls1.c b/nptl/tst-tls1.c
+index 00489e23e9..1a915224a7 100644
+--- a/nptl/tst-tls1.c
++++ b/nptl/tst-tls1.c
+@@ -19,12 +19,16 @@
+ #include <pthread.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+-
++#include <stdint.h>
++#include <inttypes.h>
++#include <support/support.h>
++#include <support/check.h>
++#include <support/xthread.h>
+ 
+ struct test_s
+ {
+-  int a;
+-  int b;
++  __attribute__ ((aligned(0x20))) int a;
++  __attribute__ ((aligned(0x200))) int b;
+ };
+ 
+ #define INIT_A 1
+@@ -36,15 +40,34 @@ __thread struct test_s s __attribute__ ((tls_model ("initial-exec"))) =
+   .b = INIT_B
+ };
+ 
++/* Use noinline in combination with not static to ensure that the
++   alignment check is really done.  Otherwise it was optimized out!  */
++__attribute__ ((noinline)) void
++check_alignment (const char *thr_name, const char *ptr_name,
++		 int *ptr, int alignment)
++{
++  uintptr_t offset_aligment = ((uintptr_t) ptr) & (alignment - 1);
++  if (offset_aligment)
++    {
++      FAIL_EXIT1 ("%s (%p) is not 0x%x-byte aligned in %s thread\n",
++		  ptr_name, ptr, alignment, thr_name);
++    }
++}
++
++static void
++check_s (const char *thr_name)
++{
++  if (s.a != INIT_A || s.b != INIT_B)
++    FAIL_EXIT1 ("initial value of s in %s thread wrong\n", thr_name);
++
++  check_alignment (thr_name, "s.a", &s.a, 0x20);
++  check_alignment (thr_name, "s.b", &s.b, 0x200);
++}
+ 
+ static void *
+ tf (void *arg)
+ {
+-  if (s.a != INIT_A || s.b != INIT_B)
+-    {
+-      puts ("initial value of s in child thread wrong");
+-      exit (1);
+-    }
++  check_s ("child");
+ 
+   ++s.a;
+ 
+@@ -55,25 +78,14 @@ tf (void *arg)
+ int
+ do_test (void)
+ {
+-  if (s.a != INIT_A || s.b != INIT_B)
+-    {
+-      puts ("initial value of s in main thread wrong");
+-      exit (1);
+-    }
++  check_s ("main");
+ 
+   pthread_attr_t a;
+ 
+-  if (pthread_attr_init (&a) != 0)
+-    {
+-      puts ("attr_init failed");
+-      exit (1);
+-    }
++  xpthread_attr_init (&a);
+ 
+-  if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
+-    {
+-      puts ("attr_setstacksize failed");
+-      return 1;
+-    }
++#define STACK_SIZE (1 * 1024 * 1024)
++  xpthread_attr_setstacksize (&a, STACK_SIZE);
+ 
+ #define N 10
+   int i;
+@@ -83,29 +95,25 @@ do_test (void)
+       pthread_t th[M];
+       int j;
+       for (j = 0; j < M; ++j, ++s.a)
+-	if (pthread_create (&th[j], &a, tf, NULL) != 0)
+-	  {
+-	    puts ("pthread_create failed");
+-	    exit (1);
+-	  }
++	th[j] = xpthread_create (&a, tf, NULL);
+ 
+       for (j = 0; j < M; ++j)
+-	if (pthread_join (th[j], NULL) != 0)
+-	  {
+-	    puts ("pthread_join failed");
+-	    exit (1);
+-	  }
++	xpthread_join (th[j]);
+     }
+ 
+-  if (pthread_attr_destroy (&a) != 0)
+-    {
+-      puts ("attr_destroy failed");
+-      exit (1);
+-    }
++  /* Also check the alignment of the tls variables if a misaligned stack is
++     specified.  */
++  pthread_t th;
++  void *thr_stack = NULL;
++  thr_stack = xposix_memalign (0x200, STACK_SIZE + 1);
++  xpthread_attr_setstack (&a, thr_stack + 1, STACK_SIZE);
++  th = xpthread_create (&a, tf, NULL);
++  xpthread_join (th);
++  free (thr_stack);
++
++  xpthread_attr_destroy (&a);
+ 
+   return 0;
+ }
+ 
+-
+-#define TEST_FUNCTION do_test ()
+-#include "../test-skeleton.c"
++#include <support/test-driver.c>
+diff --git a/support/Makefile b/support/Makefile
+index c15b93647c..9ff0ec3fff 100644
+--- a/support/Makefile
++++ b/support/Makefile
+@@ -99,10 +99,12 @@ libsupport-routines = \
+   xopen \
+   xpipe \
+   xpoll \
++  xposix_memalign \
+   xpthread_attr_destroy \
+   xpthread_attr_init \
+   xpthread_attr_setdetachstate \
+   xpthread_attr_setguardsize \
++  xpthread_attr_setstack \
+   xpthread_attr_setstacksize \
+   xpthread_barrier_destroy \
+   xpthread_barrier_init \
+diff --git a/support/support.h b/support/support.h
+index 119495e5a9..97fef2cd23 100644
+--- a/support/support.h
++++ b/support/support.h
+@@ -86,6 +86,7 @@ int support_descriptor_supports_holes (int fd);
+ void *xmalloc (size_t) __attribute__ ((malloc));
+ void *xcalloc (size_t n, size_t s) __attribute__ ((malloc));
+ void *xrealloc (void *p, size_t n);
++void *xposix_memalign (size_t alignment, size_t n);
+ char *xasprintf (const char *format, ...)
+   __attribute__ ((format (printf, 1, 2), malloc));
+ char *xstrdup (const char *);
+diff --git a/support/xposix_memalign.c b/support/xposix_memalign.c
+new file mode 100644
+index 0000000000..5501a0846a
+--- /dev/null
++++ b/support/xposix_memalign.c
+@@ -0,0 +1,35 @@
++/* Error-checking wrapper for posix_memalign.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/support.h>
++#include <stdlib.h>
++#include <errno.h>
++
++void *
++xposix_memalign (size_t alignment, size_t n)
++{
++  void *p = NULL;
++
++  int ret = posix_memalign (&p, alignment, n);
++  if (ret)
++    {
++      errno = ret;
++      oom_error ("posix_memalign", n);
++    }
++  return p;
++}
+diff --git a/support/xpthread_attr_setstack.c b/support/xpthread_attr_setstack.c
+new file mode 100644
+index 0000000000..c3772e240b
+--- /dev/null
++++ b/support/xpthread_attr_setstack.c
+@@ -0,0 +1,26 @@
++/* pthread_attr_setstack with error checking.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/xthread.h>
++
++void
++xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, size_t stacksize)
++{
++  xpthread_check_return ("pthread_attr_setstack",
++			 pthread_attr_setstack (attr, stackaddr, stacksize));
++}
+diff --git a/support/xthread.h b/support/xthread.h
+index 9fe1f68b3b..5204f78ed2 100644
+--- a/support/xthread.h
++++ b/support/xthread.h
+@@ -68,6 +68,8 @@ void xpthread_attr_destroy (pthread_attr_t *attr);
+ void xpthread_attr_init (pthread_attr_t *attr);
+ void xpthread_attr_setdetachstate (pthread_attr_t *attr,
+ 				   int detachstate);
++void xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
++			     size_t stacksize);
+ void xpthread_attr_setstacksize (pthread_attr_t *attr,
+ 				 size_t stacksize);
+ void xpthread_attr_setguardsize (pthread_attr_t *attr,
diff --git a/SOURCES/glibc-rh1764218-1.patch b/SOURCES/glibc-rh1764218-1.patch
new file mode 100644
index 0000000..583f7a7
--- /dev/null
+++ b/SOURCES/glibc-rh1764218-1.patch
@@ -0,0 +1,192 @@
+commit cb89ba9c72f66327f5d66034681eb1d46eedf96f
+Author: DJ Delorie <dj@redhat.com>
+Date:   Thu Aug 8 19:09:43 2019 -0400
+
+    Add glibc.malloc.mxfast tunable
+    
+    * elf/dl-tunables.list: Add glibc.malloc.mxfast.
+    * manual/tunables.texi: Document it.
+    * malloc/malloc.c (do_set_mxfast): New.
+    (__libc_mallopt): Call it.
+    * malloc/arena.c: Add mxfast tunable.
+    * malloc/tst-mxfast.c: New.
+    * malloc/Makefile: Add it.
+    
+    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+    (cherry picked from commit c48d92b430c480de06762f80c104922239416826)
+
+diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
+index 1f8ecb8437a0460f..1ff6fcb6f24f93a8 100644
+--- a/elf/dl-tunables.list
++++ b/elf/dl-tunables.list
+@@ -85,6 +85,11 @@ glibc {
+     tcache_unsorted_limit {
+       type: SIZE_T
+     }
++    mxfast {
++      type: SIZE_T
++      minval: 0
++      security_level: SXID_IGNORE
++    }
+   }
+   tune {
+     hwcap_mask {
+diff --git a/malloc/Makefile b/malloc/Makefile
+index 228a1279a5960d8c..bf9a53cb7c5ebacb 100644
+--- a/malloc/Makefile
++++ b/malloc/Makefile
+@@ -39,6 +39,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
+ 	 tst-malloc-too-large \
+ 	 tst-malloc-stats-cancellation \
+ 	 tst-tcfree1 tst-tcfree2 tst-tcfree3 \
++	 tst-mxfast \
+ 
+ tests-static := \
+ 	 tst-interpose-static-nothread \
+@@ -196,6 +197,8 @@ tst-malloc-usable-static-ENV = $(tst-malloc-usable-ENV)
+ tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3
+ tst-malloc-usable-static-tunables-ENV = $(tst-malloc-usable-tunables-ENV)
+ 
++tst-mxfast-ENV = GLIBC_TUNABLES=glibc.malloc.tcache_count=0:glibc.malloc.mxfast=0
++
+ ifeq ($(experimental-malloc),yes)
+ CPPFLAGS-malloc.c += -DUSE_TCACHE=1
+ else
+diff --git a/malloc/arena.c b/malloc/arena.c
+index ff8fd5d2a7e51ac8..f5c7ad4570ad6186 100644
+--- a/malloc/arena.c
++++ b/malloc/arena.c
+@@ -237,6 +237,7 @@ TUNABLE_CALLBACK_FNDECL (set_tcache_max, size_t)
+ TUNABLE_CALLBACK_FNDECL (set_tcache_count, size_t)
+ TUNABLE_CALLBACK_FNDECL (set_tcache_unsorted_limit, size_t)
+ #endif
++TUNABLE_CALLBACK_FNDECL (set_mxfast, size_t)
+ #else
+ /* Initialization routine. */
+ #include <string.h>
+@@ -324,6 +325,7 @@ ptmalloc_init (void)
+   TUNABLE_GET (tcache_unsorted_limit, size_t,
+ 	       TUNABLE_CALLBACK (set_tcache_unsorted_limit));
+ # endif
++  TUNABLE_GET (mxfast, size_t, TUNABLE_CALLBACK (set_mxfast));
+ #else
+   const char *s = NULL;
+   if (__glibc_likely (_environ != NULL))
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index fcf480acdaea1b86..9756ed0a0d28c5f6 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -5142,6 +5142,19 @@ do_set_tcache_unsorted_limit (size_t value)
+ }
+ #endif
+ 
++static inline int
++__always_inline
++do_set_mxfast (size_t value)
++{
++  if (value >= 0 && value <= MAX_FAST_SIZE)
++    {
++      LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
++      set_max_fast (value);
++      return 1;
++    }
++  return 0;
++}
++
+ int
+ __libc_mallopt (int param_number, int value)
+ {
+@@ -5161,13 +5174,7 @@ __libc_mallopt (int param_number, int value)
+   switch (param_number)
+     {
+     case M_MXFAST:
+-      if (value >= 0 && value <= MAX_FAST_SIZE)
+-        {
+-          LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
+-          set_max_fast (value);
+-        }
+-      else
+-        res = 0;
++      do_set_mxfast (value);
+       break;
+ 
+     case M_TRIM_THRESHOLD:
+diff --git a/malloc/tst-mxfast.c b/malloc/tst-mxfast.c
+new file mode 100644
+index 0000000000000000..7a371d2f9d2f0005
+--- /dev/null
++++ b/malloc/tst-mxfast.c
+@@ -0,0 +1,50 @@
++/* Test that glibc.malloc.mxfast tunable works.
++   Copyright (C) 2018, 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++/* This test verifies that setting the glibc.malloc.mxfast tunable to
++   zero results in free'd blocks being returned to the small bins, not
++   the fast bins.  */
++
++#include <malloc.h>
++#include <assert.h>
++
++int
++do_test(void)
++{
++  struct mallinfo m;
++  char * volatile p1;
++  char * volatile p2;
++
++  /* Arbitrary value; must be in default fastbin range.  */
++  p1 = malloc (3);
++  /* Something large so that p1 isn't a "top block" */
++  p2 = malloc (512);
++  free (p1);
++
++  m = mallinfo();
++
++  /* This will fail if there are any blocks in the fastbins.  */
++  assert (m.smblks == 0);
++
++  /* To keep gcc happy.  */
++  free (p2);
++
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/manual/tunables.texi b/manual/tunables.texi
+index f6c49250e3889ddd..3dc6f9a44592c030 100644
+--- a/manual/tunables.texi
++++ b/manual/tunables.texi
+@@ -213,6 +213,18 @@ pre-fill the per-thread cache with.  The default, or when set to zero,
+ is no limit.
+ @end deftp
+ 
++@deftp Tunable glibc.malloc.mxfast
++One of the optimizations malloc uses is to maintain a series of ``fast
++bins'' that hold chunks up to a specific size.  The default and
++maximum size which may be held this way is 80 bytes on 32-bit systems
++or 160 bytes on 64-bit systems.  Applications which value size over
++speed may choose to reduce the size of requests which are serviced
++from fast bins with this tunable.  Note that the value specified
++includes malloc's internal overhead, which is normally the size of one
++pointer, so add 4 on 32-bit systems or 8 on 64-bit systems to the size
++passed to @code{malloc} for the largest bin size to enable.
++@end deftp
++
+ @node Elision Tunables
+ @section Elision Tunables
+ @cindex elision tunables
diff --git a/SOURCES/glibc-rh1764218-2.patch b/SOURCES/glibc-rh1764218-2.patch
new file mode 100644
index 0000000..8408975
--- /dev/null
+++ b/SOURCES/glibc-rh1764218-2.patch
@@ -0,0 +1,72 @@
+commit 5dab5eafb3dc2f72aaab911084d127d1af45a08c
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Thu Aug 15 11:37:18 2019 +0200
+
+    malloc: Various cleanups for malloc/tst-mxfast
+    
+    (cherry picked from commit f9769a239784772453d595bc2f4bed8739810e06)
+
+diff --git a/malloc/Makefile b/malloc/Makefile
+index bf9a53cb7c5ebacb..19c2a846ed8ce049 100644
+--- a/malloc/Makefile
++++ b/malloc/Makefile
+@@ -39,7 +39,6 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
+ 	 tst-malloc-too-large \
+ 	 tst-malloc-stats-cancellation \
+ 	 tst-tcfree1 tst-tcfree2 tst-tcfree3 \
+-	 tst-mxfast \
+ 
+ tests-static := \
+ 	 tst-interpose-static-nothread \
+@@ -55,7 +54,7 @@ tests-internal += \
+ 	 tst-dynarray-at-fail \
+ 
+ ifneq (no,$(have-tunables))
+-tests += tst-malloc-usable-tunables
++tests += tst-malloc-usable-tunables tst-mxfast
+ tests-static += tst-malloc-usable-static-tunables
+ endif
+ 
+diff --git a/malloc/tst-mxfast.c b/malloc/tst-mxfast.c
+index 7a371d2f9d2f0005..7a7750bc71024bfb 100644
+--- a/malloc/tst-mxfast.c
++++ b/malloc/tst-mxfast.c
+@@ -1,5 +1,5 @@
+ /* Test that glibc.malloc.mxfast tunable works.
+-   Copyright (C) 2018, 2019 Free Software Foundation, Inc.
++   Copyright (C) 2019 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
+@@ -21,14 +21,14 @@
+    the fast bins.  */
+ 
+ #include <malloc.h>
+-#include <assert.h>
++#include <support/check.h>
+ 
+ int
+-do_test(void)
++do_test (void)
+ {
+   struct mallinfo m;
+-  char * volatile p1;
+-  char * volatile p2;
++  char *volatile p1;
++  char *volatile p2;
+ 
+   /* Arbitrary value; must be in default fastbin range.  */
+   p1 = malloc (3);
+@@ -36,10 +36,10 @@ do_test(void)
+   p2 = malloc (512);
+   free (p1);
+ 
+-  m = mallinfo();
++  m = mallinfo ();
+ 
+   /* This will fail if there are any blocks in the fastbins.  */
+-  assert (m.smblks == 0);
++  TEST_COMPARE (m.smblks, 0);
+ 
+   /* To keep gcc happy.  */
+   free (p2);
diff --git a/SOURCES/glibc-rh1764218-3.patch b/SOURCES/glibc-rh1764218-3.patch
new file mode 100644
index 0000000..ba35b8e
--- /dev/null
+++ b/SOURCES/glibc-rh1764218-3.patch
@@ -0,0 +1,31 @@
+commit f144981490bd2ab13189d85902ca74beecb307e4
+Author: DJ Delorie <dj@redhat.com>
+Date:   Wed Oct 30 18:03:14 2019 -0400
+
+    Base max_fast on alignment, not width, of bins (Bug 24903)
+    
+    set_max_fast sets the "impossibly small" value based on,
+    eventually, MALLOC_ALIGNMENT.  The comparisons for the smallest
+    chunk used is, eventually, MIN_CHUNK_SIZE.  Note that i386
+    is the only platform where these are the same, so a smallest
+    chunk *would* be put in a no-fastbins fastbin.
+    
+    This change calculates the "impossibly small" value
+    based on MIN_CHUNK_SIZE instead, so that we can know it will
+    always be impossibly small.
+    
+    (cherry picked from commit ff12e0fb91b9072800f031cb21fb2651ee7b6251)
+
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index 9756ed0a0d28c5f6..90825b2aaed53761 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -1635,7 +1635,7 @@ static INTERNAL_SIZE_T global_max_fast;
+ 
+ #define set_max_fast(s) \
+   global_max_fast = (((s) == 0)						      \
+-                     ? SMALLBIN_WIDTH : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
++                     ? MIN_CHUNK_SIZE / 2 : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
+ 
+ static inline INTERNAL_SIZE_T
+ get_max_fast (void)
diff --git a/SOURCES/glibc-rh1764223.patch b/SOURCES/glibc-rh1764223.patch
new file mode 100644
index 0000000..372efaf
--- /dev/null
+++ b/SOURCES/glibc-rh1764223.patch
@@ -0,0 +1,142 @@
+commit 2c75b545de6fe3c44138799c68217a94bc669a88
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Tue Jun 18 16:42:10 2019 +0200
+
+    elf: Refuse to dlopen PIE objects [BZ #24323]
+    
+    Another executable has already been mapped, so the dynamic linker
+    cannot perform relocations correctly for the second executable.
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 08e2f99..27a2fa8 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -310,7 +310,7 @@ test-xfail-tst-protected1b = yes
+ endif
+ ifeq (yesyes,$(have-fpie)$(build-shared))
+ modules-names += tst-piemod1
+-tests += tst-pie1 tst-pie2
++tests += tst-pie1 tst-pie2 tst-dlopen-pie
+ tests-pie += tst-pie1 tst-pie2
+ ifeq (yes,$(have-protected-data))
+ tests += vismain
+@@ -1084,6 +1084,8 @@ CFLAGS-tst-pie2.c += $(pie-ccflag)
+ 
+ $(objpfx)tst-piemod1.so: $(libsupport)
+ $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
++$(objpfx)tst-dlopen-pie: $(libdl)
++$(objpfx)tst-dlopen-pie.out: $(objpfx)tst-pie1
+ 
+ ifeq (yes,$(build-shared))
+ # NB: Please keep cet-built-dso in sysdeps/x86/Makefile in sync with
+diff --git a/elf/dl-load.c b/elf/dl-load.c
+index 2bbef81..5abeb86 100644
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -1158,6 +1158,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
+ 	goto call_lose;
+       }
+ 
++    /* dlopen of an executable is not valid because it is not possible
++       to perform proper relocations, handle static TLS, or run the
++       ELF constructors.  For PIE, the check needs the dynamic
++       section, so there is another check below.  */
+     if (__glibc_unlikely (type != ET_DYN)
+ 	&& __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0))
+       {
+@@ -1194,9 +1198,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
+   elf_get_dynamic_info (l, NULL);
+ 
+   /* Make sure we are not dlopen'ing an object that has the
+-     DF_1_NOOPEN flag set.  */
+-  if (__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)
+-      && (mode & __RTLD_DLOPEN))
++     DF_1_NOOPEN flag set, or a PIE object.  */
++  if ((__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)
++       && (mode & __RTLD_DLOPEN))
++      || (__glibc_unlikely (l->l_flags_1 & DF_1_PIE)
++	  && __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0)))
+     {
+       /* We are not supposed to load this object.  Free all resources.  */
+       _dl_unmap_segments (l);
+@@ -1207,7 +1213,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
+       if (l->l_phdr_allocated)
+ 	free ((void *) l->l_phdr);
+ 
+-      errstring = N_("shared object cannot be dlopen()ed");
++      if (l->l_flags_1 & DF_1_PIE)
++	errstring
++	  = N_("cannot dynamically load position-independent executable");
++      else
++	errstring = N_("shared object cannot be dlopen()ed");
+       goto call_lose;
+     }
+ 
+diff --git a/elf/tst-dlopen-pie.c b/elf/tst-dlopen-pie.c
+new file mode 100644
+index 0000000..6a41c73
+--- /dev/null
++++ b/elf/tst-dlopen-pie.c
+@@ -0,0 +1,49 @@
++/* dlopen test for PIE objects.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++/* This test attempts to open the (otherwise unrelated) PIE test
++   program elf/tst-pie1 and expects the attempt to fail.  */
++
++#include <dlfcn.h>
++#include <stddef.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/support.h>
++
++static void
++test_mode (int mode)
++{
++  char *pie_path = xasprintf ("%s/elf/tst-pie1", support_objdir_root);
++  if (dlopen (pie_path, mode) != NULL)
++    FAIL_EXIT1 ("dlopen succeeded unexpectedly (%d)", mode);
++  const char *message = dlerror ();
++  const char *expected
++    = "cannot dynamically load position-independent executable";
++  if (strstr (message, expected) == NULL)
++    FAIL_EXIT1 ("unexpected error message (mode %d): %s", mode, message);
++}
++
++static int
++do_test (void)
++{
++  test_mode (RTLD_LAZY);
++  test_mode (RTLD_NOW);
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/include/elf.h b/include/elf.h
+index ab76aaf..14ed67f 100644
+--- a/include/elf.h
++++ b/include/elf.h
+@@ -23,7 +23,7 @@
+ # endif
+ # define DT_1_SUPPORTED_MASK \
+    (DF_1_NOW | DF_1_NODELETE | DF_1_INITFIRST | DF_1_NOOPEN \
+-    | DF_1_ORIGIN | DF_1_NODEFLIB)
++    | DF_1_ORIGIN | DF_1_NODEFLIB | DF_1_PIE)
+ 
+ #endif /* !_ISOMAC */
+ #endif /* elf.h */
diff --git a/SOURCES/glibc-rh1764226-1.patch b/SOURCES/glibc-rh1764226-1.patch
new file mode 100644
index 0000000..44035fe
--- /dev/null
+++ b/SOURCES/glibc-rh1764226-1.patch
@@ -0,0 +1,82 @@
+commit 6c29942cbf059aca47fd4bbd852ea42c9d46b71f
+Author: Stefan Liebler <stli@linux.ibm.com>
+Date:   Mon Feb 18 16:12:01 2019 +0100
+
+    misc/tst-clone3: Fix waiting for exited thread.
+    
+    From time to time the test misc/tst-clone3 fails with a timeout.
+    Then futex_wait is blocking.  Usually ctid should be set to zero
+    due to CLONE_CHILD_CLEARTID and the futex should be waken up.
+    But the fail occures if the thread has already exited before
+    ctid is set to the return value of clone().  Then futex_wait() will
+    block as there will be nobody who wakes the futex up again.
+    
+    This patch initializes ctid to a known value before calling clone
+    and the kernel is the only one who updates the value to zero after clone.
+    If futex_wait is called then it is either waked up due to the exited thread
+    or the futex syscall fails as *ctid_ptr is already zero instead of the
+    specified value 1.
+    
+    ChangeLog:
+    
+            * sysdeps/unix/sysv/linux/tst-clone3.c (do_test):
+            Initialize ctid with a known value and remove update of ctid
+            after clone.
+            (wait_tid): Adjust arguments and call futex_wait with ctid_val
+            as assumed current value of ctid_ptr.
+
+diff --git a/sysdeps/unix/sysv/linux/tst-clone3.c b/sysdeps/unix/sysv/linux/tst-clone3.c
+index 784ce18f5343ec72..9f1ed6355e7acffd 100644
+--- a/sysdeps/unix/sysv/linux/tst-clone3.c
++++ b/sysdeps/unix/sysv/linux/tst-clone3.c
+@@ -27,6 +27,7 @@
+ 
+ #include <stackinfo.h>  /* For _STACK_GROWS_{UP,DOWN}.  */
+ #include <support/check.h>
++#include <stdatomic.h>
+ 
+ /* Test if clone call with CLONE_THREAD does not call exit_group.  The 'f'
+    function returns '1', which will be used by clone thread to call the
+@@ -42,11 +43,14 @@ f (void *a)
+ 
+ /* Futex wait for TID argument, similar to pthread_join internal
+    implementation.  */
+-#define wait_tid(tid) \
+-  do {					\
+-    __typeof (tid) __tid;		\
+-    while ((__tid = (tid)) != 0)	\
+-      futex_wait (&(tid), __tid);	\
++#define wait_tid(ctid_ptr, ctid_val)					\
++  do {									\
++    __typeof (*(ctid_ptr)) __tid;					\
++    /* We need acquire MO here so that we synchronize with the		\
++       kernel's store to 0 when the clone terminates.  */		\
++    while ((__tid = atomic_load_explicit (ctid_ptr,			\
++					  memory_order_acquire)) != 0)	\
++      futex_wait (ctid_ptr, ctid_val);					\
+   } while (0)
+ 
+ static inline int
+@@ -64,7 +68,11 @@ do_test (void)
+   clone_flags |= CLONE_VM | CLONE_SIGHAND;
+   /* We will used ctid to call on futex to wait for thread exit.  */
+   clone_flags |= CLONE_CHILD_CLEARTID;
+-  pid_t ctid, tid;
++  /* Initialize with a known value.  ctid is set to zero by the kernel after the
++     cloned thread has exited.  */
++#define CTID_INIT_VAL 1
++  pid_t ctid = CTID_INIT_VAL;
++  pid_t tid;
+ 
+ #ifdef __ia64__
+   extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base,
+@@ -86,8 +94,7 @@ do_test (void)
+   if (tid == -1)
+     FAIL_EXIT1 ("clone failed: %m");
+ 
+-  ctid = tid;
+-  wait_tid (ctid);
++  wait_tid (&ctid, CTID_INIT_VAL);
+ 
+   return 2;
+ }
diff --git a/SOURCES/glibc-rh1764226-2.patch b/SOURCES/glibc-rh1764226-2.patch
new file mode 100644
index 0000000..69902cc
--- /dev/null
+++ b/SOURCES/glibc-rh1764226-2.patch
@@ -0,0 +1,159 @@
+commit 481c30cb9573a280649fbf27251e6a0f4af1b2b1
+Author: Alexandra Hájková <ahajkova@redhat.com>
+Date:   Thu May 9 13:51:40 2019 +0200
+
+    elf: Add tst-ldconfig-bad-aux-cache test [BZ #18093]
+    
+    This test corrupts /var/cache/ldconfig/aux-cache and executes ldconfig
+    to check it will not segfault using the corrupted aux_cache. The test
+    uses the test-in-container framework. Verified no regressions on
+    x86_64.
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 139d072e136284e1..8e907e69eb35e089 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -156,6 +156,9 @@ tests-static-internal := tst-tls1-static tst-tls2-static \
+ CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o
+ tst-tls1-static-non-pie-no-pie = yes
+ 
++tests-container = \
++			  tst-ldconfig-bad-aux-cache
++
+ tests := tst-tls9 tst-leaks1 \
+ 	tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \
+ 	tst-auxv
+diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c
+new file mode 100644
+index 0000000000000000..68ce90a95648f6ab
+--- /dev/null
++++ b/elf/tst-ldconfig-bad-aux-cache.c
+@@ -0,0 +1,117 @@
++/* Test ldconfig does not segfault when aux-cache is corrupted (Bug 18093).
++   Copyright (C) 2019 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public License as
++   published by the Free Software Foundation; either version 2.1 of the
++   License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; see the file COPYING.LIB.  If
++   not, see <http://www.gnu.org/licenses/>.  */
++
++/* This test does the following:
++   Run ldconfig to create the caches.
++   Corrupt the caches.
++   Run ldconfig again.
++   At each step we verify that ldconfig does not crash.  */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <errno.h>
++#include <sys/wait.h>
++#include <ftw.h>
++#include <stdint.h>
++
++#include <support/check.h>
++#include <support/support.h>
++#include <support/xunistd.h>
++
++#include <dirent.h>
++
++static int
++display_info (const char *fpath, const struct stat *sb,
++              int tflag, struct FTW *ftwbuf)
++{
++  printf ("info: %-3s %2d %7jd   %-40s %d %s\n",
++          (tflag == FTW_D) ? "d" : (tflag == FTW_DNR) ? "dnr" :
++          (tflag == FTW_DP) ? "dp" : (tflag == FTW_F) ? "f" :
++          (tflag == FTW_NS) ? "ns" : (tflag == FTW_SL) ? "sl" :
++          (tflag == FTW_SLN) ? "sln" : "???",
++          ftwbuf->level, (intmax_t) sb->st_size,
++          fpath, ftwbuf->base, fpath + ftwbuf->base);
++  /* To tell nftw to continue.  */
++  return 0;
++}
++
++/* Run ldconfig with a corrupt aux-cache, in particular we test for size
++   truncation that might happen if a previous ldconfig run failed or if
++   there were storage or power issues while we were writing the file.
++   We want ldconfig not to crash, and it should be able to do so by
++   computing the expected size of the file (bug 18093).  */
++static int
++do_test (void)
++{
++  char *prog = xasprintf ("%s/ldconfig", support_install_rootsbindir);
++  char *const args[] = { prog, NULL };
++  const char *path = "/var/cache/ldconfig/aux-cache";
++  struct stat64 fs;
++  long int size, new_size, i;
++  int status;
++  pid_t pid;
++
++  /* Create the needed directories. */
++  xmkdirp ("/var/cache/ldconfig", 0777);
++
++  pid = xfork ();
++  /* Run ldconfig fist to generate the aux-cache.  */
++  if (pid == 0)
++    {
++      execv (args[0], args);
++      _exit (1);
++    }
++  else
++    {
++      xwaitpid (pid, &status, 0);
++      TEST_COMPARE(status, 0);
++      xstat (path, &fs);
++
++      size = fs.st_size;
++      /* Run 3 tests, each truncating aux-cache shorter and shorter.  */
++      for (i = 3; i > 0; i--)
++        {
++          new_size = size * i / 4;
++          if (truncate (path, new_size))
++              FAIL_EXIT1 ("truncation failed: %m");
++          if (nftw (path, display_info, 1000, 0) == -1)
++              FAIL_EXIT1 ("nftw failed.");
++
++          pid = xfork ();
++          /* Verify that ldconfig can run with a truncated
++             aux-cache and doesn't crash.  */
++          if (pid == 0)
++            {
++              execv (args[0], args);
++              _exit (1);
++            }
++          else
++            {
++              xwaitpid (pid, &status, 0);
++              TEST_COMPARE(status, 0);
++            }
++        }
++    }
++
++  free (prog);
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/elf/tst-ldconfig-bad-aux-cache.root/etc/ld.so.conf b/elf/tst-ldconfig-bad-aux-cache.root/etc/ld.so.conf
+new file mode 100644
+index 0000000000000000..e1e74dbda2bf3dfa
+--- /dev/null
++++ b/elf/tst-ldconfig-bad-aux-cache.root/etc/ld.so.conf
+@@ -0,0 +1,2 @@
++# This file was created to suppress a warning from ldconfig:
++# /sbin/ldconfig: Warning: ignoring configuration file that cannot be opened: /etc/ld.so.conf: No such file or directory
+diff --git a/elf/tst-ldconfig-bad-aux-cache.root/postclean.req b/elf/tst-ldconfig-bad-aux-cache.root/postclean.req
+new file mode 100644
+index 0000000000000000..e69de29bb2d1d643
diff --git a/SOURCES/glibc-rh1764226-3.patch b/SOURCES/glibc-rh1764226-3.patch
new file mode 100644
index 0000000..cda312f
--- /dev/null
+++ b/SOURCES/glibc-rh1764226-3.patch
@@ -0,0 +1,112 @@
+commit a6c1ce778e5c05a2e6925883b410157ef47654fd
+Author: Alexandra Hájková <ahajkova@redhat.com>
+Date:   Mon Aug 5 13:18:57 2019 +0200
+
+    elf: tst-ldconfig-bad-aux-cache: use support_capture_subprocess
+
+diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c
+index 68ce90a95648f6ab..6e22ff815eaaa817 100644
+--- a/elf/tst-ldconfig-bad-aux-cache.c
++++ b/elf/tst-ldconfig-bad-aux-cache.c
+@@ -31,6 +31,7 @@
+ #include <ftw.h>
+ #include <stdint.h>
+ 
++#include <support/capture_subprocess.h>
+ #include <support/check.h>
+ #include <support/support.h>
+ #include <support/xunistd.h>
+@@ -52,6 +53,15 @@ display_info (const char *fpath, const struct stat *sb,
+   return 0;
+ }
+ 
++static void
++execv_wrapper (void *args)
++{
++  char **argv = args;
++
++  execv (argv[0], argv);
++  FAIL_EXIT1 ("execv: %m");
++}
++
+ /* Run ldconfig with a corrupt aux-cache, in particular we test for size
+    truncation that might happen if a previous ldconfig run failed or if
+    there were storage or power issues while we were writing the file.
+@@ -61,53 +71,38 @@ static int
+ do_test (void)
+ {
+   char *prog = xasprintf ("%s/ldconfig", support_install_rootsbindir);
+-  char *const args[] = { prog, NULL };
++  char *args[] = { prog, NULL };
+   const char *path = "/var/cache/ldconfig/aux-cache";
+   struct stat64 fs;
+   long int size, new_size, i;
+-  int status;
+-  pid_t pid;
+ 
+   /* Create the needed directories. */
+   xmkdirp ("/var/cache/ldconfig", 0777);
+ 
+-  pid = xfork ();
+-  /* Run ldconfig fist to generate the aux-cache.  */
+-  if (pid == 0)
+-    {
+-      execv (args[0], args);
+-      _exit (1);
+-    }
+-  else
++  /* Run ldconfig first to generate the aux-cache.  */
++  struct support_capture_subprocess result;
++  result = support_capture_subprocess (execv_wrapper, args);
++  support_capture_subprocess_check (&result, "execv", 0, sc_allow_none);
++  support_capture_subprocess_free (&result);
++
++  xstat (path, &fs);
++
++  size = fs.st_size;
++  /* Run 3 tests, each truncating aux-cache shorter and shorter.  */
++  for (i = 3; i > 0; i--)
+     {
+-      xwaitpid (pid, &status, 0);
+-      TEST_COMPARE(status, 0);
+-      xstat (path, &fs);
+-
+-      size = fs.st_size;
+-      /* Run 3 tests, each truncating aux-cache shorter and shorter.  */
+-      for (i = 3; i > 0; i--)
+-        {
+-          new_size = size * i / 4;
+-          if (truncate (path, new_size))
+-              FAIL_EXIT1 ("truncation failed: %m");
+-          if (nftw (path, display_info, 1000, 0) == -1)
+-              FAIL_EXIT1 ("nftw failed.");
+-
+-          pid = xfork ();
+-          /* Verify that ldconfig can run with a truncated
+-             aux-cache and doesn't crash.  */
+-          if (pid == 0)
+-            {
+-              execv (args[0], args);
+-              _exit (1);
+-            }
+-          else
+-            {
+-              xwaitpid (pid, &status, 0);
+-              TEST_COMPARE(status, 0);
+-            }
+-        }
++      new_size = size * i / 4;
++      if (truncate (path, new_size))
++        FAIL_EXIT1 ("truncation failed: %m");
++      if (nftw (path, display_info, 1000, 0) == -1)
++        FAIL_EXIT1 ("nftw failed.");
++
++      /* Verify that ldconfig can run with a truncated
++         aux-cache and doesn't crash.  */
++      struct support_capture_subprocess result;
++      result = support_capture_subprocess (execv_wrapper, args);
++      support_capture_subprocess_check (&result, "execv", 0, sc_allow_none);
++      support_capture_subprocess_free (&result);
+     }
+ 
+   free (prog);
diff --git a/SOURCES/glibc-rh1764231-1.patch b/SOURCES/glibc-rh1764231-1.patch
new file mode 100644
index 0000000..f879427
--- /dev/null
+++ b/SOURCES/glibc-rh1764231-1.patch
@@ -0,0 +1,49 @@
+commit 17432d7150bdab3bce2ea66c70ad6c920f54077a
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Fri Jun 28 10:15:30 2019 +0200
+
+    support: Add xdlvsym function
+
+diff --git a/support/xdlfcn.c b/support/xdlfcn.c
+index f34bb059c00f27f7..b4a6b85649d181c8 100644
+--- a/support/xdlfcn.c
++++ b/support/xdlfcn.c
+@@ -48,6 +48,26 @@ xdlsym (void *handle, const char *symbol)
+   return sym;
+ }
+ 
++void *
++xdlvsym (void *handle, const char *symbol, const char *version)
++{
++  /* Clear any pending errors.  */
++  dlerror ();
++
++  void *sym = dlvsym (handle, symbol, version);
++
++  if (sym == NULL)
++    {
++      const char *error = dlerror ();
++      if (error != NULL)
++        FAIL_EXIT1 ("error: dlvsym: %s\n", error);
++      /* If there was no error, we found a NULL symbol.  Return the
++         NULL value in this case.  */
++    }
++
++  return sym;
++}
++
+ void
+ xdlclose (void *handle)
+ {
+diff --git a/support/xdlfcn.h b/support/xdlfcn.h
+index 5ab7494e70924f52..ab1cbb3cb9bb1cc7 100644
+--- a/support/xdlfcn.h
++++ b/support/xdlfcn.h
+@@ -26,6 +26,7 @@ __BEGIN_DECLS
+ /* Each of these terminates process on failure with relevant error message.  */
+ void *xdlopen (const char *filename, int flags);
+ void *xdlsym (void *handle, const char *symbol);
++void *xdlvsym (void *handle, const char *symbol, const char *version);
+ void xdlclose (void *handle);
+ 
+ 
diff --git a/SOURCES/glibc-rh1764231-2.patch b/SOURCES/glibc-rh1764231-2.patch
new file mode 100644
index 0000000..aaff767
--- /dev/null
+++ b/SOURCES/glibc-rh1764231-2.patch
@@ -0,0 +1,342 @@
+commit f0b2132b35248c1f4a80f62a2c38cddcc802aa8c
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Fri Jun 28 10:12:50 2019 +0200
+
+    ld.so: Support moving versioned symbols between sonames [BZ #24741]
+    
+    This change should be fully backwards-compatible because the old
+    code aborted the load if a soname mismatch was encountered
+    (instead of searching further for a matching symbol).  This means
+    that no different symbols are found.
+    
+    The soname check was explicitly disabled for the skip_map != NULL
+    case.  However, this only happens with dl(v)sym and RTLD_NEXT,
+    and those lookups do not come with a verneed entry that could be used
+    for the check.
+    
+    The error check was already explicitly disabled for the skip_map !=
+    NULL case, that is, when dl(v)sym was called with RTLD_NEXT.  But
+    _dl_vsym always sets filename in the struct r_found_version argument
+    to NULL, so the check was not active anyway.  This means that
+    symbol lookup results for the skip_map != NULL case do not change,
+    either.
+
+Conflicts:
+	elf/Makefile
+	  (usual missing backports)
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 29aa3a96738e4176..73f9e25ea5efd63a 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -187,7 +187,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ 	 tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \
+ 	 tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
+ 	 tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
+-	 tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note
++	 tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \
++	 tst-sonamemove-link tst-sonamemove-dlopen
+ #	 reldep9
+ tests-internal += loadtest unload unload2 circleload1 \
+ 	 neededtest neededtest2 neededtest3 neededtest4 \
+@@ -275,7 +276,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ 		tst-latepthreadmod $(tst-tls-many-dynamic-modules) \
+ 		tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \
+ 		tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \
+-		tst-absolute-zero-lib tst-big-note-lib
++		tst-absolute-zero-lib tst-big-note-lib \
++		tst-sonamemove-linkmod1 \
++		tst-sonamemove-runmod1 tst-sonamemove-runmod2
+ 
+ ifeq (yes,$(have-mtls-dialect-gnu2))
+ tests += tst-gnu2-tls1
+@@ -1374,6 +1377,28 @@ tst-audit12-ENV = LD_AUDIT=$(objpfx)tst-auditmod12.so
+ $(objpfx)tst-audit12mod1.so: $(objpfx)tst-audit12mod2.so
+ LDFLAGS-tst-audit12mod2.so = -Wl,--version-script=tst-audit12mod2.map
+ 
++# tst-sonamemove links against an older implementation of the library.
++LDFLAGS-tst-sonamemove-linkmod1.so = \
++  -Wl,--version-script=tst-sonamemove-linkmod1.map \
++  -Wl,-soname,tst-sonamemove-runmod1.so
++LDFLAGS-tst-sonamemove-runmod1.so = -Wl,--no-as-needed \
++  -Wl,--version-script=tst-sonamemove-runmod1.map \
++  -Wl,-soname,tst-sonamemove-runmod1.so
++LDFLAGS-tst-sonamemove-runmod2.so = \
++  -Wl,--version-script=tst-sonamemove-runmod2.map \
++  -Wl,-soname,tst-sonamemove-runmod2.so
++$(objpfx)tst-sonamemove-runmod1.so: $(objpfx)tst-sonamemove-runmod2.so
++# Link against the link module, but depend on the run-time modules
++# for execution.
++$(objpfx)tst-sonamemove-link: $(objpfx)tst-sonamemove-linkmod1.so
++$(objpfx)tst-sonamemove-link.out: \
++  $(objpfx)tst-sonamemove-runmod1.so \
++  $(objpfx)tst-sonamemove-runmod2.so
++$(objpfx)tst-sonamemove-dlopen: $(libdl)
++$(objpfx)tst-sonamemove-dlopen.out: \
++  $(objpfx)tst-sonamemove-runmod1.so \
++  $(objpfx)tst-sonamemove-runmod2.so
++
+ # Override -z defs, so that we can reference an undefined symbol.
+ # Force lazy binding for the same reason.
+ LDFLAGS-tst-latepthreadmod.so = \
+diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
+index 68ecc6179f608547..1d046caf017b582b 100644
+--- a/elf/dl-lookup.c
++++ b/elf/dl-lookup.c
+@@ -536,11 +536,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
+ 	}
+ 
+ skip:
+-      /* If this current map is the one mentioned in the verneed entry
+-	 and we have not found a weak entry, it is a bug.  */
+-      if (symidx == STN_UNDEF && version != NULL && version->filename != NULL
+-	  && __glibc_unlikely (_dl_name_match_p (version->filename, map)))
+-	return -1;
++      ;
+     }
+   while (++i < n);
+ 
+@@ -810,34 +806,10 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
+ 
+   /* Search the relevant loaded objects for a definition.  */
+   for (size_t start = i; *scope != NULL; start = 0, ++scope)
+-    {
+-      int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+-			     &current_value, *scope, start, version, flags,
+-			     skip_map, type_class, undef_map);
+-      if (res > 0)
+-	break;
+-
+-      if (__glibc_unlikely (res < 0) && skip_map == NULL)
+-	{
+-	  /* Oh, oh.  The file named in the relocation entry does not
+-	     contain the needed symbol.  This code is never reached
+-	     for unversioned lookups.  */
+-	  assert (version != NULL);
+-	  const char *reference_name = undef_map ? undef_map->l_name : "";
+-	  struct dl_exception exception;
+-	  /* XXX We cannot translate the message.  */
+-	  _dl_exception_create_format
+-	    (&exception, DSO_FILENAME (reference_name),
+-	     "symbol %s version %s not defined in file %s"
+-	     " with link time reference%s",
+-	     undef_name, version->name, version->filename,
+-	     res == -2 ? " (no version symbols)" : "");
+-	  _dl_signal_cexception (0, &exception, N_("relocation error"));
+-	  _dl_exception_free (&exception);
+-	  *ref = NULL;
+-	  return 0;
+-	}
+-    }
++    if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
++		     &current_value, *scope, start, version, flags,
++		     skip_map, type_class, undef_map) != 0)
++      break;
+ 
+   if (__glibc_unlikely (current_value.s == NULL))
+     {
+diff --git a/elf/tst-sonamemove-dlopen.c b/elf/tst-sonamemove-dlopen.c
+new file mode 100644
+index 0000000000000000..c496705044cdd53c
+--- /dev/null
++++ b/elf/tst-sonamemove-dlopen.c
+@@ -0,0 +1,35 @@
++/* Check that a moved versioned symbol can be found using dlsym, dlvsym.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <stddef.h>
++#include <support/check.h>
++#include <support/xdlfcn.h>
++
++static int
++do_test (void)
++{
++  /* tst-sonamemove-runmod1.so does not define moved_function, but it
++     depends on tst-sonamemove-runmod2.so, which does.  */
++  void *handle = xdlopen ("tst-sonamemove-runmod1.so", RTLD_NOW);
++  TEST_VERIFY (xdlsym (handle, "moved_function") != NULL);
++  TEST_VERIFY (xdlvsym (handle, "moved_function", "SONAME_MOVE") != NULL);
++
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/elf/tst-sonamemove-link.c b/elf/tst-sonamemove-link.c
+new file mode 100644
+index 0000000000000000..4bc3bf32f88f97a9
+--- /dev/null
++++ b/elf/tst-sonamemove-link.c
+@@ -0,0 +1,41 @@
++/* Check that a versioned symbol can move from one library to another.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++/* At link time, moved_function is bound to the symbol version
++   SONAME_MOVE in tst-sonamemove-runmod1.so, using the
++   tst-sonamemove-linkmod1.so stub object.
++
++   At run time, the process loads the real tst-sonamemove-runmod1.so,
++   which depends on tst-sonamemove-runmod2.so.
++   tst-sonamemove-runmod1.so does not define moved_function, but
++   tst-sonamemove-runmod2.so does.
++
++   The net effect is that the versioned symbol
++   moved_function@SONAME_MOVE moved from the soname
++   tst-sonamemove-linkmod1.so at link time to the soname
++   tst-sonamemove-linkmod2.so at run time. */
++void moved_function (void);
++
++static int
++do_test (void)
++{
++  moved_function ();
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/elf/tst-sonamemove-linkmod1.c b/elf/tst-sonamemove-linkmod1.c
+new file mode 100644
+index 0000000000000000..b8a354e5e394f566
+--- /dev/null
++++ b/elf/tst-sonamemove-linkmod1.c
+@@ -0,0 +1,25 @@
++/* Link interface for (lack of) soname matching in versioned symbol refs.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++/* This function moved from tst-sonamemove-runmod1.so.  This module is
++   intended for linking only, to simulate an old application which was
++   linked against an older version of the library.  */
++void
++moved_function (void)
++{
++}
+diff --git a/elf/tst-sonamemove-linkmod1.map b/elf/tst-sonamemove-linkmod1.map
+new file mode 100644
+index 0000000000000000..8fe5904018972009
+--- /dev/null
++++ b/elf/tst-sonamemove-linkmod1.map
+@@ -0,0 +1,3 @@
++SONAME_MOVE {
++  global: moved_function;
++};
+diff --git a/elf/tst-sonamemove-runmod1.c b/elf/tst-sonamemove-runmod1.c
+new file mode 100644
+index 0000000000000000..5c409e22898bc836
+--- /dev/null
++++ b/elf/tst-sonamemove-runmod1.c
+@@ -0,0 +1,23 @@
++/* Run-time module whose moved_function moved to a library dependency.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++/* Dummy function to add the required symbol version.  */
++void
++other_function (void)
++{
++}
+diff --git a/elf/tst-sonamemove-runmod1.map b/elf/tst-sonamemove-runmod1.map
+new file mode 100644
+index 0000000000000000..2ea81c6e6ffae2be
+--- /dev/null
++++ b/elf/tst-sonamemove-runmod1.map
+@@ -0,0 +1,3 @@
++SONAME_MOVE {
++  global: other_function;
++};
+diff --git a/elf/tst-sonamemove-runmod2.c b/elf/tst-sonamemove-runmod2.c
+new file mode 100644
+index 0000000000000000..b5e482eff57d7d83
+--- /dev/null
++++ b/elf/tst-sonamemove-runmod2.c
+@@ -0,0 +1,24 @@
++/* Run-time module with the actual implementation of moved_function.
++   Copyright (C) 2019 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
++   <http://www.gnu.org/licenses/>.  */
++
++/* In the test scenario, this function was originally in
++   tst-sonamemove-runmod1.so.  */
++void
++moved_function (void)
++{
++}
+diff --git a/elf/tst-sonamemove-runmod2.map b/elf/tst-sonamemove-runmod2.map
+new file mode 100644
+index 0000000000000000..8fe5904018972009
+--- /dev/null
++++ b/elf/tst-sonamemove-runmod2.map
+@@ -0,0 +1,3 @@
++SONAME_MOVE {
++  global: moved_function;
++};
diff --git a/SOURCES/glibc-rh1764234-1.patch b/SOURCES/glibc-rh1764234-1.patch
new file mode 100644
index 0000000..0bbcf35
--- /dev/null
+++ b/SOURCES/glibc-rh1764234-1.patch
@@ -0,0 +1,40 @@
+commit 47ad5e1a2a3ab8eeda491454cbef3b1c5239dc02
+Author: Joseph Myers <joseph@codesourcery.com>
+Date:   Tue Jan 1 02:01:02 2019 +0000
+
+    Update syscall-names.list for Linux 4.20.
+    
+    This patch updates sysdeps/unix/sysv/linux/syscall-names.list for
+    Linux 4.20.  Although there are no new syscalls, the
+    riscv_flush_icache syscall has moved to asm/unistd.h (previously in
+    asm/syscalls.h) and so now needs to be added to the list.
+    
+    Tested with build-many-glibcs.py.
+    
+            * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel
+            version to 4.20.
+            (riscv_flush_icache): New syscall.
+
+diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
+index 698069a52d..b650dc07cc 100644
+--- a/sysdeps/unix/sysv/linux/syscall-names.list
++++ b/sysdeps/unix/sysv/linux/syscall-names.list
+@@ -22,8 +22,8 @@
+ # names are only used if the installed kernel headers also provide
+ # them.
+ 
+-# The list of system calls is current as of Linux 4.19.
+-kernel 4.19
++# The list of system calls is current as of Linux 4.20.
++kernel 4.20
+ 
+ FAST_atomic_update
+ FAST_cmpxchg
+@@ -431,6 +431,7 @@ renameat
+ renameat2
+ request_key
+ restart_syscall
++riscv_flush_icache
+ rmdir
+ rseq
+ rt_sigaction
diff --git a/SOURCES/glibc-rh1764234-2.patch b/SOURCES/glibc-rh1764234-2.patch
new file mode 100644
index 0000000..d8d5245
--- /dev/null
+++ b/SOURCES/glibc-rh1764234-2.patch
@@ -0,0 +1,43 @@
+commit 477e739b324349df854209117047779ac3142130
+Author: Joseph Myers <joseph@codesourcery.com>
+Date:   Fri Mar 15 18:18:40 2019 +0000
+
+    Update syscall-names.list for Linux 5.0.
+    
+    This patch updates sysdeps/unix/sysv/linux/syscall-names.list for
+    Linux 5.0.  Based on testing with build-many-glibcs.py, the only new
+    entry needed is for old_getpagesize (a newly added __NR_* name for an
+    old syscall on ia64).  (Because 5.0 changes how syscall tables are
+    handled in the kernel, checking diffs wasn't a useful way of looking
+    for new syscalls in 5.0 as most of the syscall tables were moved to
+    the new representation without actually adding any syscalls to them.)
+    
+    Tested with build-many-glibcs.py.
+    
+            * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel
+            version to 5.0.
+            (old_getpagesize): New syscall.
+
+diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
+index b650dc07cc..0227e52a5f 100644
+--- a/sysdeps/unix/sysv/linux/syscall-names.list
++++ b/sysdeps/unix/sysv/linux/syscall-names.list
+@@ -22,8 +22,8 @@
+ # names are only used if the installed kernel headers also provide
+ # them.
+ 
+-# The list of system calls is current as of Linux 4.20.
+-kernel 4.20
++# The list of system calls is current as of Linux 5.0.
++kernel 5.0
+ 
+ FAST_atomic_update
+ FAST_cmpxchg
+@@ -261,6 +261,7 @@ nfsservctl
+ ni_syscall
+ nice
+ old_adjtimex
++old_getpagesize
+ oldfstat
+ oldlstat
+ oldolduname
diff --git a/SOURCES/glibc-rh1764234-3.patch b/SOURCES/glibc-rh1764234-3.patch
new file mode 100644
index 0000000..a336060
--- /dev/null
+++ b/SOURCES/glibc-rh1764234-3.patch
@@ -0,0 +1,181 @@
+commit 7621676f7a5130c030f7fff1cab72dbf2993b837
+Author: Joseph Myers <joseph@codesourcery.com>
+Date:   Tue May 7 23:57:26 2019 +0000
+
+    Update syscall-names.list for Linux 5.1.
+    
+    This patch updates syscall-names.list for Linux 5.1 (which has many
+    new syscalls, mainly but not entirely ones for 64-bit time).
+    
+    Tested with build-many-glibcs.py (before the revert of the move to
+    Linux 5.1 there; verified there were no tst-syscall-list failures).
+    
+            * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel
+            version to 5.1.
+            (clock_adjtime64) New syscall.
+            (clock_getres_time64) Likewise.
+            (clock_gettime64) Likewise.
+            (clock_nanosleep_time64) Likewise.
+            (clock_settime64) Likewise.
+            (futex_time64) Likewise.
+            (io_pgetevents_time64) Likewise.
+            (io_uring_enter) Likewise.
+            (io_uring_register) Likewise.
+            (io_uring_setup) Likewise.
+            (mq_timedreceive_time64) Likewise.
+            (mq_timedsend_time64) Likewise.
+            (pidfd_send_signal) Likewise.
+            (ppoll_time64) Likewise.
+            (pselect6_time64) Likewise.
+            (recvmmsg_time64) Likewise.
+            (rt_sigtimedwait_time64) Likewise.
+            (sched_rr_get_interval_time64) Likewise.
+            (semtimedop_time64) Likewise.
+            (timer_gettime64) Likewise.
+            (timer_settime64) Likewise.
+            (timerfd_gettime64) Likewise.
+            (timerfd_settime64) Likewise.
+            (utimensat_time64) Likewise.
+
+diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
+index 0227e52a5f..2d0354b8b3 100644
+--- a/sysdeps/unix/sysv/linux/syscall-names.list
++++ b/sysdeps/unix/sysv/linux/syscall-names.list
+@@ -22,8 +22,8 @@
+ # names are only used if the installed kernel headers also provide
+ # them.
+ 
+-# The list of system calls is current as of Linux 5.0.
+-kernel 5.0
++# The list of system calls is current as of Linux 5.1.
++kernel 5.1
+ 
+ FAST_atomic_update
+ FAST_cmpxchg
+@@ -63,10 +63,15 @@ chown
+ chown32
+ chroot
+ clock_adjtime
++clock_adjtime64
+ clock_getres
++clock_getres_time64
+ clock_gettime
++clock_gettime64
+ clock_nanosleep
++clock_nanosleep_time64
+ clock_settime
++clock_settime64
+ clone
+ clone2
+ close
+@@ -128,6 +133,7 @@ ftime
+ ftruncate
+ ftruncate64
+ futex
++futex_time64
+ futimesat
+ get_kernel_syms
+ get_mempolicy
+@@ -187,8 +193,12 @@ io_cancel
+ io_destroy
+ io_getevents
+ io_pgetevents
++io_pgetevents_time64
+ io_setup
+ io_submit
++io_uring_enter
++io_uring_register
++io_uring_setup
+ ioctl
+ ioperm
+ iopl
+@@ -242,7 +252,9 @@ mq_getsetattr
+ mq_notify
+ mq_open
+ mq_timedreceive
++mq_timedreceive_time64
+ mq_timedsend
++mq_timedsend_time64
+ mq_unlink
+ mremap
+ msgctl
+@@ -389,6 +401,7 @@ perf_event_open
+ perfctr
+ perfmonctl
+ personality
++pidfd_send_signal
+ pipe
+ pipe2
+ pivot_root
+@@ -397,6 +410,7 @@ pkey_free
+ pkey_mprotect
+ poll
+ ppoll
++ppoll_time64
+ prctl
+ pread64
+ preadv
+@@ -407,6 +421,7 @@ process_vm_writev
+ prof
+ profil
+ pselect6
++pselect6_time64
+ ptrace
+ putpmsg
+ pwrite64
+@@ -424,6 +439,7 @@ reboot
+ recv
+ recvfrom
+ recvmmsg
++recvmmsg_time64
+ recvmsg
+ remap_file_pages
+ removexattr
+@@ -442,6 +458,7 @@ rt_sigqueueinfo
+ rt_sigreturn
+ rt_sigsuspend
+ rt_sigtimedwait
++rt_sigtimedwait_time64
+ rt_tgsigqueueinfo
+ rtas
+ s390_guarded_storage
+@@ -457,6 +474,7 @@ sched_getattr
+ sched_getparam
+ sched_getscheduler
+ sched_rr_get_interval
++sched_rr_get_interval_time64
+ sched_set_affinity
+ sched_setaffinity
+ sched_setattr
+@@ -470,6 +488,7 @@ semctl
+ semget
+ semop
+ semtimedop
++semtimedop_time64
+ send
+ sendfile
+ sendfile64
+@@ -567,11 +586,15 @@ timer_create
+ timer_delete
+ timer_getoverrun
+ timer_gettime
++timer_gettime64
+ timer_settime
++timer_settime64
+ timerfd
+ timerfd_create
+ timerfd_gettime
++timerfd_gettime64
+ timerfd_settime
++timerfd_settime64
+ times
+ tkill
+ truncate
+@@ -591,6 +614,7 @@ userfaultfd
+ ustat
+ utime
+ utimensat
++utimensat_time64
+ utimes
+ utrap_install
+ vfork
diff --git a/SOURCES/glibc-rh1764234-4.patch b/SOURCES/glibc-rh1764234-4.patch
new file mode 100644
index 0000000..5488fe1
--- /dev/null
+++ b/SOURCES/glibc-rh1764234-4.patch
@@ -0,0 +1,58 @@
+commit 0bb8f8c791862a4ff38a584af23bbb5bf3f90acd
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Fri May 31 13:52:16 2019 +0200
+
+    Linux: Add oddly-named arm syscalls to syscall-names.list
+    
+    <asm/unistd.h> on arm defines the following macros:
+    
+    #define __ARM_NR_breakpoint             (__ARM_NR_BASE+1)
+    #define __ARM_NR_cacheflush             (__ARM_NR_BASE+2)
+    #define __ARM_NR_usr26                  (__ARM_NR_BASE+3)
+    #define __ARM_NR_usr32                  (__ARM_NR_BASE+4)
+    #define __ARM_NR_set_tls                (__ARM_NR_BASE+5)
+    #define __ARM_NR_get_tls                (__ARM_NR_BASE+6)
+    
+    These do not follow the regular __NR_* naming convention and
+    have so far been ignored by the syscall-names.list consistency
+    checks.  This commit adds these names to the file, preparing
+    for the availability of these names in the regular __NR_*
+    namespace.
+
+diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
+index 2d0354b8b3..ae8adabb70 100644
+--- a/sysdeps/unix/sysv/linux/syscall-names.list
++++ b/sysdeps/unix/sysv/linux/syscall-names.list
+@@ -52,6 +52,7 @@ bdflush
+ bind
+ bpf
+ break
++breakpoint
+ brk
+ cachectl
+ cacheflush
+@@ -139,6 +140,7 @@ get_kernel_syms
+ get_mempolicy
+ get_robust_list
+ get_thread_area
++get_tls
+ getcpu
+ getcwd
+ getdents
+@@ -499,6 +501,7 @@ set_mempolicy
+ set_robust_list
+ set_thread_area
+ set_tid_address
++set_tls
+ setdomainname
+ setfsgid
+ setfsgid32
+@@ -611,6 +614,8 @@ unlinkat
+ unshare
+ uselib
+ userfaultfd
++usr26
++usr32
+ ustat
+ utime
+ utimensat
diff --git a/SOURCES/glibc-rh1764234-5.patch b/SOURCES/glibc-rh1764234-5.patch
new file mode 100644
index 0000000..53988c6
--- /dev/null
+++ b/SOURCES/glibc-rh1764234-5.patch
@@ -0,0 +1,30 @@
+commit a63b96fbddbf97feaa068a9efed3b5623a1a1e78
+Author: Vincent Chen <vincentc@andestech.com>
+Date:   Wed Jun 26 17:30:11 2019 +0800
+
+    Linux: Add nds32 specific syscalls to syscall-names.list
+    
+    The nds32 creates two specific syscalls, udftrap and fp_udfiex_crtl, in
+    kernel v5.0 and v5.2, respectively. Add these two syscalls to
+    syscall-names.list.
+
+diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
+index ae8adabb70..95aa3ec7a5 100644
+--- a/sysdeps/unix/sysv/linux/syscall-names.list
++++ b/sysdeps/unix/sysv/linux/syscall-names.list
+@@ -121,6 +121,7 @@ finit_module
+ flistxattr
+ flock
+ fork
++fp_udfiex_crtl
+ free_hugepages
+ fremovexattr
+ fsetxattr
+@@ -603,6 +604,7 @@ tkill
+ truncate
+ truncate64
+ tuxcall
++udftrap
+ ugetrlimit
+ ulimit
+ umask
diff --git a/SOURCES/glibc-rh1764234-6.patch b/SOURCES/glibc-rh1764234-6.patch
new file mode 100644
index 0000000..5f29118
--- /dev/null
+++ b/SOURCES/glibc-rh1764234-6.patch
@@ -0,0 +1,52 @@
+commit 1f7097d09ce628878107ed30341cfc1eb3649a81
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Fri Jul 19 08:53:04 2019 +0200
+
+    Linux: Update syscall-names.list to Linux 5.2
+    
+    This adds the system call names fsconfig, fsmount, fsopen, fspick,
+    move_mount, open_tree.
+    
+    Tested with build-many-glibcs.py.
+
+diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
+index 95aa3ec7a5..21bf37c627 100644
+--- a/sysdeps/unix/sysv/linux/syscall-names.list
++++ b/sysdeps/unix/sysv/linux/syscall-names.list
+@@ -23,7 +23,7 @@
+ # them.
+ 
+ # The list of system calls is current as of Linux 5.1.
+-kernel 5.1
++kernel 5.2
+ 
+ FAST_atomic_update
+ FAST_cmpxchg
+@@ -124,7 +124,11 @@ fork
+ fp_udfiex_crtl
+ free_hugepages
+ fremovexattr
++fsconfig
+ fsetxattr
++fsmount
++fsopen
++fspick
+ fstat
+ fstat64
+ fstatat64
+@@ -248,6 +252,7 @@ mmap
+ mmap2
+ modify_ldt
+ mount
++move_mount
+ move_pages
+ mprotect
+ mpx
+@@ -285,6 +290,7 @@ oldumount
+ olduname
+ open
+ open_by_handle_at
++open_tree
+ openat
+ osf_adjtime
+ osf_afs_syscall
diff --git a/SOURCES/glibc-rh1764234-7.patch b/SOURCES/glibc-rh1764234-7.patch
new file mode 100644
index 0000000..9322a53
--- /dev/null
+++ b/SOURCES/glibc-rh1764234-7.patch
@@ -0,0 +1,24 @@
+commit 9c37bde5a2067e5b4dc878bac0291d6b207b8add
+Author: Joseph Myers <joseph@codesourcery.com>
+Date:   Fri Aug 2 15:08:02 2019 +0000
+
+    Update kernel version in comment in syscall-names.list.
+    
+    This patch updates the Linux kernel version in a comment in
+    syscall-names.list to agree with the following "kernel" line.
+    
+            * sysdeps/unix/sysv/linux/syscall-names.list: Update comment.
+
+diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
+index 21bf37c627..9dcdd293d3 100644
+--- a/sysdeps/unix/sysv/linux/syscall-names.list
++++ b/sysdeps/unix/sysv/linux/syscall-names.list
+@@ -22,7 +22,7 @@
+ # names are only used if the installed kernel headers also provide
+ # them.
+ 
+-# The list of system calls is current as of Linux 5.1.
++# The list of system calls is current as of Linux 5.2.
+ kernel 5.2
+ 
+ FAST_atomic_update
diff --git a/SOURCES/glibc-rh1764234-8.patch b/SOURCES/glibc-rh1764234-8.patch
new file mode 100644
index 0000000..1728729
--- /dev/null
+++ b/SOURCES/glibc-rh1764234-8.patch
@@ -0,0 +1,47 @@
+commit 0f02b6cfc44af73d4d4363c46b3cbb18b8ff9171
+Author: Joseph Myers <joseph@codesourcery.com>
+Date:   Wed Sep 18 22:57:46 2019 +0000
+
+    Update syscall-names.list for Linux 5.3.
+    
+    This patch updates syscall-names.list for Linux 5.3, adding two new
+    syscalls.
+    
+    Tested with build-many-glibcs.py.
+    
+            * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel
+            version to 5.3.
+            (clone3): New syscall.
+            (pidfd_open): Likewise.
+
+diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
+index e2382d3414..b55ffbc2a0 100644
+--- a/sysdeps/unix/sysv/linux/syscall-names.list
++++ b/sysdeps/unix/sysv/linux/syscall-names.list
+@@ -22,8 +22,8 @@
+ # names are only used if the installed kernel headers also provide
+ # them.
+ 
+-# The list of system calls is current as of Linux 5.2.
+-kernel 5.2
++# The list of system calls is current as of Linux 5.3.
++kernel 5.3
+ 
+ FAST_atomic_update
+ FAST_cmpxchg
+@@ -75,6 +75,7 @@ clock_settime
+ clock_settime64
+ clone
+ clone2
++clone3
+ close
+ cmpxchg_badaddr
+ connect
+@@ -410,6 +411,7 @@ perf_event_open
+ perfctr
+ perfmonctl
+ personality
++pidfd_open
+ pidfd_send_signal
+ pipe
+ pipe2
diff --git a/SOURCES/glibc-rh1764235.patch b/SOURCES/glibc-rh1764235.patch
new file mode 100644
index 0000000..1b783b9
--- /dev/null
+++ b/SOURCES/glibc-rh1764235.patch
@@ -0,0 +1,165 @@
+commit e621246ec6393ea08ae50310f9d5e72500f8c9bc
+Author: Carlos O'Donell <carlos@redhat.com>
+Date:   Mon Apr 8 17:35:05 2019 -0400
+
+    malloc: Set and reset all hooks for tracing (Bug 16573)
+    
+    If an error occurs during the tracing operation, particularly during a
+    call to lock_and_info() which calls _dl_addr, we may end up calling back
+    into the malloc-subsystem and relock the loader lock and deadlock. For
+    all intents and purposes the call to _dl_addr can call any of the malloc
+    family API functions and so we should disable all tracing before calling
+    such loader functions.  This is similar to the strategy that the new
+    malloc tracer takes when calling the real malloc, namely that all
+    tracing ceases at the boundary to the real function and any faults at
+    that point are the purvue of the library (though the new tracer does
+    this on a per-thread basis in an MT-safe fashion). Since the new tracer
+    and the hook deprecation are not yet complete we must fix these issues
+    where we can.
+    
+    Tested on x86_64 with no regressions.
+    
+    Co-authored-by: Kwok Cheung Yeung <kcy@codesourcery.com>
+    Reviewed-by: DJ Delorie <dj@redhat.com>
+
+diff --git a/malloc/mtrace.c b/malloc/mtrace.c
+index 9064f209ec3b24c6..546d37a26018bf41 100644
+--- a/malloc/mtrace.c
++++ b/malloc/mtrace.c
+@@ -121,6 +121,41 @@ lock_and_info (const void *caller, Dl_info *mem)
+   return res;
+ }
+ 
++static void tr_freehook (void *, const void *);
++static void * tr_mallochook (size_t, const void *);
++static void * tr_reallochook (void *, size_t, const void *);
++static void * tr_memalignhook (size_t, size_t, const void *);
++
++/* Set all the default non-trace hooks.  */
++static __always_inline void
++set_default_hooks (void)
++{
++  __free_hook = tr_old_free_hook;
++  __malloc_hook = tr_old_malloc_hook;
++  __realloc_hook = tr_old_realloc_hook;
++  __memalign_hook = tr_old_memalign_hook;
++}
++
++/* Set all of the tracing hooks used for mtrace.  */
++static __always_inline void
++set_trace_hooks (void)
++{
++  __free_hook = tr_freehook;
++  __malloc_hook = tr_mallochook;
++  __realloc_hook = tr_reallochook;
++  __memalign_hook = tr_memalignhook;
++}
++
++/* Save the current set of hooks as the default hooks.  */
++static __always_inline void
++save_default_hooks (void)
++{
++  tr_old_free_hook = __free_hook;
++  tr_old_malloc_hook = __malloc_hook;
++  tr_old_realloc_hook = __realloc_hook;
++  tr_old_memalign_hook = __memalign_hook;
++}
++
+ static void
+ tr_freehook (void *ptr, const void *caller)
+ {
+@@ -138,12 +173,12 @@ tr_freehook (void *ptr, const void *caller)
+       tr_break ();
+       __libc_lock_lock (lock);
+     }
+-  __free_hook = tr_old_free_hook;
++  set_default_hooks ();
+   if (tr_old_free_hook != NULL)
+     (*tr_old_free_hook)(ptr, caller);
+   else
+     free (ptr);
+-  __free_hook = tr_freehook;
++  set_trace_hooks ();
+   __libc_lock_unlock (lock);
+ }
+ 
+@@ -155,12 +190,12 @@ tr_mallochook (size_t size, const void *caller)
+   Dl_info mem;
+   Dl_info *info = lock_and_info (caller, &mem);
+ 
+-  __malloc_hook = tr_old_malloc_hook;
++  set_default_hooks ();
+   if (tr_old_malloc_hook != NULL)
+     hdr = (void *) (*tr_old_malloc_hook)(size, caller);
+   else
+     hdr = (void *) malloc (size);
+-  __malloc_hook = tr_mallochook;
++  set_trace_hooks ();
+ 
+   tr_where (caller, info);
+   /* We could be printing a NULL here; that's OK.  */
+@@ -185,16 +220,12 @@ tr_reallochook (void *ptr, size_t size, const void *caller)
+   Dl_info mem;
+   Dl_info *info = lock_and_info (caller, &mem);
+ 
+-  __free_hook = tr_old_free_hook;
+-  __malloc_hook = tr_old_malloc_hook;
+-  __realloc_hook = tr_old_realloc_hook;
++  set_default_hooks ();
+   if (tr_old_realloc_hook != NULL)
+     hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
+   else
+     hdr = (void *) realloc (ptr, size);
+-  __free_hook = tr_freehook;
+-  __malloc_hook = tr_mallochook;
+-  __realloc_hook = tr_reallochook;
++  set_trace_hooks ();
+ 
+   tr_where (caller, info);
+   if (hdr == NULL)
+@@ -230,14 +261,12 @@ tr_memalignhook (size_t alignment, size_t size, const void *caller)
+   Dl_info mem;
+   Dl_info *info = lock_and_info (caller, &mem);
+ 
+-  __memalign_hook = tr_old_memalign_hook;
+-  __malloc_hook = tr_old_malloc_hook;
++  set_default_hooks ();
+   if (tr_old_memalign_hook != NULL)
+     hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
+   else
+     hdr = (void *) memalign (alignment, size);
+-  __memalign_hook = tr_memalignhook;
+-  __malloc_hook = tr_mallochook;
++  set_trace_hooks ();
+ 
+   tr_where (caller, info);
+   /* We could be printing a NULL here; that's OK.  */
+@@ -305,14 +334,8 @@ mtrace (void)
+           malloc_trace_buffer = mtb;
+           setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
+           fprintf (mallstream, "= Start\n");
+-          tr_old_free_hook = __free_hook;
+-          __free_hook = tr_freehook;
+-          tr_old_malloc_hook = __malloc_hook;
+-          __malloc_hook = tr_mallochook;
+-          tr_old_realloc_hook = __realloc_hook;
+-          __realloc_hook = tr_reallochook;
+-          tr_old_memalign_hook = __memalign_hook;
+-          __memalign_hook = tr_memalignhook;
++	  save_default_hooks ();
++	  set_trace_hooks ();
+ #ifdef _LIBC
+           if (!added_atexit_handler)
+             {
+@@ -338,10 +361,7 @@ muntrace (void)
+      file.  */
+   FILE *f = mallstream;
+   mallstream = NULL;
+-  __free_hook = tr_old_free_hook;
+-  __malloc_hook = tr_old_malloc_hook;
+-  __realloc_hook = tr_old_realloc_hook;
+-  __memalign_hook = tr_old_memalign_hook;
++  set_default_hooks ();
+ 
+   fprintf (f, "= End\n");
+   fclose (f);
diff --git a/SOURCES/glibc-rh1764238-1.patch b/SOURCES/glibc-rh1764238-1.patch
new file mode 100644
index 0000000..63fc994
--- /dev/null
+++ b/SOURCES/glibc-rh1764238-1.patch
@@ -0,0 +1,92 @@
+commit dc0afac3252d0c53716ccaf0b424f7769a66d695
+Author: marxin <mliska@suse.cz>
+Date:   Wed Feb 20 14:54:35 2019 +0100
+
+    Add new Fortran vector math header file.
+
+diff --git a/bits/math-vector-fortran.h b/bits/math-vector-fortran.h
+new file mode 100644
+index 0000000000000000..7c1e095094e24571
+--- /dev/null
++++ b/bits/math-vector-fortran.h
+@@ -0,0 +1,19 @@
++! Platform-specific declarations of SIMD math functions for Fortran. -*- f90 -*-
++!   Copyright (C) 2019 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
++!   <http://www.gnu.org/licenses/>.
++
++! No SIMD math functions are available for this platform.
+diff --git a/math/Makefile b/math/Makefile
+index 90b3b68916e12d85..16e68754fc863ea2 100644
+--- a/math/Makefile
++++ b/math/Makefile
+@@ -26,6 +26,7 @@ headers		:= math.h bits/mathcalls.h bits/mathinline.h \
+ 		   fpu_control.h complex.h bits/cmathcalls.h fenv.h \
+ 		   bits/fenv.h bits/fenvinline.h bits/mathdef.h tgmath.h \
+ 		   bits/math-finite.h bits/math-vector.h \
++		   bits/math-vector-fortran.h \
+ 		   bits/libm-simd-decl-stubs.h bits/iscanonical.h \
+ 		   bits/flt-eval-method.h bits/fp-fast.h bits/fp-logb.h \
+ 		   bits/long-double.h bits/mathcalls-helper-functions.h \
+diff --git a/sysdeps/x86/fpu/bits/math-vector-fortran.h b/sysdeps/x86/fpu/bits/math-vector-fortran.h
+new file mode 100644
+index 0000000000000000..36051cc73ea03602
+--- /dev/null
++++ b/sysdeps/x86/fpu/bits/math-vector-fortran.h
+@@ -0,0 +1,43 @@
++! Platform-specific declarations of SIMD math functions for Fortran. -*- f90 -*-
++!   Copyright (C) 2019 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
++!   <http://www.gnu.org/licenses/>.
++
++!GCC$ builtin (cos) attributes simd (notinbranch) if('x86_64')
++!GCC$ builtin (cosf) attributes simd (notinbranch) if('x86_64')
++!GCC$ builtin (sin) attributes simd (notinbranch) if('x86_64')
++!GCC$ builtin (sinf) attributes simd (notinbranch) if('x86_64')
++!GCC$ builtin (sincos) attributes simd (notinbranch) if('x86_64')
++!GCC$ builtin (sincosf) attributes simd (notinbranch) if('x86_64')
++!GCC$ builtin (log) attributes simd (notinbranch) if('x86_64')
++!GCC$ builtin (logf) attributes simd (notinbranch) if('x86_64')
++!GCC$ builtin (exp) attributes simd (notinbranch) if('x86_64')
++!GCC$ builtin (expf) attributes simd (notinbranch) if('x86_64')
++!GCC$ builtin (pow) attributes simd (notinbranch) if('x86_64')
++!GCC$ builtin (powf) attributes simd (notinbranch) if('x86_64')
++
++!GCC$ builtin (cos) attributes simd (notinbranch) if('x32')
++!GCC$ builtin (cosf) attributes simd (notinbranch) if('x32')
++!GCC$ builtin (sin) attributes simd (notinbranch) if('x32')
++!GCC$ builtin (sinf) attributes simd (notinbranch) if('x32')
++!GCC$ builtin (sincos) attributes simd (notinbranch) if('x32')
++!GCC$ builtin (sincosf) attributes simd (notinbranch) if('x32')
++!GCC$ builtin (log) attributes simd (notinbranch) if('x32')
++!GCC$ builtin (logf) attributes simd (notinbranch) if('x32')
++!GCC$ builtin (exp) attributes simd (notinbranch) if('x32')
++!GCC$ builtin (expf) attributes simd (notinbranch) if('x32')
++!GCC$ builtin (pow) attributes simd (notinbranch) if('x32')
++!GCC$ builtin (powf) attributes simd (notinbranch) if('x32')
diff --git a/SOURCES/glibc-rh1764238-2.patch b/SOURCES/glibc-rh1764238-2.patch
new file mode 100644
index 0000000..5cafd01
--- /dev/null
+++ b/SOURCES/glibc-rh1764238-2.patch
@@ -0,0 +1,56 @@
+commit ae514971341dcc08ec7f8622493a65e7eb1ef9d2
+Author: marxin <mliska@suse.cz>
+Date:   Thu Mar 7 09:39:55 2019 +0100
+
+    Fix location where math-vector-fortran.h is installed.
+    
+    2019-03-07  Martin Liska  <mliska@suse.cz>
+    
+            * math/Makefile: Change location where math-vector-fortran.h is
+            installed.
+            * math/finclude/math-vector-fortran.h: Move from bits/math-vector-fortran.h.
+            * sysdeps/x86/fpu/finclude/math-vector-fortran.h: Move
+            from sysdeps/x86/fpu/bits/math-vector-fortran.h.
+            * scripts/check-installed-headers.sh: Skip Fortran header files.
+            * scripts/check-wrapper-headers.py: Likewise.
+
+Conflicts:
+	scripts/check-wrapper-headers.py
+	  (Script does not exist downstream, change dropped.)
+
+diff --git a/math/Makefile b/math/Makefile
+index 16e68754fc863ea2..df73d70840b61cd7 100644
+--- a/math/Makefile
++++ b/math/Makefile
+@@ -26,7 +26,7 @@ headers		:= math.h bits/mathcalls.h bits/mathinline.h \
+ 		   fpu_control.h complex.h bits/cmathcalls.h fenv.h \
+ 		   bits/fenv.h bits/fenvinline.h bits/mathdef.h tgmath.h \
+ 		   bits/math-finite.h bits/math-vector.h \
+-		   bits/math-vector-fortran.h \
++		   finclude/math-vector-fortran.h \
+ 		   bits/libm-simd-decl-stubs.h bits/iscanonical.h \
+ 		   bits/flt-eval-method.h bits/fp-fast.h bits/fp-logb.h \
+ 		   bits/long-double.h bits/mathcalls-helper-functions.h \
+diff --git a/bits/math-vector-fortran.h b/math/finclude/math-vector-fortran.h
+similarity index 100%
+rename from bits/math-vector-fortran.h
+rename to math/finclude/math-vector-fortran.h
+diff --git a/scripts/check-installed-headers.sh b/scripts/check-installed-headers.sh
+index 4a062e9cdaa57978..7a1969b43a144ebb 100644
+--- a/scripts/check-installed-headers.sh
++++ b/scripts/check-installed-headers.sh
+@@ -84,6 +84,10 @@ for header in "$@"; do
+         (sys/elf.h)
+             continue;;
+ 
++        # Skip Fortran headers.
++        (finclude/*)
++            continue;;
++
+ 	# sys/sysctl.h is unsupported for x32.
+ 	(sys/sysctl.h)
+             case "$is_x32" in
+diff --git a/sysdeps/x86/fpu/bits/math-vector-fortran.h b/sysdeps/x86/fpu/finclude/math-vector-fortran.h
+similarity index 100%
+rename from sysdeps/x86/fpu/bits/math-vector-fortran.h
+rename to sysdeps/x86/fpu/finclude/math-vector-fortran.h
diff --git a/SOURCES/glibc-rh1764241.patch b/SOURCES/glibc-rh1764241.patch
new file mode 100644
index 0000000..9044857
--- /dev/null
+++ b/SOURCES/glibc-rh1764241.patch
@@ -0,0 +1,544 @@
+commit 09e1b0e3f6facc1af2dbcfef204f0aaa8718772b
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Mon May 20 21:54:57 2019 +0200
+
+    libio: Remove codecvt vtable [BZ #24588]
+    
+    The codecvt vtable is not a real vtable because it also contains the
+    conversion state data.  Furthermore, wide stream support was added to
+    GCC 3.0, after a C++ ABI bump, so there is no compatibility
+    requirement with libstdc++.
+    
+    This change removes several unmangled function pointers which could
+    be used with a corrupted FILE object to redirect execution.  (libio
+    vtable verification did not cover the codecvt vtable.)
+    
+    Reviewed-by: Yann Droneaud <ydroneaud@opteya.com>
+    Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+diff --git a/libio/fileops.c b/libio/fileops.c
+index d2070a856e..daa5a05877 100644
+--- a/libio/fileops.c
++++ b/libio/fileops.c
+@@ -331,9 +331,6 @@ _IO_new_file_fopen (FILE *fp, const char *filename, const char *mode,
+ 
+ 	  cc = fp->_codecvt = &fp->_wide_data->_codecvt;
+ 
+-	  /* The functions are always the same.  */
+-	  *cc = __libio_codecvt;
+-
+ 	  cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
+ 	  cc->__cd_in.__cd.__steps = fcts.towc;
+ 
+diff --git a/libio/iofgetpos.c b/libio/iofgetpos.c
+index 8032192440..388c4a0708 100644
+--- a/libio/iofgetpos.c
++++ b/libio/iofgetpos.c
+@@ -70,8 +70,7 @@ _IO_new_fgetpos (FILE *fp, __fpos_t *posp)
+   else
+     {
+       posp->__pos = pos;
+-      if (fp->_mode > 0
+-	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)
++      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)
+ 	/* This is a stateful encoding, safe the state.  */
+ 	posp->__state = fp->_wide_data->_IO_state;
+     }
+diff --git a/libio/iofgetpos64.c b/libio/iofgetpos64.c
+index 54de6a8205..6a0ba50d29 100644
+--- a/libio/iofgetpos64.c
++++ b/libio/iofgetpos64.c
+@@ -54,8 +54,7 @@ _IO_new_fgetpos64 (FILE *fp, __fpos64_t *posp)
+   else
+     {
+       posp->__pos = pos;
+-      if (fp->_mode > 0
+-	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)
++      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)
+ 	/* This is a stateful encoding, safe the state.  */
+ 	posp->__state = fp->_wide_data->_IO_state;
+     }
+diff --git a/libio/iofsetpos.c b/libio/iofsetpos.c
+index d7b1abbc61..4df1aae082 100644
+--- a/libio/iofsetpos.c
++++ b/libio/iofsetpos.c
+@@ -58,8 +58,7 @@ _IO_new_fsetpos (FILE *fp, const __fpos_t *posp)
+   else
+     {
+       result = 0;
+-      if (fp->_mode > 0
+-	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)
++      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)
+ 	/* This is a stateful encoding, restore the state.  */
+ 	fp->_wide_data->_IO_state = posp->__state;
+     }
+diff --git a/libio/iofsetpos64.c b/libio/iofsetpos64.c
+index d1865b728e..f382ba0dc1 100644
+--- a/libio/iofsetpos64.c
++++ b/libio/iofsetpos64.c
+@@ -48,8 +48,7 @@ _IO_new_fsetpos64 (FILE *fp, const fpos64_t *posp)
+   else
+     {
+       result = 0;
+-      if (fp->_mode > 0
+-	  && (*fp->_codecvt->__codecvt_do_encoding) (fp->_codecvt) < 0)
++      if (fp->_mode > 0 && __libio_codecvt_encoding (fp->_codecvt) < 0)
+ 	/* This is a stateful encoding, safe the state.  */
+ 	fp->_wide_data->_IO_state = posp->__state;
+     }
+diff --git a/libio/iofwide.c b/libio/iofwide.c
+index 247cfde3d0..80cb2d5074 100644
+--- a/libio/iofwide.c
++++ b/libio/iofwide.c
+@@ -39,44 +39,6 @@
+ #include <sysdep.h>
+ 
+ 
+-/* Prototypes of libio's codecvt functions.  */
+-static enum __codecvt_result do_out (struct _IO_codecvt *codecvt,
+-				     __mbstate_t *statep,
+-				     const wchar_t *from_start,
+-				     const wchar_t *from_end,
+-				     const wchar_t **from_stop, char *to_start,
+-				     char *to_end, char **to_stop);
+-static enum __codecvt_result do_unshift (struct _IO_codecvt *codecvt,
+-					 __mbstate_t *statep, char *to_start,
+-					 char *to_end, char **to_stop);
+-static enum __codecvt_result do_in (struct _IO_codecvt *codecvt,
+-				    __mbstate_t *statep,
+-				    const char *from_start,
+-				    const char *from_end,
+-				    const char **from_stop, wchar_t *to_start,
+-				    wchar_t *to_end, wchar_t **to_stop);
+-static int do_encoding (struct _IO_codecvt *codecvt);
+-static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
+-		      const char *from_start,
+-		      const char *from_end, size_t max);
+-static int do_max_length (struct _IO_codecvt *codecvt);
+-static int do_always_noconv (struct _IO_codecvt *codecvt);
+-
+-
+-/* The functions used in `codecvt' for libio are always the same.  */
+-const struct _IO_codecvt __libio_codecvt =
+-{
+-  .__codecvt_destr = NULL,		/* Destructor, never used.  */
+-  .__codecvt_do_out = do_out,
+-  .__codecvt_do_unshift = do_unshift,
+-  .__codecvt_do_in = do_in,
+-  .__codecvt_do_encoding = do_encoding,
+-  .__codecvt_do_always_noconv = do_always_noconv,
+-  .__codecvt_do_length = do_length,
+-  .__codecvt_do_max_length = do_max_length
+-};
+-
+-
+ /* Return orientation of stream.  If mode is nonzero try to change
+    the orientation first.  */
+ #undef _IO_fwide
+@@ -118,9 +80,6 @@ _IO_fwide (FILE *fp, int mode)
+ 	assert (fcts.towc_nsteps == 1);
+ 	assert (fcts.tomb_nsteps == 1);
+ 
+-	/* The functions are always the same.  */
+-	*cc = __libio_codecvt;
+-
+ 	cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
+ 	cc->__cd_in.__cd.__steps = fcts.towc;
+ 
+@@ -150,11 +109,11 @@ _IO_fwide (FILE *fp, int mode)
+ }
+ 
+ 
+-static enum __codecvt_result
+-do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
+-	const wchar_t *from_start, const wchar_t *from_end,
+-	const wchar_t **from_stop, char *to_start, char *to_end,
+-	char **to_stop)
++enum __codecvt_result
++__libio_codecvt_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
++		     const wchar_t *from_start, const wchar_t *from_end,
++		     const wchar_t **from_stop, char *to_start, char *to_end,
++		     char **to_stop)
+ {
+   enum __codecvt_result result;
+ 
+@@ -202,57 +161,11 @@ do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
+ }
+ 
+ 
+-static enum __codecvt_result
+-do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep,
+-	    char *to_start, char *to_end, char **to_stop)
+-{
+-  enum __codecvt_result result;
+-
+-  struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
+-  int status;
+-  size_t dummy;
+-
+-  codecvt->__cd_out.__cd.__data[0].__outbuf = (unsigned char *) to_start;
+-  codecvt->__cd_out.__cd.__data[0].__outbufend = (unsigned char *) to_end;
+-  codecvt->__cd_out.__cd.__data[0].__statep = statep;
+-
+-  __gconv_fct fct = gs->__fct;
+-#ifdef PTR_DEMANGLE
+-  if (gs->__shlib_handle != NULL)
+-    PTR_DEMANGLE (fct);
+-#endif
+-
+-  status = DL_CALL_FCT (fct,
+-			(gs, codecvt->__cd_out.__cd.__data, NULL, NULL,
+-			 NULL, &dummy, 1, 0));
+-
+-  *to_stop = (char *) codecvt->__cd_out.__cd.__data[0].__outbuf;
+-
+-  switch (status)
+-    {
+-    case __GCONV_OK:
+-    case __GCONV_EMPTY_INPUT:
+-      result = __codecvt_ok;
+-      break;
+-
+-    case __GCONV_FULL_OUTPUT:
+-    case __GCONV_INCOMPLETE_INPUT:
+-      result = __codecvt_partial;
+-      break;
+-
+-    default:
+-      result = __codecvt_error;
+-      break;
+-    }
+-
+-  return result;
+-}
+-
+-
+-static enum __codecvt_result
+-do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
+-       const char *from_start, const char *from_end, const char **from_stop,
+-       wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
++enum __codecvt_result
++__libio_codecvt_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
++		    const char *from_start, const char *from_end,
++		    const char **from_stop,
++		    wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
+ {
+   enum __codecvt_result result;
+ 
+@@ -300,8 +213,8 @@ do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
+ }
+ 
+ 
+-static int
+-do_encoding (struct _IO_codecvt *codecvt)
++int
++__libio_codecvt_encoding (struct _IO_codecvt *codecvt)
+ {
+   /* See whether the encoding is stateful.  */
+   if (codecvt->__cd_in.__cd.__steps[0].__stateful)
+@@ -317,16 +230,10 @@ do_encoding (struct _IO_codecvt *codecvt)
+ }
+ 
+ 
+-static int
+-do_always_noconv (struct _IO_codecvt *codecvt)
+-{
+-  return 0;
+-}
+-
+-
+-static int
+-do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
+-	   const char *from_start, const char *from_end, size_t max)
++int
++__libio_codecvt_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
++			const char *from_start, const char *from_end,
++			size_t max)
+ {
+   int result;
+   const unsigned char *cp = (const unsigned char *) from_start;
+@@ -353,10 +260,3 @@ do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
+ 
+   return result;
+ }
+-
+-
+-static int
+-do_max_length (struct _IO_codecvt *codecvt)
+-{
+-  return codecvt->__cd_in.__cd.__steps[0].__max_needed_from;
+-}
+diff --git a/libio/libio.h b/libio/libio.h
+index c38095ff77..b985c386a2 100644
+--- a/libio/libio.h
++++ b/libio/libio.h
+@@ -116,40 +116,8 @@ struct _IO_marker {
+   int _pos;
+ };
+ 
+-/* This is the structure from the libstdc++ codecvt class.  */
+-enum __codecvt_result
+-{
+-  __codecvt_ok,
+-  __codecvt_partial,
+-  __codecvt_error,
+-  __codecvt_noconv
+-};
+-
+-/* The order of the elements in the following struct must match the order
+-   of the virtual functions in the libstdc++ codecvt class.  */
+ struct _IO_codecvt
+ {
+-  void (*__codecvt_destr) (struct _IO_codecvt *);
+-  enum __codecvt_result (*__codecvt_do_out) (struct _IO_codecvt *,
+-					     __mbstate_t *,
+-					     const wchar_t *,
+-					     const wchar_t *,
+-					     const wchar_t **, char *,
+-					     char *, char **);
+-  enum __codecvt_result (*__codecvt_do_unshift) (struct _IO_codecvt *,
+-						 __mbstate_t *, char *,
+-						 char *, char **);
+-  enum __codecvt_result (*__codecvt_do_in) (struct _IO_codecvt *,
+-					    __mbstate_t *,
+-					    const char *, const char *,
+-					    const char **, wchar_t *,
+-					    wchar_t *, wchar_t **);
+-  int (*__codecvt_do_encoding) (struct _IO_codecvt *);
+-  int (*__codecvt_do_always_noconv) (struct _IO_codecvt *);
+-  int (*__codecvt_do_length) (struct _IO_codecvt *, __mbstate_t *,
+-			      const char *, const char *, size_t);
+-  int (*__codecvt_do_max_length) (struct _IO_codecvt *);
+-
+   _IO_iconv_t __cd_in;
+   _IO_iconv_t __cd_out;
+ };
+diff --git a/libio/libioP.h b/libio/libioP.h
+index 7bdec86a62..66afaa8968 100644
+--- a/libio/libioP.h
++++ b/libio/libioP.h
+@@ -476,7 +476,6 @@ extern const struct _IO_jump_t _IO_streambuf_jumps;
+ extern const struct _IO_jump_t _IO_old_proc_jumps attribute_hidden;
+ extern const struct _IO_jump_t _IO_str_jumps attribute_hidden;
+ extern const struct _IO_jump_t _IO_wstr_jumps attribute_hidden;
+-extern const struct _IO_codecvt __libio_codecvt attribute_hidden;
+ extern int _IO_do_write (FILE *, const char *, size_t);
+ libc_hidden_proto (_IO_do_write)
+ extern int _IO_new_do_write (FILE *, const char *, size_t);
+@@ -932,4 +931,32 @@ IO_validate_vtable (const struct _IO_jump_t *vtable)
+   return vtable;
+ }
+ 
++/* Character set conversion.  */
++
++enum __codecvt_result
++{
++  __codecvt_ok,
++  __codecvt_partial,
++  __codecvt_error,
++  __codecvt_noconv
++};
++
++enum __codecvt_result __libio_codecvt_out (struct _IO_codecvt *,
++					   __mbstate_t *,
++					   const wchar_t *,
++					   const wchar_t *,
++					   const wchar_t **, char *,
++					   char *, char **)
++  attribute_hidden;
++enum __codecvt_result __libio_codecvt_in (struct _IO_codecvt *,
++					  __mbstate_t *,
++					  const char *, const char *,
++					  const char **, wchar_t *,
++					  wchar_t *, wchar_t **)
++  attribute_hidden;
++int __libio_codecvt_encoding (struct _IO_codecvt *) attribute_hidden;
++int __libio_codecvt_length (struct _IO_codecvt *, __mbstate_t *,
++			    const char *, const char *, size_t)
++  attribute_hidden;
++
+ #endif /* libioP.h.  */
+diff --git a/libio/wfileops.c b/libio/wfileops.c
+index 69fbb62a02..f1863db638 100644
+--- a/libio/wfileops.c
++++ b/libio/wfileops.c
+@@ -72,11 +72,11 @@ _IO_wdo_write (FILE *fp, const wchar_t *data, size_t to_do)
+ 	    }
+ 
+ 	  /* Now convert from the internal format into the external buffer.  */
+-	  result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
+-					    data, data + to_do, &new_data,
+-					    write_ptr,
+-					    buf_end,
+-					    &write_ptr);
++	  result = __libio_codecvt_out (cc, &fp->_wide_data->_IO_state,
++					data, data + to_do, &new_data,
++					write_ptr,
++					buf_end,
++					&write_ptr);
+ 
+ 	  /* Write out what we produced so far.  */
+ 	  if (_IO_new_do_write (fp, write_base, write_ptr - write_base) == EOF)
+@@ -140,12 +140,12 @@ _IO_wfile_underflow (FILE *fp)
+       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
+       fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
+ 	fp->_wide_data->_IO_buf_base;
+-      status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
+-				       fp->_IO_read_ptr, fp->_IO_read_end,
+-				       &read_stop,
+-				       fp->_wide_data->_IO_read_ptr,
+-				       fp->_wide_data->_IO_buf_end,
+-				       &fp->_wide_data->_IO_read_end);
++      status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
++				   fp->_IO_read_ptr, fp->_IO_read_end,
++				   &read_stop,
++				   fp->_wide_data->_IO_read_ptr,
++				   fp->_wide_data->_IO_buf_end,
++				   &fp->_wide_data->_IO_read_end);
+ 
+       fp->_IO_read_base = fp->_IO_read_ptr;
+       fp->_IO_read_ptr = (char *) read_stop;
+@@ -266,11 +266,11 @@ _IO_wfile_underflow (FILE *fp)
+       naccbuf += to_copy;
+       from = accbuf;
+     }
+-  status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
+-				   from, to, &read_ptr_copy,
+-				   fp->_wide_data->_IO_read_end,
+-				   fp->_wide_data->_IO_buf_end,
+-				   &fp->_wide_data->_IO_read_end);
++  status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
++			       from, to, &read_ptr_copy,
++			       fp->_wide_data->_IO_read_end,
++			       fp->_wide_data->_IO_buf_end,
++			       &fp->_wide_data->_IO_read_end);
+ 
+   if (__glibc_unlikely (naccbuf != 0))
+     fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]);
+@@ -372,12 +372,12 @@ _IO_wfile_underflow_mmap (FILE *fp)
+   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
+   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
+     fp->_wide_data->_IO_buf_base;
+-  (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
+-			  fp->_IO_read_ptr, fp->_IO_read_end,
+-			  &read_stop,
+-			  fp->_wide_data->_IO_read_ptr,
+-			  fp->_wide_data->_IO_buf_end,
+-			  &fp->_wide_data->_IO_read_end);
++  __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
++		      fp->_IO_read_ptr, fp->_IO_read_end,
++		      &read_stop,
++		      fp->_wide_data->_IO_read_ptr,
++		      fp->_wide_data->_IO_buf_end,
++		      &fp->_wide_data->_IO_read_end);
+ 
+   fp->_IO_read_ptr = (char *) read_stop;
+ 
+@@ -495,7 +495,7 @@ _IO_wfile_sync (FILE *fp)
+       struct _IO_codecvt *cv = fp->_codecvt;
+       off64_t new_pos;
+ 
+-      int clen = (*cv->__codecvt_do_encoding) (cv);
++      int clen = __libio_codecvt_encoding (cv);
+ 
+       if (clen > 0)
+ 	/* It is easy, a fixed number of input bytes are used for each
+@@ -511,9 +511,9 @@ _IO_wfile_sync (FILE *fp)
+ 	  size_t wnread = (fp->_wide_data->_IO_read_ptr
+ 			   - fp->_wide_data->_IO_read_base);
+ 	  fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
+-	  nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
+-					      fp->_IO_read_base,
+-					      fp->_IO_read_end, wnread);
++	  nread = __libio_codecvt_length (cv, &fp->_wide_data->_IO_state,
++					  fp->_IO_read_base,
++					  fp->_IO_read_end, wnread);
+ 	  fp->_IO_read_ptr = fp->_IO_read_base + nread;
+ 	  delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
+ 	}
+@@ -548,7 +548,7 @@ adjust_wide_data (FILE *fp, bool do_convert)
+ {
+   struct _IO_codecvt *cv = fp->_codecvt;
+ 
+-  int clen = (*cv->__codecvt_do_encoding) (cv);
++  int clen = __libio_codecvt_encoding (cv);
+ 
+   /* Take the easy way out for constant length encodings if we don't need to
+      convert.  */
+@@ -565,12 +565,12 @@ adjust_wide_data (FILE *fp, bool do_convert)
+     {
+ 
+       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
+-      status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state,
+-				       fp->_IO_read_base, fp->_IO_read_ptr,
+-				       &read_stop,
+-				       fp->_wide_data->_IO_read_base,
+-				       fp->_wide_data->_IO_buf_end,
+-				       &fp->_wide_data->_IO_read_end);
++      status = __libio_codecvt_in (cv, &fp->_wide_data->_IO_state,
++				   fp->_IO_read_base, fp->_IO_read_ptr,
++				   &read_stop,
++				   fp->_wide_data->_IO_read_base,
++				   fp->_wide_data->_IO_buf_end,
++				   &fp->_wide_data->_IO_read_end);
+ 
+       /* Should we return EILSEQ?  */
+       if (__glibc_unlikely (status == __codecvt_error))
+@@ -648,7 +648,7 @@ do_ftell_wide (FILE *fp)
+ 	}
+ 
+       struct _IO_codecvt *cv = fp->_codecvt;
+-      int clen = (*cv->__codecvt_do_encoding) (cv);
++      int clen = __libio_codecvt_encoding (cv);
+ 
+       if (!unflushed_writes)
+ 	{
+@@ -663,9 +663,9 @@ do_ftell_wide (FILE *fp)
+ 
+ 	      size_t delta = wide_read_ptr - wide_read_base;
+ 	      __mbstate_t state = fp->_wide_data->_IO_last_state;
+-	      nread = (*cv->__codecvt_do_length) (cv, &state,
+-						  fp->_IO_read_base,
+-						  fp->_IO_read_end, delta);
++	      nread = __libio_codecvt_length (cv, &state,
++					      fp->_IO_read_base,
++					      fp->_IO_read_end, delta);
+ 	      offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
+ 	    }
+ 	}
+@@ -688,9 +688,8 @@ do_ftell_wide (FILE *fp)
+ 	      enum __codecvt_result status;
+ 
+ 	      __mbstate_t state = fp->_wide_data->_IO_last_state;
+-	      status = (*cv->__codecvt_do_out) (cv, &state,
+-						in, in + delta, &in,
+-						out, out + outsize, &outstop);
++	      status = __libio_codecvt_out (cv, &state, in, in + delta, &in,
++					    out, out + outsize, &outstop);
+ 
+ 	      /* We don't check for __codecvt_partial because it can be
+ 		 returned on one of two conditions: either the output
+@@ -801,7 +800,7 @@ _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
+ 	 find out which position in the external buffer corresponds to
+ 	 the current position in the internal buffer.  */
+       cv = fp->_codecvt;
+-      clen = (*cv->__codecvt_do_encoding) (cv);
++      clen = __libio_codecvt_encoding (cv);
+ 
+       if (mode != 0 || !was_writing)
+ 	{
+@@ -819,10 +818,10 @@ _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
+ 	      delta = (fp->_wide_data->_IO_read_ptr
+ 		       - fp->_wide_data->_IO_read_base);
+ 	      fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
+-	      nread = (*cv->__codecvt_do_length) (cv,
+-						  &fp->_wide_data->_IO_state,
+-						  fp->_IO_read_base,
+-						  fp->_IO_read_end, delta);
++	      nread = __libio_codecvt_length (cv,
++					      &fp->_wide_data->_IO_state,
++					      fp->_IO_read_base,
++					      fp->_IO_read_end, delta);
+ 	      fp->_IO_read_ptr = fp->_IO_read_base + nread;
+ 	      fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
+ 	      offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
diff --git a/SOURCES/glibc-rh1764242.patch b/SOURCES/glibc-rh1764242.patch
new file mode 100644
index 0000000..b8c9a2f
--- /dev/null
+++ b/SOURCES/glibc-rh1764242.patch
@@ -0,0 +1,81 @@
+commit 4997e8f31e7415652c3dedec672c0e9bf8caa9ca
+Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
+Date:   Fri Feb 1 10:39:57 2019 -0200
+
+    math: Enable some math builtins for clang
+    
+    This patch enable the builtin usage for clang for the C99 functions
+    fpclassify, isfinite, isnormal, isnan, isinf, and sigbit.  This allows
+    clang optimize the calls on frontend instead of call the appropriate
+    glibc symbols.
+    
+    Checked on aarch64-linux-gnu and x86_64-linux-gnu. I checked the supported
+    version for each builtin based on released version from clang/llvm.
+    
+            * math/math.h (fpclassify, isfinite, isnormal, isnan): Use builtin for
+            clang 2.8.
+            (signbit): Use builtin for clang 3.3.
+            (isinf): Use builtin for clang 3.7.
+
+diff --git a/math/math.h b/math/math.h
+index ddee4e408389722f..b3b414f3678e91f7 100644
+--- a/math/math.h
++++ b/math/math.h
+@@ -874,7 +874,8 @@ enum
+    the __SUPPORT_SNAN__ check may be skipped for those versions.  */
+ 
+ /* Return number of classification appropriate for X.  */
+-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__			      \
++# if ((__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__)		      \
++      || __glibc_clang_prereq (2,8))					      \
+      && (!defined __OPTIMIZE_SIZE__ || defined __cplusplus)
+      /* The check for __cplusplus allows the use of the builtin, even
+ 	when optimization for size is on.  This is provided for
+@@ -889,7 +890,7 @@ enum
+ # endif
+ 
+ /* Return nonzero value if sign of X is negative.  */
+-# if __GNUC_PREREQ (6,0)
++# if __GNUC_PREREQ (6,0) || __glibc_clang_prereq (3,3)
+ #  define signbit(x) __builtin_signbit (x)
+ # elif defined __cplusplus
+   /* In C++ mode, __MATH_TG cannot be used, because it relies on
+@@ -907,14 +908,16 @@ enum
+ # endif
+ 
+ /* Return nonzero value if X is not +-Inf or NaN.  */
+-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__
++# if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \
++     || __glibc_clang_prereq (2,8)
+ #  define isfinite(x) __builtin_isfinite (x)
+ # else
+ #  define isfinite(x) __MATH_TG ((x), __finite, (x))
+ # endif
+ 
+ /* Return nonzero value if X is neither zero, subnormal, Inf, nor NaN.  */
+-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__
++# if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \
++     || __glibc_clang_prereq (2,8)
+ #  define isnormal(x) __builtin_isnormal (x)
+ # else
+ #  define isnormal(x) (fpclassify (x) == FP_NORMAL)
+@@ -922,7 +925,8 @@ enum
+ 
+ /* Return nonzero value if X is a NaN.  We could use `fpclassify' but
+    we already have this functions `__isnan' and it is faster.  */
+-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__
++# if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \
++     || __glibc_clang_prereq (2,8)
+ #  define isnan(x) __builtin_isnan (x)
+ # else
+ #  define isnan(x) __MATH_TG ((x), __isnan, (x))
+@@ -939,7 +943,8 @@ enum
+ #  define isinf(x) \
+     (__builtin_types_compatible_p (__typeof (x), _Float128) \
+      ? __isinff128 (x) : __builtin_isinf_sign (x))
+-# elif __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__
++# elif (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \
++       || __glibc_clang_prereq (3,7)
+ #  define isinf(x) __builtin_isinf_sign (x)
+ # else
+ #  define isinf(x) __MATH_TG ((x), __isinf, (x))
diff --git a/SOURCES/glibc-rh1769304.patch b/SOURCES/glibc-rh1769304.patch
new file mode 100644
index 0000000..e78c759
--- /dev/null
+++ b/SOURCES/glibc-rh1769304.patch
@@ -0,0 +1,740 @@
+commit 711a322a235d4c8177713f11aa59156603b94aeb
+Author: Zack Weinberg <zackw@panix.com>
+Date:   Mon Mar 11 10:59:27 2019 -0400
+
+    Use a proper C tokenizer to implement the obsolete typedefs test.
+    
+    The test for obsolete typedefs in installed headers was implemented
+    using grep, and could therefore get false positives on e.g. “ulong”
+    in a comment.  It was also scanning all of the headers included by
+    our headers, and therefore testing headers we don’t control, e.g.
+    Linux kernel headers.
+    
+    This patch splits the obsolete-typedef test from
+    scripts/check-installed-headers.sh to a separate program,
+    scripts/check-obsolete-constructs.py.  Being implemented in Python,
+    it is feasible to make it tokenize C accurately enough to avoid false
+    positives on the contents of comments and strings.  It also only
+    examines $(headers) in each subdirectory--all the headers we install,
+    but not any external dependencies of those headers.  Headers whose
+    installed name starts with finclude/ are ignored, on the assumption
+    that they contain Fortran.
+    
+    It is also feasible to make the new test understand the difference
+    between _defining_ the obsolete typedefs and _using_ the obsolete
+    typedefs, which means posix/{bits,sys}/types.h no longer need to be
+    exempted.  This uncovered an actual bug in bits/types.h: __quad_t and
+    __u_quad_t were being used to define __S64_TYPE, __U64_TYPE,
+    __SQUAD_TYPE and __UQUAD_TYPE.  These are changed to __int64_t and
+    __uint64_t respectively.  This is a safe change, despite the comments
+    in bits/types.h claiming a difference between __quad_t and __int64_t,
+    because those comments are incorrect.  In all current ABIs, both
+    __quad_t and __int64_t are ‘long’ when ‘long’ is a 64-bit type, and
+    ‘long long’ when ‘long’ is a 32-bit type, and similarly for __u_quad_t
+    and __uint64_t.  (Changing the types to be what the comments say they
+    are would be an ABI break, as it affects C++ name mangling.)  This
+    patch includes a minimal change to make the comments not completely
+    wrong.
+    
+    sys/types.h was defining the legacy BSD u_intN_t typedefs using a
+    construct that was not necessarily consistent with how the C99 uintN_t
+    typedefs are defined, and is also too complicated for the new script to
+    understand (it lexes C relatively accurately, but it does not attempt
+    to expand preprocessor macros, nor does it do any actual parsing).
+    This patch cuts all of that out and uses bits/types.h's __uintN_t typedefs
+    to define u_intN_t instead.  This is verified to not change the ABI on
+    any supported architecture, via the c++-types test, which means u_intN_t
+    and uintN_t were, in fact, consistent on all supported architectures.
+    
+    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+    
+            * scripts/check-obsolete-constructs.py: New test script.
+            * scripts/check-installed-headers.sh: Remove tests for
+            obsolete typedefs, superseded by check-obsolete-constructs.py.
+            * Rules: Run scripts/check-obsolete-constructs.py over $(headers)
+            as a special test.  Update commentary.
+            * posix/bits/types.h (__SQUAD_TYPE, __S64_TYPE): Define as __int64_t.
+            (__UQUAD_TYPE, __U64_TYPE): Define as __uint64_t.
+            Update commentary.
+            * posix/sys/types.h (__u_intN_t): Remove.
+            (u_int8_t): Typedef using __uint8_t.
+            (u_int16_t): Typedef using __uint16_t.
+            (u_int32_t): Typedef using __uint32_t.
+            (u_int64_t): Typedef using __uint64_t.
+
+Conflicts:
+	Rules
+	  (textual conflicts due to lack of check-wrapper-headers test.)
+
+diff --git a/Rules b/Rules
+index 5abb7270aa8e24aa..a07dbb8d978b5769 100644
+--- a/Rules
++++ b/Rules
+@@ -82,7 +82,8 @@ $(common-objpfx)dummy.c:
+ common-generated += dummy.o dummy.c
+ 
+ ifneq "$(headers)" ""
+-# Special test of all the installed headers in this directory.
++# Test that all of the headers installed by this directory can be compiled
++# in isolation.
+ tests-special += $(objpfx)check-installed-headers-c.out
+ libof-check-installed-headers-c := testsuite
+ $(objpfx)check-installed-headers-c.out: \
+@@ -93,6 +94,8 @@ $(objpfx)check-installed-headers-c.out: \
+ 	$(evaluate-test)
+ 
+ ifneq "$(CXX)" ""
++# If a C++ compiler is available, also test that they can be compiled
++# in isolation as C++.
+ tests-special += $(objpfx)check-installed-headers-cxx.out
+ libof-check-installed-headers-cxx := testsuite
+ $(objpfx)check-installed-headers-cxx.out: \
+@@ -101,8 +104,19 @@ $(objpfx)check-installed-headers-cxx.out: \
+ 	  "$(CXX) $(filter-out -std=%,$(CXXFLAGS)) -D_ISOMAC $(+includes)" \
+ 	  $(headers) > $@; \
+ 	$(evaluate-test)
+-endif
+-endif
++endif # $(CXX)
++
++# Test that none of the headers installed by this directory use certain
++# obsolete constructs (e.g. legacy BSD typedefs superseded by stdint.h).
++# This script does not need $(py-env).
++tests-special += $(objpfx)check-obsolete-constructs.out
++libof-check-obsolete-constructs := testsuite
++$(objpfx)check-obsolete-constructs.out: \
++    $(..)scripts/check-obsolete-constructs.py $(headers)
++	$(PYTHON) $^ > $@ 2>&1; \
++	$(evaluate-test)
++
++endif # $(headers)
+ 
+ # This makes all the auxiliary and test programs.
+ 
+diff --git a/posix/bits/types.h b/posix/bits/types.h
+index 5e22ce41bf4c29b3..64f344c6e7897491 100644
+--- a/posix/bits/types.h
++++ b/posix/bits/types.h
+@@ -86,7 +86,7 @@ __extension__ typedef unsigned long long int __uintmax_t;
+ 	32		-- "natural" 32-bit type (always int)
+ 	64		-- "natural" 64-bit type (long or long long)
+ 	LONG32		-- 32-bit type, traditionally long
+-	QUAD		-- 64-bit type, always long long
++	QUAD		-- 64-bit type, traditionally long long
+ 	WORD		-- natural type of __WORDSIZE bits (int or long)
+ 	LONGWORD	-- type of __WORDSIZE bits, traditionally long
+ 
+@@ -112,14 +112,14 @@ __extension__ typedef unsigned long long int __uintmax_t;
+ #define __SLONGWORD_TYPE	long int
+ #define __ULONGWORD_TYPE	unsigned long int
+ #if __WORDSIZE == 32
+-# define __SQUAD_TYPE		__quad_t
+-# define __UQUAD_TYPE		__u_quad_t
++# define __SQUAD_TYPE		__int64_t
++# define __UQUAD_TYPE		__uint64_t
+ # define __SWORD_TYPE		int
+ # define __UWORD_TYPE		unsigned int
+ # define __SLONG32_TYPE		long int
+ # define __ULONG32_TYPE		unsigned long int
+-# define __S64_TYPE		__quad_t
+-# define __U64_TYPE		__u_quad_t
++# define __S64_TYPE		__int64_t
++# define __U64_TYPE		__uint64_t
+ /* We want __extension__ before typedef's that use nonstandard base types
+    such as `long long' in C89 mode.  */
+ # define __STD_TYPE		__extension__ typedef
+diff --git a/posix/sys/types.h b/posix/sys/types.h
+index db524d6cd13f0379..47eff1a7b1a91c81 100644
+--- a/posix/sys/types.h
++++ b/posix/sys/types.h
+@@ -154,37 +154,20 @@ typedef unsigned int uint;
+ 
+ #include <bits/stdint-intn.h>
+ 
+-#if !__GNUC_PREREQ (2, 7)
+-
+ /* These were defined by ISO C without the first `_'.  */
+-typedef	unsigned char u_int8_t;
+-typedef	unsigned short int u_int16_t;
+-typedef	unsigned int u_int32_t;
+-# if __WORDSIZE == 64
+-typedef unsigned long int u_int64_t;
+-# else
+-__extension__ typedef unsigned long long int u_int64_t;
+-# endif
+-
+-typedef int register_t;
+-
+-#else
+-
+-/* For GCC 2.7 and later, we can use specific type-size attributes.  */
+-# define __u_intN_t(N, MODE) \
+-  typedef unsigned int u_int##N##_t __attribute__ ((__mode__ (MODE)))
+-
+-__u_intN_t (8, __QI__);
+-__u_intN_t (16, __HI__);
+-__u_intN_t (32, __SI__);
+-__u_intN_t (64, __DI__);
++typedef __uint8_t u_int8_t;
++typedef __uint16_t u_int16_t;
++typedef __uint32_t u_int32_t;
++typedef __uint64_t u_int64_t;
+ 
++#if __GNUC_PREREQ (2, 7)
+ typedef int register_t __attribute__ ((__mode__ (__word__)));
+-
++#else
++typedef int register_t;
++#endif
+ 
+ /* Some code from BIND tests this macro to see if the types above are
+    defined.  */
+-#endif
+ #define __BIT_TYPES_DEFINED__	1
+ 
+ 
+diff --git a/scripts/check-installed-headers.sh b/scripts/check-installed-headers.sh
+index 7a1969b43a144ebb..c2aeea5aabcc7ffd 100644
+--- a/scripts/check-installed-headers.sh
++++ b/scripts/check-installed-headers.sh
+@@ -16,11 +16,9 @@
+ # License along with the GNU C Library; if not, see
+ # <http://www.gnu.org/licenses/>.
+ 
+-# Check installed headers for cleanliness.  For each header, confirm
+-# that it's possible to compile a file that includes that header and
+-# does nothing else, in several different compilation modes.  Also,
+-# scan the header for a set of obsolete typedefs that should no longer
+-# appear.
++# For each installed header, confirm that it's possible to compile a
++# file that includes that header and does nothing else, in several
++# different compilation modes.
+ 
+ # These compilation switches assume GCC or compatible, which is probably
+ # fine since we also assume that when _building_ glibc.
+@@ -31,13 +29,6 @@ cxx_modes="-std=c++98 -std=gnu++98 -std=c++11 -std=gnu++11"
+ # These are probably the most commonly used three.
+ lib_modes="-D_DEFAULT_SOURCE=1 -D_GNU_SOURCE=1 -D_XOPEN_SOURCE=700"
+ 
+-# sys/types.h+bits/types.h have to define the obsolete types.
+-# rpc(svc)/* have the obsolete types too deeply embedded in their API
+-# to remove.
+-skip_obsolete_type_check='*/sys/types.h|*/bits/types.h|*/rpc/*|*/rpcsvc/*'
+-obsolete_type_re=\
+-'\<((__)?(quad_t|u(short|int|long|_(char|short|int([0-9]+_t)?|long|quad_t))))\>'
+-
+ if [ $# -lt 3 ]; then
+     echo "usage: $0 c|c++ \"compile command\" header header header..." >&2
+     exit 2
+@@ -46,14 +37,10 @@ case "$1" in
+     (c)
+         lang_modes="$c_modes"
+         cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.c)
+-        already="$skip_obsolete_type_check"
+     ;;
+     (c++)
+         lang_modes="$cxx_modes"
+         cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.cc)
+-        # The obsolete-type check can be skipped for C++; it is
+-        # sufficient to do it for C.
+-        already="*"
+     ;;
+     (*)
+         echo "usage: $0 c|c++ \"compile command\" header header header..." >&2
+@@ -155,22 +142,8 @@ $expanded_lib_mode
+ int avoid_empty_translation_unit;
+ EOF
+             if $cc_cmd -fsyntax-only $lang_mode "$cih_test_c" 2>&1
+-            then
+-                includes=$($cc_cmd -fsyntax-only -H $lang_mode \
+-                              "$cih_test_c" 2>&1 | sed -ne 's/^[.][.]* //p')
+-                for h in $includes; do
+-                    # Don't repeat work.
+-                    eval 'case "$h" in ('"$already"') continue;; esac'
+-
+-                    if grep -qE "$obsolete_type_re" "$h"; then
+-                        echo "*** Obsolete types detected:"
+-                        grep -HE "$obsolete_type_re" "$h"
+-                        failed=1
+-                    fi
+-                    already="$already|$h"
+-                done
+-            else
+-                failed=1
++            then :
++            else failed=1
+             fi
+         done
+     done
+diff --git a/scripts/check-obsolete-constructs.py b/scripts/check-obsolete-constructs.py
+new file mode 100755
+index 0000000000000000..ce5c72251f4d7cc0
+--- /dev/null
++++ b/scripts/check-obsolete-constructs.py
+@@ -0,0 +1,466 @@
++#! /usr/bin/python3
++# Copyright (C) 2019 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
++# <http://www.gnu.org/licenses/>.
++
++"""Verifies that installed headers do not use any obsolete constructs:
++ * legacy BSD typedefs superseded by <stdint.h>:
++   ushort uint ulong u_char u_short u_int u_long u_intNN_t quad_t u_quad_t
++   (sys/types.h is allowed to _define_ these types, but not to use them
++    to define anything else).
++"""
++
++import argparse
++import collections
++import re
++import sys
++
++# Simplified lexical analyzer for C preprocessing tokens.
++# Does not implement trigraphs.
++# Does not implement backslash-newline in the middle of any lexical
++#   item other than a string literal.
++# Does not implement universal-character-names in identifiers.
++# Treats prefixed strings (e.g. L"...") as two tokens (L and "...")
++# Accepts non-ASCII characters only within comments and strings.
++
++# Caution: The order of the outermost alternation matters.
++# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST,
++# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must
++# be last.
++# Caution: There should be no capturing groups other than the named
++# captures in the outermost alternation.
++
++# For reference, these are all of the C punctuators as of C11:
++#   [ ] ( ) { } , ; ? ~
++#   ! != * *= / /= ^ ^= = ==
++#   # ##
++#   % %= %> %: %:%:
++#   & &= &&
++#   | |= ||
++#   + += ++
++#   - -= -- ->
++#   . ...
++#   : :>
++#   < <% <: << <<= <=
++#   > >= >> >>=
++
++# The BAD_* tokens are not part of the official definition of pp-tokens;
++# they match unclosed strings, character constants, and block comments,
++# so that the regex engine doesn't have to backtrack all the way to the
++# beginning of a broken construct and then emit dozens of junk tokens.
++
++PP_TOKEN_RE_ = re.compile(r"""
++    (?P<STRING>        \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\")
++   |(?P<BAD_STRING>    \"(?:[^\"\\\r\n]|\\[ -~])*)
++   |(?P<CHARCONST>     \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\')
++   |(?P<BAD_CHARCONST> \'(?:[^\'\\\r\n]|\\[ -~])*)
++   |(?P<BLOCK_COMMENT> /\*(?:\*(?!/)|[^*])*\*/)
++   |(?P<BAD_BLOCK_COM> /\*(?:\*(?!/)|[^*])*\*?)
++   |(?P<LINE_COMMENT>  //[^\r\n]*)
++   |(?P<IDENT>         [_a-zA-Z][_a-zA-Z0-9]*)
++   |(?P<PP_NUMBER>     \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*)
++   |(?P<PUNCTUATOR>
++       [,;?~(){}\[\]]
++     | [!*/^=]=?
++     | \#\#?
++     | %(?:[=>]|:(?:%:)?)?
++     | &[=&]?
++     |\|[=|]?
++     |\+[=+]?
++     | -[=->]?
++     |\.(?:\.\.)?
++     | :>?
++     | <(?:[%:]|<(?:=|<=?)?)?
++     | >(?:=|>=?)?)
++   |(?P<ESCNL>         \\(?:\r|\n|\r\n))
++   |(?P<WHITESPACE>    [ \t\n\r\v\f]+)
++   |(?P<OTHER>         .)
++""", re.DOTALL | re.VERBOSE)
++
++HEADER_NAME_RE_ = re.compile(r"""
++    < [^>\r\n]+ >
++  | " [^"\r\n]+ "
++""", re.DOTALL | re.VERBOSE)
++
++ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""")
++
++# based on the sample code in the Python re documentation
++Token_ = collections.namedtuple("Token", (
++    "kind", "text", "line", "column", "context"))
++Token_.__doc__ = """
++   One C preprocessing token, comment, or chunk of whitespace.
++   'kind' identifies the token type, which will be one of:
++       STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT,
++       PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME,
++       or OTHER.  The BAD_* alternatives in PP_TOKEN_RE_ are
++       handled within tokenize_c, below.
++
++   'text' is the sequence of source characters making up the token;
++       no decoding whatsoever is performed.
++
++   'line' and 'column' give the position of the first character of the
++      token within the source file.  They are both 1-based.
++
++   'context' indicates whether or not this token occurred within a
++      preprocessing directive; it will be None for running text,
++      '<null>' for the leading '#' of a directive line (because '#'
++      all by itself on a line is a "null directive"), or the name of
++      the directive for tokens within a directive line, starting with
++      the IDENT for the name itself.
++"""
++
++def tokenize_c(file_contents, reporter):
++    """Yield a series of Token objects, one for each preprocessing
++       token, comment, or chunk of whitespace within FILE_CONTENTS.
++       The REPORTER object is expected to have one method,
++       reporter.error(token, message), which will be called to
++       indicate a lexical error at the position of TOKEN.
++       If MESSAGE contains the four-character sequence '{!r}', that
++       is expected to be replaced by repr(token.text).
++    """
++
++    Token = Token_
++    PP_TOKEN_RE = PP_TOKEN_RE_
++    ENDLINE_RE = ENDLINE_RE_
++    HEADER_NAME_RE = HEADER_NAME_RE_
++
++    line_num = 1
++    line_start = 0
++    pos = 0
++    limit = len(file_contents)
++    directive = None
++    at_bol = True
++    while pos < limit:
++        if directive == "include":
++            mo = HEADER_NAME_RE.match(file_contents, pos)
++            if mo:
++                kind = "HEADER_NAME"
++                directive = "after_include"
++            else:
++                mo = PP_TOKEN_RE.match(file_contents, pos)
++                kind = mo.lastgroup
++                if kind != "WHITESPACE":
++                    directive = "after_include"
++        else:
++            mo = PP_TOKEN_RE.match(file_contents, pos)
++            kind = mo.lastgroup
++
++        text = mo.group()
++        line = line_num
++        column = mo.start() - line_start
++        adj_line_start = 0
++        # only these kinds can contain a newline
++        if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT",
++                    "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"):
++            for tmo in ENDLINE_RE.finditer(text):
++                line_num += 1
++                adj_line_start = tmo.end()
++            if adj_line_start:
++                line_start = mo.start() + adj_line_start
++
++        # Track whether or not we are scanning a preprocessing directive.
++        if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start):
++            at_bol = True
++            directive = None
++        else:
++            if kind == "PUNCTUATOR" and text == "#" and at_bol:
++                directive = "<null>"
++            elif kind == "IDENT" and directive == "<null>":
++                directive = text
++            at_bol = False
++
++        # Report ill-formed tokens and rewrite them as their well-formed
++        # equivalents, so downstream processing doesn't have to know about them.
++        # (Rewriting instead of discarding provides better error recovery.)
++        if kind == "BAD_BLOCK_COM":
++            reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""),
++                           "unclosed block comment")
++            text += "*/"
++            kind = "BLOCK_COMMENT"
++        elif kind == "BAD_STRING":
++            reporter.error(Token("BAD_STRING", "", line, column+1, ""),
++                           "unclosed string")
++            text += "\""
++            kind = "STRING"
++        elif kind == "BAD_CHARCONST":
++            reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""),
++                           "unclosed char constant")
++            text += "'"
++            kind = "CHARCONST"
++
++        tok = Token(kind, text, line, column+1,
++                    "include" if directive == "after_include" else directive)
++        # Do not complain about OTHER tokens inside macro definitions.
++        # $ and @ appear in macros defined by headers intended to be
++        # included from assembly language, e.g. sysdeps/mips/sys/asm.h.
++        if kind == "OTHER" and directive != "define":
++            self.error(tok, "stray {!r} in program")
++
++        yield tok
++        pos = mo.end()
++
++#
++# Base and generic classes for individual checks.
++#
++
++class ConstructChecker:
++    """Scan a stream of C preprocessing tokens and possibly report
++       problems with them.  The REPORTER object passed to __init__ has
++       one method, reporter.error(token, message), which should be
++       called to indicate a problem detected at the position of TOKEN.
++       If MESSAGE contains the four-character sequence '{!r}' then that
++       will be replaced with a textual representation of TOKEN.
++    """
++    def __init__(self, reporter):
++        self.reporter = reporter
++
++    def examine(self, tok):
++        """Called once for each token in a header file.
++           Call self.reporter.error if a problem is detected.
++        """
++        raise NotImplementedError
++
++    def eof(self):
++        """Called once at the end of the stream.  Subclasses need only
++           override this if it might have something to do."""
++        pass
++
++class NoCheck(ConstructChecker):
++    """Generic checker class which doesn't do anything.  Substitute this
++       class for a real checker when a particular check should be skipped
++       for some file."""
++
++    def examine(self, tok):
++        pass
++
++#
++# Check for obsolete type names.
++#
++
++# The obsolete type names we're looking for:
++OBSOLETE_TYPE_RE_ = re.compile(r"""\A
++  (__)?
++  (   quad_t
++    | u(?: short | int | long
++         | _(?: char | short | int(?:[0-9]+_t)? | long | quad_t )))
++\Z""", re.VERBOSE)
++
++class ObsoleteNotAllowed(ConstructChecker):
++    """Don't allow any use of the obsolete typedefs."""
++    def examine(self, tok):
++        if OBSOLETE_TYPE_RE_.match(tok.text):
++            self.reporter.error(tok, "use of {!r}")
++
++class ObsoletePrivateDefinitionsAllowed(ConstructChecker):
++    """Allow definitions of the private versions of the
++       obsolete typedefs; that is, 'typedef [anything] __obsolete;'
++    """
++    def __init__(self, reporter):
++        super().__init__(reporter)
++        self.in_typedef = False
++        self.prev_token = None
++
++    def examine(self, tok):
++        # bits/types.h hides 'typedef' in a macro sometimes.
++        if (tok.kind == "IDENT"
++            and tok.text in ("typedef", "__STD_TYPE")
++            and tok.context is None):
++            self.in_typedef = True
++        elif tok.kind == "PUNCTUATOR" and tok.text == ";" and self.in_typedef:
++            self.in_typedef = False
++            if self.prev_token.kind == "IDENT":
++                m = OBSOLETE_TYPE_RE_.match(self.prev_token.text)
++                if m and m.group(1) != "__":
++                    self.reporter.error(self.prev_token, "use of {!r}")
++            self.prev_token = None
++        else:
++            self._check_prev()
++
++        self.prev_token = tok
++
++    def eof(self):
++        self._check_prev()
++
++    def _check_prev(self):
++        if (self.prev_token is not None
++            and self.prev_token.kind == "IDENT"
++            and OBSOLETE_TYPE_RE_.match(self.prev_token.text)):
++            self.reporter.error(self.prev_token, "use of {!r}")
++
++class ObsoletePublicDefinitionsAllowed(ConstructChecker):
++    """Allow definitions of the public versions of the obsolete
++       typedefs.  Only specific forms of definition are allowed:
++
++           typedef __obsolete obsolete;  // identifiers must agree
++           typedef __uintN_t u_intN_t;   // N must agree
++           typedef unsigned long int ulong;
++           typedef unsigned short int ushort;
++           typedef unsigned int uint;
++    """
++    def __init__(self, reporter):
++        super().__init__(reporter)
++        self.typedef_tokens = []
++
++    def examine(self, tok):
++        if tok.kind in ("WHITESPACE", "BLOCK_COMMENT",
++                        "LINE_COMMENT", "NL", "ESCNL"):
++            pass
++
++        elif (tok.kind == "IDENT" and tok.text == "typedef"
++              and tok.context is None):
++            if self.typedef_tokens:
++                self.reporter.error(tok, "typedef inside typedef")
++                self._reset()
++            self.typedef_tokens.append(tok)
++
++        elif tok.kind == "PUNCTUATOR" and tok.text == ";":
++            self._finish()
++
++        elif self.typedef_tokens:
++            self.typedef_tokens.append(tok)
++
++    def eof(self):
++        self._reset()
++
++    def _reset(self):
++        while self.typedef_tokens:
++            tok = self.typedef_tokens.pop(0)
++            if tok.kind == "IDENT" and OBSOLETE_TYPE_RE_.match(tok.text):
++                self.reporter.error(tok, "use of {!r}")
++
++    def _finish(self):
++        if not self.typedef_tokens: return
++        if self.typedef_tokens[-1].kind == "IDENT":
++            m = OBSOLETE_TYPE_RE_.match(self.typedef_tokens[-1].text)
++            if m:
++                if self._permissible_public_definition(m):
++                    self.typedef_tokens.clear()
++        self._reset()
++
++    def _permissible_public_definition(self, m):
++        if m.group(1) == "__": return False
++        name = m.group(2)
++        toks = self.typedef_tokens
++        ntok = len(toks)
++        if ntok == 3 and toks[1].kind == "IDENT":
++            defn = toks[1].text
++            n = OBSOLETE_TYPE_RE_.match(defn)
++            if n and n.group(1) == "__" and n.group(2) == name:
++                return True
++
++            if (name[:5] == "u_int" and name[-2:] == "_t"
++                and defn[:6] == "__uint" and defn[-2:] == "_t"
++                and name[5:-2] == defn[6:-2]):
++                return True
++
++            return False
++
++        if (name == "ulong" and ntok == 5
++            and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
++            and toks[2].kind == "IDENT" and toks[2].text == "long"
++            and toks[3].kind == "IDENT" and toks[3].text == "int"):
++            return True
++
++        if (name == "ushort" and ntok == 5
++            and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
++            and toks[2].kind == "IDENT" and toks[2].text == "short"
++            and toks[3].kind == "IDENT" and toks[3].text == "int"):
++            return True
++
++        if (name == "uint" and ntok == 4
++            and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
++            and toks[2].kind == "IDENT" and toks[2].text == "int"):
++            return True
++
++        return False
++
++def ObsoleteTypedefChecker(reporter, fname):
++    """Factory: produce an instance of the appropriate
++       obsolete-typedef checker for FNAME."""
++
++    # The obsolete rpc/ and rpcsvc/ headers are allowed to use the
++    # obsolete types, because it would be more trouble than it's
++    # worth to remove them from headers that we intend to stop
++    # installing eventually anyway.
++    if (fname.startswith("rpc/")
++        or fname.startswith("rpcsvc/")
++        or "/rpc/" in fname
++        or "/rpcsvc/" in fname):
++        return NoCheck(reporter)
++
++    # bits/types.h is allowed to define the __-versions of the
++    # obsolete types.
++    if (fname == "bits/types.h"
++        or fname.endswith("/bits/types.h")):
++        return ObsoletePrivateDefinitionsAllowed(reporter)
++
++    # sys/types.h is allowed to use the __-versions of the
++    # obsolete types, but only to define the unprefixed versions.
++    if (fname == "sys/types.h"
++        or fname.endswith("/sys/types.h")):
++        return ObsoletePublicDefinitionsAllowed(reporter)
++
++    return ObsoleteNotAllowed(reporter)
++
++#
++# Master control
++#
++
++class HeaderChecker:
++    """Perform all of the checks on each header.  This is also the
++       "reporter" object expected by tokenize_c and ConstructChecker.
++    """
++    def __init__(self):
++        self.fname = None
++        self.status = 0
++
++    def error(self, tok, message):
++        self.status = 1
++        if '{!r}' in message:
++            message = message.format(tok.text)
++        sys.stderr.write("{}:{}:{}: error: {}\n".format(
++            self.fname, tok.line, tok.column, message))
++
++    def check(self, fname):
++        self.fname = fname
++        try:
++            with open(fname, "rt") as fp:
++                contents = fp.read()
++        except OSError as e:
++            sys.stderr.write("{}: {}\n".format(fname, e.strerror))
++            self.status = 1
++            return
++
++        typedef_checker = ObsoleteTypedefChecker(self, self.fname)
++
++        for tok in tokenize_c(contents, self):
++            typedef_checker.examine(tok)
++
++def main():
++    ap = argparse.ArgumentParser(description=__doc__)
++    ap.add_argument("headers", metavar="header", nargs="+",
++                    help="one or more headers to scan for obsolete constructs")
++    args = ap.parse_args()
++
++    checker = HeaderChecker()
++    for fname in args.headers:
++        # Headers whose installed name begins with "finclude/" contain
++        # Fortran, not C, and this program should completely ignore them.
++        if not (fname.startswith("finclude/") or "/finclude/" in fname):
++            checker.check(fname)
++    sys.exit(checker.status)
++
++main()
diff --git a/SOURCES/glibc-rh1774021.patch b/SOURCES/glibc-rh1774021.patch
new file mode 100644
index 0000000..e298717
--- /dev/null
+++ b/SOURCES/glibc-rh1774021.patch
@@ -0,0 +1,24 @@
+commit d5dfad4326fc683c813df1e37bbf5cf920591c8e
+Author: Marcin Kościelnicki <mwk@0x04.net>
+Date:   Thu Nov 21 00:20:15 2019 +0100
+
+    rtld: Check __libc_enable_secure before honoring LD_PREFER_MAP_32BIT_EXEC (CVE-2019-19126) [BZ #25204]
+    
+    The problem was introduced in glibc 2.23, in commit
+    b9eb92ab05204df772eb4929eccd018637c9f3e9
+    ("Add Prefer_MAP_32BIT_EXEC to map executable pages with MAP_32BIT").
+
+diff --git a/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h b/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h
+index 194369174df08946..ac694c032e7baf87 100644
+--- a/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h
++++ b/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h
+@@ -31,7 +31,8 @@
+    environment variable, LD_PREFER_MAP_32BIT_EXEC.  */
+ #define EXTRA_LD_ENVVARS \
+   case 21:								  \
+-    if (memcmp (envline, "PREFER_MAP_32BIT_EXEC", 21) == 0)		  \
++    if (!__libc_enable_secure						  \
++	&& memcmp (envline, "PREFER_MAP_32BIT_EXEC", 21) == 0)		  \
+       GLRO(dl_x86_cpu_features).feature[index_arch_Prefer_MAP_32BIT_EXEC] \
+ 	|= bit_arch_Prefer_MAP_32BIT_EXEC;				  \
+     break;
diff --git a/SOURCES/glibc-rh1775294.patch b/SOURCES/glibc-rh1775294.patch
new file mode 100644
index 0000000..1805d6c
--- /dev/null
+++ b/SOURCES/glibc-rh1775294.patch
@@ -0,0 +1,70 @@
+commit bfa864e1645e140da2e1aae3cf0d0ba0674f6eb5
+Author: Emilio Cobos Álvarez <emilio@crisal.io>
+Date:   Tue Nov 12 19:18:32 2019 +0100
+
+    Don't use a custom wrapper macro around __has_include (bug 25189).
+    
+    This causes issues when using clang with -frewrite-includes to e.g.,
+    submit the translation unit to a distributed compiler.
+    
+    In my case, I was building Firefox using sccache.
+    
+    See [1] for a reduced test-case since I initially thought this was a
+    clang bug, and [2] for more context.
+    
+    Apparently doing this is invalid C++ per [cpp.cond], which mentions [3]:
+    
+    > The #ifdef and #ifndef directives, and the defined conditional
+    > inclusion operator, shall treat __has_include and __has_cpp_attribute
+    > as if they were the names of defined macros.  The identifiers
+    > __has_include and __has_cpp_attribute shall not appear in any context
+    > not mentioned in this subclause.
+    
+    [1]: https://bugs.llvm.org/show_bug.cgi?id=43982
+    [2]: https://bugs.llvm.org/show_bug.cgi?id=37990
+    [3]: http://eel.is/c++draft/cpp.cond#7.sentence-2
+    
+    Change-Id: Id4b8ee19176a9e4624b533087ba870c418f27e60
+
+diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
+index 9e840e602f815d86..3f6fe3cc8563b493 100644
+--- a/misc/sys/cdefs.h
++++ b/misc/sys/cdefs.h
+@@ -412,14 +412,6 @@
+ # define __glibc_has_attribute(attr)	0
+ #endif
+ 
+-#ifdef __has_include
+-/* Do not use a function-like macro, so that __has_include can inhibit
+-   macro expansion.  */
+-# define __glibc_has_include __has_include
+-#else
+-# define __glibc_has_include(header)	0
+-#endif
+-
+ #if (!defined _Noreturn \
+      && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \
+      &&  !__GNUC_PREREQ (4,7))
+diff --git a/sysdeps/unix/sysv/linux/bits/statx.h b/sysdeps/unix/sysv/linux/bits/statx.h
+index 206878723fd37881..aaccfdc2dc03a1dc 100644
+--- a/sysdeps/unix/sysv/linux/bits/statx.h
++++ b/sysdeps/unix/sysv/linux/bits/statx.h
+@@ -26,11 +26,13 @@
+ 
+ /* Use "" to work around incorrect macro expansion of the
+    __has_include argument (GCC PR 80005).  */
+-#if __glibc_has_include ("linux/stat.h")
+-# include "linux/stat.h"
+-# ifdef STATX_TYPE
+-#  define __statx_timestamp_defined 1
+-#  define __statx_defined 1
++#ifdef __has_include
++# if __has_include ("linux/stat.h")
++#  include "linux/stat.h"
++#  ifdef STATX_TYPE
++#   define __statx_timestamp_defined 1
++#   define __statx_defined 1
++#  endif
+ # endif
+ #endif
+ 
diff --git a/SOURCES/glibc-rh1777241.patch b/SOURCES/glibc-rh1777241.patch
new file mode 100644
index 0000000..e68afdd
--- /dev/null
+++ b/SOURCES/glibc-rh1777241.patch
@@ -0,0 +1,88 @@
+commit bfdb731438206b0f70fe7afa890681155c30b419
+Author: Stefan Liebler <stli@linux.ibm.com>
+Date:   Wed Nov 27 12:35:40 2019 +0100
+
+    S390: Fix handling of needles crossing a page in strstr z15 ifunc-variant. [BZ #25226]
+    
+    If the specified needle crosses a page-boundary, the s390-z15 ifunc variant of
+    strstr truncates the needle which results in invalid results.
+    
+    This is fixed by loading the needle beyond the page boundary to v18 instead of v16.
+    The bug is sometimes observable in test-strstr.c in check1 and check2 as the
+    haystack and needle is stored on stack. Thus the needle can be on a page boundary.
+    
+    check2 is now extended to test haystack / needles located on stack, at end of page
+    and on two pages.
+    
+    This bug was introduced with commit 6f47401bd5fc71209219779a0426170a9a7395b0
+    ("S390: Add arch13 strstr ifunc variant.") and is already released in glibc 2.30.
+
+diff --git a/string/test-strstr.c b/string/test-strstr.c
+index 5861b01b73e4c315..e9e14c1ee605516e 100644
+--- a/string/test-strstr.c
++++ b/string/test-strstr.c
+@@ -138,16 +138,45 @@ check1 (void)
+ static void
+ check2 (void)
+ {
+-  const char s1[] = ", enable_static, \0, enable_shared, ";
++  const char s1_stack[] = ", enable_static, \0, enable_shared, ";
++  const size_t s1_byte_count = 18;
++  const char *s2_stack = &(s1_stack[s1_byte_count]);
++  const size_t s2_byte_count = 18;
+   char *exp_result;
+-  char *s2 = (void *) buf1 + page_size - 18;
++  const size_t page_size_real = getpagesize ();
+ 
+-  strcpy (s2, s1);
+-  exp_result = stupid_strstr (s1, s1 + 18);
++  /* Haystack at end of page.  The following page is protected.  */
++  char *s1_page_end = (void *) buf1 + page_size - s1_byte_count;
++  strcpy (s1_page_end, s1_stack);
++
++  /* Haystack which crosses a page boundary.
++     Note: page_size is at least 2 * getpagesize.  See test_init.  */
++  char *s1_page_cross = (void *) buf1 + page_size_real - 8;
++  strcpy (s1_page_cross, s1_stack);
++
++  /* Needle at end of page.  The following page is protected.  */
++  char *s2_page_end = (void *) buf2 + page_size - s2_byte_count;
++  strcpy (s2_page_end, s2_stack);
++
++  /* Needle which crosses a page boundary.
++     Note: page_size is at least 2 * getpagesize.  See test_init.  */
++  char *s2_page_cross = (void *) buf2 + page_size_real - 8;
++  strcpy (s2_page_cross, s2_stack);
++
++  exp_result = stupid_strstr (s1_stack, s2_stack);
+   FOR_EACH_IMPL (impl, 0)
+     {
+-      check_result (impl, s1, s1 + 18, exp_result);
+-      check_result (impl, s2, s1 + 18, exp_result);
++      check_result (impl, s1_stack, s2_stack, exp_result);
++      check_result (impl, s1_stack, s2_page_end, exp_result);
++      check_result (impl, s1_stack, s2_page_cross, exp_result);
++
++      check_result (impl, s1_page_end, s2_stack, exp_result);
++      check_result (impl, s1_page_end, s2_page_end, exp_result);
++      check_result (impl, s1_page_end, s2_page_cross, exp_result);
++
++      check_result (impl, s1_page_cross, s2_stack, exp_result);
++      check_result (impl, s1_page_cross, s2_page_end, exp_result);
++      check_result (impl, s1_page_cross, s2_page_cross, exp_result);
+     }
+ }
+ 
+diff --git a/sysdeps/s390/strstr-arch13.S b/sysdeps/s390/strstr-arch13.S
+index 929b026adfeba740..faa969849e09c2e1 100644
+--- a/sysdeps/s390/strstr-arch13.S
++++ b/sysdeps/s390/strstr-arch13.S
+@@ -164,7 +164,7 @@ ENTRY(STRSTR_ARCH13)
+ 	vfenezb	%v19,%v18,%v18	/* Search zero in loaded needle bytes.  */
+ 	veclb	%v19,%v21	/* Zero index <= max loaded byte index?  */
+ 	jle	.Lneedle_loaded	/* -> v18 contains full needle.  */
+-	vl	%v16,0(%r3)	/* Load needle beyond page boundary.  */
++	vl	%v18,0(%r3)	/* Load needle beyond page boundary.  */
+ 	vfenezb	%v19,%v18,%v18
+ 	j	.Lneedle_loaded
+ END(STRSTR_ARCH13)
diff --git a/SOURCES/glibc-rh1777797.patch b/SOURCES/glibc-rh1777797.patch
deleted file mode 100644
index e68afdd..0000000
--- a/SOURCES/glibc-rh1777797.patch
+++ /dev/null
@@ -1,88 +0,0 @@
-commit bfdb731438206b0f70fe7afa890681155c30b419
-Author: Stefan Liebler <stli@linux.ibm.com>
-Date:   Wed Nov 27 12:35:40 2019 +0100
-
-    S390: Fix handling of needles crossing a page in strstr z15 ifunc-variant. [BZ #25226]
-    
-    If the specified needle crosses a page-boundary, the s390-z15 ifunc variant of
-    strstr truncates the needle which results in invalid results.
-    
-    This is fixed by loading the needle beyond the page boundary to v18 instead of v16.
-    The bug is sometimes observable in test-strstr.c in check1 and check2 as the
-    haystack and needle is stored on stack. Thus the needle can be on a page boundary.
-    
-    check2 is now extended to test haystack / needles located on stack, at end of page
-    and on two pages.
-    
-    This bug was introduced with commit 6f47401bd5fc71209219779a0426170a9a7395b0
-    ("S390: Add arch13 strstr ifunc variant.") and is already released in glibc 2.30.
-
-diff --git a/string/test-strstr.c b/string/test-strstr.c
-index 5861b01b73e4c315..e9e14c1ee605516e 100644
---- a/string/test-strstr.c
-+++ b/string/test-strstr.c
-@@ -138,16 +138,45 @@ check1 (void)
- static void
- check2 (void)
- {
--  const char s1[] = ", enable_static, \0, enable_shared, ";
-+  const char s1_stack[] = ", enable_static, \0, enable_shared, ";
-+  const size_t s1_byte_count = 18;
-+  const char *s2_stack = &(s1_stack[s1_byte_count]);
-+  const size_t s2_byte_count = 18;
-   char *exp_result;
--  char *s2 = (void *) buf1 + page_size - 18;
-+  const size_t page_size_real = getpagesize ();
- 
--  strcpy (s2, s1);
--  exp_result = stupid_strstr (s1, s1 + 18);
-+  /* Haystack at end of page.  The following page is protected.  */
-+  char *s1_page_end = (void *) buf1 + page_size - s1_byte_count;
-+  strcpy (s1_page_end, s1_stack);
-+
-+  /* Haystack which crosses a page boundary.
-+     Note: page_size is at least 2 * getpagesize.  See test_init.  */
-+  char *s1_page_cross = (void *) buf1 + page_size_real - 8;
-+  strcpy (s1_page_cross, s1_stack);
-+
-+  /* Needle at end of page.  The following page is protected.  */
-+  char *s2_page_end = (void *) buf2 + page_size - s2_byte_count;
-+  strcpy (s2_page_end, s2_stack);
-+
-+  /* Needle which crosses a page boundary.
-+     Note: page_size is at least 2 * getpagesize.  See test_init.  */
-+  char *s2_page_cross = (void *) buf2 + page_size_real - 8;
-+  strcpy (s2_page_cross, s2_stack);
-+
-+  exp_result = stupid_strstr (s1_stack, s2_stack);
-   FOR_EACH_IMPL (impl, 0)
-     {
--      check_result (impl, s1, s1 + 18, exp_result);
--      check_result (impl, s2, s1 + 18, exp_result);
-+      check_result (impl, s1_stack, s2_stack, exp_result);
-+      check_result (impl, s1_stack, s2_page_end, exp_result);
-+      check_result (impl, s1_stack, s2_page_cross, exp_result);
-+
-+      check_result (impl, s1_page_end, s2_stack, exp_result);
-+      check_result (impl, s1_page_end, s2_page_end, exp_result);
-+      check_result (impl, s1_page_end, s2_page_cross, exp_result);
-+
-+      check_result (impl, s1_page_cross, s2_stack, exp_result);
-+      check_result (impl, s1_page_cross, s2_page_end, exp_result);
-+      check_result (impl, s1_page_cross, s2_page_cross, exp_result);
-     }
- }
- 
-diff --git a/sysdeps/s390/strstr-arch13.S b/sysdeps/s390/strstr-arch13.S
-index 929b026adfeba740..faa969849e09c2e1 100644
---- a/sysdeps/s390/strstr-arch13.S
-+++ b/sysdeps/s390/strstr-arch13.S
-@@ -164,7 +164,7 @@ ENTRY(STRSTR_ARCH13)
- 	vfenezb	%v19,%v18,%v18	/* Search zero in loaded needle bytes.  */
- 	veclb	%v19,%v21	/* Zero index <= max loaded byte index?  */
- 	jle	.Lneedle_loaded	/* -> v18 contains full needle.  */
--	vl	%v16,0(%r3)	/* Load needle beyond page boundary.  */
-+	vl	%v18,0(%r3)	/* Load needle beyond page boundary.  */
- 	vfenezb	%v19,%v18,%v18
- 	j	.Lneedle_loaded
- END(STRSTR_ARCH13)
diff --git a/SOURCES/nsswitch.conf b/SOURCES/nsswitch.conf
deleted file mode 100644
index b49a3b2..0000000
--- a/SOURCES/nsswitch.conf
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# /etc/nsswitch.conf
-#
-# An example Name Service Switch config file. This file should be
-# sorted with the most-used services at the beginning.
-#
-# The entry '[NOTFOUND=return]' means that the search for an
-# entry should stop if the search in the previous entry turned
-# up nothing. Note that if the search failed due to some other reason
-# (like no NIS server responding) then the search continues with the
-# next entry.
-#
-# Valid entries include:
-#
-#	nisplus			Use NIS+ (NIS version 3)
-#	nis			Use NIS (NIS version 2), also called YP
-#	dns			Use DNS (Domain Name Service)
-#	files			Use the local files in /etc
-#	db			Use the pre-processed /var/db files
-#	compat			Use /etc files plus *_compat pseudo-databases
-#	hesiod			Use Hesiod (DNS) for user lookups
-#	sss			Use sssd (System Security Services Daemon)
-#	[NOTFOUND=return]	Stop searching if not found so far
-#
-# 'sssd' performs its own 'files'-based caching, so it should
-# generally come before 'files'.
-
-# To use 'db', install the nss_db package, and put the 'db' in front
-# of 'files' for entries you want to be looked up first in the
-# databases, like this:
-#
-# passwd:    db files
-# shadow:    db files
-# group:     db files
-
-passwd:     sss files
-shadow:     files sss
-group:      sss files
-
-hosts:      files dns myhostname
-
-bootparams: files
-
-ethers:     files
-netmasks:   files
-networks:   files
-protocols:  files
-rpc:        files
-services:   files sss
-
-netgroup:   sss
-
-publickey:  files
-
-automount:  files sss
-aliases:    files
diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec
index 7435e08..d355d29 100644
--- a/SPECS/glibc.spec
+++ b/SPECS/glibc.spec
@@ -1,6 +1,6 @@
 %define glibcsrcdir glibc-2.28
 %define glibcversion 2.28
-%define glibcrelease 72%{?dist}.1
+%define glibcrelease 101%{?dist}
 # Pre-release tarballs are pulled in from git using a command that is
 # effectively:
 #
@@ -121,7 +121,6 @@ URL: http://www.gnu.org/software/glibc/
 Source0: %{?glibc_release_url}%{glibcsrcdir}.tar.xz
 Source1: build-locale-archive.c
 Source4: nscd.conf
-Source7: nsswitch.conf
 Source8: power6emul.c
 Source9: bench.mk
 Source10: glibc-bench-compare
@@ -315,7 +314,88 @@ Patch180: glibc-rh1717438.patch
 Patch181: glibc-rh1727152.patch
 Patch182: glibc-rh1724975.patch
 Patch183: glibc-rh1722215.patch
-Patch184: glibc-rh1777797.patch
+Patch184: glibc-rh1764234-1.patch
+Patch185: glibc-rh1764234-2.patch
+Patch186: glibc-rh1764234-3.patch
+Patch187: glibc-rh1764234-4.patch
+Patch188: glibc-rh1764234-5.patch
+Patch189: glibc-rh1764234-6.patch
+Patch190: glibc-rh1764234-7.patch
+Patch191: glibc-rh1764234-8.patch
+Patch192: glibc-rh1747505-1.patch
+Patch193: glibc-rh1747505-2.patch
+Patch194: glibc-rh1747505-3.patch
+Patch195: glibc-rh1747505-4.patch
+Patch196: glibc-rh1747453.patch
+Patch197: glibc-rh1764241.patch
+Patch198: glibc-rh1746933-1.patch
+Patch199: glibc-rh1746933-2.patch
+Patch200: glibc-rh1746933-3.patch
+Patch201: glibc-rh1735747-1.patch
+Patch202: glibc-rh1735747-2.patch
+Patch203: glibc-rh1764226-1.patch
+Patch204: glibc-rh1764226-2.patch
+Patch205: glibc-rh1764226-3.patch
+Patch206: glibc-rh1764218-1.patch
+Patch207: glibc-rh1764218-2.patch
+Patch208: glibc-rh1764218-3.patch
+Patch209: glibc-rh1682954.patch
+Patch210: glibc-rh1746928.patch
+Patch211: glibc-rh1747502.patch
+Patch212: glibc-rh1747502-1.patch
+Patch213: glibc-rh1747502-2.patch
+Patch214: glibc-rh1747502-3.patch
+Patch215: glibc-rh1747502-4.patch
+Patch216: glibc-rh1747502-5.patch
+Patch217: glibc-rh1747502-6.patch
+Patch218: glibc-rh1747502-7.patch
+Patch219: glibc-rh1747502-8.patch
+Patch220: glibc-rh1747502-9.patch
+Patch221: glibc-rh1726638-1.patch
+Patch222: glibc-rh1726638-2.patch
+Patch223: glibc-rh1726638-3.patch
+Patch224: glibc-rh1764238-1.patch
+Patch225: glibc-rh1764238-2.patch
+Patch226: glibc-rh1764242.patch
+Patch227: glibc-rh1769304.patch
+Patch228: glibc-rh1749439-1.patch
+Patch229: glibc-rh1749439-2.patch
+Patch230: glibc-rh1749439-3.patch
+Patch231: glibc-rh1749439-4.patch
+Patch232: glibc-rh1749439-5.patch
+Patch233: glibc-rh1749439-6.patch
+Patch234: glibc-rh1749439-7.patch
+Patch235: glibc-rh1749439-8.patch
+Patch236: glibc-rh1749439-9.patch
+Patch237: glibc-rh1749439-10.patch
+Patch238: glibc-rh1749439-11.patch
+Patch239: glibc-rh1749439-12.patch
+Patch240: glibc-rh1749439-13.patch
+Patch241: glibc-rh1764231-1.patch
+Patch242: glibc-rh1764231-2.patch
+Patch243: glibc-rh1764235.patch
+Patch244: glibc-rh1361965.patch
+Patch245: glibc-rh1764223.patch
+Patch246: glibc-rh1764214.patch
+Patch247: glibc-rh1774021.patch
+Patch248: glibc-rh1775294.patch
+Patch249: glibc-rh1777241.patch
+Patch250: glibc-rh1410154-1.patch
+Patch251: glibc-rh1410154-2.patch
+Patch252: glibc-rh1410154-3.patch
+Patch253: glibc-rh1410154-4.patch
+Patch254: glibc-rh1410154-5.patch
+Patch255: glibc-rh1410154-6.patch
+Patch256: glibc-rh1410154-7.patch
+Patch257: glibc-rh1410154-8.patch
+Patch258: glibc-rh1410154-9.patch
+Patch259: glibc-rh1410154-10.patch
+Patch260: glibc-rh1410154-11.patch
+Patch261: glibc-rh1410154-12.patch
+Patch262: glibc-rh1410154-13.patch
+Patch263: glibc-rh1410154-14.patch
+Patch264: glibc-rh1410154-15.patch
+Patch265: glibc-rh1410154-16.patch
 
 ##############################################################################
 # Continued list of core "glibc" package information:
@@ -1238,7 +1318,7 @@ mv  %{glibc_sysroot}%{_prefix}/lib/locale/*.filelist .
 # Install configuration files for services
 ##############################################################################
 
-install -p -m 644 %{SOURCE7} %{glibc_sysroot}/etc/nsswitch.conf
+install -p -m 644 nss/nsswitch.conf %{glibc_sysroot}/etc/nsswitch.conf
 
 %ifnarch %{auxarches}
 # This is for ncsd - in glibc 2.2
@@ -2202,8 +2282,95 @@ fi
 %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
 
 %changelog
-* Thu Nov 28 2019 Florian Weimer <fweimer@redhat.com> - 2.28-72.1
-- s390x: Fix z15 strstr for patterns crossing pages (#1777797)
+* Thu Jan 16 2020 Florian Weimer <fweimer@redhat.com> - 2.28-101
+- ld.so: Reset GL (dl_initfirst) pointer on dlopen failure (#1410154)
+
+* Fri Dec 13 2019 Florian Weimer <fweimer@redhat.com> - 2.28-100
+- Roll back dynamic linker state on dlopen failure (#1410154)
+
+* Wed Nov 27 2019 Florian Weimer <fweimer@redhat.com> - 2.28-99
+- s390x: Fix z15 strstr for patterns crossing pages (#1777241)
+
+* Wed Nov 27 2019 Florian Weimer <fweimer@redhat.com> - 2.28-98
+- Rebuild with new rpm (#1654901)
+
+* Fri Nov 22 2019 Florian Weimer <fweimer@redhat.com> - 2.28-97
+- Avoid invalid __has_include in <sys/stat.h> (#1775294)
+
+* Fri Nov 22 2019 Florian Weimer <fweimer@redhat.com> - 2.28-96
+- x86-64: Ignore LD_PREFER_MAP_32BIT_EXEC in SUID binaries (#1774021)
+
+* Thu Nov 14 2019 DJ Delorie <dj@redhat.com> - 2.28-95
+- Fix alignment of TLS variables for tls variant TLS_TCB_AT_TP (#1764214)
+
+* Thu Nov 14 2019 DJ Delorie <dj@redhat.com> - 2.28-94
+- Refuse to dlopen PIE objects (#1764223)
+
+* Thu Nov 14 2019 Carlos O'Donell <carlos@redhat.com> - 2.28-93
+- Fix C.UTF-8 locale source ellipsis expressions (#1361965)
+
+* Thu Nov 14 2019 Carlos O'Donell <carlos@redhat.com> - 2.28-92
+- Fix hangs during malloc tracing (#1764235)
+
+* Thu Nov 14 2019 Carlos O'Donell <carlos@redhat.com> - 2.28-91
+- Support moving versioned symbols between sonames (#1764231)
+
+* Wed Nov 13 2019 Florian Weimer <fweimer@redhat.com> - 2.28-90
+- Avoid creating stale utmp entries for repeated pututxline (#1749439)
+
+* Wed Nov  6 2019 Florian Weimer <fweimer@redhat.com> - 2.28-89
+- Backport more precise tokenizer for installed headers test (#1769304)
+
+* Wed Nov  6 2019 Florian Weimer <fweimer@redhat.com> - 2.28-88
+- math: Enable some math builtins for clang in LLVM Toolset (#1764242)
+
+* Wed Nov  6 2019 Florian Weimer <fweimer@redhat.com> - 2.28-87
+- Support Fortran vectorized math functions with GCC Toolset 9 (#1764238)
+
+* Wed Nov  6 2019 Florian Weimer <fweimer@redhat.com> - 2.28-86
+- aarch64: Support STO_AARCH64_VARIANT_PCS, DT_AARCH64_VARIANT_PCS (#1726638)
+
+* Mon Nov  4 2019 DJ Delorie <dj@redhat.com> - 2.28-85
+- Add more test-in-container support (#1747502)
+
+* Fri Nov  1 2019 DJ Delorie <dj@redhat.com> - 2.28-84
+- Fix calling getpwent after endpwent (#1747502)
+
+* Fri Nov  1 2019 DJ Delorie <dj@redhat.com> - 2.28-83
+- nptl: Avoid fork handler lock for async-signal-safe fork (#1746928)
+
+* Thu Oct 31 2019 DJ Delorie <dj@redhat.com> - 2.28-82
+- Call _dl_open_check after relocation (#1682954)
+
+* Thu Oct 31 2019 Arjun Shankar <arjun@redhat.com> - 2.28-81
+- Add malloc fastbin tunable (#1764218)
+
+* Thu Oct 31 2019 Arjun Shankar <arjun@redhat.com> - 2.28-80
+- Fix race condition in tst-clone3 and add a new ldconfig test,
+  tst-ldconfig-bad-aux-cache (#1764226)
+
+* Thu Oct 31 2019 Arjun Shankar <arjun@redhat.com> - 2.28-79
+- Remove unwanted whitespace from size lines and account for top chunk in
+  malloc_info output (#1735747)
+
+* Wed Oct 30 2019 Arjun Shankar <arjun@redhat.com> - 2.28-78
+- Enhance malloc tcache (#1746933)
+
+* Tue Oct 29 2019 Patsy Griffin <patsy@redhat.com> - 2.28-77
+- Don't define initgroups in nsswitch.conf (#1747505)
+
+* Mon Oct 28 2019 Patsy Griffin <patsy@redhat.com> - 2.28-76
+- libio: Remove codecvt vtable. (#1764241)
+
+* Mon Oct 28 2019 Patsy Griffin <patsy@redhat.com> - 2.28-75
+- Implement --preload option for the dynamic linker.(#1747453)
+
+* Mon Oct 28 2019 Patsy Griffin <patsy@redhat.com> - 2.28-74
+- Make nsswitch.conf more distribution friendly.
+  Improve nscd.conf comments.  (#1747505)
+
+* Fri Oct 25 2019 Patsy Griffin <patsy@redhat.com> - 2.28-73
+- Update system call names list to Linux 5.3 (#1764234)
 
 * Mon Jul 22 2019 Carlos O'Donell <carlos@redhat.com> - 2.28-72
 - Skip wide buffer handling for legacy stdio handles (#1722215)