On Tue, 08/07/2025 at 20.02 -0500, Jacob Bachmeyer wrote: > On 7/8/25 14:38, Guido Trentalancia via Gnupg-devel wrote: > > The following new v10 patch has been created to fix a missing > > #ifdef > > and header file check for the case of L1D cache flushing. > > [...] > > Two major issues, further explained inline below: > - You are installing the signal handler incorrectly; this will > interfere with other possible uses of SIGBUS. > - Your message from configure when testing the option to request > L1 cache flushes is misleading. > Further, none of this actually *fixes* anything; these are > *workarounds* for widespread hardware bugs. > Also, have you actually tested this on a machine where the request > for L1 cache flushes raises SIGBUS?
I have tested it with SIGBUS (just boot with "l1d_flush=on", but without adding "nosmt"): it needs a 1-second delay in order to properly set up the signal handlers before actually logging the error, such delay is introduced in v14 patch that follows... common: Disable CPU speculative execution security vulnerabilities (CVE-2018-3639 aka Spectre variant 4, CVE-2017-5715 and optionally CVE-2020-0550) * configure.ac: add a new L1D Cache flushing option (--enable-l1d-cache-flushing) to fix CVE-2020-0550 and check for sys/prctl.h on Linux systems * common/init.c (early_system_init): Disable CPU speculative execution security vulnerabilities potentially causing data leaks: - Speculative Store Bypass (always disabled) - Indirect Branch Speculation (always disabled) - Flush L1D Cache on context switch out of the task (use the --enable-l1d-cache-flushing configure option and "nosmt l1d_flush=on" on the boot command line to mitigate the vulnerability) For further information see the kernel documentation: Documentation/userspace-api/spec_ctrl.rst Documentation/admin-guide/hw-vuln/l1d_flush.rst Signed-off-by: Guido Trentalancia <gu...@trentalancia.com> diff -pru a/common/init.c b/common/init.c --- a/common/init.c 2025-05-25 15:43:45.871984100 +0200 +++ b/common/init.c 2025-07-09 13:39:44.036998821 +0200 @@ -29,6 +29,16 @@ #include <config.h> +#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) +# include <sys/prctl.h> +#endif + +#if defined(ENABLE_L1D_CACHE_FLUSH) +# include "util.h" +# include "sysutils.h" +# include <signal.h> +#endif + #ifdef HAVE_W32_SYSTEM # if _WIN32_WINNT < 0x0600 # define _WIN32_WINNT 0x0600 /* Required for SetProcessDEPPolicy. */ @@ -128,10 +136,68 @@ writestring_via_estream (int mode, const } +#ifdef ENABLE_L1D_CACHE_FLUSH +void sigbus_handler (int signo) +{ + if (signo == SIGBUS) + { + printf ("Fatal: Level 1 Data Cache flushing requires the \"nosmt\" boot parameter.\n"); + exit (SIGBUS); + } +} +#endif + + /* This function should be the first called after main. */ void early_system_init (void) { +#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) + +/* Disable CPU speculative execution security vulnerabilities + * causing data leaks: see the Linux kernel documentation + * Documentation/userspace-api/spec_ctrl.rst + * + * - Speculative Store Bypass (CVE-2018-3639, always + * disabled) + * - Indirect Branch Speculation (CVE-2017-5715, always + * disabled) + * - Flush L1D Cache on context switch out of the task (it + * requires the "nosmt l1d_flush=on" kernel boot parameter) + */ +#ifdef PR_SPEC_STORE_BYPASS + prctl (PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_FORCE_DISABLE, 0, 0); +#endif + +#ifdef PR_SPEC_INDIRECT_BRANCH + prctl (PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_FORCE_DISABLE, 0, 0); +#endif + +#if defined(ENABLE_L1D_CACHE_FLUSH) && defined(PR_SPEC_L1D_FLUSH) + struct sigaction old_action, new_action; + + new_action.sa_handler = sigbus_handler; + sigemptyset (&new_action.sa_mask); + new_action.sa_flags = 0; + + if (sigaction (SIGBUS, &new_action, &old_action) == -1) + { + printf ("Warning: cannot catch the SIGBUS signal.\n"); + } + + if (prctl (PR_SET_SPECULATION_CTRL, PR_SPEC_L1D_FLUSH, PR_SPEC_ENABLE, 0, 0) < 0) + { + printf ("Warning: Level 1 Data Cache flushing requires the \"l1d_flush=on\" boot parameter.\n"); + } + + gnupg_sleep (1); + if (sigaction (SIGBUS, &old_action, NULL) == -1) + { + printf ("Warning: cannot restore previous action on SIGBUS.\n"); + } +#endif + +#endif /* __linux__ && HAVE_SYS_PRCTL_H */ } diff -pru a/configure.ac b/configure.ac --- a/configure.ac 2025-07-06 18:01:54.128546282 +0200 +++ b/configure.ac 2025-07-08 21:32:32.674405293 +0200 @@ -244,6 +244,16 @@ AC_ARG_ENABLE(selinux-support, AC_MSG_RESULT($selinux_support) +# Fix security vulnerability CVE-2020-0550 by enabling +# Level 1 Data Cache flushing on context switch. +AC_MSG_CHECKING([whether Level 1 Data Cache is flushed on context switch]) +AC_ARG_ENABLE(l1d-cache-flushing, + AS_HELP_STRING([--enable-l1d-cache-flushing], + [enable L1D cache flushing]), + l1d_cache_flushing=$enableval, l1d_cache_flushing=no) +AC_MSG_RESULT($l1d_cache_flushing) + + AC_MSG_CHECKING([whether to allocate extra secure memory]) AC_ARG_ENABLE(large-secmem, AS_HELP_STRING([--enable-large-secmem], @@ -1313,6 +1323,16 @@ fi # +# Level 1 Data Cache flushing on context switch (CVE-2020-0550) +# +if test "$l1d_cache_flushing" = yes ; then + AC_DEFINE(ENABLE_L1D_CACHE_FLUSH,1, + [Define to enable Layer 1 Data Cache flushing]) + AC_CHECK_HEADERS([signal.h]) +fi + + +# # Checks for header files. # AC_MSG_NOTICE([checking for header files]) @@ -1322,6 +1342,13 @@ AC_CHECK_HEADERS([unistd.h langinfo.h te ucred.h sys/ucred.h sys/sysmacros.h sys/mkdev.h]) +# See whether libc supports the prctl() +case "${host}" in + *-*-linux*) + AC_CHECK_HEADERS([sys/prctl.h]) + ;; +esac + # # Checks for typedefs, structures, and compiler characteristics. # > > diff -pru a/common/init.c b/common/init.c > > --- a/common/init.c 2025-05-25 15:43:45.871984100 +0200 > > +++ b/common/init.c 2025-07-08 21:29:23.071406450 +0200 > > [...] > > /* This function should be the first called after main. */ > > void > > early_system_init (void) > > { > > +#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) > > + > > +/* Disable CPU speculative execution security vulnerabilities > > + * causing data leaks: see the Linux kernel documentation > > + * Documentation/userspace-api/spec_ctrl.rst > > + * > > + * - Speculative Store Bypass (CVE-2018-3639, always > > + * disabled) > > + * - Indirect Branch Speculation (CVE-2017-5715, always > > + * disabled) > > + * - Flush L1D Cache on context switch out of the task (it > > + * requires the "nosmt l1d_flush=on" kernel boot parameter) > > + */ > > +#ifdef PR_SPEC_STORE_BYPASS > > + prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, > > PR_SPEC_FORCE_DISABLE, 0, 0); > > +#endif > > + > > +#ifdef PR_SPEC_INDIRECT_BRANCH > > + prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, > > PR_SPEC_FORCE_DISABLE, 0, 0); > > +#endif > > + > > +#if defined(ENABLE_L1D_CACHE_FLUSH) && defined(PR_SPEC_L1D_FLUSH) > > + if (signal(SIGBUS, sigbus_handler) == SIG_ERR) > > + { > > + log_info ("Warning: cannot catch the SIGBUS signal.\n"); > > + } > > You cannot use signal() here in a library because you must restore > any previous signal handler immediately after the prctl() call. > Other code in the program might have its own reasons to catch SIGBUS, > and this handler will interfere with that. You must use sigaction() > here to obtain the old handler in a form that you can use to restore > it after calling prctl(). > > + if (prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_L1D_FLUSH, > > PR_SPEC_ENABLE, 0, 0) < 0) > > + { > > + log_info ("Warning: Level 1 Data Cache flushing requires the > > \"l1d_flush=on\" boot parameter.\n"); > > + } > > This is where you need to restore the previous state of SIGBUS > handling. > > +#endif > > + > > +#endif /* __linux__ && HAVE_SYS_PRCTL_H */ > > } > > > > > > diff -pru a/configure.ac b/configure.ac > > --- a/configure.ac 2025-07-06 18:01:54.128546282 +0200 > > +++ b/configure.ac 2025-07-08 21:32:32.674405293 +0200 > > @@ -244,6 +244,16 @@ AC_ARG_ENABLE(selinux-support, > > AC_MSG_RESULT($selinux_support) > > > > > > +# Fix security vulnerability CVE-2020-0550 by enabling > > +# Level 1 Data Cache flushing on context switch. > > +AC_MSG_CHECKING([whether Level 1 Data Cache is flushed on context > > switch]) > > This message does not accurately describe what is going on. This > should say "whether L1 data cache should be flushed on context > switch" because it does *not* test whether the cache is *actually* > flushed, but only if the option to *request* flushing the cache is > set. > > +AC_ARG_ENABLE(l1d-cache-flushing, > > + AS_HELP_STRING([--enable-l1d-cache-flushing], > > + [enable L1D cache flushing]), > > + l1d_cache_flushing=$enableval, > > l1d_cache_flushing=no) > > +AC_MSG_RESULT($l1d_cache_flushing) > > + > > + > > AC_MSG_CHECKING([whether to allocate extra secure memory]) > > AC_ARG_ENABLE(large-secmem, > > AS_HELP_STRING([--enable-large-secmem], > > [...] > > -- Jacob _______________________________________________ Gnupg-devel mailing list Gnupg-devel@gnupg.org https://lists.gnupg.org/mailman/listinfo/gnupg-devel