public inbox for qemu-devel@nongnu.org
 help / color / mirror / Atom feed
* [PATCH v1] qga: add guest-get-windows-security-info command
@ 2026-03-16 12:31 Elizabeth Ashurov
  2026-03-17 14:07 ` Kostiantyn Kostiuk
  0 siblings, 1 reply; 8+ messages in thread
From: Elizabeth Ashurov @ 2026-03-16 12:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: kkostiuk, Elizabeth Ashurov

Add a new Windows-only QGA command to retrieve Windows security
features status including VBS, Secure Boot, and TPM information
from the guest.

The implementation queries Win32_DeviceGuard and Win32_Tpm via
WMI, and reads the SecureBoot UEFI variable through
GetFirmwareEnvironmentVariable().

Signed-off-by: Elizabeth Ashurov <eashurov@redhat.com>
---
 qga/commands-win32.c | 404 +++++++++++++++++++++++++++++++++++++++++++
 qga/qapi-schema.json |  56 ++++++
 2 files changed, 460 insertions(+)

diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index c0bf3467bd..8da9ef521f 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -28,6 +28,7 @@
 #include <wtsapi32.h>
 #include <wininet.h>
 #include <pdh.h>
+#include <wbemidl.h>
 
 #include "guest-agent-core.h"
 #include "vss-win32.h"
@@ -2764,3 +2765,406 @@ GuestNetworkRouteList *qmp_guest_network_get_route(Error **errp)
     g_hash_table_destroy(interface_metric_cache);
     return head;
 }
+
+/*
+ * WMI GUIDs
+ */
+static const GUID qga_CLSID_WbemLocator = {
+    0x4590f811, 0x1d3a, 0x11d0,
+    {0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24}
+};
+static const GUID qga_IID_IWbemLocator = {
+    0xdc12a687, 0x737f, 0x11cf,
+    {0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24}
+};
+
+static IWbemServices *wmi_connect_to_namespace(const wchar_t *namespace_path,
+                                               Error **errp)
+{
+    HRESULT hr;
+    IWbemLocator *locator = NULL;
+    IWbemServices *services = NULL;
+    BSTR bstr_ns = SysAllocString(namespace_path);
+
+    if (!bstr_ns) {
+        error_setg(errp, "failed to allocate WMI namespace string");
+        return NULL;
+    }
+
+    hr = CoCreateInstance(&qga_CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER,
+                          &qga_IID_IWbemLocator, (LPVOID *)&locator);
+    if (FAILED(hr)) {
+        error_setg_win32(errp, hr, "failed to create IWbemLocator");
+        goto out;
+    }
+
+    hr = locator->lpVtbl->ConnectServer(locator, bstr_ns, NULL, NULL, NULL,
+                                        0, NULL, NULL, &services);
+    if (FAILED(hr)) {
+        error_setg_win32(errp, hr, "failed to connect to WMI namespace");
+        goto out;
+    }
+
+    hr = CoSetProxyBlanket((IUnknown *)services,
+                           RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
+                           RPC_C_AUTHN_LEVEL_CALL,
+                           RPC_C_IMP_LEVEL_IMPERSONATE,
+                           NULL, EOAC_NONE);
+    if (FAILED(hr)) {
+        error_setg_win32(errp, hr, "failed to set WMI proxy blanket");
+        services->lpVtbl->Release(services);
+        services = NULL;
+    }
+
+out:
+    SysFreeString(bstr_ns);
+    if (locator) {
+        locator->lpVtbl->Release(locator);
+    }
+    return services;
+}
+
+static IEnumWbemClassObject *wmi_exec_query(IWbemServices *services,
+                                            const wchar_t *query,
+                                            Error **errp)
+{
+    HRESULT hr;
+    IEnumWbemClassObject *enumerator = NULL;
+    BSTR bstr_wql = SysAllocString(L"WQL");
+    BSTR bstr_query = SysAllocString(query);
+
+    if (!bstr_wql || !bstr_query) {
+        error_setg(errp, "failed to allocate WMI query strings");
+        goto out;
+    }
+
+    hr = services->lpVtbl->ExecQuery(services, bstr_wql, bstr_query,
+                                     WBEM_FLAG_RETURN_IMMEDIATELY |
+                                     WBEM_FLAG_FORWARD_ONLY,
+                                     NULL, &enumerator);
+    if (FAILED(hr)) {
+        error_setg_win32(errp, hr, "WMI query failed");
+    }
+
+out:
+    SysFreeString(bstr_wql);
+    SysFreeString(bstr_query);
+    return enumerator;
+}
+
+static HRESULT wmi_get_property(IWbemClassObject *obj, const wchar_t *name,
+                                VARIANT *var)
+{
+    return obj->lpVtbl->Get(obj, name, 0, var, NULL, NULL);
+}
+
+/* Read a WMI integer property (VT_I4 or VT_UI4). */
+static bool wmi_get_int_property(IWbemClassObject *obj,
+                                 const wchar_t *name,
+                                 int64_t *out)
+{
+    VARIANT var;
+    bool ret = false;
+
+    VariantInit(&var);
+    if (SUCCEEDED(wmi_get_property(obj, name, &var))) {
+        if (V_VT(&var) == VT_I4) {
+            *out = V_I4(&var);
+            ret = true;
+        } else if (V_VT(&var) == VT_UI4) {
+            *out = V_UI4(&var);
+            ret = true;
+        }
+    }
+    VariantClear(&var);
+    return ret;
+}
+
+/* Read an integer SAFEARRAY WMI property into a QAPI intList. */
+static bool wmi_safearray_to_int_list(IWbemClassObject *obj,
+                                      const wchar_t *prop_name,
+                                      intList **list)
+{
+    VARIANT var;
+    HRESULT hr;
+    LONG lb, ub, i;
+    uint32_t *data = NULL;
+
+    VariantInit(&var);
+    hr = wmi_get_property(obj, prop_name, &var);
+    if (FAILED(hr) || V_VT(&var) == VT_NULL) {
+        VariantClear(&var);
+        return false;
+    }
+
+    if (!(V_VT(&var) & VT_ARRAY)) {
+        VariantClear(&var);
+        return false;
+    }
+
+    SAFEARRAY *sa = V_ARRAY(&var);
+    if (FAILED(SafeArrayGetLBound(sa, 1, &lb)) ||
+        FAILED(SafeArrayGetUBound(sa, 1, &ub))) {
+        VariantClear(&var);
+        return false;
+    }
+
+    if (FAILED(SafeArrayAccessData(sa, (void **)&data))) {
+        VariantClear(&var);
+        return false;
+    }
+
+    intList **tail = list;
+    for (i = 0; i <= ub - lb; i++) {
+        QAPI_LIST_APPEND(tail, (int64_t)data[i]);
+    }
+
+    SafeArrayUnaccessData(sa);
+    VariantClear(&var);
+    return true;
+}
+
+/*
+ * Query Win32_DeviceGuard WMI class for VBS and related properties.
+ */
+static void get_device_guard_info(GuestWindowsSecurityInfo *info,
+                                  Error **errp)
+{
+    Error *local_err = NULL;
+    IWbemServices *services = NULL;
+    IEnumWbemClassObject *enumerator = NULL;
+    IWbemClassObject *obj = NULL;
+    ULONG count = 0;
+    HRESULT hr;
+    int64_t val;
+
+    services = wmi_connect_to_namespace(
+        L"ROOT\\Microsoft\\Windows\\DeviceGuard", &local_err);
+    if (!services) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    enumerator = wmi_exec_query(services,
+        L"SELECT * FROM Win32_DeviceGuard", &local_err);
+    if (!enumerator) {
+        error_propagate(errp, local_err);
+        goto out;
+    }
+
+    hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1,
+                                   &obj, &count);
+    if (FAILED(hr)) {
+        error_setg_win32(errp, hr, "failed to enumerate Win32_DeviceGuard");
+        goto out;
+    }
+    if (count == 0) {
+        error_setg(errp, "no Win32_DeviceGuard instance found");
+        goto out;
+    }
+
+    if (wmi_get_int_property(obj, L"VirtualizationBasedSecurityStatus",
+                             &val)) {
+        info->vbs_status = val;
+    }
+
+    if (wmi_get_int_property(obj, L"CodeIntegrityPolicyEnforcementStatus",
+                             &val)) {
+        info->has_code_integrity_policy_enforcement_status = true;
+        info->code_integrity_policy_enforcement_status = val;
+    }
+
+    if (wmi_get_int_property(obj,
+                             L"UsermodeCodeIntegrityPolicyEnforcementStatus",
+                             &val)) {
+        info->has_usr_cfg_code_integrity_policy_enforcement_status = true;
+        info->usr_cfg_code_integrity_policy_enforcement_status = val;
+    }
+
+    if (wmi_safearray_to_int_list(obj, L"AvailableSecurityProperties",
+                                  &info->available_security_properties)) {
+        info->has_available_security_properties = true;
+    }
+
+    if (wmi_safearray_to_int_list(obj, L"RequiredSecurityProperties",
+                                  &info->required_security_properties)) {
+        info->has_required_security_properties = true;
+    }
+
+    if (wmi_safearray_to_int_list(obj, L"SecurityServicesConfigured",
+                                  &info->security_services_configured)) {
+        info->has_security_services_configured = true;
+    }
+
+    if (wmi_safearray_to_int_list(obj, L"SecurityServicesRunning",
+                                  &info->security_services_running)) {
+        info->has_security_services_running = true;
+    }
+
+    obj->lpVtbl->Release(obj);
+    obj = NULL;
+
+    /* Drain remaining results */
+    while (true) {
+        hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1,
+                                      &obj, &count);
+        if (FAILED(hr) || count == 0) {
+            break;
+        }
+        obj->lpVtbl->Release(obj);
+        obj = NULL;
+    }
+
+out:
+    if (obj) {
+        obj->lpVtbl->Release(obj);
+    }
+    if (enumerator) {
+        enumerator->lpVtbl->Release(enumerator);
+    }
+    if (services) {
+        services->lpVtbl->Release(services);
+    }
+}
+
+/*
+ * Read the SecureBoot UEFI variable to determine whether Secure Boot
+ * is enabled.  Returns false on legacy BIOS systems.
+ */
+static bool get_secure_boot_status(Error **errp)
+{
+    Error *local_err = NULL;
+    BYTE value = 0;
+    DWORD ret;
+
+    acquire_privilege(SE_SYSTEM_ENVIRONMENT_NAME, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return false;
+    }
+
+    ret = GetFirmwareEnvironmentVariableA("SecureBoot",
+        "{8be4df61-93ca-11d2-aa0d-00e098032b8c}", &value, sizeof(value));
+
+    if (ret == 0) {
+        DWORD err = GetLastError();
+        if (err == ERROR_INVALID_FUNCTION || err == ERROR_ENVVAR_NOT_FOUND) {
+            return false;
+        }
+        error_setg_win32(errp, err,
+                         "failed to read SecureBoot UEFI variable");
+        return false;
+    }
+
+    return value == 1;
+}
+
+/*
+ * Query Win32_Tpm WMI class for TPM presence and version.
+ */
+static void get_tpm_info(GuestWindowsSecurityInfo *info, Error **errp)
+{
+    Error *local_err = NULL;
+    IWbemServices *services = NULL;
+    IEnumWbemClassObject *enumerator = NULL;
+    IWbemClassObject *obj = NULL;
+    ULONG count = 0;
+    HRESULT hr;
+    VARIANT var;
+
+    services = wmi_connect_to_namespace(
+        L"ROOT\\CIMV2\\Security\\MicrosoftTpm", &local_err);
+    if (!services) {
+        /* TPM namespace may not exist -- not an error */
+        error_free(local_err);
+        info->tpm_present = false;
+        return;
+    }
+
+    enumerator = wmi_exec_query(services,
+        L"SELECT * FROM Win32_Tpm", &local_err);
+    if (!enumerator) {
+        error_free(local_err);
+        info->tpm_present = false;
+        goto out;
+    }
+
+    hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1,
+                                   &obj, &count);
+    if (FAILED(hr) || count == 0) {
+        info->tpm_present = false;
+        goto out;
+    }
+
+    info->tpm_present = true;
+
+    VariantInit(&var);
+    if (SUCCEEDED(wmi_get_property(obj, L"SpecVersion", &var)) &&
+        V_VT(&var) == VT_BSTR && V_BSTR(&var)) {
+        info->tpm_version = g_utf16_to_utf8(
+            (const gunichar2 *)V_BSTR(&var), -1, NULL, NULL, NULL);
+        if (info->tpm_version) {
+            /* keep only the part before the first comma */
+            char *comma = strchr(info->tpm_version, ',');
+            if (comma) {
+                *comma = '\0';
+            }
+        }
+    }
+    VariantClear(&var);
+
+    obj->lpVtbl->Release(obj);
+    obj = NULL;
+
+    /* Drain remaining results */
+    while (true) {
+        hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1,
+                                      &obj, &count);
+        if (FAILED(hr) || count == 0) {
+            break;
+        }
+        obj->lpVtbl->Release(obj);
+        obj = NULL;
+    }
+
+out:
+    if (obj) {
+        obj->lpVtbl->Release(obj);
+    }
+    if (enumerator) {
+        enumerator->lpVtbl->Release(enumerator);
+    }
+    if (services) {
+        services->lpVtbl->Release(services);
+    }
+}
+
+GuestWindowsSecurityInfo *qmp_guest_get_windows_security_info(Error **errp)
+{
+    Error *local_err = NULL;
+    GuestWindowsSecurityInfo *info = g_new0(GuestWindowsSecurityInfo, 1);
+
+    get_device_guard_info(info, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        goto err;
+    }
+
+    info->secure_boot = get_secure_boot_status(&local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        goto err;
+    }
+
+    get_tpm_info(info, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        goto err;
+    }
+
+    return info;
+
+err:
+    qapi_free_GuestWindowsSecurityInfo(info);
+    return NULL;
+}
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index c57bc9a02f..f54fdf942f 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -1952,3 +1952,59 @@
   'returns': ['GuestNetworkRoute'],
   'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] }
 }
+
+##
+# @GuestWindowsSecurityInfo:
+#
+# Windows security features status.
+#
+# @vbs-status: VirtualizationBasedSecurityStatus
+#
+# @available-security-properties: AvailableSecurityProperties
+#
+# @code-integrity-policy-enforcement-status:
+#     CodeIntegrityPolicyEnforcementStatus
+#
+# @required-security-properties: RequiredSecurityProperties
+#
+# @security-services-configured: SecurityServicesConfigured
+#
+# @security-services-running: SecurityServicesRunning
+#
+# @usr-cfg-code-integrity-policy-enforcement-status:
+#     UsermodeCodeIntegrityPolicyEnforcementStatus
+#
+# @secure-boot: Whether UEFI Secure Boot is enabled
+#
+# @tpm-present: Whether a TPM device is present
+#
+# @tpm-version: TPM specification version string (e.g. "2.0")
+#
+# Since: 10.3
+##
+{ 'struct': 'GuestWindowsSecurityInfo',
+  'data': {
+      'vbs-status': 'int',
+      '*available-security-properties': ['int'],
+      '*code-integrity-policy-enforcement-status': 'int',
+      '*required-security-properties': ['int'],
+      '*security-services-configured': ['int'],
+      '*security-services-running': ['int'],
+      '*usr-cfg-code-integrity-policy-enforcement-status': 'int',
+      'secure-boot': 'bool',
+      'tpm-present': 'bool',
+      '*tpm-version': 'str' },
+  'if': 'CONFIG_WIN32' }
+
+##
+# @guest-get-windows-security-info:
+#
+# Retrieve Windows security features status (VBS, Secure Boot, TPM).
+#
+# Returns: @GuestWindowsSecurityInfo
+#
+# Since: 10.3
+##
+{ 'command': 'guest-get-windows-security-info',
+  'returns': 'GuestWindowsSecurityInfo',
+  'if': 'CONFIG_WIN32' }
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] qga: add guest-get-windows-security-info command
  2026-03-16 12:31 [PATCH v1] qga: add guest-get-windows-security-info command Elizabeth Ashurov
@ 2026-03-17 14:07 ` Kostiantyn Kostiuk
  2026-03-17 14:15   ` Daniel P. Berrangé
  0 siblings, 1 reply; 8+ messages in thread
From: Kostiantyn Kostiuk @ 2026-03-17 14:07 UTC (permalink / raw)
  To: Elizabeth Ashurov
  Cc: qemu-devel, Daniel Berrangé, Marc-André Lureau,
	Yan Vugenfirer

[-- Attachment #1: Type: text/plain, Size: 16735 bytes --]

On Mon, Mar 16, 2026 at 2:32 PM Elizabeth Ashurov <eashurov@redhat.com>
wrote:

> Add a new Windows-only QGA command to retrieve Windows security
> features status including VBS, Secure Boot, and TPM information
> from the guest.
>
> The implementation queries Win32_DeviceGuard and Win32_Tpm via
> WMI, and reads the SecureBoot UEFI variable through
> GetFirmwareEnvironmentVariable().
>
> Signed-off-by: Elizabeth Ashurov <eashurov@redhat.com>
> ---
>  qga/commands-win32.c | 404 +++++++++++++++++++++++++++++++++++++++++++
>  qga/qapi-schema.json |  56 ++++++
>  2 files changed, 460 insertions(+)
>
> diff --git a/qga/commands-win32.c b/qga/commands-win32.c
> index c0bf3467bd..8da9ef521f 100644
> --- a/qga/commands-win32.c
> +++ b/qga/commands-win32.c
> @@ -28,6 +28,7 @@
>  #include <wtsapi32.h>
>  #include <wininet.h>
>  #include <pdh.h>
> +#include <wbemidl.h>
>
>  #include "guest-agent-core.h"
>  #include "vss-win32.h"
> @@ -2764,3 +2765,406 @@ GuestNetworkRouteList
> *qmp_guest_network_get_route(Error **errp)
>      g_hash_table_destroy(interface_metric_cache);
>      return head;
>  }
> +
> +/*
> + * WMI GUIDs
> + */
> +static const GUID qga_CLSID_WbemLocator = {
> +    0x4590f811, 0x1d3a, 0x11d0,
> +    {0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24}
> +};
> +static const GUID qga_IID_IWbemLocator = {
> +    0xdc12a687, 0x737f, 0x11cf,
> +    {0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24}
> +};
> +
> +static IWbemServices *wmi_connect_to_namespace(const wchar_t
> *namespace_path,
> +                                               Error **errp)
> +{
> +    HRESULT hr;
> +    IWbemLocator *locator = NULL;
> +    IWbemServices *services = NULL;
> +    BSTR bstr_ns = SysAllocString(namespace_path);
> +
> +    if (!bstr_ns) {
> +        error_setg(errp, "failed to allocate WMI namespace string");
> +        return NULL;
> +    }
> +
> +    hr = CoCreateInstance(&qga_CLSID_WbemLocator, NULL,
> CLSCTX_INPROC_SERVER,
> +                          &qga_IID_IWbemLocator, (LPVOID *)&locator);
> +    if (FAILED(hr)) {
> +        error_setg_win32(errp, hr, "failed to create IWbemLocator");
> +        goto out;
> +    }
> +
> +    hr = locator->lpVtbl->ConnectServer(locator, bstr_ns, NULL, NULL,
> NULL,
> +                                        0, NULL, NULL, &services);
> +    if (FAILED(hr)) {
> +        error_setg_win32(errp, hr, "failed to connect to WMI namespace");
> +        goto out;
> +    }
> +
> +    hr = CoSetProxyBlanket((IUnknown *)services,
> +                           RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
> +                           RPC_C_AUTHN_LEVEL_CALL,
> +                           RPC_C_IMP_LEVEL_IMPERSONATE,
> +                           NULL, EOAC_NONE);
> +    if (FAILED(hr)) {
> +        error_setg_win32(errp, hr, "failed to set WMI proxy blanket");
> +        services->lpVtbl->Release(services);
> +        services = NULL;
> +    }
> +
> +out:
> +    SysFreeString(bstr_ns);
> +    if (locator) {
> +        locator->lpVtbl->Release(locator);
> +    }
> +    return services;
> +}
> +
> +static IEnumWbemClassObject *wmi_exec_query(IWbemServices *services,
> +                                            const wchar_t *query,
> +                                            Error **errp)
> +{
> +    HRESULT hr;
> +    IEnumWbemClassObject *enumerator = NULL;
> +    BSTR bstr_wql = SysAllocString(L"WQL");
> +    BSTR bstr_query = SysAllocString(query);
> +
> +    if (!bstr_wql || !bstr_query) {
> +        error_setg(errp, "failed to allocate WMI query strings");
> +        goto out;
> +    }
> +
> +    hr = services->lpVtbl->ExecQuery(services, bstr_wql, bstr_query,
> +                                     WBEM_FLAG_RETURN_IMMEDIATELY |
> +                                     WBEM_FLAG_FORWARD_ONLY,
> +                                     NULL, &enumerator);
> +    if (FAILED(hr)) {
> +        error_setg_win32(errp, hr, "WMI query failed");
> +    }
> +
> +out:
> +    SysFreeString(bstr_wql);
> +    SysFreeString(bstr_query);
> +    return enumerator;
> +}
> +
> +static HRESULT wmi_get_property(IWbemClassObject *obj, const wchar_t
> *name,
> +                                VARIANT *var)
> +{
> +    return obj->lpVtbl->Get(obj, name, 0, var, NULL, NULL);
> +}
> +
> +/* Read a WMI integer property (VT_I4 or VT_UI4). */
> +static bool wmi_get_int_property(IWbemClassObject *obj,
> +                                 const wchar_t *name,
> +                                 int64_t *out)
> +{
> +    VARIANT var;
> +    bool ret = false;
> +
> +    VariantInit(&var);
> +    if (SUCCEEDED(wmi_get_property(obj, name, &var))) {
> +        if (V_VT(&var) == VT_I4) {
> +            *out = V_I4(&var);
> +            ret = true;
> +        } else if (V_VT(&var) == VT_UI4) {
> +            *out = V_UI4(&var);
> +            ret = true;
> +        }
> +    }
> +    VariantClear(&var);
> +    return ret;
> +}
> +
> +/* Read an integer SAFEARRAY WMI property into a QAPI intList. */
> +static bool wmi_safearray_to_int_list(IWbemClassObject *obj,
> +                                      const wchar_t *prop_name,
> +                                      intList **list)
> +{
> +    VARIANT var;
> +    HRESULT hr;
> +    LONG lb, ub, i;
> +    uint32_t *data = NULL;
> +
> +    VariantInit(&var);
> +    hr = wmi_get_property(obj, prop_name, &var);
> +    if (FAILED(hr) || V_VT(&var) == VT_NULL) {
> +        VariantClear(&var);
> +        return false;
> +    }
> +
> +    if (!(V_VT(&var) & VT_ARRAY)) {
> +        VariantClear(&var);
> +        return false;
> +    }
> +
> +    SAFEARRAY *sa = V_ARRAY(&var);
> +    if (FAILED(SafeArrayGetLBound(sa, 1, &lb)) ||
> +        FAILED(SafeArrayGetUBound(sa, 1, &ub))) {
> +        VariantClear(&var);
> +        return false;
> +    }
> +
> +    if (FAILED(SafeArrayAccessData(sa, (void **)&data))) {
> +        VariantClear(&var);
> +        return false;
> +    }
> +
> +    intList **tail = list;
> +    for (i = 0; i <= ub - lb; i++) {
> +        QAPI_LIST_APPEND(tail, (int64_t)data[i]);
> +    }
> +
> +    SafeArrayUnaccessData(sa);
> +    VariantClear(&var);
> +    return true;
> +}
> +
> +/*
> + * Query Win32_DeviceGuard WMI class for VBS and related properties.
> + */
> +static void get_device_guard_info(GuestWindowsSecurityInfo *info,
> +                                  Error **errp)
> +{
> +    Error *local_err = NULL;
> +    IWbemServices *services = NULL;
> +    IEnumWbemClassObject *enumerator = NULL;
> +    IWbemClassObject *obj = NULL;
> +    ULONG count = 0;
> +    HRESULT hr;
> +    int64_t val;
> +
> +    services = wmi_connect_to_namespace(
> +        L"ROOT\\Microsoft\\Windows\\DeviceGuard", &local_err);
> +    if (!services) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
> +    enumerator = wmi_exec_query(services,
> +        L"SELECT * FROM Win32_DeviceGuard", &local_err);
> +    if (!enumerator) {
> +        error_propagate(errp, local_err);
> +        goto out;
> +    }
> +
> +    hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1,
> +                                   &obj, &count);
> +    if (FAILED(hr)) {
> +        error_setg_win32(errp, hr, "failed to enumerate
> Win32_DeviceGuard");
> +        goto out;
> +    }
> +    if (count == 0) {
> +        error_setg(errp, "no Win32_DeviceGuard instance found");
> +        goto out;
> +    }
> +
> +    if (wmi_get_int_property(obj, L"VirtualizationBasedSecurityStatus",
> +                             &val)) {
> +        info->vbs_status = val;
> +    }
> +
> +    if (wmi_get_int_property(obj, L"CodeIntegrityPolicyEnforcementStatus",
> +                             &val)) {
> +        info->has_code_integrity_policy_enforcement_status = true;
> +        info->code_integrity_policy_enforcement_status = val;
> +    }
> +
> +    if (wmi_get_int_property(obj,
> +
>  L"UsermodeCodeIntegrityPolicyEnforcementStatus",
> +                             &val)) {
> +        info->has_usr_cfg_code_integrity_policy_enforcement_status = true;
> +        info->usr_cfg_code_integrity_policy_enforcement_status = val;
> +    }
> +
> +    if (wmi_safearray_to_int_list(obj, L"AvailableSecurityProperties",
> +                                  &info->available_security_properties)) {
> +        info->has_available_security_properties = true;
> +    }
> +
> +    if (wmi_safearray_to_int_list(obj, L"RequiredSecurityProperties",
> +                                  &info->required_security_properties)) {
> +        info->has_required_security_properties = true;
> +    }
> +
> +    if (wmi_safearray_to_int_list(obj, L"SecurityServicesConfigured",
> +                                  &info->security_services_configured)) {
> +        info->has_security_services_configured = true;
> +    }
> +
> +    if (wmi_safearray_to_int_list(obj, L"SecurityServicesRunning",
> +                                  &info->security_services_running)) {
> +        info->has_security_services_running = true;
> +    }
> +
> +    obj->lpVtbl->Release(obj);
> +    obj = NULL;
> +
> +    /* Drain remaining results */
> +    while (true) {
> +        hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1,
> +                                      &obj, &count);
> +        if (FAILED(hr) || count == 0) {
> +            break;
> +        }
> +        obj->lpVtbl->Release(obj);
> +        obj = NULL;
> +    }
> +
> +out:
> +    if (obj) {
> +        obj->lpVtbl->Release(obj);
> +    }
> +    if (enumerator) {
> +        enumerator->lpVtbl->Release(enumerator);
> +    }
> +    if (services) {
> +        services->lpVtbl->Release(services);
> +    }
> +}
> +
> +/*
> + * Read the SecureBoot UEFI variable to determine whether Secure Boot
> + * is enabled.  Returns false on legacy BIOS systems.
> + */
> +static bool get_secure_boot_status(Error **errp)
> +{
> +    Error *local_err = NULL;
> +    BYTE value = 0;
> +    DWORD ret;
> +
> +    acquire_privilege(SE_SYSTEM_ENVIRONMENT_NAME, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return false;
> +    }
> +
> +    ret = GetFirmwareEnvironmentVariableA("SecureBoot",
> +        "{8be4df61-93ca-11d2-aa0d-00e098032b8c}", &value, sizeof(value));
>
+
> +    if (ret == 0) {
> +        DWORD err = GetLastError();
> +        if (err == ERROR_INVALID_FUNCTION || err ==
> ERROR_ENVVAR_NOT_FOUND) {
> +            return false;
> +        }
> +        error_setg_win32(errp, err,
> +                         "failed to read SecureBoot UEFI variable");
> +        return false;
> +    }
> +
> +    return value == 1;
> +}
> +
> +/*
> + * Query Win32_Tpm WMI class for TPM presence and version.
> + */
> +static void get_tpm_info(GuestWindowsSecurityInfo *info, Error **errp)
> +{
> +    Error *local_err = NULL;
> +    IWbemServices *services = NULL;
> +    IEnumWbemClassObject *enumerator = NULL;
> +    IWbemClassObject *obj = NULL;
> +    ULONG count = 0;
> +    HRESULT hr;
> +    VARIANT var;
> +
> +    services = wmi_connect_to_namespace(
> +        L"ROOT\\CIMV2\\Security\\MicrosoftTpm", &local_err);
> +    if (!services) {
> +        /* TPM namespace may not exist -- not an error */
>
This is a case for the missing "tpm_present" field


> +        error_free(local_err);
> +        info->tpm_present = false;
> +        return;
> +    }
> +
> +    enumerator = wmi_exec_query(services,
> +        L"SELECT * FROM Win32_Tpm", &local_err);
> +    if (!enumerator) {
> +        error_free(local_err);
> +        info->tpm_present = false;
> +        goto out;
> +    }
> +
> +    hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1,
> +                                   &obj, &count);
> +    if (FAILED(hr) || count == 0) {
> +        info->tpm_present = false;
> +        goto out;
> +    }
> +
> +    info->tpm_present = true;
> +
> +    VariantInit(&var);
> +    if (SUCCEEDED(wmi_get_property(obj, L"SpecVersion", &var)) &&
> +        V_VT(&var) == VT_BSTR && V_BSTR(&var)) {
> +        info->tpm_version = g_utf16_to_utf8(
> +            (const gunichar2 *)V_BSTR(&var), -1, NULL, NULL, NULL);
> +        if (info->tpm_version) {
> +            /* keep only the part before the first comma */
> +            char *comma = strchr(info->tpm_version, ',');
> +            if (comma) {
> +                *comma = '\0';
> +            }
> +        }
> +    }
> +    VariantClear(&var);
> +
> +    obj->lpVtbl->Release(obj);
> +    obj = NULL;
> +
> +    /* Drain remaining results */
> +    while (true) {
> +        hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1,
> +                                      &obj, &count);
> +        if (FAILED(hr) || count == 0) {
> +            break;
> +        }
> +        obj->lpVtbl->Release(obj);
> +        obj = NULL;
> +    }
> +
> +out:
> +    if (obj) {
> +        obj->lpVtbl->Release(obj);
> +    }
> +    if (enumerator) {
> +        enumerator->lpVtbl->Release(enumerator);
> +    }
> +    if (services) {
> +        services->lpVtbl->Release(services);
> +    }
> +}
> +
> +GuestWindowsSecurityInfo *qmp_guest_get_windows_security_info(Error
> **errp)
> +{
> +    Error *local_err = NULL;
> +    GuestWindowsSecurityInfo *info = g_new0(GuestWindowsSecurityInfo, 1);
> +
> +    get_device_guard_info(info, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        goto err;
> +    }
> +
> +    info->secure_boot = get_secure_boot_status(&local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        goto err;
> +    }
> +
> +    get_tpm_info(info, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        goto err;
> +    }
> +
> +    return info;
> +
> +err:
> +    qapi_free_GuestWindowsSecurityInfo(info);
> +    return NULL;
> +}
> diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
> index c57bc9a02f..f54fdf942f 100644
> --- a/qga/qapi-schema.json
> +++ b/qga/qapi-schema.json
> @@ -1952,3 +1952,59 @@
>    'returns': ['GuestNetworkRoute'],
>    'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] }
>  }
> +
> +##
> +# @GuestWindowsSecurityInfo:
> +#
> +# Windows security features status.
> +#
> +# @vbs-status: VirtualizationBasedSecurityStatus
> +#
> +# @available-security-properties: AvailableSecurityProperties
> +#
> +# @code-integrity-policy-enforcement-status:
> +#     CodeIntegrityPolicyEnforcementStatus
> +#
> +# @required-security-properties: RequiredSecurityProperties
> +#
> +# @security-services-configured: SecurityServicesConfigured
> +#
> +# @security-services-running: SecurityServicesRunning
> +#
> +# @usr-cfg-code-integrity-policy-enforcement-status:
> +#     UsermodeCodeIntegrityPolicyEnforcementStatus
> +#
> +# @secure-boot: Whether UEFI Secure Boot is enabled
> +#
> +# @tpm-present: Whether a TPM device is present
> +#
> +# @tpm-version: TPM specification version string (e.g. "2.0")
> +#
> +# Since: 10.3
> +##
> +{ 'struct': 'GuestWindowsSecurityInfo',
> +  'data': {
> +      'vbs-status': 'int',
> +      '*available-security-properties': ['int'],
> +      '*code-integrity-policy-enforcement-status': 'int',
> +      '*required-security-properties': ['int'],
> +      '*security-services-configured': ['int'],
> +      '*security-services-running': ['int'],
> +      '*usr-cfg-code-integrity-policy-enforcement-status': 'int',
> +      'secure-boot': 'bool',
> +      'tpm-present': 'bool',
> +      '*tpm-version': 'str' },
> +  'if': 'CONFIG_WIN32' }
>
>
Let's make this more generic
command guest-get-security-info
use 'union' to describe OS specific option like VBS
{ 'tmp_present': false, 'secure_boot': true, 'os': { 'type': 'windows',
'vbs': false, .... } }

make tmp_present, secure_boot, vbs_status optiononal
missing = unknown - as we can have it unimplemented for some POSIX/BSD OSes

vbs_status is Win10+ only feature, so it can be unknown for Win8


+
> +##
> +# @guest-get-windows-security-info:
> +#
> +# Retrieve Windows security features status (VBS, Secure Boot, TPM).
> +#
> +# Returns: @GuestWindowsSecurityInfo
> +#
> +# Since: 10.3
>

11.1


> +##
> +{ 'command': 'guest-get-windows-security-info',
> +  'returns': 'GuestWindowsSecurityInfo',
> +  'if': 'CONFIG_WIN32' }
> --
> 2.51.0
>
>

[-- Attachment #2: Type: text/html, Size: 21317 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] qga: add guest-get-windows-security-info command
  2026-03-17 14:07 ` Kostiantyn Kostiuk
@ 2026-03-17 14:15   ` Daniel P. Berrangé
  2026-03-17 14:45     ` Kostiantyn Kostiuk
  0 siblings, 1 reply; 8+ messages in thread
From: Daniel P. Berrangé @ 2026-03-17 14:15 UTC (permalink / raw)
  To: Kostiantyn Kostiuk
  Cc: Elizabeth Ashurov, qemu-devel, Marc-André Lureau,
	Yan Vugenfirer

On Tue, Mar 17, 2026 at 04:07:59PM +0200, Kostiantyn Kostiuk wrote:
> On Mon, Mar 16, 2026 at 2:32 PM Elizabeth Ashurov <eashurov@redhat.com>
> wrote:
> 
> > Add a new Windows-only QGA command to retrieve Windows security
> > features status including VBS, Secure Boot, and TPM information
> > from the guest.
> >
> > The implementation queries Win32_DeviceGuard and Win32_Tpm via
> > WMI, and reads the SecureBoot UEFI variable through
> > GetFirmwareEnvironmentVariable().
> >
> > Signed-off-by: Elizabeth Ashurov <eashurov@redhat.com>
> > ---
> >  qga/commands-win32.c | 404 +++++++++++++++++++++++++++++++++++++++++++
> >  qga/qapi-schema.json |  56 ++++++
> >  2 files changed, 460 insertions(+)

snip

> > diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
> > index c57bc9a02f..f54fdf942f 100644
> > --- a/qga/qapi-schema.json
> > +++ b/qga/qapi-schema.json
> > @@ -1952,3 +1952,59 @@
> >    'returns': ['GuestNetworkRoute'],
> >    'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] }
> >  }
> > +
> > +##
> > +# @GuestWindowsSecurityInfo:
> > +#
> > +# Windows security features status.
> > +#
> > +# @vbs-status: VirtualizationBasedSecurityStatus
> > +#
> > +# @available-security-properties: AvailableSecurityProperties
> > +#
> > +# @code-integrity-policy-enforcement-status:
> > +#     CodeIntegrityPolicyEnforcementStatus
> > +#
> > +# @required-security-properties: RequiredSecurityProperties
> > +#
> > +# @security-services-configured: SecurityServicesConfigured
> > +#
> > +# @security-services-running: SecurityServicesRunning
> > +#
> > +# @usr-cfg-code-integrity-policy-enforcement-status:
> > +#     UsermodeCodeIntegrityPolicyEnforcementStatus
> > +#
> > +# @secure-boot: Whether UEFI Secure Boot is enabled
> > +#
> > +# @tpm-present: Whether a TPM device is present
> > +#
> > +# @tpm-version: TPM specification version string (e.g. "2.0")
> > +#
> > +# Since: 10.3
> > +##
> > +{ 'struct': 'GuestWindowsSecurityInfo',
> > +  'data': {
> > +      'vbs-status': 'int',
> > +      '*available-security-properties': ['int'],
> > +      '*code-integrity-policy-enforcement-status': 'int',
> > +      '*required-security-properties': ['int'],
> > +      '*security-services-configured': ['int'],
> > +      '*security-services-running': ['int'],
> > +      '*usr-cfg-code-integrity-policy-enforcement-status': 'int',
> > +      'secure-boot': 'bool',
> > +      'tpm-present': 'bool',
> > +      '*tpm-version': 'str' },
> > +  'if': 'CONFIG_WIN32' }
> >
> >
> Let's make this more generic
> command guest-get-security-info
> use 'union' to describe OS specific option like VBS
> { 'tmp_present': false, 'secure_boot': true, 'os': { 'type': 'windows',
> 'vbs': false, .... } }
> 
> make tmp_present, secure_boot, vbs_status optiononal
> missing = unknown - as we can have it unimplemented for some POSIX/BSD OSes
> 
> vbs_status is Win10+ only feature, so it can be unknown for Win8

I wonder if a new command is justifiable / needed.

Should we consider returning more info with 'guest-get-osinfo' ? It
is slightly different from the info returned there currently, but
at the same time reasonably in scope in the sense that it is
essentially reporting a set of OS "feature flags". They happen to
be security related in this case, but we could have other feature
flags we want to report too in future.

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] qga: add guest-get-windows-security-info command
  2026-03-17 14:15   ` Daniel P. Berrangé
@ 2026-03-17 14:45     ` Kostiantyn Kostiuk
  2026-03-17 14:58       ` Daniel P. Berrangé
  0 siblings, 1 reply; 8+ messages in thread
From: Kostiantyn Kostiuk @ 2026-03-17 14:45 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Elizabeth Ashurov, qemu-devel, Marc-André Lureau,
	Yan Vugenfirer

[-- Attachment #1: Type: text/plain, Size: 4245 bytes --]

On Tue, Mar 17, 2026 at 4:15 PM Daniel P. Berrangé <berrange@redhat.com>
wrote:

> On Tue, Mar 17, 2026 at 04:07:59PM +0200, Kostiantyn Kostiuk wrote:
> > On Mon, Mar 16, 2026 at 2:32 PM Elizabeth Ashurov <eashurov@redhat.com>
> > wrote:
> >
> > > Add a new Windows-only QGA command to retrieve Windows security
> > > features status including VBS, Secure Boot, and TPM information
> > > from the guest.
> > >
> > > The implementation queries Win32_DeviceGuard and Win32_Tpm via
> > > WMI, and reads the SecureBoot UEFI variable through
> > > GetFirmwareEnvironmentVariable().
> > >
> > > Signed-off-by: Elizabeth Ashurov <eashurov@redhat.com>
> > > ---
> > >  qga/commands-win32.c | 404 +++++++++++++++++++++++++++++++++++++++++++
> > >  qga/qapi-schema.json |  56 ++++++
> > >  2 files changed, 460 insertions(+)
>
> snip
>
> > > diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
> > > index c57bc9a02f..f54fdf942f 100644
> > > --- a/qga/qapi-schema.json
> > > +++ b/qga/qapi-schema.json
> > > @@ -1952,3 +1952,59 @@
> > >    'returns': ['GuestNetworkRoute'],
> > >    'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] }
> > >  }
> > > +
> > > +##
> > > +# @GuestWindowsSecurityInfo:
> > > +#
> > > +# Windows security features status.
> > > +#
> > > +# @vbs-status: VirtualizationBasedSecurityStatus
> > > +#
> > > +# @available-security-properties: AvailableSecurityProperties
> > > +#
> > > +# @code-integrity-policy-enforcement-status:
> > > +#     CodeIntegrityPolicyEnforcementStatus
> > > +#
> > > +# @required-security-properties: RequiredSecurityProperties
> > > +#
> > > +# @security-services-configured: SecurityServicesConfigured
> > > +#
> > > +# @security-services-running: SecurityServicesRunning
> > > +#
> > > +# @usr-cfg-code-integrity-policy-enforcement-status:
> > > +#     UsermodeCodeIntegrityPolicyEnforcementStatus
> > > +#
> > > +# @secure-boot: Whether UEFI Secure Boot is enabled
> > > +#
> > > +# @tpm-present: Whether a TPM device is present
> > > +#
> > > +# @tpm-version: TPM specification version string (e.g. "2.0")
> > > +#
> > > +# Since: 10.3
> > > +##
> > > +{ 'struct': 'GuestWindowsSecurityInfo',
> > > +  'data': {
> > > +      'vbs-status': 'int',
> > > +      '*available-security-properties': ['int'],
> > > +      '*code-integrity-policy-enforcement-status': 'int',
> > > +      '*required-security-properties': ['int'],
> > > +      '*security-services-configured': ['int'],
> > > +      '*security-services-running': ['int'],
> > > +      '*usr-cfg-code-integrity-policy-enforcement-status': 'int',
> > > +      'secure-boot': 'bool',
> > > +      'tpm-present': 'bool',
> > > +      '*tpm-version': 'str' },
> > > +  'if': 'CONFIG_WIN32' }
> > >
> > >
> > Let's make this more generic
> > command guest-get-security-info
> > use 'union' to describe OS specific option like VBS
> > { 'tmp_present': false, 'secure_boot': true, 'os': { 'type': 'windows',
> > 'vbs': false, .... } }
> >
> > make tmp_present, secure_boot, vbs_status optiononal
> > missing = unknown - as we can have it unimplemented for some POSIX/BSD
> OSes
> >
> > vbs_status is Win10+ only feature, so it can be unknown for Win8
>
> I wonder if a new command is justifiable / needed.
>
> Should we consider returning more info with 'guest-get-osinfo' ? It
> is slightly different from the info returned there currently, but
> at the same time reasonably in scope in the sense that it is
> essentially reporting a set of OS "feature flags". They happen to
> be security related in this case, but we could have other feature
> flags we want to report too in future.
>

guest-get-security-info can fail due to WMI issue. If we merge this into
guest-get-osinfo,
it means guest-get-osinfo will fail just because of a Windows component
error. Sounds bad.
Currently, guest-get-osinfo uses a very stable API.

Best Regards,
Kostiantyn Kostiuk.


>
> With regards,
> Daniel
> --
> |: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
> |: https://libvirt.org          ~~          https://entangle-photo.org :|
> |: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|
>
>

[-- Attachment #2: Type: text/html, Size: 6493 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] qga: add guest-get-windows-security-info command
  2026-03-17 14:45     ` Kostiantyn Kostiuk
@ 2026-03-17 14:58       ` Daniel P. Berrangé
  2026-03-17 16:35         ` Kostiantyn Kostiuk
  0 siblings, 1 reply; 8+ messages in thread
From: Daniel P. Berrangé @ 2026-03-17 14:58 UTC (permalink / raw)
  To: Kostiantyn Kostiuk
  Cc: Elizabeth Ashurov, qemu-devel, Marc-André Lureau,
	Yan Vugenfirer

On Tue, Mar 17, 2026 at 04:45:20PM +0200, Kostiantyn Kostiuk wrote:
> On Tue, Mar 17, 2026 at 4:15 PM Daniel P. Berrangé <berrange@redhat.com>
> wrote:
> 
> > On Tue, Mar 17, 2026 at 04:07:59PM +0200, Kostiantyn Kostiuk wrote:
> > > On Mon, Mar 16, 2026 at 2:32 PM Elizabeth Ashurov <eashurov@redhat.com>
> > > wrote:
> > >
> > > > Add a new Windows-only QGA command to retrieve Windows security
> > > > features status including VBS, Secure Boot, and TPM information
> > > > from the guest.
> > > >
> > > > The implementation queries Win32_DeviceGuard and Win32_Tpm via
> > > > WMI, and reads the SecureBoot UEFI variable through
> > > > GetFirmwareEnvironmentVariable().
> > > >
> > > > Signed-off-by: Elizabeth Ashurov <eashurov@redhat.com>
> > > > ---
> > > >  qga/commands-win32.c | 404 +++++++++++++++++++++++++++++++++++++++++++
> > > >  qga/qapi-schema.json |  56 ++++++
> > > >  2 files changed, 460 insertions(+)
> >
> > snip
> >
> > > > diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
> > > > index c57bc9a02f..f54fdf942f 100644
> > > > --- a/qga/qapi-schema.json
> > > > +++ b/qga/qapi-schema.json
> > > > @@ -1952,3 +1952,59 @@
> > > >    'returns': ['GuestNetworkRoute'],
> > > >    'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] }
> > > >  }
> > > > +
> > > > +##
> > > > +# @GuestWindowsSecurityInfo:
> > > > +#
> > > > +# Windows security features status.
> > > > +#
> > > > +# @vbs-status: VirtualizationBasedSecurityStatus
> > > > +#
> > > > +# @available-security-properties: AvailableSecurityProperties
> > > > +#
> > > > +# @code-integrity-policy-enforcement-status:
> > > > +#     CodeIntegrityPolicyEnforcementStatus
> > > > +#
> > > > +# @required-security-properties: RequiredSecurityProperties
> > > > +#
> > > > +# @security-services-configured: SecurityServicesConfigured
> > > > +#
> > > > +# @security-services-running: SecurityServicesRunning
> > > > +#
> > > > +# @usr-cfg-code-integrity-policy-enforcement-status:
> > > > +#     UsermodeCodeIntegrityPolicyEnforcementStatus
> > > > +#
> > > > +# @secure-boot: Whether UEFI Secure Boot is enabled
> > > > +#
> > > > +# @tpm-present: Whether a TPM device is present
> > > > +#
> > > > +# @tpm-version: TPM specification version string (e.g. "2.0")
> > > > +#
> > > > +# Since: 10.3
> > > > +##
> > > > +{ 'struct': 'GuestWindowsSecurityInfo',
> > > > +  'data': {
> > > > +      'vbs-status': 'int',
> > > > +      '*available-security-properties': ['int'],
> > > > +      '*code-integrity-policy-enforcement-status': 'int',
> > > > +      '*required-security-properties': ['int'],
> > > > +      '*security-services-configured': ['int'],
> > > > +      '*security-services-running': ['int'],
> > > > +      '*usr-cfg-code-integrity-policy-enforcement-status': 'int',
> > > > +      'secure-boot': 'bool',
> > > > +      'tpm-present': 'bool',
> > > > +      '*tpm-version': 'str' },
> > > > +  'if': 'CONFIG_WIN32' }
> > > >
> > > >
> > > Let's make this more generic
> > > command guest-get-security-info
> > > use 'union' to describe OS specific option like VBS
> > > { 'tmp_present': false, 'secure_boot': true, 'os': { 'type': 'windows',
> > > 'vbs': false, .... } }
> > >
> > > make tmp_present, secure_boot, vbs_status optiononal
> > > missing = unknown - as we can have it unimplemented for some POSIX/BSD
> > OSes
> > >
> > > vbs_status is Win10+ only feature, so it can be unknown for Win8
> >
> > I wonder if a new command is justifiable / needed.
> >
> > Should we consider returning more info with 'guest-get-osinfo' ? It
> > is slightly different from the info returned there currently, but
> > at the same time reasonably in scope in the sense that it is
> > essentially reporting a set of OS "feature flags". They happen to
> > be security related in this case, but we could have other feature
> > flags we want to report too in future.
> >
> 
> guest-get-security-info can fail due to WMI issue. If we merge this into
> guest-get-osinfo,
> it means guest-get-osinfo will fail just because of a Windows component
> error. Sounds bad.

In what scenarios would WMI fail, and should we treat that as non-fatal
regardless ? ie indicate that the information is unavailable - that
already appears to be done for the TPM feature, but not the other
security features.

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] qga: add guest-get-windows-security-info command
  2026-03-17 14:58       ` Daniel P. Berrangé
@ 2026-03-17 16:35         ` Kostiantyn Kostiuk
  2026-03-18 12:38           ` Yan Vugenfirer
  0 siblings, 1 reply; 8+ messages in thread
From: Kostiantyn Kostiuk @ 2026-03-17 16:35 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Elizabeth Ashurov, qemu-devel, Marc-André Lureau,
	Yan Vugenfirer

[-- Attachment #1: Type: text/plain, Size: 5193 bytes --]

On Tue, Mar 17, 2026 at 4:58 PM Daniel P. Berrangé <berrange@redhat.com>
wrote:

> On Tue, Mar 17, 2026 at 04:45:20PM +0200, Kostiantyn Kostiuk wrote:
> > On Tue, Mar 17, 2026 at 4:15 PM Daniel P. Berrangé <berrange@redhat.com>
> > wrote:
> >
> > > On Tue, Mar 17, 2026 at 04:07:59PM +0200, Kostiantyn Kostiuk wrote:
> > > > On Mon, Mar 16, 2026 at 2:32 PM Elizabeth Ashurov <
> eashurov@redhat.com>
> > > > wrote:
> > > >
> > > > > Add a new Windows-only QGA command to retrieve Windows security
> > > > > features status including VBS, Secure Boot, and TPM information
> > > > > from the guest.
> > > > >
> > > > > The implementation queries Win32_DeviceGuard and Win32_Tpm via
> > > > > WMI, and reads the SecureBoot UEFI variable through
> > > > > GetFirmwareEnvironmentVariable().
> > > > >
> > > > > Signed-off-by: Elizabeth Ashurov <eashurov@redhat.com>
> > > > > ---
> > > > >  qga/commands-win32.c | 404
> +++++++++++++++++++++++++++++++++++++++++++
> > > > >  qga/qapi-schema.json |  56 ++++++
> > > > >  2 files changed, 460 insertions(+)
> > >
> > > snip
> > >
> > > > > diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
> > > > > index c57bc9a02f..f54fdf942f 100644
> > > > > --- a/qga/qapi-schema.json
> > > > > +++ b/qga/qapi-schema.json
> > > > > @@ -1952,3 +1952,59 @@
> > > > >    'returns': ['GuestNetworkRoute'],
> > > > >    'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] }
> > > > >  }
> > > > > +
> > > > > +##
> > > > > +# @GuestWindowsSecurityInfo:
> > > > > +#
> > > > > +# Windows security features status.
> > > > > +#
> > > > > +# @vbs-status: VirtualizationBasedSecurityStatus
> > > > > +#
> > > > > +# @available-security-properties: AvailableSecurityProperties
> > > > > +#
> > > > > +# @code-integrity-policy-enforcement-status:
> > > > > +#     CodeIntegrityPolicyEnforcementStatus
> > > > > +#
> > > > > +# @required-security-properties: RequiredSecurityProperties
> > > > > +#
> > > > > +# @security-services-configured: SecurityServicesConfigured
> > > > > +#
> > > > > +# @security-services-running: SecurityServicesRunning
> > > > > +#
> > > > > +# @usr-cfg-code-integrity-policy-enforcement-status:
> > > > > +#     UsermodeCodeIntegrityPolicyEnforcementStatus
> > > > > +#
> > > > > +# @secure-boot: Whether UEFI Secure Boot is enabled
> > > > > +#
> > > > > +# @tpm-present: Whether a TPM device is present
> > > > > +#
> > > > > +# @tpm-version: TPM specification version string (e.g. "2.0")
> > > > > +#
> > > > > +# Since: 10.3
> > > > > +##
> > > > > +{ 'struct': 'GuestWindowsSecurityInfo',
> > > > > +  'data': {
> > > > > +      'vbs-status': 'int',
> > > > > +      '*available-security-properties': ['int'],
> > > > > +      '*code-integrity-policy-enforcement-status': 'int',
> > > > > +      '*required-security-properties': ['int'],
> > > > > +      '*security-services-configured': ['int'],
> > > > > +      '*security-services-running': ['int'],
> > > > > +      '*usr-cfg-code-integrity-policy-enforcement-status': 'int',
> > > > > +      'secure-boot': 'bool',
> > > > > +      'tpm-present': 'bool',
> > > > > +      '*tpm-version': 'str' },
> > > > > +  'if': 'CONFIG_WIN32' }
> > > > >
> > > > >
> > > > Let's make this more generic
> > > > command guest-get-security-info
> > > > use 'union' to describe OS specific option like VBS
> > > > { 'tmp_present': false, 'secure_boot': true, 'os': { 'type':
> 'windows',
> > > > 'vbs': false, .... } }
> > > >
> > > > make tmp_present, secure_boot, vbs_status optiononal
> > > > missing = unknown - as we can have it unimplemented for some
> POSIX/BSD
> > > OSes
> > > >
> > > > vbs_status is Win10+ only feature, so it can be unknown for Win8
> > >
> > > I wonder if a new command is justifiable / needed.
> > >
> > > Should we consider returning more info with 'guest-get-osinfo' ? It
> > > is slightly different from the info returned there currently, but
> > > at the same time reasonably in scope in the sense that it is
> > > essentially reporting a set of OS "feature flags". They happen to
> > > be security related in this case, but we could have other feature
> > > flags we want to report too in future.
> > >
> >
> > guest-get-security-info can fail due to WMI issue. If we merge this into
> > guest-get-osinfo,
> > it means guest-get-osinfo will fail just because of a Windows component
> > error. Sounds bad.
>
> In what scenarios would WMI fail, and should we treat that as non-fatal
> regardless ? ie indicate that the information is unavailable - that
> already appears to be done for the TPM feature, but not the other
> security features.
>

Simple WMI fail - disable WMI service
From my experience - WMI DB was broken after 3rd-party software
installation / after Windows Update

>should we treat that as non-fatal regardless ?

I am open to discussion.


> With regards,
> Daniel
> --
> |: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
> |: https://libvirt.org          ~~          https://entangle-photo.org :|
> |: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|
>
>

[-- Attachment #2: Type: text/html, Size: 8117 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] qga: add guest-get-windows-security-info command
  2026-03-17 16:35         ` Kostiantyn Kostiuk
@ 2026-03-18 12:38           ` Yan Vugenfirer
  2026-03-18 12:41             ` Daniel P. Berrangé
  0 siblings, 1 reply; 8+ messages in thread
From: Yan Vugenfirer @ 2026-03-18 12:38 UTC (permalink / raw)
  To: Kostiantyn Kostiuk
  Cc: Daniel P. Berrangé, Elizabeth Ashurov, qemu-devel,
	Marc-André Lureau

[-- Attachment #1: Type: text/plain, Size: 5579 bytes --]

On Tue, Mar 17, 2026 at 6:35 PM Kostiantyn Kostiuk <kkostiuk@redhat.com>
wrote:

>
>
>
>
> On Tue, Mar 17, 2026 at 4:58 PM Daniel P. Berrangé <berrange@redhat.com>
> wrote:
>
>> On Tue, Mar 17, 2026 at 04:45:20PM +0200, Kostiantyn Kostiuk wrote:
>> > On Tue, Mar 17, 2026 at 4:15 PM Daniel P. Berrangé <berrange@redhat.com
>> >
>> > wrote:
>> >
>> > > On Tue, Mar 17, 2026 at 04:07:59PM +0200, Kostiantyn Kostiuk wrote:
>> > > > On Mon, Mar 16, 2026 at 2:32 PM Elizabeth Ashurov <
>> eashurov@redhat.com>
>> > > > wrote:
>> > > >
>> > > > > Add a new Windows-only QGA command to retrieve Windows security
>> > > > > features status including VBS, Secure Boot, and TPM information
>> > > > > from the guest.
>> > > > >
>> > > > > The implementation queries Win32_DeviceGuard and Win32_Tpm via
>> > > > > WMI, and reads the SecureBoot UEFI variable through
>> > > > > GetFirmwareEnvironmentVariable().
>> > > > >
>> > > > > Signed-off-by: Elizabeth Ashurov <eashurov@redhat.com>
>> > > > > ---
>> > > > >  qga/commands-win32.c | 404
>> +++++++++++++++++++++++++++++++++++++++++++
>> > > > >  qga/qapi-schema.json |  56 ++++++
>> > > > >  2 files changed, 460 insertions(+)
>> > >
>> > > snip
>> > >
>> > > > > diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
>> > > > > index c57bc9a02f..f54fdf942f 100644
>> > > > > --- a/qga/qapi-schema.json
>> > > > > +++ b/qga/qapi-schema.json
>> > > > > @@ -1952,3 +1952,59 @@
>> > > > >    'returns': ['GuestNetworkRoute'],
>> > > > >    'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] }
>> > > > >  }
>> > > > > +
>> > > > > +##
>> > > > > +# @GuestWindowsSecurityInfo:
>> > > > > +#
>> > > > > +# Windows security features status.
>> > > > > +#
>> > > > > +# @vbs-status: VirtualizationBasedSecurityStatus
>> > > > > +#
>> > > > > +# @available-security-properties: AvailableSecurityProperties
>> > > > > +#
>> > > > > +# @code-integrity-policy-enforcement-status:
>> > > > > +#     CodeIntegrityPolicyEnforcementStatus
>> > > > > +#
>> > > > > +# @required-security-properties: RequiredSecurityProperties
>> > > > > +#
>> > > > > +# @security-services-configured: SecurityServicesConfigured
>> > > > > +#
>> > > > > +# @security-services-running: SecurityServicesRunning
>> > > > > +#
>> > > > > +# @usr-cfg-code-integrity-policy-enforcement-status:
>> > > > > +#     UsermodeCodeIntegrityPolicyEnforcementStatus
>> > > > > +#
>> > > > > +# @secure-boot: Whether UEFI Secure Boot is enabled
>> > > > > +#
>> > > > > +# @tpm-present: Whether a TPM device is present
>> > > > > +#
>> > > > > +# @tpm-version: TPM specification version string (e.g. "2.0")
>> > > > > +#
>> > > > > +# Since: 10.3
>> > > > > +##
>> > > > > +{ 'struct': 'GuestWindowsSecurityInfo',
>> > > > > +  'data': {
>> > > > > +      'vbs-status': 'int',
>> > > > > +      '*available-security-properties': ['int'],
>> > > > > +      '*code-integrity-policy-enforcement-status': 'int',
>> > > > > +      '*required-security-properties': ['int'],
>> > > > > +      '*security-services-configured': ['int'],
>> > > > > +      '*security-services-running': ['int'],
>> > > > > +      '*usr-cfg-code-integrity-policy-enforcement-status': 'int',
>> > > > > +      'secure-boot': 'bool',
>> > > > > +      'tpm-present': 'bool',
>> > > > > +      '*tpm-version': 'str' },
>> > > > > +  'if': 'CONFIG_WIN32' }
>> > > > >
>> > > > >
>> > > > Let's make this more generic
>> > > > command guest-get-security-info
>> > > > use 'union' to describe OS specific option like VBS
>> > > > { 'tmp_present': false, 'secure_boot': true, 'os': { 'type':
>> 'windows',
>> > > > 'vbs': false, .... } }
>> > > >
>> > > > make tmp_present, secure_boot, vbs_status optiononal
>> > > > missing = unknown - as we can have it unimplemented for some
>> POSIX/BSD
>> > > OSes
>> > > >
>> > > > vbs_status is Win10+ only feature, so it can be unknown for Win8
>> > >
>> > > I wonder if a new command is justifiable / needed.
>> > >
>> > > Should we consider returning more info with 'guest-get-osinfo' ? It
>> > > is slightly different from the info returned there currently, but
>> > > at the same time reasonably in scope in the sense that it is
>> > > essentially reporting a set of OS "feature flags". They happen to
>> > > be security related in this case, but we could have other feature
>> > > flags we want to report too in future.
>> > >
>> >
>> > guest-get-security-info can fail due to WMI issue. If we merge this into
>> > guest-get-osinfo,
>> > it means guest-get-osinfo will fail just because of a Windows component
>> > error. Sounds bad.
>>
>> In what scenarios would WMI fail, and should we treat that as non-fatal
>> regardless ? ie indicate that the information is unavailable - that
>> already appears to be done for the TPM feature, but not the other
>> security features.
>>
>
>
How the managment layer will distingiush between the failure and old guest
agent that cannot return any data?

Best regards,
Yan.


> Simple WMI fail - disable WMI service
> From my experience - WMI DB was broken after 3rd-party software
> installation / after Windows Update
>
> >should we treat that as non-fatal regardless ?
>
> I am open to discussion.
>
>
>> With regards,
>> Daniel
>> --
>> |: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
>> |: https://libvirt.org          ~~          https://entangle-photo.org :|
>> |: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|
>>
>>

[-- Attachment #2: Type: text/html, Size: 9089 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] qga: add guest-get-windows-security-info command
  2026-03-18 12:38           ` Yan Vugenfirer
@ 2026-03-18 12:41             ` Daniel P. Berrangé
  0 siblings, 0 replies; 8+ messages in thread
From: Daniel P. Berrangé @ 2026-03-18 12:41 UTC (permalink / raw)
  To: Yan Vugenfirer
  Cc: Kostiantyn Kostiuk, Elizabeth Ashurov, qemu-devel,
	Marc-André Lureau

On Wed, Mar 18, 2026 at 02:38:16PM +0200, Yan Vugenfirer wrote:
> On Tue, Mar 17, 2026 at 6:35 PM Kostiantyn Kostiuk <kkostiuk@redhat.com>
> wrote:
> 
> >
> >
> >
> >
> > On Tue, Mar 17, 2026 at 4:58 PM Daniel P. Berrangé <berrange@redhat.com>
> > wrote:
> >
> >> On Tue, Mar 17, 2026 at 04:45:20PM +0200, Kostiantyn Kostiuk wrote:
> >> > On Tue, Mar 17, 2026 at 4:15 PM Daniel P. Berrangé <berrange@redhat.com
> >> >
> >> > wrote:
> >> >
> >> > > On Tue, Mar 17, 2026 at 04:07:59PM +0200, Kostiantyn Kostiuk wrote:
> >> > > > On Mon, Mar 16, 2026 at 2:32 PM Elizabeth Ashurov <
> >> eashurov@redhat.com>
> >> > > > wrote:
> >> > > >
> >> > > > > Add a new Windows-only QGA command to retrieve Windows security
> >> > > > > features status including VBS, Secure Boot, and TPM information
> >> > > > > from the guest.
> >> > > > >
> >> > > > > The implementation queries Win32_DeviceGuard and Win32_Tpm via
> >> > > > > WMI, and reads the SecureBoot UEFI variable through
> >> > > > > GetFirmwareEnvironmentVariable().
> >> > > > >
> >> > > > > Signed-off-by: Elizabeth Ashurov <eashurov@redhat.com>
> >> > > > > ---
> >> > > > >  qga/commands-win32.c | 404
> >> +++++++++++++++++++++++++++++++++++++++++++
> >> > > > >  qga/qapi-schema.json |  56 ++++++
> >> > > > >  2 files changed, 460 insertions(+)
> >> > >
> >> > > snip
> >> > >
> >> > > > > diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
> >> > > > > index c57bc9a02f..f54fdf942f 100644
> >> > > > > --- a/qga/qapi-schema.json
> >> > > > > +++ b/qga/qapi-schema.json
> >> > > > > @@ -1952,3 +1952,59 @@
> >> > > > >    'returns': ['GuestNetworkRoute'],
> >> > > > >    'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] }
> >> > > > >  }
> >> > > > > +
> >> > > > > +##
> >> > > > > +# @GuestWindowsSecurityInfo:
> >> > > > > +#
> >> > > > > +# Windows security features status.
> >> > > > > +#
> >> > > > > +# @vbs-status: VirtualizationBasedSecurityStatus
> >> > > > > +#
> >> > > > > +# @available-security-properties: AvailableSecurityProperties
> >> > > > > +#
> >> > > > > +# @code-integrity-policy-enforcement-status:
> >> > > > > +#     CodeIntegrityPolicyEnforcementStatus
> >> > > > > +#
> >> > > > > +# @required-security-properties: RequiredSecurityProperties
> >> > > > > +#
> >> > > > > +# @security-services-configured: SecurityServicesConfigured
> >> > > > > +#
> >> > > > > +# @security-services-running: SecurityServicesRunning
> >> > > > > +#
> >> > > > > +# @usr-cfg-code-integrity-policy-enforcement-status:
> >> > > > > +#     UsermodeCodeIntegrityPolicyEnforcementStatus
> >> > > > > +#
> >> > > > > +# @secure-boot: Whether UEFI Secure Boot is enabled
> >> > > > > +#
> >> > > > > +# @tpm-present: Whether a TPM device is present
> >> > > > > +#
> >> > > > > +# @tpm-version: TPM specification version string (e.g. "2.0")
> >> > > > > +#
> >> > > > > +# Since: 10.3
> >> > > > > +##
> >> > > > > +{ 'struct': 'GuestWindowsSecurityInfo',
> >> > > > > +  'data': {
> >> > > > > +      'vbs-status': 'int',
> >> > > > > +      '*available-security-properties': ['int'],
> >> > > > > +      '*code-integrity-policy-enforcement-status': 'int',
> >> > > > > +      '*required-security-properties': ['int'],
> >> > > > > +      '*security-services-configured': ['int'],
> >> > > > > +      '*security-services-running': ['int'],
> >> > > > > +      '*usr-cfg-code-integrity-policy-enforcement-status': 'int',
> >> > > > > +      'secure-boot': 'bool',
> >> > > > > +      'tpm-present': 'bool',
> >> > > > > +      '*tpm-version': 'str' },
> >> > > > > +  'if': 'CONFIG_WIN32' }
> >> > > > >
> >> > > > >
> >> > > > Let's make this more generic
> >> > > > command guest-get-security-info
> >> > > > use 'union' to describe OS specific option like VBS
> >> > > > { 'tmp_present': false, 'secure_boot': true, 'os': { 'type':
> >> 'windows',
> >> > > > 'vbs': false, .... } }
> >> > > >
> >> > > > make tmp_present, secure_boot, vbs_status optiononal
> >> > > > missing = unknown - as we can have it unimplemented for some
> >> POSIX/BSD
> >> > > OSes
> >> > > >
> >> > > > vbs_status is Win10+ only feature, so it can be unknown for Win8
> >> > >
> >> > > I wonder if a new command is justifiable / needed.
> >> > >
> >> > > Should we consider returning more info with 'guest-get-osinfo' ? It
> >> > > is slightly different from the info returned there currently, but
> >> > > at the same time reasonably in scope in the sense that it is
> >> > > essentially reporting a set of OS "feature flags". They happen to
> >> > > be security related in this case, but we could have other feature
> >> > > flags we want to report too in future.
> >> > >
> >> >
> >> > guest-get-security-info can fail due to WMI issue. If we merge this into
> >> > guest-get-osinfo,
> >> > it means guest-get-osinfo will fail just because of a Windows component
> >> > error. Sounds bad.
> >>
> >> In what scenarios would WMI fail, and should we treat that as non-fatal
> >> regardless ? ie indicate that the information is unavailable - that
> >> already appears to be done for the TPM feature, but not the other
> >> security features.
> >>
> >
>
> How the managment layer will distingiush between the failure and old guest
> agent that cannot return any data?

That's why we need to indicate "unavailable" as a distinct state.

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-03-18 12:41 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-16 12:31 [PATCH v1] qga: add guest-get-windows-security-info command Elizabeth Ashurov
2026-03-17 14:07 ` Kostiantyn Kostiuk
2026-03-17 14:15   ` Daniel P. Berrangé
2026-03-17 14:45     ` Kostiantyn Kostiuk
2026-03-17 14:58       ` Daniel P. Berrangé
2026-03-17 16:35         ` Kostiantyn Kostiuk
2026-03-18 12:38           ` Yan Vugenfirer
2026-03-18 12:41             ` Daniel P. Berrangé

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox