Merge tag 'staging-pull-request' of https://gitlab.com/peterx/qemu into staging
mem + migration pull for 10.2
- Fabiano's patch to fix snapshot crash by rejecting some caps
- Marco's mapped-ram support on snapshot save/load
- Steve's cpr maintainers entry update on retirement
- Peter's coverity fixes
- Chenyi's tdx fix on hugetlbfs regression
- Peter's doc update on migrate resume flag
- Peter's doc update on HMP set parameter for cpr-exec-command's char** parsing
- Xiaoyao's guest-memfd fix for enabling shmem
- Arun's fix on error_fatal regression for migration errors
- Bin's fix on redundant error free for add block failures
- Markus's cleanup around MigMode sets
- Peter's two patches (out of loadvm threadify) to cleanup qio read peek process
- Thomas's vmstate-static-checker update for possible deprecation of argparse use
- Stefan's fix on windows deadlock by making unassigned MMIOs lockless
# -----BEGIN PGP SIGNATURE-----
#
# iIgEABYKADAWIQS5GE3CDMRX2s990ak7X8zN86vXBgUCaQkZPBIccGV0ZXJ4QHJl
# ZGhhdC5jb20ACgkQO1/MzfOr1wZhTgEA8eCBMpM7PusNSdzzeIygKnIp2A8I70ca
# eIJz3ZM+FiUBAPVDrIZ59EhZA6NPcJb8Ya9OY4lT63F4BxrvN+f+uG4N
# =GUBi
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 03 Nov 2025 10:06:04 PM CET
# gpg: using EDDSA key B9184DC20CC457DACF7DD1A93B5FCCCDF3ABD706
# gpg: issuer "peterx@redhat.com"
# gpg: Good signature from "Peter Xu <xzpeter@gmail.com>" [unknown]
# gpg: aka "Peter Xu <peterx@redhat.com>" [unknown]
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: B918 4DC2 0CC4 57DA CF7D D1A9 3B5F CCCD F3AB D706
* tag 'staging-pull-request' of https://gitlab.com/peterx/qemu: (36 commits)
migration: Introduce POSTCOPY_DEVICE state
migration: Make postcopy listen thread joinable
migration: Respect exit-on-error when migration fails before resuming
migration: Refactor all incoming cleanup info migration_incoming_destroy()
migration: Introduce postcopy incoming setup and cleanup functions
migration: Move postcopy_ram_listen_thread() to postcopy-ram.c
migration: Do not try to start VM if disk activation fails
migration: Flush migration channel after sending data of CMD_PACKAGED
system/physmem: mark io_mem_unassigned lockless
scripts/vmstate-static-checker: Fix deprecation warnings with latest argparse
migration: vmsd errp handlers: return bool
migration/vmstate: stop reporting error number for new _errp APIs
tmp_emulator: improve and fix use of errp
migration: vmstate_save_state_v(): fix error path
migration: Properly wait on G_IO_IN when peeking messages
io: Add qio_channel_wait_cond() helper
migration: Put Error **errp parameter last
migration: Use bitset of MigMode instead of variable arguments
migration: Use unsigned instead of int for bit set of MigMode
migration: Don't free the reason after calling migrate_add_blocker
...
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/MAINTAINERS b/MAINTAINERS
index 12ec2d6..be6efff 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4424,6 +4424,7 @@
M: Thomas Huth <thuth@redhat.com>
R: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Daniel P. Berrange <berrange@redhat.com>
+S: Maintained
F: docs/devel/testing/functional.rst
F: scripts/clean_functional_cache.py
F: tests/functional/qemu_test/
diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c
index 2fb4643..f84342e 100644
--- a/accel/tcg/tcg-accel-ops-rr.c
+++ b/accel/tcg/tcg-accel-ops-rr.c
@@ -197,7 +197,7 @@
qemu_guest_random_seed_thread_part2(cpu->random_seed);
/* wait for initial kick-off after machine start */
- while (first_cpu->stopped) {
+ while (cpu_is_stopped(first_cpu)) {
qemu_cond_wait_bql(first_cpu->halt_cond);
/* process any pending work */
diff --git a/crypto/cipher-gnutls.c.inc b/crypto/cipher-gnutls.c.inc
index b9450d4..a8263ff 100644
--- a/crypto/cipher-gnutls.c.inc
+++ b/crypto/cipher-gnutls.c.inc
@@ -23,10 +23,6 @@
#include <gnutls/crypto.h>
-#if GNUTLS_VERSION_NUMBER >= 0x030608
-#define QEMU_GNUTLS_XTS
-#endif
-
bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
QCryptoCipherMode mode)
{
@@ -44,7 +40,6 @@
default:
return false;
}
-#ifdef QEMU_GNUTLS_XTS
case QCRYPTO_CIPHER_MODE_XTS:
switch (alg) {
case QCRYPTO_CIPHER_ALGO_AES_128:
@@ -53,7 +48,6 @@
default:
return false;
}
-#endif
default:
return false;
}
@@ -241,7 +235,6 @@
int err;
switch (mode) {
-#ifdef QEMU_GNUTLS_XTS
case QCRYPTO_CIPHER_MODE_XTS:
switch (alg) {
case QCRYPTO_CIPHER_ALGO_AES_128:
@@ -254,7 +247,6 @@
break;
}
break;
-#endif
case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_CBC:
diff --git a/crypto/cipher-nettle.c.inc b/crypto/cipher-nettle.c.inc
index ae91363..1afdc39 100644
--- a/crypto/cipher-nettle.c.inc
+++ b/crypto/cipher-nettle.c.inc
@@ -18,10 +18,6 @@
*
*/
-#ifdef CONFIG_QEMU_PRIVATE_XTS
-#include "crypto/xts.h"
-#endif
-
#include <nettle/nettle-types.h>
#include <nettle/aes.h>
#include <nettle/des.h>
@@ -30,9 +26,7 @@
#include <nettle/serpent.h>
#include <nettle/twofish.h>
#include <nettle/ctr.h>
-#ifndef CONFIG_QEMU_PRIVATE_XTS
#include <nettle/xts.h>
-#endif
#ifdef CONFIG_CRYPTO_SM4
#include <nettle/sm4.h>
#endif
@@ -154,43 +148,6 @@
};
-#ifdef CONFIG_QEMU_PRIVATE_XTS
-#define DEFINE__XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
-static void NAME##_xts_wrape(const void *ctx, size_t length, \
- uint8_t *dst, const uint8_t *src) \
-{ \
- ENCRYPT((const void *)ctx, length, dst, src); \
-} \
-static void NAME##_xts_wrapd(const void *ctx, size_t length, \
- uint8_t *dst, const uint8_t *src) \
-{ \
- DECRYPT((const void *)ctx, length, dst, src); \
-} \
-static int NAME##_encrypt_xts(QCryptoCipher *cipher, const void *in, \
- void *out, size_t len, Error **errp) \
-{ \
- TYPE *ctx = container_of(cipher, TYPE, base); \
- if (!qcrypto_length_check(len, BLEN, errp)) { \
- return -1; \
- } \
- xts_encrypt(&ctx->key, &ctx->key_xts, \
- NAME##_xts_wrape, NAME##_xts_wrapd, \
- ctx->iv, len, out, in); \
- return 0; \
-} \
-static int NAME##_decrypt_xts(QCryptoCipher *cipher, const void *in, \
- void *out, size_t len, Error **errp) \
-{ \
- TYPE *ctx = container_of(cipher, TYPE, base); \
- if (!qcrypto_length_check(len, BLEN, errp)) { \
- return -1; \
- } \
- xts_decrypt(&ctx->key, &ctx->key_xts, \
- NAME##_xts_wrape, NAME##_xts_wrapd, \
- ctx->iv, len, out, in); \
- return 0; \
-}
-#else
#define DEFINE__XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
static int NAME##_encrypt_xts(QCryptoCipher *cipher, const void *in, \
void *out, size_t len, Error **errp) \
@@ -214,7 +171,6 @@
ctx->iv, len, out, in); \
return 0; \
}
-#endif
#define DEFINE_XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
QEMU_BUILD_BUG_ON(BLEN != XTS_BLOCK_SIZE); \
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 229710f..515165e 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -142,7 +142,7 @@
#include "cipher-gcrypt.c.inc"
#elif defined CONFIG_NETTLE
#include "cipher-nettle.c.inc"
-#elif defined CONFIG_GNUTLS_CRYPTO
+#elif defined CONFIG_GNUTLS
#include "cipher-gnutls.c.inc"
#else
#include "cipher-stub.c.inc"
diff --git a/crypto/hash.c b/crypto/hash.c
index 7513769..6ffb88b 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -67,13 +67,13 @@
int qcrypto_hash_bytes(QCryptoHashAlgo alg,
- const char *buf,
+ const void *buf,
size_t len,
uint8_t **result,
size_t *resultlen,
Error **errp)
{
- struct iovec iov = { .iov_base = (char *)buf,
+ struct iovec iov = { .iov_base = (void *)buf,
.iov_len = len };
return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp);
}
@@ -89,11 +89,11 @@
}
int qcrypto_hash_update(QCryptoHash *hash,
- const char *buf,
+ const void *buf,
size_t len,
Error **errp)
{
- struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
+ struct iovec iov = { .iov_base = (void *)buf, .iov_len = len };
return qcrypto_hash_updatev(hash, &iov, 1, errp);
}
@@ -206,12 +206,12 @@
}
int qcrypto_hash_digest(QCryptoHashAlgo alg,
- const char *buf,
+ const void *buf,
size_t len,
char **digest,
Error **errp)
{
- struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
+ struct iovec iov = { .iov_base = (void *)buf, .iov_len = len };
return qcrypto_hash_digestv(alg, &iov, 1, digest, errp);
}
@@ -237,12 +237,12 @@
}
int qcrypto_hash_base64(QCryptoHashAlgo alg,
- const char *buf,
+ const void *buf,
size_t len,
char **base64,
Error **errp)
{
- struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
+ struct iovec iov = { .iov_base = (void *)buf, .iov_len = len };
return qcrypto_hash_base64v(alg, &iov, 1, base64, errp);
}
diff --git a/crypto/hmac.c b/crypto/hmac.c
index 422e005..2f0d044 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -28,14 +28,14 @@
}
int qcrypto_hmac_bytes(QCryptoHmac *hmac,
- const char *buf,
+ const void *buf,
size_t len,
uint8_t **result,
size_t *resultlen,
Error **errp)
{
struct iovec iov = {
- .iov_base = (char *)buf,
+ .iov_base = (void *)buf,
.iov_len = len
};
@@ -70,13 +70,13 @@
}
int qcrypto_hmac_digest(QCryptoHmac *hmac,
- const char *buf,
+ const void *buf,
size_t len,
char **digest,
Error **errp)
{
struct iovec iov = {
- .iov_base = (char *)buf,
+ .iov_base = (void *)buf,
.iov_len = len
};
diff --git a/crypto/meson.build b/crypto/meson.build
index 735635d..b51597a 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -25,7 +25,10 @@
))
if gnutls.found()
- crypto_ss.add(files('x509-utils.c'))
+ crypto_ss.add(files(
+ 'tlscredsbox.c',
+ 'x509-utils.c',
+ ))
endif
if nettle.found()
@@ -33,12 +36,9 @@
if hogweed.found()
crypto_ss.add(gmp, hogweed)
endif
- if xts == 'private'
- crypto_ss.add(files('xts.c'))
- endif
elif gcrypt.found()
crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c'))
-elif gnutls_crypto.found()
+elif gnutls.found()
crypto_ss.add(gnutls, files('hash-gnutls.c', 'hmac-gnutls.c', 'pbkdf-gnutls.c'))
else
crypto_ss.add(files('hash-glib.c', 'hmac-glib.c', 'pbkdf-stub.c'))
diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c
index 9e59594..fb09e29 100644
--- a/crypto/tlscreds.c
+++ b/crypto/tlscreds.c
@@ -22,6 +22,7 @@
#include "qapi/error.h"
#include "qapi-types-crypto.h"
#include "qemu/module.h"
+#include "qemu/error-report.h"
#include "tlscredspriv.h"
#include "trace.h"
@@ -38,22 +39,7 @@
trace_qcrypto_tls_creds_load_dh(creds, filename ? filename : "<generated>");
- if (filename == NULL) {
- ret = gnutls_dh_params_init(dh_params);
- if (ret < 0) {
- error_setg(errp, "Unable to initialize DH parameters: %s",
- gnutls_strerror(ret));
- return -1;
- }
- ret = gnutls_dh_params_generate2(*dh_params, DH_BITS);
- if (ret < 0) {
- gnutls_dh_params_deinit(*dh_params);
- *dh_params = NULL;
- error_setg(errp, "Unable to generate DH parameters: %s",
- gnutls_strerror(ret));
- return -1;
- }
- } else {
+ if (filename != NULL) {
GError *gerr = NULL;
gchar *contents;
gsize len;
@@ -67,6 +53,10 @@
g_error_free(gerr);
return -1;
}
+ warn_report_once("Use of an external DH parameters file '%s' is "
+ "deprecated and will be removed in a future release",
+ filename);
+
data.data = (unsigned char *)contents;
data.size = len;
ret = gnutls_dh_params_init(dh_params);
@@ -87,12 +77,22 @@
filename, gnutls_strerror(ret));
return -1;
}
+ } else {
+ *dh_params = NULL;
}
return 0;
}
+char *
+qcrypto_tls_creds_build_path(QCryptoTLSCreds *creds,
+ const char *filename)
+{
+ return g_strdup_printf("%s/%s", creds->dir, filename);
+}
+
+
int
qcrypto_tls_creds_get_path(QCryptoTLSCreds *creds,
const char *filename,
@@ -100,21 +100,11 @@
char **cred,
Error **errp)
{
- struct stat sb;
int ret = -1;
- if (!creds->dir) {
- if (required) {
- error_setg(errp, "Missing 'dir' property value");
- return -1;
- } else {
- return 0;
- }
- }
+ *cred = qcrypto_tls_creds_build_path(creds, filename);
- *cred = g_strdup_printf("%s/%s", creds->dir, filename);
-
- if (stat(*cred, &sb) < 0) {
+ if (access(*cred, R_OK) < 0) {
if (errno == ENOENT && !required) {
ret = 0;
} else {
@@ -256,6 +246,9 @@
{
QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
+#ifdef CONFIG_GNUTLS
+ qcrypto_tls_creds_box_unref(creds->box);
+#endif
g_free(creds->dir);
g_free(creds->priority);
}
@@ -272,6 +265,36 @@
return true;
}
+
+char *qcrypto_tls_creds_get_priority(QCryptoTLSCreds *creds)
+{
+ QCryptoTLSCredsClass *tcc = QCRYPTO_TLS_CREDS_GET_CLASS(creds);
+ const char *priorityBase =
+ creds->priority ? creds->priority : CONFIG_TLS_PRIORITY;
+
+ if (tcc->prioritySuffix) {
+ return g_strdup_printf("%s:%s", priorityBase, tcc->prioritySuffix);
+ } else {
+ return g_strdup(priorityBase);
+ }
+}
+
+
+bool qcrypto_tls_creds_reload(QCryptoTLSCreds *creds,
+ Error **errp)
+{
+ QCryptoTLSCredsClass *credscls = QCRYPTO_TLS_CREDS_GET_CLASS(creds);
+
+ if (credscls->reload) {
+ return credscls->reload(creds, errp);
+ }
+
+ error_setg(errp, "%s does not support reloading credentials",
+ object_get_typename(OBJECT(creds)));
+ return false;
+}
+
+
static const TypeInfo qcrypto_tls_creds_info = {
.parent = TYPE_OBJECT,
.name = TYPE_QCRYPTO_TLS_CREDS,
diff --git a/crypto/tlscredsanon.c b/crypto/tlscredsanon.c
index 44af9e6..1551382 100644
--- a/crypto/tlscredsanon.c
+++ b/crypto/tlscredsanon.c
@@ -27,15 +27,19 @@
#include "trace.h"
+struct QCryptoTLSCredsAnon {
+ QCryptoTLSCreds parent_obj;
+};
+
#ifdef CONFIG_GNUTLS
#include <gnutls/gnutls.h>
-
static int
qcrypto_tls_creds_anon_load(QCryptoTLSCredsAnon *creds,
Error **errp)
{
+ g_autoptr(QCryptoTLSCredsBox) box = NULL;
g_autofree char *dhparams = NULL;
int ret;
@@ -43,13 +47,16 @@
creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
- if (qcrypto_tls_creds_get_path(&creds->parent_obj,
+ box = qcrypto_tls_creds_box_new_server(GNUTLS_CRD_ANON);
+
+ if (creds->parent_obj.dir &&
+ qcrypto_tls_creds_get_path(&creds->parent_obj,
QCRYPTO_TLS_CREDS_DH_PARAMS,
false, &dhparams, errp) < 0) {
return -1;
}
- ret = gnutls_anon_allocate_server_credentials(&creds->data.server);
+ ret = gnutls_anon_allocate_server_credentials(&box->data.anonserver);
if (ret < 0) {
error_setg(errp, "Cannot allocate credentials: %s",
gnutls_strerror(ret));
@@ -57,46 +64,28 @@
}
if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
- &creds->parent_obj.dh_params,
- errp) < 0) {
+ &box->dh_params, errp) < 0) {
return -1;
}
- gnutls_anon_set_server_dh_params(creds->data.server,
- creds->parent_obj.dh_params);
+ if (box->dh_params) {
+ gnutls_anon_set_server_dh_params(box->data.anonserver,
+ box->dh_params);
+ }
} else {
- ret = gnutls_anon_allocate_client_credentials(&creds->data.client);
+ ret = gnutls_anon_allocate_client_credentials(&box->data.anonclient);
if (ret < 0) {
error_setg(errp, "Cannot allocate credentials: %s",
gnutls_strerror(ret));
return -1;
}
}
+ creds->parent_obj.box = g_steal_pointer(&box);
return 0;
}
-static void
-qcrypto_tls_creds_anon_unload(QCryptoTLSCredsAnon *creds)
-{
- if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
- if (creds->data.client) {
- gnutls_anon_free_client_credentials(creds->data.client);
- creds->data.client = NULL;
- }
- } else {
- if (creds->data.server) {
- gnutls_anon_free_server_credentials(creds->data.server);
- creds->data.server = NULL;
- }
- }
- if (creds->parent_obj.dh_params) {
- gnutls_dh_params_deinit(creds->parent_obj.dh_params);
- creds->parent_obj.dh_params = NULL;
- }
-}
-
#else /* ! CONFIG_GNUTLS */
@@ -108,13 +97,6 @@
}
-static void
-qcrypto_tls_creds_anon_unload(QCryptoTLSCredsAnon *creds G_GNUC_UNUSED)
-{
- /* nada */
-}
-
-
#endif /* ! CONFIG_GNUTLS */
@@ -128,20 +110,13 @@
static void
-qcrypto_tls_creds_anon_finalize(Object *obj)
-{
- QCryptoTLSCredsAnon *creds = QCRYPTO_TLS_CREDS_ANON(obj);
-
- qcrypto_tls_creds_anon_unload(creds);
-}
-
-
-static void
qcrypto_tls_creds_anon_class_init(ObjectClass *oc, const void *data)
{
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
+ QCryptoTLSCredsClass *tcc = QCRYPTO_TLS_CREDS_CLASS(oc);
ucc->complete = qcrypto_tls_creds_anon_complete;
+ tcc->prioritySuffix = "+ANON-DH";
}
@@ -149,7 +124,6 @@
.parent = TYPE_QCRYPTO_TLS_CREDS,
.name = TYPE_QCRYPTO_TLS_CREDS_ANON,
.instance_size = sizeof(QCryptoTLSCredsAnon),
- .instance_finalize = qcrypto_tls_creds_anon_finalize,
.class_size = sizeof(QCryptoTLSCredsAnonClass),
.class_init = qcrypto_tls_creds_anon_class_init,
.interfaces = (const InterfaceInfo[]) {
diff --git a/crypto/tlscredsbox.c b/crypto/tlscredsbox.c
new file mode 100644
index 0000000..b8d9846
--- /dev/null
+++ b/crypto/tlscredsbox.c
@@ -0,0 +1,101 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * QEMU crypto TLS credential support
+ *
+ * Copyright (c) 2025 Red Hat, Inc.
+ */
+
+#include "qemu/osdep.h"
+#include "crypto/tlscredsbox.h"
+#include "qemu/atomic.h"
+
+
+static QCryptoTLSCredsBox *
+qcrypto_tls_creds_box_new_impl(int type, bool server)
+{
+ QCryptoTLSCredsBox *credsbox = g_new0(QCryptoTLSCredsBox, 1);
+ credsbox->ref = 1;
+ credsbox->server = server;
+ credsbox->type = type;
+ return credsbox;
+}
+
+
+QCryptoTLSCredsBox *
+qcrypto_tls_creds_box_new_server(int type)
+{
+ return qcrypto_tls_creds_box_new_impl(type, true);
+}
+
+
+QCryptoTLSCredsBox *
+qcrypto_tls_creds_box_new_client(int type)
+{
+ return qcrypto_tls_creds_box_new_impl(type, false);
+}
+
+static void qcrypto_tls_creds_box_free(QCryptoTLSCredsBox *credsbox)
+{
+ switch (credsbox->type) {
+ case GNUTLS_CRD_CERTIFICATE:
+ if (credsbox->data.cert) {
+ gnutls_certificate_free_credentials(credsbox->data.cert);
+ }
+ break;
+ case GNUTLS_CRD_PSK:
+ if (credsbox->server) {
+ if (credsbox->data.pskserver) {
+ gnutls_psk_free_server_credentials(credsbox->data.pskserver);
+ }
+ } else {
+ if (credsbox->data.pskclient) {
+ gnutls_psk_free_client_credentials(credsbox->data.pskclient);
+ }
+ }
+ break;
+ case GNUTLS_CRD_ANON:
+ if (credsbox->server) {
+ if (credsbox->data.anonserver) {
+ gnutls_anon_free_server_credentials(credsbox->data.anonserver);
+ }
+ } else {
+ if (credsbox->data.anonclient) {
+ gnutls_anon_free_client_credentials(credsbox->data.anonclient);
+ }
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (credsbox->dh_params) {
+ gnutls_dh_params_deinit(credsbox->dh_params);
+ }
+
+ g_free(credsbox);
+}
+
+
+void qcrypto_tls_creds_box_ref(QCryptoTLSCredsBox *credsbox)
+{
+ uint32_t ref = qatomic_fetch_inc(&credsbox->ref);
+ /* Assert waaay before the integer overflows */
+ g_assert(ref < INT_MAX);
+}
+
+
+void qcrypto_tls_creds_box_unref(QCryptoTLSCredsBox *credsbox)
+{
+ if (!credsbox) {
+ return;
+ }
+
+ g_assert(credsbox->ref > 0);
+
+ if (qatomic_fetch_dec(&credsbox->ref) == 1) {
+ qcrypto_tls_creds_box_free(credsbox);
+ }
+
+}
+
diff --git a/crypto/tlscredsbox.h b/crypto/tlscredsbox.h
new file mode 100644
index 0000000..eeb54d1
--- /dev/null
+++ b/crypto/tlscredsbox.h
@@ -0,0 +1,50 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * QEMU crypto TLS credential support
+ *
+ * Copyright (c) 2025 Red Hat, Inc.
+ */
+
+#ifndef QCRYPTO_TLSCREDS_BOX_H
+#define QCRYPTO_TLSCREDS_BOX_H
+
+#include "qom/object.h"
+
+#ifdef CONFIG_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
+typedef struct QCryptoTLSCredsBox QCryptoTLSCredsBox;
+
+struct QCryptoTLSCredsBox {
+ uint32_t ref;
+ bool server;
+ int type;
+ union {
+ void *any;
+#ifdef CONFIG_GNUTLS
+ /*
+ * All of these gnutls_XXXX_credentials_t types are
+ * pointers, hence matching the 'any' field above
+ */
+ gnutls_anon_server_credentials_t anonserver;
+ gnutls_anon_client_credentials_t anonclient;
+ gnutls_psk_server_credentials_t pskserver;
+ gnutls_psk_client_credentials_t pskclient;
+ gnutls_certificate_credentials_t cert;
+#endif
+ } data;
+#ifdef CONFIG_GNUTLS
+ gnutls_dh_params_t dh_params;
+#endif
+};
+
+QCryptoTLSCredsBox *qcrypto_tls_creds_box_new_server(int type);
+QCryptoTLSCredsBox *qcrypto_tls_creds_box_new_client(int type);
+void qcrypto_tls_creds_box_ref(QCryptoTLSCredsBox *credsbox);
+void qcrypto_tls_creds_box_unref(QCryptoTLSCredsBox *credsbox);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsBox, qcrypto_tls_creds_box_unref);
+
+#endif /* QCRYPTO_TLSCREDS_BOX_H */
diff --git a/crypto/tlscredspriv.h b/crypto/tlscredspriv.h
index df9815a..8f2d096 100644
--- a/crypto/tlscredspriv.h
+++ b/crypto/tlscredspriv.h
@@ -22,6 +22,7 @@
#define QCRYPTO_TLSCREDSPRIV_H
#include "crypto/tlscreds.h"
+#include "crypto/tlscredsbox.h"
#ifdef CONFIG_GNUTLS
#include <gnutls/gnutls.h>
@@ -31,45 +32,16 @@
Object parent_obj;
char *dir;
QCryptoTLSCredsEndpoint endpoint;
-#ifdef CONFIG_GNUTLS
- gnutls_dh_params_t dh_params;
-#endif
bool verifyPeer;
char *priority;
-};
-
-struct QCryptoTLSCredsAnon {
- QCryptoTLSCreds parent_obj;
-#ifdef CONFIG_GNUTLS
- union {
- gnutls_anon_server_credentials_t server;
- gnutls_anon_client_credentials_t client;
- } data;
-#endif
-};
-
-struct QCryptoTLSCredsPSK {
- QCryptoTLSCreds parent_obj;
- char *username;
-#ifdef CONFIG_GNUTLS
- union {
- gnutls_psk_server_credentials_t server;
- gnutls_psk_client_credentials_t client;
- } data;
-#endif
-};
-
-struct QCryptoTLSCredsX509 {
- QCryptoTLSCreds parent_obj;
-#ifdef CONFIG_GNUTLS
- gnutls_certificate_credentials_t data;
-#endif
- bool sanityCheck;
- char *passwordid;
+ QCryptoTLSCredsBox *box;
};
#ifdef CONFIG_GNUTLS
+char *qcrypto_tls_creds_build_path(QCryptoTLSCreds *creds,
+ const char *filename);
+
int qcrypto_tls_creds_get_path(QCryptoTLSCreds *creds,
const char *filename,
bool required,
diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c
index 5b68a6b..e1b1e1a 100644
--- a/crypto/tlscredspsk.c
+++ b/crypto/tlscredspsk.c
@@ -27,6 +27,11 @@
#include "trace.h"
+struct QCryptoTLSCredsPSK {
+ QCryptoTLSCreds parent_obj;
+ char *username;
+};
+
#ifdef CONFIG_GNUTLS
#include <gnutls/gnutls.h>
@@ -71,6 +76,7 @@
qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds,
Error **errp)
{
+ g_autoptr(QCryptoTLSCredsBox) box = NULL;
g_autofree char *pskfile = NULL;
g_autofree char *dhparams = NULL;
const char *username;
@@ -81,7 +87,14 @@
trace_qcrypto_tls_creds_psk_load(creds,
creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
+ if (!creds->parent_obj.dir) {
+ error_setg(errp, "Missing 'dir' property value");
+ goto cleanup;
+ }
+
if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+ box = qcrypto_tls_creds_box_new_server(GNUTLS_CRD_PSK);
+
if (creds->username) {
error_setg(errp, "username should not be set when endpoint=server");
goto cleanup;
@@ -96,7 +109,7 @@
goto cleanup;
}
- ret = gnutls_psk_allocate_server_credentials(&creds->data.server);
+ ret = gnutls_psk_allocate_server_credentials(&box->data.pskserver);
if (ret < 0) {
error_setg(errp, "Cannot allocate credentials: %s",
gnutls_strerror(ret));
@@ -104,20 +117,25 @@
}
if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
- &creds->parent_obj.dh_params,
+ &box->dh_params,
errp) < 0) {
goto cleanup;
}
- ret = gnutls_psk_set_server_credentials_file(creds->data.server, pskfile);
+ ret = gnutls_psk_set_server_credentials_file(box->data.pskserver,
+ pskfile);
if (ret < 0) {
error_setg(errp, "Cannot set PSK server credentials: %s",
gnutls_strerror(ret));
goto cleanup;
}
- gnutls_psk_set_server_dh_params(creds->data.server,
- creds->parent_obj.dh_params);
+ if (box->dh_params) {
+ gnutls_psk_set_server_dh_params(box->data.pskserver,
+ box->dh_params);
+ }
} else {
+ box = qcrypto_tls_creds_box_new_client(GNUTLS_CRD_PSK);
+
if (qcrypto_tls_creds_get_path(&creds->parent_obj,
QCRYPTO_TLS_CREDS_PSKFILE,
true, &pskfile, errp) < 0) {
@@ -133,14 +151,14 @@
goto cleanup;
}
- ret = gnutls_psk_allocate_client_credentials(&creds->data.client);
+ ret = gnutls_psk_allocate_client_credentials(&box->data.pskclient);
if (ret < 0) {
error_setg(errp, "Cannot allocate credentials: %s",
gnutls_strerror(ret));
goto cleanup;
}
- ret = gnutls_psk_set_client_credentials(creds->data.client,
+ ret = gnutls_psk_set_client_credentials(box->data.pskclient,
username, &key, GNUTLS_PSK_KEY_HEX);
if (ret < 0) {
error_setg(errp, "Cannot set PSK client credentials: %s",
@@ -148,6 +166,7 @@
goto cleanup;
}
}
+ creds->parent_obj.box = g_steal_pointer(&box);
rv = 0;
cleanup:
@@ -155,27 +174,6 @@
return rv;
}
-
-static void
-qcrypto_tls_creds_psk_unload(QCryptoTLSCredsPSK *creds)
-{
- if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
- if (creds->data.client) {
- gnutls_psk_free_client_credentials(creds->data.client);
- creds->data.client = NULL;
- }
- } else {
- if (creds->data.server) {
- gnutls_psk_free_server_credentials(creds->data.server);
- creds->data.server = NULL;
- }
- }
- if (creds->parent_obj.dh_params) {
- gnutls_dh_params_deinit(creds->parent_obj.dh_params);
- creds->parent_obj.dh_params = NULL;
- }
-}
-
#else /* ! CONFIG_GNUTLS */
@@ -187,13 +185,6 @@
}
-static void
-qcrypto_tls_creds_psk_unload(QCryptoTLSCredsPSK *creds G_GNUC_UNUSED)
-{
- /* nada */
-}
-
-
#endif /* ! CONFIG_GNUTLS */
@@ -211,7 +202,6 @@
{
QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj);
- qcrypto_tls_creds_psk_unload(creds);
g_free(creds->username);
}
@@ -239,8 +229,10 @@
qcrypto_tls_creds_psk_class_init(ObjectClass *oc, const void *data)
{
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
+ QCryptoTLSCredsClass *tcc = QCRYPTO_TLS_CREDS_CLASS(oc);
ucc->complete = qcrypto_tls_creds_psk_complete;
+ tcc->prioritySuffix = "+ECDHE-PSK:+DHE-PSK:+PSK";
object_class_property_add_str(oc, "username",
qcrypto_tls_creds_psk_prop_get_username,
diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c
index db2b74b..b8d0cd2 100644
--- a/crypto/tlscredsx509.c
+++ b/crypto/tlscredsx509.c
@@ -28,12 +28,81 @@
#include "trace.h"
+struct QCryptoTLSCredsX509 {
+ QCryptoTLSCreds parent_obj;
+ bool sanityCheck;
+ char *passwordid;
+};
+
#ifdef CONFIG_GNUTLS
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
+typedef struct QCryptoTLSCredsX509IdentFiles QCryptoTLSCredsX509IdentFiles;
+struct QCryptoTLSCredsX509IdentFiles {
+ char *certpath;
+ char *keypath;
+ gnutls_x509_crt_t *certs;
+ unsigned int ncerts;
+ gnutls_x509_privkey_t key;
+};
+
+typedef struct QCryptoTLSCredsX509Files QCryptoTLSCredsX509Files;
+struct QCryptoTLSCredsX509Files {
+ char *cacertpath;
+ gnutls_x509_crt_t *cacerts;
+ unsigned int ncacerts;
+
+ QCryptoTLSCredsX509IdentFiles **identities;
+ size_t nidentities;
+};
+
+static QCryptoTLSCredsX509Files *
+qcrypto_tls_creds_x509_files_new(void)
+{
+ return g_new0(QCryptoTLSCredsX509Files, 1);
+}
+
+
+static void
+qcrypto_tls_creds_x509_ident_files_free(QCryptoTLSCredsX509IdentFiles *files)
+{
+ size_t i;
+ for (i = 0; i < files->ncerts; i++) {
+ gnutls_x509_crt_deinit(files->certs[i]);
+ }
+ gnutls_x509_privkey_deinit(files->key);
+ g_free(files->certs);
+ g_free(files->certpath);
+ g_free(files->keypath);
+ g_free(files);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsX509IdentFiles,
+ qcrypto_tls_creds_x509_ident_files_free);
+
+
+static void
+qcrypto_tls_creds_x509_files_free(QCryptoTLSCredsX509Files *files)
+{
+ size_t i;
+ for (i = 0; i < files->ncacerts; i++) {
+ gnutls_x509_crt_deinit(files->cacerts[i]);
+ }
+ g_free(files->cacerts);
+ g_free(files->cacertpath);
+ for (i = 0; i < files->nidentities; i++) {
+ qcrypto_tls_creds_x509_ident_files_free(files->identities[i]);
+ }
+ g_free(files->identities);
+ g_free(files);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsX509Files,
+ qcrypto_tls_creds_x509_files_free);
+
static int
qcrypto_tls_creds_check_cert_times(gnutls_x509_crt_t cert,
const char *certFile,
@@ -309,13 +378,10 @@
static int
qcrypto_tls_creds_check_authority_chain(QCryptoTLSCredsX509 *creds,
+ QCryptoTLSCredsX509Files *files,
gnutls_x509_crt_t *certs,
unsigned int ncerts,
- gnutls_x509_crt_t *cacerts,
- unsigned int ncacerts,
- const char *cacertFile,
bool isServer,
- bool isCA,
Error **errp)
{
gnutls_x509_crt_t cert_to_check = certs[ncerts - 1];
@@ -355,13 +421,13 @@
* reached the root of trust.
*/
return qcrypto_tls_creds_check_cert(
- creds, cert_to_check, cacertFile,
- isServer, isCA, errp);
+ creds, cert_to_check, files->cacertpath,
+ isServer, true, errp);
}
- for (int i = 0; i < ncacerts; i++) {
+ for (int i = 0; i < files->ncacerts; i++) {
if (gnutls_x509_crt_check_issuer(cert_to_check,
- cacerts[i])) {
- cert_issuer = cacerts[i];
+ files->cacerts[i])) {
+ cert_issuer = files->cacerts[i];
break;
}
}
@@ -369,8 +435,8 @@
break;
}
- if (qcrypto_tls_creds_check_cert(creds, cert_issuer, cacertFile,
- isServer, isCA, errp) < 0) {
+ if (qcrypto_tls_creds_check_cert(creds, cert_issuer, files->cacertpath,
+ isServer, true, errp) < 0) {
return -1;
}
@@ -389,19 +455,17 @@
}
static int
-qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t *certs,
+qcrypto_tls_creds_check_cert_pair(QCryptoTLSCredsX509Files *files,
+ gnutls_x509_crt_t *certs,
size_t ncerts,
const char *certFile,
- gnutls_x509_crt_t *cacerts,
- size_t ncacerts,
- const char *cacertFile,
bool isServer,
Error **errp)
{
unsigned int status;
if (gnutls_x509_crt_list_verify(certs, ncerts,
- cacerts, ncacerts,
+ files->cacerts, files->ncacerts,
NULL, 0,
0, &status) < 0) {
error_setg(errp, isServer ?
@@ -409,7 +473,7 @@
"CA certificate %s" :
"Unable to verify client certificate %s against "
"CA certificate %s",
- certFile, cacertFile);
+ certFile, files->cacertpath);
return -1;
}
@@ -434,7 +498,7 @@
error_setg(errp,
"Our own certificate %s failed validation against %s: %s",
- certFile, cacertFile, reason);
+ certFile, files->cacertpath, reason);
return -1;
}
@@ -447,14 +511,13 @@
const char *certFile,
gnutls_x509_crt_t **certs,
unsigned int *ncerts,
- bool isServer,
- bool isCA,
Error **errp)
{
gnutls_datum_t data;
g_autofree char *buf = NULL;
gsize buflen;
GError *gerr = NULL;
+ int ret;
*ncerts = 0;
trace_qcrypto_tls_creds_x509_load_cert_list(creds, certFile);
@@ -469,13 +532,94 @@
data.data = (unsigned char *)buf;
data.size = strlen(buf);
- if (gnutls_x509_crt_list_import2(certs, ncerts, &data,
- GNUTLS_X509_FMT_PEM, 0) < 0) {
- error_setg(errp,
- isCA ? "Unable to import CA certificate list %s" :
- (isServer ? "Unable to import server certificate %s" :
- "Unable to import client certificate %s"),
- certFile);
+ ret = gnutls_x509_crt_list_import2(certs, ncerts, &data,
+ GNUTLS_X509_FMT_PEM, 0);
+ if (ret < 0) {
+ error_setg(errp, "Unable to import certificate %s: %s",
+ certFile, gnutls_strerror(ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+qcrypto_tls_creds_load_privkey(QCryptoTLSCredsX509 *creds,
+ const char *keyFile,
+ gnutls_x509_privkey_t *key,
+ Error **errp)
+{
+ gnutls_datum_t data;
+ g_autofree char *buf = NULL;
+ g_autofree char *password = NULL;
+ gsize buflen;
+ GError *gerr = NULL;
+ int ret;
+
+ ret = gnutls_x509_privkey_init(key);
+ if (ret < 0) {
+ error_setg(errp, "Unable to initialize private key: %s",
+ gnutls_strerror(ret));
+ return -1;
+ }
+
+ if (!g_file_get_contents(keyFile, &buf, &buflen, &gerr)) {
+ error_setg(errp, "Cannot load private key %s: %s",
+ keyFile, gerr->message);
+ g_error_free(gerr);
+ return -1;
+ }
+
+ data.data = (unsigned char *)buf;
+ data.size = strlen(buf);
+
+ if (creds->passwordid) {
+ password = qcrypto_secret_lookup_as_utf8(creds->passwordid,
+ errp);
+ if (!password) {
+ return -1;
+ }
+ }
+
+ if (gnutls_x509_privkey_import2(*key, &data,
+ GNUTLS_X509_FMT_PEM,
+ password, 0) < 0) {
+ error_setg(errp, "Unable to import private key %s", keyFile);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+qcrypto_tls_creds_x509_sanity_check_identity(QCryptoTLSCredsX509 *creds,
+ QCryptoTLSCredsX509Files *files,
+ QCryptoTLSCredsX509IdentFiles *ifiles,
+ bool isServer,
+ Error **errp)
+{
+ size_t i;
+
+ for (i = 0; i < ifiles->ncerts; i++) {
+ if (qcrypto_tls_creds_check_cert(creds,
+ ifiles->certs[i], ifiles->certpath,
+ isServer, i != 0, errp) < 0) {
+ return -1;
+ }
+ }
+
+ if (ifiles->ncerts &&
+ qcrypto_tls_creds_check_authority_chain(creds, files,
+ ifiles->certs, ifiles->ncerts,
+ isServer, errp) < 0) {
+ return -1;
+ }
+
+ if (ifiles->ncerts &&
+ qcrypto_tls_creds_check_cert_pair(files, ifiles->certs, ifiles->ncerts,
+ ifiles->certpath, isServer, errp) < 0) {
return -1;
}
@@ -485,78 +629,191 @@
static int
qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
+ QCryptoTLSCredsX509Files *files,
bool isServer,
- const char *cacertFile,
- const char *certFile,
Error **errp)
{
- gnutls_x509_crt_t *certs = NULL;
- unsigned int ncerts = 0;
- gnutls_x509_crt_t *cacerts = NULL;
- unsigned int ncacerts = 0;
size_t i;
- int ret = -1;
-
- if (certFile &&
- access(certFile, R_OK) == 0) {
- if (qcrypto_tls_creds_load_cert_list(creds,
- certFile,
- &certs,
- &ncerts,
- isServer,
- false,
- errp) < 0) {
- goto cleanup;
+ for (i = 0; i < files->nidentities; i++) {
+ if (qcrypto_tls_creds_x509_sanity_check_identity(creds,
+ files,
+ files->identities[i],
+ isServer,
+ errp) < 0) {
+ return -1;
}
}
- if (access(cacertFile, R_OK) == 0) {
- if (qcrypto_tls_creds_load_cert_list(creds,
- cacertFile,
- &cacerts,
- &ncacerts,
- isServer,
- true,
- errp) < 0) {
- goto cleanup;
+ return 0;
+}
+
+
+static int
+qcrypto_tls_creds_x509_load_ca(QCryptoTLSCredsX509 *creds,
+ QCryptoTLSCredsBox *box,
+ QCryptoTLSCredsX509Files *files,
+ bool isServer,
+ Error **errp)
+{
+ int ret;
+
+ if (qcrypto_tls_creds_get_path(&creds->parent_obj,
+ QCRYPTO_TLS_CREDS_X509_CA_CERT,
+ true, &files->cacertpath, errp) < 0) {
+ return -1;
+ }
+
+ if (qcrypto_tls_creds_load_cert_list(creds,
+ files->cacertpath,
+ &files->cacerts,
+ &files->ncacerts,
+ errp) < 0) {
+ return -1;
+ }
+
+ ret = gnutls_certificate_set_x509_trust(box->data.cert,
+ files->cacerts, files->ncacerts);
+ if (ret < 0) {
+ error_setg(errp, "Cannot set CA certificate '%s': %s",
+ files->cacertpath, gnutls_strerror(ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static QCryptoTLSCredsX509IdentFiles *
+qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
+ QCryptoTLSCredsBox *box,
+ const char *certbase,
+ const char *keybase,
+ Error **errp)
+{
+ g_autoptr(QCryptoTLSCredsX509IdentFiles) files =
+ g_new0(QCryptoTLSCredsX509IdentFiles, 1);
+ int ret;
+
+ if (qcrypto_tls_creds_get_path(&creds->parent_obj, certbase,
+ false, &files->certpath, errp) < 0 ||
+ qcrypto_tls_creds_get_path(&creds->parent_obj, keybase,
+ false, &files->keypath, errp) < 0) {
+ return NULL;
+ }
+
+ if (!files->certpath &&
+ !files->keypath) {
+ return NULL;
+ }
+ if (files->certpath && !files->keypath) {
+ g_autofree char *keypath =
+ qcrypto_tls_creds_build_path(&creds->parent_obj, keybase);
+ error_setg(errp, "Cert '%s' without corresponding key '%s'",
+ files->certpath, keypath);
+ return NULL;
+ }
+ if (!files->certpath && files->keypath) {
+ g_autofree char *certpath =
+ qcrypto_tls_creds_build_path(&creds->parent_obj, certbase);
+ error_setg(errp, "Key '%s' without corresponding cert '%s'",
+ files->keypath, certpath);
+ return NULL;
+ }
+
+ if (qcrypto_tls_creds_load_cert_list(creds,
+ files->certpath,
+ &files->certs,
+ &files->ncerts,
+ errp) < 0) {
+ return NULL;
+ }
+
+ if (qcrypto_tls_creds_load_privkey(creds,
+ files->keypath,
+ &files->key,
+ errp) < 0) {
+ return NULL;
+ }
+
+ ret = gnutls_certificate_set_x509_key(box->data.cert,
+ files->certs,
+ files->ncerts,
+ files->key);
+ if (ret < 0) {
+ error_setg(errp, "Cannot set certificate '%s' & key '%s': %s",
+ files->certpath, files->keypath, gnutls_strerror(ret));
+ return NULL;
+ }
+ return g_steal_pointer(&files);
+}
+
+
+static int
+qcrypto_tls_creds_x509_load_identities(QCryptoTLSCredsX509 *creds,
+ QCryptoTLSCredsBox *box,
+ QCryptoTLSCredsX509Files *files,
+ bool isServer,
+ Error **errp)
+{
+ ERRP_GUARD();
+ QCryptoTLSCredsX509IdentFiles *ifiles;
+ size_t i;
+
+ ifiles = qcrypto_tls_creds_x509_load_identity(
+ creds, box,
+ isServer ?
+ QCRYPTO_TLS_CREDS_X509_SERVER_CERT :
+ QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
+ isServer ?
+ QCRYPTO_TLS_CREDS_X509_SERVER_KEY :
+ QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
+ errp);
+ if (!ifiles && *errp) {
+ return -1;
+ }
+
+ if (ifiles) {
+ files->identities = g_renew(QCryptoTLSCredsX509IdentFiles *,
+ files->identities,
+ files->nidentities + 1);
+ files->identities[files->nidentities++] = ifiles;
+ }
+
+ for (i = 0; i < QCRYPTO_TLS_CREDS_X509_IDENTITY_MAX; i++) {
+ g_autofree char *cert = g_strdup_printf(
+ isServer ?
+ QCRYPTO_TLS_CREDS_X509_SERVER_CERT_N :
+ QCRYPTO_TLS_CREDS_X509_CLIENT_CERT_N, i);
+ g_autofree char *key = g_strdup_printf(
+ isServer ?
+ QCRYPTO_TLS_CREDS_X509_SERVER_KEY_N :
+ QCRYPTO_TLS_CREDS_X509_CLIENT_KEY_N, i);
+
+ ifiles = qcrypto_tls_creds_x509_load_identity(creds, box,
+ cert, key, errp);
+ if (!ifiles && *errp) {
+ return -1;
}
- }
-
- for (i = 0; i < ncerts; i++) {
- if (qcrypto_tls_creds_check_cert(creds,
- certs[i], certFile,
- isServer, i != 0, errp) < 0) {
- goto cleanup;
+ if (!ifiles) {
+ break;
}
+
+ files->identities = g_renew(QCryptoTLSCredsX509IdentFiles *,
+ files->identities,
+ files->nidentities + 1);
+ files->identities[files->nidentities++] = ifiles;
}
- if (ncerts &&
- qcrypto_tls_creds_check_authority_chain(creds,
- certs, ncerts,
- cacerts, ncacerts,
- cacertFile, isServer,
- true, errp) < 0) {
- goto cleanup;
+ if (files->nidentities == 0 && isServer) {
+ g_autofree char *certpath = qcrypto_tls_creds_build_path(
+ &creds->parent_obj, QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
+ g_autofree char *keypath = qcrypto_tls_creds_build_path(
+ &creds->parent_obj, QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
+ error_setg(errp, "Missing server cert '%s' & key '%s'",
+ certpath, keypath);
+ return -1;
}
- if (ncerts && ncacerts &&
- qcrypto_tls_creds_check_cert_pair(certs, ncerts, certFile,
- cacerts, ncacerts, cacertFile,
- isServer, errp) < 0) {
- goto cleanup;
- }
-
- ret = 0;
-
- cleanup:
- for (i = 0; i < ncerts; i++) {
- gnutls_x509_crt_deinit(certs[i]);
- }
- for (i = 0; i < ncacerts; i++) {
- gnutls_x509_crt_deinit(cacerts[i]);
- }
- g_free(cacerts);
-
- return ret;
+ return 0;
}
@@ -564,134 +821,85 @@
qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
Error **errp)
{
- char *cacert = NULL, *cacrl = NULL, *cert = NULL,
- *key = NULL, *dhparams = NULL;
+ g_autoptr(QCryptoTLSCredsBox) box = NULL;
+ g_autoptr(QCryptoTLSCredsX509Files) files = NULL;
+ g_autofree char *cacrl = NULL;
+ g_autofree char *dhparams = NULL;
+ bool isServer = (creds->parent_obj.endpoint ==
+ QCRYPTO_TLS_CREDS_ENDPOINT_SERVER);
int ret;
- int rv = -1;
- trace_qcrypto_tls_creds_x509_load(creds,
- creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
+ if (!creds->parent_obj.dir) {
+ error_setg(errp, "Missing 'dir' property value");
+ return -1;
+ }
+
+ trace_qcrypto_tls_creds_x509_load(creds, creds->parent_obj.dir);
if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+ box = qcrypto_tls_creds_box_new_server(GNUTLS_CRD_CERTIFICATE);
+ } else {
+ box = qcrypto_tls_creds_box_new_client(GNUTLS_CRD_CERTIFICATE);
+ }
+
+ ret = gnutls_certificate_allocate_credentials(&box->data.cert);
+ if (ret < 0) {
+ error_setg(errp, "Cannot allocate credentials: '%s'",
+ gnutls_strerror(ret));
+ return -1;
+ }
+
+ files = qcrypto_tls_creds_x509_files_new();
+
+ if (qcrypto_tls_creds_x509_load_ca(creds, box, files, isServer, errp) < 0) {
+ return -1;
+ }
+
+ if (qcrypto_tls_creds_x509_load_identities(creds, box, files,
+ isServer, errp) < 0) {
+ return -1;
+ }
+
+ if (isServer) {
if (qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_CA_CERT,
- true, &cacert, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
QCRYPTO_TLS_CREDS_X509_CA_CRL,
false, &cacrl, errp) < 0 ||
qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
- true, &cert, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
- true, &key, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
QCRYPTO_TLS_CREDS_DH_PARAMS,
false, &dhparams, errp) < 0) {
- goto cleanup;
- }
- } else {
- if (qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_CA_CERT,
- true, &cacert, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
- false, &cert, errp) < 0 ||
- qcrypto_tls_creds_get_path(&creds->parent_obj,
- QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
- false, &key, errp) < 0) {
- goto cleanup;
+ return -1;
}
}
if (creds->sanityCheck &&
- qcrypto_tls_creds_x509_sanity_check(creds,
- creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
- cacert, cert, errp) < 0) {
- goto cleanup;
- }
-
- ret = gnutls_certificate_allocate_credentials(&creds->data);
- if (ret < 0) {
- error_setg(errp, "Cannot allocate credentials: '%s'",
- gnutls_strerror(ret));
- goto cleanup;
- }
-
- ret = gnutls_certificate_set_x509_trust_file(creds->data,
- cacert,
- GNUTLS_X509_FMT_PEM);
- if (ret < 0) {
- error_setg(errp, "Cannot load CA certificate '%s': %s",
- cacert, gnutls_strerror(ret));
- goto cleanup;
- }
-
- if (cert != NULL && key != NULL) {
- char *password = NULL;
- if (creds->passwordid) {
- password = qcrypto_secret_lookup_as_utf8(creds->passwordid,
- errp);
- if (!password) {
- goto cleanup;
- }
- }
- ret = gnutls_certificate_set_x509_key_file2(creds->data,
- cert, key,
- GNUTLS_X509_FMT_PEM,
- password,
- 0);
- g_free(password);
- if (ret < 0) {
- error_setg(errp, "Cannot load certificate '%s' & key '%s': %s",
- cert, key, gnutls_strerror(ret));
- goto cleanup;
- }
+ qcrypto_tls_creds_x509_sanity_check(creds, files, isServer, errp) < 0) {
+ return -1;
}
if (cacrl != NULL) {
- ret = gnutls_certificate_set_x509_crl_file(creds->data,
+ ret = gnutls_certificate_set_x509_crl_file(box->data.cert,
cacrl,
GNUTLS_X509_FMT_PEM);
if (ret < 0) {
error_setg(errp, "Cannot load CRL '%s': %s",
cacrl, gnutls_strerror(ret));
- goto cleanup;
+ return -1;
}
}
- if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+ if (isServer) {
if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
- &creds->parent_obj.dh_params,
+ &box->dh_params,
errp) < 0) {
- goto cleanup;
+ return -1;
}
- gnutls_certificate_set_dh_params(creds->data,
- creds->parent_obj.dh_params);
+ if (box->dh_params) {
+ gnutls_certificate_set_dh_params(box->data.cert, box->dh_params);
+ }
}
+ creds->parent_obj.box = g_steal_pointer(&box);
- rv = 0;
- cleanup:
- g_free(cacert);
- g_free(cacrl);
- g_free(cert);
- g_free(key);
- g_free(dhparams);
- return rv;
-}
-
-
-static void
-qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds)
-{
- if (creds->data) {
- gnutls_certificate_free_credentials(creds->data);
- creds->data = NULL;
- }
- if (creds->parent_obj.dh_params) {
- gnutls_dh_params_deinit(creds->parent_obj.dh_params);
- creds->parent_obj.dh_params = NULL;
- }
+ return 0;
}
@@ -706,13 +914,6 @@
}
-static void
-qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED)
-{
- /* nada */
-}
-
-
#endif /* ! CONFIG_GNUTLS */
@@ -775,26 +976,17 @@
{
QCryptoTLSCredsX509 *x509_creds = QCRYPTO_TLS_CREDS_X509(creds);
Error *local_err = NULL;
- gnutls_certificate_credentials_t creds_data = x509_creds->data;
- gnutls_dh_params_t creds_dh_params = x509_creds->parent_obj.dh_params;
+ QCryptoTLSCredsBox *creds_box = creds->box;
- x509_creds->data = NULL;
- x509_creds->parent_obj.dh_params = NULL;
+ creds->box = NULL;
qcrypto_tls_creds_x509_load(x509_creds, &local_err);
if (local_err) {
- qcrypto_tls_creds_x509_unload(x509_creds);
- x509_creds->data = creds_data;
- x509_creds->parent_obj.dh_params = creds_dh_params;
+ creds->box = creds_box;
error_propagate(errp, local_err);
return false;
}
- if (creds_data) {
- gnutls_certificate_free_credentials(creds_data);
- }
- if (creds_dh_params) {
- gnutls_dh_params_deinit(creds_dh_params);
- }
+ qcrypto_tls_creds_box_unref(creds_box);
return true;
}
@@ -827,7 +1019,6 @@
QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
g_free(creds->passwordid);
- qcrypto_tls_creds_x509_unload(creds);
}
diff --git a/crypto/tlssession.c b/crypto/tlssession.c
index 92fe4f0..314e3e9 100644
--- a/crypto/tlssession.c
+++ b/crypto/tlssession.c
@@ -38,6 +38,7 @@
struct QCryptoTLSSession {
QCryptoTLSCreds *creds;
+ QCryptoTLSCredsBox *credsbox;
gnutls_session_t handle;
char *hostname;
char *authzid;
@@ -78,6 +79,7 @@
g_free(session->hostname);
g_free(session->peername);
g_free(session->authzid);
+ qcrypto_tls_creds_box_unref(session->credsbox);
object_unref(OBJECT(session->creds));
qemu_mutex_destroy(&session->lock);
g_free(session);
@@ -155,9 +157,6 @@
}
}
-#define TLS_PRIORITY_ADDITIONAL_ANON "+ANON-DH"
-#define TLS_PRIORITY_ADDITIONAL_PSK "+ECDHE-PSK:+DHE-PSK:+PSK"
-
QCryptoTLSSession *
qcrypto_tls_session_new(QCryptoTLSCreds *creds,
const char *hostname,
@@ -167,6 +166,7 @@
{
QCryptoTLSSession *session;
int ret;
+ g_autofree char *prio = NULL;
session = g_new0(QCryptoTLSSession, 1);
trace_qcrypto_tls_session_new(
@@ -200,113 +200,41 @@
goto error;
}
- if (object_dynamic_cast(OBJECT(creds),
- TYPE_QCRYPTO_TLS_CREDS_ANON)) {
- QCryptoTLSCredsAnon *acreds = QCRYPTO_TLS_CREDS_ANON(creds);
- char *prio;
-
- if (creds->priority != NULL) {
- prio = g_strdup_printf("%s:%s",
- creds->priority,
- TLS_PRIORITY_ADDITIONAL_ANON);
- } else {
- prio = g_strdup(CONFIG_TLS_PRIORITY ":"
- TLS_PRIORITY_ADDITIONAL_ANON);
- }
-
- ret = gnutls_priority_set_direct(session->handle, prio, NULL);
- if (ret < 0) {
- error_setg(errp, "Unable to set TLS session priority %s: %s",
- prio, gnutls_strerror(ret));
- g_free(prio);
- goto error;
- }
- g_free(prio);
- if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
- ret = gnutls_credentials_set(session->handle,
- GNUTLS_CRD_ANON,
- acreds->data.server);
- } else {
- ret = gnutls_credentials_set(session->handle,
- GNUTLS_CRD_ANON,
- acreds->data.client);
- }
- if (ret < 0) {
- error_setg(errp, "Cannot set session credentials: %s",
- gnutls_strerror(ret));
- goto error;
- }
- } else if (object_dynamic_cast(OBJECT(creds),
- TYPE_QCRYPTO_TLS_CREDS_PSK)) {
- QCryptoTLSCredsPSK *pcreds = QCRYPTO_TLS_CREDS_PSK(creds);
- char *prio;
-
- if (creds->priority != NULL) {
- prio = g_strdup_printf("%s:%s",
- creds->priority,
- TLS_PRIORITY_ADDITIONAL_PSK);
- } else {
- prio = g_strdup(CONFIG_TLS_PRIORITY ":"
- TLS_PRIORITY_ADDITIONAL_PSK);
- }
-
- ret = gnutls_priority_set_direct(session->handle, prio, NULL);
- if (ret < 0) {
- error_setg(errp, "Unable to set TLS session priority %s: %s",
- prio, gnutls_strerror(ret));
- g_free(prio);
- goto error;
- }
- g_free(prio);
- if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
- ret = gnutls_credentials_set(session->handle,
- GNUTLS_CRD_PSK,
- pcreds->data.server);
- } else {
- ret = gnutls_credentials_set(session->handle,
- GNUTLS_CRD_PSK,
- pcreds->data.client);
- }
- if (ret < 0) {
- error_setg(errp, "Cannot set session credentials: %s",
- gnutls_strerror(ret));
- goto error;
- }
- } else if (object_dynamic_cast(OBJECT(creds),
- TYPE_QCRYPTO_TLS_CREDS_X509)) {
- QCryptoTLSCredsX509 *tcreds = QCRYPTO_TLS_CREDS_X509(creds);
- const char *prio = creds->priority;
- if (!prio) {
- prio = CONFIG_TLS_PRIORITY;
- }
-
- ret = gnutls_priority_set_direct(session->handle, prio, NULL);
- if (ret < 0) {
- error_setg(errp, "Cannot set default TLS session priority %s: %s",
- prio, gnutls_strerror(ret));
- goto error;
- }
- ret = gnutls_credentials_set(session->handle,
- GNUTLS_CRD_CERTIFICATE,
- tcreds->data);
- if (ret < 0) {
- error_setg(errp, "Cannot set session credentials: %s",
- gnutls_strerror(ret));
- goto error;
- }
-
- if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
- /* This requests, but does not enforce a client cert.
- * The cert checking code later does enforcement */
- gnutls_certificate_server_set_request(session->handle,
- GNUTLS_CERT_REQUEST);
- }
- } else {
- error_setg(errp, "Unsupported TLS credentials type %s",
- object_get_typename(OBJECT(creds)));
+ prio = qcrypto_tls_creds_get_priority(creds);
+ ret = gnutls_priority_set_direct(session->handle, prio, NULL);
+ if (ret < 0) {
+ error_setg(errp, "Unable to set TLS session priority %s: %s",
+ prio, gnutls_strerror(ret));
goto error;
}
+ ret = gnutls_credentials_set(session->handle,
+ creds->box->type,
+ creds->box->data.any);
+ if (ret < 0) {
+ error_setg(errp, "Cannot set session credentials: %s",
+ gnutls_strerror(ret));
+ goto error;
+ }
+
+ /*
+ * creds->box->data.any must be kept alive for as long
+ * as the gnutls_session_t is alive, so acquire a ref
+ */
+ qcrypto_tls_creds_box_ref(creds->box);
+ session->credsbox = creds->box;
+
+ if (object_dynamic_cast(OBJECT(creds),
+ TYPE_QCRYPTO_TLS_CREDS_X509) &&
+ creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+ /*
+ * This requests, but does not enforce a client cert.
+ * The cert checking code later does enforcement
+ */
+ gnutls_certificate_server_set_request(session->handle,
+ GNUTLS_CERT_REQUEST);
+ }
+
gnutls_transport_set_ptr(session->handle, session);
gnutls_transport_set_push_function(session->handle,
qcrypto_tls_session_push);
@@ -417,6 +345,7 @@
goto error;
}
session->peername = (char *)g_steal_pointer(&dname.data);
+ trace_qcrypto_tls_session_check_x509_dn(session, session->peername);
if (session->authzid) {
bool allow;
diff --git a/crypto/trace-events b/crypto/trace-events
index d0e3342..771f9b8 100644
--- a/crypto/trace-events
+++ b/crypto/trace-events
@@ -21,6 +21,7 @@
# 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_check_x509_dn(void *session, const char *dname) "TLS session check x509 distinguished name session=%p dname=%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"
diff --git a/crypto/xts.c b/crypto/xts.c
deleted file mode 100644
index d4a49fd..0000000
--- a/crypto/xts.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * QEMU Crypto XTS cipher mode
- *
- * Copyright (c) 2015-2016 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- * This code is originally derived from public domain / WTFPL code in
- * LibTomCrypt crytographic library http://libtom.org. The XTS code
- * was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
- * to the LibTom Projects
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu/bswap.h"
-#include "crypto/xts.h"
-
-typedef union {
- uint8_t b[XTS_BLOCK_SIZE];
- uint64_t u[2];
-} xts_uint128;
-
-static inline void xts_uint128_xor(xts_uint128 *D,
- const xts_uint128 *S1,
- const xts_uint128 *S2)
-{
- D->u[0] = S1->u[0] ^ S2->u[0];
- D->u[1] = S1->u[1] ^ S2->u[1];
-}
-
-static inline void xts_uint128_cpu_to_les(xts_uint128 *v)
-{
- cpu_to_le64s(&v->u[0]);
- cpu_to_le64s(&v->u[1]);
-}
-
-static inline void xts_uint128_le_to_cpus(xts_uint128 *v)
-{
- le64_to_cpus(&v->u[0]);
- le64_to_cpus(&v->u[1]);
-}
-
-static void xts_mult_x(xts_uint128 *I)
-{
- uint64_t tt;
-
- xts_uint128_le_to_cpus(I);
-
- tt = I->u[0] >> 63;
- I->u[0] <<= 1;
-
- if (I->u[1] >> 63) {
- I->u[0] ^= 0x87;
- }
- I->u[1] <<= 1;
- I->u[1] |= tt;
-
- xts_uint128_cpu_to_les(I);
-}
-
-
-/**
- * xts_tweak_encdec:
- * @param ctxt: the cipher context
- * @param func: the cipher function
- * @src: buffer providing the input text of XTS_BLOCK_SIZE bytes
- * @dst: buffer to output the output text of XTS_BLOCK_SIZE bytes
- * @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
- *
- * Encrypt/decrypt data with a tweak
- */
-static inline void xts_tweak_encdec(const void *ctx,
- xts_cipher_func *func,
- const xts_uint128 *src,
- xts_uint128 *dst,
- xts_uint128 *iv)
-{
- /* tweak encrypt block i */
- xts_uint128_xor(dst, src, iv);
-
- func(ctx, XTS_BLOCK_SIZE, dst->b, dst->b);
-
- xts_uint128_xor(dst, dst, iv);
-
- /* LFSR the tweak */
- xts_mult_x(iv);
-}
-
-
-void xts_decrypt(const void *datactx,
- const void *tweakctx,
- xts_cipher_func *encfunc,
- xts_cipher_func *decfunc,
- uint8_t *iv,
- size_t length,
- uint8_t *dst,
- const uint8_t *src)
-{
- xts_uint128 PP, CC, T;
- unsigned long i, m, mo, lim;
-
- /* get number of blocks */
- m = length >> 4;
- mo = length & 15;
-
- /* must have at least one full block */
- g_assert(m != 0);
-
- if (mo == 0) {
- lim = m;
- } else {
- lim = m - 1;
- }
-
- /* encrypt the iv */
- encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv);
-
- if (QEMU_PTR_IS_ALIGNED(src, sizeof(uint64_t)) &&
- QEMU_PTR_IS_ALIGNED(dst, sizeof(uint64_t))) {
- xts_uint128 *S = (xts_uint128 *)src;
- xts_uint128 *D = (xts_uint128 *)dst;
- for (i = 0; i < lim; i++, S++, D++) {
- xts_tweak_encdec(datactx, decfunc, S, D, &T);
- }
- } else {
- xts_uint128 D;
-
- for (i = 0; i < lim; i++) {
- memcpy(&D, src, XTS_BLOCK_SIZE);
- xts_tweak_encdec(datactx, decfunc, &D, &D, &T);
- memcpy(dst, &D, XTS_BLOCK_SIZE);
- src += XTS_BLOCK_SIZE;
- dst += XTS_BLOCK_SIZE;
- }
- }
-
- /* if length is not a multiple of XTS_BLOCK_SIZE then */
- if (mo > 0) {
- xts_uint128 S, D;
- memcpy(&CC, &T, XTS_BLOCK_SIZE);
- xts_mult_x(&CC);
-
- /* PP = tweak decrypt block m-1 */
- memcpy(&S, src, XTS_BLOCK_SIZE);
- xts_tweak_encdec(datactx, decfunc, &S, &PP, &CC);
-
- /* Pm = first length % XTS_BLOCK_SIZE bytes of PP */
- for (i = 0; i < mo; i++) {
- CC.b[i] = src[XTS_BLOCK_SIZE + i];
- dst[XTS_BLOCK_SIZE + i] = PP.b[i];
- }
- for (; i < XTS_BLOCK_SIZE; i++) {
- CC.b[i] = PP.b[i];
- }
-
- /* Pm-1 = Tweak uncrypt CC */
- xts_tweak_encdec(datactx, decfunc, &CC, &D, &T);
- memcpy(dst, &D, XTS_BLOCK_SIZE);
- }
-
- /* Decrypt the iv back */
- decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T.b);
-}
-
-
-void xts_encrypt(const void *datactx,
- const void *tweakctx,
- xts_cipher_func *encfunc,
- xts_cipher_func *decfunc,
- uint8_t *iv,
- size_t length,
- uint8_t *dst,
- const uint8_t *src)
-{
- xts_uint128 PP, CC, T;
- unsigned long i, m, mo, lim;
-
- /* get number of blocks */
- m = length >> 4;
- mo = length & 15;
-
- /* must have at least one full block */
- g_assert(m != 0);
-
- if (mo == 0) {
- lim = m;
- } else {
- lim = m - 1;
- }
-
- /* encrypt the iv */
- encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv);
-
- if (QEMU_PTR_IS_ALIGNED(src, sizeof(uint64_t)) &&
- QEMU_PTR_IS_ALIGNED(dst, sizeof(uint64_t))) {
- xts_uint128 *S = (xts_uint128 *)src;
- xts_uint128 *D = (xts_uint128 *)dst;
- for (i = 0; i < lim; i++, S++, D++) {
- xts_tweak_encdec(datactx, encfunc, S, D, &T);
- }
- } else {
- xts_uint128 D;
-
- for (i = 0; i < lim; i++) {
- memcpy(&D, src, XTS_BLOCK_SIZE);
- xts_tweak_encdec(datactx, encfunc, &D, &D, &T);
- memcpy(dst, &D, XTS_BLOCK_SIZE);
-
- dst += XTS_BLOCK_SIZE;
- src += XTS_BLOCK_SIZE;
- }
- }
-
- /* if length is not a multiple of XTS_BLOCK_SIZE then */
- if (mo > 0) {
- xts_uint128 S, D;
- /* CC = tweak encrypt block m-1 */
- memcpy(&S, src, XTS_BLOCK_SIZE);
- xts_tweak_encdec(datactx, encfunc, &S, &CC, &T);
-
- /* Cm = first length % XTS_BLOCK_SIZE bytes of CC */
- for (i = 0; i < mo; i++) {
- PP.b[i] = src[XTS_BLOCK_SIZE + i];
- dst[XTS_BLOCK_SIZE + i] = CC.b[i];
- }
-
- for (; i < XTS_BLOCK_SIZE; i++) {
- PP.b[i] = CC.b[i];
- }
-
- /* Cm-1 = Tweak encrypt PP */
- xts_tweak_encdec(datactx, encfunc, &PP, &D, &T);
- memcpy(dst, &D, XTS_BLOCK_SIZE);
- }
-
- /* Decrypt the iv back */
- decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T.b);
-}
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index 4ee98d6..03e2991 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -385,6 +385,15 @@
- move backing file to NVDIMM storage and keep ``pmem=on``
(to have NVDIMM with persistence guaranties).
+Using an external DH (Diffie-Hellman) parameters file (since 10.2)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Loading of external Diffie-Hellman parameters from a 'dh-params.pem'
+file is deprecated and will be removed with no replacement in a
+future release. Where no 'dh-params.pem' file is provided, the DH
+parameters will be automatically negotiated in accordance with
+RFC7919.
+
Device options
--------------
diff --git a/docs/devel/testing/fuzzing.rst b/docs/devel/testing/fuzzing.rst
index c3ac084..c43f815 100644
--- a/docs/devel/testing/fuzzing.rst
+++ b/docs/devel/testing/fuzzing.rst
@@ -263,6 +263,15 @@
- Report the bug and send a patch with the C reproducer upstream
+QEMU can also read the reproducer directly from a file rather than
+from standard input::
+
+ $QEMU_PATH $QEMU_ARGS -qtest chardev:repro \
+ -chardev file,id=repro,path=/dev/null,input-path=/tmp/reproducer
+
+This is useful if you want to run QEMU under a debugger to investigate
+the failure.
+
Implementation Details / Fuzzer Lifecycle
-----------------------------------------
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
index b2f7d29..75c8fbd 100644
--- a/docs/system/arm/imx8mp-evk.rst
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -60,3 +60,22 @@
-dtb imx8mp-evk.dtb \
-append "root=/dev/mmcblk2p2" \
-drive file=sdcard.img,if=sd,bus=2,format=raw,id=mmcblk2
+
+
+KVM Acceleration
+----------------
+
+To enable hardware-assisted acceleration via KVM, append
+``-accel kvm -cpu host`` to the command line. While this speeds up performance
+significantly, be aware of the following limitations:
+
+* The ``imx8mp-evk`` machine is not included under the "virtualization use case"
+ of :doc:`QEMU's security policy </system/security>`. This means that you
+ should not trust that it can contain malicious guests, whether it is run
+ using TCG or KVM. If you don't trust your guests and you're relying on QEMU to
+ be the security boundary, you want to choose another machine such as ``virt``.
+* Rather than Cortex-A53 CPUs, the same CPU type as the host's will be used.
+ This is a limitation of KVM and may not work with guests with a tight
+ dependency on Cortex-A53.
+* No EL2 and EL3 exception levels are available which is also a KVM limitation.
+ Direct kernel boot should work but running U-Boot, TF-A, etc. won't succeed.
diff --git a/docs/system/tls.rst b/docs/system/tls.rst
index a4f6781..03fa1d8 100644
--- a/docs/system/tls.rst
+++ b/docs/system/tls.rst
@@ -36,8 +36,58 @@
case it might be useful to use a commercial CA to avoid needing to
install custom CA certs in the web browsers.
-The recommendation is for the server to keep its certificates in either
-``/etc/pki/qemu`` or for unprivileged users in ``$HOME/.pki/qemu``.
+.. _tls_cert_file_naming:
+
+Certificate file naming
+~~~~~~~~~~~~~~~~~~~~~~~
+
+In a simple setup, where all QEMU instances on a machine share the
+same TLS configuration, it is suggested that QEMU certificates be
+kept in either ``/etc/pki/qemu`` or, for unprivileged users, in
+``$HOME/.pki/qemu``. Where different QEMU subsystems require
+different certificate configurations, sub-dirs of these locations
+may be chosen.
+
+The default file names that QEMU will traditionally load are:
+
+* ``ca-cert.pem`` - mandatory; for both client and server configurations
+* ``ca-crl.pem`` - optional; for server configurations only
+* ``server-cert.pem`` - mandatory; for server configurations only
+* ``server-key.pem`` - mandatory; for server configurations only
+* ``client-cert.pem`` - optional; for client configurations only
+* ``client-key.pem`` - optional; for client configurations only
+* ``dh-params.pem`` - optional; for server configurations only
+
+Since QEMU 10.2.0, there is support for loading upto four additional
+identities:
+
+* ``server-cert-[IDX].pem`` - optional; for server configurations only
+* ``server-key-[IDX].pem`` - optional; for server configurations only
+* ``client-cert-[IDX].pem`` - optional; for client configurations only
+* ``client-key-[IDX].pem`` - optional; for client configurations only
+
+where ``-[IDX]`` is one of the digits 0-3. Loading will terminate at
+the first absent index. The index based certificate files may be used
+as a replacement for, or in addition to, the traditional non-index
+based certificate files. The traditional certificate files will be
+loaded first, if present, then the index based certificates. Where
+multiple certificates are compatible with a TLS session, the first
+loaded certificate will preferred. IOW file naming can influence
+which certificates are used for a session.
+
+The use of multiple sets of certificates is intended to allow an
+incremental transition to certificates using different crytographic
+algorithms. This allows a newly deployed QEMU to introduce use of
+stronger cryptographic algorithms that will be preferred when talking
+to other newly deployed QEMU instances, while retaining compatbility
+with certificates issued to a historically deployed QEMU. This is
+notably useful to support live migration from an old QEMU deployed
+on older operating system releases, which may support fewer crypto
+algorithm choices than the current OS.
+
+The certificate creation commands below will be illustrated using
+the traditional naming scheme, but their args can be substituted
+to use the indexed naming in the obvious manner.
.. _tls_005fgenerate_005fca:
@@ -251,11 +301,13 @@
directory contains the credential files. This directory is expected to
contain files with the names mentioned previously, ``ca-cert.pem``,
``server-key.pem``, ``server-cert.pem``, ``client-key.pem`` and
-``client-cert.pem`` as appropriate. It is also possible to include a set
-of pre-generated Diffie-Hellman (DH) parameters in a file
-``dh-params.pem``, which can be created using the
-``certtool --generate-dh-params`` command. If omitted, QEMU will
-dynamically generate DH parameters when loading the credentials.
+``client-cert.pem`` as appropriate.
+
+While it is possible to include a set of pre-generated Diffie-Hellman
+(DH) parameters in a file ``dh-params.pem``, this facility is now
+deprecated and will be removed in a future release. When omitted the
+DH parameters will be automatically negotiated in accordance with
+RFC7919.
The ``endpoint`` parameter indicates whether the credentials will be
used for a network client or server, and determines which PEM files are
@@ -293,6 +345,74 @@
.. _tls_005fpsk:
+TLS certificates for Post-Quantum Cryptography
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Given a new enough gnutls release, suitably integrated & configured with the
+operating system crypto policies, QEMU is able to support post-quantum
+crytography on TLS enabled services, either exclusively or in a hybrid mode.
+
+In exclusive mode, only a single set of certificates need to be configured
+for QEMU, with PQC compliant algorithms. Such a QEMU configuration will only
+be able to interoperate with other services (including other QEMU's) that
+also have PQC enabled. This can result in compatibility concerns during the
+period of transition over to PQC compliant algorithms.
+
+In hybrid mode, multiple sets of certificates need to be configured for QEMU,
+at least one set with traditional (non-PQC compliant) algorithms, and at least
+one other set with modern (PQC compliant) algorithms. At time of the TLS
+handshake, the GNUTLS algorithm priorities should ensure that PQC compliant
+algorithms are negotiated if both sides of the connection support PQC. If one
+side lacks PQC, the TLS handshake should fallback to the non-PQC algorithms.
+This can assist with interoperability during the transition to PQC, but has a
+potential weakness wrt downgrade attacks forcing use of non-PQC algorithms.
+Exclusive PQC mode should be preferred where both peers in the TLS connections
+are known to support PQC.
+
+Key generation parameters
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To create certificates with PQC compliant algorithms, the ``--key-type``
+argument must be passed to ``certtool`` when creating private keys. No
+extra arguments are required for the other ``certtool`` commands, as
+their behaviour will be determined by the private key type.
+
+The typical PQC compliant algorithms to use are ``ML-DSA-44``, ``ML-DSA-65``
+and ``ML-DSA-87``, with ``ML-DSA-65`` being a suitable default choice in
+the absence of explicit requirements.
+
+Taking the example earlier, for creating a key for a client certificate,
+to use ``ML-DSA-65`` the command line would be modified to look like::
+
+ # certtool --generate-privkey --key-type=mldsa65 > client-hostNNN-key.pem
+
+The equivalent modification applies to the creation of the private keys
+used for server certs, or root/intermediate CA certs.
+
+For hybrid mode, the additional indexed certificate naming must be used.
+If multiple configured certificates are compatible with the mutually
+supported crypto algorithms between the client and server, then the
+first matching certificate will be used.
+
+IOW, to ensure that PQC certificates are preferred, they must use a
+non-index based filename, or use an index that is smaller than any
+non-PQC certificates. ie, ``server-cert.pem`` for PQC and ``server-cert-0.pem``
+for non-PQC, or ``server-cert-0.pem`` for PQC and ``server-cert-1.pem`` for
+non-PQC.
+
+Force disabling PQC via crypto priority
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the OS configuration for system crypto algorithm priorities has
+enabled PQC, this can (optionally) be overriden in QEMU configuration
+disable use of PQC using the ``priority`` parameter to the ``tls-creds-x509``
+object::
+
+ NO_MLDSA="-SIGN-ML-DSA-65:-SIGN-ML-DSA-44:-SIGN-ML-DSA-87"
+ NO_MLKEM="-GROUP-X25519-MLKEM768:-GROUP-SECP256R1-MLKEM768:-GROUP-SECP384R1-MLKEM1024"
+ # qemu-nbd --object tls-creds-x509,id=tls0,endpoint=server,dir=....,priority=@SYSTEM:$NO_MLDSA:$NO_MLKEM
+
+
TLS Pre-Shared Keys (PSK)
~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index b44b85f..0cdeb60 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -622,7 +622,8 @@
config FSL_IMX8MP_EVK
bool
default y
- depends on TCG && AARCH64
+ depends on AARCH64
+ depends on TCG || KVM
select FSL_IMX8MP
config ARM_SMMUV3
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index 866f4d1..ee6f3e4 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -12,11 +12,13 @@
#include "system/address-spaces.h"
#include "hw/arm/bsa.h"
#include "hw/arm/fsl-imx8mp.h"
-#include "hw/intc/arm_gicv3.h"
#include "hw/misc/unimp.h"
#include "hw/boards.h"
+#include "system/kvm.h"
#include "system/system.h"
+#include "target/arm/cpu.h"
#include "target/arm/cpu-qom.h"
+#include "target/arm/kvm_arm.h"
#include "qapi/error.h"
#include "qobject/qlist.h"
@@ -193,15 +195,15 @@
{
MachineState *ms = MACHINE(qdev_get_machine());
FslImx8mpState *s = FSL_IMX8MP(obj);
+ const char *cpu_type = ms->cpu_type ?: ARM_CPU_TYPE_NAME("cortex-a53");
int i;
for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX8MP_NUM_CPUS); i++) {
g_autofree char *name = g_strdup_printf("cpu%d", i);
- object_initialize_child(obj, name, &s->cpu[i],
- ARM_CPU_TYPE_NAME("cortex-a53"));
+ object_initialize_child(obj, name, &s->cpu[i], cpu_type);
}
- object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GICV3);
+ object_initialize_child(obj, "gic", &s->gic, gicv3_class_name());
object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX8MP_CCM);
@@ -274,7 +276,8 @@
/* CPUs */
for (i = 0; i < ms->smp.cpus; i++) {
/* On uniprocessor, the CBAR is set to 0 */
- if (ms->smp.cpus > 1) {
+ if (ms->smp.cpus > 1 &&
+ object_property_find(OBJECT(&s->cpu[i]), "reset-cbar")) {
object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar",
fsl_imx8mp_memmap[FSL_IMX8MP_GIC_DIST].addr,
&error_abort);
@@ -286,6 +289,16 @@
object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 8000000,
&error_abort);
+ if (object_property_find(OBJECT(&s->cpu[i]), "has_el2")) {
+ object_property_set_bool(OBJECT(&s->cpu[i]), "has_el2",
+ !kvm_enabled(), &error_abort);
+ }
+
+ if (object_property_find(OBJECT(&s->cpu[i]), "has_el3")) {
+ object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3",
+ !kvm_enabled(), &error_abort);
+ }
+
if (i) {
/*
* Secondary CPUs start in powered-down state (and can be
@@ -304,6 +317,7 @@
{
SysBusDevice *gicsbd = SYS_BUS_DEVICE(&s->gic);
QList *redist_region_count;
+ bool pmu = object_property_get_bool(OBJECT(first_cpu), "pmu", NULL);
qdev_prop_set_uint32(gicdev, "num-cpu", ms->smp.cpus);
qdev_prop_set_uint32(gicdev, "num-irq",
@@ -360,6 +374,16 @@
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
sysbus_connect_irq(gicsbd, i + 3 * ms->smp.cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
+
+ if (kvm_enabled()) {
+ if (pmu) {
+ assert(arm_feature(&s->cpu[i].env, ARM_FEATURE_PMU));
+ if (kvm_irqchip_in_kernel()) {
+ kvm_arm_pmu_set_irq(&s->cpu[i], VIRTUAL_PMU_IRQ);
+ }
+ kvm_arm_pmu_init(&s->cpu[i]);
+ }
+ }
}
}
diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c
index fc880a1..44e0601 100644
--- a/hw/arm/imx8mp-evk.c
+++ b/hw/arm/imx8mp-evk.c
@@ -13,6 +13,7 @@
#include "hw/arm/machines-qom.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
+#include "system/kvm.h"
#include "system/qtest.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
@@ -43,6 +44,15 @@
fdt_nop_property(fdt, offset, "cpu-idle-states");
offset = fdt_node_offset_by_compatible(fdt, offset, "arm,cortex-a53");
}
+
+ if (kvm_enabled()) {
+ /* Use system counter frequency from host CPU to fix time in guest */
+ offset = fdt_node_offset_by_compatible(fdt, -1, "arm,armv8-timer");
+ while (offset >= 0) {
+ fdt_nop_property(fdt, offset, "clock-frequency");
+ offset = fdt_node_offset_by_compatible(fdt, offset, "arm,armv8-timer");
+ }
+ }
}
static void imx8mp_evk_init(MachineState *machine)
@@ -94,12 +104,22 @@
}
}
+static const char *imx8mp_evk_get_default_cpu_type(const MachineState *ms)
+{
+ if (kvm_enabled()) {
+ return ARM_CPU_TYPE_NAME("host");
+ }
+
+ return ARM_CPU_TYPE_NAME("cortex-a53");
+}
+
static void imx8mp_evk_machine_init(MachineClass *mc)
{
mc->desc = "NXP i.MX 8M Plus EVK Board";
mc->init = imx8mp_evk_init;
mc->max_cpus = FSL_IMX8MP_NUM_CPUS;
mc->default_ram_id = "imx8mp-evk.ram";
+ mc->get_default_cpu_type = imx8mp_evk_get_default_cpu_type;
}
DEFINE_MACHINE_AARCH64("imx8mp-evk", imx8mp_evk_machine_init)
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index a3bb5aa..5841dfc 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -396,7 +396,7 @@
uint64_t subregion_size;
QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) {
- subregion_size = int128_get64(subregion->size);
+ subregion_size = memory_region_size(subregion);
if ((offset >= subregion->addr) &&
(offset + len) <= (subregion->addr + subregion_size)) {
mr = subregion;
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index 1868d4a..4352509 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -122,7 +122,7 @@
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_bytes(QCryptoHashAlgo alg,
- const char *buf,
+ const void *buf,
size_t len,
uint8_t **result,
size_t *resultlen,
@@ -180,7 +180,7 @@
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_update(QCryptoHash *hash,
- const char *buf,
+ const void *buf,
size_t len,
Error **errp);
@@ -289,7 +289,7 @@
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_digest(QCryptoHashAlgo alg,
- const char *buf,
+ const void *buf,
size_t len,
char **digest,
Error **errp);
@@ -335,7 +335,7 @@
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_base64(QCryptoHashAlgo alg,
- const char *buf,
+ const void *buf,
size_t len,
char **base64,
Error **errp);
diff --git a/include/crypto/hmac.h b/include/crypto/hmac.h
index af3d5f8..0885ae2 100644
--- a/include/crypto/hmac.h
+++ b/include/crypto/hmac.h
@@ -139,7 +139,7 @@
* 0 on success, -1 on error
*/
int qcrypto_hmac_bytes(QCryptoHmac *hmac,
- const char *buf,
+ const void *buf,
size_t len,
uint8_t **result,
size_t *resultlen,
@@ -187,7 +187,7 @@
* Returns: 0 on success, -1 on error
*/
int qcrypto_hmac_digest(QCryptoHmac *hmac,
- const char *buf,
+ const void *buf,
size_t len,
char **digest,
Error **errp);
diff --git a/include/crypto/tlscreds.h b/include/crypto/tlscreds.h
index 2a8a857..bb9280e 100644
--- a/include/crypto/tlscreds.h
+++ b/include/crypto/tlscreds.h
@@ -47,6 +47,7 @@
struct QCryptoTLSCredsClass {
ObjectClass parent_class;
CryptoTLSCredsReload reload;
+ const char *prioritySuffix;
};
/**
@@ -64,4 +65,29 @@
QCryptoTLSCredsEndpoint endpoint,
Error **errp);
+
+/**
+ * qcrypto_tls_creds_get_priority:
+ * @creds: pointer to a TLS credentials object
+ *
+ * Get the TLS credentials priority string. The caller
+ * must free the returned string when no longer required.
+ *
+ * Returns: a non-NULL priority string
+ */
+char *qcrypto_tls_creds_get_priority(QCryptoTLSCreds *creds);
+
+
+/**
+ * qcrypto_tls_creds_reload:
+ * @creds: pointer to a TLS credentials object
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Request a reload of the TLS credentials, if supported
+ *
+ * Returns: true on success, false on error or if not supported
+ */
+bool qcrypto_tls_creds_reload(QCryptoTLSCreds *creds,
+ Error **errp);
+
#endif /* QCRYPTO_TLSCREDS_H */
diff --git a/include/crypto/tlscredsx509.h b/include/crypto/tlscredsx509.h
index c4daba2..61b7f73 100644
--- a/include/crypto/tlscredsx509.h
+++ b/include/crypto/tlscredsx509.h
@@ -37,7 +37,13 @@
#define QCRYPTO_TLS_CREDS_X509_SERVER_CERT "server-cert.pem"
#define QCRYPTO_TLS_CREDS_X509_CLIENT_KEY "client-key.pem"
#define QCRYPTO_TLS_CREDS_X509_CLIENT_CERT "client-cert.pem"
+#define QCRYPTO_TLS_CREDS_X509_SERVER_KEY_N "server-key-%zu.pem"
+#define QCRYPTO_TLS_CREDS_X509_SERVER_CERT_N "server-cert-%zu.pem"
+#define QCRYPTO_TLS_CREDS_X509_CLIENT_KEY_N "client-key-%zu.pem"
+#define QCRYPTO_TLS_CREDS_X509_CLIENT_CERT_N "client-cert-%zu.pem"
+/* Max number of additional cert/key pairs (ie _N constants) */
+#define QCRYPTO_TLS_CREDS_X509_IDENTITY_MAX 4
/**
* QCryptoTLSCredsX509:
diff --git a/include/crypto/tlssession.h b/include/crypto/tlssession.h
index 2e9fe11..28e4196 100644
--- a/include/crypto/tlssession.h
+++ b/include/crypto/tlssession.h
@@ -199,11 +199,11 @@
* These must return QCRYPTO_TLS_SESSION_ERR_BLOCK if the I/O
* would block, but on other errors, must fill 'errp'
*/
-typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const char *buf,
+typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const void *buf,
size_t len,
void *opaque,
Error **errp);
-typedef ssize_t (*QCryptoTLSSessionReadFunc)(char *buf,
+typedef ssize_t (*QCryptoTLSSessionReadFunc)(void *buf,
size_t len,
void *opaque,
Error **errp);
diff --git a/include/crypto/xts.h b/include/crypto/xts.h
deleted file mode 100644
index f267b78..0000000
--- a/include/crypto/xts.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * QEMU Crypto XTS cipher mode
- *
- * Copyright (c) 2015-2016 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- * This code is originally derived from public domain / WTFPL code in
- * LibTomCrypt crytographic library http://libtom.org. The XTS code
- * was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
- * to the LibTom Projects
- *
- */
-
-#ifndef QCRYPTO_XTS_H
-#define QCRYPTO_XTS_H
-
-
-#define XTS_BLOCK_SIZE 16
-
-typedef void xts_cipher_func(const void *ctx,
- size_t length,
- uint8_t *dst,
- const uint8_t *src);
-
-/**
- * xts_decrypt:
- * @datactx: the cipher context for data decryption
- * @tweakctx: the cipher context for tweak decryption
- * @encfunc: the cipher function for encryption
- * @decfunc: the cipher function for decryption
- * @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
- * @length: the length of @dst and @src
- * @dst: buffer to hold the decrypted plaintext
- * @src: buffer providing the ciphertext
- *
- * Decrypts @src into @dst
- */
-void xts_decrypt(const void *datactx,
- const void *tweakctx,
- xts_cipher_func *encfunc,
- xts_cipher_func *decfunc,
- uint8_t *iv,
- size_t length,
- uint8_t *dst,
- const uint8_t *src);
-
-/**
- * xts_decrypt:
- * @datactx: the cipher context for data encryption
- * @tweakctx: the cipher context for tweak encryption
- * @encfunc: the cipher function for encryption
- * @decfunc: the cipher function for decryption
- * @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
- * @length: the length of @dst and @src
- * @dst: buffer to hold the encrypted ciphertext
- * @src: buffer providing the plaintext
- *
- * Decrypts @src into @dst
- */
-void xts_encrypt(const void *datactx,
- const void *tweakctx,
- xts_cipher_func *encfunc,
- xts_cipher_func *decfunc,
- uint8_t *iv,
- size_t length,
- uint8_t *dst,
- const uint8_t *src);
-
-
-#endif /* QCRYPTO_XTS_H */
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 67e15c8..e0be4ee 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -150,10 +150,6 @@
int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque);
-/* Returns: 0 on success, -1 on error */
-int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
- void *ptr, size_t len, bool is_write);
-
/* vl.c */
void list_cpus(void);
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index e79e8e0..9615051 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -689,6 +689,26 @@
void *opaque);
/**
+ * cpu_memory_rw_debug:
+ * @cpu: The CPU whose memory is to be accessed
+ * @addr: guest virtual address
+ * @ptr: buffer with the data transferred
+ * @len: the number of bytes to read or write
+ * @is_write: indicates the transfer direction
+ *
+ * Take a virtual address, convert it to a physical address via
+ * an MMU lookup using the current settings of the specified CPU,
+ * and then perform the access (using address_space_rw() for
+ * reads or address_space_write_rom() for writes).
+ *
+ * This function is intended for use by the GDB stub and similar code.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
+ void *ptr, size_t len, bool is_write);
+
+/**
* cpu_get_crash_info:
* @cpu: The CPU to get crash information for
*
diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h
index a88cf8b..fcfd489 100644
--- a/include/io/channel-socket.h
+++ b/include/io/channel-socket.h
@@ -49,6 +49,12 @@
socklen_t remoteAddrLen;
ssize_t zero_copy_queued;
ssize_t zero_copy_sent;
+ bool blocking;
+ /**
+ * This flag indicates whether any new data was successfully sent with
+ * zerocopy since the last qio_channel_socket_flush() call.
+ */
+ bool new_zero_copy_sent_success;
};
diff --git a/include/io/channel.h b/include/io/channel.h
index d6d5bf2..f42be76 100644
--- a/include/io/channel.h
+++ b/include/io/channel.h
@@ -437,7 +437,7 @@
* a single memory region.
*/
ssize_t qio_channel_read(QIOChannel *ioc,
- char *buf,
+ void *buf,
size_t buflen,
Error **errp);
@@ -453,7 +453,7 @@
* single memory region.
*/
ssize_t qio_channel_write(QIOChannel *ioc,
- const char *buf,
+ const void *buf,
size_t buflen,
Error **errp);
@@ -475,7 +475,7 @@
* without data, or -1 on error
*/
int coroutine_mixed_fn qio_channel_read_all_eof(QIOChannel *ioc,
- char *buf,
+ void *buf,
size_t buflen,
Error **errp);
@@ -495,7 +495,7 @@
* Returns: 0 if all bytes were read, or -1 on error
*/
int coroutine_mixed_fn qio_channel_read_all(QIOChannel *ioc,
- char *buf,
+ void *buf,
size_t buflen,
Error **errp);
@@ -514,7 +514,7 @@
* Returns: 0 if all bytes were written, or -1 on error
*/
int coroutine_mixed_fn qio_channel_write_all(QIOChannel *ioc,
- const char *buf,
+ const void *buf,
size_t buflen,
Error **errp);
@@ -595,7 +595,7 @@
* flag QIO_CHANNEL_FEATURE_SEEKABLE prior to calling this method.
*
*/
-ssize_t qio_channel_pwrite(QIOChannel *ioc, char *buf, size_t buflen,
+ssize_t qio_channel_pwrite(QIOChannel *ioc, void *buf, size_t buflen,
off_t offset, Error **errp);
/**
@@ -631,7 +631,7 @@
* flag QIO_CHANNEL_FEATURE_SEEKABLE prior to calling this method.
*
*/
-ssize_t qio_channel_pread(QIOChannel *ioc, char *buf, size_t buflen,
+ssize_t qio_channel_pread(QIOChannel *ioc, void *buf, size_t buflen,
off_t offset, Error **errp);
/**
diff --git a/include/qemu/exit-with-parent.h b/include/qemu/exit-with-parent.h
new file mode 100644
index 0000000..c00b863
--- /dev/null
+++ b/include/qemu/exit-with-parent.h
@@ -0,0 +1,57 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Originally derived from nbdkit common/utils/exit-with-parent.h
+ * Copyright Red Hat
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef NBDKIT_EXIT_WITH_PARENT_H
+#define NBDKIT_EXIT_WITH_PARENT_H
+
+/* Test if the feature is available on the platform. */
+static inline bool can_exit_with_parent(void)
+{
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
+ return true;
+#else
+ return false;
+#endif
+}
+
+/*
+ * --exit-with-parent: kill the current process if the parent exits.
+ * This may return -1 on error.
+ *
+ * Note this will abort on platforms where can_exit_with_parent()
+ * returned false.
+ */
+extern int set_exit_with_parent(void);
+
+#endif /* NBDKIT_EXIT_WITH_PARENT_H */
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index 4e2436b..0d55c63 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -271,6 +271,24 @@
bool bql_locked(void);
/**
+ * mutex_is_bql:
+ *
+ * @mutex: the mutex pointer
+ *
+ * Returns whether the mutex is the BQL.
+ */
+bool mutex_is_bql(QemuMutex *mutex);
+
+/**
+ * bql_update_status:
+ *
+ * @locked: update status on whether the BQL is locked
+ *
+ * NOTE: this should normally only be invoked when the status changed.
+ */
+void bql_update_status(bool locked);
+
+/**
* bql_block: Allow/deny releasing the BQL
*
* The Big QEMU Lock (BQL) is used to provide interior mutability to
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index 406d741..8b561cd 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -786,11 +786,12 @@
}
/**
- * initclocks:
+ * qemu_init_clocks:
+ * @notify_cb: optional call-back for timer expiry
*
* Initialise the clock & timer infrastructure
*/
-void init_clocks(QEMUTimerListNotifyCB *notify_cb);
+void qemu_init_clocks(QEMUTimerListNotifyCB *notify_cb);
static inline int64_t get_max_clock_jump(void)
{
diff --git a/io/channel-socket.c b/io/channel-socket.c
index 712b793..3053b35 100644
--- a/io/channel-socket.c
+++ b/io/channel-socket.c
@@ -37,6 +37,12 @@
#define SOCKET_MAX_FDS 16
+#ifdef QEMU_MSG_ZEROCOPY
+static int qio_channel_socket_flush_internal(QIOChannel *ioc,
+ bool block,
+ Error **errp);
+#endif
+
SocketAddress *
qio_channel_socket_get_local_address(QIOChannelSocket *ioc,
Error **errp)
@@ -65,6 +71,8 @@
sioc->fd = -1;
sioc->zero_copy_queued = 0;
sioc->zero_copy_sent = 0;
+ sioc->blocking = false;
+ sioc->new_zero_copy_sent_success = false;
ioc = QIO_CHANNEL(sioc);
qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
@@ -617,6 +625,10 @@
size_t fdsize = sizeof(int) * nfds;
struct cmsghdr *cmsg;
int sflags = 0;
+#ifdef QEMU_MSG_ZEROCOPY
+ bool blocking = sioc->blocking;
+ bool zerocopy_flushed_once = false;
+#endif
memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS));
@@ -661,13 +673,30 @@
return QIO_CHANNEL_ERR_BLOCK;
case EINTR:
goto retry;
+#ifdef QEMU_MSG_ZEROCOPY
case ENOBUFS:
if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) {
- error_setg_errno(errp, errno,
- "Process can't lock enough memory for using MSG_ZEROCOPY");
- return -1;
+ /**
+ * Socket error queueing may exhaust the OPTMEM limit. Try
+ * flushing the error queue once.
+ */
+ if (!zerocopy_flushed_once) {
+ ret = qio_channel_socket_flush_internal(ioc, blocking,
+ errp);
+ if (ret < 0) {
+ return -1;
+ }
+ zerocopy_flushed_once = true;
+ goto retry;
+ } else {
+ error_setg_errno(errp, errno,
+ "Process can't lock enough memory for "
+ "using MSG_ZEROCOPY");
+ return -1;
+ }
}
break;
+#endif
}
error_setg_errno(errp, errno,
@@ -776,8 +805,9 @@
#ifdef QEMU_MSG_ZEROCOPY
-static int qio_channel_socket_flush(QIOChannel *ioc,
- Error **errp)
+static int qio_channel_socket_flush_internal(QIOChannel *ioc,
+ bool block,
+ Error **errp)
{
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
struct msghdr msg = {};
@@ -785,7 +815,6 @@
struct cmsghdr *cm;
char control[CMSG_SPACE(sizeof(*serr))];
int received;
- int ret;
if (sioc->zero_copy_queued == sioc->zero_copy_sent) {
return 0;
@@ -795,16 +824,25 @@
msg.msg_controllen = sizeof(control);
memset(control, 0, sizeof(control));
- ret = 1;
-
while (sioc->zero_copy_sent < sioc->zero_copy_queued) {
received = recvmsg(sioc->fd, &msg, MSG_ERRQUEUE);
if (received < 0) {
switch (errno) {
case EAGAIN:
- /* Nothing on errqueue, wait until something is available */
- qio_channel_wait(ioc, G_IO_ERR);
- continue;
+ if (block) {
+ /*
+ * Nothing on errqueue, wait until something is
+ * available.
+ *
+ * Use G_IO_ERR instead of G_IO_IN since MSG_ERRQUEUE reads
+ * are signaled via POLLERR, not POLLIN, as the kernel
+ * sets POLLERR when zero-copy notificatons appear on the
+ * socket error queue.
+ */
+ qio_channel_wait(ioc, G_IO_ERR);
+ continue;
+ }
+ return 0;
case EINTR:
continue;
default:
@@ -842,13 +880,32 @@
/* No errors, count successfully finished sendmsg()*/
sioc->zero_copy_sent += serr->ee_data - serr->ee_info + 1;
- /* If any sendmsg() succeeded using zero copy, return 0 at the end */
+ /* If any sendmsg() succeeded using zero copy, mark zerocopy success */
if (serr->ee_code != SO_EE_CODE_ZEROCOPY_COPIED) {
- ret = 0;
+ sioc->new_zero_copy_sent_success = true;
}
}
- return ret;
+ return 0;
+}
+
+static int qio_channel_socket_flush(QIOChannel *ioc,
+ Error **errp)
+{
+ QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
+ int ret;
+
+ ret = qio_channel_socket_flush_internal(ioc, true, errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (sioc->new_zero_copy_sent_success) {
+ sioc->new_zero_copy_sent_success = false;
+ return 0;
+ }
+
+ return 1;
}
#endif /* QEMU_MSG_ZEROCOPY */
@@ -859,6 +916,7 @@
Error **errp)
{
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
+ sioc->blocking = enabled;
if (!qemu_set_blocking(sioc->fd, enabled, errp)) {
return -1;
diff --git a/io/channel-tls.c b/io/channel-tls.c
index ce04179..b0cec27 100644
--- a/io/channel-tls.c
+++ b/io/channel-tls.c
@@ -26,7 +26,7 @@
#include "qemu/atomic.h"
-static ssize_t qio_channel_tls_write_handler(const char *buf,
+static ssize_t qio_channel_tls_write_handler(const void *buf,
size_t len,
void *opaque,
Error **errp)
@@ -43,7 +43,7 @@
return ret;
}
-static ssize_t qio_channel_tls_read_handler(char *buf,
+static ssize_t qio_channel_tls_read_handler(void *buf,
size_t len,
void *opaque,
Error **errp)
diff --git a/io/channel.c b/io/channel.c
index b18fc34..b7966ab 100644
--- a/io/channel.c
+++ b/io/channel.c
@@ -302,7 +302,7 @@
ssize_t qio_channel_read(QIOChannel *ioc,
- char *buf,
+ void *buf,
size_t buflen,
Error **errp)
{
@@ -312,7 +312,7 @@
ssize_t qio_channel_write(QIOChannel *ioc,
- const char *buf,
+ const void *buf,
size_t buflen,
Error **errp)
{
@@ -322,7 +322,7 @@
int coroutine_mixed_fn qio_channel_read_all_eof(QIOChannel *ioc,
- char *buf,
+ void *buf,
size_t buflen,
Error **errp)
{
@@ -332,7 +332,7 @@
int coroutine_mixed_fn qio_channel_read_all(QIOChannel *ioc,
- char *buf,
+ void *buf,
size_t buflen,
Error **errp)
{
@@ -342,7 +342,7 @@
int coroutine_mixed_fn qio_channel_write_all(QIOChannel *ioc,
- const char *buf,
+ const void *buf,
size_t buflen,
Error **errp)
{
@@ -467,7 +467,7 @@
return klass->io_pwritev(ioc, iov, niov, offset, errp);
}
-ssize_t qio_channel_pwrite(QIOChannel *ioc, char *buf, size_t buflen,
+ssize_t qio_channel_pwrite(QIOChannel *ioc, void *buf, size_t buflen,
off_t offset, Error **errp)
{
struct iovec iov = {
@@ -496,7 +496,7 @@
return klass->io_preadv(ioc, iov, niov, offset, errp);
}
-ssize_t qio_channel_pread(QIOChannel *ioc, char *buf, size_t buflen,
+ssize_t qio_channel_pread(QIOChannel *ioc, void *buf, size_t buflen,
off_t offset, Error **errp)
{
struct iovec iov = {
diff --git a/meson.build b/meson.build
index df876c7..b8c1296 100644
--- a/meson.build
+++ b/meson.build
@@ -1823,33 +1823,11 @@
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
- #
- # For the crypto backends, we look for a newer
- # gnutls:
- #
- # Version 3.6.8 is needed to get XTS
- # Version 3.6.13 is needed to get PBKDF
- # Version 3.6.14 is needed to get HW accelerated XTS
- #
- # If newer enough gnutls isn't available, we can
- # still use a different crypto backend to satisfy
- # the platform support requirements
- gnutls_crypto = dependency('gnutls', version: '>=3.6.14',
- method: 'pkg-config',
- required: false)
- if gnutls_crypto.found()
- gnutls = gnutls_crypto
- else
- # Our min version if all we need is TLS
- gnutls = dependency('gnutls', version: '>=3.5.18',
- method: 'pkg-config',
- required: get_option('gnutls'))
- endif
+ gnutls = dependency('gnutls', version: '>=3.7.5',
+ method: 'pkg-config',
+ required: get_option('gnutls'))
#if gnutls.found() and not get_option('gnutls-bug1717-workaround').disabled()
# XXX: when bug 1717 is resolved, add logic to probe for
@@ -1868,20 +1846,14 @@
hogweed = not_found
crypto_sm4 = not_found
crypto_sm3 = not_found
-xts = 'none'
if get_option('nettle').enabled() and get_option('gcrypt').enabled()
error('Only one of gcrypt & nettle can be enabled')
endif
-# Explicit nettle/gcrypt request, so ignore gnutls for crypto
-if get_option('nettle').enabled() or get_option('gcrypt').enabled()
- gnutls_crypto = not_found
-endif
-
-if not gnutls_crypto.found()
+if not gnutls.found()
if (not get_option('gcrypt').auto() or have_system) and not get_option('nettle').enabled()
- gcrypt = dependency('libgcrypt', version: '>=1.8',
+ gcrypt = dependency('libgcrypt', version: '>=1.9.4',
required: get_option('gcrypt'))
# Debian has removed -lgpg-error from libgcrypt-config
# as it "spreads unnecessary dependencies" which in
@@ -1893,35 +1865,12 @@
version: gcrypt.version())
endif
crypto_sm4 = gcrypt
- # SM4 ALG is available in libgcrypt >= 1.9
- if gcrypt.found() and not cc.links('''
- #include <gcrypt.h>
- int main(void) {
- gcry_cipher_hd_t handler;
- gcry_cipher_open(&handler, GCRY_CIPHER_SM4, GCRY_CIPHER_MODE_ECB, 0);
- return 0;
- }''', dependencies: gcrypt)
- crypto_sm4 = not_found
- endif
crypto_sm3 = gcrypt
- # SM3 ALG is available in libgcrypt >= 1.9
- if gcrypt.found() and not cc.links('''
- #include <gcrypt.h>
- int main(void) {
- gcry_md_hd_t handler;
- gcry_md_open(&handler, GCRY_MD_SM3, 0);
- return 0;
- }''', dependencies: gcrypt)
- crypto_sm3 = not_found
- endif
endif
if (not get_option('nettle').auto() or have_system) and not gcrypt.found()
- nettle = dependency('nettle', version: '>=3.4',
+ nettle = dependency('nettle', version: '>=3.7.3',
method: 'pkg-config',
required: get_option('nettle'))
- if nettle.found() and not cc.has_header('nettle/xts.h', dependencies: nettle)
- xts = 'private'
- endif
crypto_sm4 = nettle
# SM4 ALG is available in nettle >= 3.9
if nettle.found() and not cc.links('''
@@ -2606,7 +2555,6 @@
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())
@@ -2614,7 +2562,6 @@
config_host_data.set('CONFIG_CRYPTO_SM4', crypto_sm4.found())
config_host_data.set('CONFIG_CRYPTO_SM3', crypto_sm3.found())
config_host_data.set('CONFIG_HOGWEED', hogweed.found())
-config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private')
config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim)
config_host_data.set('CONFIG_ZSTD', zstd.found())
config_host_data.set('CONFIG_QPL', qpl.found())
@@ -4906,14 +4853,10 @@
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}
-if nettle.found()
- summary_info += {' XTS': xts != 'private'}
-endif
summary_info += {'SM4 ALG support': crypto_sm4}
summary_info += {'SM3 ALG support': crypto_sm3}
summary_info += {'AF_ALG support': have_afalg}
diff --git a/qemu-options.hx b/qemu-options.hx
index 0223cef..fca2b7b 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -5467,15 +5467,18 @@
#if defined(CONFIG_POSIX) && !defined(EMSCRIPTEN)
DEF("run-with", HAS_ARG, QEMU_OPTION_run_with,
- "-run-with [async-teardown=on|off][,chroot=dir][user=username|uid:gid]\n"
+ "-run-with [async-teardown=on|off][,chroot=dir]\n" \
+ " [,exit-with-parent=on|off][,user=username|uid:gid]\n"
" Set miscellaneous QEMU process lifecycle options:\n"
" async-teardown=on enables asynchronous teardown (Linux only)\n"
+ " exit-with-parent=on causes QEMU to exit if the parent\n"
+ " process of QEMU exits (Linux, FreeBSD, macOS only)\n"
" chroot=dir chroot to dir just before starting the VM\n"
" user=username switch to the specified user before starting the VM\n"
" user=uid:gid ditto, but use specified user-ID and group-ID instead\n",
QEMU_ARCH_ALL)
SRST
-``-run-with [async-teardown=on|off][,chroot=dir][user=username|uid:gid]``
+``-run-with [async-teardown=on|off][,chroot=dir][,exit-with-parent=on|off][,user=username|uid:gid]``
Set QEMU process lifecycle options.
``async-teardown=on`` enables asynchronous teardown. A new process called
@@ -5493,6 +5496,12 @@
immediately before starting the guest execution. This is especially useful
in combination with ``user=...``.
+ ``exit-with-parent=on`` causes QEMU to exit if the parent process of
+ QEMU exits. This can be used when QEMU runs a captive appliance,
+ where the lifetime of the appliance is scoped to the parent process.
+ In case the parent process crashes, QEMU is still cleaned up.
+ This only works on Linux, FreeBSD and macOS platforms.
+
``user=username`` or ``user=uid:gid`` can be used to drop root privileges
before starting guest execution. QEMU will use the ``setuid`` and ``setgid``
system calls to switch to the specified identity. Note that the
diff --git a/scripts/device-crash-test b/scripts/device-crash-test
index 1ecb966..c1576e8 100755
--- a/scripts/device-crash-test
+++ b/scripts/device-crash-test
@@ -527,7 +527,7 @@
# Async QMP, when in use, is chatty about connection failures.
# This script knowingly generates a ton of connection errors.
# Silence this logger.
- logging.getLogger('qemu.qmp.qmp_client').setLevel(logging.CRITICAL)
+ logging.getLogger('qemu.qmp.protocol').setLevel(logging.CRITICAL)
fatal_failures = []
wl_stats = {}
diff --git a/stubs/iothread-lock.c b/stubs/iothread-lock.c
index 6050c08..c89c9c7 100644
--- a/stubs/iothread-lock.c
+++ b/stubs/iothread-lock.c
@@ -34,3 +34,12 @@
assert((new_value > bql_unlock_blocked) == increase);
bql_unlock_blocked = new_value;
}
+
+bool mutex_is_bql(QemuMutex *mutex)
+{
+ return false;
+}
+
+void bql_update_status(bool locked)
+{
+}
diff --git a/system/cpus.c b/system/cpus.c
index aa7bfcf..ef2d2f2 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -480,10 +480,10 @@
void cpus_kick_thread(CPUState *cpu)
{
- if (cpu->thread_kicked) {
+ if (qatomic_read(&cpu->thread_kicked)) {
return;
}
- cpu->thread_kicked = true;
+ qatomic_set(&cpu->thread_kicked, true);
#ifndef _WIN32
int err = pthread_kill(cpu->thread->thread, SIG_IPI);
@@ -524,6 +524,18 @@
QEMU_DEFINE_STATIC_CO_TLS(bool, bql_locked)
+bool mutex_is_bql(QemuMutex *mutex)
+{
+ return mutex == &bql;
+}
+
+void bql_update_status(bool locked)
+{
+ /* This function should only be used when an update happened.. */
+ assert(bql_locked() != locked);
+ set_bql_locked(locked);
+}
+
static uint32_t bql_unlock_blocked;
void bql_block_unlock(bool increase)
@@ -564,14 +576,12 @@
g_assert(!bql_locked());
bql_lock_fn(&bql, file, line);
- set_bql_locked(true);
}
void bql_unlock(void)
{
g_assert(bql_locked());
g_assert(!bql_unlock_blocked);
- set_bql_locked(false);
qemu_mutex_unlock(&bql);
}
diff --git a/system/exit-with-parent.c b/system/exit-with-parent.c
new file mode 100644
index 0000000..df65d22
--- /dev/null
+++ b/system/exit-with-parent.c
@@ -0,0 +1,140 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Originally derived from nbdkit common/utils/exit-with-parent.c
+ * Copyright Red Hat
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Implement the --exit-with-parent feature on operating systems which
+ * support it.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/exit-with-parent.h"
+
+#if defined(__linux__)
+
+#include <sys/prctl.h>
+
+/*
+ * Send SIGTERM to self when the parent exits. This will cause
+ * qemu_system_killed() to be called.
+ *
+ * PR_SET_PDEATHSIG has been defined since Linux 2.1.57.
+ */
+int
+set_exit_with_parent(void)
+{
+ return prctl(PR_SET_PDEATHSIG, SIGTERM);
+}
+
+#elif defined(__FreeBSD__)
+
+#include <sys/procctl.h>
+
+/*
+ * Send SIGTERM to self when the parent exits. This will cause
+ * qemu_system_killed() to be called.
+ *
+ * PROC_PDEATHSIG_CTL has been defined since FreeBSD 11.2.
+ */
+int
+set_exit_with_parent(void)
+{
+ const int sig = SIGTERM;
+ return procctl(P_PID, 0, PROC_PDEATHSIG_CTL, (void *) &sig);
+}
+
+#elif defined(__APPLE__)
+
+/* For macOS. */
+
+#include "qemu/thread.h"
+#include "qemu/error-report.h"
+#include "system/runstate.h"
+#include <sys/event.h>
+
+static void *
+exit_with_parent_loop(void *vp)
+{
+ const pid_t ppid = getppid();
+ int fd;
+ struct kevent kev, res[1];
+ int r;
+
+ /* Register the kevent to wait for ppid to exit. */
+ fd = kqueue();
+ if (fd == -1) {
+ error_report("exit_with_parent_loop: kqueue: %m");
+ return NULL;
+ }
+ EV_SET(&kev, ppid, EVFILT_PROC, EV_ADD | EV_ENABLE, NOTE_EXIT, 0, NULL);
+ if (kevent(fd, &kev, 1, NULL, 0, NULL) == -1) {
+ error_report("exit_with_parent_loop: kevent: %m");
+ close(fd);
+ return NULL;
+ }
+
+ /* Wait for the kevent to happen. */
+ r = kevent(fd, 0, 0, res, 1, NULL);
+ if (r == 1 && res[0].ident == ppid) {
+ /* Behave like Linux and FreeBSD above, as if SIGTERM was sent */
+ qemu_system_killed(SIGTERM, ppid);
+ }
+
+ return NULL;
+}
+
+int
+set_exit_with_parent(void)
+{
+ QemuThread exit_with_parent_thread;
+
+ /*
+ * We have to block waiting for kevent, so that requires that we
+ * start a background thread.
+ */
+ qemu_thread_create(&exit_with_parent_thread,
+ "exit-parent",
+ exit_with_parent_loop, NULL,
+ QEMU_THREAD_DETACHED);
+ return 0;
+}
+
+#else /* any platform that doesn't support this function */
+
+int
+set_exit_with_parent(void)
+{
+ g_assert_not_reached();
+}
+
+#endif
diff --git a/system/meson.build b/system/meson.build
index 6d21ff9..4b69ef0 100644
--- a/system/meson.build
+++ b/system/meson.build
@@ -15,6 +15,7 @@
'datadir.c',
'dirtylimit.c',
'dma-helpers.c',
+ 'exit-with-parent.c',
'globals.c',
'ioport.c',
'ram-block-attributes.c',
diff --git a/system/vl.c b/system/vl.c
index 29f5389..5091fe5 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -53,6 +53,7 @@
#include "qemu/sockets.h"
#include "qemu/accel.h"
#include "qemu/async-teardown.h"
+#include "qemu/exit-with-parent.h"
#include "hw/usb.h"
#include "hw/isa/isa.h"
#include "hw/scsi/scsi.h"
@@ -784,6 +785,10 @@
.type = QEMU_OPT_STRING,
},
{
+ .name = "exit-with-parent",
+ .type = QEMU_OPT_BOOL,
+ },
+ {
.name = "user",
.type = QEMU_OPT_STRING,
},
@@ -3691,6 +3696,14 @@
if (str) {
os_set_chroot(str);
}
+ if (qemu_opt_get_bool(opts, "exit-with-parent", false)) {
+ if (!can_exit_with_parent()) {
+ error_report("exit-with-parent is not available"
+ " on this platform");
+ exit(1);
+ }
+ set_exit_with_parent();
+ }
str = qemu_opt_get(opts, "user");
if (str) {
if (!os_set_runas(str)) {
diff --git a/target/rx/helper.c b/target/rx/helper.c
index ef47e32..e9a7aaf 100644
--- a/target/rx/helper.c
+++ b/target/rx/helper.c
@@ -41,11 +41,9 @@
env->psw_c = FIELD_EX32(psw, PSW, C);
}
-#define INT_FLAGS (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIR)
void rx_cpu_do_interrupt(CPUState *cs)
{
CPURXState *env = cpu_env(cs);
- int do_irq = cpu_test_interrupt(cs, INT_FLAGS);
uint32_t save_psw;
uint64_t last_pc = env->pc;
@@ -59,29 +57,26 @@
save_psw = rx_cpu_pack_psw(env);
env->psw_pm = env->psw_i = env->psw_u = 0;
- if (do_irq) {
- if (do_irq & CPU_INTERRUPT_FIR) {
- env->bpc = env->pc;
- env->bpsw = save_psw;
- env->pc = env->fintv;
- env->psw_ipl = 15;
- cpu_reset_interrupt(cs, CPU_INTERRUPT_FIR);
- qemu_set_irq(env->ack, env->ack_irq);
- qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
- qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n");
- } else if (do_irq & CPU_INTERRUPT_HARD) {
- env->isp -= 4;
- cpu_stl_data(env, env->isp, save_psw);
- env->isp -= 4;
- cpu_stl_data(env, env->isp, env->pc);
- env->pc = cpu_ldl_data(env, env->intb + env->ack_irq * 4);
- env->psw_ipl = env->ack_ipl;
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- qemu_set_irq(env->ack, env->ack_irq);
- qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
- qemu_log_mask(CPU_LOG_INT,
- "interrupt 0x%02x raised\n", env->ack_irq);
- }
+ if (cpu_test_interrupt(cs, CPU_INTERRUPT_FIR)) {
+ env->bpc = env->pc;
+ env->bpsw = save_psw;
+ env->pc = env->fintv;
+ env->psw_ipl = 15;
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_FIR);
+ qemu_set_irq(env->ack, env->ack_irq);
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
+ qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n");
+ } else if (cpu_test_interrupt(cs, CPU_INTERRUPT_HARD)) {
+ env->isp -= 4;
+ cpu_stl_data(env, env->isp, save_psw);
+ env->isp -= 4;
+ cpu_stl_data(env, env->isp, env->pc);
+ env->pc = cpu_ldl_data(env, env->intb + env->ack_irq * 4);
+ env->psw_ipl = env->ack_ipl;
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+ qemu_set_irq(env->ack, env->ack_irq);
+ qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
+ qemu_log_mask(CPU_LOG_INT, "interrupt 0x%02x raised\n", env->ack_irq);
} else {
uint32_t vec = cs->exception_index;
const char *expname = "unknown exception";
diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c
index f1acb16..24675fc 100644
--- a/target/s390x/tcg/mem_helper.c
+++ b/target/s390x/tcg/mem_helper.c
@@ -1959,6 +1959,10 @@
if (env->cregs[i] != val && i >= 9 && i <= 11) {
PERchanged = true;
}
+ if (i == 0 && !(env->cregs[i] & CR0_CKC_SC) && (val & CR0_CKC_SC)) {
+ BQL_LOCK_GUARD();
+ tcg_s390_tod_updated(env_cpu(env), RUN_ON_CPU_NULL);
+ }
env->cregs[i] = val;
HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
i, src, val);
@@ -1989,10 +1993,15 @@
for (i = r1;; i = (i + 1) % 16) {
uint32_t val = cpu_ldl_data_ra(env, src, ra);
+ uint64_t val64 = deposit64(env->cregs[i], 0, 32, val);
if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
PERchanged = true;
}
- env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
+ if (i == 0 && !(env->cregs[i] & CR0_CKC_SC) && (val64 & CR0_CKC_SC)) {
+ BQL_LOCK_GUARD();
+ tcg_s390_tod_updated(env_cpu(env), RUN_ON_CPU_NULL);
+ }
+ env->cregs[i] = val64;
HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
src += sizeof(uint32_t);
diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c
index 6d9d601..215b5b9 100644
--- a/target/s390x/tcg/misc_helper.c
+++ b/target/s390x/tcg/misc_helper.c
@@ -199,11 +199,15 @@
return;
}
- /* difference between origins */
- time = env->ckc - td->base.low;
+ if (env->ckc < td->base.low) {
+ time = 0;
+ } else {
+ /* difference between origins */
+ time = env->ckc - td->base.low;
- /* nanoseconds */
- time = tod2time(time);
+ /* nanoseconds */
+ time = tod2time(time);
+ }
timer_mod(env->tod_timer, time);
}
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index ec9e5a0..4d2b8c5 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -5613,6 +5613,7 @@
int r2 = get_field(s, r2);
if (r2 != 0) {
o->in2 = load_reg(r2);
+ gen_addi_and_wrap_i64(s, o->in2, o->in2, 0);
}
}
#define SPEC_in2_r2_nz 0
@@ -6379,10 +6380,12 @@
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
- /* 31-bit mode */
- if (!(dc->base.tb->flags & FLAG_MASK_64)) {
- dc->base.pc_first &= 0x7fffffff;
- dc->base.pc_next = dc->base.pc_first;
+ if (dc->base.tb->flags & FLAG_MASK_32) {
+ if (!(dc->base.tb->flags & FLAG_MASK_64)) {
+ assert(!(dc->base.pc_first & ~((1ULL << 31) - 1)));
+ }
+ } else {
+ assert(!(dc->base.pc_first & ~((1ULL << 24) - 1)));
}
dc->cc_op = CC_OP_DYNAMIC;
diff --git a/tests/functional/arm/test_aspeed_ast1030.py b/tests/functional/arm/test_aspeed_ast1030.py
index 60e2b02..d1822ed 100755
--- a/tests/functional/arm/test_aspeed_ast1030.py
+++ b/tests/functional/arm/test_aspeed_ast1030.py
@@ -6,9 +6,8 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-from qemu_test import LinuxKernelTest, Asset
from aspeed import AspeedTest
-from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test import Asset, exec_command_and_wait_for_pattern
class AST1030Machine(AspeedTest):
diff --git a/tests/functional/migration.py b/tests/functional/migration.py
index 0739554..2bfb1f7 100644
--- a/tests/functional/migration.py
+++ b/tests/functional/migration.py
@@ -30,11 +30,11 @@ def assert_migration(self, src_vm, dst_vm):
end = time.monotonic() + self.timeout
while time.monotonic() < end and not self.migration_finished(src_vm):
- time.sleep(0.1)
+ time.sleep(0.1)
end = time.monotonic() + self.timeout
while time.monotonic() < end and not self.migration_finished(dst_vm):
- time.sleep(0.1)
+ time.sleep(0.1)
self.assertEqual(src_vm.cmd('query-migrate')['status'], 'completed')
self.assertEqual(dst_vm.cmd('query-migrate')['status'], 'completed')
diff --git a/tests/functional/ppc/test_74xx.py b/tests/functional/ppc/test_74xx.py
index 5386016..219c799 100755
--- a/tests/functional/ppc/test_74xx.py
+++ b/tests/functional/ppc/test_74xx.py
@@ -10,7 +10,7 @@
from qemu_test import QemuSystemTest
from qemu_test import wait_for_console_pattern
-class ppc74xxCpu(QemuSystemTest):
+class Ppc74xxCpu(QemuSystemTest):
timeout = 5
diff --git a/tests/functional/ppc/test_sam460ex.py b/tests/functional/ppc/test_sam460ex.py
index 31cf9dd..024406d 100755
--- a/tests/functional/ppc/test_sam460ex.py
+++ b/tests/functional/ppc/test_sam460ex.py
@@ -8,10 +8,11 @@
from qemu_test import exec_command_and_wait_for_pattern
-class sam460exTest(LinuxKernelTest):
+class Sam460exTest(LinuxKernelTest):
ASSET_BR2_SAM460EX_LINUX = Asset(
- 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/buildroot/qemu_ppc_sam460ex-2023.11-8-gdcd9f0f6eb-20240105/vmlinux',
+ ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main'
+ '/buildroot/qemu_ppc_sam460ex-2023.11-8-gdcd9f0f6eb-20240105/vmlinux'),
'6f46346f3e20e8b5fc050ff363f350f8b9d76a051b9e0bd7ea470cc680c14df2')
def test_ppc_sam460ex_buildroot(self):
diff --git a/tests/functional/ppc64/test_mac99.py b/tests/functional/ppc64/test_mac99.py
index dfd9c01..a3261a8 100755
--- a/tests/functional/ppc64/test_mac99.py
+++ b/tests/functional/ppc64/test_mac99.py
@@ -7,14 +7,16 @@
from qemu_test import LinuxKernelTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
-class mac99Test(LinuxKernelTest):
+class Mac99Test(LinuxKernelTest):
ASSET_BR2_MAC99_LINUX = Asset(
- 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/vmlinux',
+ ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main'
+ '/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/vmlinux'),
'd59307437e4365f2cced0bbd1b04949f7397b282ef349b7cafd894d74aadfbff')
ASSET_BR2_MAC99_ROOTFS = Asset(
- 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main//buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/rootfs.ext2',
+ ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main'
+ '/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/rootfs.ext2'),
'bbd5fd8af62f580bc4e585f326fe584e22856572633a8333178ea6d4ed4955a4')
def test_ppc64_mac99_buildroot(self):
diff --git a/tests/functional/ppc64/test_powernv.py b/tests/functional/ppc64/test_powernv.py
index 9ada832..0ea6c93 100755
--- a/tests/functional/ppc64/test_powernv.py
+++ b/tests/functional/ppc64/test_powernv.py
@@ -10,7 +10,7 @@
from qemu_test import LinuxKernelTest, Asset
from qemu_test import wait_for_console_pattern
-class powernvMachine(LinuxKernelTest):
+class PowernvMachine(LinuxKernelTest):
timeout = 90
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 '
diff --git a/tests/functional/ppc64/test_pseries.py b/tests/functional/ppc64/test_pseries.py
index 6705793..7840c4e 100755
--- a/tests/functional/ppc64/test_pseries.py
+++ b/tests/functional/ppc64/test_pseries.py
@@ -10,7 +10,7 @@
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
-class pseriesMachine(QemuSystemTest):
+class PseriesMachine(QemuSystemTest):
timeout = 90
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 '
diff --git a/tests/functional/ppc64/test_reverse_debug.py b/tests/functional/ppc64/test_reverse_debug.py
index 69551fb..4eef779 100755
--- a/tests/functional/ppc64/test_reverse_debug.py
+++ b/tests/functional/ppc64/test_reverse_debug.py
@@ -18,7 +18,7 @@
from reverse_debugging import ReverseDebugging
-class ReverseDebugging_ppc64(ReverseDebugging):
+class ReverseDebuggingPpc64(ReverseDebugging):
@skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/1992")
def test_ppc64_pseries(self):
diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py
index ab3a7bb..bae4076 100644
--- a/tests/functional/qemu_test/asset.py
+++ b/tests/functional/qemu_test/asset.py
@@ -112,7 +112,7 @@ def _wait_for_other_download(self, tmp_cache_file):
return False
self.log.debug("Time out while waiting for %s!", tmp_cache_file)
- raise
+ raise TimeoutError(f"Time out while waiting for {tmp_cache_file}")
def _save_time_stamp(self):
'''
@@ -141,7 +141,7 @@ def fetch(self):
self.log.info("Downloading %s to %s...", self.url, self.cache_file)
tmp_cache_file = self.cache_file.with_suffix(".download")
- for retries in range(3):
+ for _retries in range(3):
try:
with tmp_cache_file.open("xb") as dst:
with urllib.request.urlopen(self.url) as resp:
@@ -181,7 +181,7 @@ def fetch(self):
# server or networking problem
if e.code == 404:
raise AssetError(self, "Unable to download: "
- "HTTP error %d" % e.code)
+ "HTTP error %d" % e.code) from e
continue
except URLError as e:
# This is typically a network/service level error
@@ -190,7 +190,7 @@ def fetch(self):
self.log.error("Unable to download %s: URL error %s",
self.url, e.reason)
raise AssetError(self, "Unable to download: URL error %s" %
- e.reason, transient=True)
+ e.reason, transient=True) from e
except ConnectionError as e:
# A socket connection failure, such as dropped conn
# or refused conn
@@ -201,7 +201,7 @@ def fetch(self):
except Exception as e:
tmp_cache_file.unlink()
raise AssetError(self, "Unable to download: %s" % e,
- transient=True)
+ transient=True) from e
if not os.path.exists(tmp_cache_file):
raise AssetError(self, "Download retries exceeded", transient=True)
@@ -214,7 +214,6 @@ def fetch(self):
self.hash.encode('utf8'))
except Exception as e:
self.log.debug("Unable to set xattr on %s: %s", tmp_cache_file, e)
- pass
if not self._check(tmp_cache_file):
tmp_cache_file.unlink()
@@ -224,9 +223,10 @@ def fetch(self):
# Remove write perms to stop tests accidentally modifying them
os.chmod(self.cache_file, stat.S_IRUSR | stat.S_IRGRP)
- self.log.info("Cached %s at %s" % (self.url, self.cache_file))
+ self.log.info("Cached %s at %s", self.url, self.cache_file)
return str(self.cache_file)
+ @staticmethod
def precache_test(test):
log = logging.getLogger('qemu-test')
log.setLevel(logging.DEBUG)
@@ -237,16 +237,17 @@ def precache_test(test):
handler.setFormatter(formatter)
log.addHandler(handler)
for name, asset in vars(test.__class__).items():
- if name.startswith("ASSET_") and type(asset) == Asset:
+ if name.startswith("ASSET_") and isinstance(asset, Asset):
try:
asset.fetch()
except AssetError as e:
if not e.transient:
raise
- log.error("%s: skipping asset precache" % e)
+ log.error("%s: skipping asset precache", e)
log.removeHandler(handler)
+ @staticmethod
def precache_suite(suite):
for test in suite:
if isinstance(test, unittest.TestSuite):
@@ -254,9 +255,10 @@ def precache_suite(suite):
elif isinstance(test, unittest.TestCase):
Asset.precache_test(test)
- def precache_suites(path, cacheTstamp):
+ @staticmethod
+ def precache_suites(path, cache_tstamp):
loader = unittest.loader.defaultTestLoader
tests = loader.loadTestsFromNames([path], None)
- with open(cacheTstamp, "w") as fh:
+ with open(cache_tstamp, "w", encoding='utf-8'):
Asset.precache_suite(tests)
diff --git a/tests/functional/qemu_test/decorators.py b/tests/functional/qemu_test/decorators.py
index b239295..8074183 100644
--- a/tests/functional/qemu_test/decorators.py
+++ b/tests/functional/qemu_test/decorators.py
@@ -10,136 +10,134 @@
from .cmd import which
-'''
-Decorator to skip execution of a test if the provided
-environment variables are not set.
-Example:
- @skipIfMissingEnv("QEMU_ENV_VAR0", "QEMU_ENV_VAR1")
-'''
def skipIfMissingEnv(*vars_):
+ '''
+ Decorator to skip execution of a test if the provided
+ environment variables are not set.
+ Example:
+
+ @skipIfMissingEnv("QEMU_ENV_VAR0", "QEMU_ENV_VAR1")
+ '''
missing_vars = []
for var in vars_:
- if os.getenv(var) == None:
+ if os.getenv(var) is None:
missing_vars.append(var)
- has_vars = True if len(missing_vars) == 0 else False
+ has_vars = len(missing_vars) == 0
return skipUnless(has_vars, f"Missing env var(s): {', '.join(missing_vars)}")
-'''
-
-Decorator to skip execution of a test if the list
-of command binaries is not available in $PATH.
-Example:
-
- @skipIfMissingCommands("mkisofs", "losetup")
-'''
def skipIfMissingCommands(*args):
+ '''
+ Decorator to skip execution of a test if the list
+ of command binaries is not available in $PATH.
+ Example:
+
+ @skipIfMissingCommands("mkisofs", "losetup")
+ '''
has_cmds = True
for cmd in args:
- if not which(cmd):
- has_cmds = False
- break
+ if not which(cmd):
+ has_cmds = False
+ break
return skipUnless(has_cmds, 'required command(s) "%s" not installed' %
", ".join(args))
-'''
-Decorator to skip execution of a test if the current
-host operating system does match one of the prohibited
-ones.
-Example
-
- @skipIfOperatingSystem("Linux", "Darwin")
-'''
def skipIfOperatingSystem(*args):
+ '''
+ Decorator to skip execution of a test if the current host
+ operating system does match one of the prohibited ones.
+ Example:
+
+ @skipIfOperatingSystem("Linux", "Darwin")
+ '''
return skipIf(platform.system() in args,
'running on an OS (%s) that is not able to run this test' %
", ".join(args))
-'''
-Decorator to skip execution of a test if the current
-host machine does not match one of the permitted
-machines.
-Example
-
- @skipIfNotMachine("x86_64", "aarch64")
-'''
def skipIfNotMachine(*args):
+ '''
+ Decorator to skip execution of a test if the current
+ host machine does not match one of the permitted machines.
+ Example:
+
+ @skipIfNotMachine("x86_64", "aarch64")
+ '''
return skipUnless(platform.machine() in args,
'not running on one of the required machine(s) "%s"' %
", ".join(args))
-'''
-Decorator to skip execution of flaky tests, unless
-the $QEMU_TEST_FLAKY_TESTS environment variable is set.
-A bug URL must be provided that documents the observed
-failure behaviour, so it can be tracked & re-evaluated
-in future.
-
-Historical tests may be providing "None" as the bug_url
-but this should not be done for new test.
-
-Example:
-
- @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/NNN")
-'''
def skipFlakyTest(bug_url):
+ '''
+ Decorator to skip execution of flaky tests, unless
+ the $QEMU_TEST_FLAKY_TESTS environment variable is set.
+ A bug URL must be provided that documents the observed
+ failure behaviour, so it can be tracked & re-evaluated
+ in future.
+
+ Historical tests may be providing "None" as the bug_url
+ but this should not be done for new test.
+
+ Example:
+
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/NNN")
+ '''
if bug_url is None:
bug_url = "FIXME: reproduce flaky test and file bug report or remove"
return skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'),
f'Test is unstable: {bug_url}')
-'''
-Decorator to skip execution of tests which are likely
-to execute untrusted commands on the host, or commands
-which process untrusted code, unless the
-$QEMU_TEST_ALLOW_UNTRUSTED_CODE env var is set.
-Example:
-
- @skipUntrustedTest()
-'''
def skipUntrustedTest():
+ '''
+ Decorator to skip execution of tests which are likely
+ to execute untrusted commands on the host, or commands
+ which process untrusted code, unless the
+ $QEMU_TEST_ALLOW_UNTRUSTED_CODE env var is set.
+ Example:
+
+ @skipUntrustedTest()
+ '''
return skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'),
'Test runs untrusted code / processes untrusted data')
-'''
-Decorator to skip execution of tests which need large
-data storage (over around 500MB-1GB mark) on the host,
-unless the $QEMU_TEST_ALLOW_LARGE_STORAGE environment
-variable is set
-
-Example:
-
- @skipBigDataTest()
-'''
def skipBigDataTest():
+ '''
+ Decorator to skip execution of tests which need large
+ data storage (over around 500MB-1GB mark) on the host,
+ unless the $QEMU_TEST_ALLOW_LARGE_STORAGE environment
+ variable is set
+
+ Example:
+
+ @skipBigDataTest()
+ '''
return skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'),
'Test requires large host storage space')
-'''
-Decorator to skip execution of tests which have a really long
-runtime (and might e.g. time out if QEMU has been compiled with
-debugging enabled) unless the $QEMU_TEST_ALLOW_SLOW
-environment variable is set
-
-Example:
-
- @skipSlowTest()
-'''
def skipSlowTest():
+ '''
+ Decorator to skip execution of tests which have a really long
+ runtime (and might e.g. time out if QEMU has been compiled with
+ debugging enabled) unless the $QEMU_TEST_ALLOW_SLOW
+ environment variable is set
+
+ Example:
+
+ @skipSlowTest()
+ '''
return skipUnless(os.getenv('QEMU_TEST_ALLOW_SLOW'),
'Test has a very long runtime and might time out')
-'''
-Decorator to skip execution of a test if the list
-of python imports is not available.
-Example:
-
- @skipIfMissingImports("numpy", "cv2")
-'''
def skipIfMissingImports(*args):
+ '''
+ Decorator to skip execution of a test if the list
+ of python imports is not available.
+ Example:
+
+ @skipIfMissingImports("numpy", "cv2")
+ '''
has_imports = True
for impname in args:
try:
@@ -151,15 +149,15 @@ def skipIfMissingImports(*args):
return skipUnless(has_imports, 'required import(s) "%s" not installed' %
", ".join(args))
-'''
-Decorator to skip execution of a test if the system's
-locked memory limit is below the required threshold.
-Takes required locked memory threshold in kB.
-Example:
-
- @skipLockedMemoryTest(2_097_152)
-'''
def skipLockedMemoryTest(locked_memory):
+ '''
+ Decorator to skip execution of a test if the system's
+ locked memory limit is below the required threshold.
+ Takes required locked memory threshold in kB.
+ Example:
+
+ @skipLockedMemoryTest(2_097_152)
+ '''
# get memlock hard limit in bytes
_, ulimit_memory = resource.getrlimit(resource.RLIMIT_MEMLOCK)
diff --git a/tests/functional/qemu_test/linuxkernel.py b/tests/functional/qemu_test/linuxkernel.py
index c476752..eb10a81 100644
--- a/tests/functional/qemu_test/linuxkernel.py
+++ b/tests/functional/qemu_test/linuxkernel.py
@@ -83,12 +83,12 @@ def launch_kernel(self, kernel, initrd=None, dtb=None, console_index=0,
self.vm.set_console(console_index=console_index)
self.vm.add_args('-kernel', kernel)
if initrd:
- self.vm.add_args('-initrd', initrd)
+ self.vm.add_args('-initrd', initrd)
if dtb:
- self.vm.add_args('-dtb', dtb)
+ self.vm.add_args('-dtb', dtb)
self.vm.launch()
if wait_for:
- self.wait_for_console_pattern(wait_for)
+ self.wait_for_console_pattern(wait_for)
def check_http_download(self, filename, hashsum, guestport=8080,
pythoncmd='python3 -m http.server'):
diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py
index 2c0abde..1d773dd 100644
--- a/tests/functional/qemu_test/testcase.py
+++ b/tests/functional/qemu_test/testcase.py
@@ -217,7 +217,7 @@ def setUp(self):
self._log_fh = logging.FileHandler(self.log_filename, mode='w')
self._log_fh.setLevel(logging.DEBUG)
fileFormatter = logging.Formatter(
- '%(asctime)s - %(levelname)s: %(message)s')
+ '%(asctime)s - %(levelname)s: %(name)s.%(funcName)s %(message)s')
self._log_fh.setFormatter(fileFormatter)
self.log.addHandler(self._log_fh)
@@ -225,6 +225,9 @@ def setUp(self):
self.machinelog = logging.getLogger('qemu.machine')
self.machinelog.setLevel(logging.DEBUG)
self.machinelog.addHandler(self._log_fh)
+ self.qmplog = logging.getLogger('qemu.qmp')
+ self.qmplog.setLevel(logging.DEBUG)
+ self.qmplog.addHandler(self._log_fh)
if not self.assets_available():
self.skipTest('One or more assets is not available')
@@ -233,8 +236,9 @@ def tearDown(self):
if "QEMU_TEST_KEEP_SCRATCH" not in os.environ:
shutil.rmtree(self.workdir)
if self.socketdir is not None:
- shutil.rmtree(self.socketdir.name)
+ self.socketdir.cleanup()
self.socketdir = None
+ self.qmplog.removeHandler(self._log_fh)
self.machinelog.removeHandler(self._log_fh)
self.log.removeHandler(self._log_fh)
self._log_fh.close()
diff --git a/tests/functional/qemu_test/uncompress.py b/tests/functional/qemu_test/uncompress.py
index b7ef8f7..5bbdf8f 100644
--- a/tests/functional/qemu_test/uncompress.py
+++ b/tests/functional/qemu_test/uncompress.py
@@ -58,20 +58,20 @@ def zstd_uncompress(zstd_path, output_path):
os.chmod(output_path, stat.S_IRUSR | stat.S_IWUSR)
-'''
-@params compressed: filename, Asset, or file-like object to uncompress
-@params uncompressed: filename to uncompress into
-@params format: optional compression format (gzip, lzma)
-
-Uncompresses @compressed into @uncompressed
-
-If @format is None, heuristics will be applied to guess the format
-from the filename or Asset URL. @format must be non-None if @uncompressed
-is a file-like object.
-
-Returns the fully qualified path to the uncompessed file
-'''
def uncompress(compressed, uncompressed, format=None):
+ '''
+ @params compressed: filename, Asset, or file-like object to uncompress
+ @params uncompressed: filename to uncompress into
+ @params format: optional compression format (gzip, lzma)
+
+ Uncompresses @compressed into @uncompressed
+
+ If @format is None, heuristics will be applied to guess the
+ format from the filename or Asset URL. @format must be non-None
+ if @uncompressed is a file-like object.
+
+ Returns the fully qualified path to the uncompessed file
+ '''
if format is None:
format = guess_uncompress_format(compressed)
@@ -84,19 +84,19 @@ def uncompress(compressed, uncompressed, format=None):
else:
raise Exception(f"Unknown compression format {format}")
-'''
-@params compressed: filename, Asset, or file-like object to guess
-
-Guess the format of @compressed, raising an exception if
-no format can be determined
-'''
def guess_uncompress_format(compressed):
- if type(compressed) == Asset:
+ '''
+ @params compressed: filename, Asset, or file-like object to guess
+
+ Guess the format of @compressed, raising an exception if
+ no format can be determined
+ '''
+ if isinstance(compressed, Asset):
compressed = urlparse(compressed.url).path
- elif type(compressed) != str:
+ elif not isinstance(compressed, str):
raise Exception(f"Unable to guess compression cformat for {compressed}")
- (name, ext) = os.path.splitext(compressed)
+ (_name, ext) = os.path.splitext(compressed)
if ext == ".xz":
return "xz"
elif ext == ".gz":
diff --git a/tests/functional/qemu_test/utils.py b/tests/functional/qemu_test/utils.py
index e7c8de8..826c267 100644
--- a/tests/functional/qemu_test/utils.py
+++ b/tests/functional/qemu_test/utils.py
@@ -17,10 +17,10 @@ def get_usernet_hostfwd_port(vm):
res = vm.cmd('human-monitor-command', command_line='info usernet')
return get_info_usernet_hostfwd_port(res)
-"""
-Round up to next power of 2
-"""
def pow2ceil(x):
+ """
+ Round up to next power of 2
+ """
return 1 if x == 0 else 2**(x - 1).bit_length()
def file_truncate(path, size):
@@ -28,12 +28,12 @@ def file_truncate(path, size):
with open(path, 'ab+') as fd:
fd.truncate(size)
-"""
-Expand file size to next power of 2
-"""
def image_pow2ceil_expand(path):
- size = os.path.getsize(path)
- size_aligned = pow2ceil(size)
- if size != size_aligned:
- with open(path, 'ab+') as fd:
- fd.truncate(size_aligned)
+ """
+ Expand file size to next power of 2
+ """
+ size = os.path.getsize(path)
+ size_aligned = pow2ceil(size)
+ if size != size_aligned:
+ with open(path, 'ab+') as fd:
+ fd.truncate(size_aligned)
diff --git a/tests/functional/rx/test_gdbsim.py b/tests/functional/rx/test_gdbsim.py
index 4924579..d31f9a4 100755
--- a/tests/functional/rx/test_gdbsim.py
+++ b/tests/functional/rx/test_gdbsim.py
@@ -17,9 +17,6 @@
class RxGdbSimMachine(QemuSystemTest):
- timeout = 30
- KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
-
ASSET_UBOOT = Asset(
('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/'
'u-boot.bin'),
@@ -47,7 +44,7 @@ def test_uboot(self):
self.vm.launch()
uboot_version = 'U-Boot 2016.05-rc3-23705-ga1ef3c71cb-dirty'
wait_for_console_pattern(self, uboot_version)
- gcc_version = 'rx-unknown-linux-gcc (GCC) 9.0.0 20181105 (experimental)'
+ #gcc_version = 'rx-unknown-linux-gcc (GCC) 9.0.0 20181105 (experimental)'
# FIXME limit baudrate on chardev, else we type too fast
# https://gitlab.com/qemu-project/qemu/-/issues/2691
#exec_command_and_wait_for_pattern(self, 'version', gcc_version)
@@ -63,7 +60,6 @@ def test_linux_sash(self):
kernel_path = self.ASSET_KERNEL.fetch()
self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'earlycon'
self.vm.add_args('-kernel', kernel_path,
'-dtb', dtb_path,
'-no-reboot')
diff --git a/tests/functional/x86_64/test_acpi_bits.py b/tests/functional/x86_64/test_acpi_bits.py
index 9a28165..ec716d6 100755
--- a/tests/functional/x86_64/test_acpi_bits.py
+++ b/tests/functional/x86_64/test_acpi_bits.py
@@ -57,6 +57,7 @@ class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods
"""
def __init__(self,
binary: str,
+ *,
args: Sequence[str] = (),
wrapper: Sequence[str] = (),
name: Optional[str] = None,
@@ -225,7 +226,7 @@ def generate_bits_iso(self):
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
check=True)
- self.log.info("grub-mkrescue output %s" % proc.stdout)
+ self.log.info("grub-mkrescue output %s", proc.stdout)
else:
subprocess.check_call([mkrescue_script, '-o',
iso_file, bits_dir],
@@ -287,9 +288,8 @@ def parse_log(self):
except AssertionError as e:
self._print_log(log)
raise e
- else:
- if os.getenv('V') or os.getenv('BITS_DEBUG'):
- self._print_log(log)
+ if os.getenv('V') or os.getenv('BITS_DEBUG'):
+ self._print_log(log)
def tearDown(self):
"""
diff --git a/tests/functional/x86_64/test_virtio_balloon.py b/tests/functional/x86_64/test_virtio_balloon.py
index 5877b6c..7a579e0 100755
--- a/tests/functional/x86_64/test_virtio_balloon.py
+++ b/tests/functional/x86_64/test_virtio_balloon.py
@@ -66,7 +66,7 @@ def assert_initial_stats(self):
when = ret.get('last-update')
assert when == 0
stats = ret.get('stats')
- for name, val in stats.items():
+ for _name, val in stats.items():
assert val == UNSET_STATS_VALUE
def assert_running_stats(self, then):
@@ -87,10 +87,10 @@ def assert_running_stats(self, then):
now = time.time()
- assert when > then and when < now
+ assert now > when > then
stats = ret.get('stats')
# Stat we expect this particular Kernel to have set
- expectData = [
+ expect_data = [
"stat-available-memory",
"stat-disk-caches",
"stat-free-memory",
@@ -103,7 +103,7 @@ def assert_running_stats(self, then):
"stat-total-memory",
]
for name, val in stats.items():
- if name in expectData:
+ if name in expect_data:
assert val != UNSET_STATS_VALUE
else:
assert val == UNSET_STATS_VALUE
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index 933d085..622464e 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -33,6 +33,7 @@
#include "qemu/accel.h"
#include "qemu/ctype.h"
#include "qemu/cutils.h"
+#include "qemu/exit-with-parent.h"
#include "qemu/sockets.h"
#include "qobject/qdict.h"
#include "qobject/qjson.h"
@@ -433,24 +434,6 @@
#ifndef _WIN32
pid = fork();
if (pid == 0) {
-#ifdef __linux__
- /*
- * Although we register a ABRT handler to kill off QEMU
- * when g_assert() triggers, we want an extra safety
- * net. The QEMU process might be non-functional and
- * thus not have responded to SIGTERM. The test script
- * might also have crashed with SEGV, in which case the
- * cleanup handlers won't ever run.
- *
- * This PR_SET_PDEATHSIG setup will ensure any remaining
- * QEMU will get terminated with SIGKILL in these cases.
- */
- prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
-#endif /* __linux__ */
-#ifdef __FreeBSD__
- int sig = SIGKILL;
- procctl(P_PID, getpid(), PROC_PDEATHSIG_CTL, &sig);
-#endif /* __FreeBSD__ */
execlp("/bin/sh", "sh", "-c", command->str, NULL);
exit(1);
}
@@ -482,12 +465,15 @@
"-display none "
"-audio none "
"%s"
+ "%s"
" -accel qtest",
tracearg,
socket_path,
getenv("QTEST_LOG") ? DEV_STDERR : DEV_NULL,
qmp_socket_path,
+ can_exit_with_parent() ?
+ "-run-with exit-with-parent=on " : "",
extra_args ?: "");
return args;
diff --git a/tests/tcg/s390x/Makefile.softmmu-target b/tests/tcg/s390x/Makefile.softmmu-target
index 8cd4667..a4425d3 100644
--- a/tests/tcg/s390x/Makefile.softmmu-target
+++ b/tests/tcg/s390x/Makefile.softmmu-target
@@ -28,6 +28,7 @@
mc \
per \
precise-smc-softmmu \
+ sckc \
ssm-early \
stosm-early \
stpq \
diff --git a/tests/tcg/s390x/sckc.S b/tests/tcg/s390x/sckc.S
new file mode 100644
index 0000000..ecd64a3
--- /dev/null
+++ b/tests/tcg/s390x/sckc.S
@@ -0,0 +1,63 @@
+/*
+ * Test clock comparator.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+ .org 0x130
+ext_old_psw:
+ .org 0x1b0
+ext_new_psw:
+ .quad 0x180000000, _ext /* 64-bit mode */
+ .org 0x1d0
+pgm_new_psw:
+ .quad 0x2000000000000,0 /* disabled wait */
+ .org 0x200 /* lowcore padding */
+
+ .globl _start
+_start:
+ lpswe start31_psw
+_start31:
+ stctg %c0,%c0,c0
+ oi c0+6,8 /* set clock-comparator subclass mask */
+ lctlg %c0,%c0,c0
+
+0:
+ brasl %r14,_f /* %r14's most significant bit is 1 */
+ jg 0b
+_f:
+ br %r14 /* it must not end up in ext_old_psw */
+
+_ext:
+ stg %r0,ext_saved_r0
+
+ lg %r0,ext_counter
+ aghi %r0,1
+ stg %r0,ext_counter
+
+ cgfi %r0,0x1000
+ jnz 0f
+ lpswe success_psw
+0:
+
+ stck clock
+ lg %r0,clock
+ agfi %r0,0x40000 /* 64us * 0x1000 =~ 0.25s */
+ stg %r0,clock
+ sckc clock
+
+ lg %r0,ext_saved_r0
+ lpswe ext_old_psw
+
+ .align 8
+start31_psw:
+ .quad 0x100000080000000,_start31 /* EX, 31-bit mode */
+success_psw:
+ .quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
+c0:
+ .skip 8
+clock:
+ .quad 0
+ext_counter:
+ .quad 0
+ext_saved_r0:
+ .skip 8
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index d5248ae..bd58029 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -110,9 +110,6 @@
if pam.found()
tests += {'test-authz-pam': [authz]}
endif
- if xts == 'private'
- tests += {'test-crypto-xts': [crypto, io]}
- endif
if host_os != 'windows'
tests += {
'test-image-locking': [testblock],
diff --git a/tests/unit/test-aio-multithread.c b/tests/unit/test-aio-multithread.c
index 0ead6bf..c24200a 100644
--- a/tests/unit/test-aio-multithread.c
+++ b/tests/unit/test-aio-multithread.c
@@ -443,7 +443,7 @@
int main(int argc, char **argv)
{
- init_clocks(NULL);
+ qemu_init_clocks(NULL);
g_test_init(&argc, &argv, NULL);
g_test_add_func("/aio/multi/lifecycle", test_lifecycle);
diff --git a/tests/unit/test-crypto-block.c b/tests/unit/test-crypto-block.c
index 3ac7f17..218e585 100644
--- a/tests/unit/test-crypto-block.c
+++ b/tests/unit/test-crypto-block.c
@@ -31,8 +31,7 @@
#endif
#if (defined(_WIN32) || defined RUSAGE_THREAD) && \
- (defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT) || \
- defined(CONFIG_GNUTLS_CRYPTO))
+ (defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT))
#define TEST_LUKS
#else
#undef TEST_LUKS
diff --git a/tests/unit/test-crypto-tlscredsx509.c b/tests/unit/test-crypto-tlscredsx509.c
index a5f2172..b1ad7d5 100644
--- a/tests/unit/test-crypto-tlscredsx509.c
+++ b/tests/unit/test-crypto-tlscredsx509.c
@@ -95,16 +95,16 @@
if (access(data->crt, R_OK) == 0) {
g_assert(link(data->crt,
CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0);
+ g_assert(link(KEYFILE,
+ CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0);
}
- g_assert(link(KEYFILE,
- CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0);
} else {
if (access(data->crt, R_OK) == 0) {
g_assert(link(data->crt,
CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0);
+ g_assert(link(KEYFILE,
+ CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
}
- g_assert(link(KEYFILE,
- CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
}
creds = test_tls_creds_create(
diff --git a/tests/unit/test-crypto-tlssession.c b/tests/unit/test-crypto-tlssession.c
index d0baf3b..0d06a68 100644
--- a/tests/unit/test-crypto-tlssession.c
+++ b/tests/unit/test-crypto-tlssession.c
@@ -36,7 +36,7 @@
#define KEYFILE WORKDIR "key-ctx.pem"
static ssize_t
-testWrite(const char *buf, size_t len, void *opaque, Error **errp)
+testWrite(const void *buf, size_t len, void *opaque, Error **errp)
{
int *fd = opaque;
int ret;
@@ -54,7 +54,7 @@
}
static ssize_t
-testRead(char *buf, size_t len, void *opaque, Error **errp)
+testRead(void *buf, size_t len, void *opaque, Error **errp)
{
int *fd = opaque;
int ret;
diff --git a/tests/unit/test-crypto-xts.c b/tests/unit/test-crypto-xts.c
deleted file mode 100644
index 7acbc95..0000000
--- a/tests/unit/test-crypto-xts.c
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * QEMU Crypto XTS cipher mode
- *
- * Copyright (c) 2015-2018 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- * This code is originally derived from public domain / WTFPL code in
- * LibTomCrypt crytographic library http://libtom.org. The XTS code
- * was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
- * to the LibTom Projects
- *
- */
-
-#include "qemu/osdep.h"
-#include "crypto/init.h"
-#include "crypto/xts.h"
-#include "crypto/aes.h"
-
-typedef struct {
- const char *path;
- int keylen;
- unsigned char key1[32];
- unsigned char key2[32];
- uint64_t seqnum;
- unsigned long PTLEN;
- unsigned char PTX[512], CTX[512];
-} QCryptoXTSTestData;
-
-static const QCryptoXTSTestData test_data[] = {
- /* #1 32 byte key, 32 byte PTX */
- {
- "/crypto/xts/t-1-key-32-ptx-32",
- 32,
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- 0,
- 32,
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- { 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec,
- 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92,
- 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85,
- 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e },
- },
-
- /* #2, 32 byte key, 32 byte PTX */
- {
- "/crypto/xts/t-2-key-32-ptx-32",
- 32,
- { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
- 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 },
- { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 },
- 0x3333333333LL,
- 32,
- { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
- 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
- 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
- 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 },
- { 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e,
- 0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b,
- 0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4,
- 0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 },
- },
-
- /* #5 from xts.7, 32 byte key, 32 byte PTX */
- {
- "/crypto/xts/t-5-key-32-ptx-32",
- 32,
- { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
- 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 },
- { 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
- 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 },
- 0x123456789aLL,
- 32,
- { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
- 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
- 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
- 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 },
- { 0xb0, 0x1f, 0x86, 0xf8, 0xed, 0xc1, 0x86, 0x37,
- 0x06, 0xfa, 0x8a, 0x42, 0x53, 0xe3, 0x4f, 0x28,
- 0xaf, 0x31, 0x9d, 0xe3, 0x83, 0x34, 0x87, 0x0f,
- 0x4d, 0xd1, 0xf9, 0x4c, 0xbe, 0x98, 0x32, 0xf1 },
- },
-
- /* #4, 32 byte key, 512 byte PTX */
- {
- "/crypto/xts/t-4-key-32-ptx-512",
- 32,
- { 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
- 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26 },
- { 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93,
- 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95 },
- 0,
- 512,
- {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
- 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
- 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
- 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
- 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
- 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
- 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
- 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
- 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
- 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
- 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
- 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
- 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
- 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
- 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
- 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
- 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
- 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
- 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
- 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
- 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
- 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
- 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
- },
- {
- 0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76,
- 0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2,
- 0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25,
- 0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c,
- 0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f,
- 0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00,
- 0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad,
- 0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12,
- 0x32, 0x80, 0x63, 0xfd, 0x2a, 0xab, 0x53, 0xe5,
- 0xea, 0x1e, 0x0a, 0x9f, 0x33, 0x25, 0x00, 0xa5,
- 0xdf, 0x94, 0x87, 0xd0, 0x7a, 0x5c, 0x92, 0xcc,
- 0x51, 0x2c, 0x88, 0x66, 0xc7, 0xe8, 0x60, 0xce,
- 0x93, 0xfd, 0xf1, 0x66, 0xa2, 0x49, 0x12, 0xb4,
- 0x22, 0x97, 0x61, 0x46, 0xae, 0x20, 0xce, 0x84,
- 0x6b, 0xb7, 0xdc, 0x9b, 0xa9, 0x4a, 0x76, 0x7a,
- 0xae, 0xf2, 0x0c, 0x0d, 0x61, 0xad, 0x02, 0x65,
- 0x5e, 0xa9, 0x2d, 0xc4, 0xc4, 0xe4, 0x1a, 0x89,
- 0x52, 0xc6, 0x51, 0xd3, 0x31, 0x74, 0xbe, 0x51,
- 0xa1, 0x0c, 0x42, 0x11, 0x10, 0xe6, 0xd8, 0x15,
- 0x88, 0xed, 0xe8, 0x21, 0x03, 0xa2, 0x52, 0xd8,
- 0xa7, 0x50, 0xe8, 0x76, 0x8d, 0xef, 0xff, 0xed,
- 0x91, 0x22, 0x81, 0x0a, 0xae, 0xb9, 0x9f, 0x91,
- 0x72, 0xaf, 0x82, 0xb6, 0x04, 0xdc, 0x4b, 0x8e,
- 0x51, 0xbc, 0xb0, 0x82, 0x35, 0xa6, 0xf4, 0x34,
- 0x13, 0x32, 0xe4, 0xca, 0x60, 0x48, 0x2a, 0x4b,
- 0xa1, 0xa0, 0x3b, 0x3e, 0x65, 0x00, 0x8f, 0xc5,
- 0xda, 0x76, 0xb7, 0x0b, 0xf1, 0x69, 0x0d, 0xb4,
- 0xea, 0xe2, 0x9c, 0x5f, 0x1b, 0xad, 0xd0, 0x3c,
- 0x5c, 0xcf, 0x2a, 0x55, 0xd7, 0x05, 0xdd, 0xcd,
- 0x86, 0xd4, 0x49, 0x51, 0x1c, 0xeb, 0x7e, 0xc3,
- 0x0b, 0xf1, 0x2b, 0x1f, 0xa3, 0x5b, 0x91, 0x3f,
- 0x9f, 0x74, 0x7a, 0x8a, 0xfd, 0x1b, 0x13, 0x0e,
- 0x94, 0xbf, 0xf9, 0x4e, 0xff, 0xd0, 0x1a, 0x91,
- 0x73, 0x5c, 0xa1, 0x72, 0x6a, 0xcd, 0x0b, 0x19,
- 0x7c, 0x4e, 0x5b, 0x03, 0x39, 0x36, 0x97, 0xe1,
- 0x26, 0x82, 0x6f, 0xb6, 0xbb, 0xde, 0x8e, 0xcc,
- 0x1e, 0x08, 0x29, 0x85, 0x16, 0xe2, 0xc9, 0xed,
- 0x03, 0xff, 0x3c, 0x1b, 0x78, 0x60, 0xf6, 0xde,
- 0x76, 0xd4, 0xce, 0xcd, 0x94, 0xc8, 0x11, 0x98,
- 0x55, 0xef, 0x52, 0x97, 0xca, 0x67, 0xe9, 0xf3,
- 0xe7, 0xff, 0x72, 0xb1, 0xe9, 0x97, 0x85, 0xca,
- 0x0a, 0x7e, 0x77, 0x20, 0xc5, 0xb3, 0x6d, 0xc6,
- 0xd7, 0x2c, 0xac, 0x95, 0x74, 0xc8, 0xcb, 0xbc,
- 0x2f, 0x80, 0x1e, 0x23, 0xe5, 0x6f, 0xd3, 0x44,
- 0xb0, 0x7f, 0x22, 0x15, 0x4b, 0xeb, 0xa0, 0xf0,
- 0x8c, 0xe8, 0x89, 0x1e, 0x64, 0x3e, 0xd9, 0x95,
- 0xc9, 0x4d, 0x9a, 0x69, 0xc9, 0xf1, 0xb5, 0xf4,
- 0x99, 0x02, 0x7a, 0x78, 0x57, 0x2a, 0xee, 0xbd,
- 0x74, 0xd2, 0x0c, 0xc3, 0x98, 0x81, 0xc2, 0x13,
- 0xee, 0x77, 0x0b, 0x10, 0x10, 0xe4, 0xbe, 0xa7,
- 0x18, 0x84, 0x69, 0x77, 0xae, 0x11, 0x9f, 0x7a,
- 0x02, 0x3a, 0xb5, 0x8c, 0xca, 0x0a, 0xd7, 0x52,
- 0xaf, 0xe6, 0x56, 0xbb, 0x3c, 0x17, 0x25, 0x6a,
- 0x9f, 0x6e, 0x9b, 0xf1, 0x9f, 0xdd, 0x5a, 0x38,
- 0xfc, 0x82, 0xbb, 0xe8, 0x72, 0xc5, 0x53, 0x9e,
- 0xdb, 0x60, 0x9e, 0xf4, 0xf7, 0x9c, 0x20, 0x3e,
- 0xbb, 0x14, 0x0f, 0x2e, 0x58, 0x3c, 0xb2, 0xad,
- 0x15, 0xb4, 0xaa, 0x5b, 0x65, 0x50, 0x16, 0xa8,
- 0x44, 0x92, 0x77, 0xdb, 0xd4, 0x77, 0xef, 0x2c,
- 0x8d, 0x6c, 0x01, 0x7d, 0xb7, 0x38, 0xb1, 0x8d,
- 0xeb, 0x4a, 0x42, 0x7d, 0x19, 0x23, 0xce, 0x3f,
- 0xf2, 0x62, 0x73, 0x57, 0x79, 0xa4, 0x18, 0xf2,
- 0x0a, 0x28, 0x2d, 0xf9, 0x20, 0x14, 0x7b, 0xea,
- 0xbe, 0x42, 0x1e, 0xe5, 0x31, 0x9d, 0x05, 0x68,
- }
- },
-
- /* #7, 32 byte key, 17 byte PTX */
- {
- "/crypto/xts/t-7-key-32-ptx-17",
- 32,
- { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
- 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 },
- { 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
- 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 },
- 0x123456789aLL,
- 17,
- { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
- { 0x6c, 0x16, 0x25, 0xdb, 0x46, 0x71, 0x52, 0x2d,
- 0x3d, 0x75, 0x99, 0x60, 0x1d, 0xe7, 0xca, 0x09, 0xed },
- },
-
- /* #15, 32 byte key, 25 byte PTX */
- {
- "/crypto/xts/t-15-key-32-ptx-25",
- 32,
- { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
- 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 },
- { 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
- 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 },
- 0x123456789aLL,
- 25,
- { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 },
- { 0x8f, 0x4d, 0xcb, 0xad, 0x55, 0x55, 0x8d, 0x7b,
- 0x4e, 0x01, 0xd9, 0x37, 0x9c, 0xd4, 0xea, 0x22,
- 0xed, 0xbf, 0x9d, 0xac, 0xe4, 0x5d, 0x6f, 0x6a, 0x73 },
- },
-
- /* #21, 32 byte key, 31 byte PTX */
- {
- "/crypto/xts/t-21-key-32-ptx-31",
- 32,
- { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
- 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 },
- { 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
- 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 },
- 0x123456789aLL,
- 31,
- { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e },
- { 0xd0, 0x5b, 0xc0, 0x90, 0xa8, 0xe0, 0x4f, 0x1b,
- 0x3d, 0x3e, 0xcd, 0xd5, 0xba, 0xec, 0x0f, 0xd4,
- 0xed, 0xbf, 0x9d, 0xac, 0xe4, 0x5d, 0x6f, 0x6a,
- 0x73, 0x06, 0xe6, 0x4b, 0xe5, 0xdd, 0x82 },
- },
-};
-
-#define STORE64L(x, y) \
- do { \
- (y)[7] = (unsigned char)(((x) >> 56) & 255); \
- (y)[6] = (unsigned char)(((x) >> 48) & 255); \
- (y)[5] = (unsigned char)(((x) >> 40) & 255); \
- (y)[4] = (unsigned char)(((x) >> 32) & 255); \
- (y)[3] = (unsigned char)(((x) >> 24) & 255); \
- (y)[2] = (unsigned char)(((x) >> 16) & 255); \
- (y)[1] = (unsigned char)(((x) >> 8) & 255); \
- (y)[0] = (unsigned char)((x) & 255); \
- } while (0)
-
-struct TestAES {
- AES_KEY enc;
- AES_KEY dec;
-};
-
-static void test_xts_aes_encrypt(const void *ctx,
- size_t length,
- uint8_t *dst,
- const uint8_t *src)
-{
- const struct TestAES *aesctx = ctx;
-
- AES_encrypt(src, dst, &aesctx->enc);
-}
-
-
-static void test_xts_aes_decrypt(const void *ctx,
- size_t length,
- uint8_t *dst,
- const uint8_t *src)
-{
- const struct TestAES *aesctx = ctx;
-
- AES_decrypt(src, dst, &aesctx->dec);
-}
-
-
-static void test_xts(const void *opaque)
-{
- const QCryptoXTSTestData *data = opaque;
- uint8_t out[512], Torg[16], T[16];
- uint64_t seq;
- struct TestAES aesdata;
- struct TestAES aestweak;
-
- AES_set_encrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.enc);
- AES_set_decrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.dec);
- AES_set_encrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.enc);
- AES_set_decrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.dec);
-
- seq = data->seqnum;
- STORE64L(seq, Torg);
- memset(Torg + 8, 0, 8);
-
- memcpy(T, Torg, sizeof(T));
- xts_encrypt(&aesdata, &aestweak,
- test_xts_aes_encrypt,
- test_xts_aes_decrypt,
- T, data->PTLEN, out, data->PTX);
-
- g_assert(memcmp(out, data->CTX, data->PTLEN) == 0);
-
- memcpy(T, Torg, sizeof(T));
- xts_decrypt(&aesdata, &aestweak,
- test_xts_aes_encrypt,
- test_xts_aes_decrypt,
- T, data->PTLEN, out, data->CTX);
-
- g_assert(memcmp(out, data->PTX, data->PTLEN) == 0);
-}
-
-
-static void test_xts_split(const void *opaque)
-{
- const QCryptoXTSTestData *data = opaque;
- uint8_t out[512], Torg[16], T[16];
- uint64_t seq;
- unsigned long len = data->PTLEN / 2;
- struct TestAES aesdata;
- struct TestAES aestweak;
-
- AES_set_encrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.enc);
- AES_set_decrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.dec);
- AES_set_encrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.enc);
- AES_set_decrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.dec);
-
- seq = data->seqnum;
- STORE64L(seq, Torg);
- memset(Torg + 8, 0, 8);
-
- memcpy(T, Torg, sizeof(T));
- xts_encrypt(&aesdata, &aestweak,
- test_xts_aes_encrypt,
- test_xts_aes_decrypt,
- T, len, out, data->PTX);
- xts_encrypt(&aesdata, &aestweak,
- test_xts_aes_encrypt,
- test_xts_aes_decrypt,
- T, len, &out[len], &data->PTX[len]);
-
- g_assert(memcmp(out, data->CTX, data->PTLEN) == 0);
-
- memcpy(T, Torg, sizeof(T));
- xts_decrypt(&aesdata, &aestweak,
- test_xts_aes_encrypt,
- test_xts_aes_decrypt,
- T, len, out, data->CTX);
- xts_decrypt(&aesdata, &aestweak,
- test_xts_aes_encrypt,
- test_xts_aes_decrypt,
- T, len, &out[len], &data->CTX[len]);
-
- g_assert(memcmp(out, data->PTX, data->PTLEN) == 0);
-}
-
-
-static void test_xts_unaligned(const void *opaque)
-{
-#define BAD_ALIGN 3
- const QCryptoXTSTestData *data = opaque;
- uint8_t in[512 + BAD_ALIGN], out[512 + BAD_ALIGN];
- uint8_t Torg[16], T[16 + BAD_ALIGN];
- uint64_t seq;
- struct TestAES aesdata;
- struct TestAES aestweak;
-
- AES_set_encrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.enc);
- AES_set_decrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.dec);
- AES_set_encrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.enc);
- AES_set_decrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.dec);
-
- seq = data->seqnum;
- STORE64L(seq, Torg);
- memset(Torg + 8, 0, 8);
-
- /* IV not aligned */
- memcpy(T + BAD_ALIGN, Torg, 16);
- memcpy(in, data->PTX, data->PTLEN);
- xts_encrypt(&aesdata, &aestweak,
- test_xts_aes_encrypt,
- test_xts_aes_decrypt,
- T + BAD_ALIGN, data->PTLEN, out, in);
-
- g_assert(memcmp(out, data->CTX, data->PTLEN) == 0);
-
- /* plain text not aligned */
- memcpy(T, Torg, 16);
- memcpy(in + BAD_ALIGN, data->PTX, data->PTLEN);
- xts_encrypt(&aesdata, &aestweak,
- test_xts_aes_encrypt,
- test_xts_aes_decrypt,
- T, data->PTLEN, out, in + BAD_ALIGN);
-
- g_assert(memcmp(out, data->CTX, data->PTLEN) == 0);
-
- /* cipher text not aligned */
- memcpy(T, Torg, 16);
- memcpy(in, data->PTX, data->PTLEN);
- xts_encrypt(&aesdata, &aestweak,
- test_xts_aes_encrypt,
- test_xts_aes_decrypt,
- T, data->PTLEN, out + BAD_ALIGN, in);
-
- g_assert(memcmp(out + BAD_ALIGN, data->CTX, data->PTLEN) == 0);
-
-
- /* IV not aligned */
- memcpy(T + BAD_ALIGN, Torg, 16);
- memcpy(in, data->CTX, data->PTLEN);
- xts_decrypt(&aesdata, &aestweak,
- test_xts_aes_encrypt,
- test_xts_aes_decrypt,
- T + BAD_ALIGN, data->PTLEN, out, in);
-
- g_assert(memcmp(out, data->PTX, data->PTLEN) == 0);
-
- /* cipher text not aligned */
- memcpy(T, Torg, 16);
- memcpy(in + BAD_ALIGN, data->CTX, data->PTLEN);
- xts_decrypt(&aesdata, &aestweak,
- test_xts_aes_encrypt,
- test_xts_aes_decrypt,
- T, data->PTLEN, out, in + BAD_ALIGN);
-
- g_assert(memcmp(out, data->PTX, data->PTLEN) == 0);
-
- /* plain text not aligned */
- memcpy(T, Torg, 16);
- memcpy(in, data->CTX, data->PTLEN);
- xts_decrypt(&aesdata, &aestweak,
- test_xts_aes_encrypt,
- test_xts_aes_decrypt,
- T, data->PTLEN, out + BAD_ALIGN, in);
-
- g_assert(memcmp(out + BAD_ALIGN, data->PTX, data->PTLEN) == 0);
-}
-
-
-int main(int argc, char **argv)
-{
- size_t i;
-
- g_test_init(&argc, &argv, NULL);
-
- g_assert(qcrypto_init(NULL) == 0);
-
- for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
- gchar *path = g_strdup_printf("%s/basic", test_data[i].path);
- g_test_add_data_func(path, &test_data[i], test_xts);
- g_free(path);
-
- /* skip the cases where the length is smaller than 2*blocklen
- * or the length is not a multiple of 32
- */
- if ((test_data[i].PTLEN >= 32) && !(test_data[i].PTLEN % 32)) {
- path = g_strdup_printf("%s/split", test_data[i].path);
- g_test_add_data_func(path, &test_data[i], test_xts_split);
- g_free(path);
- }
-
- path = g_strdup_printf("%s/unaligned", test_data[i].path);
- g_test_add_data_func(path, &test_data[i], test_xts_unaligned);
- g_free(path);
- }
-
- return g_test_run();
-}
diff --git a/ui/vnc.c b/ui/vnc.c
index 0094ec6..50016ff 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -578,7 +578,6 @@
bool vnc_display_reload_certs(const char *id, Error **errp)
{
VncDisplay *vd = vnc_display_find(id);
- QCryptoTLSCredsClass *creds = NULL;
if (!vd) {
error_setg(errp, "Can not find vnc display");
@@ -590,13 +589,7 @@
return false;
}
- creds = QCRYPTO_TLS_CREDS_GET_CLASS(OBJECT(vd->tlscreds));
- if (creds->reload == NULL) {
- error_setg(errp, "%s doesn't support to reload TLS credential",
- object_get_typename(OBJECT(vd->tlscreds)));
- return false;
- }
- if (!creds->reload(vd->tlscreds, errp)) {
+ if (!qcrypto_tls_creds_reload(vd->tlscreds, errp)) {
return false;
}
diff --git a/util/hexdump.c b/util/hexdump.c
index f29ffce..7cfc547 100644
--- a/util/hexdump.c
+++ b/util/hexdump.c
@@ -22,6 +22,19 @@
return (x < 10 ? '0' : 'a' - 10) + x;
}
+static size_t hexdump_line_length(size_t buf_len, size_t unit_len,
+ size_t block_len)
+{
+ size_t est = buf_len * 2;
+ if (unit_len) {
+ est += buf_len / unit_len;
+ }
+ if (block_len) {
+ est += buf_len / block_len;
+ }
+ return est;
+}
+
GString *qemu_hexdump_line(GString *str, const void *vbuf, size_t len,
size_t unit_len, size_t block_len)
{
@@ -30,14 +43,8 @@
if (str == NULL) {
/* Estimate the length of the output to avoid reallocs. */
- size_t est = len * 2;
- if (unit_len) {
- est += len / unit_len;
- }
- if (block_len) {
- est += len / block_len;
- }
- str = g_string_sized_new(est + 1);
+ str = g_string_sized_new(hexdump_line_length(len, unit_len, block_len)
+ + 1);
}
for (u = 0, b = 0; len; u++, b++, len--, buf++) {
@@ -76,13 +83,16 @@
}
#define QEMU_HEXDUMP_LINE_BYTES 16
-#define QEMU_HEXDUMP_LINE_WIDTH \
- (QEMU_HEXDUMP_LINE_BYTES * 2 + QEMU_HEXDUMP_LINE_BYTES / 4)
+#define QEMU_HEXDUMP_UNIT 1
+#define QEMU_HEXDUMP_BLOCK 4
void qemu_hexdump(FILE *fp, const char *prefix,
const void *bufptr, size_t size)
{
- g_autoptr(GString) str = g_string_sized_new(QEMU_HEXDUMP_LINE_WIDTH + 1);
+ int width = hexdump_line_length(QEMU_HEXDUMP_LINE_BYTES,
+ QEMU_HEXDUMP_UNIT,
+ QEMU_HEXDUMP_BLOCK);
+ g_autoptr(GString) str = g_string_sized_new(width + 1);
char ascii[QEMU_HEXDUMP_LINE_BYTES + 1];
size_t b, len;
@@ -90,11 +100,11 @@
len = MIN(size - b, QEMU_HEXDUMP_LINE_BYTES);
g_string_truncate(str, 0);
- qemu_hexdump_line(str, bufptr + b, len, 1, 4);
+ qemu_hexdump_line(str, bufptr + b, len,
+ QEMU_HEXDUMP_UNIT, QEMU_HEXDUMP_BLOCK);
asciidump_line(ascii, bufptr + b, len);
- fprintf(fp, "%s: %04zx: %-*s %s\n",
- prefix, b, QEMU_HEXDUMP_LINE_WIDTH, str->str, ascii);
+ fprintf(fp, "%s: %04zx: %-*s %s\n", prefix, b, width, str->str, ascii);
}
}
diff --git a/util/main-loop.c b/util/main-loop.c
index b8ddda8..b462598 100644
--- a/util/main-loop.c
+++ b/util/main-loop.c
@@ -162,7 +162,7 @@
int ret;
GSource *src;
- init_clocks(qemu_timer_notify_cb);
+ qemu_init_clocks(qemu_timer_notify_cb);
ret = qemu_signal_init(errp);
if (ret) {
diff --git a/util/qemu-thread-common.h b/util/qemu-thread-common.h
index 2af6b12..0933184 100644
--- a/util/qemu-thread-common.h
+++ b/util/qemu-thread-common.h
@@ -14,6 +14,7 @@
#define QEMU_THREAD_COMMON_H
#include "qemu/thread.h"
+#include "qemu/main-loop.h"
#include "trace.h"
static inline void qemu_mutex_post_init(QemuMutex *mutex)
@@ -39,6 +40,9 @@
mutex->line = line;
#endif
trace_qemu_mutex_locked(mutex, file, line);
+ if (mutex_is_bql(mutex)) {
+ bql_update_status(true);
+ }
}
static inline void qemu_mutex_pre_unlock(QemuMutex *mutex,
@@ -49,6 +53,9 @@
mutex->line = 0;
#endif
trace_qemu_mutex_unlock(mutex, file, line);
+ if (mutex_is_bql(mutex)) {
+ bql_update_status(false);
+ }
}
#endif
diff --git a/util/qemu-timer.c b/util/qemu-timer.c
index 56f11b6..2a6be4c 100644
--- a/util/qemu-timer.c
+++ b/util/qemu-timer.c
@@ -637,7 +637,7 @@
return cpus_set_virtual_clock(time);
}
-void init_clocks(QEMUTimerListNotifyCB *notify_cb)
+void qemu_init_clocks(QEMUTimerListNotifyCB *notify_cb)
{
QEMUClockType type;
for (type = 0; type < QEMU_CLOCK_MAX; type++) {