Tested-by: Dehan Meng <[email protected]>

On Wed, Feb 11, 2026 at 6:49 PM Kostiantyn Kostiuk <[email protected]>
wrote:

> 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