RFC: Shadow Stack support in glibc
Commit Message
On Fri, Jun 9, 2017 at 8:03 AM, Florian Weimer <fweimer@redhat.com> wrote:
> "H.J. Lu" <hjl.tools@gmail.com> writes:
>
>> We can use the unused space for SSP.
>
> Great. :)
Something like the patch here?
> Please note that SSP already stands for “stack smashing protector”, so
> it's probably best not reuse the same abbreviation for another hardening
> feature.
SSR (Shadow Stack Register)?
Comments
On Fri, 9 Jun 2017, H.J. Lu wrote:
> On Fri, Jun 9, 2017 at 8:03 AM, Florian Weimer <fweimer@redhat.com> wrote:
> > "H.J. Lu" <hjl.tools@gmail.com> writes:
> >
> >> We can use the unused space for SSP.
> >
> > Great. :)
>
> Something like the patch here?
Both "u" and the contents of <stdint.h> are outside the <setjmp.h>
namespace. And I'd strongly discourage having sysdeps versions of any
headers other than bits/ and sys/ ones, since they tend to get out of sync
with the generic versions (and in this case, the include/setjmp.h wouldn't
properly include your sysdeps version).
On 09/06/17 16:39, H.J. Lu wrote:
> Since the __saved_mask field in jmp_buf is unused for x86, replace
> __saved_mask with a union to save save shadow stack pointer while
> keeping the size of jmp_buf unchanged.
>
> * sysdeps/x86/setjmp.h: New file.
sigsetjmp/siglongjmp has to save/restore the signal mask
but the signal mask size on linux is at most 16bytes (?)
and glibc uses 128 byte sigset_t.
so instead of the union below, i'd expect a solution where
if !HURD then the first 16bytes of __saved_mask and the rest
can be accessed separately and the tail bytes are usable
for target specific data.
> +/* 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? */
> + union
> + {
> + /* Saved shadow stack pointer. */
> + uintptr_t __saved_shadow_stack_pointer;
> + /* Saved signal mask. */
> + __sigset_t __saved_mask;
> + } u;
> + };
From 96f7b89f1850a0daa771b812eead76076525eadd Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri, 9 Jun 2017 08:34:44 -0700
Subject: [PATCH] x86: Add a field to jmp_buf to save shadow stack pointer
Since the __saved_mask field in jmp_buf is unused for x86, replace
__saved_mask with a union to save save shadow stack pointer while
keeping the size of jmp_buf unchanged.
* sysdeps/x86/setjmp.h: New file.
---
sysdeps/x86/setjmp.h | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 112 insertions(+)
create mode 100644 sysdeps/x86/setjmp.h
new file mode 100644
@@ -0,0 +1,112 @@
+/* Copyright (C) 1991-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 _SETJMP_H
+#define _SETJMP_H 1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+#include <stdint.h> /* Get uintptr_t. */
+#include <bits/setjmp.h> /* Get `__jmp_buf'. */
+#include <bits/types/__sigset_t.h>
+
+/* 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? */
+ union
+ {
+ /* Saved shadow stack pointer. */
+ uintptr_t __saved_shadow_stack_pointer;
+ /* Saved signal mask. */
+ __sigset_t __saved_mask;
+ } u;
+ };
+
+
+typedef struct __jmp_buf_tag jmp_buf[1];
+
+/* Store the calling environment in ENV, also saving the signal mask.
+ Return 0. */
+extern int setjmp (jmp_buf __env) __THROWNL;
+
+/* Store the calling environment in ENV, also saving the
+ signal mask if SAVEMASK is nonzero. Return 0.
+ This is the internal name for `sigsetjmp'. */
+extern int __sigsetjmp (struct __jmp_buf_tag __env[1], int __savemask) __THROWNL;
+
+/* Store the calling environment in ENV, not saving the signal mask.
+ Return 0. */
+extern int _setjmp (struct __jmp_buf_tag __env[1]) __THROWNL;
+
+/* Do not save the signal mask. This is equivalent to the `_setjmp'
+ BSD function. */
+#define setjmp(env) _setjmp (env)
+
+
+/* Jump to the environment saved in ENV, making the
+ `setjmp' call there return VAL, or 1 if VAL is 0. */
+extern void longjmp (struct __jmp_buf_tag __env[1], int __val)
+ __THROWNL __attribute__ ((__noreturn__));
+
+#if defined __USE_MISC || defined __USE_XOPEN
+/* Same. Usually `_longjmp' is used with `_setjmp', which does not save
+ the signal mask. But it is how ENV was saved that determines whether
+ `longjmp' restores the mask; `_longjmp' is just an alias. */
+extern void _longjmp (struct __jmp_buf_tag __env[1], int __val)
+ __THROWNL __attribute__ ((__noreturn__));
+#endif
+
+
+#ifdef __USE_POSIX
+/* Use the same type for `jmp_buf' and `sigjmp_buf'.
+ The `__mask_was_saved' flag determines whether
+ or not `longjmp' will restore the signal mask. */
+typedef struct __jmp_buf_tag sigjmp_buf[1];
+
+/* Store the calling environment in ENV, also saving the
+ signal mask if SAVEMASK is nonzero. Return 0. */
+# define sigsetjmp(env, savemask) __sigsetjmp (env, savemask)
+
+/* Jump to the environment saved in ENV, making the
+ sigsetjmp call there return VAL, or 1 if VAL is 0.
+ Restore the signal mask if that sigsetjmp call saved it.
+ This is just an alias `longjmp'. */
+extern void siglongjmp (sigjmp_buf __env, int __val)
+ __THROWNL __attribute__ ((__noreturn__));
+#endif /* Use POSIX. */
+
+
+/* Define helper functions to catch unsafe code. */
+#if __USE_FORTIFY_LEVEL > 0
+# include <bits/setjmp2.h>
+#endif
+
+__END_DECLS
+
+#endif /* setjmp.h */
--
2.9.4