qga: Move CoInitialize/CoInitializeSecurity to main process thread

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 <eashurov@redhat.com>
Reviewed-by: Kostiantyn Kostiuk <kkostiuk@redhat.com>
Tested-by: Dehan Meng <demeng@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260211101744.757548-1-eashurov@redhat.com
Signed-off-by: Kostiantyn Kostiuk <kkostiuk@redhat.com>
This commit is contained in:
Elizabeth Ashurov
2026-02-11 12:17:43 +02:00
committed by Kostiantyn Kostiuk
parent 595a77289d
commit 0257ec9905
2 changed files with 42 additions and 13 deletions

View File

@@ -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);

View File

@@ -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;