[PATCH] hyperv: report whether guests have TPM enabled

Jonathon Jongsma via Devel posted 1 patch 6 days, 5 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20260224194354.3813322-1-jjongsma@redhat.com
src/hyperv/hyperv_driver.c            | 32 +++++++++++++++++++++++++++
src/hyperv/hyperv_wmi.c               | 26 ++++++++++++++++++++++
src/hyperv/hyperv_wmi.h               |  4 ++++
src/hyperv/hyperv_wmi_generator.input |  9 ++++++++
4 files changed, 71 insertions(+)
[PATCH] hyperv: report whether guests have TPM enabled
Posted by Jonathon Jongsma via Devel 6 days, 5 hours ago
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
---
 src/hyperv/hyperv_driver.c            | 32 +++++++++++++++++++++++++++
 src/hyperv/hyperv_wmi.c               | 26 ++++++++++++++++++++++
 src/hyperv/hyperv_wmi.h               |  4 ++++
 src/hyperv/hyperv_wmi_generator.input |  9 ++++++++
 4 files changed, 71 insertions(+)

diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
index b01b4919fe..7cc67129cd 100644
--- a/src/hyperv/hyperv_driver.c
+++ b/src/hyperv/hyperv_driver.c
@@ -200,6 +200,22 @@ hypervGetOperatingSystem(hypervPrivate *priv, Win32_OperatingSystem **operatingS
 }
 
 
+static int
+hypervDomainGetTPMEnabled(hypervPrivate *priv,
+                          const char *id,
+                          bool *enabled)
+{
+    g_autoptr(Msvm_SecuritySettingData) securitySD = NULL;
+
+    if (hypervGetSecuritySD(priv, id, &securitySD) < 0)
+        return -1;
+
+    VIR_DEBUG("Getting TPM state for '%s': %u", id, securitySD->data->TpmEnabled);
+    *enabled = securitySD->data->TpmEnabled;
+    return 0;
+}
+
+
 static int
 hypervRequestStateChange(virDomainPtr domain, int state)
 {
@@ -2651,6 +2667,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
     g_autoptr(Msvm_SerialPortSettingData) spsd = NULL;
     Msvm_ResourceAllocationSettingData *serialDevices = NULL;
     g_autoptr(Msvm_EthernetPortAllocationSettingData) nets = NULL;
+    bool tpmEnabled = false;
 
     virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
 
@@ -2791,6 +2808,21 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
     if (hypervDomainDefParseEthernet(domain, def, nets) < 0)
         return NULL;
 
+    if (hypervDomainGetTPMEnabled(priv, virtualSystemSettingData->data->InstanceID, &tpmEnabled) == 0
+        && tpmEnabled) {
+        virDomainTPMDef* tpm = NULL;
+
+        if (!def->tpms) {
+            def->tpms = g_new0(virDomainTPMDef *, 1);
+        }
+
+        tpm = g_new0(virDomainTPMDef, 1);
+        tpm->model = VIR_DOMAIN_TPM_MODEL_DEFAULT;
+        tpm->type = VIR_DOMAIN_TPM_TYPE_EMULATOR;
+
+        def->tpms[def->ntpms++] = tpm;
+    }
+
     /* XXX xmlopts must be non-NULL */
     return virDomainDefFormat(def, NULL, virDomainDefFormatConvertXMLFlags(flags));
 }
diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c
index 7ae3afc40a..1cf442dad3 100644
--- a/src/hyperv/hyperv_wmi.c
+++ b/src/hyperv/hyperv_wmi.c
@@ -1625,3 +1625,29 @@ hypervMsvmVSMSModifyResourceSettings(hypervPrivate *priv,
 
     return 0;
 }
+
+
+int
+hypervGetSecuritySD(hypervPrivate *priv,
+                    const char *vssd_instanceid,
+                    Msvm_SecuritySettingData **data)
+{
+    g_auto(virBuffer) query = VIR_BUFFER_INITIALIZER;
+
+    virBufferEscapeSQL(&query,
+                       "ASSOCIATORS OF {Msvm_VirtualSystemSettingData.InstanceID='%s'} "
+                       "WHERE ResultClass = Msvm_SecuritySettingData",
+                       vssd_instanceid);
+
+    if (hypervGetWmiClass(Msvm_SecuritySettingData, data) < 0)
+        return -1;
+
+    if (!*data) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Could not look up security setting data with virtual system instance ID '%1$s'"),
+                       vssd_instanceid);
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h
index 65b1211b89..0f8cfb30bc 100644
--- a/src/hyperv/hyperv_wmi.h
+++ b/src/hyperv/hyperv_wmi.h
@@ -269,6 +269,10 @@ int hypervImageManagementServiceGetVHDSD(hypervPrivate *priv,
                                          const char *vhdPath,
                                          WsXmlDocH *settingDataDoc);
 
+int hypervGetSecuritySD(hypervPrivate *priv,
+                        const char *vssd_instanceid,
+                        Msvm_SecuritySettingData **data);
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * Msvm_VirtualSystemManagementService
  */
diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input
index 017b7a0fa5..b3cd9d19fb 100644
--- a/src/hyperv/hyperv_wmi_generator.input
+++ b/src/hyperv/hyperv_wmi_generator.input
@@ -1252,3 +1252,12 @@ class Win32_DiskDrive
     uint64   TotalTracks
     uint32   TracksPerCylinder
 end
+
+class Msvm_SecuritySettingData
+    boolean TpmEnabled
+    boolean KsdEnabled
+    boolean ShieldingRequested
+    boolean DataProtectionRequested
+    boolean EncryptStateAndVmMigrationTraffic
+    boolean VirtualizationBasedSecurityOptOut
+end
-- 
2.53.0
Re: [PATCH] hyperv: report whether guests have TPM enabled
Posted by Michal Prívozník via Devel 5 days, 10 hours ago
On 2/24/26 20:43, Jonathon Jongsma via Devel wrote:
> Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
> ---
>  src/hyperv/hyperv_driver.c            | 32 +++++++++++++++++++++++++++
>  src/hyperv/hyperv_wmi.c               | 26 ++++++++++++++++++++++
>  src/hyperv/hyperv_wmi.h               |  4 ++++
>  src/hyperv/hyperv_wmi_generator.input |  9 ++++++++
>  4 files changed, 71 insertions(+)
> 
> diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
> index b01b4919fe..7cc67129cd 100644
> --- a/src/hyperv/hyperv_driver.c
> +++ b/src/hyperv/hyperv_driver.c
> @@ -200,6 +200,22 @@ hypervGetOperatingSystem(hypervPrivate *priv, Win32_OperatingSystem **operatingS
>  }
>  
>  
> +static int
> +hypervDomainGetTPMEnabled(hypervPrivate *priv,
> +                          const char *id,
> +                          bool *enabled)
> +{
> +    g_autoptr(Msvm_SecuritySettingData) securitySD = NULL;
> +
> +    if (hypervGetSecuritySD(priv, id, &securitySD) < 0)
> +        return -1;
> +
> +    VIR_DEBUG("Getting TPM state for '%s': %u", id, securitySD->data->TpmEnabled);
> +    *enabled = securitySD->data->TpmEnabled;
> +    return 0;
> +}
> +
> +
>  static int
>  hypervRequestStateChange(virDomainPtr domain, int state)
>  {
> @@ -2651,6 +2667,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
>      g_autoptr(Msvm_SerialPortSettingData) spsd = NULL;
>      Msvm_ResourceAllocationSettingData *serialDevices = NULL;
>      g_autoptr(Msvm_EthernetPortAllocationSettingData) nets = NULL;
> +    bool tpmEnabled = false;
>  
>      virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
>  
> @@ -2791,6 +2808,21 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
>      if (hypervDomainDefParseEthernet(domain, def, nets) < 0)
>          return NULL;
>  
> +    if (hypervDomainGetTPMEnabled(priv, virtualSystemSettingData->data->InstanceID, &tpmEnabled) == 0
> +        && tpmEnabled) {
> +        virDomainTPMDef* tpm = NULL;
> +
> +        if (!def->tpms) {
> +            def->tpms = g_new0(virDomainTPMDef *, 1);
> +        }
> +
> +        tpm = g_new0(virDomainTPMDef, 1);
> +        tpm->model = VIR_DOMAIN_TPM_MODEL_DEFAULT;

The model is CRB in version 2. So this should be:

        tpm = g_new0(virDomainTPMDef, 1);
        tpm->model = VIR_DOMAIN_TPM_MODEL_CRB;
        tpm->type = VIR_DOMAIN_TPM_TYPE_EMULATOR;
        tpm->data.emulator.version = VIR_DOMAIN_TPM_VERSION_2_0;


> +        tpm->type = VIR_DOMAIN_TPM_TYPE_EMULATOR;
> +
> +        def->tpms[def->ntpms++] = tpm;
> +    }
> +
>      /* XXX xmlopts must be non-NULL */
>      return virDomainDefFormat(def, NULL, virDomainDefFormatConvertXMLFlags(flags));
>  }
> diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c
> index 7ae3afc40a..1cf442dad3 100644
> --- a/src/hyperv/hyperv_wmi.c
> +++ b/src/hyperv/hyperv_wmi.c
> @@ -1625,3 +1625,29 @@ hypervMsvmVSMSModifyResourceSettings(hypervPrivate *priv,
>  
>      return 0;
>  }
> +
> +
> +int
> +hypervGetSecuritySD(hypervPrivate *priv,
> +                    const char *vssd_instanceid,
> +                    Msvm_SecuritySettingData **data)
> +{
> +    g_auto(virBuffer) query = VIR_BUFFER_INITIALIZER;
> +
> +    virBufferEscapeSQL(&query,
> +                       "ASSOCIATORS OF {Msvm_VirtualSystemSettingData.InstanceID='%s'} "
> +                       "WHERE ResultClass = Msvm_SecuritySettingData",
> +                       vssd_instanceid);


AAAgrh. I was stuck on this for a week! The closest I get was:

virBufferAsprintf(&query,
                  "ASSOCIATORS OF {Msvm_VirtualSystemSettingData.InstanceID='%s'} "
                  "WHERE AssocClass = Msvm_SecurityElementSettingData "
                  "ResultClass = Msvm_SecuritySettingData",
                  id);

Which works flawlessly in PowerShell inside my Windows VM. But the
moment I tried via wsman I got an empty answer.

Reviewed-by: Michal Privoznik <mprivozn@redhat.com>

Michal