Blame SOURCES/0009-lib-crypto-Use-GNUTLS_NO_SIGNAL-if-available.patch

64392a
From a432e773e0cdc24cb27ccdda4111744ea2c3b819 Mon Sep 17 00:00:00 2001
64392a
From: "Richard W.M. Jones" <rjones@redhat.com>
64392a
Date: Wed, 27 Jul 2022 17:08:14 +0100
64392a
Subject: [PATCH] lib/crypto: Use GNUTLS_NO_SIGNAL if available
64392a
64392a
libnbd has long used MSG_NOSIGNAL to avoid receiving SIGPIPE if we
64392a
accidentally write on a closed socket, which is a nice alternative to
64392a
using a SIGPIPE signal handler.  However with TLS connections, gnutls
64392a
did not use this flag and so programs using libnbd + TLS would receive
64392a
SIGPIPE in some situations, notably if the server closed the
64392a
connection abruptly while we were trying to write something.
64392a
64392a
GnuTLS 3.4.2 introduces GNUTLS_NO_SIGNAL which does the same thing.
64392a
Use this flag if available.
64392a
64392a
RHEL 7 has an older gnutls which lacks this flag.  To avoid qemu-nbd
64392a
interop tests failing (rarely, but more often with a forthcoming
64392a
change to TLS shutdown behaviour), register a SIGPIPE signal handler
64392a
in the test if the flag is missing.
64392a
---
64392a
 configure.ac      | 15 +++++++++++++++
64392a
 interop/interop.c | 10 ++++++++++
64392a
 lib/crypto.c      |  7 ++++++-
64392a
 3 files changed, 31 insertions(+), 1 deletion(-)
64392a
64392a
diff --git a/configure.ac b/configure.ac
64392a
index 49ca8ab..6bd9e1b 100644
64392a
--- a/configure.ac
64392a
+++ b/configure.ac
64392a
@@ -179,6 +179,21 @@ AS_IF([test "$GNUTLS_LIBS" != ""],[
64392a
         gnutls_session_set_verify_cert \
64392a
         gnutls_transport_is_ktls_enabled \
64392a
     ])
64392a
+    AC_MSG_CHECKING([if gnutls has GNUTLS_NO_SIGNAL])
64392a
+    AC_COMPILE_IFELSE(
64392a
+        [AC_LANG_PROGRAM([
64392a
+            #include <gnutls/gnutls.h>
64392a
+            gnutls_session_t session;
64392a
+         ], [
64392a
+            gnutls_init(&session, GNUTLS_CLIENT|GNUTLS_NO_SIGNAL);
64392a
+         ])
64392a
+    ], [
64392a
+        AC_MSG_RESULT([yes])
64392a
+        AC_DEFINE([HAVE_GNUTLS_NO_SIGNAL], [1],
64392a
+                  [GNUTLS_NO_SIGNAL found at compile time])
64392a
+    ], [
64392a
+        AC_MSG_RESULT([no])
64392a
+    ])
64392a
     LIBS="$old_LIBS"
64392a
 ])
64392a
 
64392a
diff --git a/interop/interop.c b/interop/interop.c
64392a
index b41f3ca..036545b 100644
64392a
--- a/interop/interop.c
64392a
+++ b/interop/interop.c
64392a
@@ -84,6 +84,16 @@ main (int argc, char *argv[])
64392a
   REQUIRES
64392a
 #endif
64392a
 
64392a
+  /* Ignore SIGPIPE.  We only need this for GnuTLS < 3.4.2, since
64392a
+   * newer GnuTLS has the GNUTLS_NO_SIGNAL flag which adds
64392a
+   * MSG_NOSIGNAL to each write call.
64392a
+   */
64392a
+#if !HAVE_GNUTLS_NO_SIGNAL
64392a
+#if TLS
64392a
+  signal (SIGPIPE, SIG_IGN);
64392a
+#endif
64392a
+#endif
64392a
+
64392a
   /* Create a large sparse temporary file. */
64392a
 #ifdef NEEDS_TMPFILE
64392a
   int fd = mkstemp (TMPFILE);
64392a
diff --git a/lib/crypto.c b/lib/crypto.c
64392a
index 1272888..ca9520e 100644
64392a
--- a/lib/crypto.c
64392a
+++ b/lib/crypto.c
64392a
@@ -588,7 +588,12 @@ nbd_internal_crypto_create_session (struct nbd_handle *h,
64392a
   gnutls_psk_client_credentials_t pskcreds = NULL;
64392a
   gnutls_certificate_credentials_t xcreds = NULL;
64392a
 
64392a
-  err = gnutls_init (&session, GNUTLS_CLIENT|GNUTLS_NONBLOCK);
64392a
+  err = gnutls_init (&session,
64392a
+                     GNUTLS_CLIENT | GNUTLS_NONBLOCK
64392a
+#if HAVE_GNUTLS_NO_SIGNAL
64392a
+                     | GNUTLS_NO_SIGNAL
64392a
+#endif
64392a
+                     );
64392a
   if (err < 0) {
64392a
     set_error (errno, "gnutls_init: %s", gnutls_strerror (err));
64392a
     return NULL;
64392a
-- 
64392a
2.31.1
64392a