1
0
mirror of https://github.com/veracrypt/VeraCrypt.git synced 2025-11-11 02:58:02 -06:00

Windows Setup: Fix "Access Denied" issue during VeraCrypt update after a Windows upgrade

During a Windows upgrade, ownership of veracrypt.sys is set to TrustedInstaller, preventing VeraCrypt from accessing the file during an update.

This commit resolves the issue by temporarily taking ownership of the file to rename it, allowing the new file to be copied. The setup process now obtains additional privileges for this operation, which are properly dropped once the file copying is complete.
This commit is contained in:
Mounir IDRASSI
2024-11-25 00:05:50 +01:00
parent 8ad9e7d769
commit 0c5fcf2286
3 changed files with 256 additions and 2 deletions

View File

@@ -591,18 +591,27 @@ BOOL SaveBufferToFile (const char *inputBuffer, const wchar_t *destinationFile,
DWORD bytesWritten; DWORD bytesWritten;
BOOL res = TRUE; BOOL res = TRUE;
DWORD dwLastError = 0; DWORD dwLastError = 0;
#if defined(SETUP) && !defined (PORTABLE)
BOOL securityModified = FALSE;
SECURITY_INFO_BACKUP secBackup = { 0 };
const wchar_t* existingFile = destinationFile;
#endif
dst = CreateFile (destinationFile, dst = CreateFile (destinationFile,
GENERIC_WRITE, GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, bAppend ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL); FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, bAppend ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL);
dwLastError = GetLastError(); dwLastError = GetLastError();
if (!bAppend && bRenameIfFailed && (dst == INVALID_HANDLE_VALUE) && (GetLastError () == ERROR_SHARING_VIOLATION)) if (!bAppend && bRenameIfFailed && (dst == INVALID_HANDLE_VALUE) && (GetLastError () == ERROR_SHARING_VIOLATION || GetLastError() == ERROR_ACCESS_DENIED))
{ {
wchar_t renamedPath[TC_MAX_PATH + 1]; wchar_t renamedPath[TC_MAX_PATH + 1];
StringCbCopyW (renamedPath, sizeof(renamedPath), destinationFile); StringCbCopyW (renamedPath, sizeof(renamedPath), destinationFile);
StringCbCatW (renamedPath, sizeof(renamedPath), VC_FILENAME_RENAMED_SUFFIX); StringCbCatW (renamedPath, sizeof(renamedPath), VC_FILENAME_RENAMED_SUFFIX);
#if defined(SETUP) && !defined (PORTABLE)
// Take ownership of the file
securityModified = ModifyFileSecurityPermissions(destinationFile, &secBackup);
#endif
/* rename the locked file in order to be able to create a new one */ /* rename the locked file in order to be able to create a new one */
if (MoveFileEx (destinationFile, renamedPath, MOVEFILE_REPLACE_EXISTING)) if (MoveFileEx (destinationFile, renamedPath, MOVEFILE_REPLACE_EXISTING))
{ {
@@ -617,10 +626,20 @@ BOOL SaveBufferToFile (const char *inputBuffer, const wchar_t *destinationFile,
} }
else else
{ {
#if defined(SETUP) && !defined (PORTABLE)
existingFile = renamedPath;
#endif
/* delete the renamed file when the machine reboots */ /* delete the renamed file when the machine reboots */
MoveFileEx (renamedPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); MoveFileEx (renamedPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
} }
} }
#if defined(SETUP) && !defined (PORTABLE)
if (securityModified)
{
RestoreSecurityInfo(existingFile, &secBackup);
FreeSecurityBackup(&secBackup);
}
#endif
} }
if (dst == INVALID_HANDLE_VALUE) if (dst == INVALID_HANDLE_VALUE)
@@ -15762,3 +15781,201 @@ DWORD FastResizeFile (const wchar_t* filePath, __int64 fileSize)
return dwRet; return dwRet;
} }
#endif // VC_COMREG #endif // VC_COMREG
#if defined(SETUP) && !defined (PORTABLE)
// Helper function to save the current state of the required privileges
BOOL SaveCurrentPrivilegeState(PPRIVILEGE_STATE state) {
if (!state) return FALSE;
state->takeOwnership = IsPrivilegeEnabled(SE_TAKE_OWNERSHIP_NAME);
state->backup = IsPrivilegeEnabled(SE_BACKUP_NAME);
state->restore = IsPrivilegeEnabled(SE_RESTORE_NAME);
return TRUE;
}
// Helper function to restore the saved state of the required privileges
BOOL RestorePrivilegeState(const PPRIVILEGE_STATE state) {
if (!state) return FALSE;
BOOL result = TRUE;
result &= SetPrivilege(SE_TAKE_OWNERSHIP_NAME, state->takeOwnership);
result &= SetPrivilege(SE_BACKUP_NAME, state->backup);
result &= SetPrivilege(SE_RESTORE_NAME, state->restore);
return result;
}
// Helper function to enable required privileges for file operations
BOOL EnableRequiredSetupPrivileges(PPRIVILEGE_STATE currentState)
{
BOOL result = TRUE;
// save the current state of the required privileges
ZeroMemory(currentState, sizeof(PRIVILEGE_STATE));
SaveCurrentPrivilegeState(currentState);
// Enable required privileges using the existing SetPrivilege function
result &= SetPrivilege(SE_TAKE_OWNERSHIP_NAME, TRUE);
result &= SetPrivilege(SE_BACKUP_NAME, TRUE);
result &= SetPrivilege(SE_RESTORE_NAME, TRUE);
return result;
}
// Helper function to backup security information
BOOL BackupSecurityInfo(const wchar_t* filePath, PSECURITY_INFO_BACKUP pBackup)
{
BOOL result = FALSE;
PSECURITY_DESCRIPTOR pSD = NULL;
DWORD dwRes;
ZeroMemory(pBackup, sizeof(SECURITY_INFO_BACKUP));
// Get the security descriptor
dwRes = GetNamedSecurityInfoW(
(LPWSTR)filePath,
SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
&pBackup->pOrigOwner,
&pBackup->pOrigGroup,
&pBackup->pOrigDacl,
&pBackup->pOrigSacl,
&pSD);
if (dwRes == ERROR_SUCCESS)
{
// The individual pointers (pOrigOwner, etc.) are now valid
// and point to the copied data
result = TRUE;
}
if (pSD)
LocalFree(pSD);
return result;
}
// Helper function to restore security information
BOOL RestoreSecurityInfo(const wchar_t* filePath, PSECURITY_INFO_BACKUP pBackup)
{
DWORD dwRes;
SECURITY_INFORMATION secInfo = 0;
if (pBackup->pOrigOwner)
secInfo |= OWNER_SECURITY_INFORMATION;
if (pBackup->pOrigGroup)
secInfo |= GROUP_SECURITY_INFORMATION;
if (pBackup->pOrigDacl)
secInfo |= DACL_SECURITY_INFORMATION;
if (pBackup->pOrigSacl)
secInfo |= SACL_SECURITY_INFORMATION;
if (secInfo == 0)
return TRUE; // Nothing to restore
dwRes = SetNamedSecurityInfoW(
(LPWSTR)filePath,
SE_FILE_OBJECT,
secInfo,
pBackup->pOrigOwner,
pBackup->pOrigGroup,
pBackup->pOrigDacl,
pBackup->pOrigSacl);
return (dwRes == ERROR_SUCCESS);
}
// Helper function to free security backup
void FreeSecurityBackup(PSECURITY_INFO_BACKUP pBackup)
{
if (pBackup->pOrigOwner)
LocalFree(pBackup->pOrigOwner);
if (pBackup->pOrigGroup)
LocalFree(pBackup->pOrigGroup);
if (pBackup->pOrigDacl)
LocalFree(pBackup->pOrigDacl);
if (pBackup->pOrigSacl)
LocalFree(pBackup->pOrigSacl);
ZeroMemory(pBackup, sizeof(SECURITY_INFO_BACKUP));
}
// Helper function to take ownership and modify file permissions
BOOL ModifyFileSecurityPermissions(const wchar_t* filePath, PSECURITY_INFO_BACKUP pBackup)
{
BOOL result = FALSE;
PSID pAdminSID = NULL;
PACL pNewDACL = NULL;
BOOL bBackupDone = FALSE;
// Get Administrator SID
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid(&SIDAuthNT, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAdminSID))
{
goto cleanup;
}
// Backup original security info
if (!BackupSecurityInfo(filePath, pBackup))
goto cleanup;
bBackupDone = TRUE;
// Take ownership
DWORD dwRes = SetNamedSecurityInfoW(
(LPWSTR)filePath,
SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION,
pAdminSID,
NULL,
NULL,
NULL);
if (dwRes != ERROR_SUCCESS)
goto cleanup;
// Modify DACL
EXPLICIT_ACCESS ea;
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = GENERIC_ALL;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea.Trustee.ptstrName = (LPTSTR)pAdminSID;
dwRes = SetEntriesInAcl(1, &ea, NULL, &pNewDACL);
if (dwRes != ERROR_SUCCESS)
goto cleanup;
// Apply new DACL
dwRes = SetNamedSecurityInfoW(
(LPWSTR)filePath,
SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
pNewDACL,
NULL);
result = (dwRes == ERROR_SUCCESS);
cleanup:
if (!result && bBackupDone)
{
FreeSecurityBackup(pBackup);
}
if (pNewDACL)
LocalFree(pNewDACL);
if (pAdminSID)
FreeSid(pAdminSID);
return result;
}
#endif

View File

@@ -598,6 +598,27 @@ DWORD FastResizeFile (const wchar_t* filePath, __int64 fileSize);
void GetAppRandomSeed (unsigned char* pbRandSeed, size_t cbRandSeed); void GetAppRandomSeed (unsigned char* pbRandSeed, size_t cbRandSeed);
#endif #endif
BOOL IsInternetConnected(); BOOL IsInternetConnected();
#if defined(SETUP) && !defined (PORTABLE)
typedef struct _SECURITY_INFO_BACKUP {
PSID pOrigOwner;
PSID pOrigGroup;
PACL pOrigDacl;
PACL pOrigSacl;
} SECURITY_INFO_BACKUP, * PSECURITY_INFO_BACKUP;
typedef struct _PRIVILEGE_STATE {
BOOL takeOwnership;
BOOL backup;
BOOL restore;
} PRIVILEGE_STATE, * PPRIVILEGE_STATE;
BOOL RestoreSecurityInfo(const wchar_t* filePath, PSECURITY_INFO_BACKUP pBackup);
void FreeSecurityBackup(PSECURITY_INFO_BACKUP pBackup);
BOOL SaveCurrentPrivilegeState(PPRIVILEGE_STATE state);
BOOL RestorePrivilegeState(const PPRIVILEGE_STATE state);
BOOL EnableRequiredSetupPrivileges(PPRIVILEGE_STATE currentState);
BOOL ModifyFileSecurityPermissions(const wchar_t* filePath, PSECURITY_INFO_BACKUP pBackup);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -765,6 +765,9 @@ BOOL DoFilesInstall (HWND hwndDlg, wchar_t *szDestDir)
BOOL bOK = TRUE; BOOL bOK = TRUE;
int i, x, fileNo; int i, x, fileNo;
wchar_t curFileName [TC_MAX_PATH] = {0}; wchar_t curFileName [TC_MAX_PATH] = {0};
#ifndef PORTABLE
PRIVILEGE_STATE originalPrivileges = { 0 };
#endif
if (!bUninstall && !bDevm) if (!bUninstall && !bDevm)
{ {
@@ -783,6 +786,10 @@ BOOL DoFilesInstall (HWND hwndDlg, wchar_t *szDestDir)
if (szDestDir[x - 1] != L'\\') if (szDestDir[x - 1] != L'\\')
StringCbCatW (szDestDir, MAX_PATH, L"\\"); StringCbCatW (szDestDir, MAX_PATH, L"\\");
#ifndef PORTABLE
EnableRequiredSetupPrivileges(&originalPrivileges);
#endif
for (i = 0; i < sizeof (szFiles) / sizeof (szFiles[0]); i++) for (i = 0; i < sizeof (szFiles) / sizeof (szFiles[0]); i++)
{ {
BOOL bResult, zipFile = FALSE; BOOL bResult, zipFile = FALSE;
@@ -1114,11 +1121,20 @@ err:
if (lpMsgBuf) LocalFree (lpMsgBuf); if (lpMsgBuf) LocalFree (lpMsgBuf);
if (!Silent && MessageBoxW (hwndDlg, szTmp2, lpszTitle, MB_YESNO | MB_ICONHAND) != IDYES) if (!Silent && MessageBoxW(hwndDlg, szTmp2, lpszTitle, MB_YESNO | MB_ICONHAND) != IDYES)
{
#ifndef PORTABLE
RestorePrivilegeState(&originalPrivileges);
#endif
return FALSE; return FALSE;
}
} }
} }
#ifndef PORTABLE
RestorePrivilegeState(&originalPrivileges);
#endif
if (bUninstall == FALSE) if (bUninstall == FALSE)
{ {
WIN32_FIND_DATA f; WIN32_FIND_DATA f;