Reviewed-by: Kostiantyn Kostiuk <[email protected]>

On Wed, Feb 11, 2026 at 12:18 PM Elizabeth Ashurov <[email protected]>
wrote:

> Problem:
> Two issues with COM initialization:
>
> Issue #1: Incorrect call order
> - requester_init() called CoInitializeSecurity first
> - Per Microsoft documentation, CoInitialize() must be called BEFORE
>   CoInitializeSecurity()
>
> Issue #2: Incorrect call location
> - CoInitializeSecurity was called from dll instead of the main process
> - Per Microsoft documentation, CoInitializeSecurity() must be called
> exactly once per process from
>   the main executable, not from a DLL
>
> Reference:
>
> https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializesecurity
>
> https://learn.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize
>
> This caused incorrect COM initialization, preventing VSS Writers from
> calling back via IVssWriterCallback (hr = 0x80070005, Access denied,
> Event ID 8194).
>
> Fix:
> - Initialize COM in main.c for both service and CLI modes
> - Call CoInitialize() followed by CoInitializeSecurity() in correct order
>   in the main thread before any VSS operations
> - Add proper CoUninitialize() cleanup
>
> Result:
> VSS Writers can now successfully call back to the agent. Event ID 8194
> error is resolved.
>
> Signed-off-by: Elizabeth Ashurov <[email protected]>
> ---
>  qga/main.c                  | 42 +++++++++++++++++++++++++++++++++++++
>  qga/vss-win32/requester.cpp | 13 ------------
>  2 files changed, 42 insertions(+), 13 deletions(-)
>
> diff --git a/qga/main.c b/qga/main.c
> index dd1c216f9a..fd19c7037d 100644
> --- a/qga/main.c
> +++ b/qga/main.c
> @@ -32,6 +32,8 @@
>  #include "qemu/systemd.h"
>  #include "qemu-version.h"
>  #ifdef _WIN32
> +#include <windows.h>
> +#include <objbase.h>
>  #include <dbt.h>
>  #include <pdh.h>
>  #include "qga/service-win32.h"
> @@ -830,6 +832,29 @@ DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD
> type, LPVOID data,
>      return ret;
>  }
>
> +/* Initialize COM for VSS operations */
> +static HRESULT init_com(void)
> +{
> +    HRESULT hr;
> +
> +    hr = CoInitialize(NULL);
> +    if (FAILED(hr)) {
> +        return hr;
> +    }
> +
> +    hr = CoInitializeSecurity(
> +        NULL, -1, NULL, NULL,
> +        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
> +        RPC_C_IMP_LEVEL_IDENTIFY,
> +        NULL, EOAC_NONE, NULL);
> +    if (FAILED(hr)) {
> +        CoUninitialize();
> +        return hr;
> +    }
> +
> +    return S_OK;
> +}
> +
>  VOID WINAPI service_main(DWORD argc, TCHAR *argv[])
>  {
>      GAService *service = &ga_state->service;
> @@ -842,6 +867,13 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[])
>          return;
>      }
>
> +    /* Initialize COM for VSS operations in the service thread */
> +    HRESULT hr_com = init_com();
> +    if (FAILED(hr_com)) {
> +        g_critical("Failed to initialize COM in service thread: 0x%lx",
> hr_com);
> +        return;
> +    }
> +
>      service->status.dwServiceType = SERVICE_WIN32;
>      service->status.dwCurrentState = SERVICE_RUNNING;
>      service->status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
> SERVICE_ACCEPT_SHUTDOWN;
> @@ -866,6 +898,8 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[])
>
>      run_agent(ga_state);
>
> +    CoUninitialize();
> +
>      UnregisterDeviceNotification(service->device_notification_handle);
>      service->status.dwCurrentState = SERVICE_STOPPED;
>      SetServiceStatus(service->status_handle, &service->status);
> @@ -1719,7 +1753,15 @@ int main(int argc, char **argv)
>          StartServiceCtrlDispatcher(service_table);
>          ret = EXIT_SUCCESS;
>      } else {
> +        HRESULT hr_com = init_com();
> +        if (FAILED(hr_com)) {
> +            g_critical("Failed to initialize COM: 0x%lx", hr_com);
> +            ret = EXIT_FAILURE;
> +            goto end;
> +        }
> +
>          ret = run_agent(s);
> +        CoUninitialize();
>      }
>  #else
>      ret = run_agent(s);
> diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp
> index 74489fcd0a..626d6ab1ff 100644
> --- a/qga/vss-win32/requester.cpp
> +++ b/qga/vss-win32/requester.cpp
> @@ -60,15 +60,6 @@ STDAPI requester_init(void)
>  {
>      qga_debug_begin;
>
> -    COMInitializer initializer; /* to call CoInitializeSecurity */
> -    HRESULT hr = CoInitializeSecurity(
> -        NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
> -        RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
> -    if (FAILED(hr)) {
> -        qga_debug("failed to CoInitializeSecurity (error %lx)", hr);
> -        return hr;
> -    }
> -
>      hLib = LoadLibraryA("VSSAPI.DLL");
>      if (!hLib) {
>          qga_debug("failed to load VSSAPI.DLL");
> @@ -320,8 +311,6 @@ void requester_freeze(int *num_vols, void
> *mountpoints, ErrorSet *errset)
>          return;
>      }
>
> -    CoInitialize(NULL);
> -
>      /* Allow unrestricted access to events */
>      InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
>      SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
> @@ -562,7 +551,6 @@ out:
>
>  out1:
>      requester_cleanup();
> -    CoUninitialize();
>
>      qga_debug_end;
>  }
> @@ -643,7 +631,6 @@ void requester_thaw(int *num_vols, void *mountpints,
> ErrorSet *errset)
>      *num_vols = vss_ctx.cFrozenVols;
>      requester_cleanup();
>
> -    CoUninitialize();
>      StopService();
>
>      qga_debug_end;
> --
> 2.51.0
>
>

Reply via email to