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