aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS10
-rw-r--r--crypto/tlssession.c103
-rw-r--r--crypto/trace-events2
-rw-r--r--include/crypto/tlssession.h14
-rw-r--r--include/io/channel.h1
-rw-r--r--io/channel-tls.c5
-rw-r--r--meson.build9
-rw-r--r--meson_options.txt2
-rw-r--r--migration/migration-hmp-cmds.c10
-rw-r--r--migration/tls.c9
-rw-r--r--scripts/meson-buildoptions.sh5
-rw-r--r--scripts/tracetool/backend/log.py14
-rw-r--r--util/log.c20
13 files changed, 177 insertions, 27 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index a462345..f1bd69c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -295,7 +295,7 @@ F: tests/tcg/openrisc/
PowerPC TCG CPUs
M: Nicholas Piggin <npiggin@gmail.com>
-M: Daniel Henrique Barboza <danielhb413@gmail.com>
+R: Chinmay Rath <rathc@linux.ibm.com>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: target/ppc/
@@ -452,7 +452,7 @@ F: target/mips/system/
PPC KVM CPUs
M: Nicholas Piggin <npiggin@gmail.com>
-R: Daniel Henrique Barboza <danielhb413@gmail.com>
+R: Harsh Prateek Bora <harshpb@linux.ibm.com>
S: Odd Fixes
F: target/ppc/kvm.c
@@ -1550,7 +1550,7 @@ F: tests/functional/test_ppc_40p.py
sPAPR (pseries)
M: Nicholas Piggin <npiggin@gmail.com>
-R: Daniel Henrique Barboza <danielhb413@gmail.com>
+M: Harsh Prateek Bora <harshpb@linux.ibm.com>
R: Harsh Prateek Bora <harshpb@linux.ibm.com>
L: qemu-ppc@nongnu.org
S: Odd Fixes
@@ -1575,7 +1575,7 @@ F: tests/functional/test_ppc64_tuxrun.py
PowerNV (Non-Virtualized)
M: Nicholas Piggin <npiggin@gmail.com>
-R: Frédéric Barrat <fbarrat@linux.ibm.com>
+R: Aditya Gupta <adityag@linux.ibm.com>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: docs/system/ppc/powernv.rst
@@ -2776,7 +2776,7 @@ F: tests/qtest/fw_cfg-test.c
T: git https://github.com/philmd/qemu.git fw_cfg-next
XIVE
-R: Frédéric Barrat <fbarrat@linux.ibm.com>
+R: Gautam Menghani <gautam@linux.ibm.com>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/*/*xive*
diff --git a/crypto/tlssession.c b/crypto/tlssession.c
index 6d8f8df..86d407a 100644
--- a/crypto/tlssession.c
+++ b/crypto/tlssession.c
@@ -19,6 +19,8 @@
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/thread.h"
#include "crypto/tlssession.h"
#include "crypto/tlscredsanon.h"
#include "crypto/tlscredspsk.h"
@@ -51,6 +53,14 @@ struct QCryptoTLSSession {
*/
Error *rerr;
Error *werr;
+
+ /*
+ * Used to protect against broken GNUTLS thread safety
+ * https://gitlab.com/gnutls/gnutls/-/issues/1717
+ */
+ bool requireThreadSafety;
+ bool lockEnabled;
+ QemuMutex lock;
};
@@ -69,6 +79,7 @@ qcrypto_tls_session_free(QCryptoTLSSession *session)
g_free(session->peername);
g_free(session->authzid);
object_unref(OBJECT(session->creds));
+ qemu_mutex_destroy(&session->lock);
g_free(session);
}
@@ -84,10 +95,19 @@ qcrypto_tls_session_push(void *opaque, const void *buf, size_t len)
return -1;
};
+ if (session->lockEnabled) {
+ qemu_mutex_unlock(&session->lock);
+ }
+
error_free(session->werr);
session->werr = NULL;
ret = session->writeFunc(buf, len, session->opaque, &session->werr);
+
+ if (session->lockEnabled) {
+ qemu_mutex_lock(&session->lock);
+ }
+
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
errno = EAGAIN;
return -1;
@@ -114,7 +134,16 @@ qcrypto_tls_session_pull(void *opaque, void *buf, size_t len)
error_free(session->rerr);
session->rerr = NULL;
+ if (session->lockEnabled) {
+ qemu_mutex_unlock(&session->lock);
+ }
+
ret = session->readFunc(buf, len, session->opaque, &session->rerr);
+
+ if (session->lockEnabled) {
+ qemu_mutex_lock(&session->lock);
+ }
+
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
errno = EAGAIN;
return -1;
@@ -153,6 +182,8 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds,
session->creds = creds;
object_ref(OBJECT(creds));
+ qemu_mutex_init(&session->lock);
+
if (creds->endpoint != endpoint) {
error_setg(errp, "Credentials endpoint doesn't match session");
goto error;
@@ -289,6 +320,11 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds,
return NULL;
}
+void qcrypto_tls_session_require_thread_safety(QCryptoTLSSession *sess)
+{
+ sess->requireThreadSafety = true;
+}
+
static int
qcrypto_tls_session_check_certificate(QCryptoTLSSession *session,
Error **errp)
@@ -480,7 +516,17 @@ qcrypto_tls_session_write(QCryptoTLSSession *session,
size_t len,
Error **errp)
{
- ssize_t ret = gnutls_record_send(session->handle, buf, len);
+ ssize_t ret;
+
+ if (session->lockEnabled) {
+ qemu_mutex_lock(&session->lock);
+ }
+
+ ret = gnutls_record_send(session->handle, buf, len);
+
+ if (session->lockEnabled) {
+ qemu_mutex_unlock(&session->lock);
+ }
if (ret < 0) {
if (ret == GNUTLS_E_AGAIN) {
@@ -509,7 +555,17 @@ qcrypto_tls_session_read(QCryptoTLSSession *session,
bool gracefulTermination,
Error **errp)
{
- ssize_t ret = gnutls_record_recv(session->handle, buf, len);
+ ssize_t ret;
+
+ if (session->lockEnabled) {
+ qemu_mutex_lock(&session->lock);
+ }
+
+ ret = gnutls_record_recv(session->handle, buf, len);
+
+ if (session->lockEnabled) {
+ qemu_mutex_unlock(&session->lock);
+ }
if (ret < 0) {
if (ret == GNUTLS_E_AGAIN) {
@@ -545,8 +601,39 @@ int
qcrypto_tls_session_handshake(QCryptoTLSSession *session,
Error **errp)
{
- int ret = gnutls_handshake(session->handle);
+ int ret;
+ ret = gnutls_handshake(session->handle);
+
if (!ret) {
+#ifdef CONFIG_GNUTLS_BUG1717_WORKAROUND
+ gnutls_cipher_algorithm_t cipher =
+ gnutls_cipher_get(session->handle);
+
+ /*
+ * Any use of rekeying in TLS 1.3 is unsafe for
+ * a gnutls with bug 1717, however, we know that
+ * QEMU won't initiate manual rekeying. Thus we
+ * only have to protect against automatic rekeying
+ * which doesn't trigger with CHACHA20
+ */
+ trace_qcrypto_tls_session_parameters(
+ session,
+ session->requireThreadSafety,
+ gnutls_protocol_get_version(session->handle),
+ cipher);
+
+ if (session->requireThreadSafety &&
+ gnutls_protocol_get_version(session->handle) ==
+ GNUTLS_TLS1_3 &&
+ cipher != GNUTLS_CIPHER_CHACHA20_POLY1305) {
+ warn_report("WARNING: activating thread safety countermeasures "
+ "for potentially broken GNUTLS with TLS1.3 cipher=%d",
+ cipher);
+ trace_qcrypto_tls_session_bug1717_workaround(session);
+ session->lockEnabled = true;
+ }
+#endif
+
session->handshakeComplete = true;
return QCRYPTO_TLS_HANDSHAKE_COMPLETE;
}
@@ -584,8 +671,15 @@ qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp)
return 0;
}
+ if (session->lockEnabled) {
+ qemu_mutex_lock(&session->lock);
+ }
ret = gnutls_bye(session->handle, GNUTLS_SHUT_WR);
+ if (session->lockEnabled) {
+ qemu_mutex_unlock(&session->lock);
+ }
+
if (!ret) {
return QCRYPTO_TLS_BYE_COMPLETE;
}
@@ -651,6 +745,9 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds G_GNUC_UNUSED,
return NULL;
}
+void qcrypto_tls_session_require_thread_safety(QCryptoTLSSession *sess)
+{
+}
void
qcrypto_tls_session_free(QCryptoTLSSession *sess G_GNUC_UNUSED)
diff --git a/crypto/trace-events b/crypto/trace-events
index bccd0bbf..d0e3342 100644
--- a/crypto/trace-events
+++ b/crypto/trace-events
@@ -21,6 +21,8 @@ qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds
# tlssession.c
qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *authzid, int endpoint) "TLS session new session=%p creds=%p hostname=%s authzid=%s endpoint=%d"
qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s"
+qcrypto_tls_session_parameters(void *session, int threadSafety, int protocol, int cipher) "TLS session parameters session=%p threadSafety=%d protocol=%d cipher=%d"
+qcrypto_tls_session_bug1717_workaround(void *session) "TLS session bug1717 workaround session=%p"
# tls-cipher-suites.c
qcrypto_tls_cipher_suite_priority(const char *name) "priority: %s"
diff --git a/include/crypto/tlssession.h b/include/crypto/tlssession.h
index d77ae0d..2f62ce2 100644
--- a/include/crypto/tlssession.h
+++ b/include/crypto/tlssession.h
@@ -166,6 +166,20 @@ void qcrypto_tls_session_free(QCryptoTLSSession *sess);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSSession, qcrypto_tls_session_free)
/**
+ * qcrypto_tls_session_require_thread_safety:
+ * @sess: the TLS session object
+ *
+ * Mark that this TLS session will require thread safety
+ * for concurrent I/O in both directions. This must be
+ * called before the handshake is performed.
+ *
+ * This will activate a workaround for GNUTLS thread
+ * safety issues, where appropriate for the negotiated
+ * TLS session parameters.
+ */
+void qcrypto_tls_session_require_thread_safety(QCryptoTLSSession *sess);
+
+/**
* qcrypto_tls_session_check_credentials:
* @sess: the TLS session object
* @errp: pointer to a NULL-initialized error object
diff --git a/include/io/channel.h b/include/io/channel.h
index 62b6571..234e5db 100644
--- a/include/io/channel.h
+++ b/include/io/channel.h
@@ -46,6 +46,7 @@ enum QIOChannelFeature {
QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY,
QIO_CHANNEL_FEATURE_READ_MSG_PEEK,
QIO_CHANNEL_FEATURE_SEEKABLE,
+ QIO_CHANNEL_FEATURE_CONCURRENT_IO,
};
diff --git a/io/channel-tls.c b/io/channel-tls.c
index db2ac1d..a8248a9 100644
--- a/io/channel-tls.c
+++ b/io/channel-tls.c
@@ -241,6 +241,11 @@ void qio_channel_tls_handshake(QIOChannelTLS *ioc,
{
QIOTask *task;
+ if (qio_channel_has_feature(QIO_CHANNEL(ioc),
+ QIO_CHANNEL_FEATURE_CONCURRENT_IO)) {
+ qcrypto_tls_session_require_thread_safety(ioc->session);
+ }
+
task = qio_task_new(OBJECT(ioc),
func, opaque, destroy);
diff --git a/meson.build b/meson.build
index c2bc3ee..e53cd5b 100644
--- a/meson.build
+++ b/meson.build
@@ -1809,6 +1809,7 @@ endif
gnutls = not_found
gnutls_crypto = not_found
+gnutls_bug1717_workaround = false
if get_option('gnutls').enabled() or (get_option('gnutls').auto() and have_system)
# For general TLS support our min gnutls matches
# that implied by our platform support matrix
@@ -1834,6 +1835,12 @@ if get_option('gnutls').enabled() or (get_option('gnutls').auto() and have_syste
method: 'pkg-config',
required: get_option('gnutls'))
endif
+
+ if gnutls.found() and not get_option('gnutls-bug1717-workaround').disabled()
+ # XXX: when bug 1717 is resolved, add logic to probe for
+ # the GNUTLS fixed version number to handle the 'auto' case
+ gnutls_bug1717_workaround = true
+ endif
endif
# We prefer use of gnutls for crypto, unless the options
@@ -2585,6 +2592,7 @@ config_host_data.set('CONFIG_KEYUTILS', keyutils.found())
config_host_data.set('CONFIG_GETTID', has_gettid)
config_host_data.set('CONFIG_GNUTLS', gnutls.found())
config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found())
+config_host_data.set('CONFIG_GNUTLS_BUG1717_WORKAROUND', gnutls_bug1717_workaround)
config_host_data.set('CONFIG_TASN1', tasn1.found())
config_host_data.set('CONFIG_GCRYPT', gcrypt.found())
config_host_data.set('CONFIG_NETTLE', nettle.found())
@@ -4869,6 +4877,7 @@ summary_info += {'TLS priority': get_option('tls_priority')}
summary_info += {'GNUTLS support': gnutls}
if gnutls.found()
summary_info += {' GNUTLS crypto': gnutls_crypto.found()}
+ summary_info += {' GNUTLS bug 1717 workaround': gnutls_bug1717_workaround }
endif
summary_info += {'libgcrypt': gcrypt}
summary_info += {'nettle': nettle}
diff --git a/meson_options.txt b/meson_options.txt
index fff1521..dd33530 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -174,6 +174,8 @@ option('libcbor', type : 'feature', value : 'auto',
description: 'libcbor support')
option('gnutls', type : 'feature', value : 'auto',
description: 'GNUTLS cryptography support')
+option('gnutls-bug1717-workaround', type: 'feature', value : 'auto',
+ description: 'GNUTLS workaround for https://gitlab.com/gnutls/gnutls/-/issues/1717')
option('nettle', type : 'feature', value : 'auto',
description: 'nettle cryptography support')
option('gcrypt', type : 'feature', value : 'auto',
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index cef5608..0fc21f0 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -57,11 +57,9 @@ static const gchar *format_time_str(uint64_t us)
const char *units[] = {"us", "ms", "sec"};
int index = 0;
- while (us > 1000) {
+ while (us >= 1000 && index + 1 < ARRAY_SIZE(units)) {
us /= 1000;
- if (++index >= (sizeof(units) - 1)) {
- break;
- }
+ index++;
}
return g_strdup_printf("%"PRIu64" %s", us, units[index]);
@@ -153,7 +151,9 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
if (info->has_status) {
monitor_printf(mon, "Status: \t\t%s",
MigrationStatus_str(info->status));
- if (info->status == MIGRATION_STATUS_FAILED && info->error_desc) {
+ if ((info->status == MIGRATION_STATUS_FAILED ||
+ info->status == MIGRATION_STATUS_POSTCOPY_PAUSED) &&
+ info->error_desc) {
monitor_printf(mon, " (%s)\n", info->error_desc);
} else {
monitor_printf(mon, "\n");
diff --git a/migration/tls.c b/migration/tls.c
index 5cbf952..284a619 100644
--- a/migration/tls.c
+++ b/migration/tls.c
@@ -90,6 +90,10 @@ void migration_tls_channel_process_incoming(MigrationState *s,
trace_migration_tls_incoming_handshake_start();
qio_channel_set_name(QIO_CHANNEL(tioc), "migration-tls-incoming");
+ if (migrate_postcopy_ram() || migrate_return_path()) {
+ qio_channel_set_feature(QIO_CHANNEL(tioc),
+ QIO_CHANNEL_FEATURE_CONCURRENT_IO);
+ }
qio_channel_tls_handshake(tioc,
migration_tls_incoming_handshake,
NULL,
@@ -149,6 +153,11 @@ void migration_tls_channel_connect(MigrationState *s,
s->hostname = g_strdup(hostname);
trace_migration_tls_outgoing_handshake_start(hostname);
qio_channel_set_name(QIO_CHANNEL(tioc), "migration-tls-outgoing");
+
+ if (migrate_postcopy_ram() || migrate_return_path()) {
+ qio_channel_set_feature(QIO_CHANNEL(tioc),
+ QIO_CHANNEL_FEATURE_CONCURRENT_IO);
+ }
qio_channel_tls_handshake(tioc,
migration_tls_outgoing_handshake,
s,
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 0ebe6bc..d559e26 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -123,6 +123,9 @@ meson_options_help() {
printf "%s\n" ' gio use libgio for D-Bus support'
printf "%s\n" ' glusterfs Glusterfs block device driver'
printf "%s\n" ' gnutls GNUTLS cryptography support'
+ printf "%s\n" ' gnutls-bug1717-workaround'
+ printf "%s\n" ' GNUTLS workaround for'
+ printf "%s\n" ' https://gitlab.com/gnutls/gnutls/-/issues/1717'
printf "%s\n" ' gtk GTK+ user interface'
printf "%s\n" ' gtk-clipboard clipboard support for the gtk UI (EXPERIMENTAL, MAY HANG)'
printf "%s\n" ' guest-agent Build QEMU Guest Agent'
@@ -331,6 +334,8 @@ _meson_option_parse() {
--disable-glusterfs) printf "%s" -Dglusterfs=disabled ;;
--enable-gnutls) printf "%s" -Dgnutls=enabled ;;
--disable-gnutls) printf "%s" -Dgnutls=disabled ;;
+ --enable-gnutls-bug1717-workaround) printf "%s" -Dgnutls-bug1717-workaround=enabled ;;
+ --disable-gnutls-bug1717-workaround) printf "%s" -Dgnutls-bug1717-workaround=disabled ;;
--enable-gtk) printf "%s" -Dgtk=enabled ;;
--disable-gtk) printf "%s" -Dgtk=disabled ;;
--enable-gtk-clipboard) printf "%s" -Dgtk_clipboard=enabled ;;
diff --git a/scripts/tracetool/backend/log.py b/scripts/tracetool/backend/log.py
index 5c9d09d..eb50cee 100644
--- a/scripts/tracetool/backend/log.py
+++ b/scripts/tracetool/backend/log.py
@@ -20,7 +20,6 @@ PUBLIC = True
def generate_h_begin(events, group):
out('#include "qemu/log-for-trace.h"',
- '#include "qemu/error-report.h"',
'')
@@ -32,20 +31,9 @@ def generate_h(event, group):
cond = "trace_event_get_state(%s)" % ("TRACE_" + event.name.upper())
out(' if (%(cond)s && qemu_loglevel_mask(LOG_TRACE)) {',
- ' if (message_with_timestamp) {',
- ' struct timeval _now;',
- ' gettimeofday(&_now, NULL);',
'#line %(event_lineno)d "%(event_filename)s"',
- ' qemu_log("%%d@%%zu.%%06zu:%(name)s " %(fmt)s "\\n",',
- ' qemu_get_thread_id(),',
- ' (size_t)_now.tv_sec, (size_t)_now.tv_usec',
- ' %(argnames)s);',
+ ' qemu_log("%(name)s " %(fmt)s "\\n"%(argnames)s);',
'#line %(out_next_lineno)d "%(out_filename)s"',
- ' } else {',
- '#line %(event_lineno)d "%(event_filename)s"',
- ' qemu_log("%(name)s " %(fmt)s "\\n"%(argnames)s);',
- '#line %(out_next_lineno)d "%(out_filename)s"',
- ' }',
' }',
cond=cond,
event_lineno=event.lineno,
diff --git a/util/log.c b/util/log.c
index 58d24de..abdcb6b 100644
--- a/util/log.c
+++ b/util/log.c
@@ -145,10 +145,28 @@ void qemu_log_unlock(FILE *logfile)
void qemu_log(const char *fmt, ...)
{
- FILE *f = qemu_log_trylock();
+ FILE *f;
+ g_autofree const char *timestr = NULL;
+
+ /*
+ * Prepare the timestamp *outside* the logging
+ * lock so it better reflects when the message
+ * was emitted if we are delayed acquiring the
+ * mutex
+ */
+ if (message_with_timestamp) {
+ g_autoptr(GDateTime) dt = g_date_time_new_now_utc();
+ timestr = g_date_time_format_iso8601(dt);
+ }
+
+ f = qemu_log_trylock();
if (f) {
va_list ap;
+ if (timestr) {
+ fprintf(f, "%s ", timestr);
+ }
+
va_start(ap, fmt);
vfprintf(f, fmt, ap);
va_end(ap);