ucontext.h: Add __INDIRECT_RETURN

Message ID 20180718173558.GA18109@intel.com
State New, archived
Headers

Commit Message

Lu, Hongjiu July 18, 2018, 5:35 p.m. UTC
  On x86, swapcontext returns via indirect branch when shadow stack is
enabled.  Add __INDIRECT_RETURN to swapcontext to mark it return via
indirect branch.  When shadow stack is enabled, __INDIRECT_RETURN is
defined with indirect_return attribute, which has been added to GCC 9.
Otherwise __INDIRECT_RETURN is defined with returns_twice attribute.

When shadow stack is enabled, remove always_inline attribute from
prepare_test_buffer in string/tst-xbzero-opt.c to avoid:

tst-xbzero-opt.c: In function ‘prepare_test_buffer’:
tst-xbzero-opt.c:105:1: error: function ‘prepare_test_buffer’ can never be inlined because it uses setjmp
 prepare_test_buffer (unsigned char *buf)

if indirect_return attribute isn't available.

OK for master branch?


H.J.
---
	* stdlib/ucontext.h (__INDIRECT_RETURN): New.  Define as empty
	if not defined.
	(swapcontext): Add __INDIRECT_RETURN.
	* string/tst-xbzero-opt.c (ALWAYS_INLINE): New.
	(prepare_test_buffer): Use it.
	* sysdeps/unix/sysv/linux/x86/sys/ucontext.h
	(__INDIRECT_RETURN): New.  Defined with indirect_return attribute
	or returns_twice attribute when shadow stack is enabled.
---
 stdlib/ucontext.h                          |  7 ++++++-
 string/tst-xbzero-opt.c                    | 10 +++++++++-
 sysdeps/unix/sysv/linux/x86/sys/ucontext.h | 11 +++++++++++
 3 files changed, 26 insertions(+), 2 deletions(-)
  

Comments

Joseph Myers July 18, 2018, 8:58 p.m. UTC | #1
On Wed, 18 Jul 2018, H.J. Lu wrote:

> +#ifndef __INDIRECT_RETURN
> +# define __INDIRECT_RETURN
> +#endif

This default definition is missing a comment to define the semantics of 
this macro.  And please avoid this #ifndef convention.  Rather, the normal 
glibc convention would be to have e.g. a bits/indirect-return.h installed 
header, with a default version with an empty definition and a comment 
documenting the semantics, and a separate x86 version.
  
Florian Weimer July 18, 2018, 9:06 p.m. UTC | #2
* H. J. Lu:

> +#ifndef __INDIRECT_RETURN
> +# if defined __CET__ && (__CET__ & 2) != 0
> +/* Note: Functions returned via indirect branch returns once.  Without

The grammar seems to be a bit off here.

> +   indirect_return attribute in GCC 9, use returns_twice attribute.  */
> +#  if __GNUC_PREREQ (9, 0)
> +#   define __INDIRECT_RETURN __attribute__ ((__indirect_return__))
> +#  else
> +#   define __INDIRECT_RETURN __attribute__ ((__returns_twice__))
> +#  endif
> +# endif
> +#endif

Do you expect distributions to backport support for the
indirect_return attribute into GCC 8?  Then this will not work.
  
H.J. Lu July 18, 2018, 10:14 p.m. UTC | #3
On Wed, Jul 18, 2018 at 2:06 PM, Florian Weimer <fw@deneb.enyo.de> wrote:
> * H. J. Lu:
>
>> +#ifndef __INDIRECT_RETURN
>> +# if defined __CET__ && (__CET__ & 2) != 0
>> +/* Note: Functions returned via indirect branch returns once.  Without
>
> The grammar seems to be a bit off here.
>
>> +   indirect_return attribute in GCC 9, use returns_twice attribute.  */
>> +#  if __GNUC_PREREQ (9, 0)
>> +#   define __INDIRECT_RETURN __attribute__ ((__indirect_return__))
>> +#  else
>> +#   define __INDIRECT_RETURN __attribute__ ((__returns_twice__))
>> +#  endif
>> +# endif
>> +#endif
>
> Do you expect distributions to backport support for the
> indirect_return attribute into GCC 8?  Then this will not work.

I am running into another swapcontext issue:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86560

I need to change indirect_return to function type attribute to support
function pointer:

https://gcc.gnu.org/ml/gcc-patches/2018-07/msg01007.html

I am planning to backport both patches to GCC 8 branch.  When that
happens, we can change __GNUC_PREREQ (9, 0) to __GNUC_PREREQ (8, x).
Do you have a better solution?
  

Patch

diff --git a/stdlib/ucontext.h b/stdlib/ucontext.h
index eec7611631..0f29c38d71 100644
--- a/stdlib/ucontext.h
+++ b/stdlib/ucontext.h
@@ -25,6 +25,10 @@ 
 /* Get machine dependent definition of data structures.  */
 #include <sys/ucontext.h>
 
+#ifndef __INDIRECT_RETURN
+# define __INDIRECT_RETURN
+#endif
+
 __BEGIN_DECLS
 
 /* Get user context and store it in variable pointed to by UCP.  */
@@ -36,7 +40,8 @@  extern int setcontext (const ucontext_t *__ucp) __THROWNL;
 /* Save current context in context variable pointed to by OUCP and set
    context from variable pointed to by UCP.  */
 extern int swapcontext (ucontext_t *__restrict __oucp,
-			const ucontext_t *__restrict __ucp) __THROWNL;
+			const ucontext_t *__restrict __ucp)
+  __THROWNL __INDIRECT_RETURN;
 
 /* Manipulate user context UCP to continue with calling functions FUNC
    and the ARGC-1 parameters following ARGC when the context is used
diff --git a/string/tst-xbzero-opt.c b/string/tst-xbzero-opt.c
index cf7041f37a..d49ddef9ae 100644
--- a/string/tst-xbzero-opt.c
+++ b/string/tst-xbzero-opt.c
@@ -100,7 +100,15 @@  static ucontext_t uc_main, uc_co;
 /* Always check the test buffer immediately after filling it; this
    makes externally visible side effects depend on the buffer existing
    and having been filled in.  */
-static inline __attribute__  ((always_inline)) void
+#if defined __CET__ && !__GNUC_PREREQ (9, 0)
+/* Note: swapcontext returns via indirect branch when SHSTK is enabled.
+   Without indirect_return attribute in GCC 9, swapcontext is marked
+   with returns_twice attribute, which prevents always_inline to work.  */
+# define ALWAYS_INLINE
+#else
+# define ALWAYS_INLINE	__attribute__  ((always_inline))
+#endif
+static inline ALWAYS_INLINE void
 prepare_test_buffer (unsigned char *buf)
 {
   for (unsigned int i = 0; i < PATTERN_REPS; i++)
diff --git a/sysdeps/unix/sysv/linux/x86/sys/ucontext.h b/sysdeps/unix/sysv/linux/x86/sys/ucontext.h
index afb7c181bf..0b2b1e4804 100644
--- a/sysdeps/unix/sysv/linux/x86/sys/ucontext.h
+++ b/sysdeps/unix/sysv/linux/x86/sys/ucontext.h
@@ -24,6 +24,17 @@ 
 #include <bits/types/sigset_t.h>
 #include <bits/types/stack_t.h>
 
+#ifndef __INDIRECT_RETURN
+# if defined __CET__ && (__CET__ & 2) != 0
+/* Note: Functions returned via indirect branch returns once.  Without
+   indirect_return attribute in GCC 9, use returns_twice attribute.  */
+#  if __GNUC_PREREQ (9, 0)
+#   define __INDIRECT_RETURN __attribute__ ((__indirect_return__))
+#  else
+#   define __INDIRECT_RETURN __attribute__ ((__returns_twice__))
+#  endif
+# endif
+#endif
 
 #ifdef __USE_MISC
 # define __ctx(fld) fld