[v3,2/9] x86: Modularize sysdeps/x86/dl-cet.c
Checks
Context |
Check |
Description |
redhat-pt-bot/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 |
fail
|
Patch failed to apply
|
Commit Message
Improve readability and make maintenance easier for dl-feature.c by
modularizing sysdeps/x86/dl-cet.c:
1. Support processors with:
a. Only IBT. Or
b. Only SHSTK. Or
c. Both IBT and SHSTK.
2. Lock CET features only if IBT or SHSTK are enabled and are not
enabled permissively.
---
sysdeps/x86/dl-cet.c | 456 ++++++++++++++++++++++++++-----------------
1 file changed, 280 insertions(+), 176 deletions(-)
Comments
On Tue, Dec 19, 2023 at 8:08 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> Improve readability and make maintenance easier for dl-feature.c by
> modularizing sysdeps/x86/dl-cet.c:
> 1. Support processors with:
> a. Only IBT. Or
> b. Only SHSTK. Or
> c. Both IBT and SHSTK.
> 2. Lock CET features only if IBT or SHSTK are enabled and are not
> enabled permissively.
> ---
> sysdeps/x86/dl-cet.c | 456 ++++++++++++++++++++++++++-----------------
> 1 file changed, 280 insertions(+), 176 deletions(-)
>
> diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c
> index 60ea1cb558..67c51ee8c2 100644
> --- a/sysdeps/x86/dl-cet.c
> +++ b/sysdeps/x86/dl-cet.c
> @@ -32,206 +32,310 @@
> # error GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK
> #endif
>
> -/* Check if object M is compatible with CET. */
> +struct dl_cet_info
> +{
> + const char *program;
> +
> + /* Check how IBT and SHSTK should be enabled. */
> + enum dl_x86_cet_control enable_ibt_type;
> + enum dl_x86_cet_control enable_shstk_type;
> +
> + /* If IBT and SHSTK were previously enabled. */
> + unsigned int feature_1_enabled;
> +
> + /* If IBT and SHSTK should be enabled. */
> + unsigned int enable_feature_1;
> +
> + /* If there are any legacy shared object. */
> + unsigned int feature_1_legacy;
> +
> + /* Which shared object is the first legacy shared object. */
> + unsigned int feature_1_legacy_ibt;
> + unsigned int feature_1_legacy_shstk;
> +};
> +
> +/* Check if the object M and its dependencies are legacy object. */
>
> static void
> -dl_cet_check (struct link_map *m, const char *program)
> +dl_check_legacy_object (struct link_map *m,
> + struct dl_cet_info *info)
> {
> - /* Check how IBT should be enabled. */
> - enum dl_x86_cet_control enable_ibt_type
> - = GL(dl_x86_feature_control).ibt;
> - /* Check how SHSTK should be enabled. */
> - enum dl_x86_cet_control enable_shstk_type
> - = GL(dl_x86_feature_control).shstk;
> -
> - /* No legacy object check if both IBT and SHSTK are always on. */
> - if (enable_ibt_type == cet_always_on
> - && enable_shstk_type == cet_always_on)
> + unsigned int i;
> + struct link_map *l = NULL;
> +
> + i = m->l_searchlist.r_nlist;
> + while (i-- > 0)
> {
> - THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1));
> - return;
> - }
> + /* Check each shared object to see if IBT and SHSTK are enabled. */
> + l = m->l_initfini[i];
>
> - /* Check if IBT is enabled by kernel. */
> - bool ibt_enabled
> - = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0;
> - /* Check if SHSTK is enabled by kernel. */
> - bool shstk_enabled
> - = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0;
> + if (l->l_init_called)
> + continue;
>
> - 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
> - && enable_ibt_type != cet_always_off);
> - bool enable_shstk = (shstk_enabled
> - && enable_shstk_type != cet_always_off);
> - if (program)
> +#ifdef SHARED
> + /* Skip check for ld.so since it has the features enabled. The
> + features will be disabled later if they are not enabled in
> + executable. */
> + if (l == &GL(dl_rtld_map)
> + || l->l_real == &GL(dl_rtld_map)
> + || (info->program != NULL && l == m))
> + continue;
> +#endif
> +
> + /* IBT and SHSTK set only if enabled in executable and all DSOs.
> + NB: cet_always_on is handled outside of the loop. */
> + info->enable_feature_1 &= ((l->l_x86_feature_1_and
> + & (GNU_PROPERTY_X86_FEATURE_1_IBT
> + | GNU_PROPERTY_X86_FEATURE_1_SHSTK))
> + | ~(GNU_PROPERTY_X86_FEATURE_1_IBT
> + | GNU_PROPERTY_X86_FEATURE_1_SHSTK));
> + if ((info->feature_1_legacy
> + & GNU_PROPERTY_X86_FEATURE_1_IBT) == 0
> + && ((info->enable_feature_1
> + & GNU_PROPERTY_X86_FEATURE_1_IBT)
> + != (info->feature_1_enabled
> + & GNU_PROPERTY_X86_FEATURE_1_IBT)))
> {
> - /* Enable IBT and SHSTK only if they are enabled in executable.
> - NB: IBT and SHSTK may be disabled by environment variable:
> -
> - GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
> - */
> - enable_ibt &= (CPU_FEATURE_USABLE (IBT)
> - && (enable_ibt_type == cet_always_on
> - || (m->l_x86_feature_1_and
> - & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0));
> - enable_shstk &= (CPU_FEATURE_USABLE (SHSTK)
> - && (enable_shstk_type == cet_always_on
> - || (m->l_x86_feature_1_and
> - & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0));
> + info->feature_1_legacy_ibt = i;
> + info->feature_1_legacy |= GNU_PROPERTY_X86_FEATURE_1_IBT;
> }
>
> - /* ld.so is CET-enabled by kernel. But shared objects may not
> - support IBT nor SHSTK. */
> - if (enable_ibt || enable_shstk)
> - {
> - unsigned int i;
> + if ((info->feature_1_legacy
> + & GNU_PROPERTY_X86_FEATURE_1_SHSTK) == 0
> + && ((info->enable_feature_1
> + & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
> + != (info->feature_1_enabled
> + & GNU_PROPERTY_X86_FEATURE_1_SHSTK)))
> + {
> + info->feature_1_legacy_shstk = i;
> + info->feature_1_legacy |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
> + }
> + }
>
> - i = m->l_searchlist.r_nlist;
> - while (i-- > 0)
> - {
> - /* Check each shared object to see if IBT and SHSTK are
> - enabled. */
> - l = m->l_initfini[i];
> + /* Handle cet_always_on. */
> + if ((info->feature_1_enabled
> + & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0
> + && info->enable_ibt_type == cet_always_on)
> + {
> + info->feature_1_legacy &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
> + info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
> + }
>
> - if (l->l_init_called)
> - continue;
> + if ((info->feature_1_enabled
> + & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0
> + && info->enable_shstk_type == cet_always_on)
> + {
> + info->feature_1_legacy &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK;
> + info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
> + }
> +}
>
> #ifdef SHARED
> - /* Skip CET check for ld.so since ld.so is CET-enabled.
> - CET will be disabled later if CET isn't enabled in
> - executable. */
> - if (l == &GL(dl_rtld_map)
> - || l->l_real == &GL(dl_rtld_map)
> - || (program && l == m))
> - continue;
> +/* Enable IBT and SHSTK only if they are enabled in executable. Set
> + feature bits properly at the start of the program. */
> +
> +static void
> +dl_cet_check_startup (struct link_map *m, struct dl_cet_info *info)
> +{
> + /* NB: IBT and SHSTK may be disabled by environment variable:
> +
> + GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK.
> + */
> + if (CPU_FEATURE_USABLE (IBT))
> + {
> + if (info->enable_ibt_type == cet_always_on)
> + info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
> + else
> + info->enable_feature_1 &= ((m->l_x86_feature_1_and
> + & GNU_PROPERTY_X86_FEATURE_1_IBT)
> + | ~GNU_PROPERTY_X86_FEATURE_1_IBT);
> + }
> + else
> + info->enable_feature_1 &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
> +
> + if (CPU_FEATURE_USABLE (SHSTK))
> + {
> + if (info->enable_shstk_type == cet_always_on)
> + info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
> + else
> + info->enable_feature_1 &= ((m->l_x86_feature_1_and
> + & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
> + | ~GNU_PROPERTY_X86_FEATURE_1_SHSTK);
> + }
> + else
> + info->enable_feature_1 &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK;
> +
> + if (info->enable_feature_1 != 0)
> + dl_check_legacy_object (m, info);
> +
> + unsigned int disable_feature_1
> + = info->enable_feature_1 ^ info->feature_1_enabled;
> + if (disable_feature_1 != 0)
> + {
> + /* Disable features in the kernel because of legacy objects or
> + cet_always_off. */
> + if (dl_cet_disable_cet (disable_feature_1) != 0)
> + _dl_fatal_printf ("%s: can't disable x86 Features\n",
> + info->program);
> +
> + /* Clear the disabled bits. Sync dl_x86_feature_1 and
> + info->feature_1_enabled with info->enable_feature_1. */
> + info->feature_1_enabled = info->enable_feature_1;
> + GL(dl_x86_feature_1) = info->enable_feature_1;
> + }
> +
> + if (HAS_CPU_FEATURE (IBT) || HAS_CPU_FEATURE (SHSTK))
> + {
> + /* Lock CET features only if IBT or SHSTK are enabled and are not
> + enabled permissively. */
> + unsigned int feature_1_lock = 0;
> +
> + if (((info->feature_1_enabled & GNU_PROPERTY_X86_FEATURE_1_IBT)
> + != 0)
> + && info->enable_ibt_type != cet_permissive)
> + feature_1_lock |= GNU_PROPERTY_X86_FEATURE_1_IBT;
> +
> + if (((info->feature_1_enabled & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
> + != 0)
> + && info->enable_shstk_type != cet_permissive)
> + feature_1_lock |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
> +
> + if (feature_1_lock != 0
> + && dl_cet_lock_cet () != 0)
> + _dl_fatal_printf ("%s: can't lock CET\n", info->program);
> + }
> +
> + THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1));
> +}
> #endif
>
> - /* 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_x86_feature_1_and
> - & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0);
> - if (!found_ibt_legacy && enable_ibt != ibt_enabled)
> - {
> - 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_x86_feature_1_and
> - & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0);
> - if (enable_shstk != shstk_enabled)
> - {
> - found_shstk_legacy = true;
> - shstk_legacy = i;
> - }
> - }
> - }
> +/* Check feature bits when dlopening the shared object M. */
> +
> +static void
> +dl_cet_check_dlopen (struct link_map *m, struct dl_cet_info *info)
> +{
> + /* Check if there are any legacy objects loaded. */
> + if (info->enable_feature_1 != 0)
> + {
> + dl_check_legacy_object (m, info);
>
> - bool cet_feature_changed = false;
> + /* Skip if there are no legacy shared objects loaded. */
> + if (info->feature_1_legacy == 0)
> + return;
> + }
>
> - if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled)
> - {
> - if (!program)
> - {
> - 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;
> -
> - if (!enable_ibt)
> - cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT;
> - if (!enable_shstk)
> - cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
> -
> - int res = dl_cet_disable_cet (cet_feature);
> - if (res != 0)
> - {
> - if (program)
> - _dl_fatal_printf ("%s: can't disable CET\n", program);
> - else
> - {
> - 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. */
> - GL(dl_x86_feature_1) &= ~cet_feature;
> -
> - cet_feature_changed = true;
> - }
> + unsigned int disable_feature_1 = 0;
> + unsigned int legacy_obj = 0;
> + const char *msg = NULL;
>
> -#ifdef SHARED
> - if (program && (ibt_enabled || shstk_enabled))
> + if ((info->feature_1_enabled
> + & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0
> + && (info->feature_1_legacy
> + & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0)
> + {
> + if (info->enable_ibt_type != cet_permissive)
> {
> - 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;
> + legacy_obj = info->feature_1_legacy_ibt;
> + msg = N_("rebuild shared object with IBT support enabled");
> }
> -#endif
> + else
> + disable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
> + }
>
> - if (cet_feature_changed)
> + /* Check the next feature only if there is no error. */
> + if (msg == NULL
> + && (info->feature_1_enabled
> + & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0
> + && (info->feature_1_legacy
> + & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0)
> + {
> + if (info->enable_shstk_type != cet_permissive)
> {
> - unsigned int feature_1 = 0;
> - if (enable_ibt)
> - feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
> - if (enable_shstk)
> - feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
> - struct pthread *self = THREAD_SELF;
> - THREAD_SETMEM (self, header.feature_1, feature_1);
> + legacy_obj = info->feature_1_legacy_shstk;
> + msg = N_("rebuild shared object with SHSTK support enabled");
> }
> + else
> + disable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
> + }
> +
> + /* If there is an error, long jump back to the caller. */
> + if (msg != NULL)
> + _dl_signal_error (0, m->l_initfini[legacy_obj]->l_name, "dlopen",
> + msg);
> +
> + if (disable_feature_1 != 0)
> + {
> + int res = dl_cet_disable_cet (disable_feature_1);
> + if (res)
> + {
> + if ((disable_feature_1
> + & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0)
> + msg = N_("can't disable IBT");
> + else
> + msg = N_("can't disable SHSTK");
> + /* Long jump back to the caller on error. */
> + _dl_signal_error (-res, m->l_initfini[legacy_obj]->l_name,
> + "dlopen", msg);
> + }
> +
> + /* Clear the disabled bits in dl_x86_feature_1. */
> + GL(dl_x86_feature_1) &= ~disable_feature_1;
> +
> + THREAD_SETMEM (THREAD_SELF, header.feature_1,
> + GL(dl_x86_feature_1));
> + }
> +}
> +
> +static void
> +dl_cet_check (struct link_map *m, const char *program)
> +{
> + struct dl_cet_info info;
> +
> + /* Check how IBT and SHSTK should be enabled. */
> + info.enable_ibt_type = GL(dl_x86_feature_control).ibt;
> + info.enable_shstk_type = GL(dl_x86_feature_control).shstk;
> +
> + info.feature_1_enabled = GL(dl_x86_feature_1);
> +
> + /* No legacy object check if IBT and SHSTK are always on. */
> + if (info.enable_ibt_type == cet_always_on
> + && info.enable_shstk_type == cet_always_on)
> + {
> +#ifdef SHARED
> + /* Set it only during startup. */
> + if (program != NULL)
> + THREAD_SETMEM (THREAD_SELF, header.feature_1,
> + info.feature_1_enabled);
> +#endif
> + return;
> }
> +
> + /* Check if IBT and SHSTK were enabled by kernel. */
> + if (info.feature_1_enabled == 0)
> + return;
> +
> + info.program = program;
> +
> + /* Check which features should be enabled. */
> + info.enable_feature_1 = 0;
> + if (info.enable_ibt_type != cet_always_off)
> + info.enable_feature_1 |= (info.feature_1_enabled
> + & GNU_PROPERTY_X86_FEATURE_1_IBT);
> + if (info.enable_shstk_type != cet_always_off)
> + info.enable_feature_1 |= (info.feature_1_enabled
> + & GNU_PROPERTY_X86_FEATURE_1_SHSTK);
> +
> + /* Start with no legacy objects. */
> + info.feature_1_legacy = 0;
> + info.feature_1_legacy_ibt = 0;
> + info.feature_1_legacy_shstk = 0;
> +
> +#ifdef SHARED
> + if (program)
> + dl_cet_check_startup (m, &info);
> + else
> +#endif
> + dl_cet_check_dlopen (m, &info);
> }
>
> void
> --
> 2.43.0
>
I will check it in tomorrow if there is no objection.
@@ -32,206 +32,310 @@
# error GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK
#endif
-/* Check if object M is compatible with CET. */
+struct dl_cet_info
+{
+ const char *program;
+
+ /* Check how IBT and SHSTK should be enabled. */
+ enum dl_x86_cet_control enable_ibt_type;
+ enum dl_x86_cet_control enable_shstk_type;
+
+ /* If IBT and SHSTK were previously enabled. */
+ unsigned int feature_1_enabled;
+
+ /* If IBT and SHSTK should be enabled. */
+ unsigned int enable_feature_1;
+
+ /* If there are any legacy shared object. */
+ unsigned int feature_1_legacy;
+
+ /* Which shared object is the first legacy shared object. */
+ unsigned int feature_1_legacy_ibt;
+ unsigned int feature_1_legacy_shstk;
+};
+
+/* Check if the object M and its dependencies are legacy object. */
static void
-dl_cet_check (struct link_map *m, const char *program)
+dl_check_legacy_object (struct link_map *m,
+ struct dl_cet_info *info)
{
- /* Check how IBT should be enabled. */
- enum dl_x86_cet_control enable_ibt_type
- = GL(dl_x86_feature_control).ibt;
- /* Check how SHSTK should be enabled. */
- enum dl_x86_cet_control enable_shstk_type
- = GL(dl_x86_feature_control).shstk;
-
- /* No legacy object check if both IBT and SHSTK are always on. */
- if (enable_ibt_type == cet_always_on
- && enable_shstk_type == cet_always_on)
+ unsigned int i;
+ struct link_map *l = NULL;
+
+ i = m->l_searchlist.r_nlist;
+ while (i-- > 0)
{
- THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1));
- return;
- }
+ /* Check each shared object to see if IBT and SHSTK are enabled. */
+ l = m->l_initfini[i];
- /* Check if IBT is enabled by kernel. */
- bool ibt_enabled
- = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0;
- /* Check if SHSTK is enabled by kernel. */
- bool shstk_enabled
- = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0;
+ if (l->l_init_called)
+ continue;
- 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
- && enable_ibt_type != cet_always_off);
- bool enable_shstk = (shstk_enabled
- && enable_shstk_type != cet_always_off);
- if (program)
+#ifdef SHARED
+ /* Skip check for ld.so since it has the features enabled. The
+ features will be disabled later if they are not enabled in
+ executable. */
+ if (l == &GL(dl_rtld_map)
+ || l->l_real == &GL(dl_rtld_map)
+ || (info->program != NULL && l == m))
+ continue;
+#endif
+
+ /* IBT and SHSTK set only if enabled in executable and all DSOs.
+ NB: cet_always_on is handled outside of the loop. */
+ info->enable_feature_1 &= ((l->l_x86_feature_1_and
+ & (GNU_PROPERTY_X86_FEATURE_1_IBT
+ | GNU_PROPERTY_X86_FEATURE_1_SHSTK))
+ | ~(GNU_PROPERTY_X86_FEATURE_1_IBT
+ | GNU_PROPERTY_X86_FEATURE_1_SHSTK));
+ if ((info->feature_1_legacy
+ & GNU_PROPERTY_X86_FEATURE_1_IBT) == 0
+ && ((info->enable_feature_1
+ & GNU_PROPERTY_X86_FEATURE_1_IBT)
+ != (info->feature_1_enabled
+ & GNU_PROPERTY_X86_FEATURE_1_IBT)))
{
- /* Enable IBT and SHSTK only if they are enabled in executable.
- NB: IBT and SHSTK may be disabled by environment variable:
-
- GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
- */
- enable_ibt &= (CPU_FEATURE_USABLE (IBT)
- && (enable_ibt_type == cet_always_on
- || (m->l_x86_feature_1_and
- & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0));
- enable_shstk &= (CPU_FEATURE_USABLE (SHSTK)
- && (enable_shstk_type == cet_always_on
- || (m->l_x86_feature_1_and
- & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0));
+ info->feature_1_legacy_ibt = i;
+ info->feature_1_legacy |= GNU_PROPERTY_X86_FEATURE_1_IBT;
}
- /* ld.so is CET-enabled by kernel. But shared objects may not
- support IBT nor SHSTK. */
- if (enable_ibt || enable_shstk)
- {
- unsigned int i;
+ if ((info->feature_1_legacy
+ & GNU_PROPERTY_X86_FEATURE_1_SHSTK) == 0
+ && ((info->enable_feature_1
+ & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
+ != (info->feature_1_enabled
+ & GNU_PROPERTY_X86_FEATURE_1_SHSTK)))
+ {
+ info->feature_1_legacy_shstk = i;
+ info->feature_1_legacy |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+ }
+ }
- i = m->l_searchlist.r_nlist;
- while (i-- > 0)
- {
- /* Check each shared object to see if IBT and SHSTK are
- enabled. */
- l = m->l_initfini[i];
+ /* Handle cet_always_on. */
+ if ((info->feature_1_enabled
+ & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0
+ && info->enable_ibt_type == cet_always_on)
+ {
+ info->feature_1_legacy &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
+ info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
+ }
- if (l->l_init_called)
- continue;
+ if ((info->feature_1_enabled
+ & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0
+ && info->enable_shstk_type == cet_always_on)
+ {
+ info->feature_1_legacy &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+ info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+ }
+}
#ifdef SHARED
- /* Skip CET check for ld.so since ld.so is CET-enabled.
- CET will be disabled later if CET isn't enabled in
- executable. */
- if (l == &GL(dl_rtld_map)
- || l->l_real == &GL(dl_rtld_map)
- || (program && l == m))
- continue;
+/* Enable IBT and SHSTK only if they are enabled in executable. Set
+ feature bits properly at the start of the program. */
+
+static void
+dl_cet_check_startup (struct link_map *m, struct dl_cet_info *info)
+{
+ /* NB: IBT and SHSTK may be disabled by environment variable:
+
+ GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK.
+ */
+ if (CPU_FEATURE_USABLE (IBT))
+ {
+ if (info->enable_ibt_type == cet_always_on)
+ info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
+ else
+ info->enable_feature_1 &= ((m->l_x86_feature_1_and
+ & GNU_PROPERTY_X86_FEATURE_1_IBT)
+ | ~GNU_PROPERTY_X86_FEATURE_1_IBT);
+ }
+ else
+ info->enable_feature_1 &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
+
+ if (CPU_FEATURE_USABLE (SHSTK))
+ {
+ if (info->enable_shstk_type == cet_always_on)
+ info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+ else
+ info->enable_feature_1 &= ((m->l_x86_feature_1_and
+ & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
+ | ~GNU_PROPERTY_X86_FEATURE_1_SHSTK);
+ }
+ else
+ info->enable_feature_1 &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+
+ if (info->enable_feature_1 != 0)
+ dl_check_legacy_object (m, info);
+
+ unsigned int disable_feature_1
+ = info->enable_feature_1 ^ info->feature_1_enabled;
+ if (disable_feature_1 != 0)
+ {
+ /* Disable features in the kernel because of legacy objects or
+ cet_always_off. */
+ if (dl_cet_disable_cet (disable_feature_1) != 0)
+ _dl_fatal_printf ("%s: can't disable x86 Features\n",
+ info->program);
+
+ /* Clear the disabled bits. Sync dl_x86_feature_1 and
+ info->feature_1_enabled with info->enable_feature_1. */
+ info->feature_1_enabled = info->enable_feature_1;
+ GL(dl_x86_feature_1) = info->enable_feature_1;
+ }
+
+ if (HAS_CPU_FEATURE (IBT) || HAS_CPU_FEATURE (SHSTK))
+ {
+ /* Lock CET features only if IBT or SHSTK are enabled and are not
+ enabled permissively. */
+ unsigned int feature_1_lock = 0;
+
+ if (((info->feature_1_enabled & GNU_PROPERTY_X86_FEATURE_1_IBT)
+ != 0)
+ && info->enable_ibt_type != cet_permissive)
+ feature_1_lock |= GNU_PROPERTY_X86_FEATURE_1_IBT;
+
+ if (((info->feature_1_enabled & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
+ != 0)
+ && info->enable_shstk_type != cet_permissive)
+ feature_1_lock |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+
+ if (feature_1_lock != 0
+ && dl_cet_lock_cet () != 0)
+ _dl_fatal_printf ("%s: can't lock CET\n", info->program);
+ }
+
+ THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1));
+}
#endif
- /* 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_x86_feature_1_and
- & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0);
- if (!found_ibt_legacy && enable_ibt != ibt_enabled)
- {
- 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_x86_feature_1_and
- & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0);
- if (enable_shstk != shstk_enabled)
- {
- found_shstk_legacy = true;
- shstk_legacy = i;
- }
- }
- }
+/* Check feature bits when dlopening the shared object M. */
+
+static void
+dl_cet_check_dlopen (struct link_map *m, struct dl_cet_info *info)
+{
+ /* Check if there are any legacy objects loaded. */
+ if (info->enable_feature_1 != 0)
+ {
+ dl_check_legacy_object (m, info);
- bool cet_feature_changed = false;
+ /* Skip if there are no legacy shared objects loaded. */
+ if (info->feature_1_legacy == 0)
+ return;
+ }
- if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled)
- {
- if (!program)
- {
- 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;
-
- if (!enable_ibt)
- cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT;
- if (!enable_shstk)
- cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
-
- int res = dl_cet_disable_cet (cet_feature);
- if (res != 0)
- {
- if (program)
- _dl_fatal_printf ("%s: can't disable CET\n", program);
- else
- {
- 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. */
- GL(dl_x86_feature_1) &= ~cet_feature;
-
- cet_feature_changed = true;
- }
+ unsigned int disable_feature_1 = 0;
+ unsigned int legacy_obj = 0;
+ const char *msg = NULL;
-#ifdef SHARED
- if (program && (ibt_enabled || shstk_enabled))
+ if ((info->feature_1_enabled
+ & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0
+ && (info->feature_1_legacy
+ & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0)
+ {
+ if (info->enable_ibt_type != cet_permissive)
{
- 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;
+ legacy_obj = info->feature_1_legacy_ibt;
+ msg = N_("rebuild shared object with IBT support enabled");
}
-#endif
+ else
+ disable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
+ }
- if (cet_feature_changed)
+ /* Check the next feature only if there is no error. */
+ if (msg == NULL
+ && (info->feature_1_enabled
+ & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0
+ && (info->feature_1_legacy
+ & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0)
+ {
+ if (info->enable_shstk_type != cet_permissive)
{
- unsigned int feature_1 = 0;
- if (enable_ibt)
- feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
- if (enable_shstk)
- feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
- struct pthread *self = THREAD_SELF;
- THREAD_SETMEM (self, header.feature_1, feature_1);
+ legacy_obj = info->feature_1_legacy_shstk;
+ msg = N_("rebuild shared object with SHSTK support enabled");
}
+ else
+ disable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+ }
+
+ /* If there is an error, long jump back to the caller. */
+ if (msg != NULL)
+ _dl_signal_error (0, m->l_initfini[legacy_obj]->l_name, "dlopen",
+ msg);
+
+ if (disable_feature_1 != 0)
+ {
+ int res = dl_cet_disable_cet (disable_feature_1);
+ if (res)
+ {
+ if ((disable_feature_1
+ & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0)
+ msg = N_("can't disable IBT");
+ else
+ msg = N_("can't disable SHSTK");
+ /* Long jump back to the caller on error. */
+ _dl_signal_error (-res, m->l_initfini[legacy_obj]->l_name,
+ "dlopen", msg);
+ }
+
+ /* Clear the disabled bits in dl_x86_feature_1. */
+ GL(dl_x86_feature_1) &= ~disable_feature_1;
+
+ THREAD_SETMEM (THREAD_SELF, header.feature_1,
+ GL(dl_x86_feature_1));
+ }
+}
+
+static void
+dl_cet_check (struct link_map *m, const char *program)
+{
+ struct dl_cet_info info;
+
+ /* Check how IBT and SHSTK should be enabled. */
+ info.enable_ibt_type = GL(dl_x86_feature_control).ibt;
+ info.enable_shstk_type = GL(dl_x86_feature_control).shstk;
+
+ info.feature_1_enabled = GL(dl_x86_feature_1);
+
+ /* No legacy object check if IBT and SHSTK are always on. */
+ if (info.enable_ibt_type == cet_always_on
+ && info.enable_shstk_type == cet_always_on)
+ {
+#ifdef SHARED
+ /* Set it only during startup. */
+ if (program != NULL)
+ THREAD_SETMEM (THREAD_SELF, header.feature_1,
+ info.feature_1_enabled);
+#endif
+ return;
}
+
+ /* Check if IBT and SHSTK were enabled by kernel. */
+ if (info.feature_1_enabled == 0)
+ return;
+
+ info.program = program;
+
+ /* Check which features should be enabled. */
+ info.enable_feature_1 = 0;
+ if (info.enable_ibt_type != cet_always_off)
+ info.enable_feature_1 |= (info.feature_1_enabled
+ & GNU_PROPERTY_X86_FEATURE_1_IBT);
+ if (info.enable_shstk_type != cet_always_off)
+ info.enable_feature_1 |= (info.feature_1_enabled
+ & GNU_PROPERTY_X86_FEATURE_1_SHSTK);
+
+ /* Start with no legacy objects. */
+ info.feature_1_legacy = 0;
+ info.feature_1_legacy_ibt = 0;
+ info.feature_1_legacy_shstk = 0;
+
+#ifdef SHARED
+ if (program)
+ dl_cet_check_startup (m, &info);
+ else
+#endif
+ dl_cet_check_dlopen (m, &info);
}
void