[PATCH gnupg v11] Disable CPU speculation-related misfeatures

Guido Trentalancia guido at trentalancia.com
Wed Jul 9 14:22:48 CEST 2025


A new v11 patch has created to use sigaction() instead of signal() to
deal with the SIGBUS signal. A few other cosmetic changes have been
introduced.

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 <guido at 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,14 @@
 
 #include <config.h>
 
+#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H)
+# include <sys/prctl.h>
+#endif
+
+#if defined(ENABLE_L1D_CACHE_FLUSH)
+# include <signal.h>
+#endif
+
 #ifdef HAVE_W32_SYSTEM
 # if _WIN32_WINNT < 0x0600
 #   define _WIN32_WINNT 0x0600  /* Required for SetProcessDEPPolicy.  */
@@ -128,10 +136,65 @@ writestring_via_estream (int mode, const
 }
 
 
+#ifdef ENABLE_L1D_CACHE_FLUSH
+void sigbus_handler (int signo)
+{
+  if (signo == SIGBUS)
+    {
+      log_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;
+
+  sigaction (SIGBUS, NULL, &old_action);
+  if (old_action.sa_handler != SIG_IGN)
+    {
+      if (sigaction (SIGBUS, &new_action, NULL) == -1)
+        {
+          log_info ("Warning: cannot catch the SIGBUS signal.\n");
+        }
+    }
+
+  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");
+    }
+#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 should be 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.
 #

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?
> > 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



More information about the Gnupg-devel mailing list