On Mon, Sep 07, 2026 at 08:55:20 +0000, Abhisek Panda wrote:
> Libvirt by default attempt to use the TLS-PSK-enabled VM migration,
> if the both source and destination support the tls-creds-psk object.
> The source host adds the pre-shared key in the migration cookie if the
> source supports the tls-creds-psk object. Upon parsing the migration
> cookie, the destination host checks for the same capability and informs
> the source host whether to use TLS X.509 or TLS PSK during VM migration
> via the migration cookie.
> 
> For a migration session, Libvirt generates a random key of the
> specified length, and then stores the content, "qemu:<random key>", at
> <tls_psk_state_dir>/$ID-$VMNAME/keys.psk on the source host. This is
> because QEMU's tls-creds-psk object does not accept a raw key string
> as a parameter, it only accepts a dir argument pointing to a directory
> from which it can read the key file. Subsequently, it sends the key to
> destination by embedding it within the migration cookie. The
> destination's Libvirt extracts the key from the migration cookie.
> Upon migration completion or any failure, both source and destination
> Libvirt must delete the directory containing the session's keys.psk.
> 
> Signed-off-by: Abhisek Panda <[email protected]>
> ---
>  src/qemu/qemu_capabilities.c                  |  2 +
>  src/qemu/qemu_capabilities.h                  |  1 +
>  src/qemu/qemu_conf.c                          |  4 +
>  src/qemu/qemu_conf.h                          |  1 +
>  src/qemu/qemu_domain.c                        |  1 +
>  src/qemu/qemu_domain.h                        |  1 +
>  src/qemu/qemu_driver.c                        |  6 ++
>  src/qemu/qemu_migration.c                     | 98 +++++++++++++++++++
>  src/qemu/qemu_migration.h                     |  3 +
>  src/qemu/qemu_migration_cookie.c              | 79 ++++++++++++++-
>  src/qemu/qemu_migration_cookie.h              |  5 +
>  src/qemu/qemu_process.c                       |  3 +
>  .../caps_10.0.0_aarch64.xml                   |  1 +
>  .../caps_10.0.0_ppc64.xml                     |  1 +
>  .../caps_10.0.0_s390x.xml                     |  1 +
>  .../caps_10.0.0_x86_64+amdsev.xml             |  1 +
>  .../caps_10.0.0_x86_64.xml                    |  1 +
>  .../caps_10.1.0_s390x.xml                     |  1 +
>  .../caps_10.1.0_x86_64+inteltdx.xml           |  1 +
>  .../caps_10.1.0_x86_64.xml                    |  1 +
>  .../caps_10.2.0_aarch64.xml                   |  1 +
>  .../caps_10.2.0_x86_64+mshv.xml               |  1 +
>  .../caps_10.2.0_x86_64.xml                    |  1 +
>  .../caps_11.0.0_aarch64.xml                   |  1 +
>  .../caps_11.0.0_s390x.xml                     |  1 +
>  .../caps_11.0.0_x86_64+sgx.xml                |  1 +
>  .../caps_11.0.0_x86_64.xml                    |  1 +
>  .../caps_11.1.0_aarch64.xml                   |  1 +
>  .../caps_11.1.0_s390x.xml                     |  1 +
>  .../caps_11.1.0_x86_64.xml                    |  1 +
>  tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml |  1 +
>  .../caps_7.2.0_x86_64+hvf.xml                 |  1 +
>  .../caps_7.2.0_x86_64.xml                     |  1 +
>  .../caps_8.0.0_x86_64.xml                     |  1 +
>  .../qemucapabilitiesdata/caps_8.1.0_s390x.xml |  1 +
>  .../caps_8.1.0_x86_64.xml                     |  1 +
>  .../caps_8.2.0_aarch64.xml                    |  1 +
>  .../caps_8.2.0_armv7l.xml                     |  1 +
>  .../caps_8.2.0_loongarch64.xml                |  1 +
>  .../qemucapabilitiesdata/caps_8.2.0_s390x.xml |  1 +
>  .../caps_8.2.0_x86_64.xml                     |  1 +
>  .../qemucapabilitiesdata/caps_9.0.0_sparc.xml |  1 +
>  .../caps_9.0.0_x86_64.xml                     |  1 +
>  .../caps_9.1.0_riscv64.xml                    |  1 +
>  .../qemucapabilitiesdata/caps_9.1.0_s390x.xml |  1 +
>  .../caps_9.1.0_x86_64.xml                     |  1 +
>  .../caps_9.2.0_aarch64+hvf.xml                |  1 +
>  .../qemucapabilitiesdata/caps_9.2.0_s390x.xml |  1 +
>  .../caps_9.2.0_x86_64+amdsev.xml              |  1 +
>  .../caps_9.2.0_x86_64.xml                     |  1 +
>  tests/qemumigrationcookiexmltest.c            | 12 ++-
>  51 files changed, 249 insertions(+), 5 deletions(-)
> 
> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
> index bc2b0412dc..3db4710dee 100644
> --- a/src/qemu/qemu_capabilities.c
> +++ b/src/qemu/qemu_capabilities.c
> @@ -776,6 +776,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
>                "arm-smmuv3.cmdqv", /* QEMU_CAPS_ARM_SMMUV3_CMDQV */
>                "iothread.poll-weight", /* QEMU_CAPS_IOTHREAD_POLL_WEIGHT */
>                "win-dmp.guest-aware", /* QEMU_CAPS_WIN_DMP_GUEST_AWARE */
> +              "tls-creds-psk", /* QEMU_CAPS_OBJECT_TLS_CREDS_PSK */
>      );
>  
>  
> @@ -1490,6 +1491,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] 
> = {
>      { "uefi-vars-sysbus", QEMU_CAPS_DEVICE_UEFI_VARS },
>      { "monitor-qmp", QEMU_CAPS_OBJECT_MONITOR_QMP },
>      { "arm-smmuv3", QEMU_CAPS_DEVICE_ARM_SMMUV3 },
> +    { "tls-creds-psk", QEMU_CAPS_OBJECT_TLS_CREDS_PSK },

Any reason why the capability is introduced? I didn't see it mentioned
in our previous conversation.

In case if the support can be compiled out it's okay to add a
capability, but new capabilities need to go into a separate commit
because they make existing commits really massive and hard to backport.

So if the capability is needed you'll have to split the hunks that add
the capability and the detection into a separate commit which will need
to preceed this one which makes use of it.

> diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
> index 28303fd8f0..1e432cdc41 100644
> --- a/src/qemu/qemu_capabilities.h
> +++ b/src/qemu/qemu_capabilities.h
> @@ -750,6 +750,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for 
> syntax-check */
>      QEMU_CAPS_ARM_SMMUV3_CMDQV, /* arm-smmuv3.cmdqv */
>      QEMU_CAPS_IOTHREAD_POLL_WEIGHT, /* -object iothread.poll-weight */
>      QEMU_CAPS_WIN_DMP_GUEST_AWARE, /* 'win-dmp' is offered only to a guest 
> that can use it */
> +    QEMU_CAPS_OBJECT_TLS_CREDS_PSK, /* -object tls-creds-psk */
>  
>      QEMU_CAPS_LAST /* this must always be the last item */
>  } virQEMUCapsFlags;
> diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
> index cca7776b80..f5c5437c89 100644
> --- a/src/qemu/qemu_conf.c
> +++ b/src/qemu/qemu_conf.c
> @@ -168,6 +168,7 @@ virQEMUDriverConfig *virQEMUDriverConfigNew(bool 
> privileged,
>          cfg->cacheDir = g_strdup_printf("%s/cache/qemu", root);
>          cfg->libDir = g_strdup_printf("%s/lib/qemu", root);
>          cfg->swtpmStorageDir = g_strdup_printf("%s/lib/swtpm", root);
> +        cfg->tlsPSKStateDir = g_strdup_printf("%s/run/psk", root);
>  
>          cfg->saveDir = g_strdup_printf("%s/save", cfg->libDir);
>          cfg->snapshotDir = g_strdup_printf("%s/snapshot", cfg->libDir);
> @@ -187,6 +188,7 @@ virQEMUDriverConfig *virQEMUDriverConfigNew(bool 
> privileged,
>          cfg->stateDir = g_strdup_printf("%s/libvirt/qemu", RUNSTATEDIR);
>          cfg->swtpmStateDir = g_strdup_printf("%s/swtpm", cfg->stateDir);
>          cfg->channelTargetDir = g_strdup_printf("%s/channel", cfg->stateDir);
> +        cfg->tlsPSKStateDir = g_strdup_printf("%s/psk", cfg->stateDir);
>  
>          cfg->cacheDir = g_strdup_printf("%s/cache/libvirt/qemu", 
> LOCALSTATEDIR);
>  
> @@ -214,6 +216,7 @@ virQEMUDriverConfig *virQEMUDriverConfigNew(bool 
> privileged,
>          cfg->stateDir = g_strdup_printf("%s/qemu/run", rundir);
>          cfg->swtpmStateDir = g_strdup_printf("%s/swtpm", cfg->stateDir);
>          cfg->channelTargetDir = g_strdup_printf("%s/channel", cfg->stateDir);
> +        cfg->tlsPSKStateDir = g_strdup_printf("%s/psk", cfg->stateDir);
>  
>          cfg->configBaseDir = virGetUserConfigDirectory();
>  
> @@ -375,6 +378,7 @@ static void virQEMUDriverConfigDispose(void *obj)
>      g_free(cfg->dbusStateDir);
>      g_free(cfg->rdpStateDir);
>      g_free(cfg->vncStateDir);
> +    g_free(cfg->tlsPSKStateDir);
>  
>      g_free(cfg->libDir);
>      g_free(cfg->cacheDir);
> diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
> index b700829342..2db3440514 100644
> --- a/src/qemu/qemu_conf.h
> +++ b/src/qemu/qemu_conf.h
> @@ -113,6 +113,7 @@ struct _virQEMUDriverConfig {
>      char *dbusStateDir;
>      char *rdpStateDir;
>      char *vncStateDir;
> +    char *tlsPSKStateDir;
>      /* These two directories are ones QEMU processes use (so must match
>       * the QEMU user/group */
>      char *libDir;
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index a4e5f92840..f4d470553d 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -1990,6 +1990,7 @@ qemuDomainObjPrivateFree(void *data)
>      virObjectUnref(priv->monConfig);
>      g_free(priv->lockState);
>      g_free(priv->origname);
> +    g_free(priv->migTLSPSK);
>  
>      virChrdevFree(priv->devs);
>  
> diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
> index 23e99dc68c..053140f7ec 100644
> --- a/src/qemu/qemu_domain.h
> +++ b/src/qemu/qemu_domain.h
> @@ -139,6 +139,7 @@ struct _qemuDomainObjPrivate {
>      char *origname;
>      int nbdPort; /* Port used for migration with NBD */
>      unsigned short migrationPort;
> +    char *migTLSPSK; /* Hex-encoded pre-shared key for TLS-PSK-enabled VM 
> migration session */
>      unsigned short backupNBDPort;
>      int preMigrationState;
>      unsigned long long preMigrationMemlock; /* Original RLIMIT_MEMLOCK in 
> case
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 8498568623..5548d6f7bd 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -664,6 +664,12 @@ qemuStateInitialize(bool privileged,
>                               cfg->vncStateDir);
>          goto error;
>      }
> +    if (virDirCreate(cfg->tlsPSKStateDir, 0700, cfg->user, cfg->group,
> +                     VIR_DIR_CREATE_ALLOW_EXIST) < 0) {
> +        virReportSystemError(errno, _("Failed to create TLS PSK state dir 
> %1$s"),
> +                             cfg->tlsPSKStateDir);
> +        goto error;

So, recently we've had a few reports about "security" bugs regarding
directories owned by "qemu:qemu" which are filled by virtqemud with some
objects.

That makes me think two things:
 1) does this need to be in a separate directory? We really should have
 a per-VM directory for all the per-instance helper files which will
 live in /run so that it's removed on reboot

 2) the directory shouldn't be owned by qemu:qemu, but rather root:root
 for the system instance and have 0711 mode so that qemu can open the
 files but not create them.

I know this is a more general thing, as our directory in /run/ is
nonsensically split to e.g. /run/libvirt/qemu/channel/$VMID rather than
have /run/libvirt/qemu/(possibly some subdir such as 'instance'/$ID'
which will include all the files.

For this series, what definitely applies is the ownership and
permissions point.



> +    }
>  
>      qemu_driver->inhibitor = virInhibitorNew(
>          VIR_INHIBITOR_WHAT_SHUTDOWN,
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> index 4a43ab83b0..b9971286fd 100644
> --- a/src/qemu/qemu_migration.c
> +++ b/src/qemu/qemu_migration.c
> @@ -59,6 +59,7 @@
>  #include "virprocess.h"
>  #include "virdomainsnapshotobjlist.h"
>  #include "virutil.h"
> +#include "virsecureerase.h"
>  
>  #define VIR_FROM_THIS VIR_FROM_QEMU
>  
> @@ -1503,6 +1504,89 @@ qemuMigrationSrcIsAllowedHostdev(const virDomainDef 
> *def)
>  }
>  
>  
> +void
> +qemuMigrationDeletePSKDir(virQEMUDriver *driver, virDomainObj *vm)
> +{
> +    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
> +    qemuDomainObjPrivate *priv = vm->privateData;
> +    g_autofree char *dir_path = NULL;
> +    g_autofree char *shortName = NULL;
> +
> +    if (priv->migTLSPSK) {
> +        virSecureEraseString(priv->migTLSPSK);
> +        g_clear_pointer(&priv->migTLSPSK, g_free);
> +    }
> +
> +    if (!(shortName = virDomainDefGetShortName(vm->def)))

This failure ...

> +        return;
> +
> +    dir_path = g_strdup_printf("%s/%s", cfg->tlsPSKStateDir, shortName);
> +
> +    if (virFileIsDir(dir_path) &&
> +        virFileDeleteTree(dir_path) < 0)
> +        VIR_WARN("Failed to delete the directory %s containing the 
> pre-shared keys for migration of domain %s",
> +                 dir_path, vm->def->name);

... has the same implication.


> +}
> +
> +
> +static int
> +qemuPersistTLSPSKHelper(int pskFD,
> +                        const char *pskPath,
> +                        const void *opaque)
> +{
> +    const char *key = opaque;
> +
> +    if (safewrite(pskFD, "qemu:", 5) < 0 ||
> +        safewrite(pskFD, key, strlen(key)) < 0) {
> +        virReportSystemError(errno,
> +                             _("Unable to write the pre-shared key to file 
> '%1$s'"),
> +                             pskPath);
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +
> +static int
> +qemuMigrationPersistPSK(virQEMUDriver *driver, virDomainObj *vm, const char 
> *tlsPSK)
> +{
> +    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
> +    g_autofree char *dir_path = NULL;
> +    g_autofree char *key_path = NULL;
> +    g_autofree char *shortName = NULL;
> +
> +    if (!(shortName = virDomainDefGetShortName(vm->def))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Could not get the shortened domain name for 
> domain: %1$s"),
> +                       vm->def->name);
> +        return -1;
> +    }
> +
> +    dir_path = g_strdup_printf("%s/%s", cfg->tlsPSKStateDir, shortName);
> +    key_path = g_strdup_printf("%s/keys.psk", dir_path);
> +
> +    if (virDirCreate(dir_path, 0700, cfg->user, cfg->group,
> +                     VIR_DIR_CREATE_ALLOW_EXIST) < 0) {

Same here, the directory IMO doesn't need to be owned by qemu because
qemu will never attempt to create a file here. It needs to be accessible
by 'other' though.


> +        virReportSystemError(errno,
> +                             _("Could not create the directory %1$s for 
> storing PSKs"),
> +                             dir_path);
> +        goto error;
> +    }
> +
> +    if (virFileRewrite(key_path, S_IRUSR, cfg->user,
> +                       cfg->group, qemuPersistTLSPSKHelper,
> +                       tlsPSK) < 0)
> +        goto error;
> +
> +    return 0;
> +
> + error:
> +    qemuMigrationDeletePSKDir(driver, vm);
> +    return -1;
> +}
> +
> +
>  static int
>  qemuDomainGetMigrationBlockers(virDomainObj *vm,
>                                 int asyncJob,
> @@ -2722,6 +2806,9 @@ qemuMigrationSrcBeginXML(virDomainObj *vm,
>      if (priv->origCPU)
>          cookieFlags |= QEMU_MIGRATION_COOKIE_CPU;
>  
> +    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_TLS_CREDS_PSK))
> +        cookieFlags |= QEMU_MIGRATION_COOKIE_TLS_PSK;
> +
>      if (!(flags & VIR_MIGRATE_OFFLINE))
>          cookieFlags |= QEMU_MIGRATION_COOKIE_CAPS;
>  
> @@ -2738,6 +2825,9 @@ qemuMigrationSrcBeginXML(virDomainObj *vm,
>                                    cookieFlags) < 0)
>          return NULL;
>  
> +    if (mig->tlsPSK && qemuMigrationPersistPSK(driver, vm, mig->tlsPSK) < 0)
> +        return NULL;
> +
>      if (xmlin) {
>          g_autoptr(virDomainDef) def = NULL;
>  
> @@ -4232,6 +4322,8 @@ qemuMigrationSrcConfirmPhase(virQEMUDriver *driver,
>          privJob->stats.mig.downtime = privMigJob->stats.mig.downtime;
>      }
>  
> +    qemuMigrationDeletePSKDir(driver, vm);
> +
>      if (flags & VIR_MIGRATE_OFFLINE)
>          return 0;
>  
> @@ -5274,6 +5366,7 @@ qemuMigrationSrcRun(virQEMUDriver *driver,
>  
>   error:
>      virErrorPreserveLast(&orig_err);
> +    qemuMigrationDeletePSKDir(driver, vm);
>  
>      if (qemuDomainObjIsActive(vm)) {
>          int reason;
> @@ -7029,6 +7122,8 @@ qemuMigrationDstFinishActive(virQEMUDriver *driver,
>                                    QEMU_MIGRATION_COOKIE_STATS) < 0)
>          VIR_WARN("Unable to encode migration cookie");
>  
> +    qemuMigrationDeletePSKDir(driver, vm);
> +
>      qemuMigrationDstComplete(driver, vm, inPostCopy,
>                               VIR_ASYNC_JOB_MIGRATION_IN, vm->job);
>  
> @@ -7039,6 +7134,8 @@ qemuMigrationDstFinishActive(virQEMUDriver *driver,
>       * overwrites it. */
>      virErrorPreserveLast(&orig_err);
>  
> +    qemuMigrationDeletePSKDir(driver, vm);
> +
>      if (qemuDomainObjIsActive(vm)) {
>          if (doKill) {
>              qemuProcessStop(vm, VIR_DOMAIN_SHUTOFF_FAILED,
> @@ -7197,6 +7294,7 @@ qemuMigrationProcessUnattended(virQEMUDriver *driver,
>      else
>          qemuMigrationSrcComplete(driver, vm, job);
>  
> +    qemuMigrationDeletePSKDir(driver, vm);
>      qemuMigrationJobFinish(vm);
>  
>      if (!virDomainObjIsActive(vm))
> diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
> index 7e9410e1f7..ce15f8024b 100644
> --- a/src/qemu/qemu_migration.h
> +++ b/src/qemu/qemu_migration.h
> @@ -279,3 +279,6 @@ int
>  qemuMigrationAnyRefreshStatus(virDomainObj *vm,
>                                virDomainAsyncJob asyncJob,
>                                virDomainJobStatus *status);
> +
> +void
> +qemuMigrationDeletePSKDir(virQEMUDriver *driver, virDomainObj *vm);
> diff --git a/src/qemu/qemu_migration_cookie.c 
> b/src/qemu/qemu_migration_cookie.c
> index 7311a8294b..0cf1ab9590 100644
> --- a/src/qemu/qemu_migration_cookie.c
> +++ b/src/qemu/qemu_migration_cookie.c
> @@ -20,6 +20,7 @@
>  
>  #include <gnutls/gnutls.h>
>  #include <gnutls/x509.h>
> +#include <inttypes.h>
>  
>  #include "locking/domain_lock.h"
>  #include "virerror.h"
> @@ -27,6 +28,7 @@
>  #include "virnetdevopenvswitch.h"
>  #include "virstring.h"
>  #include "virutil.h"
> +#include "virsecureerase.h"
>  
>  #include "qemu_domain.h"
>  #include "qemu_migration_cookie.h"
> @@ -52,6 +54,7 @@ VIR_ENUM_IMPL(qemuMigrationCookieFlag,
>                "allowReboot",
>                "capabilities",
>                "block-dirty-bitmaps",
> +              "psk",
>  );
>  
>  
> @@ -165,6 +168,9 @@ qemuMigrationCookieFree(qemuMigrationCookie *mig)
>      g_free(mig->name);
>      g_free(mig->lockState);
>      g_free(mig->lockDriver);
> +    if (mig->tlsPSK)
> +        virSecureEraseString(mig->tlsPSK);
> +    g_free(mig->tlsPSK);
>      g_clear_pointer(&mig->jobData, virDomainJobDataFree);
>      virCPUDefFree(mig->cpu);
>      qemuMigrationCookieCapsFree(mig->caps);
> @@ -575,6 +581,51 @@ qemuMigrationCookieAddCaps(qemuMigrationCookie *mig,
>  }
>  
>  
> +static int
> +qemuMigrationCookieAddTLSPSK(qemuMigrationCookie *mig,
> +                             virQEMUDriver *driver,
> +                             virDomainObj *vm)
> +{
> +    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
> +    qemuDomainObjPrivate *priv = vm->privateData;
> +    gnutls_datum_t psk_key = {NULL, 0};
> +    g_autofree char *key = NULL;
> +    size_t key_len;
> +    int ret;
> +
> +    /* Generate the pre-shared key exactly once for a migration session*/
> +    if (priv->migTLSPSK) {
> +        mig->tlsPSK = g_strdup(priv->migTLSPSK);
> +        mig->flags |= QEMU_MIGRATION_COOKIE_TLS_PSK;
> +        return 0;
> +    }
> +
> +    ret = gnutls_key_generate(&psk_key, cfg->migrateTLSPSKLength);
> +    if (ret < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("Generation of a pre-shared key failed"));
> +        return -1;
> +    }
> +    key_len = (psk_key.size*2) + 1;
> +    key = g_new0(char, key_len);
> +
> +    ret = gnutls_hex_encode(&psk_key, key, &key_len);
> +    if (ret < 0) {
> +        gnutls_free(psk_key.data);
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("Hex encoding of a PSK key failed"));
> +        return -1;
> +    }
> +
> +    priv->migTLSPSK = g_strdup(key);
> +    mig->tlsPSK = g_steal_pointer(&key);
> +    mig->flags |= QEMU_MIGRATION_COOKIE_TLS_PSK;
> +
> +    gnutls_free(psk_key.data);
> +    return 0;
> +}
> +
> +
>  static void
>  qemuMigrationCookieGraphicsXMLFormat(virBuffer *buf,
>                                       qemuMigrationCookieGraphics *grap)
> @@ -890,6 +941,9 @@ qemuMigrationCookieXMLFormat(virQEMUDriver *driver,
>      if (mig->flags & QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS)
>          qemuMigrationCookieBlockDirtyBitmapsFormat(buf, 
> mig->blockDirtyBitmaps);
>  
> +    if ((mig->flags & QEMU_MIGRATION_COOKIE_TLS_PSK) && mig->tlsPSK)
> +        virBufferAsprintf(buf, "<migration-key>%s</migration-key>\n", 
> mig->tlsPSK);
> +
>      virBufferAdjustIndent(buf, -2);
>      virBufferAddLit(buf, "</qemu-migration>\n");
>      return 0;
> @@ -1396,6 +1450,12 @@ qemuMigrationCookieXMLParse(qemuMigrationCookie *mig,
>          qemuMigrationCookieBlockDirtyBitmapsParse(ctxt, mig) < 0)
>          return -1;
>  
> +    if (flags & QEMU_MIGRATION_COOKIE_TLS_PSK) {
> +        mig->tlsPSK = virXPathString("string(./migration-key[1])", ctxt);
> +        if (mig->tlsPSK)
> +            mig->flags |= QEMU_MIGRATION_COOKIE_TLS_PSK;
> +    }
> +
>      return 0;
>  }
>  
> @@ -1471,14 +1531,29 @@ qemuMigrationCookieFormat(qemuMigrationCookie *mig,
>          qemuMigrationCookieAddCaps(mig, dom, party) < 0)
>          return -1;
>  
> +    if (flags & QEMU_MIGRATION_COOKIE_TLS_PSK) {
> +        switch (party) {
> +        case QEMU_MIGRATION_SOURCE:
> +            if (qemuMigrationCookieAddTLSPSK(mig, driver, dom) < 0)
> +                return -1;
> +            break;
> +        case QEMU_MIGRATION_DESTINATION:
> +            if (!virQEMUCapsGet(priv->qemuCaps, 
> QEMU_CAPS_OBJECT_TLS_CREDS_PSK)) {

IMO any sane build of qemu must have TLS enabled nowadays. I wonder if
it even makes sense to have this capability. If tls can be compiled out,
techincally it'd mean that there could be such a setup but IMO that
would be still insane to have a unencrypted connection.

I'd be okay just assuming that any qemu we support has TLS support. On
the offchance that someone uses an insane build they will get an error,
but I don't think I'd care for such setups.


> +                if (mig->tlsPSK)
> +                    virSecureEraseString(mig->tlsPSK);
> +                mig->flags &= ~QEMU_MIGRATION_COOKIE_TLS_PSK;
> +                g_clear_pointer(&mig->tlsPSK, g_free);
> +            }
> +            break;
> +        }
> +    }
> +
>      if (qemuMigrationCookieXMLFormat(driver, priv->qemuCaps, &buf, mig) < 0)
>          return -1;
>  
>      *cookieoutlen = virBufferUse(&buf) + 1;
>      *cookieout = virBufferContentAndReset(&buf);
>  
> -    VIR_DEBUG("cookielen=%d cookie=%s", *cookieoutlen, *cookieout);
> -
>      return 0;
>  }
>  
> diff --git a/src/qemu/qemu_migration_cookie.h 
> b/src/qemu/qemu_migration_cookie.h
> index 254372234d..fd3b4c5a56 100644
> --- a/src/qemu/qemu_migration_cookie.h
> +++ b/src/qemu/qemu_migration_cookie.h
> @@ -35,6 +35,7 @@ typedef enum {
>      QEMU_MIGRATION_COOKIE_FLAG_ALLOW_REBOOT,
>      QEMU_MIGRATION_COOKIE_FLAG_CAPS,
>      QEMU_MIGRATION_COOKIE_FLAG_BLOCK_DIRTY_BITMAPS,
> +    QEMU_MIGRATION_COOKIE_FLAG_TLS_PSK,
>  
>      QEMU_MIGRATION_COOKIE_FLAG_LAST
>  } qemuMigrationCookieFlags;
> @@ -53,6 +54,7 @@ typedef enum {
>      QEMU_MIGRATION_COOKIE_CPU = (1 << QEMU_MIGRATION_COOKIE_FLAG_CPU),
>      QEMU_MIGRATION_COOKIE_CAPS = (1 << QEMU_MIGRATION_COOKIE_FLAG_CAPS),
>      QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS = (1 << 
> QEMU_MIGRATION_COOKIE_FLAG_BLOCK_DIRTY_BITMAPS),
> +    QEMU_MIGRATION_COOKIE_TLS_PSK = (1 << 
> QEMU_MIGRATION_COOKIE_FLAG_TLS_PSK),
>  } qemuMigrationCookieFeatures;
>  
>  typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics;
> @@ -171,6 +173,9 @@ struct _qemuMigrationCookie {
>  
>      /* If flags & QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS */
>      GSList *blockDirtyBitmaps;
> +
> +    /* If flags & QEMU_MIGRATION_COOKIE_TLS_PSK */
> +    char *tlsPSK;
>  };

Reply via email to