diff options
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/x86/Makefile | 15 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/x86/tst-cet-property-1.c | 44 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/x86/tst-cet-property-2.c | 63 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/x86/tst-cet-property-dep-2.S | 63 | ||||
-rw-r--r-- | sysdeps/x86/dl-prop.h | 29 |
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 |