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 <[email protected]> --- qga/vss-win32/requester.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp index d36a90c17d1d..1b0155c691ef 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; -- 2.55.0.543.g5ebe2ebe4ea8
