about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rw-r--r--sysdeps/unix/sysv/linux/x86/Makefile15
-rw-r--r--sysdeps/unix/sysv/linux/x86/tst-cet-property-1.c44
-rw-r--r--sysdeps/unix/sysv/linux/x86/tst-cet-property-2.c63
-rw-r--r--sysdeps/unix/sysv/linux/x86/tst-cet-property-dep-2.S63
-rw-r--r--sysdeps/x86/dl-prop.h29
6 files changed, 220 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index 75796ee7d6..669bc3c8ae 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,20 @@
 2018-07-30  H.J. Lu  <hongjiu.lu@intel.com>
 
+	[BZ #23467]
+	* sysdeps/unix/sysv/linux/x86/Makefile (tests): Add
+	tst-cet-property-1 and tst-cet-property-2 if CET is enabled.
+	(CFLAGS-tst-cet-property-1.o): New.
+	(ASFLAGS-tst-cet-property-dep-2.o): Likewise.
+	($(objpfx)tst-cet-property-2): Likewise.
+	($(objpfx)tst-cet-property-2.out): Likewise.
+	* sysdeps/unix/sysv/linux/x86/tst-cet-property-1.c: New file.
+	* sysdeps/unix/sysv/linux/x86/tst-cet-property-2.c: Likewise.
+	* sysdeps/unix/sysv/linux/x86/tst-cet-property-dep-2.S: Likewise.
+	* sysdeps/x86/dl-prop.h (_dl_process_cet_property_note): Parse
+	each property item until GNU_PROPERTY_X86_FEATURE_1_AND is found.
+
+2018-07-30  H.J. Lu  <hongjiu.lu@intel.com>
+
 	[BZ #23458]
 	* sysdeps/x86/Makefile (tests): Add tst-get-cpu-features-static.
 
diff --git a/sysdeps/unix/sysv/linux/x86/Makefile b/sysdeps/unix/sysv/linux/x86/Makefile
index a30fdb1dc1..7dc4e61756 100644
--- a/sysdeps/unix/sysv/linux/x86/Makefile
+++ b/sysdeps/unix/sysv/linux/x86/Makefile
@@ -25,6 +25,21 @@ tests += tst-saved_mask-1
 endif
 
 ifeq ($(enable-cet),yes)
+ifeq ($(subdir),elf)
+tests += tst-cet-property-1 tst-cet-property-2
+
+CFLAGS-tst-cet-property-1.o += -fcf-protection
+ASFLAGS-tst-cet-property-dep-2.o += -fcf-protection
+
+$(objpfx)tst-cet-property-2: $(objpfx)tst-cet-property-dep-2.o
+$(objpfx)tst-cet-property-2.out: $(objpfx)tst-cet-property-2 \
+				 $(objpfx)tst-cet-property-1.out
+	env $(run-program-env) $(test-via-rtld-prefix) \
+	  $(objpfx)tst-cet-property-2 \
+	  < $(objpfx)tst-cet-property-1.out > $@; \
+	  $(evaluate-test)
+endif
+
 ifeq ($(subdir),stdlib)
 tests += tst-cet-setcontext-1
 CFLAGS-tst-cet-setcontext-1.c += -mshstk
diff --git a/sysdeps/unix/sysv/linux/x86/tst-cet-property-1.c b/sysdeps/unix/sysv/linux/x86/tst-cet-property-1.c
new file mode 100644
index 0000000000..21130faefc
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/tst-cet-property-1.c
@@ -0,0 +1,44 @@
+/* Test CET property note parser.
+   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 <elf.h>
+#include <tcb-offsets.h>
+
+/* This test prints out "IBT" if Intel indirect branch tracking (IBT)
+   is enabled at run-time, which is checked by tst-cet-property-2 to
+   verify that the IBT violation is caught on IBT machines.  */
+
+static int
+do_test (void)
+{
+  unsigned int feature_1;
+#ifdef __x86_64__
+# define SEG_REG "fs"
+#else
+# define SEG_REG "gs"
+#endif
+  asm ("movl %%" SEG_REG ":%P1, %0"
+       : "=r" (feature_1) : "i" (FEATURE_1_OFFSET));
+  if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0)
+    printf ("IBT\n");
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86/tst-cet-property-2.c b/sysdeps/unix/sysv/linux/x86/tst-cet-property-2.c
new file mode 100644
index 0000000000..0531074ceb
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/tst-cet-property-2.c
@@ -0,0 +1,63 @@
+/* Test CET property note parser for [BZ #23467].
+   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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <support/check.h>
+
+extern void bar (void);
+
+void
+__attribute__ ((noclone, noinline))
+test (void (*func_p) (void))
+{
+  func_p ();
+}
+
+/* bar contains an IBT violation if it is called indirectly via a
+   function pointer.  On IBT machines, it should lead to segfault
+   unless IBT is disabled by error.  */
+
+static void
+sig_handler (int signo)
+{
+  exit (EXIT_SUCCESS);
+}
+
+static int
+do_test (void)
+{
+  char buf[20];
+
+  if (scanf ("%20s", buf) != 1)
+    FAIL_UNSUPPORTED ("IBT not supported");
+
+  if (strcmp (buf, "IBT") != 0)
+    FAIL_UNSUPPORTED ("IBT not supported");
+
+  TEST_VERIFY_EXIT (signal (SIGSEGV, &sig_handler) != SIG_ERR);
+
+  /* Call bar via a function pointer to force an IBT violation.  */
+  test (bar);
+
+  return EXIT_FAILURE;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86/tst-cet-property-dep-2.S b/sysdeps/unix/sysv/linux/x86/tst-cet-property-dep-2.S
new file mode 100644
index 0000000000..5f5cad34d9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/tst-cet-property-dep-2.S
@@ -0,0 +1,63 @@
+/* Test CET property note parser.
+   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 <cet.h>
+
+	.text
+	.p2align 4,,15
+	.globl	bar
+	.type	bar, @function
+/* Since this function doesn't start with ENDBR, it should lead to the
+   IBT violation when called indirectly.  */
+bar:
+	.cfi_startproc
+	ret
+	.cfi_endproc
+	.size	bar, .-bar
+
+#if __SIZEOF_PTRDIFF_T__  == 8
+# define ALIGN 3
+#elif __SIZEOF_PTRDIFF_T__  == 4
+# define ALIGN 2
+#endif
+
+/* In NT_GNU_PROPERTY_TYPE_0 note, add a GNU_PROPERTY_STACK_SIZE property
+   before the GNU_PROPERTY_X86_FEATURE_1_AND property.  */
+	.section ".note.gnu.property", "a"
+	.p2align ALIGN
+	.long 1f - 0f		/* name length */
+	.long 5f - 2f		/* data length */
+	.long 5			/* note type */
+0:	.asciz "GNU"		/* vendor name */
+1:
+	.p2align ALIGN
+2:
+	.long 1			/* pr_type.  */
+	.long 4f - 3f		/* pr_datasz.  */
+3:
+#if __SIZEOF_PTRDIFF_T__  == 8
+	.long 0x800
+	.long 0x800
+#else
+	.long 0x08000800
+#endif
+4:
+	.p2align ALIGN
+5:
+
+	.section	.note.GNU-stack,"",@progbits
diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h
index 35d3f16a23..26c3131ac5 100644
--- a/sysdeps/x86/dl-prop.h
+++ b/sysdeps/x86/dl-prop.h
@@ -73,7 +73,7 @@ _dl_process_cet_property_note (struct link_map *l,
 	  unsigned char *ptr = (unsigned char *) (note + 1) + 4;
 	  unsigned char *ptr_end = ptr + note->n_descsz;
 
-	  while (ptr < ptr_end)
+	  do
 	    {
 	      unsigned int type = *(unsigned int *) ptr;
 	      unsigned int datasz = *(unsigned int *) (ptr + 4);
@@ -82,17 +82,28 @@ _dl_process_cet_property_note (struct link_map *l,
 	      if ((ptr + datasz) > ptr_end)
 		break;
 
-	      if (type == GNU_PROPERTY_X86_FEATURE_1_AND
-		  && datasz == 4)
+	      if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
 		{
-		  unsigned int feature_1 = *(unsigned int *) ptr;
-		  if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT))
-		    l->l_cet |= lc_ibt;
-		  if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
-		    l->l_cet |= lc_shstk;
-		  break;
+		  /* The size of GNU_PROPERTY_X86_FEATURE_1_AND is 4
+		     bytes.  When seeing GNU_PROPERTY_X86_FEATURE_1_AND,
+		     we stop the search regardless if its size is correct
+		     or not.  There is no point to continue if this note
+		     is ill-formed.  */
+		  if (datasz == 4)
+		    {
+		      unsigned int feature_1 = *(unsigned int *) ptr;
+		      if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT))
+			l->l_cet |= lc_ibt;
+		      if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
+			l->l_cet |= lc_shstk;
+		    }
+		  return;
 		}
+
+	      /* Check the next property item.  */
+	      ptr += ALIGN_UP (datasz, sizeof (ElfW(Addr)));
 	    }
+	  while ((ptr_end - ptr) >= 8);
 	}
 
       /* NB: Note sections like .note.ABI-tag and .note.gnu.build-id are