[Libguestfs] [PATCH libnbd 1/2] lib/crypto: Use GNUTLS_NO_SIGNAL if available
Laszlo Ersek
lersek at redhat.com
Thu Jul 28 13:36:52 UTC 2022
On 07/28/22 15:01, Richard W.M. Jones wrote:
> On Thu, Jul 28, 2022 at 02:57:49PM +0200, Laszlo Ersek wrote:
>> On 07/27/22 18:30, Richard W.M. Jones wrote:
>>> 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 86c3a08690..b5bae4f1b2 100644
>>> --- a/configure.ac
>>> +++ b/configure.ac
>>> @@ -182,6 +182,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/gnutls.h>
>>> + 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 b41f3ca887..036545bd82 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 ffc2b4ab5f..ffba4bda9b 100644
>>> --- a/lib/crypto.c
>>> +++ b/lib/crypto.c
>>> @@ -590,7 +590,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;
>>>
>>
>> I've never seen a single example of SIGPIPE being useful to a program
>> that checks for, and properly handles, write() / send() / sendto() /
>> sendmsg() failures.
>
> Agreed!
>
>> Even if we want to die with a SIGPIPE actually (so that the parent see
>> it), we can recognize errno == EPIPE, then reset the disposition of
>> SIGPIPE to SIG_DFLT in a controlled manner, and re-raise the signal.
>> (But this is totally obscure; in most cases, a parent process is
>> satisfied if the child exits with status 1 or so in case the child sees
>> an EPIPE.)
>>
>> So, why not set the disposition of SIGPIPE to SIG_IGN indiscriminately?
>
> Basically because changing signal handlers of a program from a library
> is not cool.
Ouch, I completely lost track that this was *libnbd*. :/
You are right of course!
Acked-by: Laszlo Ersek <lersek at redhat.com>
> There are related issues with programs linked to
> multiple libraries that might all have their own idea of signal
> handling, and also with thread safety since signal handlers are
> program-global state.
>
> Rich.
>
More information about the Libguestfs
mailing list