public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 2/2] jmpbuf: Add paddings for target specific usage
@ 2017-11-07 22:39 H.J. Lu
  2017-11-08  6:06 ` Florian Weimer
  0 siblings, 1 reply; 16+ messages in thread
From: H.J. Lu @ 2017-11-07 22:39 UTC (permalink / raw)
  To: GNU C Library

To support Shadow Stack (SHSTK) in Intel Control-flow Enforcement
Technology (CET) in setjmp/longjmp, we need to save shadow stack
pointer in jmp_buf.  The __saved_mask field in jmp_buf has type
of __sigset_t.  On Linux, __sigset_t is defined as

 #define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
  unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;

which is much bigger than expected by the __sigprocmask system call,
which has

typedef struct {
        unsigned long sig[_NSIG_WORDS];
} sigset_t;

We can shrink __sigset_t used by __saved_mask in jmp_buf to add paddings
for target specific usage.  As long as the new __sigset_t is not smaller
than sigset_t expected by the __sigprocmask system call, it should work
correctly.  This patch defines __jmp_buf_sigset_t for __saved_mask in
jmp_buf on Linux and verifies __jmp_buf_sigset_t has the suitable size
for the __sigprocmask system call.

Tested with build-many-glibcs.py.

OK for master?

H.J.
---
	* bits/setjmp3.h: New file.
	* sysdeps/unix/sysv/linux/bits/setjmp3.h: Likewise.
	* setjmp/Makefile (headers): Add bits/setjmp3.h.
	* setjmp/longjmp.c (__libc_siglongjmp): Cast &env[0].__saved_mask
	to "sigset_t *".
	* setjmp/sigjmp.c (__sigjmp_save): Likewise.
	* sysdeps/powerpc/longjmp.c (__vmx__libc_siglongjmp): Likewise.
	* sysdeps/powerpc/novmx-longjmp.c (__novmx__libc_siglongjmp):
	Likewise.
	* sysdeps/powerpc/novmx-sigjmp.c (__novmx__sigjmp_save): Likewise.
	* sysdeps/powerpc/sigjmp.c (__vmx__sigjmp_save): Likewise.
	* sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c
	(__libc_unwind_longjmp): Likewise.
	* setjmp/setjmp.h: Include <bits/setjmp3.h> instead of
	<bits/types/__sigset_t.h>.
	(__jmp_buf_tag): Change __saved_mask to __target.
	* setjmp/tst-jmp_buf.c: Include <signal.h>.
	[_NSIG] (KERNEL_NSIG_WORDS): New.
	[_NSIG] (kernel_sigset_t): Likewise.
	[_NSIG] (do_test): Add _Static_assert for size of __saved_mask
	in jmp_buf >= sizeof kernel_sigset_t.
---
 bits/setjmp3.h                                | 31 +++++++++++++++++
 setjmp/Makefile                               |  2 +-
 setjmp/longjmp.c                              |  3 +-
 setjmp/setjmp.h                               |  4 +--
 setjmp/sigjmp.c                               |  2 +-
 setjmp/tst-jmp_buf.c                          | 17 ++++++++++
 sysdeps/powerpc/longjmp.c                     |  3 +-
 sysdeps/powerpc/novmx-longjmp.c               |  3 +-
 sysdeps/powerpc/novmx-sigjmp.c                |  2 +-
 sysdeps/powerpc/sigjmp.c                      |  2 +-
 sysdeps/unix/sysv/linux/bits/setjmp3.h        | 48 +++++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c |  3 +-
 12 files changed, 110 insertions(+), 10 deletions(-)
 create mode 100644 bits/setjmp3.h
 create mode 100644 sysdeps/unix/sysv/linux/bits/setjmp3.h

diff --git a/bits/setjmp3.h b/bits/setjmp3.h
new file mode 100644
index 0000000000..b164c8d449
--- /dev/null
+++ b/bits/setjmp3.h
@@ -0,0 +1,31 @@
+/* Generic __jmpbuf_target_t defition.
+   Copyright (C) 2017 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 _SETJMP_H
+# error "Never include <bits/setjmp3.h> directly; use <setjmp.h> instead."
+#endif
+
+#include <bits/types/__sigset_t.h>
+
+typedef struct
+  {
+    __sigset_t __saved_mask;
+  } __jmpbuf_target_t;
+
+/* Saved signal mask.  */
+#define __saved_mask __target.__saved_mask
diff --git a/setjmp/Makefile b/setjmp/Makefile
index 857e0b8d0f..6ab9b4c3ca 100644
--- a/setjmp/Makefile
+++ b/setjmp/Makefile
@@ -22,7 +22,7 @@ subdir	:= setjmp
 
 include ../Makeconfig
 
-headers	:= setjmp.h bits/setjmp.h bits/setjmp2.h
+headers	:= setjmp.h bits/setjmp.h bits/setjmp2.h bits/setjmp3.h
 
 routines	:= setjmp sigjmp bsd-setjmp bsd-_setjmp \
 		   longjmp __longjmp jmp-unwind
diff --git a/setjmp/longjmp.c b/setjmp/longjmp.c
index 2453c2c124..86a024b4b8 100644
--- a/setjmp/longjmp.c
+++ b/setjmp/longjmp.c
@@ -31,7 +31,8 @@ __libc_siglongjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/setjmp/setjmp.h b/setjmp/setjmp.h
index 86fb2edf6c..1082fb0142 100644
--- a/setjmp/setjmp.h
+++ b/setjmp/setjmp.h
@@ -27,7 +27,7 @@
 __BEGIN_DECLS
 
 #include <bits/setjmp.h>		/* Get `__jmp_buf'.  */
-#include <bits/types/__sigset_t.h>
+#include <bits/setjmp3.h>
 
 /* Calling environment, plus possibly a saved signal mask.  */
 struct __jmp_buf_tag
@@ -38,7 +38,7 @@ struct __jmp_buf_tag
        or add others before it.  */
     __jmp_buf __jmpbuf;		/* Calling environment.  */
     int __mask_was_saved;	/* Saved the signal mask?  */
-    __sigset_t __saved_mask;	/* Saved signal mask.  */
+    __jmpbuf_target_t __target;	/* Target specific data.  */
   };
 
 
diff --git a/setjmp/sigjmp.c b/setjmp/sigjmp.c
index 30839ae819..0cd733b3ee 100644
--- a/setjmp/sigjmp.c
+++ b/setjmp/sigjmp.c
@@ -28,7 +28,7 @@ __sigjmp_save (sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/setjmp/tst-jmp_buf.c b/setjmp/tst-jmp_buf.c
index 1b25d85876..16ddebc224 100644
--- a/setjmp/tst-jmp_buf.c
+++ b/setjmp/tst-jmp_buf.c
@@ -18,9 +18,19 @@
 
 #include <stdio.h>
 #include <setjmp.h>
+#include <signal.h>
 #include <stddef.h>
 #include <jmp_buf-macros.h>
 
+#ifdef _NSIG
+# define KERNEL_NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[KERNEL_NSIG_WORDS];
+  } kernel_sigset_t;
+#endif
+
 #define STR_HELPER(x) #x
 #define STR(x) STR_HELPER(x)
 
@@ -54,6 +64,13 @@ do_test (void)
   TEST_OFFSET (struct __jmp_buf_tag, __saved_mask,
 	       SAVED_MASK_OFFSET);
 
+#ifdef _NSIG
+  jmp_buf buf;
+  __typeof (buf[0].__saved_mask) saved_mask;
+  _Static_assert (sizeof (saved_mask) >= sizeof (kernel_sigset_t),
+		  "size of saved_mask < size of kernel_sigset_t");
+#endif
+
   return 0;
 }
 
diff --git a/sysdeps/powerpc/longjmp.c b/sysdeps/powerpc/longjmp.c
index bd3ed8c22b..a23f2c582b 100644
--- a/sysdeps/powerpc/longjmp.c
+++ b/sysdeps/powerpc/longjmp.c
@@ -39,7 +39,8 @@ __vmx__libc_siglongjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/sysdeps/powerpc/novmx-longjmp.c b/sysdeps/powerpc/novmx-longjmp.c
index b0020b728a..662fbc5432 100644
--- a/sysdeps/powerpc/novmx-longjmp.c
+++ b/sysdeps/powerpc/novmx-longjmp.c
@@ -37,7 +37,8 @@ __novmx__libc_siglongjmp (__novmx__sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/sysdeps/powerpc/novmx-sigjmp.c b/sysdeps/powerpc/novmx-sigjmp.c
index 7d0ae59437..62680fe38f 100644
--- a/sysdeps/powerpc/novmx-sigjmp.c
+++ b/sysdeps/powerpc/novmx-sigjmp.c
@@ -35,7 +35,7 @@ __novmx__sigjmp_save (__novmx__sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/sysdeps/powerpc/sigjmp.c b/sysdeps/powerpc/sigjmp.c
index 6d593a0992..736491eff9 100644
--- a/sysdeps/powerpc/sigjmp.c
+++ b/sysdeps/powerpc/sigjmp.c
@@ -31,7 +31,7 @@ __vmx__sigjmp_save (sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/sysdeps/unix/sysv/linux/bits/setjmp3.h b/sysdeps/unix/sysv/linux/bits/setjmp3.h
new file mode 100644
index 0000000000..e86dbdcba4
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/bits/setjmp3.h
@@ -0,0 +1,48 @@
+/* __jmpbuf_target_t defition for Linux.
+   Copyright (C) 2017 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 _SETJMP_H
+# error "Never include <bits/setjmp3.h> directly; use <setjmp.h> instead."
+#endif
+
+#include <bits/types/__sigset_t.h>
+
+/* The biggest signal number + 1  */
+#define _JUMP_BUF_SIGSET_NSIG	257
+/* Number of longs to hold all signals.  */
+#define _JUMP_BUF_SIGSET_NWORDS \
+  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_JUMP_BUF_SIGSET_NWORDS];
+  } __jmp_buf_sigset_t;
+
+typedef union
+  {
+    __sigset_t __saved_mask_compat;
+    struct
+      {
+	__jmp_buf_sigset_t __saved_mask;
+	/* Paddings for target specific usage.  */
+	unsigned long int __padding[12];
+      } __saved;
+  } __jmpbuf_target_t;
+
+/* Saved signal mask.  */
+#define __saved_mask __target.__saved.__saved_mask
diff --git a/sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c b/sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c
index 874ed18d6b..658a25b87b 100644
--- a/sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c
+++ b/sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c
@@ -34,7 +34,8 @@ __libc_unwind_longjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
-- 
2.13.6

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-07 22:39 [PATCH 2/2] jmpbuf: Add paddings for target specific usage H.J. Lu
@ 2017-11-08  6:06 ` Florian Weimer
  2017-11-08 18:27   ` H.J. Lu
  0 siblings, 1 reply; 16+ messages in thread
From: Florian Weimer @ 2017-11-08  6:06 UTC (permalink / raw)
  To: H.J. Lu; +Cc: GNU C Library

On 11/07/2017 11:39 PM, H.J. Lu wrote:
> +typedef struct
> +  {
> +    __sigset_t __saved_mask;
> +  } __jmpbuf_target_t;

“Target” in the sense of “target architecture”, not “jump target”? 
Maybe it's better to pick a different name.

Should <bits/setjmp3.h> be a header under bits/types/ instead?

Thanks,
Florian

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-08  6:06 ` Florian Weimer
@ 2017-11-08 18:27   ` H.J. Lu
  2017-11-13 13:09     ` Florian Weimer
  0 siblings, 1 reply; 16+ messages in thread
From: H.J. Lu @ 2017-11-08 18:27 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library

[-- Attachment #1: Type: text/plain, Size: 637 bytes --]

On Tue, Nov 7, 2017 at 10:05 PM, Florian Weimer <fweimer@redhat.com> wrote:
> On 11/07/2017 11:39 PM, H.J. Lu wrote:
>>
>> +typedef struct
>> +  {
>> +    __sigset_t __saved_mask;
>> +  } __jmpbuf_target_t;
>
>
> “Target” in the sense of “target architecture”, not “jump target”? Maybe
> it's better to pick a different name.

I checked it to __jmpbuf_arch_t.

> Should <bits/setjmp3.h> be a header under bits/types/ instead?
>

I renamed it to bits/types/__jmpbuf_arch_t.h.

Here is the updated patch.  Tested with build-many-glibcs.py.

Are there any comments or objections?

Thanks.


-- 
H.J.

[-- Attachment #2: 0002-jmpbuf-Add-paddings-for-architecture-specific-usage.patch --]
[-- Type: text/x-patch, Size: 12116 bytes --]

From 21223ad34a68a2053a78efcee4856733eb4b46e0 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sat, 10 Jun 2017 17:23:06 -0700
Subject: [PATCH 2/2] jmpbuf: Add paddings for architecture specific usage

To support Shadow Stack (SHSTK) in Intel Control-flow Enforcement
Technology (CET) in setjmp/longjmp, we need to save shadow stack
pointer in jmp_buf.  The __saved_mask field in jmp_buf has type
of __sigset_t.  On Linux, __sigset_t is defined as

 #define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
  unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;

which is much bigger than expected by the __sigprocmask system call,
which has

typedef struct {
        unsigned long sig[_NSIG_WORDS];
} sigset_t;

We can shrink __sigset_t used by __saved_mask in jmp_buf to add paddings
for architecture specific usage.  As long as the new __sigset_t is not
smaller than sigset_t expected by the __sigprocmask system call, it should
work correctly.  This patch defines __jmp_buf_sigset_t for __saved_mask in
jmp_buf on Linux and verifies __jmp_buf_sigset_t has the suitable size
for the __sigprocmask system call.

Tested with build-many-glibcs.py.

	* bits/types/__jmpbuf_arch_t.h: New file.
	* sysdeps/unix/sysv/linux/bits/types/__jmpbuf_arch_t.h: Likewise.
	* include/setjmp.h [!_ISOMAC]: Include <signal.h>.
	[_NSIG] (_SIGPROCMASK_NSIG_WORDS): New.
	[_NSIG] (__sigprocmask_sigset_t): Likewise.
	[_NSIG] (do_test): Add _Static_assert for size of __saved_mask
	in jmp_buf >= sizeof __sigprocmask_sigset_t.
	* setjmp/Makefile (headers): Add bits/types/__jmpbuf_arch_t.h.
	* setjmp/longjmp.c (__libc_siglongjmp): Cast &env[0].__saved_mask
	to "sigset_t *".
	* setjmp/sigjmp.c (__sigjmp_save): Likewise.
	* sysdeps/powerpc/longjmp.c (__vmx__libc_siglongjmp): Likewise.
	* sysdeps/powerpc/novmx-longjmp.c (__novmx__libc_siglongjmp):
	Likewise.
	* sysdeps/powerpc/novmx-sigjmp.c (__novmx__sigjmp_save): Likewise.
	* sysdeps/powerpc/sigjmp.c (__vmx__sigjmp_save): Likewise.
	* sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c
	(__libc_unwind_longjmp): Likewise.
	* setjmp/setjmp.h: Include <bits/types/__jmpbuf_arch_t.h> instead
	of <bits/types/__sigset_t.h>.
	(__jmp_buf_tag): Change __saved_mask to __arch.
---
 bits/types/__jmpbuf_arch_t.h                       | 31 ++++++++++++++
 include/setjmp.h                                   | 15 +++++++
 setjmp/Makefile                                    |  3 +-
 setjmp/longjmp.c                                   |  3 +-
 setjmp/setjmp.h                                    |  4 +-
 setjmp/sigjmp.c                                    |  2 +-
 sysdeps/powerpc/longjmp.c                          |  3 +-
 sysdeps/powerpc/novmx-longjmp.c                    |  3 +-
 sysdeps/powerpc/novmx-sigjmp.c                     |  2 +-
 sysdeps/powerpc/sigjmp.c                           |  2 +-
 .../unix/sysv/linux/bits/types/__jmpbuf_arch_t.h   | 48 ++++++++++++++++++++++
 sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c      |  3 +-
 12 files changed, 109 insertions(+), 10 deletions(-)
 create mode 100644 bits/types/__jmpbuf_arch_t.h
 create mode 100644 sysdeps/unix/sysv/linux/bits/types/__jmpbuf_arch_t.h

diff --git a/bits/types/__jmpbuf_arch_t.h b/bits/types/__jmpbuf_arch_t.h
new file mode 100644
index 0000000000..05a69b42b0
--- /dev/null
+++ b/bits/types/__jmpbuf_arch_t.h
@@ -0,0 +1,31 @@
+/* Generic __jmpbuf_arch_t defition.
+   Copyright (C) 2017 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 _SETJMP_H
+# error "Never include <bits/types/__jmpbuf_arch_t.h directly; use <setjmp.h> instead."
+#endif
+
+#include <bits/types/__sigset_t.h>
+
+typedef struct
+  {
+    __sigset_t __saved_mask;
+  } __jmpbuf_arch_t;
+
+/* Saved signal mask.  */
+#define __saved_mask __arch.__saved_mask
diff --git a/include/setjmp.h b/include/setjmp.h
index f1b19f5ceb..91d916212c 100644
--- a/include/setjmp.h
+++ b/include/setjmp.h
@@ -33,6 +33,7 @@ extern __typeof (__sigsetjmp) __sigsetjmp attribute_hidden;
 # endif
 
 /* Check jmp_buf sizes, alignments and offsets.  */
+# include <signal.h>
 # include <stddef.h>
 # include <jmp_buf-macros.h>
 
@@ -65,6 +66,20 @@ TEST_OFFSET (struct __jmp_buf_tag, __mask_was_saved,
 	     MASK_WAS_SAVED_OFFSET);
 TEST_OFFSET (struct __jmp_buf_tag, __saved_mask,
 	     SAVED_MASK_OFFSET);
+
+# ifdef _NSIG
+#  define _SIGPROCMASK_NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_SIGPROCMASK_NSIG_WORDS];
+  } __sigprocmask_sigset_t;
+
+extern jmp_buf ___buf;
+extern  __typeof (___buf[0].__saved_mask) ___saved_mask;
+_Static_assert (sizeof (___saved_mask) >= sizeof (__sigprocmask_sigset_t),
+		"size of ___saved_mask < size of __sigprocmask_sigset_t");
+# endif
 #endif
 
 #endif
diff --git a/setjmp/Makefile b/setjmp/Makefile
index ca80b8ea13..24d1899825 100644
--- a/setjmp/Makefile
+++ b/setjmp/Makefile
@@ -22,7 +22,8 @@ subdir	:= setjmp
 
 include ../Makeconfig
 
-headers	:= setjmp.h bits/setjmp.h bits/setjmp2.h
+headers	:= setjmp.h bits/setjmp.h bits/setjmp2.h \
+	   bits/types/__jmpbuf_arch_t.h
 
 routines	:= setjmp sigjmp bsd-setjmp bsd-_setjmp \
 		   longjmp __longjmp jmp-unwind
diff --git a/setjmp/longjmp.c b/setjmp/longjmp.c
index 2453c2c124..86a024b4b8 100644
--- a/setjmp/longjmp.c
+++ b/setjmp/longjmp.c
@@ -31,7 +31,8 @@ __libc_siglongjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/setjmp/setjmp.h b/setjmp/setjmp.h
index 86fb2edf6c..56d2abd3fb 100644
--- a/setjmp/setjmp.h
+++ b/setjmp/setjmp.h
@@ -27,7 +27,7 @@
 __BEGIN_DECLS
 
 #include <bits/setjmp.h>		/* Get `__jmp_buf'.  */
-#include <bits/types/__sigset_t.h>
+#include <bits/types/__jmpbuf_arch_t.h>
 
 /* Calling environment, plus possibly a saved signal mask.  */
 struct __jmp_buf_tag
@@ -38,7 +38,7 @@ struct __jmp_buf_tag
        or add others before it.  */
     __jmp_buf __jmpbuf;		/* Calling environment.  */
     int __mask_was_saved;	/* Saved the signal mask?  */
-    __sigset_t __saved_mask;	/* Saved signal mask.  */
+    __jmpbuf_arch_t __arch;	/* Architecture specific data.  */
   };
 
 
diff --git a/setjmp/sigjmp.c b/setjmp/sigjmp.c
index 30839ae819..0cd733b3ee 100644
--- a/setjmp/sigjmp.c
+++ b/setjmp/sigjmp.c
@@ -28,7 +28,7 @@ __sigjmp_save (sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/sysdeps/powerpc/longjmp.c b/sysdeps/powerpc/longjmp.c
index bd3ed8c22b..a23f2c582b 100644
--- a/sysdeps/powerpc/longjmp.c
+++ b/sysdeps/powerpc/longjmp.c
@@ -39,7 +39,8 @@ __vmx__libc_siglongjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/sysdeps/powerpc/novmx-longjmp.c b/sysdeps/powerpc/novmx-longjmp.c
index b0020b728a..662fbc5432 100644
--- a/sysdeps/powerpc/novmx-longjmp.c
+++ b/sysdeps/powerpc/novmx-longjmp.c
@@ -37,7 +37,8 @@ __novmx__libc_siglongjmp (__novmx__sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/sysdeps/powerpc/novmx-sigjmp.c b/sysdeps/powerpc/novmx-sigjmp.c
index 7d0ae59437..62680fe38f 100644
--- a/sysdeps/powerpc/novmx-sigjmp.c
+++ b/sysdeps/powerpc/novmx-sigjmp.c
@@ -35,7 +35,7 @@ __novmx__sigjmp_save (__novmx__sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/sysdeps/powerpc/sigjmp.c b/sysdeps/powerpc/sigjmp.c
index 6d593a0992..736491eff9 100644
--- a/sysdeps/powerpc/sigjmp.c
+++ b/sysdeps/powerpc/sigjmp.c
@@ -31,7 +31,7 @@ __vmx__sigjmp_save (sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/sysdeps/unix/sysv/linux/bits/types/__jmpbuf_arch_t.h b/sysdeps/unix/sysv/linux/bits/types/__jmpbuf_arch_t.h
new file mode 100644
index 0000000000..bd75a6bce8
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/bits/types/__jmpbuf_arch_t.h
@@ -0,0 +1,48 @@
+/* __jmpbuf_arch_t defition for Linux.
+   Copyright (C) 2017 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 _SETJMP_H
+# error "Never include <bits/types/__jmpbuf_arch_t.h> directly; use <setjmp.h> instead."
+#endif
+
+#include <bits/types/__sigset_t.h>
+
+/* The biggest signal number + 1  */
+#define _JUMP_BUF_SIGSET_NSIG	257
+/* Number of longs to hold all signals.  */
+#define _JUMP_BUF_SIGSET_NWORDS \
+  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_JUMP_BUF_SIGSET_NWORDS];
+  } __jmp_buf_sigset_t;
+
+typedef union
+  {
+    __sigset_t __saved_mask_compat;
+    struct
+      {
+	__jmp_buf_sigset_t __saved_mask;
+	/* Paddings for target specific usage.  */
+	unsigned long int __padding[12];
+      } __saved;
+  } __jmpbuf_arch_t;
+
+/* Saved signal mask.  */
+#define __saved_mask __arch.__saved.__saved_mask
diff --git a/sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c b/sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c
index 874ed18d6b..658a25b87b 100644
--- a/sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c
+++ b/sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c
@@ -34,7 +34,8 @@ __libc_unwind_longjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
-- 
2.13.6


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-08 18:27   ` H.J. Lu
@ 2017-11-13 13:09     ` Florian Weimer
  2017-11-13 14:05       ` H.J. Lu
  0 siblings, 1 reply; 16+ messages in thread
From: Florian Weimer @ 2017-11-13 13:09 UTC (permalink / raw)
  To: H.J. Lu; +Cc: GNU C Library

On 11/08/2017 07:27 PM, H.J. Lu wrote:
> +/* The biggest signal number + 1  */
> +#define _JUMP_BUF_SIGSET_NSIG	257
> +/* Number of longs to hold all signals.  */
> +#define _JUMP_BUF_SIGSET_NWORDS \
> +  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))

Where does 257 come from?  65 or 129 I would understand considering the 
kernel sources, but 257 is odd.

I think it would be clearer to hard-code the array sizes and explain why 
the values where chosen in that way.

We also need a test that setprocmask does not read from the previously 
unused part.  I can move the existing next_to_fault bits to support/ if 
that would help.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-13 13:09     ` Florian Weimer
@ 2017-11-13 14:05       ` H.J. Lu
  2017-11-13 16:34         ` Florian Weimer
  0 siblings, 1 reply; 16+ messages in thread
From: H.J. Lu @ 2017-11-13 14:05 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library

On Mon, Nov 13, 2017 at 5:09 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 11/08/2017 07:27 PM, H.J. Lu wrote:
>>
>> +/* The biggest signal number + 1  */
>> +#define _JUMP_BUF_SIGSET_NSIG  257
>> +/* Number of longs to hold all signals.  */
>> +#define _JUMP_BUF_SIGSET_NWORDS \
>> +  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
>
>
> Where does 257 come from?  65 or 129 I would understand considering the
> kernel sources, but 257 is odd.

I picked 257 to leave some room
> I think it would be clearer to hard-code the array sizes and explain why the
> values where chosen in that way.
>
> We also need a test that setprocmask does not read from the previously

Did you mean "sigprocmask"?

> unused part.  I can move the existing next_to_fault bits to support/ if that
> would help.

Yes, please.

Thanks.

-- 
H.J.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-13 14:05       ` H.J. Lu
@ 2017-11-13 16:34         ` Florian Weimer
  2017-11-13 16:44           ` H.J. Lu
  0 siblings, 1 reply; 16+ messages in thread
From: Florian Weimer @ 2017-11-13 16:34 UTC (permalink / raw)
  To: H.J. Lu; +Cc: GNU C Library

On 11/13/2017 03:05 PM, H.J. Lu wrote:
> On Mon, Nov 13, 2017 at 5:09 AM, Florian Weimer <fweimer@redhat.com> wrote:
>> On 11/08/2017 07:27 PM, H.J. Lu wrote:
>>>
>>> +/* The biggest signal number + 1  */
>>> +#define _JUMP_BUF_SIGSET_NSIG  257
>>> +/* Number of longs to hold all signals.  */
>>> +#define _JUMP_BUF_SIGSET_NWORDS \
>>> +  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
>>
>>
>> Where does 257 come from?  65 or 129 I would understand considering the
>> kernel sources, but 257 is odd.

Oh.  I'm not sure if we should put this into installed header.

Maybe we can use a different approach?  Something similar to the pthread 
types?  Or just not change the external type at all and just ad some 
internal space reuse mechanism?

We had problems with people poking at supposedly invisible jmpbuf 
contents in the past, and I'm worried that adding even __ members will 
encourage that.

>> I think it would be clearer to hard-code the array sizes and explain why the
>> values where chosen in that way.
>>
>> We also need a test that setprocmask does not read from the previously
> 
> Did you mean "sigprocmask"?

Right.

>> unused part.  I can move the existing next_to_fault bits to support/ if that
>> would help.
> 
> Yes, please.

Okay, I'll move it to support/ soon.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-13 16:34         ` Florian Weimer
@ 2017-11-13 16:44           ` H.J. Lu
  2017-11-13 19:40             ` H.J. Lu
  0 siblings, 1 reply; 16+ messages in thread
From: H.J. Lu @ 2017-11-13 16:44 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library

On Mon, Nov 13, 2017 at 8:34 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 11/13/2017 03:05 PM, H.J. Lu wrote:
>>
>> On Mon, Nov 13, 2017 at 5:09 AM, Florian Weimer <fweimer@redhat.com>
>> wrote:
>>>
>>> On 11/08/2017 07:27 PM, H.J. Lu wrote:
>>>>
>>>>
>>>> +/* The biggest signal number + 1  */
>>>> +#define _JUMP_BUF_SIGSET_NSIG  257
>>>> +/* Number of longs to hold all signals.  */
>>>> +#define _JUMP_BUF_SIGSET_NWORDS \
>>>> +  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
>>>
>>>
>>>
>>> Where does 257 come from?  65 or 129 I would understand considering the
>>> kernel sources, but 257 is odd.
>
>
> Oh.  I'm not sure if we should put this into installed header.
>
> Maybe we can use a different approach?  Something similar to the pthread
> types?  Or just not change the external type at all and just ad some
> internal space reuse mechanism?

I will see what I can do.

> We had problems with people poking at supposedly invisible jmpbuf contents
> in the past, and I'm worried that adding even __ members will encourage
> that.
>
>>> I think it would be clearer to hard-code the array sizes and explain why
>>> the
>>> values where chosen in that way.
>>>
>>> We also need a test that setprocmask does not read from the previously
>>
>>
>> Did you mean "sigprocmask"?
>
>
> Right.
>
>>> unused part.  I can move the existing next_to_fault bits to support/ if
>>> that
>>> would help.
>>
>>
>> Yes, please.
>
>
> Okay, I'll move it to support/ soon.
>

Here is what the test will look like

static int
do_test (void)
{
  struct __jmp_buf_tag *sj = memory from next_to_fault
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
"SJ" will point to the end of page in such a way that sigprocmask
will fail if it reads beyond the actual __saved_mask.

  sigset_t m;

  sigemptyset (&m);
  sigprocmask (SIG_SETMASK, &m, NULL);
  if (sigsetjmp (sj, 0) == 0)
    {
      sigaddset (&m, SIGUSR1);
      sigprocmask (SIG_SETMASK, &m, NULL);
      siglongjmp (sj, 1);
      return EXIT_FAILURE;
    }
  sigprocmask (SIG_SETMASK, NULL, &m);
  return sigismember (&m, SIGUSR1) ? EXIT_SUCCESS : EXIT_FAILURE;
}

#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

Thanks.

-- 
H.J.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-13 16:44           ` H.J. Lu
@ 2017-11-13 19:40             ` H.J. Lu
  2017-11-13 23:22               ` H.J. Lu
  0 siblings, 1 reply; 16+ messages in thread
From: H.J. Lu @ 2017-11-13 19:40 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library

[-- Attachment #1: Type: text/plain, Size: 2182 bytes --]

On Mon, Nov 13, 2017 at 8:44 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Mon, Nov 13, 2017 at 8:34 AM, Florian Weimer <fweimer@redhat.com> wrote:
>> On 11/13/2017 03:05 PM, H.J. Lu wrote:
>>>
>>> On Mon, Nov 13, 2017 at 5:09 AM, Florian Weimer <fweimer@redhat.com>
>>> wrote:
>>>>
>>>> On 11/08/2017 07:27 PM, H.J. Lu wrote:
>>>>>
>>>>>
>>>>> +/* The biggest signal number + 1  */
>>>>> +#define _JUMP_BUF_SIGSET_NSIG  257
>>>>> +/* Number of longs to hold all signals.  */
>>>>> +#define _JUMP_BUF_SIGSET_NWORDS \
>>>>> +  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
>>>>
>>>>
>>>>
>>>> Where does 257 come from?  65 or 129 I would understand considering the
>>>> kernel sources, but 257 is odd.
>>
>>
>> Oh.  I'm not sure if we should put this into installed header.
>>
>> Maybe we can use a different approach?  Something similar to the pthread
>> types?  Or just not change the external type at all and just ad some
>> internal space reuse mechanism?
>
> I will see what I can do.
>
>> We had problems with people poking at supposedly invisible jmpbuf contents
>> in the past, and I'm worried that adding even __ members will encourage
>> that.
>>
>>>> I think it would be clearer to hard-code the array sizes and explain why
>>>> the
>>>> values where chosen in that way.
>>>>
>>>> We also need a test that setprocmask does not read from the previously
>>>
>>>
>>> Did you mean "sigprocmask"?
>>
>>
>> Right.
>>
>>>> unused part.  I can move the existing next_to_fault bits to support/ if
>>>> that
>>>> would help.
>>>
>>>
>>> Yes, please.
>>
>>
>> Okay, I'll move it to support/ soon.
>>
>

Here is the updated patch to add <setjmpP.h>.  I added a test:

  struct support_next_to_fault jmpbuf
    = support_next_to_fault_allocate (SAVED_MASK_OFFSET + (_NSIG / 8));
  struct __jmp_buf_tag *sj = (struct __jmp_buf_tag *) jmpbuf.buffer;

  errno = 0;
  if (sigsetjmp (sj, 1) == 0)
    {
      siglongjmp (sj, 1);
      return EXIT_FAILURE;
    }
  if (errno != 0)
    {
      printf ("sigsetjmp: %s\n", strerror (errno));
      return EXIT_FAILURE;
    }

to verify that __sigprocmask won't read beyond _NSIG / 8.

Does it look OK?

Thanks.

-- 
H.J.

[-- Attachment #2: 0001-jmpbuf-Add-paddings-for-architecture-specific-usage.patch --]
[-- Type: text/x-patch, Size: 17631 bytes --]

From fe74415d7c260b11af530d71f6e1c730374978a6 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sat, 10 Jun 2017 17:23:06 -0700
Subject: [PATCH] jmpbuf: Add paddings for architecture specific usage

To support Shadow Stack (SHSTK) in Intel Control-flow Enforcement
Technology (CET) in setjmp/longjmp, we need to save shadow stack
pointer in jmp_buf.  The __saved_mask field in jmp_buf has type
of __sigset_t.  On Linux, __sigset_t is defined as

 #define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
  unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;

which is much bigger than expected by the __sigprocmask system call,
which has

typedef struct {
        unsigned long sig[_NSIG_WORDS];
} sigset_t;

We can shrink __sigset_t used by __saved_mask in jmp_buf to add paddings
for architecture specific usage.  As long as the new __sigset_t is not
smaller than sigset_t expected by the __sigprocmask system call, it should
work correctly.  This patch adds an internal header file, <setjmpP.h>,
to define __jmp_buf_sigset_t for __saved_mask in jmp_buf on Linux and
verifies __jmp_buf_sigset_t has the suitable size for the __sigprocmask
system call.

Tested with build-many-glibcs.py.

	* debug/longjmp_chk.c: Include <setjmpP.h> instead of
	<setjmp.h>.
	* include/setjmpP.h: New file.
	* setjmp/setjmpP.h: Likewise.
	* sysdeps/generic/__jmpbuf_arch_t.h: Likewise.
	* sysdeps/generic/__saved_mask.h: Likewise.
	* sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h: Likewise.
	* sysdeps/unix/sysv/linux/__saved_mask.h: Likewise.
	* setjmp/tst-sigsetjmp2.c: Likewise.
	* include/setjmp.h: [!_ISOMAC]: Include <signal.h>.
	[_NSIG] (_SIGPROCMASK_NSIG_WORDS): New.
	[_NSIG] (__sigprocmask_sigset_t): Likewise.
	[_NSIG] (do_test): Add _Static_assert for size of __saved_mask
	in jmp_buf >= sizeof __sigprocmask_sigset_t.
	* setjmp/Makefile (tests): Add tst-sigsetjmp2.
	* setjmp/longjmp.c: Include <setjmpP.h> instead of <setjmp.h>.
	(__libc_siglongjmp): Cast &env[0].__saved_mask to "sigset_t *".
	* setjmp/sigjmp.c: Include <setjmpP.h> instead of <setjmp.h>.
	(__sigjmp_save): Cast &env[0].__saved_mask to "sigset_t *".
	* sysdeps/powerpc/longjmp.c: Include <setjmpP.h> instead of
	<setjmp.h>.
	(__vmx__libc_siglongjmp): Cast &env[0].__saved_mask to
	"sigset_t *".
	* sysdeps/powerpc/sigjmp.c: Include <setjmpP.h> instead of
	<setjmp.h>.
	(__vmx__sigjmp_save): Cast &env[0].__saved_mask to "sigset_t *".
	* sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c: Include
	<setjmpP.h> instead of <setjmp.h>.
	(__libc_unwind_longjmp): Cast &env[0].__saved_mask to "sigset_t *".
---
 debug/longjmp_chk.c                           |  2 +-
 include/setjmp.h                              | 15 ++++++++
 include/setjmpP.h                             |  1 +
 setjmp/Makefile                               |  2 +-
 setjmp/longjmp.c                              |  5 +--
 setjmp/setjmpP.h                              | 32 +++++++++++++++++
 setjmp/sigjmp.c                               |  4 +--
 setjmp/tst-sigsetjmp2.c                       | 50 +++++++++++++++++++++++++++
 sysdeps/generic/__jmpbuf_arch_t.h             | 24 +++++++++++++
 sysdeps/generic/__saved_mask.h                | 20 +++++++++++
 sysdeps/powerpc/longjmp.c                     |  5 +--
 sysdeps/powerpc/sigjmp.c                      |  4 +--
 sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h     | 43 +++++++++++++++++++++++
 sysdeps/unix/sysv/linux/__saved_mask.h        | 20 +++++++++++
 sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c |  5 +--
 15 files changed, 220 insertions(+), 12 deletions(-)
 create mode 100644 include/setjmpP.h
 create mode 100644 setjmp/setjmpP.h
 create mode 100644 setjmp/tst-sigsetjmp2.c
 create mode 100644 sysdeps/generic/__jmpbuf_arch_t.h
 create mode 100644 sysdeps/generic/__saved_mask.h
 create mode 100644 sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h
 create mode 100644 sysdeps/unix/sysv/linux/__saved_mask.h

diff --git a/debug/longjmp_chk.c b/debug/longjmp_chk.c
index 1cea6c05ef..61be0da0cd 100644
--- a/debug/longjmp_chk.c
+++ b/debug/longjmp_chk.c
@@ -15,7 +15,7 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <setjmp.h>
+#include <setjmpP.h>
 
 #define __longjmp ____longjmp_chk
 #define __libc_siglongjmp __longjmp_chk
diff --git a/include/setjmp.h b/include/setjmp.h
index f1b19f5ceb..91d916212c 100644
--- a/include/setjmp.h
+++ b/include/setjmp.h
@@ -33,6 +33,7 @@ extern __typeof (__sigsetjmp) __sigsetjmp attribute_hidden;
 # endif
 
 /* Check jmp_buf sizes, alignments and offsets.  */
+# include <signal.h>
 # include <stddef.h>
 # include <jmp_buf-macros.h>
 
@@ -65,6 +66,20 @@ TEST_OFFSET (struct __jmp_buf_tag, __mask_was_saved,
 	     MASK_WAS_SAVED_OFFSET);
 TEST_OFFSET (struct __jmp_buf_tag, __saved_mask,
 	     SAVED_MASK_OFFSET);
+
+# ifdef _NSIG
+#  define _SIGPROCMASK_NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_SIGPROCMASK_NSIG_WORDS];
+  } __sigprocmask_sigset_t;
+
+extern jmp_buf ___buf;
+extern  __typeof (___buf[0].__saved_mask) ___saved_mask;
+_Static_assert (sizeof (___saved_mask) >= sizeof (__sigprocmask_sigset_t),
+		"size of ___saved_mask < size of __sigprocmask_sigset_t");
+# endif
 #endif
 
 #endif
diff --git a/include/setjmpP.h b/include/setjmpP.h
new file mode 100644
index 0000000000..8aa6a25957
--- /dev/null
+++ b/include/setjmpP.h
@@ -0,0 +1 @@
+#include <setjmp/setjmpP.h>
diff --git a/setjmp/Makefile b/setjmp/Makefile
index ca80b8ea13..e0a1f4a30b 100644
--- a/setjmp/Makefile
+++ b/setjmp/Makefile
@@ -28,7 +28,7 @@ routines	:= setjmp sigjmp bsd-setjmp bsd-_setjmp \
 		   longjmp __longjmp jmp-unwind
 
 tests		:= tst-setjmp jmpbug bug269-setjmp tst-setjmp-fp \
-		   tst-sigsetjmp tst-setjmp-static
+		   tst-sigsetjmp tst-setjmp-static tst-sigsetjmp2
 tests-static	:= tst-setjmp-static
 
 
diff --git a/setjmp/longjmp.c b/setjmp/longjmp.c
index 2453c2c124..e144a874d7 100644
--- a/setjmp/longjmp.c
+++ b/setjmp/longjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 
@@ -31,7 +31,8 @@ __libc_siglongjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/setjmp/setjmpP.h b/setjmp/setjmpP.h
new file mode 100644
index 0000000000..e65d72b654
--- /dev/null
+++ b/setjmp/setjmpP.h
@@ -0,0 +1,32 @@
+/* Internal __sigset_t type used in struct __jmp_buf_tag.
+   Copyright (C) 2017 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/>.  */
+
+/*
+ *	ISO C99 Standard: 7.13 Nonlocal jumps	<setjmp.h>
+ */
+
+#ifndef	_SETJMPP_H
+#define	_SETJMPP_H	1
+
+#include <__jmpbuf_arch_t.h>
+#undef __sigset_t
+#define __sigset_t __jmpbuf_arch_t
+#include <setjmp.h>
+#include <__saved_mask.h>
+
+#endif /* setjmpP.h  */
diff --git a/setjmp/sigjmp.c b/setjmp/sigjmp.c
index 30839ae819..32b727fae8 100644
--- a/setjmp/sigjmp.c
+++ b/setjmp/sigjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 /* This function is called by the `sigsetjmp' macro
@@ -28,7 +28,7 @@ __sigjmp_save (sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/setjmp/tst-sigsetjmp2.c b/setjmp/tst-sigsetjmp2.c
new file mode 100644
index 0000000000..131531feb0
--- /dev/null
+++ b/setjmp/tst-sigsetjmp2.c
@@ -0,0 +1,50 @@
+/* Test that sigprocmask does not read from the unused part of jmpbuf.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <jmp_buf-macros.h>
+#include <support/next_to_fault.h>
+
+static int
+do_test (void)
+{
+  struct support_next_to_fault jmpbuf
+    = support_next_to_fault_allocate (SAVED_MASK_OFFSET + (_NSIG / 8));
+  struct __jmp_buf_tag *sj = (struct __jmp_buf_tag *) jmpbuf.buffer;
+
+  errno = 0;
+  if (sigsetjmp (sj, 1) == 0)
+    {
+      siglongjmp (sj, 1);
+      return EXIT_FAILURE;
+    }
+  if (errno != 0)
+    {
+      printf ("sigsetjmp: %s\n", strerror (errno));
+      return EXIT_FAILURE;
+    }
+  return EXIT_SUCCESS;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/sysdeps/generic/__jmpbuf_arch_t.h b/sysdeps/generic/__jmpbuf_arch_t.h
new file mode 100644
index 0000000000..b663202a82
--- /dev/null
+++ b/sysdeps/generic/__jmpbuf_arch_t.h
@@ -0,0 +1,24 @@
+/* Generic __jmpbuf_arch_t defition.
+   Copyright (C) 2017 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 <bits/types/__sigset_t.h>
+
+typedef struct
+  {
+    __sigset_t __saved_mask;
+  } __jmpbuf_arch_t;
diff --git a/sysdeps/generic/__saved_mask.h b/sysdeps/generic/__saved_mask.h
new file mode 100644
index 0000000000..5a59d5f385
--- /dev/null
+++ b/sysdeps/generic/__saved_mask.h
@@ -0,0 +1,20 @@
+/* Generic __saved_mask defition.
+   Copyright (C) 2017 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/>.  */
+
+/* Saved signal mask.  */
+#define __saved_mask __saved_mask.__saved_mask
diff --git a/sysdeps/powerpc/longjmp.c b/sysdeps/powerpc/longjmp.c
index bd3ed8c22b..c22915fc11 100644
--- a/sysdeps/powerpc/longjmp.c
+++ b/sysdeps/powerpc/longjmp.c
@@ -19,7 +19,7 @@
 
 #include  <shlib-compat.h>
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 extern void __vmx__longjmp (__jmp_buf __env, int __val)
@@ -39,7 +39,8 @@ __vmx__libc_siglongjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/sysdeps/powerpc/sigjmp.c b/sysdeps/powerpc/sigjmp.c
index 6d593a0992..cd35b751ed 100644
--- a/sysdeps/powerpc/sigjmp.c
+++ b/sysdeps/powerpc/sigjmp.c
@@ -19,7 +19,7 @@
 
 #include  <shlib-compat.h>
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 /* This function is called by the `sigsetjmp' macro
@@ -31,7 +31,7 @@ __vmx__sigjmp_save (sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h b/sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h
new file mode 100644
index 0000000000..e2372e898b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h
@@ -0,0 +1,43 @@
+/* __jmpbuf_arch_t defition for Linux.
+   Copyright (C) 2017 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 <bits/types/__sigset_t.h>
+
+/* The biggest signal number + 1.  As of kernel 4.13, the maximum number
+   of signals is 128 on MIPS.  Define it to 257 to leave some rooms for
+   the future.  */
+#define _JUMP_BUF_SIGSET_NSIG	257
+/* Number of longs to hold all signals.  */
+#define _JUMP_BUF_SIGSET_NWORDS \
+  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_JUMP_BUF_SIGSET_NWORDS];
+  } __jmp_buf_sigset_t;
+
+typedef union
+  {
+    __sigset_t __saved_mask_compat;
+    struct
+      {
+	__jmp_buf_sigset_t __saved_mask;
+	/* Paddings for architecture specific usage.  */
+	unsigned long int __padding[12];
+      } __saved;
+  } __jmpbuf_arch_t;
diff --git a/sysdeps/unix/sysv/linux/__saved_mask.h b/sysdeps/unix/sysv/linux/__saved_mask.h
new file mode 100644
index 0000000000..fcc7c26c9b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/__saved_mask.h
@@ -0,0 +1,20 @@
+/* __saved_mask defition for Linux.
+   Copyright (C) 2017 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/>.  */
+
+/* Saved signal mask.  */
+#define __saved_mask __saved_mask.__saved.__saved_mask
diff --git a/sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c b/sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c
index 874ed18d6b..2711e083cb 100644
--- a/sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c
+++ b/sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 #include <pthreadP.h>
 #include <jmpbuf-unwind.h>
@@ -34,7 +34,8 @@ __libc_unwind_longjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
-- 
2.13.6


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-13 19:40             ` H.J. Lu
@ 2017-11-13 23:22               ` H.J. Lu
  2017-11-14 12:26                 ` Florian Weimer
  0 siblings, 1 reply; 16+ messages in thread
From: H.J. Lu @ 2017-11-13 23:22 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library

[-- Attachment #1: Type: text/plain, Size: 2437 bytes --]

On Mon, Nov 13, 2017 at 11:40 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Mon, Nov 13, 2017 at 8:44 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Mon, Nov 13, 2017 at 8:34 AM, Florian Weimer <fweimer@redhat.com> wrote:
>>> On 11/13/2017 03:05 PM, H.J. Lu wrote:
>>>>
>>>> On Mon, Nov 13, 2017 at 5:09 AM, Florian Weimer <fweimer@redhat.com>
>>>> wrote:
>>>>>
>>>>> On 11/08/2017 07:27 PM, H.J. Lu wrote:
>>>>>>
>>>>>>
>>>>>> +/* The biggest signal number + 1  */
>>>>>> +#define _JUMP_BUF_SIGSET_NSIG  257
>>>>>> +/* Number of longs to hold all signals.  */
>>>>>> +#define _JUMP_BUF_SIGSET_NWORDS \
>>>>>> +  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
>>>>>
>>>>>
>>>>>
>>>>> Where does 257 come from?  65 or 129 I would understand considering the
>>>>> kernel sources, but 257 is odd.
>>>
>>>
>>> Oh.  I'm not sure if we should put this into installed header.
>>>
>>> Maybe we can use a different approach?  Something similar to the pthread
>>> types?  Or just not change the external type at all and just ad some
>>> internal space reuse mechanism?
>>
>> I will see what I can do.
>>
>>> We had problems with people poking at supposedly invisible jmpbuf contents
>>> in the past, and I'm worried that adding even __ members will encourage
>>> that.
>>>
>>>>> I think it would be clearer to hard-code the array sizes and explain why
>>>>> the
>>>>> values where chosen in that way.
>>>>>
>>>>> We also need a test that setprocmask does not read from the previously
>>>>
>>>>
>>>> Did you mean "sigprocmask"?
>>>
>>>
>>> Right.
>>>
>>>>> unused part.  I can move the existing next_to_fault bits to support/ if
>>>>> that
>>>>> would help.
>>>>
>>>>
>>>> Yes, please.
>>>
>>>
>>> Okay, I'll move it to support/ soon.
>>>
>>
>
> Here is the updated patch to add <setjmpP.h>.  I added a test:
>
>   struct support_next_to_fault jmpbuf
>     = support_next_to_fault_allocate (SAVED_MASK_OFFSET + (_NSIG / 8));
>   struct __jmp_buf_tag *sj = (struct __jmp_buf_tag *) jmpbuf.buffer;
>
>   errno = 0;
>   if (sigsetjmp (sj, 1) == 0)
>     {
>       siglongjmp (sj, 1);
>       return EXIT_FAILURE;
>     }
>   if (errno != 0)
>     {
>       printf ("sigsetjmp: %s\n", strerror (errno));
>       return EXIT_FAILURE;
>     }
>
> to verify that __sigprocmask won't read beyond _NSIG / 8.
>
> Does it look OK?
>

This is the updated patch.  Tested with build-many-glibcs.py.

Any other comments?

Thanks.


-- 
H.J.

[-- Attachment #2: 0001-jmpbuf-Add-paddings-for-architecture-specific-usage.patch --]
[-- Type: text/x-patch, Size: 15484 bytes --]

From 2bad2646b07903c0e9ba5b63656c5d2bbae4f6cf Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sat, 10 Jun 2017 17:23:06 -0700
Subject: [PATCH] jmpbuf: Add paddings for architecture specific usage

To support Shadow Stack (SHSTK) in Intel Control-flow Enforcement
Technology (CET) in setjmp/longjmp, we need to save shadow stack
pointer in jmp_buf.  The __saved_mask field in jmp_buf has type
of __sigset_t.  On Linux, __sigset_t is defined as

 #define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
  unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;

which is much bigger than expected by the __sigprocmask system call,
which has

typedef struct {
        unsigned long sig[_NSIG_WORDS];
} sigset_t;

We can shrink __sigset_t used by __saved_mask in jmp_buf to add paddings
for architecture specific usage.  As long as the new __sigset_t is not
smaller than sigset_t expected by the __sigprocmask system call, it should
work correctly.  This patch adds an internal header file, <setjmpP.h>,
to define __jmp_buf_sigset_t for __saved_mask in jmp_buf on Linux and
verifies __jmp_buf_sigset_t has the suitable size for the __sigprocmask
system call.

Tested with build-many-glibcs.py.

	* debug/longjmp_chk.c: Include <setjmpP.h> instead of
	<setjmp.h>.
	* sysdeps/unix/sysv/linux/s390/longjmp_chk.c: Likewise.
	* include/setjmpP.h: New file.
	* setjmp/setjmpP.h: Likewise.
	* sysdeps/generic/__jmpbuf_arch_t.h: Likewise.
	* sysdeps/generic/__saved_mask.h: Likewise.
	* sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h: Likewise.
	* sysdeps/unix/sysv/linux/__saved_mask.h: Likewise.
	* setjmp/tst-sigsetjmp2.c: Likewise.
	* include/setjmp.h: [!_ISOMAC]: Include <signal.h>.
	[_NSIG] (_SIGPROCMASK_NSIG_WORDS): New.
	[_NSIG] (__sigprocmask_sigset_t): Likewise.
	[_NSIG] (do_test): Add _Static_assert for size of __saved_mask
	in jmp_buf >= sizeof __sigprocmask_sigset_t.
	* setjmp/Makefile (tests): Add tst-sigsetjmp2.
	* setjmp/longjmp.c: Include <setjmpP.h> instead of <setjmp.h>.
	(__libc_siglongjmp): Cast &env[0].__saved_mask to "sigset_t *".
	* setjmp/sigjmp.c: Include <setjmpP.h> instead of <setjmp.h>.
	(__sigjmp_save): Cast &env[0].__saved_mask to "sigset_t *".
---
 debug/longjmp_chk.c                        |  2 +-
 include/setjmp.h                           | 15 +++++++++
 include/setjmpP.h                          |  1 +
 setjmp/Makefile                            |  2 +-
 setjmp/longjmp.c                           |  5 +--
 setjmp/setjmpP.h                           | 32 +++++++++++++++++++
 setjmp/sigjmp.c                            |  4 +--
 setjmp/tst-sigsetjmp2.c                    | 50 ++++++++++++++++++++++++++++++
 sysdeps/generic/__jmpbuf_arch_t.h          | 24 ++++++++++++++
 sysdeps/generic/__saved_mask.h             | 20 ++++++++++++
 sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h  | 43 +++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/__saved_mask.h     | 20 ++++++++++++
 sysdeps/unix/sysv/linux/s390/longjmp_chk.c |  2 +-
 13 files changed, 213 insertions(+), 7 deletions(-)
 create mode 100644 include/setjmpP.h
 create mode 100644 setjmp/setjmpP.h
 create mode 100644 setjmp/tst-sigsetjmp2.c
 create mode 100644 sysdeps/generic/__jmpbuf_arch_t.h
 create mode 100644 sysdeps/generic/__saved_mask.h
 create mode 100644 sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h
 create mode 100644 sysdeps/unix/sysv/linux/__saved_mask.h

diff --git a/debug/longjmp_chk.c b/debug/longjmp_chk.c
index 1cea6c05ef..61be0da0cd 100644
--- a/debug/longjmp_chk.c
+++ b/debug/longjmp_chk.c
@@ -15,7 +15,7 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <setjmp.h>
+#include <setjmpP.h>
 
 #define __longjmp ____longjmp_chk
 #define __libc_siglongjmp __longjmp_chk
diff --git a/include/setjmp.h b/include/setjmp.h
index f1b19f5ceb..91d916212c 100644
--- a/include/setjmp.h
+++ b/include/setjmp.h
@@ -33,6 +33,7 @@ extern __typeof (__sigsetjmp) __sigsetjmp attribute_hidden;
 # endif
 
 /* Check jmp_buf sizes, alignments and offsets.  */
+# include <signal.h>
 # include <stddef.h>
 # include <jmp_buf-macros.h>
 
@@ -65,6 +66,20 @@ TEST_OFFSET (struct __jmp_buf_tag, __mask_was_saved,
 	     MASK_WAS_SAVED_OFFSET);
 TEST_OFFSET (struct __jmp_buf_tag, __saved_mask,
 	     SAVED_MASK_OFFSET);
+
+# ifdef _NSIG
+#  define _SIGPROCMASK_NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_SIGPROCMASK_NSIG_WORDS];
+  } __sigprocmask_sigset_t;
+
+extern jmp_buf ___buf;
+extern  __typeof (___buf[0].__saved_mask) ___saved_mask;
+_Static_assert (sizeof (___saved_mask) >= sizeof (__sigprocmask_sigset_t),
+		"size of ___saved_mask < size of __sigprocmask_sigset_t");
+# endif
 #endif
 
 #endif
diff --git a/include/setjmpP.h b/include/setjmpP.h
new file mode 100644
index 0000000000..8aa6a25957
--- /dev/null
+++ b/include/setjmpP.h
@@ -0,0 +1 @@
+#include <setjmp/setjmpP.h>
diff --git a/setjmp/Makefile b/setjmp/Makefile
index ca80b8ea13..e0a1f4a30b 100644
--- a/setjmp/Makefile
+++ b/setjmp/Makefile
@@ -28,7 +28,7 @@ routines	:= setjmp sigjmp bsd-setjmp bsd-_setjmp \
 		   longjmp __longjmp jmp-unwind
 
 tests		:= tst-setjmp jmpbug bug269-setjmp tst-setjmp-fp \
-		   tst-sigsetjmp tst-setjmp-static
+		   tst-sigsetjmp tst-setjmp-static tst-sigsetjmp2
 tests-static	:= tst-setjmp-static
 
 
diff --git a/setjmp/longjmp.c b/setjmp/longjmp.c
index 2453c2c124..e144a874d7 100644
--- a/setjmp/longjmp.c
+++ b/setjmp/longjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 
@@ -31,7 +31,8 @@ __libc_siglongjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/setjmp/setjmpP.h b/setjmp/setjmpP.h
new file mode 100644
index 0000000000..e65d72b654
--- /dev/null
+++ b/setjmp/setjmpP.h
@@ -0,0 +1,32 @@
+/* Internal __sigset_t type used in struct __jmp_buf_tag.
+   Copyright (C) 2017 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/>.  */
+
+/*
+ *	ISO C99 Standard: 7.13 Nonlocal jumps	<setjmp.h>
+ */
+
+#ifndef	_SETJMPP_H
+#define	_SETJMPP_H	1
+
+#include <__jmpbuf_arch_t.h>
+#undef __sigset_t
+#define __sigset_t __jmpbuf_arch_t
+#include <setjmp.h>
+#include <__saved_mask.h>
+
+#endif /* setjmpP.h  */
diff --git a/setjmp/sigjmp.c b/setjmp/sigjmp.c
index 30839ae819..32b727fae8 100644
--- a/setjmp/sigjmp.c
+++ b/setjmp/sigjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 /* This function is called by the `sigsetjmp' macro
@@ -28,7 +28,7 @@ __sigjmp_save (sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/setjmp/tst-sigsetjmp2.c b/setjmp/tst-sigsetjmp2.c
new file mode 100644
index 0000000000..131531feb0
--- /dev/null
+++ b/setjmp/tst-sigsetjmp2.c
@@ -0,0 +1,50 @@
+/* Test that sigprocmask does not read from the unused part of jmpbuf.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <jmp_buf-macros.h>
+#include <support/next_to_fault.h>
+
+static int
+do_test (void)
+{
+  struct support_next_to_fault jmpbuf
+    = support_next_to_fault_allocate (SAVED_MASK_OFFSET + (_NSIG / 8));
+  struct __jmp_buf_tag *sj = (struct __jmp_buf_tag *) jmpbuf.buffer;
+
+  errno = 0;
+  if (sigsetjmp (sj, 1) == 0)
+    {
+      siglongjmp (sj, 1);
+      return EXIT_FAILURE;
+    }
+  if (errno != 0)
+    {
+      printf ("sigsetjmp: %s\n", strerror (errno));
+      return EXIT_FAILURE;
+    }
+  return EXIT_SUCCESS;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/sysdeps/generic/__jmpbuf_arch_t.h b/sysdeps/generic/__jmpbuf_arch_t.h
new file mode 100644
index 0000000000..b663202a82
--- /dev/null
+++ b/sysdeps/generic/__jmpbuf_arch_t.h
@@ -0,0 +1,24 @@
+/* Generic __jmpbuf_arch_t defition.
+   Copyright (C) 2017 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 <bits/types/__sigset_t.h>
+
+typedef struct
+  {
+    __sigset_t __saved_mask;
+  } __jmpbuf_arch_t;
diff --git a/sysdeps/generic/__saved_mask.h b/sysdeps/generic/__saved_mask.h
new file mode 100644
index 0000000000..5a59d5f385
--- /dev/null
+++ b/sysdeps/generic/__saved_mask.h
@@ -0,0 +1,20 @@
+/* Generic __saved_mask defition.
+   Copyright (C) 2017 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/>.  */
+
+/* Saved signal mask.  */
+#define __saved_mask __saved_mask.__saved_mask
diff --git a/sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h b/sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h
new file mode 100644
index 0000000000..e2372e898b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h
@@ -0,0 +1,43 @@
+/* __jmpbuf_arch_t defition for Linux.
+   Copyright (C) 2017 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 <bits/types/__sigset_t.h>
+
+/* The biggest signal number + 1.  As of kernel 4.13, the maximum number
+   of signals is 128 on MIPS.  Define it to 257 to leave some rooms for
+   the future.  */
+#define _JUMP_BUF_SIGSET_NSIG	257
+/* Number of longs to hold all signals.  */
+#define _JUMP_BUF_SIGSET_NWORDS \
+  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_JUMP_BUF_SIGSET_NWORDS];
+  } __jmp_buf_sigset_t;
+
+typedef union
+  {
+    __sigset_t __saved_mask_compat;
+    struct
+      {
+	__jmp_buf_sigset_t __saved_mask;
+	/* Paddings for architecture specific usage.  */
+	unsigned long int __padding[12];
+      } __saved;
+  } __jmpbuf_arch_t;
diff --git a/sysdeps/unix/sysv/linux/__saved_mask.h b/sysdeps/unix/sysv/linux/__saved_mask.h
new file mode 100644
index 0000000000..fcc7c26c9b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/__saved_mask.h
@@ -0,0 +1,20 @@
+/* __saved_mask defition for Linux.
+   Copyright (C) 2017 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/>.  */
+
+/* Saved signal mask.  */
+#define __saved_mask __saved_mask.__saved.__saved_mask
diff --git a/sysdeps/unix/sysv/linux/s390/longjmp_chk.c b/sysdeps/unix/sysv/linux/s390/longjmp_chk.c
index 878cbd4850..5e474bb6d2 100644
--- a/sysdeps/unix/sysv/linux/s390/longjmp_chk.c
+++ b/sysdeps/unix/sysv/linux/s390/longjmp_chk.c
@@ -24,7 +24,7 @@
 /* this is a copy from debug/longjmp_chk.c because we need an unique name
    for __longjmp_chk, but it is already named via a define
    for __libc_siglongjmp in debug/longjmp_chk.c.  */
-# include <setjmp.h>
+# include <setjmpP.h>
 
 // XXX Should move to include/setjmp.h
 extern void ____longjmp_chk (__jmp_buf __env, int __val)
-- 
2.13.6


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-13 23:22               ` H.J. Lu
@ 2017-11-14 12:26                 ` Florian Weimer
  2017-11-14 13:11                   ` H.J. Lu
  0 siblings, 1 reply; 16+ messages in thread
From: Florian Weimer @ 2017-11-14 12:26 UTC (permalink / raw)
  To: H.J. Lu; +Cc: GNU C Library

On 11/14/2017 12:22 AM, H.J. Lu wrote:
> diff --git a/setjmp/tst-sigsetjmp2.c b/setjmp/tst-sigsetjmp2.c
> new file mode 100644
> index 0000000000..131531feb0
> --- /dev/null
> +++ b/setjmp/tst-sigsetjmp2.c
> @@ -0,0 +1,50 @@
> +/* Test that sigprocmask does not read from the unused part of jmpbuf.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include <stdlib.h>
> +#include <signal.h>
> +#include <setjmp.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <jmp_buf-macros.h>
> +#include <support/next_to_fault.h>
> +
> +static int
> +do_test (void)
> +{
> +  struct support_next_to_fault jmpbuf
> +    = support_next_to_fault_allocate (SAVED_MASK_OFFSET + (_NSIG / 8));
> +  struct __jmp_buf_tag *sj = (struct __jmp_buf_tag *) jmpbuf.buffer;
> +
> +  errno = 0;
> +  if (sigsetjmp (sj, 1) == 0)
> +    {
> +      siglongjmp (sj, 1);
> +      return EXIT_FAILURE;
> +    }
> +  if (errno != 0)
> +    {
> +      printf ("sigsetjmp: %s\n", strerror (errno));
> +      return EXIT_FAILURE;
> +    }
> +  return EXIT_SUCCESS;
> +}
> +
> +#define TEST_FUNCTION do_test ()
> +#include "../test-skeleton.c"

Please use <support/test-driver.c>.

Wouldn't the test start to fail if sigsetjmp/siglongjmp actually started 
using the padding you are freeing up for use?

I think you need test sigprocmask directly to ensure it has the desired 
property of not clobbering the padding.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-14 12:26                 ` Florian Weimer
@ 2017-11-14 13:11                   ` H.J. Lu
  2017-11-15 11:10                     ` Florian Weimer
  0 siblings, 1 reply; 16+ messages in thread
From: H.J. Lu @ 2017-11-14 13:11 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library

[-- Attachment #1: Type: text/plain, Size: 2431 bytes --]

On Tue, Nov 14, 2017 at 4:26 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 11/14/2017 12:22 AM, H.J. Lu wrote:
>>
>> diff --git a/setjmp/tst-sigsetjmp2.c b/setjmp/tst-sigsetjmp2.c
>> new file mode 100644
>> index 0000000000..131531feb0
>> --- /dev/null
>> +++ b/setjmp/tst-sigsetjmp2.c
>> @@ -0,0 +1,50 @@
>> +/* Test that sigprocmask does not read from the unused part of jmpbuf.
>> +   Copyright (C) 2017 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   The GNU C Library is free software; you can redistribute it and/or
>> +   modify it under the terms of the GNU Lesser General Public
>> +   License as published by the Free Software Foundation; either
>> +   version 2.1 of the License, or (at your option) any later version.
>> +
>> +   The GNU C Library is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +   Lesser General Public License for more details.
>> +
>> +   You should have received a copy of the GNU Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +<http://www.gnu.org/licenses/>.  */
>> +
>> +#include <stdlib.h>
>> +#include <signal.h>
>> +#include <setjmp.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <errno.h>
>> +#include <jmp_buf-macros.h>
>> +#include <support/next_to_fault.h>
>> +
>> +static int
>> +do_test (void)
>> +{
>> +  struct support_next_to_fault jmpbuf
>> +    = support_next_to_fault_allocate (SAVED_MASK_OFFSET + (_NSIG / 8));
>> +  struct __jmp_buf_tag *sj = (struct __jmp_buf_tag *) jmpbuf.buffer;
>> +
>> +  errno = 0;
>> +  if (sigsetjmp (sj, 1) == 0)
>> +    {
>> +      siglongjmp (sj, 1);
>> +      return EXIT_FAILURE;
>> +    }
>> +  if (errno != 0)
>> +    {
>> +      printf ("sigsetjmp: %s\n", strerror (errno));
>> +      return EXIT_FAILURE;
>> +    }
>> +  return EXIT_SUCCESS;
>> +}
>> +
>> +#define TEST_FUNCTION do_test ()
>> +#include "../test-skeleton.c"
>
>
> Please use <support/test-driver.c>.

Done.

> Wouldn't the test start to fail if sigsetjmp/siglongjmp actually started
> using the padding you are freeing up for use?

You are right.

> I think you need test sigprocmask directly to ensure it has the desired
> property of not clobbering the padding.

Here is the updated patch.   OK for master?

Thanks.


-- 
H.J.

[-- Attachment #2: 0001-jmpbuf-Add-paddings-for-architecture-specific-usage.patch --]
[-- Type: text/x-patch, Size: 16310 bytes --]

From ce65f7a8121c2ed13b5b7bd12059c0ae481a0d5f Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sat, 10 Jun 2017 17:23:06 -0700
Subject: [PATCH] jmpbuf: Add paddings for architecture specific usage

To support Shadow Stack (SHSTK) in Intel Control-flow Enforcement
Technology (CET) in setjmp/longjmp, we need to save shadow stack
pointer in jmp_buf.  The __saved_mask field in jmp_buf has type
of __sigset_t.  On Linux, __sigset_t is defined as

 #define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
  unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;

which is much bigger than expected by the __sigprocmask system call,
which has

typedef struct {
        unsigned long sig[_NSIG_WORDS];
} sigset_t;

We can shrink __sigset_t used by __saved_mask in jmp_buf to add paddings
for architecture specific usage.  As long as the new __sigset_t is not
smaller than sigset_t expected by the __sigprocmask system call, it should
work correctly.  This patch adds an internal header file, <setjmpP.h>,
to define __jmp_buf_sigset_t for __saved_mask in jmp_buf on Linux and
verifies __jmp_buf_sigset_t has the suitable size for the __sigprocmask
system call.   A run-time test, tst-sigsetjmp2.c, is added to verify that
size of __jmp_buf_sigset_t is sufficient.  If size is too small, the test
fails with

rt_sigprocmask(SIG_SETMASK, strace: umoven: short read (4 < 8) @0x7fa8aa28effc
0x7fa8aa28effc, NULL, 8) = -1 EFAULT (Bad address)
rt_sigprocmask(SIG_SETMASK, strace: umoven: short read (4 < 8) @0x7fa8aa28effc
0x7fa8aa28effc, NULL, 8) = -1 EFAULT (Bad address)
rt_sigprocmask(SIG_SETMASK, NULL, 0x7fa8aa28effc, 8) = -1 EFAULT (Bad address)
exit_group(1)                           = ?

Tested with build-many-glibcs.py.

	* debug/longjmp_chk.c: Include <setjmpP.h> instead of
	<setjmp.h>.
	* sysdeps/unix/sysv/linux/s390/longjmp_chk.c: Likewise.
	* include/setjmpP.h: New file.
	* setjmp/setjmpP.h: Likewise.
	* sysdeps/generic/__jmpbuf_arch_t.h: Likewise.
	* sysdeps/generic/__saved_mask.h: Likewise.
	* sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h: Likewise.
	* sysdeps/unix/sysv/linux/__saved_mask.h: Likewise.
	* setjmp/tst-sigsetjmp2.c: Likewise.
	* include/setjmp.h: [!_ISOMAC]: Include <signal.h>.
	[_NSIG] (_SIGPROCMASK_NSIG_WORDS): New.
	[_NSIG] (__sigprocmask_sigset_t): Likewise.
	[_NSIG] (do_test): Add _Static_assert for size of __saved_mask
	in jmp_buf >= sizeof __sigprocmask_sigset_t.
	* setjmp/Makefile (tests): Add tst-sigsetjmp2.
	* setjmp/longjmp.c: Include <setjmpP.h> instead of <setjmp.h>.
	(__libc_siglongjmp): Cast &env[0].__saved_mask to "sigset_t *".
	* setjmp/sigjmp.c: Include <setjmpP.h> instead of <setjmp.h>.
	(__sigjmp_save): Cast &env[0].__saved_mask to "sigset_t *".
---
 debug/longjmp_chk.c                        |  2 +-
 include/setjmp.h                           | 15 ++++++++
 include/setjmpP.h                          |  1 +
 setjmp/Makefile                            |  2 +-
 setjmp/longjmp.c                           |  5 +--
 setjmp/setjmpP.h                           | 32 +++++++++++++++++
 setjmp/sigjmp.c                            |  4 +--
 setjmp/tst-sigsetjmp2.c                    | 56 ++++++++++++++++++++++++++++++
 sysdeps/generic/__jmpbuf_arch_t.h          | 24 +++++++++++++
 sysdeps/generic/__saved_mask.h             | 20 +++++++++++
 sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h  | 43 +++++++++++++++++++++++
 sysdeps/unix/sysv/linux/__saved_mask.h     | 20 +++++++++++
 sysdeps/unix/sysv/linux/s390/longjmp_chk.c |  2 +-
 13 files changed, 219 insertions(+), 7 deletions(-)
 create mode 100644 include/setjmpP.h
 create mode 100644 setjmp/setjmpP.h
 create mode 100644 setjmp/tst-sigsetjmp2.c
 create mode 100644 sysdeps/generic/__jmpbuf_arch_t.h
 create mode 100644 sysdeps/generic/__saved_mask.h
 create mode 100644 sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h
 create mode 100644 sysdeps/unix/sysv/linux/__saved_mask.h

diff --git a/debug/longjmp_chk.c b/debug/longjmp_chk.c
index 1cea6c05ef..61be0da0cd 100644
--- a/debug/longjmp_chk.c
+++ b/debug/longjmp_chk.c
@@ -15,7 +15,7 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <setjmp.h>
+#include <setjmpP.h>
 
 #define __longjmp ____longjmp_chk
 #define __libc_siglongjmp __longjmp_chk
diff --git a/include/setjmp.h b/include/setjmp.h
index f1b19f5ceb..91d916212c 100644
--- a/include/setjmp.h
+++ b/include/setjmp.h
@@ -33,6 +33,7 @@ extern __typeof (__sigsetjmp) __sigsetjmp attribute_hidden;
 # endif
 
 /* Check jmp_buf sizes, alignments and offsets.  */
+# include <signal.h>
 # include <stddef.h>
 # include <jmp_buf-macros.h>
 
@@ -65,6 +66,20 @@ TEST_OFFSET (struct __jmp_buf_tag, __mask_was_saved,
 	     MASK_WAS_SAVED_OFFSET);
 TEST_OFFSET (struct __jmp_buf_tag, __saved_mask,
 	     SAVED_MASK_OFFSET);
+
+# ifdef _NSIG
+#  define _SIGPROCMASK_NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_SIGPROCMASK_NSIG_WORDS];
+  } __sigprocmask_sigset_t;
+
+extern jmp_buf ___buf;
+extern  __typeof (___buf[0].__saved_mask) ___saved_mask;
+_Static_assert (sizeof (___saved_mask) >= sizeof (__sigprocmask_sigset_t),
+		"size of ___saved_mask < size of __sigprocmask_sigset_t");
+# endif
 #endif
 
 #endif
diff --git a/include/setjmpP.h b/include/setjmpP.h
new file mode 100644
index 0000000000..8aa6a25957
--- /dev/null
+++ b/include/setjmpP.h
@@ -0,0 +1 @@
+#include <setjmp/setjmpP.h>
diff --git a/setjmp/Makefile b/setjmp/Makefile
index ca80b8ea13..e0a1f4a30b 100644
--- a/setjmp/Makefile
+++ b/setjmp/Makefile
@@ -28,7 +28,7 @@ routines	:= setjmp sigjmp bsd-setjmp bsd-_setjmp \
 		   longjmp __longjmp jmp-unwind
 
 tests		:= tst-setjmp jmpbug bug269-setjmp tst-setjmp-fp \
-		   tst-sigsetjmp tst-setjmp-static
+		   tst-sigsetjmp tst-setjmp-static tst-sigsetjmp2
 tests-static	:= tst-setjmp-static
 
 
diff --git a/setjmp/longjmp.c b/setjmp/longjmp.c
index 2453c2c124..e144a874d7 100644
--- a/setjmp/longjmp.c
+++ b/setjmp/longjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 
@@ -31,7 +31,8 @@ __libc_siglongjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/setjmp/setjmpP.h b/setjmp/setjmpP.h
new file mode 100644
index 0000000000..e65d72b654
--- /dev/null
+++ b/setjmp/setjmpP.h
@@ -0,0 +1,32 @@
+/* Internal __sigset_t type used in struct __jmp_buf_tag.
+   Copyright (C) 2017 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/>.  */
+
+/*
+ *	ISO C99 Standard: 7.13 Nonlocal jumps	<setjmp.h>
+ */
+
+#ifndef	_SETJMPP_H
+#define	_SETJMPP_H	1
+
+#include <__jmpbuf_arch_t.h>
+#undef __sigset_t
+#define __sigset_t __jmpbuf_arch_t
+#include <setjmp.h>
+#include <__saved_mask.h>
+
+#endif /* setjmpP.h  */
diff --git a/setjmp/sigjmp.c b/setjmp/sigjmp.c
index 30839ae819..32b727fae8 100644
--- a/setjmp/sigjmp.c
+++ b/setjmp/sigjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 /* This function is called by the `sigsetjmp' macro
@@ -28,7 +28,7 @@ __sigjmp_save (sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/setjmp/tst-sigsetjmp2.c b/setjmp/tst-sigsetjmp2.c
new file mode 100644
index 0000000000..1c5adebf0b
--- /dev/null
+++ b/setjmp/tst-sigsetjmp2.c
@@ -0,0 +1,56 @@
+/* Test that sigprocmask does not read from the unused part of jmpbuf.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <string.h>
+#include <errno.h>
+#include <__jmpbuf_arch_t.h>
+#include <support/next_to_fault.h>
+
+#define SIZEOF_SIGSET_T sizeof (__jmp_buf_sigset_t)
+
+static int
+do_test (void)
+{
+  sigjmp_buf sj;
+  struct support_next_to_fault sigset_t_buf
+    = support_next_to_fault_allocate (SIZEOF_SIGSET_T);
+  sigset_t *m_p = (sigset_t *) sigset_t_buf.buffer;
+  sigset_t m;
+
+  sigemptyset (&m);
+  memcpy (m_p, &m, SIZEOF_SIGSET_T);
+  sigprocmask (SIG_SETMASK, m_p, NULL);
+  memcpy (&m, m_p, SIZEOF_SIGSET_T);
+  if (sigsetjmp (sj, 0) == 0)
+    {
+      sigaddset (&m, SIGUSR1);
+      memcpy (m_p, &m, SIZEOF_SIGSET_T);
+      sigprocmask (SIG_SETMASK, m_p, NULL);
+      memcpy (&m, m_p, SIZEOF_SIGSET_T);
+      siglongjmp (sj, 1);
+      return EXIT_FAILURE;
+    }
+  sigprocmask (SIG_SETMASK, NULL, m_p);
+  memcpy (&m, m_p, SIZEOF_SIGSET_T);
+  return sigismember (&m, SIGUSR1) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/generic/__jmpbuf_arch_t.h b/sysdeps/generic/__jmpbuf_arch_t.h
new file mode 100644
index 0000000000..b663202a82
--- /dev/null
+++ b/sysdeps/generic/__jmpbuf_arch_t.h
@@ -0,0 +1,24 @@
+/* Generic __jmpbuf_arch_t defition.
+   Copyright (C) 2017 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 <bits/types/__sigset_t.h>
+
+typedef struct
+  {
+    __sigset_t __saved_mask;
+  } __jmpbuf_arch_t;
diff --git a/sysdeps/generic/__saved_mask.h b/sysdeps/generic/__saved_mask.h
new file mode 100644
index 0000000000..5a59d5f385
--- /dev/null
+++ b/sysdeps/generic/__saved_mask.h
@@ -0,0 +1,20 @@
+/* Generic __saved_mask defition.
+   Copyright (C) 2017 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/>.  */
+
+/* Saved signal mask.  */
+#define __saved_mask __saved_mask.__saved_mask
diff --git a/sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h b/sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h
new file mode 100644
index 0000000000..e2372e898b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h
@@ -0,0 +1,43 @@
+/* __jmpbuf_arch_t defition for Linux.
+   Copyright (C) 2017 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 <bits/types/__sigset_t.h>
+
+/* The biggest signal number + 1.  As of kernel 4.13, the maximum number
+   of signals is 128 on MIPS.  Define it to 257 to leave some rooms for
+   the future.  */
+#define _JUMP_BUF_SIGSET_NSIG	257
+/* Number of longs to hold all signals.  */
+#define _JUMP_BUF_SIGSET_NWORDS \
+  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_JUMP_BUF_SIGSET_NWORDS];
+  } __jmp_buf_sigset_t;
+
+typedef union
+  {
+    __sigset_t __saved_mask_compat;
+    struct
+      {
+	__jmp_buf_sigset_t __saved_mask;
+	/* Paddings for architecture specific usage.  */
+	unsigned long int __padding[12];
+      } __saved;
+  } __jmpbuf_arch_t;
diff --git a/sysdeps/unix/sysv/linux/__saved_mask.h b/sysdeps/unix/sysv/linux/__saved_mask.h
new file mode 100644
index 0000000000..fcc7c26c9b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/__saved_mask.h
@@ -0,0 +1,20 @@
+/* __saved_mask defition for Linux.
+   Copyright (C) 2017 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/>.  */
+
+/* Saved signal mask.  */
+#define __saved_mask __saved_mask.__saved.__saved_mask
diff --git a/sysdeps/unix/sysv/linux/s390/longjmp_chk.c b/sysdeps/unix/sysv/linux/s390/longjmp_chk.c
index 878cbd4850..5e474bb6d2 100644
--- a/sysdeps/unix/sysv/linux/s390/longjmp_chk.c
+++ b/sysdeps/unix/sysv/linux/s390/longjmp_chk.c
@@ -24,7 +24,7 @@
 /* this is a copy from debug/longjmp_chk.c because we need an unique name
    for __longjmp_chk, but it is already named via a define
    for __libc_siglongjmp in debug/longjmp_chk.c.  */
-# include <setjmp.h>
+# include <setjmpP.h>
 
 // XXX Should move to include/setjmp.h
 extern void ____longjmp_chk (__jmp_buf __env, int __val)
-- 
2.13.6


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-14 13:11                   ` H.J. Lu
@ 2017-11-15 11:10                     ` Florian Weimer
  2017-11-15 13:20                       ` H.J. Lu
  0 siblings, 1 reply; 16+ messages in thread
From: Florian Weimer @ 2017-11-15 11:10 UTC (permalink / raw)
  To: H.J. Lu; +Cc: GNU C Library

On 11/14/2017 02:10 PM, H.J. Lu wrote:
> +static int
> +do_test (void)
> +{
> +  sigjmp_buf sj;
> +  struct support_next_to_fault sigset_t_buf
> +    = support_next_to_fault_allocate (SIZEOF_SIGSET_T);
> +  sigset_t *m_p = (sigset_t *) sigset_t_buf.buffer;
> +  sigset_t m;
> +
> +  sigemptyset (&m);
> +  memcpy (m_p, &m, SIZEOF_SIGSET_T);
> +  sigprocmask (SIG_SETMASK, m_p, NULL);
> +  memcpy (&m, m_p, SIZEOF_SIGSET_T);
> +  if (sigsetjmp (sj, 0) == 0)
> +    {
> +      sigaddset (&m, SIGUSR1);
> +      memcpy (m_p, &m, SIZEOF_SIGSET_T);
> +      sigprocmask (SIG_SETMASK, m_p, NULL);
> +      memcpy (&m, m_p, SIZEOF_SIGSET_T);
> +      siglongjmp (sj, 1);
> +      return EXIT_FAILURE;
> +    }
> +  sigprocmask (SIG_SETMASK, NULL, m_p);
> +  memcpy (&m, m_p, SIZEOF_SIGSET_T);
> +  return sigismember (&m, SIGUSR1) ? EXIT_SUCCESS : EXIT_FAILURE;
> +}

Sorry, I don't understand anymore what this test is supposed to test and 
how.

To be honest, I don't like how you inject the internal definition of 
jmp_buf.  Is this the way we do it for the nptl types?

I think you should check _JUMP_BUF_SIGSET_NSIG against a kernel constant 
(_NSIGS?) somewhere.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-15 11:10                     ` Florian Weimer
@ 2017-11-15 13:20                       ` H.J. Lu
  2017-11-21 22:22                         ` H.J. Lu
  0 siblings, 1 reply; 16+ messages in thread
From: H.J. Lu @ 2017-11-15 13:20 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library

[-- Attachment #1: Type: text/plain, Size: 3295 bytes --]

On Wed, Nov 15, 2017 at 3:10 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 11/14/2017 02:10 PM, H.J. Lu wrote:
>>
>> +static int
>> +do_test (void)
>> +{
>> +  sigjmp_buf sj;
>> +  struct support_next_to_fault sigset_t_buf
>> +    = support_next_to_fault_allocate (SIZEOF_SIGSET_T);
>> +  sigset_t *m_p = (sigset_t *) sigset_t_buf.buffer;
>> +  sigset_t m;
>> +
>> +  sigemptyset (&m);
>> +  memcpy (m_p, &m, SIZEOF_SIGSET_T);
>> +  sigprocmask (SIG_SETMASK, m_p, NULL);
>> +  memcpy (&m, m_p, SIZEOF_SIGSET_T);
>> +  if (sigsetjmp (sj, 0) == 0)
>> +    {
>> +      sigaddset (&m, SIGUSR1);
>> +      memcpy (m_p, &m, SIZEOF_SIGSET_T);
>> +      sigprocmask (SIG_SETMASK, m_p, NULL);
>> +      memcpy (&m, m_p, SIZEOF_SIGSET_T);
>> +      siglongjmp (sj, 1);
>> +      return EXIT_FAILURE;
>> +    }
>> +  sigprocmask (SIG_SETMASK, NULL, m_p);
>> +  memcpy (&m, m_p, SIZEOF_SIGSET_T);
>> +  return sigismember (&m, SIGUSR1) ? EXIT_SUCCESS : EXIT_FAILURE;
>> +}
>
>
> Sorry, I don't understand anymore what this test is supposed to test and
> how.

This tests the reduced __jmp_buf_sigset_t used by __saved_mask is
bigger than sigset expected by kernel.

> To be honest, I don't like how you inject the internal definition of
> jmp_buf.  Is this the way we do it for the nptl types?

I only need to make some room in

/* Calling environment, plus possibly a saved signal mask.  */
struct __jmp_buf_tag
  {
    /* NOTE: The machine-dependent definitions of `__sigsetjmp'
       assume that a `jmp_buf' begins with a `__jmp_buf' and that
       `__mask_was_saved' follows it.  Do not move these members
       or add others before it.  */
    __jmp_buf __jmpbuf; /* Calling environment.  */
    int __mask_was_saved; /* Saved the signal mask?  */
    __sigset_t __saved_mask; /* Saved signal mask.  */
  };

for target specific purpose.   I changed it to

struct __jmp_buf_tag
  {
    /* NOTE: The machine-dependent definitions of `__sigsetjmp'
       assume that a `jmp_buf' begins with a `__jmp_buf' and that
       `__mask_was_saved' follows it.  Do not move these members
       or add others before it.  */
    __jmp_buf __jmpbuf; /* Calling environment.  */
    int __mask_was_saved; /* Saved the signal mask?  */
    union
    {
    __sigset_t __saved_mask_compat;
    struct
      {
__jmp_buf_sigset_t __saved_mask;
/* Paddings for architecture specific usage.  */
unsigned long int __padding[12];
      } __saved;
    }  __saved_mask;
  };

#define __saved_mask __saved_mask.__saved.__saved_mask

I did only to  __sigset_t  in __jmp_buf_tag and this test verifies that the size
of __jmp_buf_sigset_t works with sigprocmask.

Are you suggesting we make some room in __sigset_t directly?  This will
require very extensive changes. If not, what do you exactly suggest?

> I think you should check _JUMP_BUF_SIGSET_NSIG against a kernel constant
> (_NSIGS?) somewhere.

There is a _Static_assert in include/setjmp.h.  But it isn't triggered.  This
updated patch moves it to sysdeps/unix/sysv/linux/__saved_mask.h.   Now
I got

../sysdeps/unix/sysv/linux/__saved_mask.h:32:1: error: static
assertion failed: "size of ___saved_mask < size of
__sigprocmask_sigset_t"
 _Static_assert (sizeof (___saved_mask) >= sizeof (__sigprocmask_sigset_t),

if __jmp_buf_sigset_t is too small.

-- 
H.J.

[-- Attachment #2: 0001-jmpbuf-Add-paddings-for-architecture-specific-usage.patch --]
[-- Type: text/x-patch, Size: 15460 bytes --]

From f5168887870e1046017e534b7b0eb8c52133d941 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sat, 10 Jun 2017 17:23:06 -0700
Subject: [PATCH] jmpbuf: Add paddings for architecture specific usage

To support Shadow Stack (SHSTK) in Intel Control-flow Enforcement
Technology (CET) in setjmp/longjmp, we need to save shadow stack
pointer in jmp_buf.  The __saved_mask field in jmp_buf has type
of __sigset_t.  On Linux, __sigset_t is defined as

 #define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
  unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;

which is much bigger than expected by the __sigprocmask system call,
which has

typedef struct {
        unsigned long sig[_NSIG_WORDS];
} sigset_t;

We can shrink __sigset_t used by __saved_mask in jmp_buf to add paddings
for architecture specific usage.  As long as the new __sigset_t is not
smaller than sigset_t expected by the __sigprocmask system call, it should
work correctly.  This patch adds an internal header file, <setjmpP.h>,
to define __jmp_buf_sigset_t for __saved_mask in jmp_buf on Linux and
verifies __jmp_buf_sigset_t has the suitable size for the __sigprocmask
system call.   A run-time test, tst-sigsetjmp2.c, is added to verify that
size of __jmp_buf_sigset_t is sufficient.  If size is too small, the test
fails with

rt_sigprocmask(SIG_SETMASK, strace: umoven: short read (4 < 8) @0x7fa8aa28effc
0x7fa8aa28effc, NULL, 8) = -1 EFAULT (Bad address)
rt_sigprocmask(SIG_SETMASK, strace: umoven: short read (4 < 8) @0x7fa8aa28effc
0x7fa8aa28effc, NULL, 8) = -1 EFAULT (Bad address)
rt_sigprocmask(SIG_SETMASK, NULL, 0x7fa8aa28effc, 8) = -1 EFAULT (Bad address)
exit_group(1)                           = ?

Tested with build-many-glibcs.py.

	* debug/longjmp_chk.c: Include <setjmpP.h> instead of
	<setjmp.h>.
	* sysdeps/unix/sysv/linux/s390/longjmp_chk.c: Likewise.
	* include/setjmpP.h: New file.
	* setjmp/setjmpP.h: Likewise.
	* sysdeps/generic/__jmpbuf_arch_t.h: Likewise.
	* sysdeps/generic/__saved_mask.h: Likewise.
	* sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h: Likewise.
	* sysdeps/unix/sysv/linux/__saved_mask.h: Likewise.
	* setjmp/tst-sigsetjmp2.c: Likewise.
	* setjmp/Makefile (tests): Add tst-sigsetjmp2.
	* setjmp/longjmp.c: Include <setjmpP.h> instead of <setjmp.h>.
	(__libc_siglongjmp): Cast &env[0].__saved_mask to "sigset_t *".
	* setjmp/sigjmp.c: Include <setjmpP.h> instead of <setjmp.h>.
	(__sigjmp_save): Cast &env[0].__saved_mask to "sigset_t *".
---
 debug/longjmp_chk.c                        |  2 +-
 include/setjmpP.h                          |  1 +
 setjmp/Makefile                            |  2 +-
 setjmp/longjmp.c                           |  5 +--
 setjmp/setjmpP.h                           | 32 +++++++++++++++++
 setjmp/sigjmp.c                            |  4 +--
 setjmp/tst-sigsetjmp2.c                    | 56 ++++++++++++++++++++++++++++++
 sysdeps/generic/__jmpbuf_arch_t.h          | 24 +++++++++++++
 sysdeps/generic/__saved_mask.h             | 20 +++++++++++
 sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h  | 43 +++++++++++++++++++++++
 sysdeps/unix/sysv/linux/__saved_mask.h     | 34 ++++++++++++++++++
 sysdeps/unix/sysv/linux/s390/longjmp_chk.c |  2 +-
 12 files changed, 218 insertions(+), 7 deletions(-)
 create mode 100644 include/setjmpP.h
 create mode 100644 setjmp/setjmpP.h
 create mode 100644 setjmp/tst-sigsetjmp2.c
 create mode 100644 sysdeps/generic/__jmpbuf_arch_t.h
 create mode 100644 sysdeps/generic/__saved_mask.h
 create mode 100644 sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h
 create mode 100644 sysdeps/unix/sysv/linux/__saved_mask.h

diff --git a/debug/longjmp_chk.c b/debug/longjmp_chk.c
index 1cea6c05ef..61be0da0cd 100644
--- a/debug/longjmp_chk.c
+++ b/debug/longjmp_chk.c
@@ -15,7 +15,7 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <setjmp.h>
+#include <setjmpP.h>
 
 #define __longjmp ____longjmp_chk
 #define __libc_siglongjmp __longjmp_chk
diff --git a/include/setjmpP.h b/include/setjmpP.h
new file mode 100644
index 0000000000..8aa6a25957
--- /dev/null
+++ b/include/setjmpP.h
@@ -0,0 +1 @@
+#include <setjmp/setjmpP.h>
diff --git a/setjmp/Makefile b/setjmp/Makefile
index ca80b8ea13..e0a1f4a30b 100644
--- a/setjmp/Makefile
+++ b/setjmp/Makefile
@@ -28,7 +28,7 @@ routines	:= setjmp sigjmp bsd-setjmp bsd-_setjmp \
 		   longjmp __longjmp jmp-unwind
 
 tests		:= tst-setjmp jmpbug bug269-setjmp tst-setjmp-fp \
-		   tst-sigsetjmp tst-setjmp-static
+		   tst-sigsetjmp tst-setjmp-static tst-sigsetjmp2
 tests-static	:= tst-setjmp-static
 
 
diff --git a/setjmp/longjmp.c b/setjmp/longjmp.c
index 2453c2c124..e144a874d7 100644
--- a/setjmp/longjmp.c
+++ b/setjmp/longjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 
@@ -31,7 +31,8 @@ __libc_siglongjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/setjmp/setjmpP.h b/setjmp/setjmpP.h
new file mode 100644
index 0000000000..e65d72b654
--- /dev/null
+++ b/setjmp/setjmpP.h
@@ -0,0 +1,32 @@
+/* Internal __sigset_t type used in struct __jmp_buf_tag.
+   Copyright (C) 2017 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/>.  */
+
+/*
+ *	ISO C99 Standard: 7.13 Nonlocal jumps	<setjmp.h>
+ */
+
+#ifndef	_SETJMPP_H
+#define	_SETJMPP_H	1
+
+#include <__jmpbuf_arch_t.h>
+#undef __sigset_t
+#define __sigset_t __jmpbuf_arch_t
+#include <setjmp.h>
+#include <__saved_mask.h>
+
+#endif /* setjmpP.h  */
diff --git a/setjmp/sigjmp.c b/setjmp/sigjmp.c
index 30839ae819..32b727fae8 100644
--- a/setjmp/sigjmp.c
+++ b/setjmp/sigjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 /* This function is called by the `sigsetjmp' macro
@@ -28,7 +28,7 @@ __sigjmp_save (sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/setjmp/tst-sigsetjmp2.c b/setjmp/tst-sigsetjmp2.c
new file mode 100644
index 0000000000..1c5adebf0b
--- /dev/null
+++ b/setjmp/tst-sigsetjmp2.c
@@ -0,0 +1,56 @@
+/* Test that sigprocmask does not read from the unused part of jmpbuf.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <string.h>
+#include <errno.h>
+#include <__jmpbuf_arch_t.h>
+#include <support/next_to_fault.h>
+
+#define SIZEOF_SIGSET_T sizeof (__jmp_buf_sigset_t)
+
+static int
+do_test (void)
+{
+  sigjmp_buf sj;
+  struct support_next_to_fault sigset_t_buf
+    = support_next_to_fault_allocate (SIZEOF_SIGSET_T);
+  sigset_t *m_p = (sigset_t *) sigset_t_buf.buffer;
+  sigset_t m;
+
+  sigemptyset (&m);
+  memcpy (m_p, &m, SIZEOF_SIGSET_T);
+  sigprocmask (SIG_SETMASK, m_p, NULL);
+  memcpy (&m, m_p, SIZEOF_SIGSET_T);
+  if (sigsetjmp (sj, 0) == 0)
+    {
+      sigaddset (&m, SIGUSR1);
+      memcpy (m_p, &m, SIZEOF_SIGSET_T);
+      sigprocmask (SIG_SETMASK, m_p, NULL);
+      memcpy (&m, m_p, SIZEOF_SIGSET_T);
+      siglongjmp (sj, 1);
+      return EXIT_FAILURE;
+    }
+  sigprocmask (SIG_SETMASK, NULL, m_p);
+  memcpy (&m, m_p, SIZEOF_SIGSET_T);
+  return sigismember (&m, SIGUSR1) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/generic/__jmpbuf_arch_t.h b/sysdeps/generic/__jmpbuf_arch_t.h
new file mode 100644
index 0000000000..b663202a82
--- /dev/null
+++ b/sysdeps/generic/__jmpbuf_arch_t.h
@@ -0,0 +1,24 @@
+/* Generic __jmpbuf_arch_t defition.
+   Copyright (C) 2017 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 <bits/types/__sigset_t.h>
+
+typedef struct
+  {
+    __sigset_t __saved_mask;
+  } __jmpbuf_arch_t;
diff --git a/sysdeps/generic/__saved_mask.h b/sysdeps/generic/__saved_mask.h
new file mode 100644
index 0000000000..5a59d5f385
--- /dev/null
+++ b/sysdeps/generic/__saved_mask.h
@@ -0,0 +1,20 @@
+/* Generic __saved_mask defition.
+   Copyright (C) 2017 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/>.  */
+
+/* Saved signal mask.  */
+#define __saved_mask __saved_mask.__saved_mask
diff --git a/sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h b/sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h
new file mode 100644
index 0000000000..e2372e898b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/__jmpbuf_arch_t.h
@@ -0,0 +1,43 @@
+/* __jmpbuf_arch_t defition for Linux.
+   Copyright (C) 2017 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 <bits/types/__sigset_t.h>
+
+/* The biggest signal number + 1.  As of kernel 4.13, the maximum number
+   of signals is 128 on MIPS.  Define it to 257 to leave some rooms for
+   the future.  */
+#define _JUMP_BUF_SIGSET_NSIG	257
+/* Number of longs to hold all signals.  */
+#define _JUMP_BUF_SIGSET_NWORDS \
+  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_JUMP_BUF_SIGSET_NWORDS];
+  } __jmp_buf_sigset_t;
+
+typedef union
+  {
+    __sigset_t __saved_mask_compat;
+    struct
+      {
+	__jmp_buf_sigset_t __saved_mask;
+	/* Paddings for architecture specific usage.  */
+	unsigned long int __padding[12];
+      } __saved;
+  } __jmpbuf_arch_t;
diff --git a/sysdeps/unix/sysv/linux/__saved_mask.h b/sysdeps/unix/sysv/linux/__saved_mask.h
new file mode 100644
index 0000000000..aad8871999
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/__saved_mask.h
@@ -0,0 +1,34 @@
+/* __saved_mask defition for Linux.
+   Copyright (C) 2017 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/>.  */
+
+/* Saved signal mask.  */
+#define __saved_mask __saved_mask.__saved.__saved_mask
+
+#include <signal.h>
+
+#define _SIGPROCMASK_NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_SIGPROCMASK_NSIG_WORDS];
+  } __sigprocmask_sigset_t;
+
+extern jmp_buf ___buf;
+extern  __typeof (___buf[0].__saved_mask) ___saved_mask;
+_Static_assert (sizeof (___saved_mask) >= sizeof (__sigprocmask_sigset_t),
+		"size of ___saved_mask < size of __sigprocmask_sigset_t");
diff --git a/sysdeps/unix/sysv/linux/s390/longjmp_chk.c b/sysdeps/unix/sysv/linux/s390/longjmp_chk.c
index 878cbd4850..5e474bb6d2 100644
--- a/sysdeps/unix/sysv/linux/s390/longjmp_chk.c
+++ b/sysdeps/unix/sysv/linux/s390/longjmp_chk.c
@@ -24,7 +24,7 @@
 /* this is a copy from debug/longjmp_chk.c because we need an unique name
    for __longjmp_chk, but it is already named via a define
    for __libc_siglongjmp in debug/longjmp_chk.c.  */
-# include <setjmp.h>
+# include <setjmpP.h>
 
 // XXX Should move to include/setjmp.h
 extern void ____longjmp_chk (__jmp_buf __env, int __val)
-- 
2.13.6


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-15 13:20                       ` H.J. Lu
@ 2017-11-21 22:22                         ` H.J. Lu
  2017-11-25 16:34                           ` H.J. Lu
  0 siblings, 1 reply; 16+ messages in thread
From: H.J. Lu @ 2017-11-21 22:22 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library

On Wed, Nov 15, 2017 at 5:20 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Nov 15, 2017 at 3:10 AM, Florian Weimer <fweimer@redhat.com> wrote:
>> On 11/14/2017 02:10 PM, H.J. Lu wrote:
>>>
>>> +static int
>>> +do_test (void)
>>> +{
>>> +  sigjmp_buf sj;
>>> +  struct support_next_to_fault sigset_t_buf
>>> +    = support_next_to_fault_allocate (SIZEOF_SIGSET_T);
>>> +  sigset_t *m_p = (sigset_t *) sigset_t_buf.buffer;
>>> +  sigset_t m;
>>> +
>>> +  sigemptyset (&m);
>>> +  memcpy (m_p, &m, SIZEOF_SIGSET_T);
>>> +  sigprocmask (SIG_SETMASK, m_p, NULL);
>>> +  memcpy (&m, m_p, SIZEOF_SIGSET_T);
>>> +  if (sigsetjmp (sj, 0) == 0)
>>> +    {
>>> +      sigaddset (&m, SIGUSR1);
>>> +      memcpy (m_p, &m, SIZEOF_SIGSET_T);
>>> +      sigprocmask (SIG_SETMASK, m_p, NULL);
>>> +      memcpy (&m, m_p, SIZEOF_SIGSET_T);
>>> +      siglongjmp (sj, 1);
>>> +      return EXIT_FAILURE;
>>> +    }
>>> +  sigprocmask (SIG_SETMASK, NULL, m_p);
>>> +  memcpy (&m, m_p, SIZEOF_SIGSET_T);
>>> +  return sigismember (&m, SIGUSR1) ? EXIT_SUCCESS : EXIT_FAILURE;
>>> +}
>>
>>
>> Sorry, I don't understand anymore what this test is supposed to test and
>> how.
>
> This tests the reduced __jmp_buf_sigset_t used by __saved_mask is
> bigger than sigset expected by kernel.
>
>> To be honest, I don't like how you inject the internal definition of
>> jmp_buf.  Is this the way we do it for the nptl types?
>
> I only need to make some room in
>
> /* Calling environment, plus possibly a saved signal mask.  */
> struct __jmp_buf_tag
>   {
>     /* NOTE: The machine-dependent definitions of `__sigsetjmp'
>        assume that a `jmp_buf' begins with a `__jmp_buf' and that
>        `__mask_was_saved' follows it.  Do not move these members
>        or add others before it.  */
>     __jmp_buf __jmpbuf; /* Calling environment.  */
>     int __mask_was_saved; /* Saved the signal mask?  */
>     __sigset_t __saved_mask; /* Saved signal mask.  */
>   };
>
> for target specific purpose.   I changed it to
>
> struct __jmp_buf_tag
>   {
>     /* NOTE: The machine-dependent definitions of `__sigsetjmp'
>        assume that a `jmp_buf' begins with a `__jmp_buf' and that
>        `__mask_was_saved' follows it.  Do not move these members
>        or add others before it.  */
>     __jmp_buf __jmpbuf; /* Calling environment.  */
>     int __mask_was_saved; /* Saved the signal mask?  */
>     union
>     {
>     __sigset_t __saved_mask_compat;
>     struct
>       {
> __jmp_buf_sigset_t __saved_mask;
> /* Paddings for architecture specific usage.  */
> unsigned long int __padding[12];
>       } __saved;
>     }  __saved_mask;
>   };
>
> #define __saved_mask __saved_mask.__saved.__saved_mask
>
> I did only to  __sigset_t  in __jmp_buf_tag and this test verifies that the size
> of __jmp_buf_sigset_t works with sigprocmask.
>
> Are you suggesting we make some room in __sigset_t directly?  This will
> require very extensive changes. If not, what do you exactly suggest?
>
>> I think you should check _JUMP_BUF_SIGSET_NSIG against a kernel constant
>> (_NSIGS?) somewhere.
>
> There is a _Static_assert in include/setjmp.h.  But it isn't triggered.  This
> updated patch moves it to sysdeps/unix/sysv/linux/__saved_mask.h.   Now
> I got
>
> ../sysdeps/unix/sysv/linux/__saved_mask.h:32:1: error: static
> assertion failed: "size of ___saved_mask < size of
> __sigprocmask_sigset_t"
>  _Static_assert (sizeof (___saved_mask) >= sizeof (__sigprocmask_sigset_t),
>
> if __jmp_buf_sigset_t is too small.
>
> --
> H.J.

Any comments, suggestions or objections?  The patch is at

https://sourceware.org/ml/libc-alpha/2017-11/msg00510.html

-- 
H.J.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-21 22:22                         ` H.J. Lu
@ 2017-11-25 16:34                           ` H.J. Lu
  2017-11-29 21:16                             ` H.J. Lu
  0 siblings, 1 reply; 16+ messages in thread
From: H.J. Lu @ 2017-11-25 16:34 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library

[-- Attachment #1: Type: text/plain, Size: 3904 bytes --]

On Tue, Nov 21, 2017 at 2:22 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Nov 15, 2017 at 5:20 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Wed, Nov 15, 2017 at 3:10 AM, Florian Weimer <fweimer@redhat.com> wrote:
>>> On 11/14/2017 02:10 PM, H.J. Lu wrote:
>>>>
>>>> +static int
>>>> +do_test (void)
>>>> +{
>>>> +  sigjmp_buf sj;
>>>> +  struct support_next_to_fault sigset_t_buf
>>>> +    = support_next_to_fault_allocate (SIZEOF_SIGSET_T);
>>>> +  sigset_t *m_p = (sigset_t *) sigset_t_buf.buffer;
>>>> +  sigset_t m;
>>>> +
>>>> +  sigemptyset (&m);
>>>> +  memcpy (m_p, &m, SIZEOF_SIGSET_T);
>>>> +  sigprocmask (SIG_SETMASK, m_p, NULL);
>>>> +  memcpy (&m, m_p, SIZEOF_SIGSET_T);
>>>> +  if (sigsetjmp (sj, 0) == 0)
>>>> +    {
>>>> +      sigaddset (&m, SIGUSR1);
>>>> +      memcpy (m_p, &m, SIZEOF_SIGSET_T);
>>>> +      sigprocmask (SIG_SETMASK, m_p, NULL);
>>>> +      memcpy (&m, m_p, SIZEOF_SIGSET_T);
>>>> +      siglongjmp (sj, 1);
>>>> +      return EXIT_FAILURE;
>>>> +    }
>>>> +  sigprocmask (SIG_SETMASK, NULL, m_p);
>>>> +  memcpy (&m, m_p, SIZEOF_SIGSET_T);
>>>> +  return sigismember (&m, SIGUSR1) ? EXIT_SUCCESS : EXIT_FAILURE;
>>>> +}
>>>
>>>
>>> Sorry, I don't understand anymore what this test is supposed to test and
>>> how.
>>
>> This tests the reduced __jmp_buf_sigset_t used by __saved_mask is
>> bigger than sigset expected by kernel.
>>
>>> To be honest, I don't like how you inject the internal definition of
>>> jmp_buf.  Is this the way we do it for the nptl types?
>>
>> I only need to make some room in
>>
>> /* Calling environment, plus possibly a saved signal mask.  */
>> struct __jmp_buf_tag
>>   {
>>     /* NOTE: The machine-dependent definitions of `__sigsetjmp'
>>        assume that a `jmp_buf' begins with a `__jmp_buf' and that
>>        `__mask_was_saved' follows it.  Do not move these members
>>        or add others before it.  */
>>     __jmp_buf __jmpbuf; /* Calling environment.  */
>>     int __mask_was_saved; /* Saved the signal mask?  */
>>     __sigset_t __saved_mask; /* Saved signal mask.  */
>>   };
>>
>> for target specific purpose.   I changed it to
>>
>> struct __jmp_buf_tag
>>   {
>>     /* NOTE: The machine-dependent definitions of `__sigsetjmp'
>>        assume that a `jmp_buf' begins with a `__jmp_buf' and that
>>        `__mask_was_saved' follows it.  Do not move these members
>>        or add others before it.  */
>>     __jmp_buf __jmpbuf; /* Calling environment.  */
>>     int __mask_was_saved; /* Saved the signal mask?  */
>>     union
>>     {
>>     __sigset_t __saved_mask_compat;
>>     struct
>>       {
>> __jmp_buf_sigset_t __saved_mask;
>> /* Paddings for architecture specific usage.  */
>> unsigned long int __padding[12];
>>       } __saved;
>>     }  __saved_mask;
>>   };
>>
>> #define __saved_mask __saved_mask.__saved.__saved_mask
>>
>> I did only to  __sigset_t  in __jmp_buf_tag and this test verifies that the size
>> of __jmp_buf_sigset_t works with sigprocmask.
>>
>> Are you suggesting we make some room in __sigset_t directly?  This will
>> require very extensive changes. If not, what do you exactly suggest?
>>
>>> I think you should check _JUMP_BUF_SIGSET_NSIG against a kernel constant
>>> (_NSIGS?) somewhere.
>>
>> There is a _Static_assert in include/setjmp.h.  But it isn't triggered.  This
>> updated patch moves it to sysdeps/unix/sysv/linux/__saved_mask.h.   Now
>> I got
>>
>> ../sysdeps/unix/sysv/linux/__saved_mask.h:32:1: error: static
>> assertion failed: "size of ___saved_mask < size of
>> __sigprocmask_sigset_t"
>>  _Static_assert (sizeof (___saved_mask) >= sizeof (__sigprocmask_sigset_t),
>>
>> if __jmp_buf_sigset_t is too small.
>>
>> --
>> H.J.
>
> Any comments, suggestions or objections?  The patch is at
>
> https://sourceware.org/ml/libc-alpha/2017-11/msg00510.html
>

This is the updated patch.  It limited the changes to Linux/x86.
Any comments?


-- 
H.J.

[-- Attachment #2: 0001-x86-Add-paddings-in-jmpbuf-for-shadow-stack-pointer.patch --]
[-- Type: text/x-patch, Size: 13355 bytes --]

From 71ac6d741e74e8be54fdc74132bce3def8d90bea Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sat, 10 Jun 2017 17:23:06 -0700
Subject: [PATCH] x86: Add paddings in jmpbuf for shadow stack pointer

To support Shadow Stack (SHSTK) in Intel Control-flow Enforcement
Technology (CET) in setjmp/longjmp, we need to save shadow stack
pointer in jmp_buf.  The __saved_mask field in jmp_buf has type
of __sigset_t.  On Linux, __sigset_t is defined as

 #define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
  unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;

which is much bigger than expected by the __sigprocmask system call,
which has

typedef struct {
        unsigned long sig[_NSIG_WORDS];
} sigset_t;

For Linux/x86, we can shrink __sigset_t used by __saved_mask in jmp_buf
to add paddings for shadow stack pointer.  As long as the new __sigset_t
is not smaller than sigset_t expected by the __sigprocmask system call,
it should work correctly.  This patch adds an internal header file,
<setjmpP.h>, to define __jmp_buf_sigset_t for __saved_mask in jmp_buf
for Linux/x86 and verifies __jmp_buf_sigset_t has the suitable size for
the __sigprocmask system call.   A run-time test, tst-saved_mask-1.c, is
added to verify that size of __jmp_buf_sigset_t is sufficient.  If size
is too small, the test fails with

rt_sigprocmask(SIG_SETMASK, strace: umoven: short read (4 < 8) @0x7fa8aa28effc
0x7fa8aa28effc, NULL, 8) = -1 EFAULT (Bad address)
rt_sigprocmask(SIG_SETMASK, strace: umoven: short read (4 < 8) @0x7fa8aa28effc
0x7fa8aa28effc, NULL, 8) = -1 EFAULT (Bad address)
rt_sigprocmask(SIG_SETMASK, NULL, 0x7fa8aa28effc, 8) = -1 EFAULT (Bad address)
exit_group(1)                           = ?

Tested with build-many-glibcs.py.

	* debug/longjmp_chk.c: Include <setjmpP.h> instead of
	<setjmp.h>.
	* setjmp/longjmp.c: Include <setjmpP.h> instead of <setjmp.h>.
	(__libc_siglongjmp): Cast &env[0].__saved_mask to "sigset_t *".
	* setjmp/sigjmp.c: Include <setjmpP.h> instead of <setjmp.h>.
	(__sigjmp_save): Cast &env[0].__saved_mask to "sigset_t *".
	* sysdeps/generic/setjmpP.h: New file.
	* sysdeps/unix/sysv/linux/x86/__jmpbuf_arch_t.h: Likewise.
	* sysdeps/unix/sysv/linux/x86/__saved_mask.h: Likewise.
	* sysdeps/unix/sysv/linux/x86/setjmpP.h: Likewise.
	* sysdeps/unix/sysv/linux/x86/tst-saved_mask-1.c: Likewise.
	* sysdeps/unix/sysv/linux/x86/Makefile (tests): Add
	tst-saved_mask-1.
---
 debug/longjmp_chk.c                            |  2 +-
 setjmp/longjmp.c                               |  5 ++-
 setjmp/sigjmp.c                                |  4 +-
 sysdeps/generic/setjmpP.h                      | 24 +++++++++++
 sysdeps/unix/sysv/linux/x86/Makefile           |  4 ++
 sysdeps/unix/sysv/linux/x86/__jmpbuf_arch_t.h  | 43 ++++++++++++++++++++
 sysdeps/unix/sysv/linux/x86/__saved_mask.h     | 34 ++++++++++++++++
 sysdeps/unix/sysv/linux/x86/setjmpP.h          | 28 +++++++++++++
 sysdeps/unix/sysv/linux/x86/tst-saved_mask-1.c | 56 ++++++++++++++++++++++++++
 9 files changed, 195 insertions(+), 5 deletions(-)
 create mode 100644 sysdeps/generic/setjmpP.h
 create mode 100644 sysdeps/unix/sysv/linux/x86/__jmpbuf_arch_t.h
 create mode 100644 sysdeps/unix/sysv/linux/x86/__saved_mask.h
 create mode 100644 sysdeps/unix/sysv/linux/x86/setjmpP.h
 create mode 100644 sysdeps/unix/sysv/linux/x86/tst-saved_mask-1.c

diff --git a/debug/longjmp_chk.c b/debug/longjmp_chk.c
index 1cea6c05ef..61be0da0cd 100644
--- a/debug/longjmp_chk.c
+++ b/debug/longjmp_chk.c
@@ -15,7 +15,7 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <setjmp.h>
+#include <setjmpP.h>
 
 #define __longjmp ____longjmp_chk
 #define __libc_siglongjmp __longjmp_chk
diff --git a/setjmp/longjmp.c b/setjmp/longjmp.c
index 2453c2c124..e144a874d7 100644
--- a/setjmp/longjmp.c
+++ b/setjmp/longjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 
@@ -31,7 +31,8 @@ __libc_siglongjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/setjmp/sigjmp.c b/setjmp/sigjmp.c
index 30839ae819..32b727fae8 100644
--- a/setjmp/sigjmp.c
+++ b/setjmp/sigjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 /* This function is called by the `sigsetjmp' macro
@@ -28,7 +28,7 @@ __sigjmp_save (sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/sysdeps/generic/setjmpP.h b/sysdeps/generic/setjmpP.h
new file mode 100644
index 0000000000..a878ce6b35
--- /dev/null
+++ b/sysdeps/generic/setjmpP.h
@@ -0,0 +1,24 @@
+/* Internal header file for <setjmp.h>.  Generic version.
+   Copyright (C) 2017 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	_SETJMPP_H
+#define	_SETJMPP_H	1
+
+#include <setjmp.h>
+
+#endif /* setjmpP.h  */
diff --git a/sysdeps/unix/sysv/linux/x86/Makefile b/sysdeps/unix/sysv/linux/x86/Makefile
index c069570683..111ff9ff58 100644
--- a/sysdeps/unix/sysv/linux/x86/Makefile
+++ b/sysdeps/unix/sysv/linux/x86/Makefile
@@ -19,3 +19,7 @@ endif
 ifeq ($(subdir),elf)
 sysdep_routines += dl-vdso
 endif
+
+ifeq ($(subdir),setjmp)
+tests += tst-saved_mask-1
+endif
diff --git a/sysdeps/unix/sysv/linux/x86/__jmpbuf_arch_t.h b/sysdeps/unix/sysv/linux/x86/__jmpbuf_arch_t.h
new file mode 100644
index 0000000000..a170f3ef9b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/__jmpbuf_arch_t.h
@@ -0,0 +1,43 @@
+/* __jmpbuf_arch_t defition for Linux/x86.
+   Copyright (C) 2017 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 <bits/types/__sigset_t.h>
+
+/* The biggest signal number + 1.  As of kernel 4.13, the maximum number
+   of signals is 128 on MIPS.  Define it to 257 to leave some rooms for
+   the future.  */
+#define _JUMP_BUF_SIGSET_NSIG	257
+/* Number of longs to hold all signals.  */
+#define _JUMP_BUF_SIGSET_NWORDS \
+  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_JUMP_BUF_SIGSET_NWORDS];
+  } __jmp_buf_sigset_t;
+
+typedef union
+  {
+    __sigset_t __saved_mask_compat;
+    struct
+      {
+	__jmp_buf_sigset_t __saved_mask;
+	/* Paddings for architecture specific usage.  */
+	unsigned long int __padding[12];
+      } __saved;
+  } __jmpbuf_arch_t;
diff --git a/sysdeps/unix/sysv/linux/x86/__saved_mask.h b/sysdeps/unix/sysv/linux/x86/__saved_mask.h
new file mode 100644
index 0000000000..98b3bbc836
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/__saved_mask.h
@@ -0,0 +1,34 @@
+/* __saved_mask defition for Linux/x86.
+   Copyright (C) 2017 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/>.  */
+
+/* Saved signal mask.  */
+#define __saved_mask __saved_mask.__saved.__saved_mask
+
+#include <signal.h>
+
+#define _SIGPROCMASK_NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_SIGPROCMASK_NSIG_WORDS];
+  } __sigprocmask_sigset_t;
+
+extern jmp_buf ___buf;
+extern  __typeof (___buf[0].__saved_mask) ___saved_mask;
+_Static_assert (sizeof (___saved_mask) >= sizeof (__sigprocmask_sigset_t),
+		"size of ___saved_mask < size of __sigprocmask_sigset_t");
diff --git a/sysdeps/unix/sysv/linux/x86/setjmpP.h b/sysdeps/unix/sysv/linux/x86/setjmpP.h
new file mode 100644
index 0000000000..03bc477166
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/setjmpP.h
@@ -0,0 +1,28 @@
+/* Internal header file for <setjmp.h>.  Linux/x86 version.
+   Copyright (C) 2017 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	_SETJMPP_H
+#define	_SETJMPP_H	1
+
+#include <__jmpbuf_arch_t.h>
+#undef __sigset_t
+#define __sigset_t __jmpbuf_arch_t
+#include <setjmp.h>
+#include <__saved_mask.h>
+
+#endif /* setjmpP.h  */
diff --git a/sysdeps/unix/sysv/linux/x86/tst-saved_mask-1.c b/sysdeps/unix/sysv/linux/x86/tst-saved_mask-1.c
new file mode 100644
index 0000000000..1c5adebf0b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/tst-saved_mask-1.c
@@ -0,0 +1,56 @@
+/* Test that sigprocmask does not read from the unused part of jmpbuf.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <string.h>
+#include <errno.h>
+#include <__jmpbuf_arch_t.h>
+#include <support/next_to_fault.h>
+
+#define SIZEOF_SIGSET_T sizeof (__jmp_buf_sigset_t)
+
+static int
+do_test (void)
+{
+  sigjmp_buf sj;
+  struct support_next_to_fault sigset_t_buf
+    = support_next_to_fault_allocate (SIZEOF_SIGSET_T);
+  sigset_t *m_p = (sigset_t *) sigset_t_buf.buffer;
+  sigset_t m;
+
+  sigemptyset (&m);
+  memcpy (m_p, &m, SIZEOF_SIGSET_T);
+  sigprocmask (SIG_SETMASK, m_p, NULL);
+  memcpy (&m, m_p, SIZEOF_SIGSET_T);
+  if (sigsetjmp (sj, 0) == 0)
+    {
+      sigaddset (&m, SIGUSR1);
+      memcpy (m_p, &m, SIZEOF_SIGSET_T);
+      sigprocmask (SIG_SETMASK, m_p, NULL);
+      memcpy (&m, m_p, SIZEOF_SIGSET_T);
+      siglongjmp (sj, 1);
+      return EXIT_FAILURE;
+    }
+  sigprocmask (SIG_SETMASK, NULL, m_p);
+  memcpy (&m, m_p, SIZEOF_SIGSET_T);
+  return sigismember (&m, SIGUSR1) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+#include <support/test-driver.c>
-- 
2.14.3


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] jmpbuf: Add paddings for target specific usage
  2017-11-25 16:34                           ` H.J. Lu
@ 2017-11-29 21:16                             ` H.J. Lu
  0 siblings, 0 replies; 16+ messages in thread
From: H.J. Lu @ 2017-11-29 21:16 UTC (permalink / raw)
  To: Florian Weimer; +Cc: GNU C Library, Senkevich, Andrew, Tsimbalist, Igor V

[-- Attachment #1: Type: text/plain, Size: 4223 bytes --]

On Sat, Nov 25, 2017 at 8:34 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Tue, Nov 21, 2017 at 2:22 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Wed, Nov 15, 2017 at 5:20 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>> On Wed, Nov 15, 2017 at 3:10 AM, Florian Weimer <fweimer@redhat.com> wrote:
>>>> On 11/14/2017 02:10 PM, H.J. Lu wrote:
>>>>>
>>>>> +static int
>>>>> +do_test (void)
>>>>> +{
>>>>> +  sigjmp_buf sj;
>>>>> +  struct support_next_to_fault sigset_t_buf
>>>>> +    = support_next_to_fault_allocate (SIZEOF_SIGSET_T);
>>>>> +  sigset_t *m_p = (sigset_t *) sigset_t_buf.buffer;
>>>>> +  sigset_t m;
>>>>> +
>>>>> +  sigemptyset (&m);
>>>>> +  memcpy (m_p, &m, SIZEOF_SIGSET_T);
>>>>> +  sigprocmask (SIG_SETMASK, m_p, NULL);
>>>>> +  memcpy (&m, m_p, SIZEOF_SIGSET_T);
>>>>> +  if (sigsetjmp (sj, 0) == 0)
>>>>> +    {
>>>>> +      sigaddset (&m, SIGUSR1);
>>>>> +      memcpy (m_p, &m, SIZEOF_SIGSET_T);
>>>>> +      sigprocmask (SIG_SETMASK, m_p, NULL);
>>>>> +      memcpy (&m, m_p, SIZEOF_SIGSET_T);
>>>>> +      siglongjmp (sj, 1);
>>>>> +      return EXIT_FAILURE;
>>>>> +    }
>>>>> +  sigprocmask (SIG_SETMASK, NULL, m_p);
>>>>> +  memcpy (&m, m_p, SIZEOF_SIGSET_T);
>>>>> +  return sigismember (&m, SIGUSR1) ? EXIT_SUCCESS : EXIT_FAILURE;
>>>>> +}
>>>>
>>>>
>>>> Sorry, I don't understand anymore what this test is supposed to test and
>>>> how.
>>>
>>> This tests the reduced __jmp_buf_sigset_t used by __saved_mask is
>>> bigger than sigset expected by kernel.
>>>
>>>> To be honest, I don't like how you inject the internal definition of
>>>> jmp_buf.  Is this the way we do it for the nptl types?
>>>
>>> I only need to make some room in
>>>
>>> /* Calling environment, plus possibly a saved signal mask.  */
>>> struct __jmp_buf_tag
>>>   {
>>>     /* NOTE: The machine-dependent definitions of `__sigsetjmp'
>>>        assume that a `jmp_buf' begins with a `__jmp_buf' and that
>>>        `__mask_was_saved' follows it.  Do not move these members
>>>        or add others before it.  */
>>>     __jmp_buf __jmpbuf; /* Calling environment.  */
>>>     int __mask_was_saved; /* Saved the signal mask?  */
>>>     __sigset_t __saved_mask; /* Saved signal mask.  */
>>>   };
>>>
>>> for target specific purpose.   I changed it to
>>>
>>> struct __jmp_buf_tag
>>>   {
>>>     /* NOTE: The machine-dependent definitions of `__sigsetjmp'
>>>        assume that a `jmp_buf' begins with a `__jmp_buf' and that
>>>        `__mask_was_saved' follows it.  Do not move these members
>>>        or add others before it.  */
>>>     __jmp_buf __jmpbuf; /* Calling environment.  */
>>>     int __mask_was_saved; /* Saved the signal mask?  */
>>>     union
>>>     {
>>>     __sigset_t __saved_mask_compat;
>>>     struct
>>>       {
>>> __jmp_buf_sigset_t __saved_mask;
>>> /* Paddings for architecture specific usage.  */
>>> unsigned long int __padding[12];
>>>       } __saved;
>>>     }  __saved_mask;
>>>   };
>>>
>>> #define __saved_mask __saved_mask.__saved.__saved_mask
>>>
>>> I did only to  __sigset_t  in __jmp_buf_tag and this test verifies that the size
>>> of __jmp_buf_sigset_t works with sigprocmask.
>>>
>>> Are you suggesting we make some room in __sigset_t directly?  This will
>>> require very extensive changes. If not, what do you exactly suggest?
>>>
>>>> I think you should check _JUMP_BUF_SIGSET_NSIG against a kernel constant
>>>> (_NSIGS?) somewhere.
>>>
>>> There is a _Static_assert in include/setjmp.h.  But it isn't triggered.  This
>>> updated patch moves it to sysdeps/unix/sysv/linux/__saved_mask.h.   Now
>>> I got
>>>
>>> ../sysdeps/unix/sysv/linux/__saved_mask.h:32:1: error: static
>>> assertion failed: "size of ___saved_mask < size of
>>> __sigprocmask_sigset_t"
>>>  _Static_assert (sizeof (___saved_mask) >= sizeof (__sigprocmask_sigset_t),
>>>
>>> if __jmp_buf_sigset_t is too small.
>>>
>>> --
>>> H.J.
>>
>> Any comments, suggestions or objections?  The patch is at
>>
>> https://sourceware.org/ml/libc-alpha/2017-11/msg00510.html
>>
>
> This is the updated patch.  It limited the changes to Linux/x86.
> Any comments?
>

This is the patch I am checking in tomorrow.

Andrew, you can include <jmp_buf-ssp.h> to get
SHADOW_STACK_POINTER_OFFSET in jmp_buf.


-- 
H.J.

[-- Attachment #2: 0001-x86-Make-a-space-in-jmpbuf-for-shadow-stack-pointer.patch --]
[-- Type: text/x-patch, Size: 11386 bytes --]

From 902cbf786768eb04dde1c7333ff40ecae15f8a54 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sat, 10 Jun 2017 17:23:06 -0700
Subject: [PATCH] x86: Make a space in jmpbuf for shadow stack pointer

To support Shadow Stack (SHSTK) in Intel Control-flow Enforcement
Technology (CET) in setjmp/longjmp, we need to save shadow stack
pointer in jmp_buf.  The __saved_mask field in jmp_buf has type
of __sigset_t.  On Linux, __sigset_t is defined as

 #define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
  unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;

which is much bigger than expected by the __sigprocmask system call,
which has

typedef struct {
        unsigned long sig[_NSIG_WORDS];
} sigset_t;

For Linux/x86, we can shrink __sigset_t used by __saved_mask in jmp_buf
to add paddings for shadow stack pointer.  As long as the new __sigset_t
is not smaller than sigset_t expected by the __sigprocmask system call,
it should work correctly.

This patch adds an internal header file, <setjmpP.h>, to define
__jmp_buf_sigset_t for __saved_mask in jmp_buf for Linux/x86 with a
space to store shadow stack pointer.  It verifies __jmp_buf_sigset_t has
the suitable size for the __sigprocmask system call.   A run-time test,
tst-saved_mask-1.c, is added to verify that size of __jmp_buf_sigset_t
is sufficient.  If its size is too small, the test fails with

rt_sigprocmask(SIG_SETMASK, strace: umoven: short read (4 < 8) @0x7fa8aa28effc
0x7fa8aa28effc, NULL, 8) = -1 EFAULT (Bad address)
rt_sigprocmask(SIG_SETMASK, strace: umoven: short read (4 < 8) @0x7fa8aa28effc
0x7fa8aa28effc, NULL, 8) = -1 EFAULT (Bad address)
rt_sigprocmask(SIG_SETMASK, NULL, 0x7fa8aa28effc, 8) = -1 EFAULT (Bad address)
exit_group(1)                           = ?

Tested with build-many-glibcs.py.

	* debug/longjmp_chk.c: Include <setjmpP.h> instead of
	<setjmp.h>.
	* setjmp/longjmp.c: Include <setjmpP.h> instead of <setjmp.h>.
	(__libc_siglongjmp): Cast &env[0].__saved_mask to "sigset_t *".
	* setjmp/sigjmp.c: Include <setjmpP.h> instead of <setjmp.h>.
	(__sigjmp_save): Cast &env[0].__saved_mask to "sigset_t *".
	* sysdeps/generic/setjmpP.h: New file.
	* sysdeps/unix/sysv/linux/x86/jmp_buf-ssp.sym: Likewise.
	* sysdeps/unix/sysv/linux/x86/setjmpP.h: Likewise.
	* sysdeps/unix/sysv/linux/x86/tst-saved_mask-1.c: Likewise.
	* sysdeps/unix/sysv/linux/x86/Makefile (gen-as-const-headers):
	Add jmp_buf-ssp.sym.
	(tests): Add tst-saved_mask-1.
---
 debug/longjmp_chk.c                            |  2 +-
 setjmp/longjmp.c                               |  5 +-
 setjmp/sigjmp.c                                |  4 +-
 sysdeps/generic/setjmpP.h                      | 24 +++++++++
 sysdeps/unix/sysv/linux/x86/Makefile           |  5 ++
 sysdeps/unix/sysv/linux/x86/jmp_buf-ssp.sym    |  5 ++
 sysdeps/unix/sysv/linux/x86/setjmpP.h          | 67 ++++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/x86/tst-saved_mask-1.c | 55 +++++++++++++++++++++
 8 files changed, 162 insertions(+), 5 deletions(-)
 create mode 100644 sysdeps/generic/setjmpP.h
 create mode 100644 sysdeps/unix/sysv/linux/x86/jmp_buf-ssp.sym
 create mode 100644 sysdeps/unix/sysv/linux/x86/setjmpP.h
 create mode 100644 sysdeps/unix/sysv/linux/x86/tst-saved_mask-1.c

diff --git a/debug/longjmp_chk.c b/debug/longjmp_chk.c
index 1cea6c05ef..61be0da0cd 100644
--- a/debug/longjmp_chk.c
+++ b/debug/longjmp_chk.c
@@ -15,7 +15,7 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <setjmp.h>
+#include <setjmpP.h>
 
 #define __longjmp ____longjmp_chk
 #define __libc_siglongjmp __longjmp_chk
diff --git a/setjmp/longjmp.c b/setjmp/longjmp.c
index 2453c2c124..e144a874d7 100644
--- a/setjmp/longjmp.c
+++ b/setjmp/longjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 
@@ -31,7 +31,8 @@ __libc_siglongjmp (sigjmp_buf env, int val)
 
   if (env[0].__mask_was_saved)
     /* Restore the saved signal mask.  */
-    (void) __sigprocmask (SIG_SETMASK, &env[0].__saved_mask,
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
 			  (sigset_t *) NULL);
 
   /* Call the machine-dependent function to restore machine state.  */
diff --git a/setjmp/sigjmp.c b/setjmp/sigjmp.c
index 30839ae819..32b727fae8 100644
--- a/setjmp/sigjmp.c
+++ b/setjmp/sigjmp.c
@@ -16,7 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stddef.h>
-#include <setjmp.h>
+#include <setjmpP.h>
 #include <signal.h>
 
 /* This function is called by the `sigsetjmp' macro
@@ -28,7 +28,7 @@ __sigjmp_save (sigjmp_buf env, int savemask)
 {
   env[0].__mask_was_saved = (savemask &&
 			     __sigprocmask (SIG_BLOCK, (sigset_t *) NULL,
-					    &env[0].__saved_mask) == 0);
+					    (sigset_t *) &env[0].__saved_mask) == 0);
 
   return 0;
 }
diff --git a/sysdeps/generic/setjmpP.h b/sysdeps/generic/setjmpP.h
new file mode 100644
index 0000000000..a878ce6b35
--- /dev/null
+++ b/sysdeps/generic/setjmpP.h
@@ -0,0 +1,24 @@
+/* Internal header file for <setjmp.h>.  Generic version.
+   Copyright (C) 2017 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	_SETJMPP_H
+#define	_SETJMPP_H	1
+
+#include <setjmp.h>
+
+#endif /* setjmpP.h  */
diff --git a/sysdeps/unix/sysv/linux/x86/Makefile b/sysdeps/unix/sysv/linux/x86/Makefile
index c069570683..c55a43e58d 100644
--- a/sysdeps/unix/sysv/linux/x86/Makefile
+++ b/sysdeps/unix/sysv/linux/x86/Makefile
@@ -19,3 +19,8 @@ endif
 ifeq ($(subdir),elf)
 sysdep_routines += dl-vdso
 endif
+
+ifeq ($(subdir),setjmp)
+gen-as-const-headers += jmp_buf-ssp.sym
+tests += tst-saved_mask-1
+endif
diff --git a/sysdeps/unix/sysv/linux/x86/jmp_buf-ssp.sym b/sysdeps/unix/sysv/linux/x86/jmp_buf-ssp.sym
new file mode 100644
index 0000000000..12829196db
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/jmp_buf-ssp.sym
@@ -0,0 +1,5 @@
+#include <setjmpP.h>
+#undef __saved_mask
+
+--
+SHADOW_STACK_POINTER_OFFSET offsetof(struct __jmp_buf_tag, __saved_mask.__saved.__shadow_stack_pointer)
diff --git a/sysdeps/unix/sysv/linux/x86/setjmpP.h b/sysdeps/unix/sysv/linux/x86/setjmpP.h
new file mode 100644
index 0000000000..69a46d0ce2
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/setjmpP.h
@@ -0,0 +1,67 @@
+/* Internal header file for <setjmp.h>.  Linux/x86 version.
+   Copyright (C) 2017 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	_SETJMPP_H
+#define	_SETJMPP_H	1
+
+#include <bits/types/__sigset_t.h>
+
+/* The biggest signal number + 1.  As of kernel 4.14, x86 _NSIG is 64.
+   Define it to 513 to leave some rooms for future use.  */
+#define _JUMP_BUF_SIGSET_NSIG	513
+/* Number of longs to hold all signals.  */
+#define _JUMP_BUF_SIGSET_NWORDS \
+  ((_JUMP_BUF_SIGSET_NSIG - 1 + 7) / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_JUMP_BUF_SIGSET_NWORDS];
+  } __jmp_buf_sigset_t;
+
+typedef union
+  {
+    __sigset_t __saved_mask_compat;
+    struct
+      {
+	__jmp_buf_sigset_t __saved_mask;
+	/* Used for shadow stack pointer.  */
+	unsigned long int __shadow_stack_pointer;
+      } __saved;
+  } __jmpbuf_arch_t;
+
+#undef __sigset_t
+#define __sigset_t __jmpbuf_arch_t
+#include <setjmp.h>
+#undef __saved_mask
+#define __saved_mask __saved_mask.__saved.__saved_mask
+
+#include <signal.h>
+
+#define _SIGPROCMASK_NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int)))
+
+typedef struct
+  {
+    unsigned long int __val[_SIGPROCMASK_NSIG_WORDS];
+  } __sigprocmask_sigset_t;
+
+extern jmp_buf ___buf;
+extern  __typeof (___buf[0].__saved_mask) ___saved_mask;
+_Static_assert (sizeof (___saved_mask) >= sizeof (__sigprocmask_sigset_t),
+		"size of ___saved_mask < size of __sigprocmask_sigset_t");
+
+#endif /* setjmpP.h  */
diff --git a/sysdeps/unix/sysv/linux/x86/tst-saved_mask-1.c b/sysdeps/unix/sysv/linux/x86/tst-saved_mask-1.c
new file mode 100644
index 0000000000..f383408b63
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/tst-saved_mask-1.c
@@ -0,0 +1,55 @@
+/* Test that sigprocmask does not read from the unused part of jmpbuf.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <setjmpP.h>
+#include <support/next_to_fault.h>
+
+#define SIZEOF_SIGSET_T sizeof (__jmp_buf_sigset_t)
+
+static int
+do_test (void)
+{
+  sigjmp_buf sj;
+  struct support_next_to_fault sigset_t_buf
+    = support_next_to_fault_allocate (SIZEOF_SIGSET_T);
+  sigset_t *m_p = (sigset_t *) sigset_t_buf.buffer;
+  sigset_t m;
+
+  sigemptyset (&m);
+  memcpy (m_p, &m, SIZEOF_SIGSET_T);
+  sigprocmask (SIG_SETMASK, m_p, NULL);
+  memcpy (&m, m_p, SIZEOF_SIGSET_T);
+  if (sigsetjmp (sj, 0) == 0)
+    {
+      sigaddset (&m, SIGUSR1);
+      memcpy (m_p, &m, SIZEOF_SIGSET_T);
+      sigprocmask (SIG_SETMASK, m_p, NULL);
+      memcpy (&m, m_p, SIZEOF_SIGSET_T);
+      siglongjmp (sj, 1);
+      return EXIT_FAILURE;
+    }
+  sigprocmask (SIG_SETMASK, NULL, m_p);
+  memcpy (&m, m_p, SIZEOF_SIGSET_T);
+  return sigismember (&m, SIGUSR1) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+#include <support/test-driver.c>
-- 
2.14.3


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2017-11-29 21:16 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-07 22:39 [PATCH 2/2] jmpbuf: Add paddings for target specific usage H.J. Lu
2017-11-08  6:06 ` Florian Weimer
2017-11-08 18:27   ` H.J. Lu
2017-11-13 13:09     ` Florian Weimer
2017-11-13 14:05       ` H.J. Lu
2017-11-13 16:34         ` Florian Weimer
2017-11-13 16:44           ` H.J. Lu
2017-11-13 19:40             ` H.J. Lu
2017-11-13 23:22               ` H.J. Lu
2017-11-14 12:26                 ` Florian Weimer
2017-11-14 13:11                   ` H.J. Lu
2017-11-15 11:10                     ` Florian Weimer
2017-11-15 13:20                       ` H.J. Lu
2017-11-21 22:22                         ` H.J. Lu
2017-11-25 16:34                           ` H.J. Lu
2017-11-29 21:16                             ` H.J. Lu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).