I have attached a v12 patch which restores the old signal action after calling prctl().
Please note that sigaction() is used in several other source files within gnupg. I have tested the patch and the logging functions work as I would expect. They might need to be initialized before early_system_init(), that's another problem that has nothing to do with this patch. The most important point is that the security vulnerabilities addressed by this patch are not being tackled, while a multitude of supposed minor imperfections or different coding styles are being pointed out as the culprit of all problems: this is out of touch with reality ! The time is can spend on improving this patch is limited, I would recommend the real underlying security problem is tackled without hesitation since such security issues have been affecting gnupg since 2017, leaving the program vulnerable to data leaks for about 8 years ! That is the real problem !! Patch v12 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,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,68 @@ 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; + sigemptyset (&new_action.sa_mask); + new_action.sa_flags = 0; + + 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"); + } + + sigaction (SIGBUS, &old_action, NULL); +#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. # On Wed, 09/07/2025 at 22.40 -0500, Jacob Bachmeyer wrote: > On 7/9/25 07:22, Guido Trentalancia wrote: > > 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. > > This v11 does not actually fix the problem with the patch in v10: > you > now *obtain* the previous SIGBUS handler but you never *restore* it > after prctl() returns. (You need a second (or third) sigaction() > call > to reinstall the old handler after calling prctl(). A single > sigaction() call could both set a new handler *and* return the old > handler before calling prctl().) > > Further, as Werner Koch, who is the GPG maintainer and therefore the > person whose approval you need for this patch to be accepted, noted > in > another reply to the v10 patch, signal handling in GnuPG uses the > nPth > signal features, with which I am unfamiliar. You will need to find > those and use them instead of signal() or sigaction(). > > Also, as Werner Koch noted, you cannot call log_* functions in a > signal > handler, nor can you call them from code in early_system_init(), > although the latter appears to "happen to work" *if* you have > actually > been testing your patch. > > Are you actually testing the error paths in your patch? Are you > testing > the patch at all? > > > -- Jacob > _______________________________________________ Gnupg-devel mailing list Gnupg-devel@gnupg.org https://lists.gnupg.org/mailman/listinfo/gnupg-devel