Commit fb2ae6d9ea for qemu.org
commit fb2ae6d9ea26ea26f9a4829183fccd8a222a601b
Author: Marc-André Lureau <marcandre.lureau@redhat.com>
Date: Mon Sep 7 14:50:14 2026 +0400
qga/vss-win32: restrict access to freeze/thaw synchronisation events
The freeze, thaw and timeout events were created with a NULL DACL,
granting unrestricted access. Any local process could open and signal
them, allowing an unprivileged guest process to trigger a filesystem
freeze or premature thaw.
Replace the NULL DACL with an explicit ACL that grants EVENT_ALL_ACCESS
only to SYSTEM and the built-in Administrators group, which are the
accounts under which the VSS service and qemu-ga operate.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Kostiantyn Kostiuk <kkostiuk@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260907-qga-v1-16-86456ad356e2@redhat.com
Signed-off-by: Kostiantyn Kostiuk <kkostiuk@redhat.com>
diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp
index d36a90c17d..1b0155c691 100644
--- a/qga/vss-win32/requester.cpp
+++ b/qga/vss-win32/requester.cpp
@@ -17,6 +17,7 @@
#include "install.h"
#include <vswriter.h>
#include <vsbackup.h>
+#include <aclapi.h>
/* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
#define VSS_TIMEOUT_FREEZE_MSEC 60000
@@ -298,10 +299,14 @@ void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset)
HRESULT hr;
LONG ctx;
GUID guidSnapshotSet = GUID_NULL;
+ SID_IDENTIFIER_AUTHORITY sia_nt = SECURITY_NT_AUTHORITY;
+ PSID pSidSystem = NULL, pSidAdmins = NULL;
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa;
+ EXPLICIT_ACCESS ea[2];
+ PACL pAcl = NULL;
WCHAR short_volume_name[64], *display_name = short_volume_name;
- DWORD wait_status;
+ DWORD wait_status, aclResult;
int num_fixed_drives = 0, i;
int num_mount_points = 0;
VSS_BACKUP_TYPE vss_bt = get_vss_backup_type();
@@ -313,9 +318,48 @@ void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset)
return;
}
- /* Allow unrestricted access to events */
+ /* Grant access to SYSTEM and Administrators only */
+ if (!AllocateAndInitializeSid(&sia_nt, 1,
+ SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
+ &pSidSystem)) {
+ err_set(errset, GetLastError(), "failed to create SYSTEM SID");
+ goto out;
+ }
+ if (!AllocateAndInitializeSid(&sia_nt, 2,
+ SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0, &pSidAdmins)) {
+ DWORD err = GetLastError();
+ FreeSid(pSidSystem);
+ err_set(errset, err, "failed to create Administrators SID");
+ goto out;
+ }
+
+ ZeroMemory(&ea, sizeof(ea));
+ ea[0].grfAccessPermissions = EVENT_ALL_ACCESS;
+ ea[0].grfAccessMode = SET_ACCESS;
+ ea[0].grfInheritance = NO_INHERITANCE;
+ ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
+ ea[0].Trustee.ptstrName = (LPTSTR)pSidSystem;
+ ea[1].grfAccessPermissions = EVENT_ALL_ACCESS;
+ ea[1].grfAccessMode = SET_ACCESS;
+ ea[1].grfInheritance = NO_INHERITANCE;
+ ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
+ ea[1].Trustee.ptstrName = (LPTSTR)pSidAdmins;
+
+ aclResult = SetEntriesInAcl(2, ea, NULL, &pAcl);
+ if (aclResult != ERROR_SUCCESS) {
+ FreeSid(pSidSystem);
+ FreeSid(pSidAdmins);
+ err_set(errset, aclResult, "failed to create ACL for events");
+ goto out;
+ }
+ FreeSid(pSidSystem);
+ FreeSid(pSidAdmins);
+
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
- SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
+ SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE);
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
@@ -551,6 +595,7 @@ void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset)
}
qga_debug("end successful");
+ LocalFree(pAcl);
return;
out:
@@ -559,6 +604,7 @@ out:
}
out1:
+ LocalFree(pAcl);
requester_cleanup();
qga_debug_end;