diff options
Diffstat (limited to 'sysdeps/x86/dl-cet.c')
-rw-r--r-- | sysdeps/x86/dl-cet.c | 217 |
1 files changed, 60 insertions, 157 deletions
diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c index ca3b584..c7029f1 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 @@ -117,6 +60,8 @@ dl_cet_check (struct link_map *m, const char *program) if (ibt_enabled || shstk_enabled) { struct link_map *l = NULL; + unsigned int ibt_legacy = 0, shstk_legacy = 0; + bool found_ibt_legacy = false, found_shstk_legacy = false; /* Check if IBT and SHSTK are enabled in object. */ bool enable_ibt = (ibt_enabled @@ -142,10 +87,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,91 +109,25 @@ 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)) + /* 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); + if (!found_ibt_legacy && enable_ibt != ibt_enabled) { - /* Remember the first and last legacy objects. */ - if (!need_legacy_bitmap) - last_legacy = i; - first_legacy = i; - need_legacy_bitmap = true; + found_ibt_legacy = true; + ibt_legacy = i; } /* 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) - { - if (GL(dl_x86_legacy_bitmap)[0]) - { - /* 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 + if (enable_shstk != shstk_enabled) { - /* 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")); - } + found_shstk_legacy = true; + shstk_legacy = i; } - - /* Put legacy shared objects in legacy bitmap. */ - for (i = first_legacy; i <= last_legacy; i++) - { - 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")); - } - } - - /* 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; } } @@ -259,23 +135,40 @@ mprotect_failure: if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled) { - if (!program - && enable_shstk_type != CET_PERMISSIVE) + if (!program) { - /* 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) + { + /* When IBT is enabled, we cannot dlopen a shared + object without IBT. */ + if (found_ibt_legacy) + _dl_signal_error (0, + m->l_initfini[ibt_legacy]->l_name, + "dlopen", + N_("rebuild shared object with IBT support enabled")); + } + + if (enable_shstk_type != CET_PERMISSIVE) + { + /* When SHSTK is enabled, we cannot dlopen a shared + object without SHSTK. */ + if (found_shstk_legacy) + _dl_signal_error (0, + m->l_initfini[shstk_legacy]->l_name, + "dlopen", + N_("rebuild shared object with SHSTK support enabled")); + } + + 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; @@ -286,8 +179,14 @@ mprotect_failure: if (program) _dl_fatal_printf ("%s: can't disable CET\n", program); else - _dl_signal_error (-res, l->l_name, "dlopen", - N_("can't disable CET")); + { + if (found_ibt_legacy) + l = m->l_initfini[ibt_legacy]; + else + l = m->l_initfini[shstk_legacy]; + _dl_signal_error (-res, l->l_name, "dlopen", + N_("can't disable CET")); + } } /* Clear the disabled bits in dl_x86_feature_1. */ @@ -297,17 +196,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 |