Gnutls documents that while many apps simply yank out the underlying transport at the end of communication in the name of efficiency, this is indistinguishable from a malicious actor terminating the connection prematurely. Since our channel I/O code already supports the notion of a graceful shutdown request, it is time to plumb that through to the TLS layer, and wait for TLS to give the all clear before then terminating traffic on the underlying channel.
Note that channel-tls now always advertises shutdown support, regardless of whether the underlying channel also has that support. Signed-off-by: Eric Blake <ebl...@redhat.com> --- io/channel-tls.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/io/channel-tls.c b/io/channel-tls.c index 7ec8ceff2f01..f90905823e1d 100644 --- a/io/channel-tls.c +++ b/io/channel-tls.c @@ -360,10 +360,35 @@ static int qio_channel_tls_shutdown(QIOChannel *ioc, Error **errp) { QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc); + int ret = 0; tioc->shutdown |= how; - return qio_channel_shutdown(tioc->master, how, errp); + do { + switch (how) { + case QIO_CHANNEL_SHUTDOWN_READ: + /* No TLS counterpart */ + break; + case QIO_CHANNEL_SHUTDOWN_WRITE: + ret = qcrypto_tls_session_shutdown(tioc->session, QCRYPTO_SHUT_WR); + break; + case QIO_CHANNEL_SHUTDOWN_BOTH: + ret = qcrypto_tls_session_shutdown(tioc->session, + QCRYPTO_SHUT_RDWR); + break; + default: + abort(); + } + } while (ret == -EAGAIN); + if (ret < 0) { + error_setg_errno(errp, -ret, "Cannot shut down TLS channel"); + return -1; + } + + if (qio_channel_has_feature(tioc->master, QIO_CHANNEL_FEATURE_SHUTDOWN)) { + return qio_channel_shutdown(tioc->master, how, errp); + } + return 0; } static int qio_channel_tls_close(QIOChannel *ioc, -- 2.26.0.rc2