From patchwork Sat Mar 7 00:25:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 38516 Received: (qmail 89532 invoked by alias); 7 Mar 2020 00:25:39 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 89513 invoked by uid 89); 7 Mar 2020 00:25:39 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.3 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=dlfcnh, UD:dlfcn.h, dlfcn.h X-HELO: mail-pg1-f172.google.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=lRdHGQM/MxFgZuxWiOLbv+nBafNjYRL2Su6nFjETYs4=; b=Pg4igawDS4BbkFHtegytOApPQld6J3bATBZej7M1+26i1djG9W8gn9NYwHPbEg9rgT +7PpaYQfcNUMLUxFy1sgi1xvvWrPmCOJ0uz78Q+LwFCMWKlgLhK06JJHECMkH44DtlSM 5MgvWvZPiKx4whAkMzZ0qQCsZbKkBKs2Ws5LfTXoD4LlrIYPvFz3c77sA8vh6KI7kgvW zwQ2HPJa/cc05ErTdrjsFPH7dEh/4RK6HsJkFBUO5N4oBMG5qjzK0oF7wehaWlfBLx2O rK2urJjBbfL5ByTelIC+x9NXJ5Tg2noih3Yt51E+jvAdzm2nGxYhR6fgo22Zrgl1arLX U9ew== Return-Path: From: "H.J. Lu" To: libc-alpha@sourceware.org Subject: [PATCH] x86: Remove ARCH_CET_LEGACY_BITMAP [BZ #25397] Date: Fri, 6 Mar 2020 16:25:30 -0800 Message-Id: <20200307002530.54013-1-hjl.tools@gmail.com> MIME-Version: 1.0 Since legacy bitmap covers legacy JIT engine, but doesn't cover jitted code generated by legacy JIT engine, it isn't very useful. This patch treats indirect branch tracking (IBT) similar to shadow stack (SHSTK) by removing legacy bitmap support so that both IBT and SHSTK are disabled on legacy JIT engine. --- sysdeps/unix/sysv/linux/x86/dl-cet.h | 20 -- .../unix/sysv/linux/x86/include/asm/prctl.h | 5 - sysdeps/x86/Makefile | 7 +- sysdeps/x86/dl-cet.c | 197 ++++-------------- sysdeps/x86/dl-procruntime.c | 11 - sysdeps/x86/tst-cet-legacy-4.c | 19 +- sysdeps/x86/tst-cet-legacy-7.c | 40 ++++ 7 files changed, 92 insertions(+), 207 deletions(-) create mode 100644 sysdeps/x86/tst-cet-legacy-7.c diff --git a/sysdeps/unix/sysv/linux/x86/dl-cet.h b/sysdeps/unix/sysv/linux/x86/dl-cet.h index 9b2aaa238c..ae97a433a2 100644 --- a/sysdeps/unix/sysv/linux/x86/dl-cet.h +++ b/sysdeps/unix/sysv/linux/x86/dl-cet.h @@ -18,26 +18,6 @@ #include #include -static inline int __attribute__ ((always_inline)) -dl_cet_allocate_legacy_bitmap (unsigned long *legacy_bitmap) -{ - /* Allocate legacy bitmap. */ -#ifdef __LP64__ - return (int) INTERNAL_SYSCALL_CALL (arch_prctl, - ARCH_CET_LEGACY_BITMAP, legacy_bitmap); -#else - unsigned long long legacy_bitmap_u64[2]; - int res = INTERNAL_SYSCALL_CALL (arch_prctl, - ARCH_CET_LEGACY_BITMAP, legacy_bitmap_u64); - if (res == 0) - { - legacy_bitmap[0] = legacy_bitmap_u64[0]; - legacy_bitmap[1] = legacy_bitmap_u64[1]; - } - return res; -#endif -} - static inline int __attribute__ ((always_inline)) dl_cet_disable_cet (unsigned int cet_feature) { diff --git a/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h b/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h index f67f3299b9..45ad0b052f 100644 --- a/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h +++ b/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h @@ -24,9 +24,4 @@ OUT: allocated shadow stack address: *addr. */ # define ARCH_CET_ALLOC_SHSTK 0x3004 -/* Return legacy region bitmap info in unsigned long long *addr: - address: addr[0]. - size: addr[1]. - */ -# define ARCH_CET_LEGACY_BITMAP 0x3005 #endif /* ARCH_CET_STATUS */ diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile index 95182a508c..ec96b59a78 100644 --- a/sysdeps/x86/Makefile +++ b/sysdeps/x86/Makefile @@ -20,7 +20,7 @@ sysdep-dl-routines += dl-cet tests += tst-cet-legacy-1 tst-cet-legacy-1a tst-cet-legacy-2 \ tst-cet-legacy-2a tst-cet-legacy-3 tst-cet-legacy-4 \ - tst-cet-legacy-5a tst-cet-legacy-6a + tst-cet-legacy-5a tst-cet-legacy-6a tst-cet-legacy-7 tst-cet-legacy-1a-ARGS = -- $(host-test-program-cmd) ifneq (no,$(have-tunables)) tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c \ @@ -43,14 +43,15 @@ CFLAGS-tst-cet-legacy-4b.c += -fcf-protection CFLAGS-tst-cet-legacy-mod-4.c += -fcf-protection=none CFLAGS-tst-cet-legacy-5a.c += -fcf-protection CFLAGS-tst-cet-legacy-5b.c += -fcf-protection -CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=none +CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=branch CFLAGS-tst-cet-legacy-mod-5b.c += -fcf-protection CFLAGS-tst-cet-legacy-mod-5c.c += -fcf-protection CFLAGS-tst-cet-legacy-6a.c += -fcf-protection CFLAGS-tst-cet-legacy-6b.c += -fcf-protection -CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=none +CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=branch CFLAGS-tst-cet-legacy-mod-6b.c += -fcf-protection CFLAGS-tst-cet-legacy-mod-6c.c += -fcf-protection +CFLAGS-tst-cet-legacy-7.c += -fcf-protection=none $(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \ $(objpfx)tst-cet-legacy-mod-2.so diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c index ca3b5849bc..2be7a3a49f 100644 --- a/sysdeps/x86/dl-cet.c +++ b/sysdeps/x86/dl-cet.c @@ -33,63 +33,6 @@ # error GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK #endif -static int -dl_cet_mark_legacy_region (struct link_map *l) -{ - /* Mark PT_LOAD segments with PF_X in legacy code page bitmap. */ - size_t i, phnum = l->l_phnum; - const ElfW(Phdr) *phdr = l->l_phdr; -#ifdef __x86_64__ - typedef unsigned long long word_t; -#else - typedef unsigned long word_t; -#endif - unsigned int bits_to_set; - word_t mask_to_set; -#define BITS_PER_WORD (sizeof (word_t) * 8) -#define BITMAP_FIRST_WORD_MASK(start) \ - (~((word_t) 0) << ((start) & (BITS_PER_WORD - 1))) -#define BITMAP_LAST_WORD_MASK(nbits) \ - (~((word_t) 0) >> (-(nbits) & (BITS_PER_WORD - 1))) - - word_t *bitmap = (word_t *) GL(dl_x86_legacy_bitmap)[0]; - word_t bitmap_size = GL(dl_x86_legacy_bitmap)[1]; - word_t *p; - size_t page_size = GLRO(dl_pagesize); - - for (i = 0; i < phnum; i++) - if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_X)) - { - /* One bit in legacy bitmap represents a page. */ - ElfW(Addr) start = (phdr[i].p_vaddr + l->l_addr) / page_size; - ElfW(Addr) len = (phdr[i].p_memsz + page_size - 1) / page_size; - ElfW(Addr) end = start + len; - - if ((end / 8) > bitmap_size) - return -EINVAL; - - p = bitmap + (start / BITS_PER_WORD); - bits_to_set = BITS_PER_WORD - (start % BITS_PER_WORD); - mask_to_set = BITMAP_FIRST_WORD_MASK (start); - - while (len >= bits_to_set) - { - *p |= mask_to_set; - len -= bits_to_set; - bits_to_set = BITS_PER_WORD; - mask_to_set = ~((word_t) 0); - p++; - } - if (len) - { - mask_to_set &= BITMAP_LAST_WORD_MASK (end); - *p |= mask_to_set; - } - } - - return 0; -} - /* Check if object M is compatible with CET. */ static void @@ -142,10 +85,7 @@ dl_cet_check (struct link_map *m, const char *program) support IBT nor SHSTK. */ if (enable_ibt || enable_shstk) { - int res; unsigned int i; - unsigned int first_legacy, last_legacy; - bool need_legacy_bitmap = false; i = m->l_searchlist.r_nlist; while (i-- > 0) @@ -167,115 +107,52 @@ dl_cet_check (struct link_map *m, const char *program) continue; #endif - if (enable_ibt - && enable_ibt_type != CET_ALWAYS_ON - && !(l->l_cet & lc_ibt)) - { - /* Remember the first and last legacy objects. */ - if (!need_legacy_bitmap) - last_legacy = i; - first_legacy = i; - need_legacy_bitmap = true; - } + /* IBT is enabled only if it is enabled in executable as + well as all shared objects. */ + enable_ibt &= (enable_ibt_type == CET_ALWAYS_ON + || (l->l_cet & lc_ibt) != 0); /* SHSTK is enabled only if it is enabled in executable as well as all shared objects. */ enable_shstk &= (enable_shstk_type == CET_ALWAYS_ON || (l->l_cet & lc_shstk) != 0); } + } - if (need_legacy_bitmap) + bool cet_feature_changed = false; + + if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled) + { + if (!program) { - if (GL(dl_x86_legacy_bitmap)[0]) + if (enable_ibt_type != CET_PERMISSIVE) { - /* Change legacy bitmap to writable. */ - if (__mprotect ((void *) GL(dl_x86_legacy_bitmap)[0], - GL(dl_x86_legacy_bitmap)[1], - PROT_READ | PROT_WRITE) < 0) - { -mprotect_failure: - if (program) - _dl_fatal_printf ("%s: mprotect legacy bitmap failed\n", - l->l_name); - else - _dl_signal_error (EINVAL, l->l_name, "dlopen", - N_("mprotect legacy bitmap failed")); - } - } - else - { - /* Allocate legacy bitmap. */ - int res = dl_cet_allocate_legacy_bitmap - (GL(dl_x86_legacy_bitmap)); - if (res != 0) - { - if (program) - _dl_fatal_printf ("%s: legacy bitmap isn't available\n", - l->l_name); - else - _dl_signal_error (EINVAL, l->l_name, "dlopen", - N_("legacy bitmap isn't available")); - } + /* When IBT is enabled, we can't dlopening a shared + object without IBT. */ + if (enable_ibt != ibt_enabled) + _dl_signal_error (EINVAL, l->l_name, "dlopen", + N_("indirect branch tracking isn't enabled")); } - /* Put legacy shared objects in legacy bitmap. */ - for (i = first_legacy; i <= last_legacy; i++) + if (enable_shstk_type != CET_PERMISSIVE) { - l = m->l_initfini[i]; - - if (l->l_init_called || (l->l_cet & lc_ibt)) - continue; - -#ifdef SHARED - if (l == &GL(dl_rtld_map) - || l->l_real == &GL(dl_rtld_map) - || (program && l == m)) - continue; -#endif - - /* If IBT is enabled in executable and IBT isn't enabled - in this shard object, mark PT_LOAD segments with PF_X - in legacy code page bitmap. */ - res = dl_cet_mark_legacy_region (l); - if (res != 0) - { - if (program) - _dl_fatal_printf ("%s: failed to mark legacy code region\n", - l->l_name); - else - _dl_signal_error (-res, l->l_name, "dlopen", - N_("failed to mark legacy code region")); - } + /* When SHSTK is enabled, we can't dlopening a shared + object without SHSTK. */ + if (enable_shstk != shstk_enabled) + _dl_signal_error (EINVAL, l->l_name, "dlopen", + N_("shadow stack isn't enabled")); } - /* Change legacy bitmap to read-only. */ - if (__mprotect ((void *) GL(dl_x86_legacy_bitmap)[0], - GL(dl_x86_legacy_bitmap)[1], PROT_READ) < 0) - goto mprotect_failure; - } - } - - bool cet_feature_changed = false; - - if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled) - { - if (!program - && enable_shstk_type != CET_PERMISSIVE) - { - /* When SHSTK is enabled, we can't dlopening a shared - object without SHSTK. */ - if (enable_shstk != shstk_enabled) - _dl_signal_error (EINVAL, l->l_name, "dlopen", - N_("shadow stack isn't enabled")); - return; + if (enable_ibt_type != CET_PERMISSIVE + && enable_shstk_type != CET_PERMISSIVE) + return; } /* Disable IBT and/or SHSTK if they are enabled by kernel, but disabled in executable or shared objects. */ unsigned int cet_feature = 0; - /* Disable IBT only during program startup. */ - if (program && !enable_ibt) + if (!enable_ibt) cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT; if (!enable_shstk) cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; @@ -297,17 +174,21 @@ mprotect_failure: } #ifdef SHARED - if (program - && (!shstk_enabled - || enable_shstk_type != CET_PERMISSIVE) - && (ibt_enabled || shstk_enabled)) + if (program && (ibt_enabled || shstk_enabled)) { - /* Lock CET if IBT or SHSTK is enabled in executable. Don't - lock CET if SHSTK is enabled permissively. */ - int res = dl_cet_lock_cet (); - if (res != 0) - _dl_fatal_printf ("%s: can't lock CET\n", program); + if ((!ibt_enabled + || enable_ibt_type != CET_PERMISSIVE) + && (!shstk_enabled + || enable_shstk_type != CET_PERMISSIVE)) + { + /* Lock CET if IBT or SHSTK is enabled in executable unless + IBT or SHSTK is enabled permissively. */ + int res = dl_cet_lock_cet (); + if (res != 0) + _dl_fatal_printf ("%s: can't lock CET\n", program); + } + /* Set feature_1 if IBT or SHSTK is enabled in executable. */ cet_feature_changed = true; } #endif diff --git a/sysdeps/x86/dl-procruntime.c b/sysdeps/x86/dl-procruntime.c index fb36801f3e..5e39a38133 100644 --- a/sysdeps/x86/dl-procruntime.c +++ b/sysdeps/x86/dl-procruntime.c @@ -54,15 +54,4 @@ PROCINFO_CLASS unsigned int _dl_x86_feature_1[2] # else , # endif - -# if !defined PROCINFO_DECL && defined SHARED - ._dl_x86_legacy_bitmap -# else -PROCINFO_CLASS unsigned long _dl_x86_legacy_bitmap[2] -# endif -# if !defined SHARED || defined PROCINFO_DECL -; -# else -, -# endif #endif diff --git a/sysdeps/x86/tst-cet-legacy-4.c b/sysdeps/x86/tst-cet-legacy-4.c index a77078afc9..da1f3d1e0d 100644 --- a/sysdeps/x86/tst-cet-legacy-4.c +++ b/sysdeps/x86/tst-cet-legacy-4.c @@ -20,6 +20,9 @@ #include #include #include +#include + +#include static int do_test (void) @@ -31,22 +34,18 @@ do_test (void) h = dlopen (modname, RTLD_LAZY); if (h == NULL) { - printf ("cannot open '%s': %s\n", modname, dlerror ()); - exit (1); + const char *err = dlerror (); + if (!strstr (err, "indirect branch tracking isn't enabled")) + FAIL_EXIT1 ("incorrect dlopen '%s' error: %s\n", modname, err); + return 0; } fp = dlsym (h, "test"); if (fp == NULL) - { - printf ("cannot get symbol 'test': %s\n", dlerror ()); - exit (1); - } + FAIL_EXIT1 ("cannot get symbol 'test': %s\n", dlerror ()); if (fp () != 0) - { - puts ("test () != 0"); - exit (1); - } + FAIL_EXIT1 ("test () != 0"); dlclose (h); diff --git a/sysdeps/x86/tst-cet-legacy-7.c b/sysdeps/x86/tst-cet-legacy-7.c new file mode 100644 index 0000000000..e6f5d6f145 --- /dev/null +++ b/sysdeps/x86/tst-cet-legacy-7.c @@ -0,0 +1,40 @@ +/* Check compatibility of legacy executable with a JIT engine. + Copyright (C) 2020 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 + . */ + +#include +#include +#include + +#include + +static int +do_test (void) +{ + void (*funcp) (void); + funcp = mmap (NULL, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (funcp == MAP_FAILED) + FAIL_EXIT1 ("mmap failed (errno=%d)", errno); + printf ("mmap = %p\n", funcp); + /* Write RET instruction. */ + *(char *) funcp = 0xc3; + funcp (); + return 0; +} + +#include