V2 [PATCH] x86/CET: Add a setcontext test for CET

Message ID CAMe9rOrCwy5vpQNHMXCkDU2Y7CMdnLim1rvLhvOwOQnCqAB-qw@mail.gmail.com
State New, archived
Headers

Commit Message

H.J. Lu July 25, 2018, 3:01 p.m. UTC
  On Wed, Jul 25, 2018 at 6:29 AM, Carlos O'Donell <carlos@redhat.com> wrote:
> On 07/25/2018 08:22 AM, H.J. Lu wrote:
>> Verify that setcontext works with gaps above and below the newly
>> allocated shadow stack.
>>
>> OK for master?
>>
>> H.J.
>> ---
>>       * sysdeps/x86/Makefile (tests): Add tst-cet-setcontext-1 if
>>       CET is enabled.
>>       (CFLAGS-tst-cet-setcontext-1.c): Add -mshstk.
>>       * sysdeps/x86/tst-cet-setcontext-1.c: New file.
>
> OK for 2.28 only if you add a paragraph about exactly how the shadow
> stacks are being laid out by the calls and why unmapping ctx3 and ctx4 works
> to leave ctx1 with gap above and below.
>

Here is the updated patch with a comment:

  /* NB: When shadow stack is enabled, makecontext calls arch_prctl
     with ARCH_CET_ALLOC_SHSTK to allocate a new shadow stack which
     can be unmapped.  The base address and size of the new shadow
     stack are returned in __ssp[1] and __ssp[2].  makecontext is
     called for CTX1, CTX3 and CTX4.  But only CTX1 is used.  New
     shadow stacks are allocated in the order of CTX3, CTX1, CTX4.
     It is very likely that CTX1's shadow stack is placed between
     CTX3 and CTX4.  We munmap CTX3's and CTX4's shadow stacks to
     create gaps above and below CTX1's shadow stack.  We check that
     setcontext CTX1 works correctly in this case.  */

It is also moved to sysdeps/unix/sysv/linux/x86/tst-cet-setcontext-1.c since
it is Linux/x86 specific.

OK for master?

Thanks.
  

Comments

Carlos O'Donell July 25, 2018, 3:34 p.m. UTC | #1
On 07/25/2018 11:01 AM, H.J. Lu wrote:
> On Wed, Jul 25, 2018 at 6:29 AM, Carlos O'Donell <carlos@redhat.com> wrote:
>> On 07/25/2018 08:22 AM, H.J. Lu wrote:
>>> Verify that setcontext works with gaps above and below the newly
>>> allocated shadow stack.
>>>
>>> OK for master?
>>>
>>> H.J.
>>> ---
>>>       * sysdeps/x86/Makefile (tests): Add tst-cet-setcontext-1 if
>>>       CET is enabled.
>>>       (CFLAGS-tst-cet-setcontext-1.c): Add -mshstk.
>>>       * sysdeps/x86/tst-cet-setcontext-1.c: New file.
>>
>> OK for 2.28 only if you add a paragraph about exactly how the shadow
>> stacks are being laid out by the calls and why unmapping ctx3 and ctx4 works
>> to leave ctx1 with gap above and below.
>>
> 
> Here is the updated patch with a comment:
> 
>   /* NB: When shadow stack is enabled, makecontext calls arch_prctl
>      with ARCH_CET_ALLOC_SHSTK to allocate a new shadow stack which
>      can be unmapped.  The base address and size of the new shadow
>      stack are returned in __ssp[1] and __ssp[2].  makecontext is
>      called for CTX1, CTX3 and CTX4.  But only CTX1 is used.  New
>      shadow stacks are allocated in the order of CTX3, CTX1, CTX4.
>      It is very likely that CTX1's shadow stack is placed between
>      CTX3 and CTX4.  We munmap CTX3's and CTX4's shadow stacks to
>      create gaps above and below CTX1's shadow stack.  We check that
>      setcontext CTX1 works correctly in this case.  */

Perfect!

> It is also moved to sysdeps/unix/sysv/linux/x86/tst-cet-setcontext-1.c since
> it is Linux/x86 specific.
> 
> OK for master?

OK for 2.28.

Thanks for the update.

Cheers,
Carlos.
  

Patch

From 7b1a739cec11ac76e712769ecdd8585e0e74ad9c Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Tue, 24 Jul 2018 14:58:25 -0700
Subject: [PATCH] x86/CET: Add a setcontext test for CET

Verify that setcontext works with gaps above and below the newly
allocated shadow stack.

	* sysdeps/unix/sysv/linux/x86/Makefile (tests): Add
	tst-cet-setcontext-1 if CET is enabled.
	(CFLAGS-tst-cet-setcontext-1.c): Add -mshstk.
	* sysdeps/unix/sysv/linux/x86/tst-cet-setcontext-1.c: New file.
---
 sysdeps/unix/sysv/linux/x86/Makefile          |   7 +
 .../sysv/linux/x86/tst-cet-setcontext-1.c     | 127 ++++++++++++++++++
 2 files changed, 134 insertions(+)
 create mode 100644 sysdeps/unix/sysv/linux/x86/tst-cet-setcontext-1.c

diff --git a/sysdeps/unix/sysv/linux/x86/Makefile b/sysdeps/unix/sysv/linux/x86/Makefile
index 111ff9ff58..a30fdb1dc1 100644
--- a/sysdeps/unix/sysv/linux/x86/Makefile
+++ b/sysdeps/unix/sysv/linux/x86/Makefile
@@ -23,3 +23,10 @@  endif
 ifeq ($(subdir),setjmp)
 tests += tst-saved_mask-1
 endif
+
+ifeq ($(enable-cet),yes)
+ifeq ($(subdir),stdlib)
+tests += tst-cet-setcontext-1
+CFLAGS-tst-cet-setcontext-1.c += -mshstk
+endif
+endif
diff --git a/sysdeps/unix/sysv/linux/x86/tst-cet-setcontext-1.c b/sysdeps/unix/sysv/linux/x86/tst-cet-setcontext-1.c
new file mode 100644
index 0000000000..ecf86a9e16
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/tst-cet-setcontext-1.c
@@ -0,0 +1,127 @@ 
+/* Check getcontext and setcontext on the context from makecontext
+   with shadow stack.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <ucontext.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdatomic.h>
+#include <x86intrin.h>
+
+static ucontext_t ctx[5];
+static atomic_int done;
+
+static void
+__attribute__((noinline, noclone))
+f2 (void)
+{
+  printf ("start f2\n");
+  done++;
+  if (setcontext (&ctx[2]) != 0)
+    {
+      printf ("%s: setcontext: %m\n", __FUNCTION__);
+      exit (EXIT_FAILURE);
+    }
+}
+
+static void
+f1 (void)
+{
+  printf ("start f1\n");
+  if (getcontext (&ctx[2]) != 0)
+    {
+      printf ("%s: getcontext: %m\n", __FUNCTION__);
+      exit (EXIT_FAILURE);
+    }
+  if (done)
+    exit (EXIT_SUCCESS);
+  f2 ();
+}
+
+static int
+do_test (void)
+{
+  char st1[32768];
+  puts ("making contexts");
+  if (getcontext (&ctx[0]) != 0)
+    {
+      printf ("%s: getcontext: %m\n", __FUNCTION__);
+      exit (EXIT_FAILURE);
+    }
+  if (getcontext (&ctx[1]) != 0)
+    {
+      printf ("%s: getcontext: %m\n", __FUNCTION__);
+      exit (EXIT_FAILURE);
+    }
+
+  ctx[3].uc_stack.ss_sp = st1;
+  ctx[3].uc_stack.ss_size = sizeof st1;
+  ctx[3].uc_link = &ctx[0];
+  makecontext (&ctx[3], (void (*) (void)) f1, 0);
+
+  ctx[1].uc_stack.ss_sp = st1;
+  ctx[1].uc_stack.ss_size = sizeof st1;
+  ctx[1].uc_link = &ctx[0];
+  makecontext (&ctx[1], (void (*) (void)) f1, 0);
+
+  ctx[4].uc_stack.ss_sp = st1;
+  ctx[4].uc_stack.ss_size = sizeof st1;
+  ctx[4].uc_link = &ctx[0];
+  makecontext (&ctx[4], (void (*) (void)) f1, 0);
+
+  /* NB: When shadow stack is enabled, makecontext calls arch_prctl
+     with ARCH_CET_ALLOC_SHSTK to allocate a new shadow stack which
+     can be unmapped.  The base address and size of the new shadow
+     stack are returned in __ssp[1] and __ssp[2].  makecontext is
+     called for CTX1, CTX3 and CTX4.  But only CTX1 is used.  New
+     shadow stacks are allocated in the order of CTX3, CTX1, CTX4.
+     It is very likely that CTX1's shadow stack is placed between
+     CTX3 and CTX4.  We munmap CTX3's and CTX4's shadow stacks to
+     create gaps above and below CTX1's shadow stack.  We check
+     that setcontext CTX1 works correctly in this case.  */
+  if (_get_ssp () != 0)
+    {
+      if (ctx[3].__ssp[1] != 0
+	  && munmap ((void *) (uintptr_t) ctx[3].__ssp[1],
+		     (size_t) ctx[3].__ssp[2]) != 0)
+	{
+	  printf ("%s: munmap: %m\n", __FUNCTION__);
+	  exit (EXIT_FAILURE);
+	}
+
+      if (ctx[4].__ssp[1] != 0
+	  && munmap ((void *) (uintptr_t) ctx[4].__ssp[1],
+		     (size_t) ctx[4].__ssp[2]) != 0)
+	{
+	  printf ("%s: munmap: %m\n", __FUNCTION__);
+	  exit (EXIT_FAILURE);
+	}
+    }
+
+  if (setcontext (&ctx[1]) != 0)
+    {
+      printf ("%s: setcontext: %m\n", __FUNCTION__);
+      exit (EXIT_FAILURE);
+    }
+  exit (EXIT_FAILURE);
+}
+
+#include <support/test-driver.c>
-- 
2.17.1