diff mbox series

x86: Properly set usable CET feature bits [BZ #26625]

Message ID 20210127122702.3044784-1-hjl.tools@gmail.com
State Superseded
Headers show
Series x86: Properly set usable CET feature bits [BZ #26625] | expand

Commit Message

H.J. Lu Jan. 27, 2021, 12:27 p.m. UTC
commit 94cd37ebb293321115a36a422b091fdb72d2fb08
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Wed Sep 16 05:27:32 2020 -0700

    x86: Use HAS_CPU_FEATURE with IBT and SHSTK [BZ #26625]

broke

GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK

since it can no longer disable IBT nor SHSTK.  Handle IBT and SHSTK with:

1. Revert commit 94cd37ebb293321115a36a422b091fdb72d2fb08.
2. Clears the usable CET feature bits if kernel doesn't support CET.
3. Add GLIBC_TUNABLES tests without dlopen.
4. Add tests to verify that CPU_FEATURE_USABLE on IBT and SHSTK matches
_get_ssp.
5. Update GLIBC_TUNABLES tests with dlopen to verify that CET is disabled
with GLIBC_TUNABLES.
---
 sysdeps/x86/Makefile                   |  8 ++++-
 sysdeps/x86/cpu-features.c             | 11 +++++--
 sysdeps/x86/dl-cet.c                   |  4 +--
 sysdeps/x86/tst-cet-legacy-10-static.c |  1 +
 sysdeps/x86/tst-cet-legacy-10.c        | 43 ++++++++++++++++++++++++++
 sysdeps/x86/tst-cet-legacy-5.c         | 11 ++++---
 sysdeps/x86/tst-cet-legacy-6.c         | 11 ++++---
 sysdeps/x86/tst-cet-legacy-9-static.c  |  1 +
 sysdeps/x86/tst-cet-legacy-9.c         | 41 ++++++++++++++++++++++++
 sysdeps/x86/tst-get-cpu-features.c     |  2 ++
 10 files changed, 120 insertions(+), 13 deletions(-)
 create mode 100644 sysdeps/x86/tst-cet-legacy-10-static.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-10.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-9-static.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-9.c

Comments

Adhemerval Zanella Jan. 28, 2021, 5:51 p.m. UTC | #1
On 27/01/2021 09:27, H.J. Lu wrote:
> commit 94cd37ebb293321115a36a422b091fdb72d2fb08
> Author: H.J. Lu <hjl.tools@gmail.com>
> Date:   Wed Sep 16 05:27:32 2020 -0700
> 
>     x86: Use HAS_CPU_FEATURE with IBT and SHSTK [BZ #26625]
> 
> broke
> 
> GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
> 
> since it can no longer disable IBT nor SHSTK.  Handle IBT and SHSTK with:
> 
> 1. Revert commit 94cd37ebb293321115a36a422b091fdb72d2fb08.
> 2. Clears the usable CET feature bits if kernel doesn't support CET.
> 3. Add GLIBC_TUNABLES tests without dlopen.
> 4. Add tests to verify that CPU_FEATURE_USABLE on IBT and SHSTK matches
> _get_ssp.
> 5. Update GLIBC_TUNABLES tests with dlopen to verify that CET is disabled
> with GLIBC_TUNABLES.

Patch looks ok with some minot nit below, but I am kind worried it would 
require a lot of x86 testing where there are already results posted on 
release wiki.

Carlos and Florian, what do you think? Should we push it for the 2.33 release
on backport on the release branch?

> ---
>  sysdeps/x86/Makefile                   |  8 ++++-
>  sysdeps/x86/cpu-features.c             | 11 +++++--
>  sysdeps/x86/dl-cet.c                   |  4 +--
>  sysdeps/x86/tst-cet-legacy-10-static.c |  1 +
>  sysdeps/x86/tst-cet-legacy-10.c        | 43 ++++++++++++++++++++++++++
>  sysdeps/x86/tst-cet-legacy-5.c         | 11 ++++---
>  sysdeps/x86/tst-cet-legacy-6.c         | 11 ++++---
>  sysdeps/x86/tst-cet-legacy-9-static.c  |  1 +
>  sysdeps/x86/tst-cet-legacy-9.c         | 41 ++++++++++++++++++++++++
>  sysdeps/x86/tst-get-cpu-features.c     |  2 ++
>  10 files changed, 120 insertions(+), 13 deletions(-)
>  create mode 100644 sysdeps/x86/tst-cet-legacy-10-static.c
>  create mode 100644 sysdeps/x86/tst-cet-legacy-10.c
>  create mode 100644 sysdeps/x86/tst-cet-legacy-9-static.c
>  create mode 100644 sysdeps/x86/tst-cet-legacy-9.c
> 
> diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
> index 7549507a9a..dd82674342 100644
> --- a/sysdeps/x86/Makefile
> +++ b/sysdeps/x86/Makefile
> @@ -82,7 +82,9 @@ 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-7 \
> -	 tst-cet-legacy-8
> +	 tst-cet-legacy-8 tst-cet-legacy-9 tst-cet-legacy-9-static \
> +	 tst-cet-legacy-10 tst-cet-legacy-10-static
> +tests-static += tst-cet-legacy-9-static tst-cet-legacy-10-static

Do we need to stat the static variant to 'tests' rule as well?

>  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 \
> @@ -123,6 +125,8 @@ 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
>  CFLAGS-tst-cet-legacy-8.c += -mshstk
> +CFLAGS-tst-cet-legacy-10.c += -mshstk
> +CFLAGS-tst-cet-legacy-10-static.c += -mshstk
>  
>  $(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \
>  		       $(objpfx)tst-cet-legacy-mod-2.so

Ok.

> @@ -163,6 +167,8 @@ $(objpfx)tst-cet-legacy-6b: $(libdl)
>  $(objpfx)tst-cet-legacy-6b.out: $(objpfx)tst-cet-legacy-mod-6a.so \
>  				$(objpfx)tst-cet-legacy-mod-6b.so
>  tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
> +tst-cet-legacy-9-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
> +tst-cet-legacy-9-static-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
>  endif
>  endif
>  

Ok.

> diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
> index 6496512a0d..73b0a4dc9a 100644
> --- a/sysdeps/x86/cpu-features.c
> +++ b/sysdeps/x86/cpu-features.c
> @@ -75,6 +75,7 @@ update_usable (struct cpu_features *cpu_features)
>    CPU_FEATURE_SET_USABLE (cpu_features, PREFETCHWT1);
>    CPU_FEATURE_SET_USABLE (cpu_features, OSPKE);
>    CPU_FEATURE_SET_USABLE (cpu_features, WAITPKG);
> +  CPU_FEATURE_SET_USABLE (cpu_features, SHSTK);
>    CPU_FEATURE_SET_USABLE (cpu_features, GFNI);
>    CPU_FEATURE_SET_USABLE (cpu_features, RDPID);
>    CPU_FEATURE_SET_USABLE (cpu_features, RDRAND);
> @@ -84,6 +85,7 @@ update_usable (struct cpu_features *cpu_features)
>    CPU_FEATURE_SET_USABLE (cpu_features, FSRM);
>    CPU_FEATURE_SET_USABLE (cpu_features, SERIALIZE);
>    CPU_FEATURE_SET_USABLE (cpu_features, TSXLDTRK);
> +  CPU_FEATURE_SET_USABLE (cpu_features, IBT);
>    CPU_FEATURE_SET_USABLE (cpu_features, LAHF64_SAHF64);
>    CPU_FEATURE_SET_USABLE (cpu_features, LZCNT);
>    CPU_FEATURE_SET_USABLE (cpu_features, SSE4A);

Ok.

> @@ -705,6 +707,11 @@ no_cpuid:
>    /* Check CET status.  */
>    unsigned int cet_status = get_cet_status ();
>  
> +  if ((cet_status & GNU_PROPERTY_X86_FEATURE_1_IBT) == 0)
> +    CPU_FEATURE_UNSET (cpu_features, IBT)
> +  if ((cet_status & GNU_PROPERTY_X86_FEATURE_1_SHSTK) == 0)
> +    CPU_FEATURE_UNSET (cpu_features, SHSTK)
> +
>    if (cet_status)
>      {
>        GL(dl_x86_feature_1) = cet_status;

Ok

> @@ -720,9 +727,9 @@ no_cpuid:
>  	     GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
>  	   */
>  	  unsigned int cet_feature = 0;
> -	  if (!HAS_CPU_FEATURE (IBT))
> +	  if (!CPU_FEATURE_USABLE (IBT))
>  	    cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT;
> -	  if (!HAS_CPU_FEATURE (SHSTK))
> +	  if (!CPU_FEATURE_USABLE (SHSTK))
>  	    cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
>  
>  	  if (cet_feature)

Ok, it is changing the check from 'cpuid' field to 'usable'.

> diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c
> index a63b9c7164..c74e577289 100644
> --- a/sysdeps/x86/dl-cet.c
> +++ b/sysdeps/x86/dl-cet.c
> @@ -77,11 +77,11 @@ dl_cet_check (struct link_map *m, const char *program)
>  
>  	     GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
>  	   */
> -	  enable_ibt &= (HAS_CPU_FEATURE (IBT)
> +	  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 &= (HAS_CPU_FEATURE (SHSTK)
> +	  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));

Ok.

> diff --git a/sysdeps/x86/tst-cet-legacy-10-static.c b/sysdeps/x86/tst-cet-legacy-10-static.c
> new file mode 100644
> index 0000000000..ecc1208e35
> --- /dev/null
> +++ b/sysdeps/x86/tst-cet-legacy-10-static.c
> @@ -0,0 +1 @@
> +#include "tst-cet-legacy-10.c"

Ok.

> diff --git a/sysdeps/x86/tst-cet-legacy-10.c b/sysdeps/x86/tst-cet-legacy-10.c
> new file mode 100644
> index 0000000000..a618557f45
> --- /dev/null
> +++ b/sysdeps/x86/tst-cet-legacy-10.c
> @@ -0,0 +1,43 @@
> +/* Check CPU_FEATURE_USABLE on IBT and SHSTK.
> +   Copyright (C) 2021 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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <x86intrin.h>
> +#include <sys/platform/x86.h>
> +#include <support/test-driver.h>
> +#include <support/xunistd.h>
> +
> +/* Check that CPU_FEATURE_USABLE on IBT and SHSTK matches _get_ssp.  */
> +
> +static int
> +do_test (void)
> +{
> +  if (_get_ssp () != 0)
> +    {
> +      if (CPU_FEATURE_USABLE (IBT) && CPU_FEATURE_USABLE (SHSTK))
> +	return EXIT_SUCCESS;
> +    }
> +  else
> +    {
> +      if (!CPU_FEATURE_USABLE (IBT) && !CPU_FEATURE_USABLE (SHSTK))
> +	return EXIT_SUCCESS;
> +    }
> +
> +  return EXIT_FAILURE;
> +}
> +
> +#include <support/test-driver.c>

Ok. Checking on the _get_ssp documentation the idea is on hardware without CET
support it returns 0, right?

> diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c
> index e3efeb1f4e..d870de3eae 100644
> --- a/sysdeps/x86/tst-cet-legacy-5.c
> +++ b/sysdeps/x86/tst-cet-legacy-5.c
> @@ -37,6 +37,12 @@ do_test_1 (const char *modname, bool fail)
>    int (*fp) (void);
>    void *h;
>  
> +  /* NB: dlopen should never fail on non-CET platforms.  If SHSTK is
> +     disabled, assuming IBT is also disabled.  */
> +  bool cet_enabled = _get_ssp () != 0 && !CET_MAYBE_DISABLED;
> +  if (!cet_enabled)
> +    fail = false;
> +
>    h = dlopen (modname, RTLD_LAZY);
>    if (h == NULL)
>      {
> @@ -53,10 +59,7 @@ do_test_1 (const char *modname, bool fail)
>        FAIL_EXIT1 ("cannot open '%s': %s\n", modname, err);
>      }
>  
> -  /* NB: dlopen should never fail on non-CET platforms.  If SHSTK is
> -     disabled, assuming IBT is also disabled.  */
> -  bool cet_enabled = _get_ssp () != 0 && !CET_MAYBE_DISABLED;
> -  if (fail && cet_enabled)
> +  if (fail)
>      FAIL_EXIT1 ("dlopen should have failed\n");
>  
>    fp = dlsym (h, "test");

Ok.

> diff --git a/sysdeps/x86/tst-cet-legacy-6.c b/sysdeps/x86/tst-cet-legacy-6.c
> index 44b2ef5c7a..8e82ee2246 100644
> --- a/sysdeps/x86/tst-cet-legacy-6.c
> +++ b/sysdeps/x86/tst-cet-legacy-6.c
> @@ -37,6 +37,12 @@ do_test_1 (const char *modname, bool fail)
>    int (*fp) (void);
>    void *h;
>  
> +  /* NB: dlopen should never fail on non-CET platforms.  If SHSTK is
> +     disabled, assuming IBT is also disabled.  */
> +  bool cet_enabled = _get_ssp () != 0 && !CET_MAYBE_DISABLED;
> +  if (!cet_enabled)
> +    fail = false;
> +
>    h = dlopen (modname, RTLD_LAZY);
>    if (h == NULL)
>      {
> @@ -53,10 +59,7 @@ do_test_1 (const char *modname, bool fail)
>        FAIL_EXIT1 ("cannot open '%s': %s\n", modname, err);
>      }
>  
> -  /* NB: dlopen should never fail on non-CET platforms.  If SHSTK is
> -     disabled, assuming IBT is also disabled.  */
> -  bool cet_enabled = _get_ssp () != 0 && !CET_MAYBE_DISABLED;
> -  if (fail && cet_enabled)
> +  if (fail)
>      FAIL_EXIT1 ("dlopen should have failed\n");
>  
>    fp = dlsym (h, "test");

Ok.

> diff --git a/sysdeps/x86/tst-cet-legacy-9-static.c b/sysdeps/x86/tst-cet-legacy-9-static.c
> new file mode 100644
> index 0000000000..f9a8518b99
> --- /dev/null
> +++ b/sysdeps/x86/tst-cet-legacy-9-static.c
> @@ -0,0 +1 @@
> +#include "tst-cet-legacy-9.c"

Ok.

> diff --git a/sysdeps/x86/tst-cet-legacy-9.c b/sysdeps/x86/tst-cet-legacy-9.c
> new file mode 100644
> index 0000000000..2b526c9055
> --- /dev/null
> +++ b/sysdeps/x86/tst-cet-legacy-9.c
> @@ -0,0 +1,41 @@
> +/* Check CET compatibility with legacy JIT engine via GLIBC_TUNABLES.
> +   Copyright (C) 2021 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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/mman.h>
> +#include <support/test-driver.h>
> +#include <support/xunistd.h>
> +
> +/* Check that mmapped legacy code won't trigger segfault with
> +   -fcf-protection and GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK.  */
> +
> +static int
> +do_test (void)
> +{
> +  void (*funcp) (void);
> +  funcp = xmmap (NULL, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE,
> +		 MAP_ANONYMOUS | MAP_PRIVATE, -1);

Although x86_64 only support 4k page currently (not counting large
pages, but which requires an additional mmap flag anyway), I think it
should use xsysconf (_SC_PAGESIZE) to be future-proof.

> +  printf ("mmap = %p\n", funcp);
> +  /* Write RET instruction.  */
> +  *(char *) funcp = 0xc3;
> +  funcp ();
> +  return EXIT_SUCCESS;
> +}
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c
> index dcdb86bb93..b5e7f6e7b0 100644
> --- a/sysdeps/x86/tst-get-cpu-features.c
> +++ b/sysdeps/x86/tst-get-cpu-features.c
> @@ -301,6 +301,7 @@ do_test (void)
>    CHECK_CPU_FEATURE_USABLE (OSPKE);
>    CHECK_CPU_FEATURE_USABLE (WAITPKG);
>    CHECK_CPU_FEATURE_USABLE (AVX512_VBMI2);
> +  CHECK_CPU_FEATURE_USABLE (SHSTK);
>    CHECK_CPU_FEATURE_USABLE (GFNI);
>    CHECK_CPU_FEATURE_USABLE (VAES);
>    CHECK_CPU_FEATURE_USABLE (VPCLMULQDQ);
> @@ -324,6 +325,7 @@ do_test (void)
>    CHECK_CPU_FEATURE_USABLE (HYBRID);
>    CHECK_CPU_FEATURE_USABLE (TSXLDTRK);
>    CHECK_CPU_FEATURE_USABLE (PCONFIG);
> +  CHECK_CPU_FEATURE_USABLE (IBT);
>    CHECK_CPU_FEATURE_USABLE (AMX_BF16);
>    CHECK_CPU_FEATURE_USABLE (AVX512_FP16);
>    CHECK_CPU_FEATURE_USABLE (AMX_TILE);
> 

Ok.+
Carlos O'Donell Jan. 29, 2021, 2:45 a.m. UTC | #2
On 1/28/21 12:51 PM, Adhemerval Zanella wrote:
> Carlos and Florian, what do you think? Should we push it for the 2.33 release
> on backport on the release branch?

I would push this for 2.33.

It has limited scope and is a bug fix that enables testing on newer Tigerlake
hardware. Laptops with Tigerlake are already shipping.

This change does not impact nor invalidate the testing we've already done.
diff mbox series

Patch

diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
index 7549507a9a..dd82674342 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -82,7 +82,9 @@  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-7 \
-	 tst-cet-legacy-8
+	 tst-cet-legacy-8 tst-cet-legacy-9 tst-cet-legacy-9-static \
+	 tst-cet-legacy-10 tst-cet-legacy-10-static
+tests-static += tst-cet-legacy-9-static tst-cet-legacy-10-static
 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 \
@@ -123,6 +125,8 @@  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
 CFLAGS-tst-cet-legacy-8.c += -mshstk
+CFLAGS-tst-cet-legacy-10.c += -mshstk
+CFLAGS-tst-cet-legacy-10-static.c += -mshstk
 
 $(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \
 		       $(objpfx)tst-cet-legacy-mod-2.so
@@ -163,6 +167,8 @@  $(objpfx)tst-cet-legacy-6b: $(libdl)
 $(objpfx)tst-cet-legacy-6b.out: $(objpfx)tst-cet-legacy-mod-6a.so \
 				$(objpfx)tst-cet-legacy-mod-6b.so
 tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
+tst-cet-legacy-9-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
+tst-cet-legacy-9-static-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
 endif
 endif
 
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index 6496512a0d..73b0a4dc9a 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -75,6 +75,7 @@  update_usable (struct cpu_features *cpu_features)
   CPU_FEATURE_SET_USABLE (cpu_features, PREFETCHWT1);
   CPU_FEATURE_SET_USABLE (cpu_features, OSPKE);
   CPU_FEATURE_SET_USABLE (cpu_features, WAITPKG);
+  CPU_FEATURE_SET_USABLE (cpu_features, SHSTK);
   CPU_FEATURE_SET_USABLE (cpu_features, GFNI);
   CPU_FEATURE_SET_USABLE (cpu_features, RDPID);
   CPU_FEATURE_SET_USABLE (cpu_features, RDRAND);
@@ -84,6 +85,7 @@  update_usable (struct cpu_features *cpu_features)
   CPU_FEATURE_SET_USABLE (cpu_features, FSRM);
   CPU_FEATURE_SET_USABLE (cpu_features, SERIALIZE);
   CPU_FEATURE_SET_USABLE (cpu_features, TSXLDTRK);
+  CPU_FEATURE_SET_USABLE (cpu_features, IBT);
   CPU_FEATURE_SET_USABLE (cpu_features, LAHF64_SAHF64);
   CPU_FEATURE_SET_USABLE (cpu_features, LZCNT);
   CPU_FEATURE_SET_USABLE (cpu_features, SSE4A);
@@ -705,6 +707,11 @@  no_cpuid:
   /* Check CET status.  */
   unsigned int cet_status = get_cet_status ();
 
+  if ((cet_status & GNU_PROPERTY_X86_FEATURE_1_IBT) == 0)
+    CPU_FEATURE_UNSET (cpu_features, IBT)
+  if ((cet_status & GNU_PROPERTY_X86_FEATURE_1_SHSTK) == 0)
+    CPU_FEATURE_UNSET (cpu_features, SHSTK)
+
   if (cet_status)
     {
       GL(dl_x86_feature_1) = cet_status;
@@ -720,9 +727,9 @@  no_cpuid:
 	     GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
 	   */
 	  unsigned int cet_feature = 0;
-	  if (!HAS_CPU_FEATURE (IBT))
+	  if (!CPU_FEATURE_USABLE (IBT))
 	    cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT;
-	  if (!HAS_CPU_FEATURE (SHSTK))
+	  if (!CPU_FEATURE_USABLE (SHSTK))
 	    cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
 
 	  if (cet_feature)
diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c
index a63b9c7164..c74e577289 100644
--- a/sysdeps/x86/dl-cet.c
+++ b/sysdeps/x86/dl-cet.c
@@ -77,11 +77,11 @@  dl_cet_check (struct link_map *m, const char *program)
 
 	     GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
 	   */
-	  enable_ibt &= (HAS_CPU_FEATURE (IBT)
+	  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 &= (HAS_CPU_FEATURE (SHSTK)
+	  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));
diff --git a/sysdeps/x86/tst-cet-legacy-10-static.c b/sysdeps/x86/tst-cet-legacy-10-static.c
new file mode 100644
index 0000000000..ecc1208e35
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-10-static.c
@@ -0,0 +1 @@ 
+#include "tst-cet-legacy-10.c"
diff --git a/sysdeps/x86/tst-cet-legacy-10.c b/sysdeps/x86/tst-cet-legacy-10.c
new file mode 100644
index 0000000000..a618557f45
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-10.c
@@ -0,0 +1,43 @@ 
+/* Check CPU_FEATURE_USABLE on IBT and SHSTK.
+   Copyright (C) 2021 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <x86intrin.h>
+#include <sys/platform/x86.h>
+#include <support/test-driver.h>
+#include <support/xunistd.h>
+
+/* Check that CPU_FEATURE_USABLE on IBT and SHSTK matches _get_ssp.  */
+
+static int
+do_test (void)
+{
+  if (_get_ssp () != 0)
+    {
+      if (CPU_FEATURE_USABLE (IBT) && CPU_FEATURE_USABLE (SHSTK))
+	return EXIT_SUCCESS;
+    }
+  else
+    {
+      if (!CPU_FEATURE_USABLE (IBT) && !CPU_FEATURE_USABLE (SHSTK))
+	return EXIT_SUCCESS;
+    }
+
+  return EXIT_FAILURE;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c
index e3efeb1f4e..d870de3eae 100644
--- a/sysdeps/x86/tst-cet-legacy-5.c
+++ b/sysdeps/x86/tst-cet-legacy-5.c
@@ -37,6 +37,12 @@  do_test_1 (const char *modname, bool fail)
   int (*fp) (void);
   void *h;
 
+  /* NB: dlopen should never fail on non-CET platforms.  If SHSTK is
+     disabled, assuming IBT is also disabled.  */
+  bool cet_enabled = _get_ssp () != 0 && !CET_MAYBE_DISABLED;
+  if (!cet_enabled)
+    fail = false;
+
   h = dlopen (modname, RTLD_LAZY);
   if (h == NULL)
     {
@@ -53,10 +59,7 @@  do_test_1 (const char *modname, bool fail)
       FAIL_EXIT1 ("cannot open '%s': %s\n", modname, err);
     }
 
-  /* NB: dlopen should never fail on non-CET platforms.  If SHSTK is
-     disabled, assuming IBT is also disabled.  */
-  bool cet_enabled = _get_ssp () != 0 && !CET_MAYBE_DISABLED;
-  if (fail && cet_enabled)
+  if (fail)
     FAIL_EXIT1 ("dlopen should have failed\n");
 
   fp = dlsym (h, "test");
diff --git a/sysdeps/x86/tst-cet-legacy-6.c b/sysdeps/x86/tst-cet-legacy-6.c
index 44b2ef5c7a..8e82ee2246 100644
--- a/sysdeps/x86/tst-cet-legacy-6.c
+++ b/sysdeps/x86/tst-cet-legacy-6.c
@@ -37,6 +37,12 @@  do_test_1 (const char *modname, bool fail)
   int (*fp) (void);
   void *h;
 
+  /* NB: dlopen should never fail on non-CET platforms.  If SHSTK is
+     disabled, assuming IBT is also disabled.  */
+  bool cet_enabled = _get_ssp () != 0 && !CET_MAYBE_DISABLED;
+  if (!cet_enabled)
+    fail = false;
+
   h = dlopen (modname, RTLD_LAZY);
   if (h == NULL)
     {
@@ -53,10 +59,7 @@  do_test_1 (const char *modname, bool fail)
       FAIL_EXIT1 ("cannot open '%s': %s\n", modname, err);
     }
 
-  /* NB: dlopen should never fail on non-CET platforms.  If SHSTK is
-     disabled, assuming IBT is also disabled.  */
-  bool cet_enabled = _get_ssp () != 0 && !CET_MAYBE_DISABLED;
-  if (fail && cet_enabled)
+  if (fail)
     FAIL_EXIT1 ("dlopen should have failed\n");
 
   fp = dlsym (h, "test");
diff --git a/sysdeps/x86/tst-cet-legacy-9-static.c b/sysdeps/x86/tst-cet-legacy-9-static.c
new file mode 100644
index 0000000000..f9a8518b99
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-9-static.c
@@ -0,0 +1 @@ 
+#include "tst-cet-legacy-9.c"
diff --git a/sysdeps/x86/tst-cet-legacy-9.c b/sysdeps/x86/tst-cet-legacy-9.c
new file mode 100644
index 0000000000..2b526c9055
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-9.c
@@ -0,0 +1,41 @@ 
+/* Check CET compatibility with legacy JIT engine via GLIBC_TUNABLES.
+   Copyright (C) 2021 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <support/test-driver.h>
+#include <support/xunistd.h>
+
+/* Check that mmapped legacy code won't trigger segfault with
+   -fcf-protection and GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK.  */
+
+static int
+do_test (void)
+{
+  void (*funcp) (void);
+  funcp = xmmap (NULL, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE,
+		 MAP_ANONYMOUS | MAP_PRIVATE, -1);
+  printf ("mmap = %p\n", funcp);
+  /* Write RET instruction.  */
+  *(char *) funcp = 0xc3;
+  funcp ();
+  return EXIT_SUCCESS;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/x86/tst-get-cpu-features.c b/sysdeps/x86/tst-get-cpu-features.c
index dcdb86bb93..b5e7f6e7b0 100644
--- a/sysdeps/x86/tst-get-cpu-features.c
+++ b/sysdeps/x86/tst-get-cpu-features.c
@@ -301,6 +301,7 @@  do_test (void)
   CHECK_CPU_FEATURE_USABLE (OSPKE);
   CHECK_CPU_FEATURE_USABLE (WAITPKG);
   CHECK_CPU_FEATURE_USABLE (AVX512_VBMI2);
+  CHECK_CPU_FEATURE_USABLE (SHSTK);
   CHECK_CPU_FEATURE_USABLE (GFNI);
   CHECK_CPU_FEATURE_USABLE (VAES);
   CHECK_CPU_FEATURE_USABLE (VPCLMULQDQ);
@@ -324,6 +325,7 @@  do_test (void)
   CHECK_CPU_FEATURE_USABLE (HYBRID);
   CHECK_CPU_FEATURE_USABLE (TSXLDTRK);
   CHECK_CPU_FEATURE_USABLE (PCONFIG);
+  CHECK_CPU_FEATURE_USABLE (IBT);
   CHECK_CPU_FEATURE_USABLE (AMX_BF16);
   CHECK_CPU_FEATURE_USABLE (AVX512_FP16);
   CHECK_CPU_FEATURE_USABLE (AMX_TILE);