x86: Add __sigsetjmp_cancel and __setjmp_cancel

Message ID CAMe9rOqaF+eVmQ=THJUro5=gw=PRn7FjQghXUVRC85zFKKGLRw@mail.gmail.com
State New, archived
Headers

Commit Message

H.J. Lu March 22, 2018, 8:59 p.m. UTC
  On Fri, Mar 16, 2018 at 4:28 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Fri, Mar 16, 2018 at 1:24 AM, Florian Weimer <fw@deneb.enyo.de> wrote:
>> * H. J. Lu:
>>
>>> +/* Function used in the macros.  */
>>> +struct __jmp_buf_tag;
>>> +extern int __sigsetjmp_cancel (struct __jmp_buf_tag *__env, int __savemask)
>>> +  __THROWNL __attribute_returns_twice__;
>>
>> How is __THROWNL correct here?  We do unwind through this function.
>> The __EXCEPTIONS guard is not effective because of LTO, and some
>> applications undefine __EXCEPTIONS to avoid the table-based
>> cancellation handlers.
>
> This is moved from <pthread.h>:
>
> /* Function used in the macros.  */
> struct __jmp_buf_tag;
> extern int __sigsetjmp (struct __jmp_buf_tag *__env, int __savemask) __THROWNL;
>
> Is <pthread.h> wrong?

It turns out that since libpthread provides compatible versions of
longjmp and siglongjmp
which don't save and restore shadow stack,  new versions of longjmp
and siglongjmp,
which save and restore shadow stack, should be added to libc.
Otherwise, porgrams
linked with libpthread will pick the wrong longjmp.

Here is the updated patch.  OK for master?

Thanks.
  

Comments

Florian Weimer March 29, 2018, 5:34 p.m. UTC | #1
* H. J. Lu:

> Here is the updated patch.  OK for master?

If you want to backport this into Fedora 28, you will have to avoid
new symbol versions.
  
H.J. Lu March 29, 2018, 5:59 p.m. UTC | #2
On Thu, Mar 29, 2018 at 10:34 AM, Florian Weimer <fw@deneb.enyo.de> wrote:
> * H. J. Lu:
>
>> Here is the updated patch.  OK for master?
>
> If you want to backport this into Fedora 28, you will have to avoid
> new symbol versions.

Should we revisit my patch to extend struct pthread_unwind_buf:

https://sourceware.org/ml/libc-alpha/2018-02/msg00291.html

This patch doesn't introduce the new symbol version.
  
Florian Weimer March 29, 2018, 7:42 p.m. UTC | #3
* H. J. Lu:

> On Thu, Mar 29, 2018 at 10:34 AM, Florian Weimer <fw@deneb.enyo.de> wrote:
>> * H. J. Lu:
>>
>>> Here is the updated patch.  OK for master?
>>
>> If you want to backport this into Fedora 28, you will have to avoid
>> new symbol versions.
>
> Should we revisit my patch to extend struct pthread_unwind_buf:
>
> https://sourceware.org/ml/libc-alpha/2018-02/msg00291.html
>
> This patch doesn't introduce the new symbol version.

That patch will require recompiling a subset of static libraries in
Fedora 28 to avoid crashes once CET is enabled.  Which should be
doable at a technical level, but takes resources away from other work,
obviously.

My preference still is a solution where we shift the stored signal
mask to make room for the shadow stack data in CET mode (for maximum
compatibility).  But I expect that Carlos will review your patch.
  
H.J. Lu March 29, 2018, 8:01 p.m. UTC | #4
On Thu, Mar 29, 2018 at 12:42 PM, Florian Weimer <fw@deneb.enyo.de> wrote:
> * H. J. Lu:
>
>> On Thu, Mar 29, 2018 at 10:34 AM, Florian Weimer <fw@deneb.enyo.de> wrote:
>>> * H. J. Lu:
>>>
>>>> Here is the updated patch.  OK for master?
>>>
>>> If you want to backport this into Fedora 28, you will have to avoid
>>> new symbol versions.
>>
>> Should we revisit my patch to extend struct pthread_unwind_buf:
>>
>> https://sourceware.org/ml/libc-alpha/2018-02/msg00291.html
>>
>> This patch doesn't introduce the new symbol version.
>
> That patch will require recompiling a subset of static libraries in
> Fedora 28 to avoid crashes once CET is enabled.  Which should be
> doable at a technical level, but takes resources away from other work,
> obviously.

BOTH approaches NEED to recompile a subset of static libraries in Fedora
28, as stated in

https://sourceware.org/ml/libc-alpha/2018-03/msg00521.html

NB: Shared libraries built with glibc 2.27 or older are compatible with
glibc 2.28.  Relocatable objects compiled against glibc 2.27 or older
are incompatible with glibc 2.28 since they reference the older version
of __sigsetjmp.

> My preference still is a solution where we shift the stored signal
> mask to make room for the shadow stack data in CET mode (for maximum
> compatibility).  But I expect that Carlos will review your patch.

As I have pointed out before

Note: There is an unused pointer space in pthread_unwind_buf_data.  But
it isn't suitable for saving and restoring shadow stack register since
x32 is a 64-bit process with 32-bit software pointer and kernel may
place x32 shadow stack above 4GB.  We need to save and restore 64-bit
shadow stack register for x32.
  
Florian Weimer March 29, 2018, 8:09 p.m. UTC | #5
* H. J. Lu:

> On Thu, Mar 29, 2018 at 12:42 PM, Florian Weimer <fw@deneb.enyo.de> wrote:
>> * H. J. Lu:
>>
>>> On Thu, Mar 29, 2018 at 10:34 AM, Florian Weimer <fw@deneb.enyo.de> wrote:
>>>> * H. J. Lu:
>>>>
>>>>> Here is the updated patch.  OK for master?
>>>>
>>>> If you want to backport this into Fedora 28, you will have to avoid
>>>> new symbol versions.
>>>
>>> Should we revisit my patch to extend struct pthread_unwind_buf:
>>>
>>> https://sourceware.org/ml/libc-alpha/2018-02/msg00291.html
>>>
>>> This patch doesn't introduce the new symbol version.
>>
>> That patch will require recompiling a subset of static libraries in
>> Fedora 28 to avoid crashes once CET is enabled.  Which should be
>> doable at a technical level, but takes resources away from other work,
>> obviously.
>
> BOTH approaches NEED to recompile a subset of static libraries in Fedora
> 28, as stated in
>
> https://sourceware.org/ml/libc-alpha/2018-03/msg00521.html

That's just another suboptimal implementation, I think.

> NB: Shared libraries built with glibc 2.27 or older are compatible with
> glibc 2.28.  Relocatable objects compiled against glibc 2.27 or older
> are incompatible with glibc 2.28 since they reference the older version
> of __sigsetjmp.

Understood.

>> My preference still is a solution where we shift the stored signal
>> mask to make room for the shadow stack data in CET mode (for maximum
>> compatibility).  But I expect that Carlos will review your patch.
>
> As I have pointed out before
>
> Note: There is an unused pointer space in pthread_unwind_buf_data.  But
> it isn't suitable for saving and restoring shadow stack register since
> x32 is a 64-bit process with 32-bit software pointer and kernel may
> place x32 shadow stack above 4GB.  We need to save and restore 64-bit
> shadow stack register for x32.

I thought you agreed that we do not need to unwind the shadow stack
pointer?  Therefore, __sigsetjmp can override the other members, too.
It's just a dead store, and __pthread_register_cancel will overwrite
it.

This will need a longjmp_cancel which does not restore the shadow
stack pointer.  But that can be a GLIBC_PRIVATE symbol.
  
H.J. Lu March 29, 2018, 8:13 p.m. UTC | #6
On Thu, Mar 29, 2018 at 1:09 PM, Florian Weimer <fw@deneb.enyo.de> wrote:
> * H. J. Lu:
>
>> On Thu, Mar 29, 2018 at 12:42 PM, Florian Weimer <fw@deneb.enyo.de> wrote:
>>> * H. J. Lu:
>>>
>>>> On Thu, Mar 29, 2018 at 10:34 AM, Florian Weimer <fw@deneb.enyo.de> wrote:
>>>>> * H. J. Lu:
>>>>>
>>>>>> Here is the updated patch.  OK for master?
>>>>>
>>>>> If you want to backport this into Fedora 28, you will have to avoid
>>>>> new symbol versions.
>>>>
>>>> Should we revisit my patch to extend struct pthread_unwind_buf:
>>>>
>>>> https://sourceware.org/ml/libc-alpha/2018-02/msg00291.html
>>>>
>>>> This patch doesn't introduce the new symbol version.
>>>
>>> That patch will require recompiling a subset of static libraries in
>>> Fedora 28 to avoid crashes once CET is enabled.  Which should be
>>> doable at a technical level, but takes resources away from other work,
>>> obviously.
>>
>> BOTH approaches NEED to recompile a subset of static libraries in Fedora
>> 28, as stated in
>>
>> https://sourceware.org/ml/libc-alpha/2018-03/msg00521.html
>
> That's just another suboptimal implementation, I think.
>
>> NB: Shared libraries built with glibc 2.27 or older are compatible with
>> glibc 2.28.  Relocatable objects compiled against glibc 2.27 or older
>> are incompatible with glibc 2.28 since they reference the older version
>> of __sigsetjmp.
>
> Understood.
>
>>> My preference still is a solution where we shift the stored signal
>>> mask to make room for the shadow stack data in CET mode (for maximum
>>> compatibility).  But I expect that Carlos will review your patch.
>>
>> As I have pointed out before
>>
>> Note: There is an unused pointer space in pthread_unwind_buf_data.  But
>> it isn't suitable for saving and restoring shadow stack register since
>> x32 is a 64-bit process with 32-bit software pointer and kernel may
>> place x32 shadow stack above 4GB.  We need to save and restore 64-bit
>> shadow stack register for x32.
>
> I thought you agreed that we do not need to unwind the shadow stack
> pointer?  Therefore, __sigsetjmp can override the other members, too.
> It's just a dead store, and __pthread_register_cancel will overwrite
> it.
>
> This will need a longjmp_cancel which does not restore the shadow
> stack pointer.  But that can be a GLIBC_PRIVATE symbol.

You need to make a choice.  You either don't introduce a new symbol
version or don't save shadow stack for thread cancellation.   You can't
have both.
  
Florian Weimer March 29, 2018, 8:15 p.m. UTC | #7
* H. J. Lu:

> You need to make a choice.  You either don't introduce a new symbol
> version or don't save shadow stack for thread cancellation.  You
> can't have both.

I don't understand.  We have room to save the shadow stack pointer in
the existing struct.
  
H.J. Lu March 29, 2018, 8:17 p.m. UTC | #8
On Thu, Mar 29, 2018 at 1:15 PM, Florian Weimer <fw@deneb.enyo.de> wrote:
> * H. J. Lu:
>
>> You need to make a choice.  You either don't introduce a new symbol
>> version or don't save shadow stack for thread cancellation.  You
>> can't have both.
>
> I don't understand.  We have room to save the shadow stack pointer in
> the existing struct.

No, we don't have room in struct pthread_unwind_buf:

Note: There is an unused pointer space in pthread_unwind_buf_data.  But
it isn't suitable for saving and restoring shadow stack register since
x32 is a 64-bit process with 32-bit software pointer and kernel may
place x32 shadow stack above 4GB.  We need to save and restore 64-bit
shadow stack register for x32.
  
Florian Weimer March 29, 2018, 8:20 p.m. UTC | #9
* H. J. Lu:

> On Thu, Mar 29, 2018 at 1:15 PM, Florian Weimer <fw@deneb.enyo.de> wrote:
>> * H. J. Lu:
>>
>>> You need to make a choice.  You either don't introduce a new symbol
>>> version or don't save shadow stack for thread cancellation.  You
>>> can't have both.
>>
>> I don't understand.  We have room to save the shadow stack pointer in
>> the existing struct.
>
> No, we don't have room in struct pthread_unwind_buf:
>
> Note: There is an unused pointer space in pthread_unwind_buf_data.  But
> it isn't suitable for saving and restoring shadow stack register since
> x32 is a 64-bit process with 32-bit software pointer and kernel may
> place x32 shadow stack above 4GB.  We need to save and restore 64-bit
> shadow stack register for x32.

We have for void * fields.  They are subsequently overwritten by
__pthread_register_cancel.  But __sigsetjmp can write to them first
without causing any harm.  We just need a private __longjmp_cancel
that doesn't restore the shadow stack pointer.
  

Patch

From 25647d4e7f72138563da1da8492855321e77695d Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sun, 25 Feb 2018 09:48:39 -0800
Subject: [PATCH] x86: Add __sigsetjmp_cancel and __setjmp_cancel

Functions, like LIBC_START_MAIN, START_THREAD_DEFN as well as these
with thread cancellation, call setjmp, but never return to their
callers after longjmp returns.  This patch adds <bits/setjmp-cancel.h>
and <setjmp-cancelP.h> to provide a version of setjmp family functions,
__setjmp_cancel and __sigsetjmp_cancel, which are used to implement
thread cancellation.  The default __setjmp_cancel and __sigsetjmp_cancel
are defined as setjmp and __sigsetjmp, respectively, which are the same
as before.

On x86, __sigsetjmp_cancel, which is a public function used by macros
in <pthread.h>, and __setjmp_cancel, which is a private interface for
cancellation implementation in libpthread, are added to avoid saving
and restoring shadow stack register.  A new version of __sigsetjmp is
added to save and restore shadow stack register. The compatible version
of __sigsetjmp, which doesn't save and restore shadow stack register,
is provided for shared libraries built with glibc 2.27 or older.
__libc_longjmp, which is a private interface for cancellation
implementation in libpthread, is changed to call __longjmp_cancel
instead of __longjmp.  Since libpthread provides compatible versions
of longjmp and siglongjmp which don't save and restore shadow stack,
new versions of longjmp and siglongjmp, which save and restore shadow
stack, are also added to libc.

NB: Shared libraries built with glibc 2.27 or older are compatible with
glibc 2.28.  Relocatable objects compiled against glibc 2.27 or older
are incompatible with glibc 2.28 since they reference the older version
of __sigsetjmp.

Tested with build-many-glibcs.py.

	* bits/setjmp-cancel.h: New file.
	* sysdeps/generic/setjmp-cancelP.h: Likewise.
	* sysdeps/x86/__longjmp_cancel.S: Likewise.
	* sysdeps/x86/bsd-_setjmp_cancel.S: Likewise.
	* sysdeps/x86/longjmp.c: Likewise.
	* sysdeps/x86/setjmp-cancelP.h: Likewise.
	* sysdeps/x86/setjmp_cancel.S: Likewise.
	* sysdeps/x86/bits/setjmp-cancel.h: Likewise.
	* sysdeps/x86_64/setjmp_cancel.S: Likewise.
	* csu/libc-start.c (LIBC_START_MAIN): Replace setjmp with
	__setjmp_cancel.
	* nptl/pthread_create.c (START_THREAD_DEFN): Likewise.
	* include/setjmp.h: Include <setjmp-cancelP.h> and
	<bits/setjmp-cancel.h>.
	* misc/sys/cdefs.h (__attribute_returns_twice__): New.
	* nptl/Makefile (headers): Add bits/setjmp-cancel.h.
	* setjmp/longjmp.c (__libc_longjmp): Don't define alias if
	defined.
	(longjmp): Likewise.
	(siglongjmp): Likewise.
	* sysdeps/i386/bsd-_setjmp.S (_setjmp): Don't add hidden_def.
	* sysdeps/x86_64/bsd-_setjmp.S (_setjmp): Likewise.
	* sysdeps/i386/setjmp.S (__sigsetjmp): Don't add hidden_def and
	redefined to __redirect___sigsetjmp in libc.so if __sigsetjmp
	is undefined.
	(__GI___sigsetjmp): New.  Defined if __redirect___sigsetjmp is
	defined.
	(__sigsetjmp): Add to GLIBC_2_28 if __redirect___sigsetjmp is
	defined.
	* sysdeps/x86_64/setjmp.S: Likewise.
	* sysdeps/nptl/pthread.h (pthread_cleanup_push): Replace
	__sigsetjmp with __sigsetjmp_cancel.
	(pthread_cleanup_push_defer_np): Likewise.
	(__jmp_buf_tag): Removed.
	(__sigsetjmp): Likewise.
	Include <bits/setjmp-cancel.h>.
	* sysdeps/unix/sysv/linux/i386/libc.abilist: Regenerated.
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.
	* sysdeps/x86/Makefile (sysdep_routines): Add
	bsd-_setjmp_cancel, __longjmp_cancel and setjmp_cancel.
	* sysdeps/x86/Versions (longjmp): Add to GLIBC_2.28 in libc.
	(siglongjmp): Likewise.
	(__sigsetjmp_cancel): Likewise.
	(__setjmp_cancel): Add to GLIBC_PRIVATE in libc.
	* sysdeps/x86_64/bsd-_setjmp.S (SIGSETJMP): New.
	(_setjmp): Jmp to SIGSETJMP.
---
 bits/setjmp-cancel.h                            | 33 +++++++++++++++
 csu/libc-start.c                                |  2 +-
 include/setjmp.h                                |  3 ++
 misc/sys/cdefs.h                                |  6 +++
 nptl/Makefile                                   |  2 +-
 nptl/pthread_create.c                           |  2 +-
 setjmp/longjmp.c                                |  4 +-
 sysdeps/generic/setjmp-cancelP.h                | 19 +++++++++
 sysdeps/i386/bsd-_setjmp.S                      |  2 +
 sysdeps/i386/setjmp.S                           | 16 +++++++-
 sysdeps/nptl/pthread.h                          | 15 ++++---
 sysdeps/unix/sysv/linux/i386/libc.abilist       |  5 +++
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist  |  5 +++
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist |  5 +++
 sysdeps/x86/Makefile                            |  4 ++
 sysdeps/x86/Versions                            | 15 +++++++
 sysdeps/x86/__longjmp_cancel.S                  | 20 +++++++++
 sysdeps/x86/bits/setjmp-cancel.h                | 31 ++++++++++++++
 sysdeps/x86/bsd-_setjmp_cancel.S                | 22 ++++++++++
 sysdeps/x86/longjmp.c                           | 54 +++++++++++++++++++++++++
 sysdeps/x86/setjmp-cancelP.h                    | 24 +++++++++++
 sysdeps/x86/setjmp_cancel.S                     | 26 ++++++++++++
 sysdeps/x86_64/bsd-_setjmp.S                    | 25 +++++++++---
 sysdeps/x86_64/setjmp.S                         | 16 +++++++-
 sysdeps/x86_64/setjmp_cancel.S                  | 21 ++++++++++
 25 files changed, 358 insertions(+), 19 deletions(-)
 create mode 100644 bits/setjmp-cancel.h
 create mode 100644 sysdeps/generic/setjmp-cancelP.h
 create mode 100644 sysdeps/x86/__longjmp_cancel.S
 create mode 100644 sysdeps/x86/bits/setjmp-cancel.h
 create mode 100644 sysdeps/x86/bsd-_setjmp_cancel.S
 create mode 100644 sysdeps/x86/longjmp.c
 create mode 100644 sysdeps/x86/setjmp-cancelP.h
 create mode 100644 sysdeps/x86/setjmp_cancel.S
 create mode 100644 sysdeps/x86_64/setjmp_cancel.S

diff --git a/bits/setjmp-cancel.h b/bits/setjmp-cancel.h
new file mode 100644
index 0000000000..a0c4566127
--- /dev/null
+++ b/bits/setjmp-cancel.h
@@ -0,0 +1,33 @@ 
+/* __sigsetjmp_cancel for thread cancellation.  Generic version.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _BITS_SETJMP_CANCEL_H
+#define _BITS_SETJMP_CANCEL_H  1
+
+#if !defined _SETJMP_H && !defined _PTHREAD_H
+# error "Never include <bits/setjmp-cancel.h> directly; use <setjmp.h> instead."
+#endif
+
+#define __sigsetjmp_cancel __sigsetjmp
+
+struct __jmp_buf_tag;
+/* Function used in the macros.  */
+extern int __sigsetjmp (struct __jmp_buf_tag *__env,
+			int __savemask) __THROWNL;
+
+#endif  /* bits/setjmp-cancel.h */
diff --git a/csu/libc-start.c b/csu/libc-start.c
index 605222fa3f..0c1e2fa830 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -292,7 +292,7 @@  LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
   struct pthread_unwind_buf unwind_buf;
 
   int not_first_call;
-  not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
+  not_first_call = __setjmp_cancel ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
   if (__glibc_likely (! not_first_call))
     {
       struct pthread *self = THREAD_SELF;
diff --git a/include/setjmp.h b/include/setjmp.h
index 263bc64b3d..fa846c83cc 100644
--- a/include/setjmp.h
+++ b/include/setjmp.h
@@ -31,6 +31,9 @@  libc_hidden_proto (__sigsetjmp)
 extern __typeof (__sigsetjmp) __sigsetjmp attribute_hidden;
 # endif
 
+# include <setjmp-cancelP.h>
+# include <bits/setjmp-cancel.h>
+
 /* Check jmp_buf sizes, alignments and offsets.  */
 # include <stddef.h>
 # include <jmp_buf-macros.h>
diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index e80a45ca68..5f704f41db 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -416,6 +416,12 @@ 
 # endif
 #endif
 
+#if __GNUC_PREREQ (4, 1)
+# define __attribute_returns_twice__ __attribute__ ((__returns_twice__))
+#else
+# define __attribute_returns_twice__ /* Ignore.  */
+#endif
+
 #if __GNUC_PREREQ (8, 0)
 /* Describes a char array whose address can safely be passed as the first
    argument to strncpy and strncat, as the char array is not necessarily
diff --git a/nptl/Makefile b/nptl/Makefile
index 94be92c789..fa3027072d 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -22,7 +22,7 @@  subdir	:= nptl
 
 include ../Makeconfig
 
-headers := pthread.h semaphore.h bits/semaphore.h
+headers := pthread.h semaphore.h bits/semaphore.h bits/setjmp-cancel.h
 
 extra-libs := libpthread
 extra-libs-others := $(extra-libs)
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index caaf07c134..0728779994 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -432,7 +432,7 @@  START_THREAD_DEFN
   unwind_buf.priv.data.cleanup = NULL;
 
   int not_first_call;
-  not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
+  not_first_call = __setjmp_cancel ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
   if (__glibc_likely (! not_first_call))
     {
       /* Store the new cleanup handler info.  */
diff --git a/setjmp/longjmp.c b/setjmp/longjmp.c
index a2a7065a85..4abf1662ac 100644
--- a/setjmp/longjmp.c
+++ b/setjmp/longjmp.c
@@ -40,10 +40,12 @@  __libc_siglongjmp (sigjmp_buf env, int val)
 }
 
 #ifndef __libc_siglongjmp
+# ifndef __libc_longjmp
 /* __libc_longjmp is a private interface for cancellation implementation
    in libpthread.  */
 strong_alias (__libc_siglongjmp, __libc_longjmp)
-weak_alias (__libc_siglongjmp, _longjmp)
 weak_alias (__libc_siglongjmp, longjmp)
 weak_alias (__libc_siglongjmp, siglongjmp)
+# endif
+weak_alias (__libc_siglongjmp, _longjmp)
 #endif
diff --git a/sysdeps/generic/setjmp-cancelP.h b/sysdeps/generic/setjmp-cancelP.h
new file mode 100644
index 0000000000..658a3306f3
--- /dev/null
+++ b/sysdeps/generic/setjmp-cancelP.h
@@ -0,0 +1,19 @@ 
+/* Internal header file for <bits/setjmp-cancel.h>.  Generic version.
+   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define __setjmp_cancel setjmp
diff --git a/sysdeps/i386/bsd-_setjmp.S b/sysdeps/i386/bsd-_setjmp.S
index a626cc6d22..51446a5614 100644
--- a/sysdeps/i386/bsd-_setjmp.S
+++ b/sysdeps/i386/bsd-_setjmp.S
@@ -53,4 +53,6 @@  ENTRY (_setjmp)
 	movl %eax, JB_SIZE(%edx) /* No signal mask set.  */
 	ret
 END (_setjmp)
+#ifndef _setjmp
 libc_hidden_def (_setjmp)
+#endif
diff --git a/sysdeps/i386/setjmp.S b/sysdeps/i386/setjmp.S
index 6a08701717..e7ba7a7ce5 100644
--- a/sysdeps/i386/setjmp.S
+++ b/sysdeps/i386/setjmp.S
@@ -25,6 +25,11 @@ 
 #define JMPBUF	PARMS
 #define SIGMSK	JMPBUF+4
 
+#if !defined __sigsetjmp && defined SHARED && !IS_IN (rtld)
+# define __sigsetjmp __redirect___sigsetjmp
+# define __redirect___sigsetjmp __redirect___sigsetjmp
+#endif
+
 ENTRY (__sigsetjmp)
 
 	movl JMPBUF(%esp), %eax
@@ -55,4 +60,13 @@  ENTRY (__sigsetjmp)
 	jmp __sigjmp_save
 #endif
 END (__sigsetjmp)
-hidden_def (__sigsetjmp)
+#ifdef __redirect___sigsetjmp
+# undef __sigsetjmp
+
+	.globl __GI___sigsetjmp
+	.hidden __GI___sigsetjmp
+	__GI___sigsetjmp = __redirect___sigsetjmp
+
+# include <shlib-compat.h>
+versioned_symbol (libc, __redirect___sigsetjmp, __sigsetjmp, GLIBC_2_28);
+#endif
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index df049abf74..8568baff9d 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -667,8 +667,9 @@  __pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame)
     __pthread_unwind_buf_t __cancel_buf;				      \
     void (*__cancel_routine) (void *) = (routine);			      \
     void *__cancel_arg = (arg);						      \
-    int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *)     \
-					__cancel_buf.__cancel_jmp_buf, 0);    \
+    int __not_first_call						      \
+      = __sigsetjmp_cancel ((struct __jmp_buf_tag *) (void *)		      \
+			    __cancel_buf.__cancel_jmp_buf, 0);		      \
     if (__glibc_unlikely (__not_first_call))				      \
       {									      \
 	__cancel_routine (__cancel_arg);				      \
@@ -702,8 +703,9 @@  extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf)
     __pthread_unwind_buf_t __cancel_buf;				      \
     void (*__cancel_routine) (void *) = (routine);			      \
     void *__cancel_arg = (arg);						      \
-    int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *)     \
-					__cancel_buf.__cancel_jmp_buf, 0);    \
+    int __not_first_call						      \
+      = __sigsetjmp_cancel ((struct __jmp_buf_tag *) (void *)		      \
+			    __cancel_buf.__cancel_jmp_buf, 0);		      \
     if (__glibc_unlikely (__not_first_call))				      \
       {									      \
 	__cancel_routine (__cancel_arg);				      \
@@ -739,10 +741,7 @@  extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf)
      ;
 #endif
 
-/* Function used in the macros.  */
-struct __jmp_buf_tag;
-extern int __sigsetjmp (struct __jmp_buf_tag *__env, int __savemask) __THROWNL;
-
+#include <bits/setjmp-cancel.h>
 
 /* Mutex handling.  */
 
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 39c993fd79..4f1f689302 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2064,6 +2064,11 @@  GLIBC_2.27 wcstof64 F
 GLIBC_2.27 wcstof64_l F
 GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 GLIBC_2.28 A
+GLIBC_2.28 __sigsetjmp F
+GLIBC_2.28 __sigsetjmp_cancel F
+GLIBC_2.28 longjmp F
+GLIBC_2.28 siglongjmp F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 2a3cc40674..a94347b8d6 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1905,6 +1905,11 @@  GLIBC_2.27 wcstof64 F
 GLIBC_2.27 wcstof64_l F
 GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 GLIBC_2.28 A
+GLIBC_2.28 __sigsetjmp F
+GLIBC_2.28 __sigsetjmp_cancel F
+GLIBC_2.28 longjmp F
+GLIBC_2.28 siglongjmp F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 8bc16b9004..e8dd56c69a 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2148,3 +2148,8 @@  GLIBC_2.27 wcstof64 F
 GLIBC_2.27 wcstof64_l F
 GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 GLIBC_2.28 A
+GLIBC_2.28 __sigsetjmp F
+GLIBC_2.28 __sigsetjmp_cancel F
+GLIBC_2.28 longjmp F
+GLIBC_2.28 siglongjmp F
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
index 0d0326c21a..d23ee462f7 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -8,3 +8,7 @@  sysdep-dl-routines += dl-get-cpu-features
 tests += tst-get-cpu-features
 tests-static += tst-get-cpu-features-static
 endif
+
+ifeq ($(subdir),setjmp)
+sysdep_routines += bsd-_setjmp_cancel __longjmp_cancel setjmp_cancel
+endif
diff --git a/sysdeps/x86/Versions b/sysdeps/x86/Versions
index e02923708e..bcb86a73e0 100644
--- a/sysdeps/x86/Versions
+++ b/sysdeps/x86/Versions
@@ -3,3 +3,18 @@  ld {
     __get_cpu_features;
   }
 }
+libc {
+  GLIBC_2.28 {
+   # New versions to avoid picking up old ones in libpthread.
+   longjmp;
+   siglongjmp;
+   __sigsetjmp;
+
+   # used to implement thread cancellation.
+   __sigsetjmp_cancel;
+  }
+  GLIBC_PRIVATE {
+   # used to implement thread cancellation.
+    __setjmp_cancel;
+  }
+}
diff --git a/sysdeps/x86/__longjmp_cancel.S b/sysdeps/x86/__longjmp_cancel.S
new file mode 100644
index 0000000000..b57dbfa376
--- /dev/null
+++ b/sysdeps/x86/__longjmp_cancel.S
@@ -0,0 +1,20 @@ 
+/* __longjmp_cancel for x86.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define __longjmp __longjmp_cancel
+#include <__longjmp.S>
diff --git a/sysdeps/x86/bits/setjmp-cancel.h b/sysdeps/x86/bits/setjmp-cancel.h
new file mode 100644
index 0000000000..87fd6cf96f
--- /dev/null
+++ b/sysdeps/x86/bits/setjmp-cancel.h
@@ -0,0 +1,31 @@ 
+/* __sigsetjmp_cancel for thread cancellation.  x86 version.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _BITS_SETJMP_CANCEL_H
+#define _BITS_SETJMP_CANCEL_H  1
+
+#if !defined _SETJMP_H && !defined _PTHREAD_H
+# error "Never include <bits/setjmp-cancel.h> directly; use <setjmp.h> instead."
+#endif
+
+/* Function used in the macros.  */
+struct __jmp_buf_tag;
+extern int __sigsetjmp_cancel (struct __jmp_buf_tag *__env, int __savemask)
+  __THROWNL __attribute_returns_twice__;
+
+#endif  /* bits/setjmp-cancel.h */
diff --git a/sysdeps/x86/bsd-_setjmp_cancel.S b/sysdeps/x86/bsd-_setjmp_cancel.S
new file mode 100644
index 0000000000..25b2a95960
--- /dev/null
+++ b/sysdeps/x86/bsd-_setjmp_cancel.S
@@ -0,0 +1,22 @@ 
+/* __setjmp_cancel for x86.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define _setjmp __setjmp_cancel
+#include <bsd-_setjmp.S>
+
+libc_hidden_def (__setjmp_cancel)
diff --git a/sysdeps/x86/longjmp.c b/sysdeps/x86/longjmp.c
new file mode 100644
index 0000000000..72c04a9584
--- /dev/null
+++ b/sysdeps/x86/longjmp.c
@@ -0,0 +1,54 @@ 
+/* __libc_siglongjmp for x86.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define __libc_longjmp __redirect___libc_longjmp
+#include <setjmp/longjmp.c>
+#undef __libc_longjmp
+
+/* Since __libc_longjmp is a private interface for cancellation
+   implementation in libpthread, there is no need to restore shadow
+   stack register.  */
+
+void
+__libc_longjmp (sigjmp_buf env, int val)
+{
+  /* Perform any cleanups needed by the frames being unwound.  */
+  _longjmp_unwind (env, val);
+
+  if (env[0].__mask_was_saved)
+    /* Restore the saved signal mask.  */
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
+			  (sigset_t *) NULL);
+
+  /* Call the machine-dependent function to restore machine state
+     without shadow stack.  */
+  __longjmp_cancel (env[0].__jmpbuf, val ?: 1);
+}
+
+#include <shlib-compat.h>
+
+versioned_symbol (libc, __libc_siglongjmp, siglongjmp, GLIBC_2_28);
+strong_alias (__libc_siglongjmp, __libc_siglongjmp_alias)
+versioned_symbol (libc, __libc_siglongjmp_alias, longjmp, GLIBC_2_28);
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
+compat_symbol (libc, __libc_longjmp, longjmp, GLIBC_2_0);
+strong_alias (__libc_longjmp, __libc_longjmp_alias)
+compat_symbol (libc, __libc_longjmp_alias, siglongjmp, GLIBC_2_0);
+#endif
diff --git a/sysdeps/x86/setjmp-cancelP.h b/sysdeps/x86/setjmp-cancelP.h
new file mode 100644
index 0000000000..1cd4f94b50
--- /dev/null
+++ b/sysdeps/x86/setjmp-cancelP.h
@@ -0,0 +1,24 @@ 
+/* Internal header file for <bits/setjmp-cancel.h>.  x86 version.
+   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+extern int __setjmp_cancel (struct __jmp_buf_tag __env[1])
+  __attribute__((__returns_twice__));
+libc_hidden_proto (__setjmp_cancel, __returns_twice__)
+
+extern void __longjmp_cancel (__jmp_buf __env, int __val)
+     __attribute__ ((__noreturn__)) attribute_hidden;
diff --git a/sysdeps/x86/setjmp_cancel.S b/sysdeps/x86/setjmp_cancel.S
new file mode 100644
index 0000000000..b2bca39883
--- /dev/null
+++ b/sysdeps/x86/setjmp_cancel.S
@@ -0,0 +1,26 @@ 
+/* __sigsetjmp_cancel for x86.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define __sigsetjmp __sigsetjmp_cancel
+#include <setjmp.S>
+#undef __sigsetjmp
+
+#include <shlib-compat.h>
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
+compat_symbol (libc, __sigsetjmp_cancel, __sigsetjmp, GLIBC_2_0);
+#endif
diff --git a/sysdeps/x86_64/bsd-_setjmp.S b/sysdeps/x86_64/bsd-_setjmp.S
index 58c997de59..e4908b0081 100644
--- a/sysdeps/x86_64/bsd-_setjmp.S
+++ b/sysdeps/x86_64/bsd-_setjmp.S
@@ -25,13 +25,28 @@ 
 #define _SETJMP_H
 #include <bits/setjmp.h>
 
+/* If _setjmp is defined for __setjmp_cancel, call __sigsetjmp_cancel
+   instead of __sigsetjmp.
+ */
+#ifdef _setjmp
+# ifdef PIC
+#  define SIGSETJMP HIDDEN_JUMPTARGET (__sigsetjmp_cancel)
+# else
+#  define SIGSETJMP __sigsetjmp_cancel
+# endif
+#else
+# ifdef PIC
+#  define SIGSETJMP HIDDEN_JUMPTARGET (__sigsetjmp)
+# else
+#  define SIGSETJMP __sigsetjmp
+# endif
+#endif
+
 ENTRY (_setjmp)
 	/* Set up arguments, we only need to set the second arg.  */
 	xorl %esi, %esi
-#ifdef PIC
-	jmp HIDDEN_JUMPTARGET (__sigsetjmp)
-#else
-	jmp __sigsetjmp
-#endif
+	jmp SIGSETJMP
 END (_setjmp)
+#ifndef _setjmp
 libc_hidden_def (_setjmp)
+#endif
diff --git a/sysdeps/x86_64/setjmp.S b/sysdeps/x86_64/setjmp.S
index e0a648e3e4..c7cbb29111 100644
--- a/sysdeps/x86_64/setjmp.S
+++ b/sysdeps/x86_64/setjmp.S
@@ -21,6 +21,11 @@ 
 #include <asm-syntax.h>
 #include <stap-probe.h>
 
+#if !defined __sigsetjmp && defined SHARED && !IS_IN (rtld)
+# define __sigsetjmp __redirect___sigsetjmp
+# define __redirect___sigsetjmp __redirect___sigsetjmp
+#endif
+
 ENTRY (__sigsetjmp)
 	/* Save registers.  */
 	movq %rbx, (JB_RBX*8)(%rdi)
@@ -63,4 +68,13 @@  ENTRY (__sigsetjmp)
 	jmp __sigjmp_save
 #endif
 END (__sigsetjmp)
-hidden_def (__sigsetjmp)
+#ifdef __redirect___sigsetjmp
+# undef __sigsetjmp
+
+	.globl __GI___sigsetjmp
+	.hidden __GI___sigsetjmp
+	__GI___sigsetjmp = __redirect___sigsetjmp
+
+# include <shlib-compat.h>
+versioned_symbol (libc, __redirect___sigsetjmp, __sigsetjmp, GLIBC_2_28);
+#endif
diff --git a/sysdeps/x86_64/setjmp_cancel.S b/sysdeps/x86_64/setjmp_cancel.S
new file mode 100644
index 0000000000..3727a9c7dc
--- /dev/null
+++ b/sysdeps/x86_64/setjmp_cancel.S
@@ -0,0 +1,21 @@ 
+/* __sigsetjmp_cancel for x86-64.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sysdeps/x86/setjmp_cancel.S>
+
+libc_hidden_def (__sigsetjmp_cancel)
-- 
2.14.3