93dc2d
commit 95e114a0919d844d8fe07839cb6538b7f5ee920e
93dc2d
Author: Florian Weimer <fweimer@redhat.com>
93dc2d
Date:   Thu Dec 9 09:49:32 2021 +0100
93dc2d
93dc2d
    nptl: Add rseq registration
93dc2d
    
93dc2d
    The rseq area is placed directly into struct pthread.  rseq
93dc2d
    registration failure is not treated as an error, so it is possible
93dc2d
    that threads run with inconsistent registration status.
93dc2d
    
93dc2d
    <sys/rseq.h> is not yet installed as a public header.
93dc2d
    
93dc2d
    Co-Authored-By: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
93dc2d
    Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
93dc2d
    Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
93dc2d
93dc2d
diff --git a/nptl/descr.h b/nptl/descr.h
93dc2d
index 57be5b4fef564b36..dabf980e29615db3 100644
93dc2d
--- a/nptl/descr.h
93dc2d
+++ b/nptl/descr.h
93dc2d
@@ -35,6 +35,7 @@
93dc2d
 #include <bits/types/res_state.h>
93dc2d
 #include <kernel-features.h>
93dc2d
 #include <tls-internal-struct.h>
93dc2d
+#include <sys/rseq.h>
93dc2d
 
93dc2d
 #ifndef TCB_ALIGNMENT
93dc2d
 # define TCB_ALIGNMENT 32
93dc2d
@@ -407,6 +408,9 @@ struct pthread
93dc2d
   /* Used on strsignal.  */
93dc2d
   struct tls_internal_t tls_state;
93dc2d
 
93dc2d
+  /* rseq area registered with the kernel.  */
93dc2d
+  struct rseq rseq_area;
93dc2d
+
93dc2d
   /* This member must be last.  */
93dc2d
   char end_padding[];
93dc2d
 
93dc2d
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
93dc2d
index 3db0c9fdf40ae2bf..d2b40924dafad316 100644
93dc2d
--- a/nptl/pthread_create.c
93dc2d
+++ b/nptl/pthread_create.c
93dc2d
@@ -33,6 +33,7 @@
93dc2d
 #include <default-sched.h>
93dc2d
 #include <futex-internal.h>
93dc2d
 #include <tls-setup.h>
93dc2d
+#include <rseq-internal.h>
93dc2d
 #include "libioP.h"
93dc2d
 #include <sys/single_threaded.h>
93dc2d
 #include <version.h>
93dc2d
@@ -367,6 +368,9 @@ start_thread (void *arg)
93dc2d
   /* Initialize pointers to locale data.  */
93dc2d
   __ctype_init ();
93dc2d
 
93dc2d
+  /* Register rseq TLS to the kernel.  */
93dc2d
+  rseq_register_current_thread (pd);
93dc2d
+
93dc2d
 #ifndef __ASSUME_SET_ROBUST_LIST
93dc2d
   if (__nptl_set_robust_list_avail)
93dc2d
 #endif
93dc2d
@@ -572,6 +576,15 @@ out:
93dc2d
      process is really dead since 'clone' got passed the CLONE_CHILD_CLEARTID
93dc2d
      flag.  The 'tid' field in the TCB will be set to zero.
93dc2d
 
93dc2d
+     rseq TLS is still registered at this point.  Rely on implicit
93dc2d
+     unregistration performed by the kernel on thread teardown.  This is not a
93dc2d
+     problem because the rseq TLS lives on the stack, and the stack outlives
93dc2d
+     the thread.  If TCB allocation is ever changed, additional steps may be
93dc2d
+     required, such as performing explicit rseq unregistration before
93dc2d
+     reclaiming the rseq TLS area memory.  It is NOT sufficient to block
93dc2d
+     signals because the kernel may write to the rseq area even without
93dc2d
+     signals.
93dc2d
+
93dc2d
      The exit code is zero since in case all threads exit by calling
93dc2d
      'pthread_exit' the exit status must be 0 (zero).  */
93dc2d
   while (1)
93dc2d
diff --git a/sysdeps/nptl/dl-tls_init_tp.c b/sysdeps/nptl/dl-tls_init_tp.c
93dc2d
index ca494dd3a52c4ebf..fedb876fdb2642d2 100644
93dc2d
--- a/sysdeps/nptl/dl-tls_init_tp.c
93dc2d
+++ b/sysdeps/nptl/dl-tls_init_tp.c
93dc2d
@@ -21,6 +21,7 @@
93dc2d
 #include <list.h>
93dc2d
 #include <pthreadP.h>
93dc2d
 #include <tls.h>
93dc2d
+#include <rseq-internal.h>
93dc2d
 
93dc2d
 #ifndef __ASSUME_SET_ROBUST_LIST
93dc2d
 bool __nptl_set_robust_list_avail;
93dc2d
@@ -57,11 +58,12 @@ __tls_pre_init_tp (void)
93dc2d
 void
93dc2d
 __tls_init_tp (void)
93dc2d
 {
93dc2d
+  struct pthread *pd = THREAD_SELF;
93dc2d
+
93dc2d
   /* Set up thread stack list management.  */
93dc2d
-  list_add (&THREAD_SELF->list, &GL (dl_stack_user));
93dc2d
+  list_add (&pd->list, &GL (dl_stack_user));
93dc2d
 
93dc2d
    /* Early initialization of the TCB.   */
93dc2d
-   struct pthread *pd = THREAD_SELF;
93dc2d
    pd->tid = INTERNAL_SYSCALL_CALL (set_tid_address, &pd->tid);
93dc2d
    THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]);
93dc2d
    THREAD_SETMEM (pd, user_stack, true);
93dc2d
@@ -90,6 +92,8 @@ __tls_init_tp (void)
93dc2d
       }
93dc2d
   }
93dc2d
 
93dc2d
+  rseq_register_current_thread (pd);
93dc2d
+
93dc2d
   /* Set initial thread's stack block from 0 up to __libc_stack_end.
93dc2d
      It will be bigger than it actually is, but for unwind.c/pt-longjmp.c
93dc2d
      purposes this is good enough.  */
93dc2d
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
93dc2d
index 76ad06361c4323d7..f84ccd6bbb3b16ad 100644
93dc2d
--- a/sysdeps/unix/sysv/linux/Makefile
93dc2d
+++ b/sysdeps/unix/sysv/linux/Makefile
93dc2d
@@ -130,7 +130,10 @@ ifeq ($(have-GLIBC_2.27)$(build-shared),yesyes)
93dc2d
 tests += tst-ofdlocks-compat
93dc2d
 endif
93dc2d
 
93dc2d
-tests-internal += tst-sigcontext-get_pc
93dc2d
+tests-internal += \
93dc2d
+  tst-rseq \
93dc2d
+  tst-sigcontext-get_pc \
93dc2d
+  # tests-internal
93dc2d
 
93dc2d
 tests-time64 += \
93dc2d
   tst-adjtimex-time64 \
93dc2d
@@ -356,4 +359,8 @@ endif
93dc2d
 
93dc2d
 ifeq ($(subdir),nptl)
93dc2d
 tests += tst-align-clone tst-getpid1
93dc2d
+
93dc2d
+# tst-rseq-nptl is an internal test because it requires a definition of
93dc2d
+# __NR_rseq from the internal system call list.
93dc2d
+tests-internal += tst-rseq-nptl
93dc2d
 endif
93dc2d
diff --git a/sysdeps/unix/sysv/linux/aarch64/bits/rseq.h b/sysdeps/unix/sysv/linux/aarch64/bits/rseq.h
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..9ba92725c76b9d4f
93dc2d
--- /dev/null
93dc2d
+++ b/sysdeps/unix/sysv/linux/aarch64/bits/rseq.h
93dc2d
@@ -0,0 +1,43 @@
93dc2d
+/* Restartable Sequences Linux aarch64 architecture header.
93dc2d
+   Copyright (C) 2021 Free Software Foundation, Inc.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#ifndef _SYS_RSEQ_H
93dc2d
+# error "Never use <bits/rseq.h> directly; include <sys/rseq.h> instead."
93dc2d
+#endif
93dc2d
+
93dc2d
+/* RSEQ_SIG is a signature required before each abort handler code.
93dc2d
+
93dc2d
+   It is a 32-bit value that maps to actual architecture code compiled
93dc2d
+   into applications and libraries.  It needs to be defined for each
93dc2d
+   architecture.  When choosing this value, it needs to be taken into
93dc2d
+   account that generating invalid instructions may have ill effects on
93dc2d
+   tools like objdump, and may also have impact on the CPU speculative
93dc2d
+   execution efficiency in some cases.
93dc2d
+
93dc2d
+   aarch64 -mbig-endian generates mixed endianness code vs data:
93dc2d
+   little-endian code and big-endian data.  Ensure the RSEQ_SIG signature
93dc2d
+   matches code endianness.  */
93dc2d
+
93dc2d
+#define RSEQ_SIG_CODE  0xd428bc00  /* BRK #0x45E0.  */
93dc2d
+
93dc2d
+#ifdef __AARCH64EB__
93dc2d
+# define RSEQ_SIG_DATA 0x00bc28d4  /* BRK #0x45E0.  */
93dc2d
+#else
93dc2d
+# define RSEQ_SIG_DATA RSEQ_SIG_CODE
93dc2d
+#endif
93dc2d
+
93dc2d
+#define RSEQ_SIG       RSEQ_SIG_DATA
93dc2d
diff --git a/sysdeps/unix/sysv/linux/arm/bits/rseq.h b/sysdeps/unix/sysv/linux/arm/bits/rseq.h
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..0542b26f6a023dec
93dc2d
--- /dev/null
93dc2d
+++ b/sysdeps/unix/sysv/linux/arm/bits/rseq.h
93dc2d
@@ -0,0 +1,83 @@
93dc2d
+/* Restartable Sequences Linux arm architecture header.
93dc2d
+   Copyright (C) 2021 Free Software Foundation, Inc.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#ifndef _SYS_RSEQ_H
93dc2d
+# error "Never use <bits/rseq.h> directly; include <sys/rseq.h> instead."
93dc2d
+#endif
93dc2d
+
93dc2d
+/*
93dc2d
+   RSEQ_SIG is a signature required before each abort handler code.
93dc2d
+
93dc2d
+   It is a 32-bit value that maps to actual architecture code compiled
93dc2d
+   into applications and libraries.  It needs to be defined for each
93dc2d
+   architecture.  When choosing this value, it needs to be taken into
93dc2d
+   account that generating invalid instructions may have ill effects on
93dc2d
+   tools like objdump, and may also have impact on the CPU speculative
93dc2d
+   execution efficiency in some cases.
93dc2d
+
93dc2d
+   - ARM little endian
93dc2d
+
93dc2d
+   RSEQ_SIG uses the udf A32 instruction with an uncommon immediate operand
93dc2d
+   value 0x5de3.  This traps if user-space reaches this instruction by mistake,
93dc2d
+   and the uncommon operand ensures the kernel does not move the instruction
93dc2d
+   pointer to attacker-controlled code on rseq abort.
93dc2d
+
93dc2d
+   The instruction pattern in the A32 instruction set is:
93dc2d
+
93dc2d
+   e7f5def3    udf    #24035    ; 0x5de3
93dc2d
+
93dc2d
+   This translates to the following instruction pattern in the T16 instruction
93dc2d
+   set:
93dc2d
+
93dc2d
+   little endian:
93dc2d
+   def3        udf    #243      ; 0xf3
93dc2d
+   e7f5        b.n    <7f5>
93dc2d
+
93dc2d
+   - ARMv6+ big endian (BE8):
93dc2d
+
93dc2d
+   ARMv6+ -mbig-endian generates mixed endianness code vs data: little-endian
93dc2d
+   code and big-endian data.  The data value of the signature needs to have its
93dc2d
+   byte order reversed to generate the trap instruction:
93dc2d
+
93dc2d
+   Data: 0xf3def5e7
93dc2d
+
93dc2d
+   Translates to this A32 instruction pattern:
93dc2d
+
93dc2d
+   e7f5def3    udf    #24035    ; 0x5de3
93dc2d
+
93dc2d
+   Translates to this T16 instruction pattern:
93dc2d
+
93dc2d
+   def3        udf    #243      ; 0xf3
93dc2d
+   e7f5        b.n    <7f5>
93dc2d
+
93dc2d
+   - Prior to ARMv6 big endian (BE32):
93dc2d
+
93dc2d
+   Prior to ARMv6, -mbig-endian generates big-endian code and data
93dc2d
+   (which match), so the endianness of the data representation of the
93dc2d
+   signature should not be reversed.  However, the choice between BE32
93dc2d
+   and BE8 is done by the linker, so we cannot know whether code and
93dc2d
+   data endianness will be mixed before the linker is invoked.  So rather
93dc2d
+   than try to play tricks with the linker, the rseq signature is simply
93dc2d
+   data (not a trap instruction) prior to ARMv6 on big endian.  This is
93dc2d
+   why the signature is expressed as data (.word) rather than as
93dc2d
+   instruction (.inst) in assembler.  */
93dc2d
+
93dc2d
+#ifdef __ARMEB__
93dc2d
+# define RSEQ_SIG    0xf3def5e7      /* udf    #24035    ; 0x5de3 (ARMv6+) */
93dc2d
+#else
93dc2d
+# define RSEQ_SIG    0xe7f5def3      /* udf    #24035    ; 0x5de3 */
93dc2d
+#endif
93dc2d
diff --git a/sysdeps/unix/sysv/linux/bits/rseq.h b/sysdeps/unix/sysv/linux/bits/rseq.h
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..46cf5d1c743f25eb
93dc2d
--- /dev/null
93dc2d
+++ b/sysdeps/unix/sysv/linux/bits/rseq.h
93dc2d
@@ -0,0 +1,29 @@
93dc2d
+/* Restartable Sequences architecture header.  Stub version.
93dc2d
+   Copyright (C) 2021 Free Software Foundation, Inc.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#ifndef _SYS_RSEQ_H
93dc2d
+# error "Never use <bits/rseq.h> directly; include <sys/rseq.h> instead."
93dc2d
+#endif
93dc2d
+
93dc2d
+/* RSEQ_SIG is a signature required before each abort handler code.
93dc2d
+
93dc2d
+   It is a 32-bit value that maps to actual architecture code compiled
93dc2d
+   into applications and libraries.  It needs to be defined for each
93dc2d
+   architecture.  When choosing this value, it needs to be taken into
93dc2d
+   account that generating invalid instructions may have ill effects on
93dc2d
+   tools like objdump, and may also have impact on the CPU speculative
93dc2d
+   execution efficiency in some cases.  */
93dc2d
diff --git a/sysdeps/unix/sysv/linux/mips/bits/rseq.h b/sysdeps/unix/sysv/linux/mips/bits/rseq.h
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..a9defee568ae04a5
93dc2d
--- /dev/null
93dc2d
+++ b/sysdeps/unix/sysv/linux/mips/bits/rseq.h
93dc2d
@@ -0,0 +1,62 @@
93dc2d
+/* Restartable Sequences Linux mips architecture header.
93dc2d
+   Copyright (C) 2021 Free Software Foundation, Inc.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#ifndef _SYS_RSEQ_H
93dc2d
+# error "Never use <bits/rseq.h> directly; include <sys/rseq.h> instead."
93dc2d
+#endif
93dc2d
+
93dc2d
+/* RSEQ_SIG is a signature required before each abort handler code.
93dc2d
+
93dc2d
+   It is a 32-bit value that maps to actual architecture code compiled
93dc2d
+   into applications and libraries.  It needs to be defined for each
93dc2d
+   architecture.  When choosing this value, it needs to be taken into
93dc2d
+   account that generating invalid instructions may have ill effects on
93dc2d
+   tools like objdump, and may also have impact on the CPU speculative
93dc2d
+   execution efficiency in some cases.
93dc2d
+
93dc2d
+   RSEQ_SIG uses the break instruction.  The instruction pattern is:
93dc2d
+
93dc2d
+   On MIPS:
93dc2d
+        0350000d        break     0x350
93dc2d
+
93dc2d
+   On nanoMIPS:
93dc2d
+        00100350        break     0x350
93dc2d
+
93dc2d
+   On microMIPS:
93dc2d
+        0000d407        break     0x350
93dc2d
+
93dc2d
+   For nanoMIPS32 and microMIPS, the instruction stream is encoded as
93dc2d
+   16-bit halfwords, so the signature halfwords need to be swapped
93dc2d
+   accordingly for little-endian.  */
93dc2d
+
93dc2d
+#if defined (__nanomips__)
93dc2d
+# ifdef __MIPSEL__
93dc2d
+#  define RSEQ_SIG      0x03500010
93dc2d
+# else
93dc2d
+#  define RSEQ_SIG      0x00100350
93dc2d
+# endif
93dc2d
+#elif defined (__mips_micromips)
93dc2d
+# ifdef __MIPSEL__
93dc2d
+#  define RSEQ_SIG      0xd4070000
93dc2d
+# else
93dc2d
+#  define RSEQ_SIG      0x0000d407
93dc2d
+# endif
93dc2d
+#elif defined (__mips__)
93dc2d
+# define RSEQ_SIG       0x0350000d
93dc2d
+#else
93dc2d
+/* Unknown MIPS architecture.  */
93dc2d
+#endif
93dc2d
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/rseq.h b/sysdeps/unix/sysv/linux/powerpc/bits/rseq.h
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..05b3cf7b8fe75b92
93dc2d
--- /dev/null
93dc2d
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/rseq.h
93dc2d
@@ -0,0 +1,37 @@
93dc2d
+/* Restartable Sequences Linux powerpc architecture header.
93dc2d
+   Copyright (C) 2021 Free Software Foundation, Inc.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#ifndef _SYS_RSEQ_H
93dc2d
+# error "Never use <bits/rseq.h> directly; include <sys/rseq.h> instead."
93dc2d
+#endif
93dc2d
+
93dc2d
+/* RSEQ_SIG is a signature required before each abort handler code.
93dc2d
+
93dc2d
+   It is a 32-bit value that maps to actual architecture code compiled
93dc2d
+   into applications and libraries.  It needs to be defined for each
93dc2d
+   architecture.  When choosing this value, it needs to be taken into
93dc2d
+   account that generating invalid instructions may have ill effects on
93dc2d
+   tools like objdump, and may also have impact on the CPU speculative
93dc2d
+   execution efficiency in some cases.
93dc2d
+
93dc2d
+   RSEQ_SIG uses the following trap instruction:
93dc2d
+
93dc2d
+   powerpc-be:    0f e5 00 0b           twui   r5,11
93dc2d
+   powerpc64-le:  0b 00 e5 0f           twui   r5,11
93dc2d
+   powerpc64-be:  0f e5 00 0b           twui   r5,11  */
93dc2d
+
93dc2d
+#define RSEQ_SIG        0x0fe5000b
93dc2d
diff --git a/sysdeps/unix/sysv/linux/rseq-internal.h b/sysdeps/unix/sysv/linux/rseq-internal.h
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..909f5478251d3d13
93dc2d
--- /dev/null
93dc2d
+++ b/sysdeps/unix/sysv/linux/rseq-internal.h
93dc2d
@@ -0,0 +1,45 @@
93dc2d
+/* Restartable Sequences internal API.  Linux implementation.
93dc2d
+   Copyright (C) 2021 Free Software Foundation, Inc.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#ifndef RSEQ_INTERNAL_H
93dc2d
+#define RSEQ_INTERNAL_H
93dc2d
+
93dc2d
+#include <sysdep.h>
93dc2d
+#include <errno.h>
93dc2d
+#include <kernel-features.h>
93dc2d
+#include <stdio.h>
93dc2d
+#include <sys/rseq.h>
93dc2d
+
93dc2d
+#ifdef RSEQ_SIG
93dc2d
+static inline void
93dc2d
+rseq_register_current_thread (struct pthread *self)
93dc2d
+{
93dc2d
+  int ret = INTERNAL_SYSCALL_CALL (rseq,
93dc2d
+                                   &self->rseq_area, sizeof (self->rseq_area),
93dc2d
+                                   0, RSEQ_SIG);
93dc2d
+  if (INTERNAL_SYSCALL_ERROR_P (ret))
93dc2d
+    THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED);
93dc2d
+}
93dc2d
+#else /* RSEQ_SIG */
93dc2d
+static inline void
93dc2d
+rseq_register_current_thread (struct pthread *self)
93dc2d
+{
93dc2d
+  THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED);
93dc2d
+}
93dc2d
+#endif /* RSEQ_SIG */
93dc2d
+
93dc2d
+#endif /* rseq-internal.h */
93dc2d
diff --git a/sysdeps/unix/sysv/linux/s390/bits/rseq.h b/sysdeps/unix/sysv/linux/s390/bits/rseq.h
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..3030e38f403784b3
93dc2d
--- /dev/null
93dc2d
+++ b/sysdeps/unix/sysv/linux/s390/bits/rseq.h
93dc2d
@@ -0,0 +1,37 @@
93dc2d
+/* Restartable Sequences Linux s390 architecture header.
93dc2d
+   Copyright (C) 2021 Free Software Foundation, Inc.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#ifndef _SYS_RSEQ_H
93dc2d
+# error "Never use <bits/rseq.h> directly; include <sys/rseq.h> instead."
93dc2d
+#endif
93dc2d
+
93dc2d
+/* RSEQ_SIG is a signature required before each abort handler code.
93dc2d
+
93dc2d
+   It is a 32-bit value that maps to actual architecture code compiled
93dc2d
+   into applications and libraries.  It needs to be defined for each
93dc2d
+   architecture.  When choosing this value, it needs to be taken into
93dc2d
+   account that generating invalid instructions may have ill effects on
93dc2d
+   tools like objdump, and may also have impact on the CPU speculative
93dc2d
+   execution efficiency in some cases.
93dc2d
+
93dc2d
+   RSEQ_SIG uses the trap4 instruction.  As Linux does not make use of the
93dc2d
+   access-register mode nor the linkage stack this instruction will always
93dc2d
+   cause a special-operation exception (the trap-enabled bit in the DUCT
93dc2d
+   is and will stay 0).  The instruction pattern is
93dc2d
+       b2 ff 0f ff        trap4   4095(%r0)  */
93dc2d
+
93dc2d
+#define RSEQ_SIG        0xB2FF0FFF
93dc2d
diff --git a/sysdeps/unix/sysv/linux/sys/rseq.h b/sysdeps/unix/sysv/linux/sys/rseq.h
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..c8edff50d40e29b6
93dc2d
--- /dev/null
93dc2d
+++ b/sysdeps/unix/sysv/linux/sys/rseq.h
93dc2d
@@ -0,0 +1,174 @@
93dc2d
+/* Restartable Sequences exported symbols.  Linux header.
93dc2d
+   Copyright (C) 2021 Free Software Foundation, Inc.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#ifndef _SYS_RSEQ_H
93dc2d
+#define _SYS_RSEQ_H	1
93dc2d
+
93dc2d
+/* Architecture-specific rseq signature.  */
93dc2d
+#include <bits/rseq.h>
93dc2d
+
93dc2d
+#include <stdint.h>
93dc2d
+#include <sys/cdefs.h>
93dc2d
+#include <bits/endian.h>
93dc2d
+
93dc2d
+#ifdef __has_include
93dc2d
+# if __has_include ("linux/rseq.h")
93dc2d
+#  define __GLIBC_HAVE_KERNEL_RSEQ
93dc2d
+# endif
93dc2d
+#else
93dc2d
+# include <linux/version.h>
93dc2d
+# if LINUX_VERSION_CODE >= KERNEL_VERSION (4, 18, 0)
93dc2d
+#  define __GLIBC_HAVE_KERNEL_RSEQ
93dc2d
+# endif
93dc2d
+#endif
93dc2d
+
93dc2d
+#ifdef __GLIBC_HAVE_KERNEL_RSEQ
93dc2d
+/* We use the structures declarations from the kernel headers.  */
93dc2d
+# include <linux/rseq.h>
93dc2d
+#else /* __GLIBC_HAVE_KERNEL_RSEQ */
93dc2d
+/* We use a copy of the include/uapi/linux/rseq.h kernel header.  */
93dc2d
+
93dc2d
+enum rseq_cpu_id_state
93dc2d
+  {
93dc2d
+    RSEQ_CPU_ID_UNINITIALIZED = -1,
93dc2d
+    RSEQ_CPU_ID_REGISTRATION_FAILED = -2,
93dc2d
+  };
93dc2d
+
93dc2d
+enum rseq_flags
93dc2d
+  {
93dc2d
+    RSEQ_FLAG_UNREGISTER = (1 << 0),
93dc2d
+  };
93dc2d
+
93dc2d
+enum rseq_cs_flags_bit
93dc2d
+  {
93dc2d
+    RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0,
93dc2d
+    RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1,
93dc2d
+    RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2,
93dc2d
+  };
93dc2d
+
93dc2d
+enum rseq_cs_flags
93dc2d
+  {
93dc2d
+    RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT =
93dc2d
+      (1U << RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT),
93dc2d
+    RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL =
93dc2d
+      (1U << RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT),
93dc2d
+    RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE =
93dc2d
+      (1U << RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT),
93dc2d
+  };
93dc2d
+
93dc2d
+/* struct rseq_cs is aligned on 32 bytes to ensure it is always
93dc2d
+   contained within a single cache-line.  It is usually declared as
93dc2d
+   link-time constant data.  */
93dc2d
+struct rseq_cs
93dc2d
+  {
93dc2d
+    /* Version of this structure.  */
93dc2d
+    uint32_t version;
93dc2d
+    /* enum rseq_cs_flags.  */
93dc2d
+    uint32_t flags;
93dc2d
+    uint64_t start_ip;
93dc2d
+    /* Offset from start_ip.  */
93dc2d
+    uint64_t post_commit_offset;
93dc2d
+    uint64_t abort_ip;
93dc2d
+  } __attribute__ ((__aligned__ (32)));
93dc2d
+
93dc2d
+/* struct rseq is aligned on 32 bytes to ensure it is always
93dc2d
+   contained within a single cache-line.
93dc2d
+
93dc2d
+   A single struct rseq per thread is allowed.  */
93dc2d
+struct rseq
93dc2d
+  {
93dc2d
+    /* Restartable sequences cpu_id_start field.  Updated by the
93dc2d
+       kernel.  Read by user-space with single-copy atomicity
93dc2d
+       semantics.  This field should only be read by the thread which
93dc2d
+       registered this data structure.  Aligned on 32-bit.  Always
93dc2d
+       contains a value in the range of possible CPUs, although the
93dc2d
+       value may not be the actual current CPU (e.g. if rseq is not
93dc2d
+       initialized).  This CPU number value should always be compared
93dc2d
+       against the value of the cpu_id field before performing a rseq
93dc2d
+       commit or returning a value read from a data structure indexed
93dc2d
+       using the cpu_id_start value.  */
93dc2d
+    uint32_t cpu_id_start;
93dc2d
+    /* Restartable sequences cpu_id field.  Updated by the kernel.
93dc2d
+       Read by user-space with single-copy atomicity semantics.  This
93dc2d
+       field should only be read by the thread which registered this
93dc2d
+       data structure.  Aligned on 32-bit.  Values
93dc2d
+       RSEQ_CPU_ID_UNINITIALIZED and RSEQ_CPU_ID_REGISTRATION_FAILED
93dc2d
+       have a special semantic: the former means "rseq uninitialized",
93dc2d
+       and latter means "rseq initialization failed".  This value is
93dc2d
+       meant to be read within rseq critical sections and compared
93dc2d
+       with the cpu_id_start value previously read, before performing
93dc2d
+       the commit instruction, or read and compared with the
93dc2d
+       cpu_id_start value before returning a value loaded from a data
93dc2d
+       structure indexed using the cpu_id_start value.  */
93dc2d
+    uint32_t cpu_id;
93dc2d
+    /* Restartable sequences rseq_cs field.
93dc2d
+
93dc2d
+       Contains NULL when no critical section is active for the current
93dc2d
+       thread, or holds a pointer to the currently active struct rseq_cs.
93dc2d
+
93dc2d
+       Updated by user-space, which sets the address of the currently
93dc2d
+       active rseq_cs at the beginning of assembly instruction sequence
93dc2d
+       block, and set to NULL by the kernel when it restarts an assembly
93dc2d
+       instruction sequence block, as well as when the kernel detects that
93dc2d
+       it is preempting or delivering a signal outside of the range
93dc2d
+       targeted by the rseq_cs.  Also needs to be set to NULL by user-space
93dc2d
+       before reclaiming memory that contains the targeted struct rseq_cs.
93dc2d
+
93dc2d
+       Read and set by the kernel.  Set by user-space with single-copy
93dc2d
+       atomicity semantics.  This field should only be updated by the
93dc2d
+       thread which registered this data structure.  Aligned on 64-bit.  */
93dc2d
+    union
93dc2d
+      {
93dc2d
+        uint64_t ptr64;
93dc2d
+# ifdef __LP64__
93dc2d
+        uint64_t ptr;
93dc2d
+# else /* __LP64__ */
93dc2d
+        struct
93dc2d
+          {
93dc2d
+#if __BYTE_ORDER == __BIG_ENDIAN
93dc2d
+            uint32_t padding; /* Initialized to zero.  */
93dc2d
+            uint32_t ptr32;
93dc2d
+#  else /* LITTLE */
93dc2d
+            uint32_t ptr32;
93dc2d
+            uint32_t padding; /* Initialized to zero.  */
93dc2d
+#  endif /* ENDIAN */
93dc2d
+          } ptr;
93dc2d
+# endif /* __LP64__ */
93dc2d
+      } rseq_cs;
93dc2d
+
93dc2d
+    /* Restartable sequences flags field.
93dc2d
+
93dc2d
+       This field should only be updated by the thread which
93dc2d
+       registered this data structure.  Read by the kernel.
93dc2d
+       Mainly used for single-stepping through rseq critical sections
93dc2d
+       with debuggers.
93dc2d
+
93dc2d
+       - RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT
93dc2d
+           Inhibit instruction sequence block restart on preemption
93dc2d
+           for this thread.
93dc2d
+       - RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL
93dc2d
+           Inhibit instruction sequence block restart on signal
93dc2d
+           delivery for this thread.
93dc2d
+       - RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE
93dc2d
+           Inhibit instruction sequence block restart on migration for
93dc2d
+           this thread.  */
93dc2d
+    uint32_t flags;
93dc2d
+  } __attribute__ ((__aligned__ (32)));
93dc2d
+
93dc2d
+#endif /* __GLIBC_HAVE_KERNEL_RSEQ */
93dc2d
+
93dc2d
+#endif /* sys/rseq.h */
93dc2d
diff --git a/sysdeps/unix/sysv/linux/tst-rseq-nptl.c b/sysdeps/unix/sysv/linux/tst-rseq-nptl.c
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..d31d94445caa9ee3
93dc2d
--- /dev/null
93dc2d
+++ b/sysdeps/unix/sysv/linux/tst-rseq-nptl.c
93dc2d
@@ -0,0 +1,260 @@
93dc2d
+/* Restartable Sequences NPTL test.
93dc2d
+   Copyright (C) 2021 Free Software Foundation, Inc.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+/* These tests validate that rseq is registered from various execution
93dc2d
+   contexts (main thread, destructor, other threads, other threads created
93dc2d
+   from destructor, forked process (without exec), pthread_atfork handlers,
93dc2d
+   pthread setspecific destructors, signal handlers, atexit handlers).
93dc2d
+
93dc2d
+   See the Linux kernel selftests for extensive rseq stress-tests.  */
93dc2d
+
93dc2d
+#include <stdio.h>
93dc2d
+#include <support/check.h>
93dc2d
+#include <support/xthread.h>
93dc2d
+#include <sys/rseq.h>
93dc2d
+#include <unistd.h>
93dc2d
+
93dc2d
+#ifdef RSEQ_SIG
93dc2d
+# include <array_length.h>
93dc2d
+# include <errno.h>
93dc2d
+# include <error.h>
93dc2d
+# include <pthread.h>
93dc2d
+# include <signal.h>
93dc2d
+# include <stdlib.h>
93dc2d
+# include <string.h>
93dc2d
+# include <support/namespace.h>
93dc2d
+# include <support/xsignal.h>
93dc2d
+# include <syscall.h>
93dc2d
+# include <sys/types.h>
93dc2d
+# include <sys/wait.h>
93dc2d
+# include "tst-rseq.h"
93dc2d
+
93dc2d
+static pthread_key_t rseq_test_key;
93dc2d
+
93dc2d
+static void
93dc2d
+atfork_prepare (void)
93dc2d
+{
93dc2d
+  if (!rseq_thread_registered ())
93dc2d
+    {
93dc2d
+      printf ("error: rseq not registered in pthread atfork prepare\n");
93dc2d
+      support_record_failure ();
93dc2d
+    }
93dc2d
+}
93dc2d
+
93dc2d
+static void
93dc2d
+atfork_parent (void)
93dc2d
+{
93dc2d
+  if (!rseq_thread_registered ())
93dc2d
+    {
93dc2d
+      printf ("error: rseq not registered in pthread atfork parent\n");
93dc2d
+      support_record_failure ();
93dc2d
+    }
93dc2d
+}
93dc2d
+
93dc2d
+static void
93dc2d
+atfork_child (void)
93dc2d
+{
93dc2d
+  if (!rseq_thread_registered ())
93dc2d
+    {
93dc2d
+      printf ("error: rseq not registered in pthread atfork child\n");
93dc2d
+      support_record_failure ();
93dc2d
+    }
93dc2d
+}
93dc2d
+
93dc2d
+static void
93dc2d
+rseq_key_destructor (void *arg)
93dc2d
+{
93dc2d
+  /* Cannot use deferred failure reporting after main returns.  */
93dc2d
+  if (!rseq_thread_registered ())
93dc2d
+    FAIL_EXIT1 ("rseq not registered in pthread key destructor");
93dc2d
+}
93dc2d
+
93dc2d
+static void
93dc2d
+atexit_handler (void)
93dc2d
+{
93dc2d
+  /* Cannot use deferred failure reporting after main returns.  */
93dc2d
+  if (!rseq_thread_registered ())
93dc2d
+    FAIL_EXIT1 ("rseq not registered in atexit handler");
93dc2d
+}
93dc2d
+
93dc2d
+/* Used to avoid -Werror=stringop-overread warning with
93dc2d
+   pthread_setspecific and GCC 11.  */
93dc2d
+static char one = 1;
93dc2d
+
93dc2d
+static void
93dc2d
+do_rseq_main_test (void)
93dc2d
+{
93dc2d
+  TEST_COMPARE (atexit (atexit_handler), 0);
93dc2d
+  rseq_test_key = xpthread_key_create (rseq_key_destructor);
93dc2d
+  TEST_COMPARE (pthread_atfork (atfork_prepare, atfork_parent, atfork_child), 0);
93dc2d
+  xraise (SIGUSR1);
93dc2d
+  TEST_COMPARE (pthread_setspecific (rseq_test_key, &one), 0);
93dc2d
+  TEST_VERIFY_EXIT (rseq_thread_registered ());
93dc2d
+}
93dc2d
+
93dc2d
+static void
93dc2d
+cancel_routine (void *arg)
93dc2d
+{
93dc2d
+  if (!rseq_thread_registered ())
93dc2d
+    {
93dc2d
+      printf ("error: rseq not registered in cancel routine\n");
93dc2d
+      support_record_failure ();
93dc2d
+    }
93dc2d
+}
93dc2d
+
93dc2d
+static pthread_barrier_t cancel_thread_barrier;
93dc2d
+static pthread_cond_t cancel_thread_cond = PTHREAD_COND_INITIALIZER;
93dc2d
+static pthread_mutex_t cancel_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
93dc2d
+
93dc2d
+static void
93dc2d
+test_cancel_thread (void)
93dc2d
+{
93dc2d
+  pthread_cleanup_push (cancel_routine, NULL);
93dc2d
+  (void) xpthread_barrier_wait (&cancel_thread_barrier);
93dc2d
+  /* Wait forever until cancellation.  */
93dc2d
+  xpthread_cond_wait (&cancel_thread_cond, &cancel_thread_mutex);
93dc2d
+  pthread_cleanup_pop (0);
93dc2d
+}
93dc2d
+
93dc2d
+static void *
93dc2d
+thread_function (void * arg)
93dc2d
+{
93dc2d
+  int i = (int) (intptr_t) arg;
93dc2d
+
93dc2d
+  xraise (SIGUSR1);
93dc2d
+  if (i == 0)
93dc2d
+    test_cancel_thread ();
93dc2d
+  TEST_COMPARE (pthread_setspecific (rseq_test_key, &one), 0);
93dc2d
+  return rseq_thread_registered () ? NULL : (void *) 1l;
93dc2d
+}
93dc2d
+
93dc2d
+static void
93dc2d
+sighandler (int sig)
93dc2d
+{
93dc2d
+  if (!rseq_thread_registered ())
93dc2d
+    {
93dc2d
+      printf ("error: rseq not registered in signal handler\n");
93dc2d
+      support_record_failure ();
93dc2d
+    }
93dc2d
+}
93dc2d
+
93dc2d
+static void
93dc2d
+setup_signals (void)
93dc2d
+{
93dc2d
+  struct sigaction sa;
93dc2d
+
93dc2d
+  sigemptyset (&sa.sa_mask);
93dc2d
+  sigaddset (&sa.sa_mask, SIGUSR1);
93dc2d
+  sa.sa_flags = 0;
93dc2d
+  sa.sa_handler = sighandler;
93dc2d
+  xsigaction (SIGUSR1, &sa, NULL);
93dc2d
+}
93dc2d
+
93dc2d
+static int
93dc2d
+do_rseq_threads_test (int nr_threads)
93dc2d
+{
93dc2d
+  pthread_t th[nr_threads];
93dc2d
+  int i;
93dc2d
+  int result = 0;
93dc2d
+
93dc2d
+  xpthread_barrier_init (&cancel_thread_barrier, NULL, 2);
93dc2d
+
93dc2d
+  for (i = 0; i < nr_threads; ++i)
93dc2d
+    th[i] = xpthread_create (NULL, thread_function,
93dc2d
+                             (void *) (intptr_t) i);
93dc2d
+
93dc2d
+  (void) xpthread_barrier_wait (&cancel_thread_barrier);
93dc2d
+
93dc2d
+  xpthread_cancel (th[0]);
93dc2d
+
93dc2d
+  for (i = 0; i < nr_threads; ++i)
93dc2d
+    {
93dc2d
+      void *v;
93dc2d
+
93dc2d
+      v = xpthread_join (th[i]);
93dc2d
+      if (i != 0 && v != NULL)
93dc2d
+        {
93dc2d
+          printf ("error: join %d successful, but child failed\n", i);
93dc2d
+          result = 1;
93dc2d
+        }
93dc2d
+      else if (i == 0 && v == NULL)
93dc2d
+        {
93dc2d
+          printf ("error: join %d successful, child did not fail as expected\n", i);
93dc2d
+          result = 1;
93dc2d
+        }
93dc2d
+    }
93dc2d
+
93dc2d
+  xpthread_barrier_destroy (&cancel_thread_barrier);
93dc2d
+
93dc2d
+  return result;
93dc2d
+}
93dc2d
+
93dc2d
+static void
93dc2d
+subprocess_callback (void *closure)
93dc2d
+{
93dc2d
+  do_rseq_main_test ();
93dc2d
+}
93dc2d
+
93dc2d
+static void
93dc2d
+do_rseq_fork_test (void)
93dc2d
+{
93dc2d
+  support_isolate_in_subprocess (subprocess_callback, NULL);
93dc2d
+}
93dc2d
+
93dc2d
+static int
93dc2d
+do_rseq_test (void)
93dc2d
+{
93dc2d
+  int t[] = { 1, 2, 6, 5, 4, 3, 50 };
93dc2d
+  int i, result = 0;
93dc2d
+
93dc2d
+  if (!rseq_available ())
93dc2d
+    FAIL_UNSUPPORTED ("kernel does not support rseq, skipping test");
93dc2d
+  setup_signals ();
93dc2d
+  xraise (SIGUSR1);
93dc2d
+  do_rseq_main_test ();
93dc2d
+  for (i = 0; i < array_length (t); i++)
93dc2d
+    if (do_rseq_threads_test (t[i]))
93dc2d
+      result = 1;
93dc2d
+  do_rseq_fork_test ();
93dc2d
+  return result;
93dc2d
+}
93dc2d
+
93dc2d
+static void __attribute__ ((destructor))
93dc2d
+do_rseq_destructor_test (void)
93dc2d
+{
93dc2d
+  /* Cannot use deferred failure reporting after main returns.  */
93dc2d
+  if (do_rseq_test ())
93dc2d
+    FAIL_EXIT1 ("rseq not registered within destructor");
93dc2d
+  xpthread_key_delete (rseq_test_key);
93dc2d
+}
93dc2d
+
93dc2d
+#else /* RSEQ_SIG */
93dc2d
+static int
93dc2d
+do_rseq_test (void)
93dc2d
+{
93dc2d
+  FAIL_UNSUPPORTED ("glibc does not define RSEQ_SIG, skipping test");
93dc2d
+  return 0;
93dc2d
+}
93dc2d
+#endif /* RSEQ_SIG */
93dc2d
+
93dc2d
+static int
93dc2d
+do_test (void)
93dc2d
+{
93dc2d
+  return do_rseq_test ();
93dc2d
+}
93dc2d
+
93dc2d
+#include <support/test-driver.c>
93dc2d
diff --git a/sysdeps/unix/sysv/linux/tst-rseq.c b/sysdeps/unix/sysv/linux/tst-rseq.c
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..926376b6a5446ece
93dc2d
--- /dev/null
93dc2d
+++ b/sysdeps/unix/sysv/linux/tst-rseq.c
93dc2d
@@ -0,0 +1,64 @@
93dc2d
+/* Restartable Sequences single-threaded tests.
93dc2d
+   Copyright (C) 2021 Free Software Foundation, Inc.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+/* These tests validate that rseq is registered from main in an executable
93dc2d
+   not linked against libpthread.  */
93dc2d
+
93dc2d
+#include <support/check.h>
93dc2d
+#include <stdio.h>
93dc2d
+#include <sys/rseq.h>
93dc2d
+#include <unistd.h>
93dc2d
+
93dc2d
+#ifdef RSEQ_SIG
93dc2d
+# include <errno.h>
93dc2d
+# include <error.h>
93dc2d
+# include <stdlib.h>
93dc2d
+# include <string.h>
93dc2d
+# include <syscall.h>
93dc2d
+# include "tst-rseq.h"
93dc2d
+
93dc2d
+static void
93dc2d
+do_rseq_main_test (void)
93dc2d
+{
93dc2d
+  TEST_VERIFY_EXIT (rseq_thread_registered ());
93dc2d
+}
93dc2d
+
93dc2d
+static void
93dc2d
+do_rseq_test (void)
93dc2d
+{
93dc2d
+  if (!rseq_available ())
93dc2d
+    {
93dc2d
+      FAIL_UNSUPPORTED ("kernel does not support rseq, skipping test");
93dc2d
+    }
93dc2d
+  do_rseq_main_test ();
93dc2d
+}
93dc2d
+#else /* RSEQ_SIG */
93dc2d
+static void
93dc2d
+do_rseq_test (void)
93dc2d
+{
93dc2d
+  FAIL_UNSUPPORTED ("glibc does not define RSEQ_SIG, skipping test");
93dc2d
+}
93dc2d
+#endif /* RSEQ_SIG */
93dc2d
+
93dc2d
+static int
93dc2d
+do_test (void)
93dc2d
+{
93dc2d
+  do_rseq_test ();
93dc2d
+  return 0;
93dc2d
+}
93dc2d
+
93dc2d
+#include <support/test-driver.c>
93dc2d
diff --git a/sysdeps/unix/sysv/linux/tst-rseq.h b/sysdeps/unix/sysv/linux/tst-rseq.h
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..a476c316fc2671a0
93dc2d
--- /dev/null
93dc2d
+++ b/sysdeps/unix/sysv/linux/tst-rseq.h
93dc2d
@@ -0,0 +1,57 @@
93dc2d
+/* Restartable Sequences tests header.
93dc2d
+   Copyright (C) 2021 Free Software Foundation, Inc.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#include <errno.h>
93dc2d
+#include <error.h>
93dc2d
+#include <stdbool.h>
93dc2d
+#include <stdint.h>
93dc2d
+#include <support/check.h>
93dc2d
+#include <syscall.h>
93dc2d
+#include <sys/rseq.h>
93dc2d
+#include <tls.h>
93dc2d
+
93dc2d
+static inline bool
93dc2d
+rseq_thread_registered (void)
93dc2d
+{
93dc2d
+  return THREAD_GETMEM_VOLATILE (THREAD_SELF, rseq_area.cpu_id) >= 0;
93dc2d
+}
93dc2d
+
93dc2d
+static inline int
93dc2d
+sys_rseq (struct rseq *rseq_abi, uint32_t rseq_len, int flags, uint32_t sig)
93dc2d
+{
93dc2d
+  return syscall (__NR_rseq, rseq_abi, rseq_len, flags, sig);
93dc2d
+}
93dc2d
+
93dc2d
+static inline bool
93dc2d
+rseq_available (void)
93dc2d
+{
93dc2d
+  int rc;
93dc2d
+
93dc2d
+  rc = sys_rseq (NULL, 0, 0, 0);
93dc2d
+  if (rc != -1)
93dc2d
+    FAIL_EXIT1 ("Unexpected rseq return value %d", rc);
93dc2d
+  switch (errno)
93dc2d
+    {
93dc2d
+    case ENOSYS:
93dc2d
+      return false;
93dc2d
+    case EINVAL:
93dc2d
+      /* rseq is implemented, but detected an invalid rseq_len parameter.  */
93dc2d
+      return true;
93dc2d
+    default:
93dc2d
+      FAIL_EXIT1 ("Unexpected rseq error %s", strerror (errno));
93dc2d
+    }
93dc2d
+}
93dc2d
diff --git a/sysdeps/unix/sysv/linux/x86/bits/rseq.h b/sysdeps/unix/sysv/linux/x86/bits/rseq.h
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..9fc909e7c8a25bbb
93dc2d
--- /dev/null
93dc2d
+++ b/sysdeps/unix/sysv/linux/x86/bits/rseq.h
93dc2d
@@ -0,0 +1,30 @@
93dc2d
+/* Restartable Sequences Linux x86 architecture header.
93dc2d
+   Copyright (C) 2021 Free Software Foundation, Inc.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#ifndef _SYS_RSEQ_H
93dc2d
+# error "Never use <bits/rseq.h> directly; include <sys/rseq.h> instead."
93dc2d
+#endif
93dc2d
+
93dc2d
+/* RSEQ_SIG is a signature required before each abort handler code.
93dc2d
+
93dc2d
+   RSEQ_SIG is used with the following reserved undefined instructions, which
93dc2d
+   trap in user-space:
93dc2d
+
93dc2d
+   x86-32:    0f b9 3d 53 30 05 53      ud1    0x53053053,%edi
93dc2d
+   x86-64:    0f b9 3d 53 30 05 53      ud1    0x53053053(%rip),%edi  */
93dc2d
+
93dc2d
+#define RSEQ_SIG        0x53053053