From 8bbee9c0ff052cf8ab5ba81fd1b67e3c45e7012a Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 27 Jul 2022 16:07:37 +0100 Subject: [PATCH] lib/crypto.c: Ignore TLS premature termination after write shutdown qemu-nbd doesn't call gnutls_bye to cleanly shut down the connection after we send NBD_CMD_DISC. When copying from a qemu-nbd server (or any operation which calls nbd_shutdown) you will see errors like this: $ nbdcopy nbds://foo?tls-certificates=/var/tmp/pki null: nbds://foo?tls-certificates=/var/tmp/pki: nbd_shutdown: gnutls_record_recv: The TLS connection was non-properly terminated. Relatedly you may also see: nbd_shutdown: gnutls_record_recv: Error in the pull function. This commit suppresses the error in the case where we know that we have shut down writes (which happens after NBD_CMD_DISC has been sent on the wire). --- interop/interop.c | 9 --------- lib/crypto.c | 17 +++++++++++++++++ lib/internal.h | 1 + 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/interop/interop.c b/interop/interop.c index 036545b..cce9407 100644 --- a/interop/interop.c +++ b/interop/interop.c @@ -226,19 +226,10 @@ main (int argc, char *argv[]) /* XXX In future test more operations here. */ -#if !TLS - /* XXX qemu doesn't shut down the connection nicely (using - * gnutls_bye) and because of this the following call will fail - * with: - * - * nbd_shutdown: gnutls_record_recv: The TLS connection was - * non-properly terminated. - */ if (nbd_shutdown (nbd, 0) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); exit (EXIT_FAILURE); } -#endif nbd_close (nbd); diff --git a/lib/crypto.c b/lib/crypto.c index ca9520e..aa5d820 100644 --- a/lib/crypto.c +++ b/lib/crypto.c @@ -187,6 +187,22 @@ tls_recv (struct nbd_handle *h, struct socket *sock, void *buf, size_t len) errno = EAGAIN; return -1; } + if (h->tls_shut_writes && + (r == GNUTLS_E_PULL_ERROR || r == GNUTLS_E_PREMATURE_TERMINATION)) { + /* qemu-nbd doesn't call gnutls_bye to cleanly shut down the + * connection after we send NBD_CMD_DISC, instead it simply + * closes the connection. On the client side we see + * "gnutls_record_recv: The TLS connection was non-properly + * terminated" or "gnutls_record_recv: Error in the pull + * function.". + * + * If we see these errors after we shut down the write side + * (h->tls_shut_writes), which happens after we have sent + * NBD_CMD_DISC on the wire, downgrade them to a debug message. + */ + debug (h, "gnutls_record_recv: %s", gnutls_strerror (r)); + return 0; /* EOF */ + } set_error (0, "gnutls_record_recv: %s", gnutls_strerror (r)); errno = EIO; return -1; @@ -234,6 +250,7 @@ tls_shut_writes (struct nbd_handle *h, struct socket *sock) return false; if (r != 0) debug (h, "ignoring gnutls_bye failure: %s", gnutls_strerror (r)); + h->tls_shut_writes = true; return sock->u.tls.oldsock->ops->shut_writes (h, sock->u.tls.oldsock); } diff --git a/lib/internal.h b/lib/internal.h index 6aaced3..f1b4c63 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -307,6 +307,7 @@ struct nbd_handle { struct command *reply_cmd; bool disconnect_request; /* True if we've queued NBD_CMD_DISC */ + bool tls_shut_writes; /* Used by lib/crypto.c to track disconnect. */ }; struct meta_context { -- 2.31.1