commit 0b03996304f86d6dba8f0d4b7048b9bb7186f17d
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Tue Aug 3 21:10:10 2021 +0530

    ldconfig: avoid leak on empty paths in config file
    
    Reviewed-by: Arjun Shankar <arjun@redhat.com>
    (cherry picked from commit b0234d79e7d82475d1666f25326ec045c045b3ed)

diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index 1037e8d0cf..b8893637f8 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -503,7 +503,11 @@ add_dir_1 (const char *line, const char *from_file, int from_line)
     entry->path[--i] = '\0';
 
   if (i == 0)
-    return;
+    {
+      free (entry->path);
+      free (entry);
+      return;
+    }
 
   char *path = entry->path;
   if (opt_chroot != NULL)

commit 3a48da47a91ccc6f5de260574809e7a44551b876
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Tue Aug 3 21:10:20 2021 +0530

    gconv_parseconfdir: Fix memory leak
    
    The allocated `conf` would leak if we have to skip over the file due
    to the underlying filesystem not supporting dt_type.
    
    Reviewed-by: Arjun Shankar <arjun@redhat.com>
    (cherry picked from commit 5f9b78fe35d08739b6da1e5b356786d41116c108)

diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
index a4153e54c6..2f062689ec 100644
--- a/iconv/gconv_parseconfdir.h
+++ b/iconv/gconv_parseconfdir.h
@@ -153,12 +153,11 @@ gconv_parseconfdir (const char *dir, size_t dir_len)
 	      struct stat64 st;
 	      if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
 		continue;
-	      if (ent->d_type == DT_UNKNOWN
-		  && (lstat64 (conf, &st) == -1
-		      || !S_ISREG (st.st_mode)))
-		continue;
 
-	      found |= read_conf_file (conf, dir, dir_len);
+	      if (ent->d_type != DT_UNKNOWN
+		  || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode)))
+		found |= read_conf_file (conf, dir, dir_len);
+
 	      free (conf);
 	    }
 	}

commit a5bd2e10e0c25b80286dc36068e22a4cb4893af0
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Tue Aug 3 21:11:03 2021 +0530

    gaiconf_init: Avoid double-free in label and precedence lists
    
    labellist and precedencelist could get freed a second time if there
    are allocation failures, so set them to NULL to avoid a double-free.
    
    Reviewed-by: Arjun Shankar <arjun@redhat.com>
    (cherry picked from commit 77a34079d8f3d63b61543bf3af93043f8674e4c4)

diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 838a68f022..43dfc6739e 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -2008,6 +2008,7 @@ gaiconf_init (void)
 	      l = l->next;
 	    }
 	  free_prefixlist (labellist);
+	  labellist = NULL;
 
 	  /* Sort the entries so that the most specific ones are at
 	     the beginning.  */
@@ -2046,6 +2047,7 @@ gaiconf_init (void)
 	      l = l->next;
 	    }
 	  free_prefixlist (precedencelist);
+	  precedencelist = NULL;
 
 	  /* Sort the entries so that the most specific ones are at
 	     the beginning.  */

commit 7ff4da3dc26de351a5abe7c2905038cbe55c8041
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Tue Aug 3 21:10:53 2021 +0530

    copy_and_spawn_sgid: Avoid double calls to close()
    
    If close() on infd and outfd succeeded, reset the fd numbers so that
    we don't attempt to close them again.
    
    Reviewed-by: Arjun Shankar <arjun@redhat.com>
    (cherry picked from commit 45caed9d67a00af917d8b5b88d4b5eb1225b7aef)

diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
index 27bfd19c93..0bacf6dbc2 100644
--- a/support/support_capture_subprocess.c
+++ b/support/support_capture_subprocess.c
@@ -170,6 +170,7 @@ copy_and_spawn_sgid (char *child_id, gid_t gid)
      support_subprogram because we only want the program exit status, not the
      contents.  */
   ret = 0;
+  infd = outfd = -1;
 
   char * const args[] = {execname, child_id, NULL};
 

commit 9995d0588f4f9adc68419224d2b3698e2ca4f77e
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Tue Aug 3 21:10:29 2021 +0530

    iconv_charmap: Close output file when done
    
    Reviewed-by: Arjun Shankar <arjun@redhat.com>
    (cherry picked from commit 1e0e6d656db9dfa12ef7eb67976385d3deb0d4ff)

diff --git a/iconv/iconv_charmap.c b/iconv/iconv_charmap.c
index e2d53fee3c..a8b6b56124 100644
--- a/iconv/iconv_charmap.c
+++ b/iconv/iconv_charmap.c
@@ -234,6 +234,8 @@ charmap_conversion (const char *from_code, struct charmap_t *from_charmap,
     while (++remaining < argc);
 
   /* All done.  */
+  if (output != stdout)
+    fclose (output);
   free_table (cvtbl);
   return status;
 }

commit 31902ae639d6a50e768a85f1cd2a17e56b8463c2
Author: Florian Weimer <fweimer@redhat.com>
Date:   Fri Aug 6 09:51:38 2021 +0200

    Linux: Fix fcntl, ioctl, prctl redirects for _TIME_BITS=64 (bug 28182)
    
    __REDIRECT and __THROW are not compatible with C++ due to the ordering of the
    __asm__ alias and the throw specifier. __REDIRECT_NTH has to be used
    instead.
    
    Fixes commit 8a40aff86ba5f64a3a84883e539cb67b ("io: Add time64 alias
    for fcntl"), commit 82c395d91ea4f69120d453aeec398e30 ("misc: Add
    time64 alias for ioctl"), commit b39ffab860cd743a82c91946619f1b8158
    ("Linux: Add time64 alias for prctl").
    
    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
    (cherry picked from commit c87fcacc50505d550f1bb038382bcc7ea73a5926)

diff --git a/NEWS b/NEWS
index 3c610744c9..89e20cf062 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,13 @@ See the end for copying conditions.
 
 Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
 using `glibc' in the "product" field.
+
+Version 2.34.1
+
+The following bugs are resolved with this release:
+
+  [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl
+
 
 Version 2.34
 
diff --git a/io/fcntl.h b/io/fcntl.h
index 8917a73b42..1c96f98f4d 100644
--- a/io/fcntl.h
+++ b/io/fcntl.h
@@ -187,10 +187,10 @@ extern int fcntl64 (int __fd, int __cmd, ...);
 # endif
 #else /* __USE_TIME_BITS64 */
 # ifdef __REDIRECT
-extern int __REDIRECT (fcntl, (int __fd, int __request, ...),
-		       __fcntl_time64)  __THROW;
-extern int __REDIRECT (fcntl64, (int __fd, int __request, ...),
-		       __fcntl_time64)  __THROW;
+extern int __REDIRECT_NTH (fcntl, (int __fd, int __request, ...),
+			   __fcntl_time64);
+extern int __REDIRECT_NTH (fcntl64, (int __fd, int __request, ...),
+			   __fcntl_time64);
 # else
 extern int __fcntl_time64 (int __fd, int __request, ...) __THROW;
 #  define fcntl64 __fcntl_time64
diff --git a/misc/sys/ioctl.h b/misc/sys/ioctl.h
index 6884d9925f..9945c1e918 100644
--- a/misc/sys/ioctl.h
+++ b/misc/sys/ioctl.h
@@ -42,8 +42,8 @@ __BEGIN_DECLS
 extern int ioctl (int __fd, unsigned long int __request, ...) __THROW;
 #else
 # ifdef __REDIRECT
-extern int __REDIRECT (ioctl, (int __fd, unsigned long int __request, ...),
-		       __ioctl_time64) __THROW;
+extern int __REDIRECT_NTH (ioctl, (int __fd, unsigned long int __request, ...),
+			   __ioctl_time64);
 # else
 extern int __ioctl_time64 (int __fd, unsigned long int __request, ...) __THROW;
 #  define ioctl __ioctl_time64
diff --git a/sysdeps/unix/sysv/linux/sys/prctl.h b/sysdeps/unix/sysv/linux/sys/prctl.h
index db88938b3a..f0e0d2f27f 100644
--- a/sysdeps/unix/sysv/linux/sys/prctl.h
+++ b/sysdeps/unix/sysv/linux/sys/prctl.h
@@ -42,7 +42,7 @@ __BEGIN_DECLS
 extern int prctl (int __option, ...) __THROW;
 #else
 # ifdef __REDIRECT
-extern int __REDIRECT (prctl, (int __option, ...), __prctl_time64) __THROW;
+extern int __REDIRECT_NTH (prctl, (int __option, ...), __prctl_time64);
 # else
 extern int __prctl_time64 (int __option,d ...) __THROW;
 #  define ioctl __prctl_time64

commit 79474303223c5665bec75ffbdb2a86ee04a2514b
Author: Nikita Popov <npv1310@gmail.com>
Date:   Mon Aug 9 20:17:34 2021 +0530

    librt: fix NULL pointer dereference (bug 28213)
    
    Helper thread frees copied attribute on NOTIFY_REMOVED message
    received from the OS kernel.  Unfortunately, it fails to check whether
    copied attribute actually exists (data.attr != NULL).  This worked
    earlier because free() checks passed pointer before actually
    attempting to release corresponding memory.  But
    __pthread_attr_destroy assumes pointer is not NULL.
    
    So passing NULL pointer to __pthread_attr_destroy will result in
    segmentation fault.  This scenario is possible if
    notification->sigev_notify_attributes == NULL (which means default
    thread attributes should be used).
    
    Signed-off-by: Nikita Popov <npv1310@gmail.com>
    Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
    (cherry picked from commit b805aebd42364fe696e417808a700fdb9800c9e8)

diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c
index 9799dcdaa4..eccae2e4c6 100644
--- a/sysdeps/unix/sysv/linux/mq_notify.c
+++ b/sysdeps/unix/sysv/linux/mq_notify.c
@@ -131,7 +131,7 @@ helper_thread (void *arg)
 	       to wait until it is done with it.  */
 	    (void) __pthread_barrier_wait (&notify_barrier);
 	}
-      else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED)
+      else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED && data.attr != NULL)
 	{
 	  /* The only state we keep is the copy of the thread attributes.  */
 	  __pthread_attr_destroy (data.attr);

commit 7c987a5ccb31df80456d53a094e47f81310f549b
Author: Nikita Popov <npv1310@gmail.com>
Date:   Thu Aug 12 16:09:50 2021 +0530

    librt: add test (bug 28213)
    
    This test implements following logic:
    1) Create POSIX message queue.
       Register a notification with mq_notify (using NULL attributes).
       Then immediately unregister the notification with mq_notify.
       Helper thread in a vulnerable version of glibc
       should cause NULL pointer dereference after these steps.
    2) Once again, register the same notification.
       Try to send a dummy message.
       Test is considered successfulif the dummy message
       is successfully received by the callback function.
    
    Signed-off-by: Nikita Popov <npv1310@gmail.com>
    Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
    (cherry picked from commit 4cc79c217744743077bf7a0ec5e0a4318f1e6641)

diff --git a/rt/Makefile b/rt/Makefile
index 113cea03a5..910e775995 100644
--- a/rt/Makefile
+++ b/rt/Makefile
@@ -74,6 +74,7 @@ tests := tst-shm tst-timer tst-timer2 \
 	 tst-aio7 tst-aio8 tst-aio9 tst-aio10 \
 	 tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \
 	 tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \
+	 tst-bz28213 \
 	 tst-timer3 tst-timer4 tst-timer5 \
 	 tst-cpuclock2 tst-cputimer1 tst-cputimer2 tst-cputimer3 \
 	 tst-shm-cancel \
diff --git a/rt/tst-bz28213.c b/rt/tst-bz28213.c
new file mode 100644
index 0000000000..0c096b5a0a
--- /dev/null
+++ b/rt/tst-bz28213.c
@@ -0,0 +1,101 @@
+/* Bug 28213: test for NULL pointer dereference in mq_notify.
+   Copyright (C) The GNU Toolchain Authors.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <mqueue.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+
+static mqd_t m = -1;
+static const char msg[] = "hello";
+
+static void
+check_bz28213_cb (union sigval sv)
+{
+  char buf[sizeof (msg)];
+
+  (void) sv;
+
+  TEST_VERIFY_EXIT ((size_t) mq_receive (m, buf, sizeof (buf), NULL)
+		    == sizeof (buf));
+  TEST_VERIFY_EXIT (memcmp (buf, msg, sizeof (buf)) == 0);
+
+  exit (0);
+}
+
+static void
+check_bz28213 (void)
+{
+  struct sigevent sev;
+
+  memset (&sev, '\0', sizeof (sev));
+  sev.sigev_notify = SIGEV_THREAD;
+  sev.sigev_notify_function = check_bz28213_cb;
+
+  /* Step 1: Register & unregister notifier.
+     Helper thread should receive NOTIFY_REMOVED notification.
+     In a vulnerable version of glibc, NULL pointer dereference follows. */
+  TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0);
+  TEST_VERIFY_EXIT (mq_notify (m, NULL) == 0);
+
+  /* Step 2: Once again, register notification.
+     Try to send one message.
+     Test is considered successful, if the callback does exit (0). */
+  TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0);
+  TEST_VERIFY_EXIT (mq_send (m, msg, sizeof (msg), 1) == 0);
+
+  /* Wait... */
+  pause ();
+}
+
+static int
+do_test (void)
+{
+  static const char m_name[] = "/bz28213_queue";
+  struct mq_attr m_attr;
+
+  memset (&m_attr, '\0', sizeof (m_attr));
+  m_attr.mq_maxmsg = 1;
+  m_attr.mq_msgsize = sizeof (msg);
+
+  m = mq_open (m_name,
+               O_RDWR | O_CREAT | O_EXCL,
+               0600,
+               &m_attr);
+
+  if (m < 0)
+    {
+      if (errno == ENOSYS)
+        FAIL_UNSUPPORTED ("POSIX message queues are not implemented\n");
+      FAIL_EXIT1 ("Failed to create POSIX message queue: %m\n");
+    }
+
+  TEST_VERIFY_EXIT (mq_unlink (m_name) == 0);
+
+  check_bz28213 ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>

commit 9acab0bba6a5a57323b1f94bf95b21618a9e5aa4
Author: Arjun Shankar <arjun@redhat.com>
Date:   Fri Aug 20 16:24:05 2021 +0200

    elf: Fix missing colon in LD_SHOW_AUXV output [BZ #28253]
    
    This commit adds a missing colon in the AT_MINSIGSTKSZ entry in
    the _dl_show_auxv function.
    
    (cherry picked from commit 82fbcd7118d760492e2ecc9fa291e358b9ba0361)

diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
index d47bef1340..2c684c2db2 100644
--- a/elf/dl-sysdep.c
+++ b/elf/dl-sysdep.c
@@ -317,7 +317,7 @@ _dl_show_auxv (void)
 	  [AT_SYSINFO_EHDR - 2] =	{ "SYSINFO_EHDR:      0x", hex },
 	  [AT_RANDOM - 2] =		{ "RANDOM:            0x", hex },
 	  [AT_HWCAP2 - 2] =		{ "HWCAP2:            0x", hex },
-	  [AT_MINSIGSTKSZ - 2] =	{ "MINSIGSTKSZ        ", dec },
+	  [AT_MINSIGSTKSZ - 2] =	{ "MINSIGSTKSZ:       ", dec },
 	  [AT_L1I_CACHESIZE - 2] =	{ "L1I_CACHESIZE:     ", dec },
 	  [AT_L1I_CACHEGEOMETRY - 2] =	{ "L1I_CACHEGEOMETRY: 0x", hex },
 	  [AT_L1D_CACHESIZE - 2] =	{ "L1D_CACHESIZE:     ", dec },

commit f2413f2710d5d5cc884b413b83fcf8198e3717fa
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Sat Aug 28 06:10:38 2021 -0700

    x86-64: Use testl to check __x86_string_control
    
    Use testl, instead of andl, to check __x86_string_control to avoid
    updating __x86_string_control.
    
    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
    (cherry picked from commit 3c8b9879cab6d41787bc5b14c1748f62fd6d0e5f)

diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S
index 9f02624375..abde8438d4 100644
--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S
+++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S
@@ -325,7 +325,7 @@ L(movsb):
 	/* Avoid slow backward REP MOVSB.  */
 	jb	L(more_8x_vec_backward)
 # if AVOID_SHORT_DISTANCE_REP_MOVSB
-	andl	$X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip)
+	testl	$X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip)
 	jz	3f
 	movq	%rdi, %rcx
 	subq	%rsi, %rcx
@@ -333,7 +333,7 @@ L(movsb):
 # endif
 1:
 # if AVOID_SHORT_DISTANCE_REP_MOVSB
-	andl	$X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip)
+	testl	$X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip)
 	jz	3f
 	movq	%rsi, %rcx
 	subq	%rdi, %rcx

commit 52d0119743180164d1664b6773ac5d873f224608
Author: Jiaxun Yang <jiaxun.yang@flygoat.com>
Date:   Tue Sep 7 13:31:42 2021 +0800

    MIPS: Setup errno for {f,l,}xstat
    
    {f,l,}xstat stub for MIPS is using INTERNAL_SYSCALL
    to do xstat syscall for glibc ver, However it leaves
    errno untouched and thus giving bad errno output.
    
    Setup errno properly when syscall returns non-zero.
    
    Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
    Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
    
    (cherry picked from commit 66016ec8aeefd40e016d7040d966484c764b0e9c)

diff --git a/sysdeps/unix/sysv/linux/mips/fxstat.c b/sysdeps/unix/sysv/linux/mips/fxstat.c
index 11511d30b3..4a6016ff12 100644
--- a/sysdeps/unix/sysv/linux/mips/fxstat.c
+++ b/sysdeps/unix/sysv/linux/mips/fxstat.c
@@ -35,7 +35,9 @@ __fxstat (int vers, int fd, struct stat *buf)
       {
 	struct kernel_stat kbuf;
 	int r = INTERNAL_SYSCALL_CALL (fstat, fd, &kbuf);
-	return r ?: __xstat_conv (vers, &kbuf, buf);
+	if (r == 0)
+	  return  __xstat_conv (vers, &kbuf, buf);
+	return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
       }
     }
 }
diff --git a/sysdeps/unix/sysv/linux/mips/lxstat.c b/sysdeps/unix/sysv/linux/mips/lxstat.c
index 871fb6c6c5..54f990a250 100644
--- a/sysdeps/unix/sysv/linux/mips/lxstat.c
+++ b/sysdeps/unix/sysv/linux/mips/lxstat.c
@@ -35,7 +35,9 @@ __lxstat (int vers, const char *name, struct stat *buf)
       {
 	struct kernel_stat kbuf;
 	int r = INTERNAL_SYSCALL_CALL (lstat, name, &kbuf);
-	return r ?: __xstat_conv (vers, &kbuf, buf);
+	if (r == 0)
+	  return  __xstat_conv (vers, &kbuf, buf);
+	return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
       }
     }
 }
diff --git a/sysdeps/unix/sysv/linux/mips/xstat.c b/sysdeps/unix/sysv/linux/mips/xstat.c
index 9d810b6f65..86f4dc31a8 100644
--- a/sysdeps/unix/sysv/linux/mips/xstat.c
+++ b/sysdeps/unix/sysv/linux/mips/xstat.c
@@ -35,7 +35,9 @@ __xstat (int vers, const char *name, struct stat *buf)
       {
 	struct kernel_stat kbuf;
 	int r = INTERNAL_SYSCALL_CALL (stat, name, &kbuf);
-	return r ?: __xstat_conv (vers, &kbuf, buf);
+	if (r == 0)
+	  return  __xstat_conv (vers, &kbuf, buf);
+	return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
       }
     }
 }

commit addc9d62d61eea790a35328cbfce53333a07bd3e
Author: Florian Weimer <fweimer@redhat.com>
Date:   Mon Aug 30 13:43:56 2021 +0200

    support: Add support_wait_for_thread_exit
    
    (cherry picked from commit 032d74eaf6179100048a5bf0ce942e97dc8b9a60)

diff --git a/support/Makefile b/support/Makefile
index a462781718..ef2b1a980a 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -82,9 +82,10 @@ libsupport-routines = \
   support_test_compare_blob \
   support_test_compare_failure \
   support_test_compare_string \
-  support_write_file_string \
   support_test_main \
   support_test_verify_impl \
+  support_wait_for_thread_exit \
+  support_write_file_string \
   temp_file \
   timespec \
   timespec-time64 \
diff --git a/support/support.h b/support/support.h
index 834dba9097..a5978b939a 100644
--- a/support/support.h
+++ b/support/support.h
@@ -174,6 +174,10 @@ timer_t support_create_timer (uint64_t sec, long int nsec, bool repeat,
 /* Disable the timer TIMER.  */
 void support_delete_timer (timer_t timer);
 
+/* Wait until all threads except the current thread have exited (as
+   far as the kernel is concerned).  */
+void support_wait_for_thread_exit (void);
+
 struct support_stack
 {
   void *stack;
diff --git a/support/support_wait_for_thread_exit.c b/support/support_wait_for_thread_exit.c
new file mode 100644
index 0000000000..658a813810
--- /dev/null
+++ b/support/support_wait_for_thread_exit.c
@@ -0,0 +1,72 @@
+/* Wait until all threads except the current thread has exited.
+   Copyright (C) 2021 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 <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <unistd.h>
+
+void
+support_wait_for_thread_exit (void)
+{
+#ifdef __linux__
+  DIR *proc_self_task = opendir ("/proc/self/task");
+  TEST_VERIFY_EXIT (proc_self_task != NULL);
+
+  while (true)
+    {
+      errno = 0;
+      struct dirent *e = readdir (proc_self_task);
+      if (e == NULL && errno != 0)
+        FAIL_EXIT1 ("readdir: %m");
+      if (e == NULL)
+        {
+          /* Only the main thread remains.  Testing may continue.  */
+          closedir (proc_self_task);
+          return;
+        }
+
+      if (strcmp (e->d_name, ".") == 0 || strcmp (e->d_name, "..") == 0)
+        continue;
+
+      int task_tid = atoi (e->d_name);
+      if (task_tid <= 0)
+        FAIL_EXIT1 ("Invalid /proc/self/task entry: %s", e->d_name);
+
+      if (task_tid == gettid ())
+        /* The current thread.  Keep scanning for other
+           threads.  */
+        continue;
+
+      /* task_tid does not refer to this thread here, i.e., there is
+         another running thread.  */
+
+      /* Small timeout to give the thread a chance to exit.  */
+      usleep (50 * 1000);
+
+      /* Start scanning the directory from the start.  */
+      rewinddir (proc_self_task);
+    }
+#else
+  /* Use a large timeout because we cannot verify that the thread has
+     exited.  */
+  usleep (5 * 1000 * 1000);
+#endif
+}

commit 3abf3bd4edc86fb28c099cc85203cb46a811e0b8
Author: Florian Weimer <fweimer@redhat.com>
Date:   Mon Sep 13 11:06:08 2021 +0200

    nptl: pthread_kill, pthread_cancel should not fail after exit (bug 19193)
    
    This closes one remaining race condition related to bug 12889: if
    the thread already exited on the kernel side, returning ESRCH
    is not correct because that error is reserved for the thread IDs
    (pthread_t values) whose lifetime has ended.  In case of a
    kernel-side exit and a valid thread ID, no signal needs to be sent
    and cancellation does not have an effect, so just return 0.
    
    sysdeps/pthread/tst-kill4.c triggers undefined behavior and is
    removed with this commit.
    
    Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
    (cherry picked from commit 8af8456004edbab71f8903a60a3cae442cf6fe69)

diff --git a/NEWS b/NEWS
index 89e20cf062..8e9e56d2c2 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ Version 2.34.1
 
 The following bugs are resolved with this release:
 
+  [19193] nptl: pthread_kill, pthread_cancel should not fail after exit
   [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl
 
 
diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c
index cc25ff21f3..9bac6e3b76 100644
--- a/nptl/pthread_cancel.c
+++ b/nptl/pthread_cancel.c
@@ -62,10 +62,11 @@ __pthread_cancel (pthread_t th)
 {
   volatile struct pthread *pd = (volatile struct pthread *) th;
 
-  /* Make sure the descriptor is valid.  */
-  if (INVALID_TD_P (pd))
-    /* Not a valid thread handle.  */
-    return ESRCH;
+  if (pd->tid == 0)
+    /* The thread has already exited on the kernel side.  Its outcome
+       (regular exit, other cancelation) has already been
+       determined.  */
+    return 0;
 
   static int init_sigcancel = 0;
   if (atomic_load_relaxed (&init_sigcancel) == 0)
diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c
index f79a2b26fc..5d4c86f920 100644
--- a/nptl/pthread_kill.c
+++ b/nptl/pthread_kill.c
@@ -46,7 +46,12 @@ __pthread_kill_internal (pthread_t threadid, int signo)
 	    ? INTERNAL_SYSCALL_ERRNO (val) : 0);
     }
   else
-    val = ESRCH;
+    /* The kernel reports that the thread has exited.  POSIX specifies
+       the ESRCH error only for the case when the lifetime of a thread
+       ID has ended, but calling pthread_kill on such a thread ID is
+       undefined in glibc.  Therefore, do not treat kernel thread exit
+       as an error.  */
+    val = 0;
 
   return val;
 }
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index 42f9fc5072..dedfa0d290 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -89,7 +89,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
 	 tst-join8 tst-join9 tst-join10 tst-join11 tst-join12 tst-join13 \
 	 tst-join14 tst-join15 \
 	 tst-key1 tst-key2 tst-key3 tst-key4 \
-	 tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \
+	 tst-kill1 tst-kill2 tst-kill3 tst-kill5 tst-kill6 \
 	 tst-locale1 tst-locale2 \
 	 tst-memstream \
 	 tst-mutex-errorcheck tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 \
@@ -118,6 +118,9 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
 	 tst-unload \
 	 tst-unwind-thread \
 	 tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \
+	 tst-pthread_cancel-exited \
+	 tst-pthread_kill-exited \
+	 # tests
 
 tests-time64 := \
   tst-abstime-time64 \
diff --git a/sysdeps/pthread/tst-kill4.c b/sysdeps/pthread/tst-kill4.c
deleted file mode 100644
index 9563939792..0000000000
--- a/sysdeps/pthread/tst-kill4.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Copyright (C) 2003-2021 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <errno.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-
-static void *
-tf (void *a)
-{
-  return NULL;
-}
-
-
-int
-do_test (void)
-{
-  pthread_attr_t at;
-  if (pthread_attr_init (&at) != 0)
-    {
-      puts ("attr_create failed");
-      exit (1);
-    }
-
-  /* Limit thread stack size, because if it is too large, pthread_join
-     will free it immediately rather than put it into stack cache.  */
-  if (pthread_attr_setstacksize (&at, 2 * 1024 * 1024) != 0)
-    {
-      puts ("setstacksize failed");
-      exit (1);
-    }
-
-  pthread_t th;
-  if (pthread_create (&th, &at, tf, NULL) != 0)
-    {
-      puts ("create failed");
-      exit (1);
-    }
-
-  pthread_attr_destroy (&at);
-
-  if (pthread_join (th, NULL) != 0)
-    {
-      puts ("join failed");
-      exit (1);
-    }
-
-  /* The following only works because we assume here something about
-     the implementation.  Namely, that the memory allocated for the
-     thread descriptor is not going away, that the TID field is
-     cleared and therefore the signal is sent to process 0, and that
-     we can savely assume there is no other process with this ID at
-     that time.  */
-  int e = pthread_kill (th, 0);
-  if (e == 0)
-    {
-      puts ("pthread_kill succeeded");
-      exit (1);
-    }
-  if (e != ESRCH)
-    {
-      puts ("pthread_kill didn't return ESRCH");
-      exit (1);
-    }
-
-  return 0;
-}
-
-
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
diff --git a/sysdeps/pthread/tst-pthread_cancel-exited.c b/sysdeps/pthread/tst-pthread_cancel-exited.c
new file mode 100644
index 0000000000..811c9bee07
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread_cancel-exited.c
@@ -0,0 +1,45 @@
+/* Test that pthread_kill succeeds for an exited thread.
+   Copyright (C) 2021 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 verifies that pthread_kill returns 0 (and not ESRCH) for
+   a thread that has exited on the kernel side.  */
+
+#include <stddef.h>
+#include <support/support.h>
+#include <support/xthread.h>
+
+static void *
+noop_thread (void *closure)
+{
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  pthread_t thr = xpthread_create (NULL, noop_thread, NULL);
+
+  support_wait_for_thread_exit ();
+
+  xpthread_cancel (thr);
+  xpthread_join (thr);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/tst-pthread_kill-exited.c b/sysdeps/pthread/tst-pthread_kill-exited.c
new file mode 100644
index 0000000000..7575fb6d58
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread_kill-exited.c
@@ -0,0 +1,46 @@
+/* Test that pthread_kill succeeds for an exited thread.
+   Copyright (C) 2021 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 verifies that pthread_kill returns 0 (and not ESRCH) for
+   a thread that has exited on the kernel side.  */
+
+#include <signal.h>
+#include <stddef.h>
+#include <support/support.h>
+#include <support/xthread.h>
+
+static void *
+noop_thread (void *closure)
+{
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  pthread_t thr = xpthread_create (NULL, noop_thread, NULL);
+
+  support_wait_for_thread_exit ();
+
+  xpthread_kill (thr, SIGUSR1);
+  xpthread_join (thr);
+
+  return 0;
+}
+
+#include <support/test-driver.c>

commit a8ac8c4725ddb1119764126a8674a04c9dd5aea8
Author: Florian Weimer <fweimer@redhat.com>
Date:   Mon Sep 13 11:06:08 2021 +0200

    nptl: Fix race between pthread_kill and thread exit (bug 12889)
    
    A new thread exit lock and flag are introduced.  They are used to
    detect that the thread is about to exit or has exited in
    __pthread_kill_internal, and the signal is not sent in this case.
    
    The test sysdeps/pthread/tst-pthread_cancel-select-loop.c is derived
    from a downstream test originally written by Marek Polacek.
    
    Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
    (cherry picked from commit 526c3cf11ee9367344b6b15d669e4c3cb461a2be)

diff --git a/NEWS b/NEWS
index 8e9e56d2c2..00fae31e92 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ Version 2.34.1
 
 The following bugs are resolved with this release:
 
+  [12889] nptl: Fix race between pthread_kill and thread exit
   [19193] nptl: pthread_kill, pthread_cancel should not fail after exit
   [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl
 
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index cfe37a3443..50065bc9bd 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -32,6 +32,7 @@
 #include <futex-internal.h>
 #include <kernel-features.h>
 #include <nptl-stack.h>
+#include <libc-lock.h>
 
 /* Default alignment of stack.  */
 #ifndef STACK_ALIGN
@@ -127,6 +128,8 @@ get_cached_stack (size_t *sizep, void **memp)
   /* No pending event.  */
   result->nextevent = NULL;
 
+  result->exiting = false;
+  __libc_lock_init (result->exit_lock);
   result->tls_state = (struct tls_internal_t) { 0 };
 
   /* Clear the DTV.  */
diff --git a/nptl/descr.h b/nptl/descr.h
index c85778d449..4de84138fb 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -396,6 +396,12 @@ struct pthread
      PTHREAD_CANCEL_ASYNCHRONOUS).  */
   unsigned char canceltype;
 
+  /* Used in __pthread_kill_internal to detected a thread that has
+     exited or is about to exit.  exit_lock must only be acquired
+     after blocking signals.  */
+  bool exiting;
+  int exit_lock; /* A low-level lock (for use with __libc_lock_init etc).  */
+
   /* Used on strsignal.  */
   struct tls_internal_t tls_state;
 
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index d8ec299cb1..33b426fc68 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -37,6 +37,7 @@
 #include <sys/single_threaded.h>
 #include <version.h>
 #include <clone_internal.h>
+#include <futex-internal.h>
 
 #include <shlib-compat.h>
 
@@ -485,6 +486,19 @@ start_thread (void *arg)
     /* This was the last thread.  */
     exit (0);
 
+  /* This prevents sending a signal from this thread to itself during
+     its final stages.  This must come after the exit call above
+     because atexit handlers must not run with signals blocked.  */
+  __libc_signal_block_all (NULL);
+
+  /* Tell __pthread_kill_internal that this thread is about to exit.
+     If there is a __pthread_kill_internal in progress, this delays
+     the thread exit until the signal has been queued by the kernel
+     (so that the TID used to send it remains valid).  */
+  __libc_lock_lock (pd->exit_lock);
+  pd->exiting = true;
+  __libc_lock_unlock (pd->exit_lock);
+
 #ifndef __ASSUME_SET_ROBUST_LIST
   /* If this thread has any robust mutexes locked, handle them now.  */
 # if __PTHREAD_MUTEX_HAVE_PREV
diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c
index 5d4c86f920..fb7862eff7 100644
--- a/nptl/pthread_kill.c
+++ b/nptl/pthread_kill.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <libc-lock.h>
 #include <unistd.h>
 #include <pthreadP.h>
 #include <shlib-compat.h>
@@ -23,37 +24,51 @@
 int
 __pthread_kill_internal (pthread_t threadid, int signo)
 {
-  pid_t tid;
   struct pthread *pd = (struct pthread *) threadid;
-
   if (pd == THREAD_SELF)
-    /* It is a special case to handle raise() implementation after a vfork
-       call (which does not update the PD tid field).  */
-    tid = INLINE_SYSCALL_CALL (gettid);
-  else
-    /* Force load of pd->tid into local variable or register.  Otherwise
-       if a thread exits between ESRCH test and tgkill, we might return
-       EINVAL, because pd->tid would be cleared by the kernel.  */
-    tid = atomic_forced_read (pd->tid);
-
-  int val;
-  if (__glibc_likely (tid > 0))
     {
-      pid_t pid = __getpid ();
-
-      val = INTERNAL_SYSCALL_CALL (tgkill, pid, tid, signo);
-      val = (INTERNAL_SYSCALL_ERROR_P (val)
-	    ? INTERNAL_SYSCALL_ERRNO (val) : 0);
+      /* Use the actual TID from the kernel, so that it refers to the
+         current thread even if called after vfork.  There is no
+         signal blocking in this case, so that the signal is delivered
+         immediately, before __pthread_kill_internal returns: a signal
+         sent to the thread itself needs to be delivered
+         synchronously.  (It is unclear if Linux guarantees the
+         delivery of all pending signals after unblocking in the code
+         below.  POSIX only guarantees delivery of a single signal,
+         which may not be the right one.)  */
+      pid_t tid = INTERNAL_SYSCALL_CALL (gettid);
+      int ret = INTERNAL_SYSCALL_CALL (kill, tid, signo);
+      return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
     }
+
+  /* Block all signals, as required by pd->exit_lock.  */
+  sigset_t old_mask;
+  __libc_signal_block_all (&old_mask);
+  __libc_lock_lock (pd->exit_lock);
+
+  int ret;
+  if (pd->exiting)
+    /* The thread is about to exit (or has exited).  Sending the
+       signal is either not observable (the target thread has already
+       blocked signals at this point), or it will fail, or it might be
+       delivered to a new, unrelated thread that has reused the TID.
+       So do not actually send the signal.  Do not report an error
+       because the threadid argument is still valid (the thread ID
+       lifetime has not ended), and ESRCH (for example) would be
+       misleading.  */
+    ret = 0;
   else
-    /* The kernel reports that the thread has exited.  POSIX specifies
-       the ESRCH error only for the case when the lifetime of a thread
-       ID has ended, but calling pthread_kill on such a thread ID is
-       undefined in glibc.  Therefore, do not treat kernel thread exit
-       as an error.  */
-    val = 0;
+    {
+      /* Using tgkill is a safety measure.  pd->exit_lock ensures that
+	 the target thread cannot exit.  */
+      ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo);
+      ret = INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
+    }
+
+  __libc_lock_unlock (pd->exit_lock);
+  __libc_signal_restore_set (&old_mask);
 
-  return val;
+  return ret;
 }
 
 int
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index dedfa0d290..48dba717a1 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -119,7 +119,9 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
 	 tst-unwind-thread \
 	 tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \
 	 tst-pthread_cancel-exited \
+	 tst-pthread_cancel-select-loop \
 	 tst-pthread_kill-exited \
+	 tst-pthread_kill-exiting \
 	 # tests
 
 tests-time64 := \
diff --git a/sysdeps/pthread/tst-pthread_cancel-select-loop.c b/sysdeps/pthread/tst-pthread_cancel-select-loop.c
new file mode 100644
index 0000000000..a62087589c
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread_cancel-select-loop.c
@@ -0,0 +1,87 @@
+/* Test that pthread_cancel succeeds during thread exit.
+   Copyright (C) 2021 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 tries to trigger an internal race condition in
+   pthread_cancel, where the cancellation signal is sent after the
+   thread has begun the cancellation process.  This can result in a
+   spurious ESRCH error.  For the original bug 12889, the window is
+   quite small, so the bug was not reproduced in every run.  */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <support/check.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+/* Set to true by timeout_thread_function when the test should
+   terminate.  */
+static bool timeout;
+
+static void *
+timeout_thread_function (void *unused)
+{
+  usleep (5 * 1000 * 1000);
+  __atomic_store_n (&timeout, true, __ATOMIC_RELAXED);
+  return NULL;
+}
+
+/* Used for blocking the select function below.  */
+static int pipe_fds[2];
+
+static void *
+canceled_thread_function (void *unused)
+{
+  while (true)
+    {
+      fd_set rfs;
+      fd_set wfs;
+      fd_set efs;
+      FD_ZERO (&rfs);
+      FD_ZERO (&wfs);
+      FD_ZERO (&efs);
+      FD_SET (pipe_fds[0], &rfs);
+
+      /* If the cancellation request is recognized early, the thread
+         begins exiting while the cancellation signal arrives.  */
+      select (FD_SETSIZE, &rfs, &wfs, &efs, NULL);
+    }
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  xpipe (pipe_fds);
+  pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL);
+
+  while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED))
+    {
+      pthread_t thr = xpthread_create (NULL, canceled_thread_function, NULL);
+      xpthread_cancel (thr);
+      TEST_VERIFY (xpthread_join (thr) == PTHREAD_CANCELED);
+    }
+
+  xpthread_join (thr_timeout);
+  xclose (pipe_fds[0]);
+  xclose (pipe_fds[1]);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/tst-pthread_kill-exiting.c b/sysdeps/pthread/tst-pthread_kill-exiting.c
new file mode 100644
index 0000000000..f803e94f11
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread_kill-exiting.c
@@ -0,0 +1,123 @@
+/* Test that pthread_kill succeeds during thread exit.
+   Copyright (C) 2021 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 verifies that pthread_kill for a thread that is exiting
+   succeeds (with or without actually delivering the signal).  */
+
+#include <array_length.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <support/xsignal.h>
+#include <support/xthread.h>
+#include <unistd.h>
+
+/* Set to true by timeout_thread_function when the test should
+   terminate.  */
+static bool timeout;
+
+static void *
+timeout_thread_function (void *unused)
+{
+  usleep (1000 * 1000);
+  __atomic_store_n (&timeout, true, __ATOMIC_RELAXED);
+  return NULL;
+}
+
+/* Used to synchronize the sending threads with the target thread and
+   main thread.  */
+static pthread_barrier_t barrier_1;
+static pthread_barrier_t barrier_2;
+
+/* The target thread to which signals are to be sent.  */
+static pthread_t target_thread;
+
+/* Set by the main thread to true after timeout has been set to
+   true.  */
+static bool exiting;
+
+static void *
+sender_thread_function (void *unused)
+{
+  while (true)
+    {
+      /* Wait until target_thread has been initialized.  The target
+         thread and main thread participate in this barrier.  */
+      xpthread_barrier_wait (&barrier_1);
+
+      if (exiting)
+        break;
+
+      xpthread_kill (target_thread, SIGUSR1);
+
+      /* Communicate that the signal has been sent.  The main thread
+         participates in this barrier.  */
+      xpthread_barrier_wait (&barrier_2);
+    }
+  return NULL;
+}
+
+static void *
+target_thread_function (void *unused)
+{
+  target_thread = pthread_self ();
+  xpthread_barrier_wait (&barrier_1);
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  xsignal (SIGUSR1, SIG_IGN);
+
+  pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL);
+
+  pthread_t threads[4];
+  xpthread_barrier_init (&barrier_1, NULL, array_length (threads) + 2);
+  xpthread_barrier_init (&barrier_2, NULL, array_length (threads) + 1);
+
+  for (int i = 0; i < array_length (threads); ++i)
+    threads[i] = xpthread_create (NULL, sender_thread_function, NULL);
+
+  while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED))
+    {
+      xpthread_create (NULL, target_thread_function, NULL);
+
+      /* Wait for the target thread to be set up and signal sending to
+         start.  */
+      xpthread_barrier_wait (&barrier_1);
+
+      /* Wait for signal sending to complete.  */
+      xpthread_barrier_wait (&barrier_2);
+
+      xpthread_join (target_thread);
+    }
+
+  exiting = true;
+
+  /* Signal the sending threads to exit.  */
+  xpthread_create (NULL, target_thread_function, NULL);
+  xpthread_barrier_wait (&barrier_1);
+
+  for (int i = 0; i < array_length (threads); ++i)
+    xpthread_join (threads[i]);
+  xpthread_join (thr_timeout);
+
+  return 0;
+}
+
+#include <support/test-driver.c>

commit 3fc51f35b4f32e1bb99d85c1578e930e725ff929
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Mon Sep 13 20:48:35 2021 +0530

    iconvconfig: Fix behaviour with --prefix [BZ #28199]
    
    The consolidation of configuration parsing broke behaviour with
    --prefix, where the prefix bled into the modules cache.  Accept a
    prefix which, when non-NULL, is prepended to the path when looking for
    configuration files but only the original directory is added to the
    modules cache.
    
    This has no effect on the codegen of gconv_conf since it passes NULL.
    
    Reported-by: Patrick McCarty <patrick.mccarty@intel.com>
    Reported-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
    Reviewed-by: Andreas Schwab <schwab@linux-m68k.org>
    (cherry picked from commit 43cea6d5652b6b9e61ac6ecc69419c909b504f47)

diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
index 62bee28769..cc391d8f93 100644
--- a/iconv/gconv_conf.c
+++ b/iconv/gconv_conf.c
@@ -478,7 +478,7 @@ __gconv_read_conf (void)
   __gconv_get_path ();
 
   for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt)
-    gconv_parseconfdir (__gconv_path_elem[cnt].name,
+    gconv_parseconfdir (NULL, __gconv_path_elem[cnt].name,
 			__gconv_path_elem[cnt].len);
 #endif
 
diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
index 2f062689ec..a586268abc 100644
--- a/iconv/gconv_parseconfdir.h
+++ b/iconv/gconv_parseconfdir.h
@@ -39,7 +39,6 @@
 /* Name of the file containing the module information in the directories
    along the path.  */
 static const char gconv_conf_filename[] = "gconv-modules";
-static const char gconv_conf_dirname[] = "gconv-modules.d";
 
 static void add_alias (char *);
 static void add_module (char *, const char *, size_t, int);
@@ -110,19 +109,28 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len)
   return true;
 }
 
+/* Prefix DIR (with length DIR_LEN) with PREFIX if the latter is non-NULL and
+   parse configuration in it.  */
+
 static __always_inline bool
-gconv_parseconfdir (const char *dir, size_t dir_len)
+gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
 {
-  /* No slash needs to be inserted between dir and gconv_conf_filename;
-     dir already ends in a slash.  */
-  char *buf = malloc (dir_len + sizeof (gconv_conf_dirname));
+  /* No slash needs to be inserted between dir and gconv_conf_filename; dir
+     already ends in a slash.  The additional 2 is to accommodate the ".d"
+     when looking for configuration files in gconv-modules.d.  */
+  size_t buflen = dir_len + sizeof (gconv_conf_filename) + 2;
+  char *buf = malloc (buflen + (prefix != NULL ? strlen (prefix) : 0));
+  char *cp = buf;
   bool found = false;
 
   if (buf == NULL)
     return false;
 
-  char *cp = mempcpy (mempcpy (buf, dir, dir_len), gconv_conf_filename,
-		      sizeof (gconv_conf_filename));
+  if (prefix != NULL)
+    cp = stpcpy (cp, prefix);
+
+  cp = mempcpy (mempcpy (cp, dir, dir_len), gconv_conf_filename,
+		sizeof (gconv_conf_filename));
 
   /* Read the gconv-modules configuration file first.  */
   found = read_conf_file (buf, dir, dir_len);
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
index 783b2bbdbb..273a71f673 100644
--- a/iconv/iconvconfig.c
+++ b/iconv/iconvconfig.c
@@ -653,13 +653,21 @@ add_module (char *rp, const char *directory,
 static int
 handle_dir (const char *dir)
 {
+  char *newp = NULL;
   size_t dirlen = strlen (dir);
   bool found = false;
 
-  char *fulldir = xasprintf ("%s%s%s", dir[0] == '/' ? prefix : "",
-			     dir, dir[dirlen - 1] != '/' ? "/" : "");
+  /* End directory path with a '/' if it doesn't already.  */
+  if (dir[dirlen - 1] != '/')
+    {
+      newp = xmalloc (dirlen + 2);
+      memcpy (newp, dir, dirlen);
+      newp[dirlen++] = '/';
+      newp[dirlen] = '\0';
+      dir = newp;
+    }
 
-  found = gconv_parseconfdir (fulldir, strlen (fulldir));
+  found = gconv_parseconfdir (dir[0] == '/' ? prefix : NULL, dir, dirlen);
 
   if (!found)
     {
@@ -671,7 +679,7 @@ handle_dir (const char *dir)
 	     "configuration files with names ending in .conf.");
     }
 
-  free (fulldir);
+  free (newp);
 
   return found ? 0 : 1;
 }

commit ae925404a10bf0ea63d6e8d41e3821f68b4d776c
Author: Aurelien Jarno <aurelien@aurel32.net>
Date:   Fri Sep 3 00:28:14 2021 +0200

    Fix failing nss/tst-nss-files-hosts-long with local resolver
    
    When a local resolver like unbound is listening on the IPv4 loopback
    address 127.0.0.1, the nss/tst-nss-files-hosts-long test fails. This is
    due to:
    - the default resolver in the absence of resolv.conf being 127.0.0.1
    - the default DNS NSS database configuration in the absence of
      nsswitch.conf being 'hosts: dns [!UNAVAIL=return] file'
    
    This causes the requests for 'test4' and 'test6' to first be sent to the
    local resolver, which responds with NXDOMAIN in the likely case those
    records do no exist. In turn that causes the access to /etc/hosts to be
    skipped, which is the purpose of that test.
    
    Fix that by providing a simple nsswitch.conf file forcing access to
    /etc/hosts for that test. I have tested that the only changed result in
    the testsuite is that test.
    
    (cherry picked from commit 2738480a4b0866723fb8c633f36bdd34a8767581)

diff --git a/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf
new file mode 100644
index 0000000000..5b0c6a4199
--- /dev/null
+++ b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf
@@ -0,0 +1 @@
+hosts: files

commit 007d699d0e0d0957eead78ad252ad592656284de
Author: Joseph Myers <joseph@codesourcery.com>
Date:   Tue Sep 7 13:08:38 2021 +0000

    Use Linux 5.14 in build-many-glibcs.py
    
    This patch makes build-many-glibcs.py use Linux 5.14.
    
    Tested with build-many-glibcs.py (host-libraries, compilers and glibcs
    builds).
    
    (cherry picked from commit 4e04a47208e1712fcf202a6d9831f0900d575225)

diff --git a/scripts/build-many-glibcs.py b/scripts/build-many-glibcs.py
index 5a77af90a6..86537fa800 100755
--- a/scripts/build-many-glibcs.py
+++ b/scripts/build-many-glibcs.py
@@ -782,7 +782,7 @@ class Context(object):
                             'gcc': 'vcs-11',
                             'glibc': 'vcs-mainline',
                             'gmp': '6.2.1',
-                            'linux': '5.13',
+                            'linux': '5.14',
                             'mpc': '1.2.1',
                             'mpfr': '4.1.0',
                             'mig': 'vcs-mainline',

commit 005bafcf5b8a85d4c82831401f052747e160a7e8
Author: Joseph Myers <joseph@codesourcery.com>
Date:   Wed Sep 8 12:42:06 2021 +0000

    Update syscall lists for Linux 5.14
    
    Linux 5.14 has two new syscalls, memfd_secret (on some architectures
    only) and quotactl_fd.  Update syscall-names.list and regenerate the
    arch-syscall.h headers with build-many-glibcs.py update-syscalls.
    
    Tested with build-many-glibcs.py.
    
    (cherry picked from commit 89dc0372a9055e7ef86fe19be6201fa0b16b2f0e)

diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
index e9eb707d0a..bedab1abba 100644
--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
@@ -126,6 +126,7 @@
 #define __NR_mbind 235
 #define __NR_membarrier 283
 #define __NR_memfd_create 279
+#define __NR_memfd_secret 447
 #define __NR_migrate_pages 238
 #define __NR_mincore 232
 #define __NR_mkdirat 34
@@ -187,6 +188,7 @@
 #define __NR_pwritev 70
 #define __NR_pwritev2 287
 #define __NR_quotactl 60
+#define __NR_quotactl_fd 443
 #define __NR_read 63
 #define __NR_readahead 213
 #define __NR_readlinkat 78
diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
index bd6b7d4003..91354ed9e2 100644
--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
@@ -337,6 +337,7 @@
 #define __NR_pwritev2 521
 #define __NR_query_module 347
 #define __NR_quotactl 148
+#define __NR_quotactl_fd 553
 #define __NR_read 3
 #define __NR_readahead 379
 #define __NR_readlink 58
diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h
index 10650549c1..ff5c7eb36d 100644
--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h
@@ -190,6 +190,7 @@
 #define __NR_pwritev 70
 #define __NR_pwritev2 287
 #define __NR_quotactl 60
+#define __NR_quotactl_fd 443
 #define __NR_read 63
 #define __NR_readahead 213
 #define __NR_readlinkat 78
diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h
index 85c9b236ce..5772333cee 100644
--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h
@@ -244,6 +244,7 @@
 #define __NR_pwritev 362
 #define __NR_pwritev2 393
 #define __NR_quotactl 131
+#define __NR_quotactl_fd 443
 #define __NR_read 3
 #define __NR_readahead 225
 #define __NR_readlink 85
diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h
index 24b0d1f94e..4af6d6202f 100644
--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h
@@ -199,6 +199,7 @@
 #define __NR_pwritev 70
 #define __NR_pwritev2 287
 #define __NR_quotactl 60
+#define __NR_quotactl_fd 443
 #define __NR_read 63
 #define __NR_readahead 213
 #define __NR_readlinkat 78
diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
index feb70abc3e..b07fc8549d 100644
--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
@@ -231,6 +231,7 @@
 #define __NR_pwritev 316
 #define __NR_pwritev2 348
 #define __NR_quotactl 131
+#define __NR_quotactl_fd 443
 #define __NR_read 3
 #define __NR_readahead 207
 #define __NR_readlink 85
diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h
index 3b1894a79b..6e4264698b 100644
--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h
@@ -183,6 +183,7 @@
 #define __NR_mbind 274
 #define __NR_membarrier 375
 #define __NR_memfd_create 356
+#define __NR_memfd_secret 447
 #define __NR_migrate_pages 294
 #define __NR_mincore 218
 #define __NR_mkdir 39
@@ -266,6 +267,7 @@
 #define __NR_pwritev2 379
 #define __NR_query_module 167
 #define __NR_quotactl 131
+#define __NR_quotactl_fd 443
 #define __NR_read 3
 #define __NR_readahead 225
 #define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h
index fb388a5fa4..1ca706d721 100644
--- a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h
@@ -218,6 +218,7 @@
 #define __NR_pwritev 1320
 #define __NR_pwritev2 1349
 #define __NR_quotactl 1137
+#define __NR_quotactl_fd 1467
 #define __NR_read 1026
 #define __NR_readahead 1216
 #define __NR_readlink 1092
diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
index 7bc8c4af92..2f10f71f90 100644
--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
@@ -254,6 +254,7 @@
 #define __NR_pwritev2 378
 #define __NR_query_module 167
 #define __NR_quotactl 131
+#define __NR_quotactl_fd 443
 #define __NR_read 3
 #define __NR_readahead 240
 #define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
index cf560d3af4..0607a4dfa6 100644
--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
@@ -266,6 +266,7 @@
 #define __NR_pwritev2 394
 #define __NR_query_module 167
 #define __NR_quotactl 131
+#define __NR_quotactl_fd 443
 #define __NR_read 3
 #define __NR_readahead 225
 #define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
index f346460f48..0055eec0b1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
@@ -251,6 +251,7 @@
 #define __NR_pwritev2 4362
 #define __NR_query_module 4187
 #define __NR_quotactl 4131
+#define __NR_quotactl_fd 4443
 #define __NR_read 4003
 #define __NR_readahead 4223
 #define __NR_readdir 4089
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
index 38ed84997a..8e8e9f91cc 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
@@ -232,6 +232,7 @@
 #define __NR_pwritev2 6326
 #define __NR_query_module 6171
 #define __NR_quotactl 6172
+#define __NR_quotactl_fd 6443
 #define __NR_read 6000
 #define __NR_readahead 6179
 #define __NR_readlink 6087
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
index e6a10c8421..ebd1545f80 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
@@ -219,6 +219,7 @@
 #define __NR_pwritev2 5322
 #define __NR_query_module 5171
 #define __NR_quotactl 5172
+#define __NR_quotactl_fd 5443
 #define __NR_read 5000
 #define __NR_readahead 5179
 #define __NR_readlink 5087
diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
index 5314890289..2b530b1f88 100644
--- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
@@ -198,6 +198,7 @@
 #define __NR_pwritev 70
 #define __NR_pwritev2 287
 #define __NR_quotactl 60
+#define __NR_quotactl_fd 443
 #define __NR_read 63
 #define __NR_readahead 213
 #define __NR_readlinkat 78
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
index b5b0758532..a32984a9c1 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
@@ -260,6 +260,7 @@
 #define __NR_pwritev2 381
 #define __NR_query_module 166
 #define __NR_quotactl 131
+#define __NR_quotactl_fd 443
 #define __NR_read 3
 #define __NR_readahead 191
 #define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
index c77435ca61..b01e464fb9 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
@@ -243,6 +243,7 @@
 #define __NR_pwritev2 381
 #define __NR_query_module 166
 #define __NR_quotactl 131
+#define __NR_quotactl_fd 443
 #define __NR_read 3
 #define __NR_readahead 191
 #define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
index 70854bb9e3..24d0a2c455 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
@@ -179,6 +179,7 @@
 #define __NR_pwritev 70
 #define __NR_pwritev2 287
 #define __NR_quotactl 60
+#define __NR_quotactl_fd 443
 #define __NR_read 63
 #define __NR_readahead 213
 #define __NR_readlinkat 78
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
index 83b9f31aba..e526c89ae7 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
@@ -187,6 +187,7 @@
 #define __NR_pwritev 70
 #define __NR_pwritev2 287
 #define __NR_quotactl 60
+#define __NR_quotactl_fd 443
 #define __NR_read 63
 #define __NR_readahead 213
 #define __NR_readlinkat 78
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
index b224c4aad4..d4c7b101b6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
@@ -251,6 +251,7 @@
 #define __NR_pwritev2 377
 #define __NR_query_module 167
 #define __NR_quotactl 131
+#define __NR_quotactl_fd 443
 #define __NR_read 3
 #define __NR_readahead 222
 #define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
index 59864af125..bd8c78d705 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
@@ -221,6 +221,7 @@
 #define __NR_pwritev2 377
 #define __NR_query_module 167
 #define __NR_quotactl 131
+#define __NR_quotactl_fd 443
 #define __NR_read 3
 #define __NR_readahead 222
 #define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h
index 23612c9092..3b6ac3d084 100644
--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h
@@ -246,6 +246,7 @@
 #define __NR_pwritev 334
 #define __NR_pwritev2 382
 #define __NR_quotactl 131
+#define __NR_quotactl_fd 443
 #define __NR_read 3
 #define __NR_readahead 225
 #define __NR_readdir 89
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
index 380cddb2d8..35221a707e 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
@@ -252,6 +252,7 @@
 #define __NR_pwritev2 359
 #define __NR_query_module 184
 #define __NR_quotactl 165
+#define __NR_quotactl_fd 443
 #define __NR_read 3
 #define __NR_readahead 205
 #define __NR_readdir 204
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
index 2175eeb6ed..5ba2b20509 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
@@ -231,6 +231,7 @@
 #define __NR_pwritev2 359
 #define __NR_query_module 184
 #define __NR_quotactl 165
+#define __NR_quotactl_fd 443
 #define __NR_read 3
 #define __NR_readahead 205
 #define __NR_readdir 204
diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
index 89c5895b9b..fd98893b0e 100644
--- a/sysdeps/unix/sysv/linux/syscall-names.list
+++ b/sysdeps/unix/sysv/linux/syscall-names.list
@@ -21,8 +21,8 @@
 # This file can list all potential system calls.  The names are only
 # used if the installed kernel headers also provide them.
 
-# The list of system calls is current as of Linux 5.13.
-kernel 5.13
+# The list of system calls is current as of Linux 5.14.
+kernel 5.14
 
 FAST_atomic_update
 FAST_cmpxchg
@@ -247,6 +247,7 @@ madvise
 mbind
 membarrier
 memfd_create
+memfd_secret
 memory_ordering
 migrate_pages
 mincore
@@ -452,6 +453,7 @@ pwritev
 pwritev2
 query_module
 quotactl
+quotactl_fd
 read
 readahead
 readdir
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
index 8e028eb62b..26d6ac68a6 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
@@ -154,6 +154,7 @@
 #define __NR_mbind 237
 #define __NR_membarrier 324
 #define __NR_memfd_create 319
+#define __NR_memfd_secret 447
 #define __NR_migrate_pages 256
 #define __NR_mincore 27
 #define __NR_mkdir 83
@@ -224,6 +225,7 @@
 #define __NR_pwritev2 328
 #define __NR_query_module 178
 #define __NR_quotactl 179
+#define __NR_quotactl_fd 443
 #define __NR_read 0
 #define __NR_readahead 187
 #define __NR_readlink 89
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
index 004feb53f1..36847783f6 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
@@ -148,6 +148,7 @@
 #define __NR_mbind 1073742061
 #define __NR_membarrier 1073742148
 #define __NR_memfd_create 1073742143
+#define __NR_memfd_secret 1073742271
 #define __NR_migrate_pages 1073742080
 #define __NR_mincore 1073741851
 #define __NR_mkdir 1073741907
@@ -216,6 +217,7 @@
 #define __NR_pwritev 1073742359
 #define __NR_pwritev2 1073742371
 #define __NR_quotactl 1073742003
+#define __NR_quotactl_fd 1073742267
 #define __NR_read 1073741824
 #define __NR_readahead 1073742011
 #define __NR_readlink 1073741913

commit 114581bf53864aaee562ee237461fc394bc61963
Author: Joseph Myers <joseph@codesourcery.com>
Date:   Tue Sep 14 13:51:58 2021 +0000

    Update kernel version to 5.14 in tst-mman-consts.py
    
    This patch updates the kernel version in the test tst-mman-consts.py
    to 5.14.  (There are no new MAP_* constants covered by this test in
    5.14 that need any other header changes.)
    
    Tested with build-many-glibcs.py.
    
    (cherry picked from commit 4b39e3498324d1aea802fea8d4b8764f5ddb4fd1)

diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py
index ee5b13ee12..810433c238 100644
--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py
+++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py
@@ -33,7 +33,7 @@ def main():
                         help='C compiler (including options) to use')
     args = parser.parse_args()
     linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
-    linux_version_glibc = (5, 13)
+    linux_version_glibc = (5, 14)
     sys.exit(glibcextract.compare_macro_consts(
         '#define _GNU_SOURCE 1\n'
         '#include <sys/mman.h>\n',

commit 4ed990e5b97a61f29f929bdeb36c5b2abb547a64
Author: Joseph Myers <joseph@codesourcery.com>
Date:   Tue Sep 14 14:19:24 2021 +0000

    Add MADV_POPULATE_READ and MADV_POPULATE_WRITE from Linux 5.14 to bits/mman-linux.h
    
    Linux 5.14 adds constants MADV_POPULATE_READ and MADV_POPULATE_WRITE
    (with the same values on all architectures).  Add these to glibc's
    bits/mman-linux.h.
    
    Tested for x86_64.
    
    (cherry picked from commit 3561106278cddd2f007bd27fd4c3e90caaf14b43)

diff --git a/sysdeps/unix/sysv/linux/bits/mman-linux.h b/sysdeps/unix/sysv/linux/bits/mman-linux.h
index 3b1ae418e0..31451c28d9 100644
--- a/sysdeps/unix/sysv/linux/bits/mman-linux.h
+++ b/sysdeps/unix/sysv/linux/bits/mman-linux.h
@@ -89,6 +89,10 @@
 # define MADV_KEEPONFORK  19	/* Undo MADV_WIPEONFORK.  */
 # define MADV_COLD        20	/* Deactivate these pages.  */
 # define MADV_PAGEOUT     21	/* Reclaim these pages.  */
+# define MADV_POPULATE_READ 22	/* Populate (prefault) page tables
+				   readable.  */
+# define MADV_POPULATE_WRITE 23	/* Populate (prefault) page tables
+				   writable.  */
 # define MADV_HWPOISON	  100	/* Poison a page for testing.  */
 #endif
 

commit 433ec4f14a5753c7689c83c20c9972915c53c204
Author: Aurelien Jarno <aurelien@aurel32.net>
Date:   Fri Sep 10 19:39:35 2021 +0200

    posix: Fix attribute access mode on getcwd [BZ #27476]
    
    There is a GNU extension that allows to call getcwd(NULL, >0). It is
    described in the documentation, but also directly in the unistd.h
    header, just above the declaration.
    
    Therefore the attribute access mode added in commit 06febd8c6705
    is not correct. Drop it.

diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h
index f0831386c7..622adeb2b2 100644
--- a/posix/bits/unistd.h
+++ b/posix/bits/unistd.h
@@ -199,10 +199,9 @@ __NTH (readlinkat (int __fd, const char *__restrict __path,
 #endif
 
 extern char *__getcwd_chk (char *__buf, size_t __size, size_t __buflen)
-     __THROW __wur __attr_access ((__write_only__, 1, 2));
+     __THROW __wur;
 extern char *__REDIRECT_NTH (__getcwd_alias,
-			     (char *__buf, size_t __size), getcwd)
-  __wur __attr_access ((__write_only__, 1, 2));
+			     (char *__buf, size_t __size), getcwd) __wur;
 extern char *__REDIRECT_NTH (__getcwd_chk_warn,
 			     (char *__buf, size_t __size, size_t __buflen),
 			     __getcwd_chk)
diff --git a/posix/unistd.h b/posix/unistd.h
index 3dca65732f..8224c5fbc9 100644
--- a/posix/unistd.h
+++ b/posix/unistd.h
@@ -528,8 +528,7 @@ extern int fchdir (int __fd) __THROW __wur;
    an array is allocated with `malloc'; the array is SIZE
    bytes long, unless SIZE == 0, in which case it is as
    big as necessary.  */
-extern char *getcwd (char *__buf, size_t __size) __THROW __wur
-    __attr_access ((__write_only__, 1, 2));
+extern char *getcwd (char *__buf, size_t __size) __THROW __wur;
 
 #ifdef	__USE_GNU
 /* Return a malloc'd string containing the current directory name.

commit 73c7f5a87971de2797f261e1a447f68dce09284b
Author: Florian Weimer <fweimer@redhat.com>
Date:   Mon Sep 20 14:56:08 2021 +0200

    nptl: pthread_kill needs to return ESRCH for old programs (bug 19193)
    
    The fix for bug 19193 breaks some old applications which appear
    to use pthread_kill to probe if a thread is still running, something
    that is not supported by POSIX.
    
    (cherry picked from commit 95dba35bf05e4a5d69dfae5e9c9d4df3646a7f93)

diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c
index fb7862eff7..a44dc8f2d9 100644
--- a/nptl/pthread_kill.c
+++ b/nptl/pthread_kill.c
@@ -21,8 +21,11 @@
 #include <pthreadP.h>
 #include <shlib-compat.h>
 
-int
-__pthread_kill_internal (pthread_t threadid, int signo)
+/* Sends SIGNO to THREADID.  If the thread is about to exit or has
+   already exited on the kernel side, return NO_TID.  Otherwise return
+   0 or an error code. */
+static int
+__pthread_kill_implementation (pthread_t threadid, int signo, int no_tid)
 {
   struct pthread *pd = (struct pthread *) threadid;
   if (pd == THREAD_SELF)
@@ -52,11 +55,8 @@ __pthread_kill_internal (pthread_t threadid, int signo)
        signal is either not observable (the target thread has already
        blocked signals at this point), or it will fail, or it might be
        delivered to a new, unrelated thread that has reused the TID.
-       So do not actually send the signal.  Do not report an error
-       because the threadid argument is still valid (the thread ID
-       lifetime has not ended), and ESRCH (for example) would be
-       misleading.  */
-    ret = 0;
+       So do not actually send the signal.  */
+    ret = no_tid;
   else
     {
       /* Using tgkill is a safety measure.  pd->exit_lock ensures that
@@ -71,6 +71,15 @@ __pthread_kill_internal (pthread_t threadid, int signo)
   return ret;
 }
 
+int
+__pthread_kill_internal (pthread_t threadid, int signo)
+{
+  /* Do not report an error in the no-tid case because the threadid
+     argument is still valid (the thread ID lifetime has not ended),
+     and ESRCH (for example) would be misleading.  */
+  return __pthread_kill_implementation (threadid, signo, 0);
+}
+
 int
 __pthread_kill (pthread_t threadid, int signo)
 {
@@ -81,6 +90,7 @@ __pthread_kill (pthread_t threadid, int signo)
 
   return __pthread_kill_internal (threadid, signo);
 }
+
 /* Some architectures (for instance arm) might pull raise through libgcc, so
    avoid the symbol version if it ends up being used on ld.so.  */
 #if !IS_IN(rtld)
@@ -88,6 +98,17 @@ libc_hidden_def (__pthread_kill)
 versioned_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_34);
 
 # if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34)
-compat_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_0);
+/* Variant which returns ESRCH in the no-TID case, for backwards
+   compatibility.  */
+int
+attribute_compat_text_section
+__pthread_kill_esrch (pthread_t threadid, int signo)
+{
+  if (__is_internal_signal (signo))
+    return EINVAL;
+
+  return __pthread_kill_implementation (threadid, signo, ESRCH);
+}
+compat_symbol (libc, __pthread_kill_esrch, pthread_kill, GLIBC_2_0);
 # endif
 #endif
diff --git a/sysdeps/pthread/tst-pthread_kill-exited.c b/sysdeps/pthread/tst-pthread_kill-exited.c
index 7575fb6d58..a2fddad526 100644
--- a/sysdeps/pthread/tst-pthread_kill-exited.c
+++ b/sysdeps/pthread/tst-pthread_kill-exited.c
@@ -16,11 +16,15 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-/* This test verifies that pthread_kill returns 0 (and not ESRCH) for
-   a thread that has exited on the kernel side.  */
+/* This test verifies that the default pthread_kill returns 0 (and not
+   ESRCH) for a thread that has exited on the kernel side.  */
 
+#include <errno.h>
+#include <pthread.h>
+#include <shlib-compat.h>
 #include <signal.h>
 #include <stddef.h>
+#include <support/check.h>
 #include <support/support.h>
 #include <support/xthread.h>
 
@@ -30,6 +34,12 @@ noop_thread (void *closure)
   return NULL;
 }
 
+#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC
+extern __typeof (pthread_kill) compat_pthread_kill;
+compat_symbol_reference (libpthread, compat_pthread_kill, pthread_kill,
+                         GLIBC_2_0);
+#endif
+
 static int
 do_test (void)
 {
@@ -37,7 +47,14 @@ do_test (void)
 
   support_wait_for_thread_exit ();
 
+  /* NB: Always uses the default symbol due to separate compilation.  */
   xpthread_kill (thr, SIGUSR1);
+
+#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC
+  /* Old binaries need the non-conforming ESRCH error code.  */
+  TEST_COMPARE (compat_pthread_kill (thr, SIGUSR1), ESRCH);
+#endif
+
   xpthread_join (thr);
 
   return 0;

commit 8b8a1d0b7375c547ae905917a03743ed6759c5bc
Author: Florian Weimer <fweimer@redhat.com>
Date:   Tue Sep 21 07:12:56 2021 +0200

    nptl: Fix type of pthread_mutexattr_getrobust_np, pthread_mutexattr_setrobust_np (bug 28036)
    
    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
    Tested-by: Carlos O'Donell <carlos@redhat.com>
    (cherry picked from commit f3e664563361dc17530113b3205998d1f19dc4d9)

diff --git a/NEWS b/NEWS
index 00fae31e92..a0c27ecf55 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,7 @@ The following bugs are resolved with this release:
 
   [12889] nptl: Fix race between pthread_kill and thread exit
   [19193] nptl: pthread_kill, pthread_cancel should not fail after exit
+  [28036] Incorrect types for pthread_mutexattr_set/getrobust_np
   [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl
 
 
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index f1b7f2bdc6..43146e91c9 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -933,7 +933,7 @@ extern int pthread_mutexattr_getrobust (const pthread_mutexattr_t *__attr,
 # ifdef __USE_GNU
 #  ifdef __REDIRECT_NTH
 extern int __REDIRECT_NTH (pthread_mutexattr_getrobust_np,
-			   (pthread_mutex_t *, int *),
+			   (pthread_mutexattr_t *, int *),
 			   pthread_mutexattr_getrobust) __nonnull ((1))
   __attribute_deprecated_msg__ ("\
 pthread_mutexattr_getrobust_np is deprecated, use pthread_mutexattr_getrobust");
@@ -949,7 +949,7 @@ extern int pthread_mutexattr_setrobust (pthread_mutexattr_t *__attr,
 # ifdef __USE_GNU
 #  ifdef __REDIRECT_NTH
 extern int __REDIRECT_NTH (pthread_mutexattr_setrobust_np,
-			   (pthread_mutex_t *, int),
+			   (pthread_mutexattr_t *, int),
 			   pthread_mutexattr_setrobust) __nonnull ((1))
   __attribute_deprecated_msg__ ("\
 pthread_mutexattr_setrobust_np is deprecated, use pthread_mutexattr_setrobust");

commit 5ad589d63bc2d9b1fc3d9f32144acaebb85e0803
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Tue Aug 24 16:12:24 2021 -0300

    support: Add support_open_dev_null_range
    
    It returns a range of file descriptor referring to the '/dev/null'
    pathname.  The function takes care of restarting the open range
    if a file descriptor is found within the specified range and
    also increases RLIMIT_NOFILE if required.
    
    Checked on x86_64-linux-gnu.
    
    (cherry picked from commit e814f4b04ee413a7bb3dfa43e74c8fb4abf58359)

diff --git a/support/Makefile b/support/Makefile
index ef2b1a980a..2a0731796f 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -66,6 +66,7 @@ libsupport-routines = \
   support_path_support_time64 \
   support_process_state \
   support_ptrace \
+  support-open-dev-null-range \
   support_openpty \
   support_paths \
   support_quote_blob \
@@ -265,6 +266,7 @@ tests = \
   tst-support_capture_subprocess \
   tst-support_descriptors \
   tst-support_format_dns_packet \
+  tst-support-open-dev-null-range \
   tst-support-process_state \
   tst-support_quote_blob \
   tst-support_quote_string \
diff --git a/support/support-open-dev-null-range.c b/support/support-open-dev-null-range.c
new file mode 100644
index 0000000000..80d9dba504
--- /dev/null
+++ b/support/support-open-dev-null-range.c
@@ -0,0 +1,134 @@
+/* Return a range of open file descriptors.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <support/support.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+
+static void
+increase_nofile (void)
+{
+  struct rlimit rl;
+  if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
+    FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
+
+  rl.rlim_cur += 128;
+
+  if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
+    FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
+}
+
+static int
+open_dev_null (int flags, mode_t mode)
+{
+ int fd = open64 ("/dev/null", flags, mode);
+ if (fd > 0)
+   return fd;
+
+ if (fd < 0 && errno != EMFILE)
+   FAIL_EXIT1 ("open64 (\"/dev/null\", 0x%x, 0%o): %m", flags, mode);
+
+ increase_nofile ();
+
+ return xopen ("/dev/null", flags, mode);
+}
+
+struct range
+{
+  int lowfd;
+  size_t len;
+};
+
+struct range_list
+{
+  size_t total;
+  size_t used;
+  struct range *ranges;
+};
+
+static void
+range_init (struct range_list *r)
+{
+  r->total = 8;
+  r->used = 0;
+  r->ranges = xmalloc (r->total * sizeof (struct range));
+}
+
+static void
+range_add (struct range_list *r, int lowfd, size_t len)
+{
+  if (r->used == r->total)
+    {
+      r->total *= 2;
+      r->ranges = xrealloc (r->ranges, r->total * sizeof (struct range));
+    }
+  r->ranges[r->used].lowfd = lowfd;
+  r->ranges[r->used].len = len;
+  r->used++;
+}
+
+static void
+range_close (struct range_list *r)
+{
+  for (size_t i = 0; i < r->used; i++)
+    {
+      int minfd = r->ranges[i].lowfd;
+      int maxfd = r->ranges[i].lowfd + r->ranges[i].len;
+      for (int fd = minfd; fd < maxfd; fd++)
+	xclose (fd);
+    }
+  free (r->ranges);
+}
+
+int
+support_open_dev_null_range (int num, int flags, mode_t mode)
+{
+  /* We keep track of the ranges that hit an already opened descriptor, so
+     we close them after we get a working range.  */
+  struct range_list rl;
+  range_init (&rl);
+
+  int lowfd = open_dev_null (flags, mode);
+  int prevfd = lowfd;
+  while (true)
+    {
+      int i = 1;
+      for (; i < num; i++)
+	{
+	  int fd = open_dev_null (flags, mode);
+	  if (fd != lowfd + i)
+	    {
+	      range_add (&rl, lowfd, prevfd - lowfd + 1);
+
+	      prevfd = lowfd = fd;
+	      break;
+	    }
+	  prevfd = fd;
+	}
+      if (i == num)
+	break;
+    }
+
+  range_close (&rl);
+
+  return lowfd;
+}
diff --git a/support/support.h b/support/support.h
index a5978b939a..c219e0d9d1 100644
--- a/support/support.h
+++ b/support/support.h
@@ -197,6 +197,14 @@ struct support_stack support_stack_alloc (size_t size);
 /* Deallocate the STACK.  */
 void support_stack_free (struct support_stack *stack);
 
+
+/* Create a range of NUM opened '/dev/null' file descriptors using FLAGS and
+   MODE.  The function takes care of restarting the open range if a file
+   descriptor is found within the specified range and also increases
+   RLIMIT_NOFILE if required.
+   The returned value is the lowest file descriptor number.  */
+int support_open_dev_null_range (int num, int flags, mode_t mode);
+
 __END_DECLS
 
 #endif /* SUPPORT_H */
diff --git a/support/tst-support-open-dev-null-range.c b/support/tst-support-open-dev-null-range.c
new file mode 100644
index 0000000000..8e29def1ce
--- /dev/null
+++ b/support/tst-support-open-dev-null-range.c
@@ -0,0 +1,155 @@
+/* Tests for support_open_dev_null_range.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <sys/resource.h>
+#include <stdlib.h>
+
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+#include <stdio.h>
+
+static void
+check_path (int fd)
+{
+  char *proc_fd_path = xasprintf ("/proc/self/fd/%d", fd);
+  char file_path[PATH_MAX];
+  ssize_t file_path_length
+    = readlink (proc_fd_path, file_path, sizeof (file_path));
+  free (proc_fd_path);
+  if (file_path_length < 0)
+    FAIL_EXIT1 ("readlink (%s, %p, %zu)", proc_fd_path, file_path,
+		sizeof (file_path));
+  file_path[file_path_length] = '\0';
+  TEST_COMPARE_STRING (file_path, "/dev/null");
+}
+
+static int
+number_of_opened_files (void)
+{
+  DIR *fds = opendir ("/proc/self/fd");
+  if (fds == NULL)
+    FAIL_EXIT1 ("opendir (\"/proc/self/fd\"): %m");
+
+  int r = 0;
+  while (true)
+    {
+      errno = 0;
+      struct dirent64 *e = readdir64 (fds);
+      if (e == NULL)
+        {
+          if (errno != 0)
+            FAIL_EXIT1 ("readdir: %m");
+          break;
+        }
+
+      if (e->d_name[0] == '.')
+        continue;
+
+      char *endptr;
+      long int fd = strtol (e->d_name, &endptr, 10);
+      if (*endptr != '\0' || fd < 0 || fd > INT_MAX)
+        FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s",
+                    e->d_name);
+
+      /* Skip the descriptor which is used to enumerate the
+         descriptors.  */
+      if (fd == dirfd (fds))
+        continue;
+
+      r = r + 1;
+    }
+
+  closedir (fds);
+
+  return r;
+}
+
+static int
+do_test (void)
+{
+  const int nfds1 = 8;
+  int lowfd = support_open_dev_null_range (nfds1, O_RDONLY, 0600);
+  for (int i = 0; i < nfds1; i++)
+    {
+      TEST_VERIFY (fcntl (lowfd + i, F_GETFL) > -1);
+      check_path (lowfd + i);
+    }
+
+  /* create some gaps.  */
+  xclose (lowfd + 1);
+  xclose (lowfd + 5);
+  xclose (lowfd + 6);
+
+  const int nfds2 = 16;
+  int lowfd2 = support_open_dev_null_range (nfds2, O_RDONLY, 0600);
+  for (int i = 0; i < nfds2; i++)
+    {
+      TEST_VERIFY (fcntl (lowfd2 + i, F_GETFL) > -1);
+      check_path (lowfd2 + i);
+    }
+
+  /* Decrease the maximum number of files.  */
+  {
+    struct rlimit rl;
+    if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
+      FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
+    
+    rl.rlim_cur = number_of_opened_files ();
+
+    if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
+      FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
+  }
+
+  const int nfds3 = 16;
+  int lowfd3 = support_open_dev_null_range (nfds3, O_RDONLY, 0600);
+  for (int i = 0; i < nfds3; i++)
+    {
+      TEST_VERIFY (fcntl (lowfd3 + i, F_GETFL) > -1);
+      check_path (lowfd3 + i);
+    }
+
+  /* create a lot of gaps to trigger the range extension.  */
+  xclose (lowfd3 + 1);
+  xclose (lowfd3 + 3);
+  xclose (lowfd3 + 5);
+  xclose (lowfd3 + 7);
+  xclose (lowfd3 + 9);
+  xclose (lowfd3 + 11);
+  xclose (lowfd3 + 13);
+
+  const int nfds4 = 16;
+  int lowfd4 = support_open_dev_null_range (nfds4, O_RDONLY, 0600);
+  for (int i = 0; i < nfds4; i++)
+    {
+      TEST_VERIFY (fcntl (lowfd4 + i, F_GETFL) > -1);
+      check_path (lowfd4 + i);
+    }
+
+  return 0;
+}
+
+#include <support/test-driver.c>

commit 772e33411bc730f832f415f93eb3e7c67e4d5488
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Tue Aug 24 16:15:50 2021 -0300

    Use support_open_dev_null_range io/tst-closefrom, misc/tst-close_range, and posix/tst-spawn5 (BZ #28260)
    
    It ensures a continuous range of file descriptor and avoid hitting
    the RLIMIT_NOFILE.
    
    Checked on x86_64-linux-gnu.
    
    (cherry picked from commit 6b20880b22d1d0fce7e9f506baa6fe2d5c7fcfdc)

diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c
index d4c187073c..395ec0d894 100644
--- a/io/tst-closefrom.c
+++ b/io/tst-closefrom.c
@@ -24,31 +24,22 @@
 #include <support/check.h>
 #include <support/descriptors.h>
 #include <support/xunistd.h>
+#include <support/support.h>
 
 #include <array_length.h>
 
 #define NFDS 100
 
-static int
-open_multiple_temp_files (void)
-{
-  /* Check if the temporary file descriptor has no no gaps.  */
-  int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
-  for (int i = 1; i <= NFDS; i++)
-    TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), lowfd + i);
-  return lowfd;
-}
-
 static int
 closefrom_test (void)
 {
   struct support_descriptors *descrs = support_descriptors_list ();
 
-  int lowfd = open_multiple_temp_files ();
+  int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
 
-  const int maximum_fd = lowfd + NFDS;
+  const int maximum_fd = lowfd + NFDS - 1;
   const int half_fd = lowfd + NFDS / 2;
-  const int gap = maximum_fd / 4;
+  const int gap = lowfd + NFDS / 4;
 
   /* Close half of the descriptors and check result.  */
   closefrom (half_fd);
@@ -58,7 +49,7 @@ closefrom_test (void)
       TEST_COMPARE (fcntl (i, F_GETFL), -1);
       TEST_COMPARE (errno, EBADF);
     }
-  for (int i = 0; i < half_fd; i++)
+  for (int i = lowfd; i < half_fd; i++)
     TEST_VERIFY (fcntl (i, F_GETFL) > -1);
 
   /* Create some gaps, close up to a threshold, and check result.  */
@@ -74,7 +65,7 @@ closefrom_test (void)
       TEST_COMPARE (fcntl (i, F_GETFL), -1);
       TEST_COMPARE (errno, EBADF);
     }
-  for (int i = 0; i < gap; i++)
+  for (int i = lowfd; i < gap; i++)
     TEST_VERIFY (fcntl (i, F_GETFL) > -1);
 
   /* Close the remmaining but the last one.  */
diff --git a/posix/tst-spawn5.c b/posix/tst-spawn5.c
index ac66738004..a95199af6b 100644
--- a/posix/tst-spawn5.c
+++ b/posix/tst-spawn5.c
@@ -47,17 +47,6 @@ static int initial_argv_count;
 
 #define NFDS 100
 
-static int
-open_multiple_temp_files (void)
-{
-  /* Check if the temporary file descriptor has no no gaps.  */
-  int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
-  for (int i = 1; i <= NFDS; i++)
-    TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600),
-		  lowfd + i);
-  return lowfd;
-}
-
 static int
 parse_fd (const char *str)
 {
@@ -185,7 +174,7 @@ spawn_closefrom_test (posix_spawn_file_actions_t *fa, int lowfd, int highfd,
 static void
 do_test_closefrom (void)
 {
-  int lowfd = open_multiple_temp_files ();
+  int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
   const int half_fd = lowfd + NFDS / 2;
 
   /* Close half of the descriptors and check result.  */
diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c
index dccb6189c5..f5069d1b8a 100644
--- a/sysdeps/unix/sysv/linux/tst-close_range.c
+++ b/sysdeps/unix/sysv/linux/tst-close_range.c
@@ -36,23 +36,12 @@
 
 #define NFDS 100
 
-static int
-open_multiple_temp_files (void)
-{
-  /* Check if the temporary file descriptor has no no gaps.  */
-  int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
-  for (int i = 1; i <= NFDS; i++)
-    TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600),
-		  lowfd + i);
-  return lowfd;
-}
-
 static void
 close_range_test_max_upper_limit (void)
 {
   struct support_descriptors *descrs = support_descriptors_list ();
 
-  int lowfd = open_multiple_temp_files ();
+  int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
 
   {
     int r = close_range (lowfd, ~0U, 0);
@@ -68,7 +57,7 @@ close_range_test_max_upper_limit (void)
 static void
 close_range_test_common (int lowfd, unsigned int flags)
 {
-  const int maximum_fd = lowfd + NFDS;
+  const int maximum_fd = lowfd + NFDS - 1;
   const int half_fd = lowfd + NFDS / 2;
   const int gap_1 = maximum_fd - 8;
 
@@ -121,7 +110,7 @@ close_range_test (void)
   struct support_descriptors *descrs = support_descriptors_list ();
 
   /* Check if the temporary file descriptor has no no gaps.  */
-  int lowfd = open_multiple_temp_files ();
+  int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
 
   close_range_test_common (lowfd, 0);
 
@@ -146,7 +135,7 @@ close_range_test_subprocess (void)
   struct support_descriptors *descrs = support_descriptors_list ();
 
   /* Check if the temporary file descriptor has no no gaps.  */
-  int lowfd = open_multiple_temp_files ();
+  int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
 
   struct support_stack stack = support_stack_alloc (4096);
 
@@ -184,7 +173,7 @@ close_range_unshare_test (void)
   struct support_descriptors *descrs1 = support_descriptors_list ();
 
   /* Check if the temporary file descriptor has no no gaps.  */
-  int lowfd = open_multiple_temp_files ();
+  int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
 
   struct support_descriptors *descrs2 = support_descriptors_list ();
 
@@ -200,7 +189,7 @@ close_range_unshare_test (void)
 
   support_stack_free (&stack);
 
-  for (int i = 0; i < NFDS; i++)
+  for (int i = lowfd; i < lowfd + NFDS; i++)
     TEST_VERIFY (fcntl (i, F_GETFL) > -1);
 
   support_descriptors_check (descrs2);
@@ -226,9 +215,9 @@ static void
 close_range_cloexec_test (void)
 {
   /* Check if the temporary file descriptor has no no gaps.  */
-  const int lowfd = open_multiple_temp_files ();
+  int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
 
-  const int maximum_fd = lowfd + NFDS;
+  const int maximum_fd = lowfd + NFDS - 1;
   const int half_fd = lowfd + NFDS / 2;
   const int gap_1 = maximum_fd - 8;
 
@@ -251,13 +240,13 @@ close_range_cloexec_test (void)
   /* Create some gaps, close up to a threshold, and check result.  */
   static int gap_close[] = { 57, 78, 81, 82, 84, 90 };
   for (int i = 0; i < array_length (gap_close); i++)
-    xclose (gap_close[i]);
+    xclose (lowfd + gap_close[i]);
 
   TEST_COMPARE (close_range (half_fd + 1, gap_1, CLOSE_RANGE_CLOEXEC), 0);
   for (int i = half_fd + 1; i < gap_1; i++)
     {
       int flags = fcntl (i, F_GETFD);
-      if (is_in_array (gap_close, array_length (gap_close), i))
+      if (is_in_array (gap_close, array_length (gap_close), i - lowfd))
         TEST_COMPARE (flags, -1);
       else
         {

commit 33adeaa3e2b9143c38884bc5aa65ded222ed274e
Author: Florian Weimer <fweimer@redhat.com>
Date:   Thu Sep 23 09:55:54 2021 +0200

    nptl: Avoid setxid deadlock with blocked signals in thread exit [BZ #28361]
    
    As part of the fix for bug 12889, signals are blocked during
    thread exit, so that application code cannot run on the thread that
    is about to exit.  This would cause problems if the application
    expected signals to be delivered after the signal handler revealed
    the thread to still exist, despite pthread_kill can no longer be used
    to send signals to it.  However, glibc internally uses the SIGSETXID
    signal in a way that is incompatible with signal blocking, due to the
    way the setxid handshake delays thread exit until the setxid operation
    has completed.  With a blocked SIGSETXID, the handshake can never
    complete, causing a deadlock.
    
    As a band-aid, restore the previous handshake protocol by not blocking
    SIGSETXID during thread exit.
    
    The new test sysdeps/pthread/tst-pthread-setuid-loop.c is based on
    a downstream test by Martin Osvald.
    
    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
    Tested-by: Carlos O'Donell <carlos@redhat.com>
    (cherry picked from commit 2849e2f53311b66853cb5159b64cba2bddbfb854)

diff --git a/NEWS b/NEWS
index a0c27ecf55..cccbf11ad9 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,7 @@ The following bugs are resolved with this release:
   [19193] nptl: pthread_kill, pthread_cancel should not fail after exit
   [28036] Incorrect types for pthread_mutexattr_set/getrobust_np
   [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl
+  [28361] nptl: Avoid setxid deadlock with blocked signals in thread exit
 
 
 Version 2.34
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index 33b426fc68..bc213f0bc4 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -488,8 +488,16 @@ start_thread (void *arg)
 
   /* This prevents sending a signal from this thread to itself during
      its final stages.  This must come after the exit call above
-     because atexit handlers must not run with signals blocked.  */
-  __libc_signal_block_all (NULL);
+     because atexit handlers must not run with signals blocked.
+
+     Do not block SIGSETXID.  The setxid handshake below expects the
+     signal to be delivered.  (SIGSETXID cannot run application code,
+     nor does it use pthread_kill.)  Reuse the pd->sigmask space for
+     computing the signal mask, to save stack space.  */
+  __sigfillset (&pd->sigmask);
+  __sigdelset (&pd->sigmask, SIGSETXID);
+  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &pd->sigmask, NULL,
+			 __NSIG_BYTES);
 
   /* Tell __pthread_kill_internal that this thread is about to exit.
      If there is a __pthread_kill_internal in progress, this delays
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index 48dba717a1..d4bd2d4e3e 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -118,6 +118,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
 	 tst-unload \
 	 tst-unwind-thread \
 	 tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \
+	 tst-pthread-setuid-loop \
 	 tst-pthread_cancel-exited \
 	 tst-pthread_cancel-select-loop \
 	 tst-pthread_kill-exited \
diff --git a/sysdeps/pthread/tst-pthread-setuid-loop.c b/sysdeps/pthread/tst-pthread-setuid-loop.c
new file mode 100644
index 0000000000..fda2a49b7f
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread-setuid-loop.c
@@ -0,0 +1,61 @@
+/* Test that setuid, pthread_create, thread exit do not deadlock (bug 28361).
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+#include <support/xthread.h>
+#include <unistd.h>
+
+/* How many threads to launch during each iteration.  */
+enum { threads = 4 };
+
+/* How many iterations to perform.  This value seems to reproduce
+   bug 28361 in a bout one in three runs.  */
+enum { iterations = 5000 };
+
+/* Cache of the real user ID used by setuid_thread.  */
+static uid_t uid;
+
+/* Start routine for the threads.  */
+static void *
+setuid_thread (void *closure)
+{
+  TEST_COMPARE (setuid (uid), 0);
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  /* The setxid machinery is still invoked even if the UID is
+     unchanged.  (The kernel might reset other credentials as part of
+     the system call.)  */
+  uid = getuid ();
+
+  for (int i = 0; i < iterations; ++i)
+    {
+      pthread_t thread_ids[threads];
+      for (int j = 0; j < threads; ++j)
+        thread_ids[j] = xpthread_create (NULL, setuid_thread, NULL);
+      for (int j = 0; j < threads; ++j)
+        xpthread_join (thread_ids[j]);
+    }
+
+  return 0;
+}
+
+#include <support/test-driver.c>

commit 4bf72519987ebc2be4a2058c670379040fae90ea
Author: Florian Weimer <fweimer@redhat.com>
Date:   Fri Oct 1 18:16:41 2021 +0200

    support: Add check for TID zero in support_wait_for_thread_exit
    
    Some kernel versions (observed with kernel 5.14 and earlier) can list
    "0" entries in /proc/self/task.  This happens when a thread exits
    while the task list is being constructed.  Treat this entry as not
    present, like the proposed kernel patch does:
    
    [PATCH] procfs: Do not list TID 0 in /proc/<pid>/task
    <https://lore.kernel.org/all/8735pn5dx7.fsf@oldenburg.str.redhat.com/>
    
    Fixes commit 032d74eaf6179100048a5bf0ce942e97dc8b9a60 ("support: Add
    support_wait_for_thread_exit").
    
    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
    Tested-by: Carlos O'Donell <carlos@redhat.com>
    (cherry picked from commit 176c88f5214d8107d330971cbbfbbba5186a111f)

diff --git a/support/support_wait_for_thread_exit.c b/support/support_wait_for_thread_exit.c
index 658a813810..5e3be421a7 100644
--- a/support/support_wait_for_thread_exit.c
+++ b/support/support_wait_for_thread_exit.c
@@ -43,7 +43,10 @@ support_wait_for_thread_exit (void)
           return;
         }
 
-      if (strcmp (e->d_name, ".") == 0 || strcmp (e->d_name, "..") == 0)
+      /* In some kernels, "0" entries denote a thread that has just
+         exited.  */
+      if (strcmp (e->d_name, ".") == 0 || strcmp (e->d_name, "..") == 0
+          || strcmp (e->d_name, "0") == 0)
         continue;
 
       int task_tid = atoi (e->d_name);

commit 40bade26d5bcbda3d21fb598c5063d9df62de966
Author: Florian Weimer <fweimer@redhat.com>
Date:   Fri Oct 1 18:16:41 2021 +0200

    nptl: pthread_kill must send signals to a specific thread [BZ #28407]
    
    The choice between the kill vs tgkill system calls is not just about
    the TID reuse race, but also about whether the signal is sent to the
    whole process (and any thread in it) or to a specific thread.
    
    This was caught by the openposix test suite:
    
      LTP: openposix test suite - FAIL: SIGUSR1 is member of new thread pendingset.
      <https://gitlab.com/cki-project/kernel-tests/-/issues/764>
    
    Fixes commit 526c3cf11ee9367344b6b15d669e4c3cb461a2be ("nptl: Fix race
    between pthread_kill and thread exit (bug 12889)").
    
    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
    Tested-by: Carlos O'Donell <carlos@redhat.com>
    (cherry picked from commit eae81d70574e923ce3c59078b8df857ae192efa6)

diff --git a/NEWS b/NEWS
index cccbf11ad9..b7994015d9 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ The following bugs are resolved with this release:
   [28036] Incorrect types for pthread_mutexattr_set/getrobust_np
   [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl
   [28361] nptl: Avoid setxid deadlock with blocked signals in thread exit
+  [28407] pthread_kill assumes that kill and tgkill are equivalent
 
 
 Version 2.34
diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c
index a44dc8f2d9..35bf1f973e 100644
--- a/nptl/pthread_kill.c
+++ b/nptl/pthread_kill.c
@@ -40,7 +40,7 @@ __pthread_kill_implementation (pthread_t threadid, int signo, int no_tid)
          below.  POSIX only guarantees delivery of a single signal,
          which may not be the right one.)  */
       pid_t tid = INTERNAL_SYSCALL_CALL (gettid);
-      int ret = INTERNAL_SYSCALL_CALL (kill, tid, signo);
+      int ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), tid, signo);
       return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
     }
 
@@ -59,8 +59,6 @@ __pthread_kill_implementation (pthread_t threadid, int signo, int no_tid)
     ret = no_tid;
   else
     {
-      /* Using tgkill is a safety measure.  pd->exit_lock ensures that
-	 the target thread cannot exit.  */
       ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo);
       ret = INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
     }
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index d4bd2d4e3e..0af9c59b42 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -121,6 +121,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
 	 tst-pthread-setuid-loop \
 	 tst-pthread_cancel-exited \
 	 tst-pthread_cancel-select-loop \
+	 tst-pthread-raise-blocked-self \
 	 tst-pthread_kill-exited \
 	 tst-pthread_kill-exiting \
 	 # tests
diff --git a/sysdeps/pthread/tst-pthread-raise-blocked-self.c b/sysdeps/pthread/tst-pthread-raise-blocked-self.c
new file mode 100644
index 0000000000..128e1a6071
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread-raise-blocked-self.c
@@ -0,0 +1,92 @@
+/* Test that raise sends signal to current thread even if blocked.
+   Copyright (C) 2021 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 <signal.h>
+#include <support/check.h>
+#include <support/xsignal.h>
+#include <support/xthread.h>
+#include <pthread.h>
+#include <unistd.h>
+
+/* Used to create a dummy thread ID distinct from all other thread
+   IDs.  */
+static void *
+noop (void *ignored)
+{
+  return NULL;
+}
+
+static volatile pthread_t signal_thread;
+
+static void
+signal_handler (int signo)
+{
+  signal_thread = pthread_self ();
+}
+
+/* Used to ensure that waiting_thread has launched and can accept
+   signals.  */
+static pthread_barrier_t barrier;
+
+static void *
+waiting_thread (void *ignored)
+{
+  xpthread_barrier_wait (&barrier);
+  pause ();
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  xsignal (SIGUSR1, signal_handler);
+  xpthread_barrier_init (&barrier, NULL, 2);
+
+  /* Distinct thread ID value to */
+  pthread_t dummy = xpthread_create (NULL, noop, NULL);
+  signal_thread = dummy;
+
+  pthread_t helper = xpthread_create (NULL, waiting_thread, NULL);
+
+  /* Make sure that the thread is running.  */
+  xpthread_barrier_wait (&barrier);
+
+  /* Block signals on this thread.  */
+  sigset_t set;
+  sigfillset (&set);
+  xpthread_sigmask (SIG_BLOCK, &set, NULL);
+
+  /* Send the signal to this thread.  It must not be delivered.  */
+  raise (SIGUSR1);
+  TEST_VERIFY (signal_thread == dummy);
+
+  /* Wait a bit to give a chance for signal delivery (increases
+     chances of failure with bug 28407).  */
+  usleep (50 * 1000);
+
+  /* Unblocking should cause synchronous delivery of the signal.  */
+  xpthread_sigmask (SIG_UNBLOCK, &set, NULL);
+  TEST_VERIFY (signal_thread == pthread_self ());
+
+  xpthread_cancel (helper);
+  xpthread_join (helper);
+  xpthread_join (dummy);
+  return 0;
+}
+
+#include <support/test-driver.c>

commit e870aac8974cda746157a5a3c9f452ccd70da29b
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Mon Sep 6 12:22:54 2021 -0300

    misc: Add __get_nprocs_sched
    
    This is an internal function meant to return the number of avaliable
    processor where the process can scheduled, different than the
    __get_nprocs which returns a the system available online CPU.
    
    The Linux implementation currently only calls __get_nprocs(), which
    in tuns calls sched_getaffinity.
    
    Reviewed-by: Florian Weimer <fweimer@redhat.com>
    (cherry picked from commit 11a02b035b464ab6813676adfd19c4a59c36d907)

diff --git a/include/sys/sysinfo.h b/include/sys/sysinfo.h
index 7388356a19..c490561581 100644
--- a/include/sys/sysinfo.h
+++ b/include/sys/sysinfo.h
@@ -9,10 +9,15 @@
 extern int __get_nprocs_conf (void);
 libc_hidden_proto (__get_nprocs_conf)
 
-/* Return number of available processors.  */
+/* Return number of available processors (not all of them will be
+   available to the caller process).  */
 extern int __get_nprocs (void);
 libc_hidden_proto (__get_nprocs)
 
+/* Return the number of available processors which the process can
+   be scheduled.  */
+extern int __get_nprocs_sched (void) attribute_hidden;
+
 /* Return number of physical pages of memory in the system.  */
 extern long int __get_phys_pages (void);
 libc_hidden_proto (__get_phys_pages)
diff --git a/malloc/arena.c b/malloc/arena.c
index 667484630e..f1f0af8648 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -879,7 +879,7 @@ arena_get2 (size_t size, mstate avoid_arena)
             narenas_limit = mp_.arena_max;
           else if (narenas > mp_.arena_test)
             {
-              int n = __get_nprocs ();
+              int n = __get_nprocs_sched ();
 
               if (n >= 1)
                 narenas_limit = NARENAS_FROM_NCORES (n);
diff --git a/misc/getsysstats.c b/misc/getsysstats.c
index 0eedface6d..57d93601e2 100644
--- a/misc/getsysstats.c
+++ b/misc/getsysstats.c
@@ -45,6 +45,12 @@ weak_alias (__get_nprocs, get_nprocs)
 link_warning (get_nprocs, "warning: get_nprocs will always return 1")
 
 
+int
+__get_nprocs_sched (void)
+{
+  return 1;
+}
+
 long int
 __get_phys_pages (void)
 {
diff --git a/sysdeps/mach/getsysstats.c b/sysdeps/mach/getsysstats.c
index 1267f39da2..cc8023f979 100644
--- a/sysdeps/mach/getsysstats.c
+++ b/sysdeps/mach/getsysstats.c
@@ -62,6 +62,12 @@ __get_nprocs (void)
 libc_hidden_def (__get_nprocs)
 weak_alias (__get_nprocs, get_nprocs)
 
+int
+__get_nprocs_sched (void)
+{
+  return __get_nprocs ();
+}
+
 /* Return the number of physical pages on the system. */
 long int
 __get_phys_pages (void)
diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c
index 1391e360b8..120ce1bb75 100644
--- a/sysdeps/unix/sysv/linux/getsysstats.c
+++ b/sysdeps/unix/sysv/linux/getsysstats.c
@@ -88,6 +88,12 @@ __get_nprocs (void)
 libc_hidden_def (__get_nprocs)
 weak_alias (__get_nprocs, get_nprocs)
 
+int
+__get_nprocs_sched (void)
+{
+  return __get_nprocs ();
+}
+
 
 /* On some architectures it is possible to distinguish between configured
    and active cpus.  */

commit cda99af14e82b4bb6abaecd717ebe3b57c0aa534
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Mon Sep 6 12:28:24 2021 -0300

    linux: Simplify get_nprocs
    
    This patch simplifies the memory allocation code and uses the sched
    routines instead of reimplement it.  This still uses a stack
    allocation buffer, so it can be used on malloc initialization code.
    
    Linux currently supports at maximum of 4096 cpus for most architectures:
    
    $ find -iname Kconfig | xargs git grep -A10 -w NR_CPUS | grep -w range
    arch/alpha/Kconfig-     range 2 32
    arch/arc/Kconfig-       range 2 4096
    arch/arm/Kconfig-       range 2 16 if DEBUG_KMAP_LOCAL
    arch/arm/Kconfig-       range 2 32 if !DEBUG_KMAP_LOCAL
    arch/arm64/Kconfig-     range 2 4096
    arch/csky/Kconfig-      range 2 32
    arch/hexagon/Kconfig-   range 2 6 if SMP
    arch/ia64/Kconfig-      range 2 4096
    arch/mips/Kconfig-      range 2 256
    arch/openrisc/Kconfig-  range 2 32
    arch/parisc/Kconfig-    range 2 32
    arch/riscv/Kconfig-     range 2 32
    arch/s390/Kconfig-      range 2 512
    arch/sh/Kconfig-        range 2 32
    arch/sparc/Kconfig-     range 2 32 if SPARC32
    arch/sparc/Kconfig-     range 2 4096 if SPARC64
    arch/um/Kconfig-        range 1 1
    arch/x86/Kconfig-# [NR_CPUS_RANGE_BEGIN ... NR_CPUS_RANGE_END] range.
    arch/x86/Kconfig-       range NR_CPUS_RANGE_BEGIN NR_CPUS_RANGE_END
    arch/xtensa/Kconfig-    range 2 32
    
    With x86 supporting 8192:
    
    arch/x86/Kconfig
     976 config NR_CPUS_RANGE_END
     977         int
     978         depends on X86_64
     979         default 8192 if  SMP && CPUMASK_OFFSTACK
     980         default  512 if  SMP && !CPUMASK_OFFSTACK
     981         default    1 if !SMP
    
    So using a maximum of 32k cpu should cover all cases (and I would
    expect once we start to have many more CPUs that Linux would provide
    a more straightforward way to query for such information).
    
    A test is added to check if sched_getaffinity can successfully return
    with large buffers.
    
    Checked on x86_64-linux-gnu and i686-linux-gnu.
    
    Reviewed-by: Florian Weimer <fweimer@redhat.com>
    (cherry picked from commit 33099d72e41cf8a129b362e9709eb2be9372d844)

diff --git a/posix/Makefile b/posix/Makefile
index 059efb3cd2..09460a28e8 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -107,7 +107,8 @@ tests		:= test-errno tstgetopt testfnm runtests runptests \
 		   tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \
 		   tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \
 		   bug-regex38 tst-regcomp-truncated tst-spawn-chdir \
-		   tst-wordexp-nocmd tst-execveat tst-spawn5
+		   tst-wordexp-nocmd tst-execveat tst-spawn5 \
+		   tst-sched_getaffinity
 
 # Test for the glob symbol version that was replaced in glibc 2.27.
 ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes)
diff --git a/posix/tst-sched_getaffinity.c b/posix/tst-sched_getaffinity.c
new file mode 100644
index 0000000000..db9d517a96
--- /dev/null
+++ b/posix/tst-sched_getaffinity.c
@@ -0,0 +1,48 @@
+/* Tests for sched_getaffinity with large buffers.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <array_length.h>
+#include <sched.h>
+#include <support/check.h>
+
+/* NB: this test may fail on system with more than 32k cpus.  */
+
+static int
+do_test (void)
+{
+  /* The values are larger than the default cpu_set_t.  */
+  const int bufsize[] = { 1<<11, 1<<12, 1<<13, 1<<14, 1<<15, 1<<16, 1<<17 };
+  int cpucount[array_length (bufsize)];
+
+  for (int i = 0; i < array_length (bufsize); i++)
+    {
+      cpu_set_t *cpuset = CPU_ALLOC (bufsize[i]);
+      TEST_VERIFY (cpuset != NULL);
+      size_t size = CPU_ALLOC_SIZE (bufsize[i]);
+      TEST_COMPARE (sched_getaffinity (0, size, cpuset), 0);
+      cpucount[i] = CPU_COUNT_S (size, cpuset);
+      CPU_FREE (cpuset);
+    }
+
+  for (int i = 0; i < array_length (cpucount) - 1; i++)
+    TEST_COMPARE (cpucount[i], cpucount[i + 1]);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c
index 120ce1bb75..61d20e7bab 100644
--- a/sysdeps/unix/sysv/linux/getsysstats.c
+++ b/sysdeps/unix/sysv/linux/getsysstats.c
@@ -29,61 +29,29 @@
 #include <sys/sysinfo.h>
 #include <sysdep.h>
 
-/* Compute the population count of the entire array.  */
-static int
-__get_nprocs_count (const unsigned long int *array, size_t length)
-{
-  int count = 0;
-  for (size_t i = 0; i < length; ++i)
-    if (__builtin_add_overflow (count,  __builtin_popcountl (array[i]),
-				&count))
-      return INT_MAX;
-  return count;
-}
-
-/* __get_nprocs with a large buffer.  */
-static int
-__get_nprocs_large (void)
-{
-  /* This code cannot use scratch_buffer because it is used during
-     malloc initialization.  */
-  size_t pagesize = GLRO (dl_pagesize);
-  unsigned long int *page = __mmap (0, pagesize, PROT_READ | PROT_WRITE,
-				    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
-  if (page == MAP_FAILED)
-    return 2;
-  int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, pagesize, page);
-  int count;
-  if (r > 0)
-    count = __get_nprocs_count (page, pagesize / sizeof (unsigned long int));
-  else if (r == -EINVAL)
-    /* One page is still not enough to store the bits.  A more-or-less
-       arbitrary value.  This assumes t hat such large systems never
-       happen in practice.  */
-    count = GLRO (dl_pagesize) * CHAR_BIT;
-  else
-    count = 2;
-  __munmap (page, GLRO (dl_pagesize));
-  return count;
-}
-
 int
 __get_nprocs (void)
 {
-  /* Fast path for most systems.  The kernel expects a buffer size
-     that is a multiple of 8.  */
-  unsigned long int small_buffer[1024 / CHAR_BIT / sizeof (unsigned long int)];
-  int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0,
-				 sizeof (small_buffer), small_buffer);
+  enum
+    {
+      max_num_cpus = 32768,
+      cpu_bits_size = CPU_ALLOC_SIZE (32768)
+    };
+
+  /* This cannot use malloc because it is used on malloc initialization.  */
+  __cpu_mask cpu_bits[cpu_bits_size / sizeof (__cpu_mask)];
+  int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, cpu_bits_size,
+				 cpu_bits);
   if (r > 0)
-    return __get_nprocs_count (small_buffer, r / sizeof (unsigned long int));
+    return CPU_COUNT_S (cpu_bits_size, (cpu_set_t*) cpu_bits);
   else if (r == -EINVAL)
-    /* The kernel requests a larger buffer to store the data.  */
-    return __get_nprocs_large ();
-  else
-    /* Some other error.  2 is conservative (not a uniprocessor
-       system, so atomics are needed). */
-    return 2;
+    /* The input buffer is still not enough to store the number of cpus.  This
+       is an arbitrary values assuming such systems should be rare and there
+       is no offline cpus.  */
+    return max_num_cpus;
+  /* Some other error.  2 is conservative (not a uniprocessor system, so
+     atomics are needed). */
+  return 2;
 }
 libc_hidden_def (__get_nprocs)
 weak_alias (__get_nprocs, get_nprocs)

commit 822662cf2a4b170ade4c5342f035d68815a03276
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Mon Sep 6 14:19:51 2021 -0300

    linux: Revert the use of sched_getaffinity on get_nproc (BZ #28310)
    
    The use of sched_getaffinity on get_nproc and
    sysconf (_SC_NPROCESSORS_ONLN) done in 903bc7dcc2acafc40 (BZ #27645)
    breaks the top command in common hypervisor configurations and also
    other monitoring tools.
    
    The main issue using sched_getaffinity changed the symbols semantic
    from system-wide scope of online CPUs to per-process one (which can
    be changed with kernel cpusets or book parameters in VM).
    
    This patch reverts mostly of the 903bc7dcc2acafc40, with the
    exceptions:
    
      * No more cached values and atomic updates, since they are inherent
        racy.
    
      * No /proc/cpuinfo fallback, since /proc/stat is already used and
        it would require to revert more arch-specific code.
    
      * The alloca is replace with a static buffer of 1024 bytes.
    
    So the implementation first consult the sysfs, and fallbacks to procfs.
    
    Checked on x86_64-linux-gnu.
    
    Reviewed-by: Florian Weimer <fweimer@redhat.com>
    (cherry picked from commit 342298278eabc75baabcaced110a11a02c3d3580)

diff --git a/NEWS b/NEWS
index b7994015d9..273a85da4d 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,7 @@ The following bugs are resolved with this release:
   [19193] nptl: pthread_kill, pthread_cancel should not fail after exit
   [28036] Incorrect types for pthread_mutexattr_set/getrobust_np
   [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl
+  [28310] Do not use affinity mask for sysconf (_SC_NPROCESSORS_CONF)
   [28361] nptl: Avoid setxid deadlock with blocked signals in thread exit
   [28407] pthread_kill assumes that kill and tgkill are equivalent
 
diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c
index 61d20e7bab..d70ed95869 100644
--- a/sysdeps/unix/sysv/linux/getsysstats.c
+++ b/sysdeps/unix/sysv/linux/getsysstats.c
@@ -18,6 +18,8 @@
    <https://www.gnu.org/licenses/>.  */
 
 #include <array_length.h>
+#include <assert.h>
+#include <ctype.h>
 #include <dirent.h>
 #include <errno.h>
 #include <ldsodefs.h>
@@ -30,7 +32,7 @@
 #include <sysdep.h>
 
 int
-__get_nprocs (void)
+__get_nprocs_sched (void)
 {
   enum
     {
@@ -53,14 +55,141 @@ __get_nprocs (void)
      atomics are needed). */
   return 2;
 }
-libc_hidden_def (__get_nprocs)
-weak_alias (__get_nprocs, get_nprocs)
+
+static char *
+next_line (int fd, char *const buffer, char **cp, char **re,
+           char *const buffer_end)
+{
+  char *res = *cp;
+  char *nl = memchr (*cp, '\n', *re - *cp);
+  if (nl == NULL)
+    {
+      if (*cp != buffer)
+        {
+          if (*re == buffer_end)
+            {
+              memmove (buffer, *cp, *re - *cp);
+              *re = buffer + (*re - *cp);
+              *cp = buffer;
+
+              ssize_t n = __read_nocancel (fd, *re, buffer_end - *re);
+              if (n < 0)
+                return NULL;
+
+              *re += n;
+
+              nl = memchr (*cp, '\n', *re - *cp);
+              while (nl == NULL && *re == buffer_end)
+                {
+                  /* Truncate too long lines.  */
+                  *re = buffer + 3 * (buffer_end - buffer) / 4;
+                  n = __read_nocancel (fd, *re, buffer_end - *re);
+                  if (n < 0)
+                    return NULL;
+
+                  nl = memchr (*re, '\n', n);
+                  **re = '\n';
+                  *re += n;
+                }
+            }
+          else
+            nl = memchr (*cp, '\n', *re - *cp);
+
+          res = *cp;
+        }
+
+      if (nl == NULL)
+        nl = *re - 1;
+    }
+
+  *cp = nl + 1;
+  assert (*cp <= *re);
+
+  return res == *re ? NULL : res;
+}
+
 
 int
-__get_nprocs_sched (void)
+__get_nprocs (void)
 {
-  return __get_nprocs ();
+  enum { buffer_size = 1024 };
+  char buffer[buffer_size];
+  char *buffer_end = buffer + buffer_size;
+  char *cp = buffer_end;
+  char *re = buffer_end;
+
+  const int flags = O_RDONLY | O_CLOEXEC;
+  /* This file contains comma-separated ranges.  */
+  int fd = __open_nocancel ("/sys/devices/system/cpu/online", flags);
+  char *l;
+  int result = 0;
+  if (fd != -1)
+    {
+      l = next_line (fd, buffer, &cp, &re, buffer_end);
+      if (l != NULL)
+	do
+	  {
+	    char *endp;
+	    unsigned long int n = strtoul (l, &endp, 10);
+	    if (l == endp)
+	      {
+		result = 0;
+		break;
+	      }
+
+	    unsigned long int m = n;
+	    if (*endp == '-')
+	      {
+		l = endp + 1;
+		m = strtoul (l, &endp, 10);
+		if (l == endp)
+		  {
+		    result = 0;
+		    break;
+		  }
+	      }
+
+	    result += m - n + 1;
+
+	    l = endp;
+	    if (l < re && *l == ',')
+	      ++l;
+	  }
+	while (l < re && *l != '\n');
+
+      __close_nocancel_nostatus (fd);
+
+      if (result > 0)
+	return result;
+    }
+
+  cp = buffer_end;
+  re = buffer_end;
+
+  /* Default to an SMP system in case we cannot obtain an accurate
+     number.  */
+  result = 2;
+
+  fd = __open_nocancel ("/proc/stat", flags);
+  if (fd != -1)
+    {
+      result = 0;
+
+      while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL)
+	/* The current format of /proc/stat has all the cpu* entries
+	   at the front.  We assume here that stays this way.  */
+	if (strncmp (l, "cpu", 3) != 0)
+	  break;
+	else if (isdigit (l[3]))
+	  ++result;
+
+      __close_nocancel_nostatus (fd);
+    }
+
+  return result;
 }
+libc_hidden_def (__get_nprocs)
+weak_alias (__get_nprocs, get_nprocs)
 
 
 /* On some architectures it is possible to distinguish between configured

commit 80a009119ba2330768120476aaad63767b81d543
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed May 19 16:48:19 2021 +0100

    Suppress -Wcast-qual warnings in bsearch
    
    The first cast to (void *) is redundant but should be (const void *)
    anyway, because that's the type of the lvalue being assigned to.
    
    The second cast is necessary and intentionally not const-correct, so
    tell the compiler not to warn about it.
    
    Reviewed-by: Florian Weimer <fweimer@redhat.com>
    (cherry picked from commit a725ff1de965f4cc4f36a7e8ae795d40ca0350d7)

diff --git a/bits/stdlib-bsearch.h b/bits/stdlib-bsearch.h
index 4132dc6af0..d688ed2e15 100644
--- a/bits/stdlib-bsearch.h
+++ b/bits/stdlib-bsearch.h
@@ -29,14 +29,21 @@ bsearch (const void *__key, const void *__base, size_t __nmemb, size_t __size,
   while (__l < __u)
     {
       __idx = (__l + __u) / 2;
-      __p = (void *) (((const char *) __base) + (__idx * __size));
+      __p = (const void *) (((const char *) __base) + (__idx * __size));
       __comparison = (*__compar) (__key, __p);
       if (__comparison < 0)
 	__u = __idx;
       else if (__comparison > 0)
 	__l = __idx + 1;
       else
+#if __GNUC_PREREQ(4, 6)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
 	return (void *) __p;
+#if __GNUC_PREREQ(4, 6)
+# pragma GCC diagnostic pop
+#endif
     }
 
   return NULL;

commit a996d13b8a2e101bedbb1bdaa7ffcfea3b959bb2
Author: Florian Weimer <fweimer@redhat.com>
Date:   Thu Sep 30 18:44:06 2021 +0200

    Add missing braces to bsearch inline implementation [BZ #28400]
    
    GCC treats the pragma as a statement, so that the else branch only
    consists of the pragma, not the return statement.
    
    Fixes commit a725ff1de965f4cc4f36a7e8ae795d40ca0350d7 ("Suppress
    -Wcast-qual warnings in bsearch").
    
    Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
    (cherry picked from commit 32b96d0dec0294465d2221a8f049703599d9d8e4)

diff --git a/bits/stdlib-bsearch.h b/bits/stdlib-bsearch.h
index d688ed2e15..e2fcea6e17 100644
--- a/bits/stdlib-bsearch.h
+++ b/bits/stdlib-bsearch.h
@@ -36,14 +36,16 @@ bsearch (const void *__key, const void *__base, size_t __nmemb, size_t __size,
       else if (__comparison > 0)
 	__l = __idx + 1;
       else
+	{
 #if __GNUC_PREREQ(4, 6)
 # pragma GCC diagnostic push
 # pragma GCC diagnostic ignored "-Wcast-qual"
 #endif
-	return (void *) __p;
+	  return (void *) __p;
 #if __GNUC_PREREQ(4, 6)
 # pragma GCC diagnostic pop
 #endif
+	}
     }
 
   return NULL;

commit 558168c78ea1eb8efb33959c1da9d6b5a997fd7b
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Wed Oct 6 21:48:35 2021 +0530

    support: Also return fd when it is 0
    
    The fd validity check in open_dev_null checks if fd > 0, which would
    lead to a leaked fd if it is == 0.
    
    Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
    Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
    (cherry picked from commit 27b6edbb090f736b101f569620d8ad0e7217ddf8)

diff --git a/support/support-open-dev-null-range.c b/support/support-open-dev-null-range.c
index 80d9dba504..66a8504105 100644
--- a/support/support-open-dev-null-range.c
+++ b/support/support-open-dev-null-range.c
@@ -40,16 +40,16 @@ increase_nofile (void)
 static int
 open_dev_null (int flags, mode_t mode)
 {
- int fd = open64 ("/dev/null", flags, mode);
- if (fd > 0)
-   return fd;
+  int fd = open64 ("/dev/null", flags, mode);
+  if (fd >= 0)
+    return fd;
 
- if (fd < 0 && errno != EMFILE)
-   FAIL_EXIT1 ("open64 (\"/dev/null\", 0x%x, 0%o): %m", flags, mode);
+  if (fd < 0 && errno != EMFILE)
+    FAIL_EXIT1 ("open64 (\"/dev/null\", 0x%x, 0%o): %m", flags, mode);
 
- increase_nofile ();
+  increase_nofile ();
 
- return xopen ("/dev/null", flags, mode);
+  return xopen ("/dev/null", flags, mode);
 }
 
 struct range

commit cb44a620ef2336449af60694b6696efced161774
Author: Stefan Liebler <stli@linux.ibm.com>
Date:   Tue Oct 5 16:14:10 2021 +0200

    S390: Add PCI_MIO and SIE HWCAPs
    
    Both new HWCAPs were introduced in these kernel commits:
    - 7e8403ecaf884f307b627f3c371475913dd29292
      "s390: add HWCAP_S390_PCI_MIO to ELF hwcaps"
    - 7e82523f2583e9813e4109df3656707162541297
      "s390/hwcaps: make sie capability regular hwcap"
    
    Also note that the kernel commit 511ad531afd4090625def4d9aba1f5227bd44b8e
    "s390/hwcaps: shorten HWCAP defines" has shortened the prefix of the macros
    from "HWCAP_S390_" to "HWCAP_".  For compatibility reasons, we do not
    change the prefix in public glibc header file.
    
    (cherry picked from commit f2e06656d04a9fcb0603802a4f8ce7aa3a1f055e)

diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c
index c174e27b35..155f0bd99e 100644
--- a/sysdeps/s390/dl-procinfo.c
+++ b/sysdeps/s390/dl-procinfo.c
@@ -46,13 +46,13 @@
 #if !defined PROCINFO_DECL && defined SHARED
   ._dl_s390_cap_flags
 #else
-PROCINFO_CLASS const char _dl_s390_cap_flags[21][9]
+PROCINFO_CLASS const char _dl_s390_cap_flags[23][9]
 #endif
 #ifndef PROCINFO_DECL
 = {
      "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh",
      "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt",
-     "vxp2", "nnpa"
+     "vxp2", "nnpa", "pcimio", "sie"
   }
 #endif
 #if !defined SHARED || defined PROCINFO_DECL
diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h
index 2d9c305808..e4e3e334a5 100644
--- a/sysdeps/s390/dl-procinfo.h
+++ b/sysdeps/s390/dl-procinfo.h
@@ -21,7 +21,7 @@
 #define _DL_PROCINFO_H	1
 #include <ldsodefs.h>
 
-#define _DL_HWCAP_COUNT 21
+#define _DL_HWCAP_COUNT 23
 
 #define _DL_PLATFORMS_COUNT	10
 
@@ -63,6 +63,8 @@ enum
   HWCAP_S390_DFLT = 1 << 18,
   HWCAP_S390_VXRS_PDE2 = 1 << 19,
   HWCAP_S390_NNPA = 1 << 20,
+  HWCAP_S390_PCI_MIO = 1 << 21,
+  HWCAP_S390_SIE = 1 << 22,
 };
 
 #define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \
diff --git a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
index e9bd3684db..00e73a3e3b 100644
--- a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
+++ b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
@@ -22,6 +22,11 @@
 
 /*
  * The following must match the kernels asm/elf.h.
+ * Note: The kernel commit 511ad531afd4090625def4d9aba1f5227bd44b8e
+ * "s390/hwcaps: shorten HWCAP defines" has shortened the prefix of the macros
+ * from "HWCAP_S390_" to "HWCAP_".  For compatibility reasons, we do not
+ * change the prefix in public glibc header file.
+ *
  * Note that these are *not* the same as the STORE FACILITY LIST bits.
  */
 #define HWCAP_S390_ESAN3        1
@@ -48,3 +53,5 @@
 #define HWCAP_S390_DFLT         262144
 #define HWCAP_S390_VXRS_PDE2    524288
 #define HWCAP_S390_NNPA         1048576
+#define HWCAP_S390_PCI_MIO      2097152
+#define HWCAP_S390_SIE          4194304

commit 79528414dc1578800cbf1fba2fbdb6335f4f39bf
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Thu Sep 30 10:29:17 2021 -0700

    elf: Replace nsid with args.nsid [BZ #27609]
    
    commit ec935dea6332cb22f9881cd1162bad156173f4b0
    Author: Florian Weimer <fweimer@redhat.com>
    Date:   Fri Apr 24 22:31:15 2020 +0200
    
        elf: Implement __libc_early_init
    
    has
    
    @@ -856,6 +876,11 @@ no more namespaces available for dlmopen()"));
       /* See if an error occurred during loading.  */
       if (__glibc_unlikely (exception.errstring != NULL))
         {
    +      /* Avoid keeping around a dangling reference to the libc.so link
    +   map in case it has been cached in libc_map.  */
    +      if (!args.libc_already_loaded)
    +  GL(dl_ns)[nsid].libc_map = NULL;
    +
    
    do_dlopen calls _dl_open with nsid == __LM_ID_CALLER (-2), which calls
    dl_open_worker with args.nsid = nsid.  dl_open_worker updates args.nsid
    if it is __LM_ID_CALLER.  After dl_open_worker returns, it is wrong to
    use nsid.
    
    Replace nsid with args.nsid after dl_open_worker returns.  This fixes
    BZ #27609.
    
    (cherry picked from commit 1e1ecea62e899acb58c3fdf3b320a0833ddd0dff)

diff --git a/elf/dl-open.c b/elf/dl-open.c
index ec386626f9..41c7250bf6 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -886,7 +886,7 @@ no more namespaces available for dlmopen()"));
       /* Avoid keeping around a dangling reference to the libc.so link
 	 map in case it has been cached in libc_map.  */
       if (!args.libc_already_loaded)
-	GL(dl_ns)[nsid].libc_map = NULL;
+	GL(dl_ns)[args.nsid].libc_map = NULL;
 
       /* Remove the object from memory.  It may be in an inconsistent
 	 state if relocation failed, for example.  */

commit 76843f3b3ecb886b8d300220e6ec378e0fd09a8b
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Wed Oct 6 08:10:13 2021 -0300

    y2038: Use a common definition for stat for sparc32
    
    The sparc32 misses support for support done by 4e8521333bea6.
    
    Checked on sparcv9-linux-gnu.
    
    (cherry picked from commit d2b1254db208b35ff060f00a15f22a1eed5306d2)

diff --git a/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h b/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h
index b481b4f9f8..45db6b6ffb 100644
--- a/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h
+++ b/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h
@@ -28,32 +28,35 @@
 
 struct stat
   {
+#ifdef __USE_TIME_BITS64
+# include <bits/struct_stat_time64_helper.h>
+#else
     __dev_t st_dev;			/* Device.  */
-#if __WORDSIZE == 64 || !defined __USE_FILE_OFFSET64
+# if __WORDSIZE == 64 || !defined __USE_FILE_OFFSET64
     unsigned short int __pad1;
     __ino_t st_ino;			/* File serial number.	*/
-#else
+# else
     __ino64_t st_ino;			/* File serial number.	*/
-#endif
+# endif
     __mode_t st_mode;			/* File mode.  */
     __nlink_t st_nlink;			/* Link count.  */
     __uid_t st_uid;			/* User ID of the file's owner.	*/
     __gid_t st_gid;			/* Group ID of the file's group.*/
     __dev_t st_rdev;			/* Device number, if device.  */
     unsigned short int __pad2;
-#ifndef __USE_FILE_OFFSET64
+# ifndef __USE_FILE_OFFSET64
     __off_t st_size;			/* Size of file, in bytes.  */
-#else
+# else
     __off64_t st_size;			/* Size of file, in bytes.  */
-#endif
+# endif
     __blksize_t st_blksize;		/* Optimal block size for I/O.  */
 
-#ifndef __USE_FILE_OFFSET64
+# ifndef __USE_FILE_OFFSET64
     __blkcnt_t st_blocks;		/* Number 512-byte blocks allocated. */
-#else
+# else
     __blkcnt64_t st_blocks;		/* Number 512-byte blocks allocated. */
-#endif
-#ifdef __USE_XOPEN2K8
+# endif
+# ifdef __USE_XOPEN2K8
     /* Nanosecond resolution timestamps are stored in a format
        equivalent to 'struct timespec'.  This is the type used
        whenever possible but the Unix namespace rules do not allow the
@@ -63,28 +66,32 @@ struct stat
     struct timespec st_atim;		/* Time of last access.  */
     struct timespec st_mtim;		/* Time of last modification.  */
     struct timespec st_ctim;		/* Time of last status change.  */
-# define st_atime st_atim.tv_sec	/* Backward compatibility.  */
-# define st_mtime st_mtim.tv_sec
-# define st_ctime st_ctim.tv_sec
-#else
+#  define st_atime st_atim.tv_sec	/* Backward compatibility.  */
+#  define st_mtime st_mtim.tv_sec
+#  define st_ctime st_ctim.tv_sec
+# else
     __time_t st_atime;			/* Time of last access.  */
     unsigned long int st_atimensec;	/* Nscecs of last access.  */
     __time_t st_mtime;			/* Time of last modification.  */
     unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
     __time_t st_ctime;			/* Time of last status change.  */
     unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
-#endif
+# endif
     unsigned long int __glibc_reserved4;
     unsigned long int __glibc_reserved5;
+#endif /* __USE_TIME_BITS64  */
   };
 
 #ifdef __USE_LARGEFILE64
 struct stat64
   {
+# ifdef __USE_TIME_BITS64
+#  include <bits/struct_stat_time64_helper.h>
+# else
     __dev_t st_dev;			/* Device.  */
-# if __WORDSIZE == 64
+#  if __WORDSIZE == 64
     unsigned short int __pad1;
-# endif
+#  endif
     __ino64_t st_ino;			/* File serial number.	*/
     __mode_t st_mode;			/* File mode.  */
     __nlink_t st_nlink;			/* Link count.  */
@@ -96,7 +103,7 @@ struct stat64
     __blksize_t st_blksize;		/* Optimal block size for I/O.  */
 
     __blkcnt64_t st_blocks;		/* Number 512-byte blocks allocated. */
-# ifdef __USE_XOPEN2K8
+#  ifdef __USE_XOPEN2K8
     /* Nanosecond resolution timestamps are stored in a format
        equivalent to 'struct timespec'.  This is the type used
        whenever possible but the Unix namespace rules do not allow the
@@ -106,19 +113,20 @@ struct stat64
     struct timespec st_atim;		/* Time of last access.  */
     struct timespec st_mtim;		/* Time of last modification.  */
     struct timespec st_ctim;		/* Time of last status change.  */
-#  define st_atime st_atim.tv_sec	/* Backward compatibility.  */
-#  define st_mtime st_mtim.tv_sec
-#  define st_ctime st_ctim.tv_sec
-# else
+#   define st_atime st_atim.tv_sec	/* Backward compatibility.  */
+#   define st_mtime st_mtim.tv_sec
+#   define st_ctime st_ctim.tv_sec
+#  else
     __time_t st_atime;			/* Time of last access.  */
     unsigned long int st_atimensec;	/* Nscecs of last access.  */
     __time_t st_mtime;			/* Time of last modification.  */
     unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
     __time_t st_ctime;			/* Time of last status change.  */
     unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
-# endif
+#  endif
     unsigned long int __glibc_reserved4;
     unsigned long int __glibc_reserved5;
+# endif /* __USE_TIME_BITS64  */
   };
 #endif
 

commit cb9b8b5d7670df1a13544857640efd86a299d0e4
Author: Stafford Horne <shorne@gmail.com>
Date:   Fri Oct 15 06:17:41 2021 +0900

    timex: Use 64-bit fields on 32-bit TIMESIZE=64 systems (BZ #28469)
    
    This was found when testing the OpenRISC port I am working on.  These
    two tests fail with SIGSEGV:
    
      FAIL: misc/tst-ntp_gettime
      FAIL: misc/tst-ntp_gettimex
    
    This was found to be due to the kernel overwriting the stack space
    allocated by the timex structure.  The reason for the overwrite being
    that the kernel timex has 64-bit fields and user space code only
    allocates enough stack space for timex with 32-bit fields.
    
    On 32-bit systems with TIMESIZE=64 __USE_TIME_BITS64 is not defined.
    This causes the timex structure to use 32-bit fields with type
    __syscall_slong_t.
    
    This patch adjusts the ifdef condition to allow 32-bit systems with
    TIMESIZE=64 to use the 64-bit long long timex definition.
    
    Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
    
    (Cherry picked from commit 1d550265a75b412cea4889a50b101395f6a8e025)

diff --git a/sysdeps/unix/sysv/linux/bits/timex.h b/sysdeps/unix/sysv/linux/bits/timex.h
index ee37694e8f..4a5db6deca 100644
--- a/sysdeps/unix/sysv/linux/bits/timex.h
+++ b/sysdeps/unix/sysv/linux/bits/timex.h
@@ -25,7 +25,7 @@
 
 struct timex
 {
-# ifdef __USE_TIME_BITS64
+# if defined __USE_TIME_BITS64 || (__TIMESIZE == 64 && __WORDSIZE == 32)
   unsigned int modes;          /* mode selector */
   int :32;                     /* pad */
   long long offset;            /* time offset (usec) */

commit 024a7640ab9ecea80e527f4e4d7f7a1868e952c5
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date:   Wed Sep 15 15:16:19 2021 +0100

    elf: Avoid deadlock between pthread_create and ctors [BZ #28357]
    
    The fix for bug 19329 caused a regression such that pthread_create can
    deadlock when concurrent ctors from dlopen are waiting for it to finish.
    Use a new GL(dl_load_tls_lock) in pthread_create that is not taken
    around ctors in dlopen.
    
    The new lock is also used in __tls_get_addr instead of GL(dl_load_lock).
    
    The new lock is held in _dl_open_worker and _dl_close_worker around
    most of the logic before/after the init/fini routines.  When init/fini
    routines are running then TLS is in a consistent, usable state.
    In _dl_open_worker the new lock requires catching and reraising dlopen
    failures that happen in the critical section.
    
    The new lock is reinitialized in a fork child, to keep the existing
    behaviour and it is kept recursive in case malloc interposition or TLS
    access from signal handlers can retake it.  It is not obvious if this
    is necessary or helps, but avoids changing the preexisting behaviour.
    
    The new lock may be more appropriate for dl_iterate_phdr too than
    GL(dl_load_write_lock), since TLS state of an incompletely loaded
    module may be accessed.  If the new lock can replace the old one,
    that can be a separate change.
    
    Fixes bug 28357.
    
    Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
    (cherry picked from commit 83b5323261bb72313bffcf37476c1b8f0847c736)

diff --git a/NEWS b/NEWS
index 273a85da4d..c0952d7558 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ The following bugs are resolved with this release:
   [28036] Incorrect types for pthread_mutexattr_set/getrobust_np
   [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl
   [28310] Do not use affinity mask for sysconf (_SC_NPROCESSORS_CONF)
+  [28357] deadlock between pthread_create and ELF constructors
   [28361] nptl: Avoid setxid deadlock with blocked signals in thread exit
   [28407] pthread_kill assumes that kill and tgkill are equivalent
 
diff --git a/elf/dl-close.c b/elf/dl-close.c
index f39001cab9..cd7b9c9fe8 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -549,6 +549,9 @@ _dl_close_worker (struct link_map *map, bool force)
   size_t tls_free_end;
   tls_free_start = tls_free_end = NO_TLS_OFFSET;
 
+  /* Protects global and module specitic TLS state.  */
+  __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
+
   /* We modify the list of loaded objects.  */
   __rtld_lock_lock_recursive (GL(dl_load_write_lock));
 
@@ -784,6 +787,9 @@ _dl_close_worker (struct link_map *map, bool force)
 	GL(dl_tls_static_used) = tls_free_start;
     }
 
+  /* TLS is cleaned up for the unloaded modules.  */
+  __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+
 #ifdef SHARED
   /* Auditing checkpoint: we have deleted all objects.  */
   if (__glibc_unlikely (do_audit))
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 41c7250bf6..bc68e2c376 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -66,6 +66,9 @@ struct dl_open_args
      libc_map value in the namespace in case of a dlopen failure.  */
   bool libc_already_loaded;
 
+  /* Set to true if the end of dl_open_worker_begin was reached.  */
+  bool worker_continue;
+
   /* Original parameters to the program and the current environment.  */
   int argc;
   char **argv;
@@ -482,7 +485,7 @@ call_dl_init (void *closure)
 }
 
 static void
-dl_open_worker (void *a)
+dl_open_worker_begin (void *a)
 {
   struct dl_open_args *args = a;
   const char *file = args->file;
@@ -774,6 +777,36 @@ dl_open_worker (void *a)
       _dl_call_libc_early_init (libc_map, false);
     }
 
+  args->worker_continue = true;
+}
+
+static void
+dl_open_worker (void *a)
+{
+  struct dl_open_args *args = a;
+
+  args->worker_continue = false;
+
+  {
+    /* Protects global and module specific TLS state.  */
+    __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
+
+    struct dl_exception ex;
+    int err = _dl_catch_exception (&ex, dl_open_worker_begin, args);
+
+    __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+
+    if (__glibc_unlikely (ex.errstring != NULL))
+      /* Reraise the error.  */
+      _dl_signal_exception (err, &ex, NULL);
+  }
+
+  if (!args->worker_continue)
+    return;
+
+  int mode = args->mode;
+  struct link_map *new = args->map;
+
   /* Run the initializer functions of new objects.  Temporarily
      disable the exception handler, so that lazy binding failures are
      fatal.  */
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 0155718175..d8c06ba7eb 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -229,6 +229,13 @@ __rtld_lock_define_initialized_recursive (, _dl_load_lock)
    list of loaded objects while an object is added to or removed from
    that list.  */
 __rtld_lock_define_initialized_recursive (, _dl_load_write_lock)
+  /* This lock protects global and module specific TLS related data.
+     E.g. it is held in dlopen and dlclose when GL(dl_tls_generation),
+     GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are
+     accessed and when TLS related relocations are processed for a
+     module.  It was introduced to keep pthread_create accessing TLS
+     state that is being set up.  */
+__rtld_lock_define_initialized_recursive (, _dl_load_tls_lock)
 
 
 #ifdef HAVE_AUX_VECTOR
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 423e380f7c..40263cf586 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -532,7 +532,7 @@ _dl_allocate_tls_init (void *result)
   size_t maxgen = 0;
 
   /* Protects global dynamic TLS related state.  */
-  __rtld_lock_lock_recursive (GL(dl_load_lock));
+  __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
 
   /* Check if the current dtv is big enough.   */
   if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
@@ -606,7 +606,7 @@ _dl_allocate_tls_init (void *result)
       listp = listp->next;
       assert (listp != NULL);
     }
-  __rtld_lock_unlock_recursive (GL(dl_load_lock));
+  __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
 
   /* The DTV version is up-to-date now.  */
   dtv[0].counter = maxgen;
@@ -745,7 +745,7 @@ _dl_update_slotinfo (unsigned long int req_modid)
 
 	 Here the dtv needs to be updated to new_gen generation count.
 
-	 This code may be called during TLS access when GL(dl_load_lock)
+	 This code may be called during TLS access when GL(dl_load_tls_lock)
 	 is not held.  In that case the user code has to synchronize with
 	 dlopen and dlclose calls of relevant modules.  A module m is
 	 relevant if the generation of m <= new_gen and dlclose of m is
@@ -867,11 +867,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
   if (__glibc_unlikely (the_map->l_tls_offset
 			!= FORCED_DYNAMIC_TLS_OFFSET))
     {
-      __rtld_lock_lock_recursive (GL(dl_load_lock));
+      __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
       if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET))
 	{
 	  the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
-	  __rtld_lock_unlock_recursive (GL(dl_load_lock));
+	  __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
 	}
       else if (__glibc_likely (the_map->l_tls_offset
 			       != FORCED_DYNAMIC_TLS_OFFSET))
@@ -883,7 +883,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
 #else
 # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
 #endif
-	  __rtld_lock_unlock_recursive (GL(dl_load_lock));
+	  __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
 
 	  dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
 	  dtv[GET_ADDR_MODULE].pointer.val = p;
@@ -891,7 +891,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
 	  return (char *) p + GET_ADDR_OFFSET;
 	}
       else
-	__rtld_lock_unlock_recursive (GL(dl_load_lock));
+	__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
     }
   struct dtv_pointer result = allocate_and_init (the_map);
   dtv[GET_ADDR_MODULE].pointer = result;
@@ -962,7 +962,7 @@ _dl_tls_get_addr_soft (struct link_map *l)
     return NULL;
 
   dtv_t *dtv = THREAD_DTV ();
-  /* This may be called without holding the GL(dl_load_lock).  Reading
+  /* This may be called without holding the GL(dl_load_tls_lock).  Reading
      arbitrary gen value is fine since this is best effort code.  */
   size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
   if (__glibc_unlikely (dtv[0].counter != gen))
diff --git a/elf/rtld.c b/elf/rtld.c
index d733359eaf..08cf50145a 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -322,6 +322,7 @@ struct rtld_global _rtld_global =
 #ifdef _LIBC_REENTRANT
     ._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
     ._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
+    ._dl_load_tls_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
 #endif
     ._dl_nns = 1,
     ._dl_ns =
diff --git a/posix/fork.c b/posix/fork.c
index c471f7b15f..021691b9b7 100644
--- a/posix/fork.c
+++ b/posix/fork.c
@@ -99,6 +99,9 @@ __libc_fork (void)
       /* Reset the lock the dynamic loader uses to protect its data.  */
       __rtld_lock_initialize (GL(dl_load_lock));
 
+      /* Reset the lock protecting dynamic TLS related data.  */
+      __rtld_lock_initialize (GL(dl_load_tls_lock));
+
       reclaim_stacks ();
 
       /* Run the handlers registered for the child.  */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 9c15259236..1ceb9c3212 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -372,6 +372,13 @@ struct rtld_global
      list of loaded objects while an object is added to or removed
      from that list.  */
   __rtld_lock_define_recursive (EXTERN, _dl_load_write_lock)
+  /* This lock protects global and module specific TLS related data.
+     E.g. it is held in dlopen and dlclose when GL(dl_tls_generation),
+     GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are
+     accessed and when TLS related relocations are processed for a
+     module.  It was introduced to keep pthread_create accessing TLS
+     state that is being set up.  */
+  __rtld_lock_define_recursive (EXTERN, _dl_load_tls_lock)
 
   /* Incremented whenever something may have been added to dl_loaded.  */
   EXTERN unsigned long long _dl_load_adds;
@@ -1261,7 +1268,7 @@ extern int _dl_scope_free (void *) attribute_hidden;
 
 /* Add module to slot information data.  If DO_ADD is false, only the
    required memory is allocated.  Must be called with GL
-   (dl_load_lock) acquired.  If the function has already been called
+   (dl_load_tls_lock) acquired.  If the function has already been called
    for the link map L with !do_add, then this function will not raise
    an exception, otherwise it is possible that it encounters a memory
    allocation failure.  */
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index 0af9c59b42..df8943f486 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -152,15 +152,17 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx6 tst-cancelx8 tst-cancelx9 \
 	 tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3
 
 ifeq ($(build-shared),yes)
-tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1
+tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1 tst-create1
 tests-nolibpthread += tst-fini1
 endif
 
 modules-names += tst-atfork2mod tst-tls4moda tst-tls4modb \
-		 tst-_res1mod1 tst-_res1mod2 tst-fini1mod
+		 tst-_res1mod1 tst-_res1mod2 tst-fini1mod \
+		 tst-create1mod
 test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
 
 tst-atfork2mod.so-no-z-defs = yes
+tst-create1mod.so-no-z-defs = yes
 
 ifeq ($(build-shared),yes)
 # Build all the modules even when not actually running test programs.
@@ -279,4 +281,8 @@ LDFLAGS-tst-join7mod.so = -Wl,-soname,tst-join7mod.so
 
 CFLAGS-tst-unwind-thread.c += -funwind-tables
 
+LDFLAGS-tst-create1 = -Wl,-export-dynamic
+$(objpfx)tst-create1: $(shared-thread-library)
+$(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so
+
 endif
diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c
new file mode 100644
index 0000000000..932586c309
--- /dev/null
+++ b/sysdeps/pthread/tst-create1.c
@@ -0,0 +1,119 @@
+/* Verify that pthread_create does not deadlock when ctors take locks.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <support/xdlfcn.h>
+#include <support/xthread.h>
+
+/*
+Check if ctor and pthread_create deadlocks in
+
+thread 1: dlopen -> ctor -> lock(user_lock)
+thread 2: lock(user_lock) -> pthread_create
+
+or in
+
+thread 1: dlclose -> dtor -> lock(user_lock)
+thread 2: lock(user_lock) -> pthread_create
+*/
+
+static pthread_barrier_t bar_ctor;
+static pthread_barrier_t bar_dtor;
+static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER;
+
+void
+ctor (void)
+{
+  xpthread_barrier_wait (&bar_ctor);
+  dprintf (1, "thread 1: in ctor: started.\n");
+  xpthread_mutex_lock (&user_lock);
+  dprintf (1, "thread 1: in ctor: locked user_lock.\n");
+  xpthread_mutex_unlock (&user_lock);
+  dprintf (1, "thread 1: in ctor: unlocked user_lock.\n");
+  dprintf (1, "thread 1: in ctor: done.\n");
+}
+
+void
+dtor (void)
+{
+  xpthread_barrier_wait (&bar_dtor);
+  dprintf (1, "thread 1: in dtor: started.\n");
+  xpthread_mutex_lock (&user_lock);
+  dprintf (1, "thread 1: in dtor: locked user_lock.\n");
+  xpthread_mutex_unlock (&user_lock);
+  dprintf (1, "thread 1: in dtor: unlocked user_lock.\n");
+  dprintf (1, "thread 1: in dtor: done.\n");
+}
+
+static void *
+thread3 (void *a)
+{
+  dprintf (1, "thread 3: started.\n");
+  dprintf (1, "thread 3: done.\n");
+  return 0;
+}
+
+static void *
+thread2 (void *a)
+{
+  pthread_t t3;
+  dprintf (1, "thread 2: started.\n");
+
+  xpthread_mutex_lock (&user_lock);
+  dprintf (1, "thread 2: locked user_lock.\n");
+  xpthread_barrier_wait (&bar_ctor);
+  t3 = xpthread_create (0, thread3, 0);
+  xpthread_mutex_unlock (&user_lock);
+  dprintf (1, "thread 2: unlocked user_lock.\n");
+  xpthread_join (t3);
+
+  xpthread_mutex_lock (&user_lock);
+  dprintf (1, "thread 2: locked user_lock.\n");
+  xpthread_barrier_wait (&bar_dtor);
+  t3 = xpthread_create (0, thread3, 0);
+  xpthread_mutex_unlock (&user_lock);
+  dprintf (1, "thread 2: unlocked user_lock.\n");
+  xpthread_join (t3);
+
+  dprintf (1, "thread 2: done.\n");
+  return 0;
+}
+
+static void
+thread1 (void)
+{
+  dprintf (1, "thread 1: started.\n");
+  xpthread_barrier_init (&bar_ctor, NULL, 2);
+  xpthread_barrier_init (&bar_dtor, NULL, 2);
+  pthread_t t2 = xpthread_create (0, thread2, 0);
+  void *p = xdlopen ("tst-create1mod.so", RTLD_NOW | RTLD_GLOBAL);
+  dprintf (1, "thread 1: dlopen done.\n");
+  xdlclose (p);
+  dprintf (1, "thread 1: dlclose done.\n");
+  xpthread_join (t2);
+  dprintf (1, "thread 1: done.\n");
+}
+
+static int
+do_test (void)
+{
+  thread1 ();
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/tst-create1mod.c b/sysdeps/pthread/tst-create1mod.c
new file mode 100644
index 0000000000..62c9006961
--- /dev/null
+++ b/sysdeps/pthread/tst-create1mod.c
@@ -0,0 +1,41 @@
+/* Verify that pthread_create does not deadlock when ctors take locks.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+
+/* Require TLS setup for the module.  */
+__thread int tlsvar;
+
+void ctor (void);
+void dtor (void);
+
+static void __attribute__ ((constructor))
+do_init (void)
+{
+  dprintf (1, "constructor started: %d.\n", tlsvar++);
+  ctor ();
+  dprintf (1, "constructor done: %d.\n", tlsvar++);
+}
+
+static void __attribute__ ((destructor))
+do_end (void)
+{
+  dprintf (1, "destructor started: %d.\n", tlsvar++);
+  dtor ();
+  dprintf (1, "destructor done: %d.\n", tlsvar++);
+}

commit 01bffc013cdad1e0c45db7aa57efb2bee61f3338
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Fri Oct 29 14:53:55 2021 +0530

    Handle NULL input to malloc_usable_size [BZ #28506]
    
    Hoist the NULL check for malloc_usable_size into its entry points in
    malloc-debug and malloc and assume non-NULL in all callees.  This fixes
    BZ #28506
    
    Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
    Reviewed-by: Florian Weimer <fweimer@redhat.com>
    Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
    (cherry picked from commit 88e316b06414ee7c944cd6f8b30b07a972b78499)

diff --git a/malloc/malloc-debug.c b/malloc/malloc-debug.c
index 9922ef5f25..3d7e6d44fd 100644
--- a/malloc/malloc-debug.c
+++ b/malloc/malloc-debug.c
@@ -1,5 +1,6 @@
 /* Malloc debug DSO.
    Copyright (C) 2021 Free Software Foundation, Inc.
+   Copyright The GNU Toolchain Authors.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -399,17 +400,17 @@ strong_alias (__debug_calloc, calloc)
 size_t
 malloc_usable_size (void *mem)
 {
+  if (mem == NULL)
+    return 0;
+
   if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
     return mcheck_usable_size (mem);
   if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
     return malloc_check_get_size (mem);
 
-  if (mem != NULL)
-    {
-      mchunkptr p = mem2chunk (mem);
-     if (DUMPED_MAIN_ARENA_CHUNK (p))
-       return chunksize (p) - SIZE_SZ;
-    }
+  mchunkptr p = mem2chunk (mem);
+  if (DUMPED_MAIN_ARENA_CHUNK (p))
+    return chunksize (p) - SIZE_SZ;
 
   return musable (mem);
 }
diff --git a/malloc/malloc.c b/malloc/malloc.c
index e065785af7..7882c70f0a 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1,5 +1,6 @@
 /* Malloc implementation for multiple threads without lock contention.
    Copyright (C) 1996-2021 Free Software Foundation, Inc.
+   Copyright The GNU Toolchain Authors.
    This file is part of the GNU C Library.
    Contributed by Wolfram Gloger <wg@malloc.de>
    and Doug Lea <dl@cs.oswego.edu>, 2001.
@@ -5009,20 +5010,13 @@ __malloc_trim (size_t s)
 static size_t
 musable (void *mem)
 {
-  mchunkptr p;
-  if (mem != 0)
-    {
-      size_t result = 0;
-
-      p = mem2chunk (mem);
+  mchunkptr p = mem2chunk (mem);
 
-      if (chunk_is_mmapped (p))
-	result = chunksize (p) - CHUNK_HDR_SZ;
-      else if (inuse (p))
-	result = memsize (p);
+  if (chunk_is_mmapped (p))
+    return chunksize (p) - CHUNK_HDR_SZ;
+  else if (inuse (p))
+    return memsize (p);
 
-      return result;
-    }
   return 0;
 }
 
@@ -5030,10 +5024,9 @@ musable (void *mem)
 size_t
 __malloc_usable_size (void *m)
 {
-  size_t result;
-
-  result = musable (m);
-  return result;
+  if (m == NULL)
+    return 0;
+  return musable (m);
 }
 #endif
 
diff --git a/malloc/tst-malloc-usable.c b/malloc/tst-malloc-usable.c
index a1074b782a..b0d702be10 100644
--- a/malloc/tst-malloc-usable.c
+++ b/malloc/tst-malloc-usable.c
@@ -2,6 +2,7 @@
    MALLOC_CHECK_ exported to a positive value.
 
    Copyright (C) 2012-2021 Free Software Foundation, Inc.
+   Copyright The GNU Toolchain Authors.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -21,29 +22,24 @@
 #include <malloc.h>
 #include <string.h>
 #include <stdio.h>
+#include <support/support.h>
+#include <support/check.h>
 
 static int
 do_test (void)
 {
   size_t usable_size;
   void *p = malloc (7);
-  if (!p)
-    {
-      printf ("memory allocation failed\n");
-      return 1;
-    }
 
+  TEST_VERIFY_EXIT (p != NULL);
   usable_size = malloc_usable_size (p);
-  if (usable_size != 7)
-    {
-      printf ("malloc_usable_size: expected 7 but got %zu\n", usable_size);
-      return 1;
-    }
-
+  TEST_COMPARE (usable_size, 7);
   memset (p, 0, usable_size);
   free (p);
+
+  TEST_COMPARE (malloc_usable_size (NULL), 0);
+
   return 0;
 }
 
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include "support/test-driver.c"

commit f42373f911a28d34325a5bfc1ed5a962c89da7eb
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Thu Sep 16 08:15:29 2021 -0700

    ld.so: Replace DL_RO_DYN_SECTION with dl_relocate_ld [BZ #28340]
    
    We can't relocate entries in dynamic section if it is readonly:
    
    1. Add a l_ld_readonly field to struct link_map to indicate if dynamic
    section is readonly and set it based on p_flags of PT_DYNAMIC segment.
    2. Replace DL_RO_DYN_SECTION with dl_relocate_ld to decide if dynamic
    section should be relocated.
    3. Remove DL_RO_DYN_TEMP_CNT.
    4. Don't use a static dynamic section to make readonly dynamic section
    in vDSO writable.
    5. Remove the temp argument from elf_get_dynamic_info.
    
    This fixes BZ #28340.
    
    Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
    (cherry picked from commit b413280cfb16834450f66f554bc0d618bb513851)

diff --git a/NEWS b/NEWS
index c0952d7558..cc5641e4da 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,7 @@ The following bugs are resolved with this release:
   [28357] deadlock between pthread_create and ELF constructors
   [28361] nptl: Avoid setxid deadlock with blocked signals in thread exit
   [28407] pthread_kill assumes that kill and tgkill are equivalent
+  [28340] ld.so crashes while loading a DSO with a read-only dynamic section
 
 
 Version 2.34
diff --git a/elf/Makefile b/elf/Makefile
index d05f410592..de854b4d1a 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -224,7 +224,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
 	 tst-tls-ie tst-tls-ie-dlmopen argv0test \
 	 tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \
 	 tst-tls20 tst-tls21 tst-dlmopen-dlerror tst-dlmopen-gethostbyname \
-	 tst-dl-is_dso
+	 tst-dl-is_dso tst-ro-dynamic
 #	 reldep9
 tests-internal += loadtest unload unload2 circleload1 \
 	 neededtest neededtest2 neededtest3 neededtest4 \
@@ -357,7 +357,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \
 		tst-tls20mod-bad tst-tls21mod tst-dlmopen-dlerror-mod \
 		tst-auxvalmod \
-		tst-dlmopen-gethostbyname-mod \
+		tst-dlmopen-gethostbyname-mod tst-ro-dynamic-mod \
 
 # Most modules build with _ISOMAC defined, but those filtered out
 # depend on internal headers.
@@ -1906,3 +1906,10 @@ $(objpfx)tst-getauxval-static.out: $(objpfx)tst-auxvalmod.so
 tst-getauxval-static-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx)
 
 $(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so
+
+$(objpfx)tst-ro-dynamic: $(objpfx)tst-ro-dynamic-mod.so
+$(objpfx)tst-ro-dynamic-mod.so: $(objpfx)tst-ro-dynamic-mod.os \
+  tst-ro-dynamic-mod.map
+	$(LINK.o) -nostdlib -nostartfiles -shared -o $@ \
+		-Wl,--script=tst-ro-dynamic-mod.map \
+		$(objpfx)tst-ro-dynamic-mod.os
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 650e4edc35..4445c28ef3 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1149,6 +1149,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 		 such a segment to avoid a crash later.  */
 	      l->l_ld = (void *) ph->p_vaddr;
 	      l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+	      l->l_ld_readonly = (ph->p_flags & PF_W) == 0;
 	    }
 	  break;
 
@@ -1292,7 +1293,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
   else
     l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
 
-  elf_get_dynamic_info (l, NULL);
+  elf_get_dynamic_info (l);
 
   /* Make sure we are not dlopen'ing an object that has the
      DF_1_NOOPEN flag set, or a PIE object.  */
diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
index d5bd2f31e9..2fb02d7276 100644
--- a/elf/dl-reloc-static-pie.c
+++ b/elf/dl-reloc-static-pie.c
@@ -40,7 +40,17 @@ _dl_relocate_static_pie (void)
 
   /* Read our own dynamic section and fill in the info array.  */
   main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ());
-  elf_get_dynamic_info (main_map, NULL);
+
+  const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
+  size_t phnum = GL(dl_phnum);
+  for (ph = phdr; ph < &phdr[phnum]; ++ph)
+    if (ph->p_type == PT_DYNAMIC)
+      {
+	main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
+	break;
+      }
+
+  elf_get_dynamic_info (main_map);
 
 # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
   ELF_MACHINE_BEFORE_RTLD_RELOC (main_map->l_info);
diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
index d8ec32377d..4aa2058abf 100644
--- a/elf/get-dynamic-info.h
+++ b/elf/get-dynamic-info.h
@@ -28,7 +28,7 @@ static
 auto
 #endif
 inline void __attribute__ ((unused, always_inline))
-elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
+elf_get_dynamic_info (struct link_map *l)
 {
 #if __ELF_NATIVE_CLASS == 32
   typedef Elf32_Word d_tag_utype;
@@ -69,28 +69,15 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
       info[i] = dyn;
     }
 
-#define DL_RO_DYN_TEMP_CNT	8
-
-#ifndef DL_RO_DYN_SECTION
   /* Don't adjust .dynamic unnecessarily.  */
-  if (l->l_addr != 0)
+  if (l->l_addr != 0 && dl_relocate_ld (l))
     {
       ElfW(Addr) l_addr = l->l_addr;
-      int cnt = 0;
 
 # define ADJUST_DYN_INFO(tag) \
       do								      \
 	if (info[tag] != NULL)						      \
-	  {								      \
-	    if (temp)							      \
-	      {								      \
-		temp[cnt].d_tag = info[tag]->d_tag;			      \
-		temp[cnt].d_un.d_ptr = info[tag]->d_un.d_ptr + l_addr;	      \
-		info[tag] = temp + cnt++;				      \
-	      }								      \
-	    else							      \
-	      info[tag]->d_un.d_ptr += l_addr;				      \
-	  }								      \
+         info[tag]->d_un.d_ptr += l_addr;				      \
       while (0)
 
       ADJUST_DYN_INFO (DT_HASH);
@@ -107,9 +94,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
       ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
       ADJUST_DYN_INFO (ADDRIDX (DT_GNU_HASH));
 # undef ADJUST_DYN_INFO
-      assert (cnt <= DL_RO_DYN_TEMP_CNT);
     }
-#endif
   if (info[DT_PLTREL] != NULL)
     {
 #if ELF_MACHINE_NO_RELA
diff --git a/elf/rtld.c b/elf/rtld.c
index 08cf50145a..405166d62b 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -464,6 +464,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
 #ifndef DONT_USE_BOOTSTRAP_MAP
   GL(dl_rtld_map).l_addr = info->l.l_addr;
   GL(dl_rtld_map).l_ld = info->l.l_ld;
+  GL(dl_rtld_map).l_ld_readonly = info->l.l_ld_readonly;
   memcpy (GL(dl_rtld_map).l_info, info->l.l_info,
 	  sizeof GL(dl_rtld_map).l_info);
   GL(dl_rtld_map).l_mach = info->l.l_mach;
@@ -547,7 +548,7 @@ _dl_start (void *arg)
 
   /* Read our own dynamic section and fill in the info array.  */
   bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
-  elf_get_dynamic_info (&bootstrap_map, NULL);
+  elf_get_dynamic_info (&bootstrap_map);
 
 #if NO_TLS_OFFSET != 0
   bootstrap_map.l_tls_offset = NO_TLS_OFFSET;
@@ -1469,6 +1470,7 @@ dl_main (const ElfW(Phdr) *phdr,
 	/* This tells us where to find the dynamic section,
 	   which tells us everything we need to do.  */
 	main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
+	main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
 	break;
       case PT_INTERP:
 	/* This "interpreter segment" was used by the program loader to
@@ -1614,7 +1616,7 @@ dl_main (const ElfW(Phdr) *phdr,
   if (! rtld_is_main)
     {
       /* Extract the contents of the dynamic section for easy access.  */
-      elf_get_dynamic_info (main_map, NULL);
+      elf_get_dynamic_info (main_map);
 
       /* If the main map is libc.so, update the base namespace to
 	 refer to this map.  If libc.so is loaded later, this happens
diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h
index 86c491e49c..f44748bc98 100644
--- a/elf/setup-vdso.h
+++ b/elf/setup-vdso.h
@@ -33,8 +33,6 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
 				       0, LM_ID_BASE);
   if (__glibc_likely (l != NULL))
     {
-      static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro;
-
       l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso)
 		   + GLRO(dl_sysinfo_dso)->e_phoff);
       l->l_phnum = GLRO(dl_sysinfo_dso)->e_phnum;
@@ -45,6 +43,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
 	    {
 	      l->l_ld = (void *) ph->p_vaddr;
 	      l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+	      l->l_ld_readonly = (ph->p_flags & PF_W) == 0;
 	    }
 	  else if (ph->p_type == PT_LOAD)
 	    {
@@ -65,7 +64,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
       l->l_map_end += l->l_addr;
       l->l_text_end += l->l_addr;
       l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr);
-      elf_get_dynamic_info (l, dyn_temp);
+      elf_get_dynamic_info (l);
       _dl_setup_hash (l);
       l->l_relocated = 1;
 
diff --git a/elf/tst-ro-dynamic-mod.c b/elf/tst-ro-dynamic-mod.c
new file mode 100644
index 0000000000..6d99925964
--- /dev/null
+++ b/elf/tst-ro-dynamic-mod.c
@@ -0,0 +1,19 @@
+/* Test case for DSO with readonly dynamic section.
+   Copyright (C) 2021 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/>.  */
+
+int foo = -1;
diff --git a/elf/tst-ro-dynamic-mod.map b/elf/tst-ro-dynamic-mod.map
new file mode 100644
index 0000000000..2fe4a2998c
--- /dev/null
+++ b/elf/tst-ro-dynamic-mod.map
@@ -0,0 +1,16 @@
+SECTIONS
+{
+ . = SIZEOF_HEADERS;
+ .dynamic : { *(.dynamic) } :text :dynamic
+ .rodata : { *(.data*) *(.bss*) } :text
+ /DISCARD/ : {
+  *(.note.gnu.property)
+ }
+ .note : { *(.note.*) } :text :note
+}
+PHDRS
+{
+ text PT_LOAD FLAGS(5) FILEHDR PHDRS;
+ dynamic PT_DYNAMIC FLAGS(4);
+ note PT_NOTE FLAGS(4);
+}
diff --git a/elf/tst-ro-dynamic.c b/elf/tst-ro-dynamic.c
new file mode 100644
index 0000000000..3a18f8789a
--- /dev/null
+++ b/elf/tst-ro-dynamic.c
@@ -0,0 +1,31 @@
+/* Test case for DSO with readonly dynamic section.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+#include <support/test-driver.h>
+
+extern int foo;
+
+static int
+do_test (void)
+{
+  TEST_COMPARE (foo, -1);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/include/link.h b/include/link.h
index 4af16cb596..c46aced9f7 100644
--- a/include/link.h
+++ b/include/link.h
@@ -205,6 +205,7 @@ struct link_map
     unsigned int l_free_initfini:1; /* Nonzero if l_initfini can be
 				       freed, ie. not allocated with
 				       the dummy malloc in ld.so.  */
+    unsigned int l_ld_readonly:1; /* Nonzero if dynamic section is readonly.  */
 
     /* NODELETE status of the map.  Only valid for maps of type
        lt_loaded.  Lazy binding sets l_nodelete_active directly,
@@ -342,6 +343,8 @@ struct link_map
     unsigned long long int l_serial;
   };
 
+#include <dl-relocate-ld.h>
+
 /* Information used by audit modules.  For most link maps, this data
    immediate follows the link map in memory.  For the dynamic linker,
    it is allocated separately.  See link_map_audit_state in
diff --git a/sysdeps/generic/dl-relocate-ld.h b/sysdeps/generic/dl-relocate-ld.h
new file mode 100644
index 0000000000..5fae206db9
--- /dev/null
+++ b/sysdeps/generic/dl-relocate-ld.h
@@ -0,0 +1,32 @@
+/* Check if dynamic section should be relocated.  Generic version.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_RELOCATE_LD_H
+#define _DL_RELOCATE_LD_H
+
+/* Return true if dynamic section in the shared library L should be
+   relocated.  */
+
+static inline bool
+dl_relocate_ld (const struct link_map *l)
+{
+  /* Don't relocate dynamic section if it is readonly  */
+  return !l->l_ld_readonly;
+}
+
+#endif /* _DL_RELOCATE_LD_H */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 1ceb9c3212..ed10953f34 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -75,11 +75,8 @@ __BEGIN_DECLS
   have to be accessed via the D_PTR macro.  The macro is needed since for
   most architectures the entry is already relocated - but for some not
   and we need to relocate at access time.  */
-#ifdef DL_RO_DYN_SECTION
-# define D_PTR(map, i) ((map)->i->d_un.d_ptr + (map)->l_addr)
-#else
-# define D_PTR(map, i) (map)->i->d_un.d_ptr
-#endif
+#define D_PTR(map, i) \
+  ((map)->i->d_un.d_ptr + (dl_relocate_ld (map) ? 0 : (map)->l_addr))
 
 /* Result of the lookup functions and how to retrieve the base address.  */
 typedef struct link_map *lookup_t;
diff --git a/sysdeps/mips/dl-relocate-ld.h b/sysdeps/mips/dl-relocate-ld.h
new file mode 100644
index 0000000000..0c18d9a567
--- /dev/null
+++ b/sysdeps/mips/dl-relocate-ld.h
@@ -0,0 +1,32 @@
+/* Check if dynamic section should be relocated.  MIPS version.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_RELOCATE_LD_H
+#define _DL_RELOCATE_LD_H
+
+/* Return true if dynamic section in the shared library L should be
+   relocated.  */
+
+static inline bool
+dl_relocate_ld (const struct link_map *l)
+{
+  /* Never relocate dynamic section.  */
+  return false;
+}
+
+#endif /* _DL_RELOCATE_LD_H */
diff --git a/sysdeps/mips/ldsodefs.h b/sysdeps/mips/ldsodefs.h
index 4db7c60e38..36fd09a8bd 100644
--- a/sysdeps/mips/ldsodefs.h
+++ b/sysdeps/mips/ldsodefs.h
@@ -75,10 +75,6 @@ struct La_mips_64_retval;
 					  struct La_mips_64_retval *,	    \
 					  const char *);
 
-/* The MIPS ABI specifies that the dynamic section has to be read-only.  */
-
-#define DL_RO_DYN_SECTION 1
-
 #include_next <ldsodefs.h>
 
 /* The 64-bit MIPS ELF ABI uses an unusual reloc format.  Each
diff --git a/sysdeps/riscv/dl-relocate-ld.h b/sysdeps/riscv/dl-relocate-ld.h
new file mode 100644
index 0000000000..10327454b1
--- /dev/null
+++ b/sysdeps/riscv/dl-relocate-ld.h
@@ -0,0 +1,32 @@
+/* Check if dynamic section should be relocated.  RISC-V version.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_RELOCATE_LD_H
+#define _DL_RELOCATE_LD_H
+
+/* Return true if dynamic section in the shared library L should be
+   relocated.  */
+
+static inline bool
+dl_relocate_ld (const struct link_map *l)
+{
+  /* Never relocate dynamic section for ABI compatibility.  */
+  return false;
+}
+
+#endif /* _DL_RELOCATE_LD_H */
diff --git a/sysdeps/riscv/ldsodefs.h b/sysdeps/riscv/ldsodefs.h
index 0c696714a7..8947ffe4b5 100644
--- a/sysdeps/riscv/ldsodefs.h
+++ b/sysdeps/riscv/ldsodefs.h
@@ -38,11 +38,6 @@ struct La_riscv_retval;
 				       struct La_riscv_retval *,	\
 				       const char *);
 
-/* Although the RISC-V ABI does not specify that the dynamic section has
-   to be read-only, it needs to be kept for ABI compatibility.  */
-
-#define DL_RO_DYN_SECTION 1
-
 #include_next <ldsodefs.h>
 
 #endif

commit 5f36e5c70107ecb59281ef57f9f1c0e37ec3076d
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Thu Sep 23 09:06:49 2021 -0700

    ld.so: Initialize bootstrap_map.l_ld_readonly [BZ #28340]
    
    1. Define DL_RO_DYN_SECTION to initalize bootstrap_map.l_ld_readonly
    before calling elf_get_dynamic_info to get dynamic info in bootstrap_map,
    2. Define a single
    
    static inline bool
    dl_relocate_ld (const struct link_map *l)
    {
      /* Don't relocate dynamic section if it is readonly  */
      return !(l->l_ld_readonly || DL_RO_DYN_SECTION);
    }
    
    This updates BZ #28340 fix.
    
    (cherry picked from commit 2ec99d8c42b2ff1a1231e4df462a0910a9b7fdef)

diff --git a/elf/rtld.c b/elf/rtld.c
index 405166d62b..d83ac1bdc4 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -548,6 +548,7 @@ _dl_start (void *arg)
 
   /* Read our own dynamic section and fill in the info array.  */
   bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
+  bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION;
   elf_get_dynamic_info (&bootstrap_map);
 
 #if NO_TLS_OFFSET != 0
diff --git a/sysdeps/generic/dl-relocate-ld.h b/sysdeps/generic/dl-relocate-ld.h
index 5fae206db9..cfb86c2d6a 100644
--- a/sysdeps/generic/dl-relocate-ld.h
+++ b/sysdeps/generic/dl-relocate-ld.h
@@ -19,14 +19,7 @@
 #ifndef _DL_RELOCATE_LD_H
 #define _DL_RELOCATE_LD_H
 
-/* Return true if dynamic section in the shared library L should be
-   relocated.  */
-
-static inline bool
-dl_relocate_ld (const struct link_map *l)
-{
-  /* Don't relocate dynamic section if it is readonly  */
-  return !l->l_ld_readonly;
-}
+/* The dynamic section is writable.  */
+#define DL_RO_DYN_SECTION 0
 
 #endif /* _DL_RELOCATE_LD_H */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index ed10953f34..fcbbf69748 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -69,6 +69,16 @@ __BEGIN_DECLS
    `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'.  */
 #define ELFW(type)	_ElfW (ELF, __ELF_NATIVE_CLASS, type)
 
+/* Return true if dynamic section in the shared library L should be
+   relocated.  */
+
+static inline bool
+dl_relocate_ld (const struct link_map *l)
+{
+  /* Don't relocate dynamic section if it is readonly  */
+  return !(l->l_ld_readonly || DL_RO_DYN_SECTION);
+}
+
 /* All references to the value of l_info[DT_PLTGOT],
   l_info[DT_STRTAB], l_info[DT_SYMTAB], l_info[DT_RELA],
   l_info[DT_REL], l_info[DT_JMPREL], and l_info[VERSYMIDX (DT_VERSYM)]
diff --git a/sysdeps/mips/dl-relocate-ld.h b/sysdeps/mips/dl-relocate-ld.h
index 0c18d9a567..376ad75dd1 100644
--- a/sysdeps/mips/dl-relocate-ld.h
+++ b/sysdeps/mips/dl-relocate-ld.h
@@ -19,14 +19,7 @@
 #ifndef _DL_RELOCATE_LD_H
 #define _DL_RELOCATE_LD_H
 
-/* Return true if dynamic section in the shared library L should be
-   relocated.  */
-
-static inline bool
-dl_relocate_ld (const struct link_map *l)
-{
-  /* Never relocate dynamic section.  */
-  return false;
-}
+/* The dynamic section is readonly.  */
+#define DL_RO_DYN_SECTION 1
 
 #endif /* _DL_RELOCATE_LD_H */
diff --git a/sysdeps/riscv/dl-relocate-ld.h b/sysdeps/riscv/dl-relocate-ld.h
index 10327454b1..2ab2b8ac6c 100644
--- a/sysdeps/riscv/dl-relocate-ld.h
+++ b/sysdeps/riscv/dl-relocate-ld.h
@@ -19,14 +19,7 @@
 #ifndef _DL_RELOCATE_LD_H
 #define _DL_RELOCATE_LD_H
 
-/* Return true if dynamic section in the shared library L should be
-   relocated.  */
-
-static inline bool
-dl_relocate_ld (const struct link_map *l)
-{
-  /* Never relocate dynamic section for ABI compatibility.  */
-  return false;
-}
+/* The dynamic section is readonly for ABI compatibility.  */
+#define DL_RO_DYN_SECTION 1
 
 #endif /* _DL_RELOCATE_LD_H */

commit 6548a9bdba95b3e1fcdbd85445342467e4b0cd4f
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri Sep 24 08:56:42 2021 -0700

    Avoid warning: overriding recipe for .../tst-ro-dynamic-mod.so
    
    Add tst-ro-dynamic-mod to modules-names-nobuild to avoid
    
    ../Makerules:767: warning: ignoring old recipe for target '.../elf/tst-ro-dynamic-mod.so'
    
    This updates BZ #28340 fix.
    
    (cherry picked from commit 15e6d6785ac2935bb963506b47a37b3d1f728952)

diff --git a/elf/Makefile b/elf/Makefile
index de854b4d1a..118d579c42 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -399,8 +399,9 @@ endif
 modules-execstack-yes = tst-execstack-mod
 extra-test-objs += $(addsuffix .os,$(strip $(modules-names)))
 
-# filtmod1.so, tst-big-note-lib.so have special rules.
-modules-names-nobuild := filtmod1 tst-big-note-lib
+# filtmod1.so, tst-big-note-lib.so, tst-ro-dynamic-mod.so have special
+# rules.
+modules-names-nobuild := filtmod1 tst-big-note-lib tst-ro-dynamic-mod
 
 tests += $(tests-static)
 

commit f411207a833d0c49578ebe7062aee3660813ed5f
Author: Nikita Popov <npv1310@gmail.com>
Date:   Tue Nov 2 13:21:42 2021 +0500

    gconv: Do not emit spurious NUL character in ISO-2022-JP-3 (bug 28524)
    
    Bugfix 27256 has introduced another issue:
    In conversion from ISO-2022-JP-3 encoding, it is possible
    to force iconv to emit extra NUL character on internal state reset.
    To do this, it is sufficient to feed iconv with escape sequence
    which switches active character set.
    The simplified check 'data->__statep->__count != ASCII_set'
    introduced by the aforementioned bugfix picks that case and
    behaves as if '\0' character has been queued thus emitting it.
    
    To eliminate this issue, these steps are taken:
    * Restore original condition
    '(data->__statep->__count & ~7) != ASCII_set'.
    It is necessary since bits 0-2 may contain
    number of buffered input characters.
    * Check that queued character is not NUL.
    Similar step is taken for main conversion loop.
    
    Bundled test case follows following logic:
    * Try to convert ISO-2022-JP-3 escape sequence
    switching active character set
    * Reset internal state by providing NULL as input buffer
    * Ensure that nothing has been converted.
    
    Signed-off-by: Nikita Popov <npv1310@gmail.com>
    (cherry picked from commit ff012870b2c02a62598c04daa1e54632e020fd7d)

diff --git a/NEWS b/NEWS
index cc5641e4da..b7a75cc2d4 100644
--- a/NEWS
+++ b/NEWS
@@ -14,10 +14,11 @@ The following bugs are resolved with this release:
   [28036] Incorrect types for pthread_mutexattr_set/getrobust_np
   [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl
   [28310] Do not use affinity mask for sysconf (_SC_NPROCESSORS_CONF)
+  [28340] ld.so crashes while loading a DSO with a read-only dynamic section
   [28357] deadlock between pthread_create and ELF constructors
   [28361] nptl: Avoid setxid deadlock with blocked signals in thread exit
   [28407] pthread_kill assumes that kill and tgkill are equivalent
-  [28340] ld.so crashes while loading a DSO with a read-only dynamic section
+  [28524] Conversion from ISO-2022-JP-3 with iconv may emit spurious NULs
 
 
 Version 2.34
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index c216f959df..d5507a048c 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -1,4 +1,5 @@
 # Copyright (C) 1997-2021 Free Software Foundation, Inc.
+# Copyright (C) The GNU Toolchain Authors.
 # This file is part of the GNU C Library.
 
 # The GNU C Library is free software; you can redistribute it and/or
@@ -74,7 +75,7 @@ ifeq (yes,$(build-shared))
 tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
 	tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
 	bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \
-	bug-iconv13 bug-iconv14
+	bug-iconv13 bug-iconv14 bug-iconv15
 ifeq ($(have-thread-library),yes)
 tests += bug-iconv3
 endif
@@ -327,6 +328,8 @@ $(objpfx)bug-iconv12.out: $(addprefix $(objpfx), $(gconv-modules)) \
 			  $(addprefix $(objpfx),$(modules.so))
 $(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \
 			  $(addprefix $(objpfx),$(modules.so))
+$(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \
+			  $(addprefix $(objpfx),$(modules.so))
 
 $(objpfx)iconv-test.out: run-iconv-test.sh \
 			 $(addprefix $(objpfx), $(gconv-modules)) \
diff --git a/iconvdata/bug-iconv15.c b/iconvdata/bug-iconv15.c
new file mode 100644
index 0000000000..cc04bd0313
--- /dev/null
+++ b/iconvdata/bug-iconv15.c
@@ -0,0 +1,60 @@
+/* Bug 28524: Conversion from ISO-2022-JP-3 with iconv
+   may emit spurious NUL character on state reset.
+   Copyright (C) The GNU Toolchain Authors.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+#include <iconv.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  char in[] = "\x1b(I";
+  char *inbuf = in;
+  size_t inleft = sizeof (in) - 1;
+  char out[1];
+  char *outbuf = out;
+  size_t outleft = sizeof (out);
+  iconv_t cd;
+
+  cd = iconv_open ("UTF8", "ISO-2022-JP-3");
+  TEST_VERIFY_EXIT (cd != (iconv_t) -1);
+
+  /* First call to iconv should alter internal state.
+     Now, JISX0201_Kana_set is selected and
+     state value != ASCII_set.  */
+  TEST_VERIFY (iconv (cd, &inbuf, &inleft, &outbuf, &outleft) != (size_t) -1);
+
+  /* No bytes should have been added to
+     the output buffer at this point.  */
+  TEST_VERIFY (outbuf == out);
+  TEST_VERIFY (outleft == sizeof (out));
+
+  /* Second call shall emit spurious NUL character in unpatched glibc.  */
+  TEST_VERIFY (iconv (cd, NULL, NULL, &outbuf, &outleft) != (size_t) -1);
+
+  /* No characters are expected to be produced.  */
+  TEST_VERIFY (outbuf == out);
+  TEST_VERIFY (outleft == sizeof (out));
+
+  TEST_VERIFY_EXIT (iconv_close (cd) != -1);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c
index c8ba88cdc9..5fc0c0f739 100644
--- a/iconvdata/iso-2022-jp-3.c
+++ b/iconvdata/iso-2022-jp-3.c
@@ -1,5 +1,6 @@
 /* Conversion module for ISO-2022-JP-3.
    Copyright (C) 1998-2021 Free Software Foundation, Inc.
+   Copyright (C) The GNU Toolchain Authors.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998,
    and Bruno Haible <bruno@clisp.org>, 2002.
@@ -81,20 +82,31 @@ enum
    the output state to the initial state.  This has to be done during the
    flushing.  */
 #define EMIT_SHIFT_TO_INIT \
-  if (data->__statep->__count != ASCII_set)			      \
+  if ((data->__statep->__count & ~7) != ASCII_set)			      \
     {									      \
       if (FROM_DIRECTION)						      \
 	{								      \
-	  if (__glibc_likely (outbuf + 4 <= outend))			      \
+	  uint32_t ch = data->__statep->__count >> 6;			      \
+									      \
+	  if (__glibc_unlikely (ch != 0))				      \
 	    {								      \
-	      /* Write out the last character.  */			      \
-	      *((uint32_t *) outbuf) = data->__statep->__count >> 6;	      \
-	      outbuf += sizeof (uint32_t);				      \
-	      data->__statep->__count = ASCII_set;			\
+	      if (__glibc_likely (outbuf + 4 <= outend))		      \
+		{							      \
+		  /* Write out the last character.  */			      \
+		  put32u (outbuf, ch);					      \
+		  outbuf += 4;						      \
+		  data->__statep->__count &= 7;				      \
+		  data->__statep->__count |= ASCII_set;			      \
+		}							      \
+	      else							      \
+		/* We don't have enough room in the output buffer.  */	      \
+		status = __GCONV_FULL_OUTPUT;				      \
 	    }								      \
 	  else								      \
-	    /* We don't have enough room in the output buffer.  */	      \
-	    status = __GCONV_FULL_OUTPUT;				      \
+	    {								      \
+	      data->__statep->__count &= 7;				      \
+	      data->__statep->__count |= ASCII_set;			      \
+	    }								      \
 	}								      \
       else								      \
 	{								      \

commit cf8c6a634c0a04a9f5d198ef05310f85f7338839
Author: Florian Weimer <fweimer@redhat.com>
Date:   Fri Nov 5 17:01:24 2021 +0100

    elf: Earlier missing dynamic segment check in _dl_map_object_from_fd
    
    Separated debuginfo files have PT_DYNAMIC with p_filesz == 0.  We
    need to check for that before the _dl_map_segments call because
    that could attempt to write to mappings that extend beyond the end
    of the file, resulting in SIGBUS.
    
    Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
    (cherry picked from commit ea32ec354c65ddad11b82ca9d057010df13a9cea)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index 4445c28ef3..0976977fbd 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1130,6 +1130,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
     struct loadcmd loadcmds[l->l_phnum];
     size_t nloadcmds = 0;
     bool has_holes = false;
+    bool empty_dynamic = false;
 
     /* The struct is initialized to zero so this is not necessary:
     l->l_ld = 0;
@@ -1142,7 +1143,9 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 	     segments are mapped in.  We record the addresses it says
 	     verbatim, and later correct for the run-time load address.  */
 	case PT_DYNAMIC:
-	  if (ph->p_filesz)
+	  if (ph->p_filesz == 0)
+	    empty_dynamic = true; /* Usually separate debuginfo.  */
+	  else
 	    {
 	      /* Debuginfo only files from "objcopy --only-keep-debug"
 		 contain a PT_DYNAMIC segment with p_filesz == 0.  Skip
@@ -1265,6 +1268,13 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 	goto lose;
       }
 
+    /* This check recognizes most separate debuginfo files.  */
+    if (__glibc_unlikely ((l->l_ld == 0 && type == ET_DYN) || empty_dynamic))
+      {
+	errstring = N_("object file has no dynamic section");
+	goto lose;
+      }
+
     /* Length of the sections to be loaded.  */
     maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart;
 
@@ -1282,15 +1292,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
       }
   }
 
-  if (l->l_ld == 0)
-    {
-      if (__glibc_unlikely (type == ET_DYN))
-	{
-	  errstring = N_("object file has no dynamic section");
-	  goto lose;
-	}
-    }
-  else
+  if (l->l_ld != 0)
     l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
 
   elf_get_dynamic_info (l);

commit a4f3bc23461e3f9f6053e827715984ba0d2e589a
Author: Florian Weimer <fweimer@redhat.com>
Date:   Wed Nov 10 15:21:37 2021 +0100

    s390: Use long branches across object boundaries (jgh instead of jh)
    
    Depending on the layout chosen by the linker, the 16-bit displacement
    of the jh instruction is insufficient to reach the target label.
    
    Analysis of the linker failure was carried out by Nick Clifton.
    
    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
    Reviewed-by: Stefan Liebler <stli@linux.ibm.com>
    (cherry picked from commit 98966749f2b418825ff2ea496a0ee89fe63d2cc8)

diff --git a/sysdeps/s390/memmem-arch13.S b/sysdeps/s390/memmem-arch13.S
index c5c8d8c97e..58df8cdb14 100644
--- a/sysdeps/s390/memmem-arch13.S
+++ b/sysdeps/s390/memmem-arch13.S
@@ -41,7 +41,7 @@ ENTRY(MEMMEM_ARCH13)
 #  error The arch13 variant of memmem needs the z13 variant of memmem!
 # endif
 	clgfi	%r5,9
-	jh	MEMMEM_Z13
+	jgh	MEMMEM_Z13
 
 	aghik	%r0,%r5,-1		/* vll needs highest index.  */
 	bc	4,0(%r14)		/* cc==1: return if needle-len == 0.  */
diff --git a/sysdeps/s390/strstr-arch13.S b/sysdeps/s390/strstr-arch13.S
index c7183e627c..222a6de91a 100644
--- a/sysdeps/s390/strstr-arch13.S
+++ b/sysdeps/s390/strstr-arch13.S
@@ -49,7 +49,7 @@ ENTRY(STRSTR_ARCH13)
 #  error The arch13 variant of strstr needs the z13 variant of strstr!
 # endif
 	clgfi	%r4,9
-	jh	STRSTR_Z13
+	jgh	STRSTR_Z13
 
 	/* In case of a partial match, the vstrs instruction returns the index
 	   of the partial match in a vector-register.  Then we have to

commit bfe68fe3c475fe34bed4e017d6e63196c305c934
Author: Florian Weimer <fweimer@redhat.com>
Date:   Wed Nov 24 08:59:54 2021 +0100

    nptl: Do not set signal mask on second setjmp return [BZ #28607]
    
    __libc_signal_restore_set was in the wrong place: It also ran
    when setjmp returned the second time (after pthread_exit or
    pthread_cancel).  This is observable with blocked pending
    signals during thread exit.
    
    Fixes commit b3cae39dcbfa2432b3f3aa28854d8ac57f0de1b8
    ("nptl: Start new threads with all signals blocked [BZ #25098]").
    
    Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
    (cherry picked from commit e186fc5a31e46f2cbf5ea1a75223b4412907f3d8)

diff --git a/NEWS b/NEWS
index b7a75cc2d4..b352a92704 100644
--- a/NEWS
+++ b/NEWS
@@ -19,6 +19,7 @@ The following bugs are resolved with this release:
   [28361] nptl: Avoid setxid deadlock with blocked signals in thread exit
   [28407] pthread_kill assumes that kill and tgkill are equivalent
   [28524] Conversion from ISO-2022-JP-3 with iconv may emit spurious NULs
+  [28607] Masked signals are delivered on thread exit
 
 
 Version 2.34
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index bc213f0bc4..3db0c9fdf4 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -407,8 +407,6 @@ start_thread (void *arg)
   unwind_buf.priv.data.prev = NULL;
   unwind_buf.priv.data.cleanup = NULL;
 
-  __libc_signal_restore_set (&pd->sigmask);
-
   /* Allow setxid from now onwards.  */
   if (__glibc_unlikely (atomic_exchange_acq (&pd->setxid_futex, 0) == -2))
     futex_wake (&pd->setxid_futex, 1, FUTEX_PRIVATE);
@@ -418,6 +416,8 @@ start_thread (void *arg)
       /* Store the new cleanup handler info.  */
       THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf);
 
+      __libc_signal_restore_set (&pd->sigmask);
+
       LIBC_PROBE (pthread_start, 3, (pthread_t) pd, pd->start_routine, pd->arg);
 
       /* Run the code the user provided.  */
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index df8943f486..c657101696 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -118,6 +118,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
 	 tst-unload \
 	 tst-unwind-thread \
 	 tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \
+	 tst-pthread-exit-signal \
 	 tst-pthread-setuid-loop \
 	 tst-pthread_cancel-exited \
 	 tst-pthread_cancel-select-loop \
diff --git a/sysdeps/pthread/tst-pthread-exit-signal.c b/sysdeps/pthread/tst-pthread-exit-signal.c
new file mode 100644
index 0000000000..b4526fe663
--- /dev/null
+++ b/sysdeps/pthread/tst-pthread-exit-signal.c
@@ -0,0 +1,45 @@
+/* Test that pending signals are not delivered on thread exit (bug 28607).
+   Copyright (C) 2021 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/>.  */
+
+/* Due to bug 28607, pthread_kill (or pthread_cancel) restored the
+   signal mask during during thread exit, triggering the delivery of a
+   blocked pending signal (SIGUSR1 in this test).  */
+
+#include <support/xthread.h>
+#include <support/xsignal.h>
+
+static void *
+threadfunc (void *closure)
+{
+  sigset_t sigmask;
+  sigfillset (&sigmask);
+  xpthread_sigmask (SIG_SETMASK, &sigmask, NULL);
+  xpthread_kill (pthread_self (), SIGUSR1);
+  pthread_exit (NULL);
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  pthread_t thr = xpthread_create (NULL, threadfunc, NULL);
+  xpthread_join (thr);
+  return 0;
+}
+
+#include <support/test-driver.c>
