diff --git a/src/Common/BootEncryption.cpp b/src/Common/BootEncryption.cpp index 4f616688..aa91b999 100644 --- a/src/Common/BootEncryption.cpp +++ b/src/Common/BootEncryption.cpp @@ -2640,7 +2640,7 @@ namespace VeraCrypt IDR_EFI_DCSINFO_2023 }; - static const wchar_t *EfiBootLoaderDiagnosticsRegistryKey = L"Software\\VeraCrypt\\Diagnostics\\EfiBootLoader"; + static const wchar_t *EfiBootLoaderDiagnosticsRegistryKey = VC_EFI_BOOT_LOADER_DIAGNOSTICS_REGISTRY_KEY; static bool ReadFirmwareEnvironmentVariableBuffer (const wchar_t* name, const wchar_t* guid, std::vector& value, DWORD* pLastError = NULL) { @@ -2732,6 +2732,75 @@ namespace VeraCrypt return selection; } + static bool ReadRecordedEfiBootLoaderResourceSet (DWORD& resourceSet) + { + resourceSet = 0; + return ReadLocalMachineRegistryDword ( + (wchar_t *) EfiBootLoaderDiagnosticsRegistryKey, + (wchar_t *) VC_EFI_BOOT_LOADER_RESOURCE_SET_VALUE_NAME, + &resourceSet) && resourceSet != 0; + } + + static DWORD ReadEfiBootLoaderRescueDiskPromptId () + { + DWORD promptId = 0; + ReadLocalMachineRegistryDword ( + (wchar_t *) EfiBootLoaderDiagnosticsRegistryKey, + (wchar_t *) VC_EFI_BOOT_LOADER_RESCUE_DISK_PROMPT_ID_VALUE_NAME, + &promptId); + return promptId; + } + + static bool WriteEfiBootLoaderDiagnosticsRegistryDword (const wchar_t *valueName, DWORD value) + { +#ifndef SETUP + if (!IsAdmin () && IsUacSupported ()) + { + try + { + Elevator::WriteLocalMachineRegistryDwordValue ((wchar_t *) EfiBootLoaderDiagnosticsRegistryKey, (wchar_t *) valueName, value); + return true; + } + catch (...) { } + + return false; + } +#endif + return WriteLocalMachineRegistryDword ((wchar_t *) EfiBootLoaderDiagnosticsRegistryKey, (wchar_t *) valueName, value) ? true : false; + } + + static void MarkEfiBootLoaderRescueDiskRecreationNeeded (const EfiBootLoaderImages& images) + { + if (!images.ResourceSet) + return; + + DWORD previousLastError = GetLastError (); + DWORD promptId = ReadEfiBootLoaderRescueDiskPromptId () + 1; + if (promptId == 0) + promptId = 1; + + WriteEfiBootLoaderDiagnosticsRegistryDword (VC_EFI_BOOT_LOADER_RESCUE_DISK_PROMPT_RESOURCE_SET_VALUE_NAME, images.ResourceSet); + WriteEfiBootLoaderDiagnosticsRegistryDword (VC_EFI_BOOT_LOADER_RESCUE_DISK_PROMPT_ID_VALUE_NAME, promptId); + SetLastError (previousLastError); + } + + static void RecordEfiBootLoaderRescueDiskResourceSet (const EfiBootLoaderImages& images) + { + if (!images.ResourceSet) + return; + + DWORD previousLastError = GetLastError (); + WriteEfiBootLoaderDiagnosticsRegistryDword (VC_EFI_BOOT_LOADER_RESCUE_DISK_RESOURCE_SET_VALUE_NAME, images.ResourceSet); + SetLastError (previousLastError); + } + + static void ClearEfiBootLoaderDiagnosticsRegistry () + { + DWORD previousLastError = GetLastError (); + ::DeleteRegistryKey (HKEY_LOCAL_MACHINE, EfiBootLoaderDiagnosticsRegistryKey); + SetLastError (previousLastError); + } + static void RecordEfiBootLoaderResourceSetSelection (const EfiBootLoaderImages& images) { if (!images.ResourceSet || !images.SelectionReason) @@ -2744,7 +2813,7 @@ namespace VeraCrypt StringCchPrintfW (selectionTimeUtc, ARRAYSIZE (selectionTimeUtc), L"%04u-%02u-%02uT%02u:%02u:%02uZ", systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond); - WriteLocalMachineRegistryDword ((wchar_t *) EfiBootLoaderDiagnosticsRegistryKey, L"EfiBootLoaderResourceSet", images.ResourceSet); + WriteLocalMachineRegistryDword ((wchar_t *) EfiBootLoaderDiagnosticsRegistryKey, (wchar_t *) VC_EFI_BOOT_LOADER_RESOURCE_SET_VALUE_NAME, images.ResourceSet); WriteLocalMachineRegistryDword ((wchar_t *) EfiBootLoaderDiagnosticsRegistryKey, L"EfiBootLoaderFirmwareDbLastError", images.FirmwareDbError); WriteLocalMachineRegistryString (EfiBootLoaderDiagnosticsRegistryKey, L"EfiBootLoaderSelectionReason", images.SelectionReason, FALSE); WriteLocalMachineRegistryString (EfiBootLoaderDiagnosticsRegistryKey, L"EfiBootLoaderSelectionTimeUtc", selectionTimeUtc, FALSE); @@ -3003,18 +3072,18 @@ namespace VeraCrypt if (TryFirmwareDbContainsMicrosoft2023UefiCAs (bContainsMicrosoft2023UefiCAs)) { if (bContainsMicrosoft2023UefiCAs) - return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2023, 2023, L"firmware db contains Microsoft UEFI CA 2023 and Microsoft Option ROM UEFI CA 2023", ERROR_SUCCESS); + return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2023, VC_EFI_BOOT_LOADER_RESOURCE_SET_2023, L"firmware db contains Microsoft UEFI CA 2023 and Microsoft Option ROM UEFI CA 2023", ERROR_SUCCESS); - return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2011, 2011, L"firmware db does not contain both Microsoft 2023 UEFI CAs", ERROR_SUCCESS); + return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2011, VC_EFI_BOOT_LOADER_RESOURCE_SET_2011, L"firmware db does not contain both Microsoft 2023 UEFI CAs", ERROR_SUCCESS); } DWORD dwError = GetLastError (); if (IsFirmwareDbUnavailableError (dwError)) - return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2011, 2011, L"firmware db is unavailable; using 2011 compatibility fallback", dwError); + return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2011, VC_EFI_BOOT_LOADER_RESOURCE_SET_2011, L"firmware db is unavailable; using 2011 compatibility fallback", dwError); bool bSecureBootEnabled = false; if (TryFirmwareSecureBootEnabled (bSecureBootEnabled) && !bSecureBootEnabled) - return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2011, 2011, L"Secure Boot is disabled and firmware db could not be read; using 2011 compatibility fallback", dwError); + return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2011, VC_EFI_BOOT_LOADER_RESOURCE_SET_2011, L"Secure Boot is disabled and firmware db could not be read; using 2011 compatibility fallback", dwError); #ifndef SETUP if (!IsAdmin () && IsUacSupported ()) { @@ -3024,13 +3093,13 @@ namespace VeraCrypt BOOL bElevatedContainsMicrosoft2023UefiCAs = FALSE; Elevator::GetEfiBootLoaderSigningSupport (&bElevatedContainsMicrosoft2023UefiCAs); if (bElevatedContainsMicrosoft2023UefiCAs) - return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2023, 2023, L"elevated helper reported Microsoft 2023 UEFI CA support", dwError); + return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2023, VC_EFI_BOOT_LOADER_RESOURCE_SET_2023, L"elevated helper reported Microsoft 2023 UEFI CA support", dwError); - return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2011, 2011, L"elevated helper did not report Microsoft 2023 UEFI CA support", dwError); + return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2011, VC_EFI_BOOT_LOADER_RESOURCE_SET_2011, L"elevated helper did not report Microsoft 2023 UEFI CA support", dwError); } #endif - return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2011, 2011, L"firmware db could not be read; using 2011 compatibility fallback", dwError); + return MakeEfiBootLoaderResourceSelection (EfiBootLoaderResources2011, VC_EFI_BOOT_LOADER_RESOURCE_SET_2011, L"firmware db could not be read; using 2011 compatibility fallback", dwError); } static void ThrowMissingEfiResource (const wchar_t* resourceName, bool rescueDisk) @@ -3093,6 +3162,35 @@ namespace VeraCrypt BackupEfiBootLoaderImageIfDifferent (efiBoot, L"\\EFI\\VeraCrypt\\DcsInfo.dcs", L"\\EFI\\VeraCrypt\\DcsInfo.dcs.vc_backup", images.DcsInfo, images.SizeDcsInfo); } + static bool EfiBootLoaderImageDiffers (EfiBoot& efiBoot, const wchar_t* imageName, uint8* replacementData, DWORD replacementSize) + { + std::vector currentImage; + if (!efiBoot.ReadFileToBuffer (imageName, currentImage)) + return false; + + return (currentImage.size () != replacementSize) + || ((replacementSize != 0) && (memcmp (currentImage.data (), replacementData, replacementSize) != 0)); + } + + static bool EfiBootLoaderImagesDiffer (EfiBoot& efiBoot, const EfiBootLoaderImages& images) + { + return EfiBootLoaderImageDiffers (efiBoot, L"\\EFI\\VeraCrypt\\DcsBoot.efi", images.DcsBoot, images.SizeDcsBoot) + || EfiBootLoaderImageDiffers (efiBoot, L"\\EFI\\VeraCrypt\\DcsInt.dcs", images.DcsInt, images.SizeDcsInt) + || EfiBootLoaderImageDiffers (efiBoot, L"\\EFI\\VeraCrypt\\DcsCfg.dcs", images.DcsCfg, images.SizeDcsCfg) + || EfiBootLoaderImageDiffers (efiBoot, L"\\EFI\\VeraCrypt\\LegacySpeaker.dcs", images.LegacySpeaker, images.SizeLegacySpeaker) + || EfiBootLoaderImageDiffers (efiBoot, L"\\EFI\\VeraCrypt\\DcsInfo.dcs", images.DcsInfo, images.SizeDcsInfo); + } + + static bool EfiBootLoaderRefreshRequiresRescueDiskPrompt (EfiBoot& efiBoot, const EfiBootLoaderImages& images) + { + DWORD recordedResourceSet = 0; + bool bRecordedResourceSetKnown = ReadRecordedEfiBootLoaderResourceSet (recordedResourceSet); + if (bRecordedResourceSetKnown && recordedResourceSet == images.ResourceSet) + return false; + + return EfiBootLoaderImagesDiffer (efiBoot, images); + } + static void SaveEfiBootLoaderImages (EfiBoot& efiBoot, const EfiBootLoaderImages& images, bool backupExistingImages = false) { if (backupExistingImages) @@ -4158,6 +4256,7 @@ namespace VeraCrypt const bool bRefreshMsBootloader = !bModifiedMsBoot || bMissingMsBoot || (EfiBootInst.FileExists (szStdMsBootloader) && EfiBootInst.IsVeraCryptBootLoader (szStdMsBootloader)); + const bool bRescueDiskPromptRequired = EfiBootLoaderRefreshRequiresRescueDiskPrompt (EfiBootInst, efiImages); // Keep the firmware-visible loader path valid before the larger module refresh. if (bRefreshMsBootloader && !EfiBootInst.FileExists (szStdMsBootloader)) @@ -4215,6 +4314,8 @@ namespace VeraCrypt EfiBootInst.CopyFile (L"\\EFI\\VeraCrypt\\DcsBoot.efi", szStdEfiBootloader); } } + if (bRescueDiskPromptRequired) + MarkEfiBootLoaderRescueDiskRecreationNeeded (efiImages); return; } } @@ -4575,6 +4676,7 @@ namespace VeraCrypt { File isoFile (isoImagePath, false, true); isoFile.Write (RescueZipData, RescueZipSize); + RecordEfiBootLoaderRescueDiskResourceSet (efiImages); } } else @@ -5324,6 +5426,8 @@ namespace VeraCrypt device.Write (bootLoaderBuf, sizeof (bootLoaderBuf)); } + ClearEfiBootLoaderDiagnosticsRegistry (); + if (!IsAdmin() && IsUacSupported()) { Elevator::UpdateSetupConfigFile (false); diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c index 4fb8db68..ed03e5b4 100644 --- a/src/Common/Dlgcode.c +++ b/src/Common/Dlgcode.c @@ -3739,9 +3739,56 @@ void SavePostInstallTasksSettings (int command) } +static BOOL ReadEfiBootLoaderDiagnosticsDword (const wchar_t *valueName, DWORD *value) +{ + return ReadLocalMachineRegistryDword ( + (wchar_t *) VC_EFI_BOOT_LOADER_DIAGNOSTICS_REGISTRY_KEY, + (wchar_t *) valueName, + value); +} + + +static BOOL EfiBootLoaderRescueDiskResourceSetMatches (DWORD resourceSet) +{ + DWORD rescueDiskResourceSet = 0; + + return resourceSet != 0 + && ReadEfiBootLoaderDiagnosticsDword (VC_EFI_BOOT_LOADER_RESCUE_DISK_RESOURCE_SET_VALUE_NAME, &rescueDiskResourceSet) + && rescueDiskResourceSet == resourceSet; +} + + +static BOOL IsEfiBootLoaderRescueDiskPromptPending (void) +{ + DWORD promptId = 0; + DWORD recordedResourceSet = 0; + DWORD promptResourceSet = 0; + + if (ReadEfiBootLoaderDiagnosticsDword (VC_EFI_BOOT_LOADER_RESCUE_DISK_PROMPT_ID_VALUE_NAME, &promptId) && promptId != 0) + { + if (!ReadEfiBootLoaderDiagnosticsDword (VC_EFI_BOOT_LOADER_RESCUE_DISK_PROMPT_RESOURCE_SET_VALUE_NAME, &promptResourceSet)) + { + if (!ReadEfiBootLoaderDiagnosticsDword (VC_EFI_BOOT_LOADER_RESOURCE_SET_VALUE_NAME, &promptResourceSet)) + return FALSE; + } + + return !EfiBootLoaderRescueDiskResourceSetMatches (promptResourceSet); + } + + if (ReadEfiBootLoaderDiagnosticsDword (VC_EFI_BOOT_LOADER_RESOURCE_SET_VALUE_NAME, &recordedResourceSet) + && recordedResourceSet == VC_EFI_BOOT_LOADER_RESOURCE_SET_2023) + { + return !EfiBootLoaderRescueDiskResourceSetMatches (recordedResourceSet); + } + + return FALSE; +} + + void DoPostInstallTasks (HWND hwndDlg) { BOOL bDone = FALSE; + BOOL bEfiBootLoaderRescueDiskPromptPending = IsEfiBootLoaderRescueDiskPromptPending (); if (FileExists (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_TUTORIAL))) { @@ -3759,7 +3806,7 @@ void DoPostInstallTasks (HWND hwndDlg) bDone = TRUE; } - if (FileExists (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_RESCUE_DISK))) + if (FileExists (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_RESCUE_DISK)) || bEfiBootLoaderRescueDiskPromptPending) { if (AskYesNo ("AFTER_UPGRADE_RESCUE_DISK", hwndDlg) == IDYES) PostMessage (hwndDlg, VC_APPMSG_CREATE_RESCUE_DISK, 0, 0); diff --git a/src/Common/Dlgcode.h b/src/Common/Dlgcode.h index 88e171d6..eef51754 100644 --- a/src/Common/Dlgcode.h +++ b/src/Common/Dlgcode.h @@ -82,6 +82,14 @@ enum #define TC_APPD_FILENAME_POST_INSTALL_TASK_RELEASE_NOTES L"Post-Install Task - Release Notes" #define TC_APPD_FILENAME_POST_INSTALL_TASK_RESCUE_DISK L"Post-Install Task - Rescue Disk" +#define VC_EFI_BOOT_LOADER_DIAGNOSTICS_REGISTRY_KEY L"Software\\VeraCrypt\\Diagnostics\\EfiBootLoader" +#define VC_EFI_BOOT_LOADER_RESOURCE_SET_2011 2011 +#define VC_EFI_BOOT_LOADER_RESOURCE_SET_2023 2023 +#define VC_EFI_BOOT_LOADER_RESOURCE_SET_VALUE_NAME L"EfiBootLoaderResourceSet" +#define VC_EFI_BOOT_LOADER_RESCUE_DISK_PROMPT_ID_VALUE_NAME L"EfiBootLoaderRescueDiskPromptId" +#define VC_EFI_BOOT_LOADER_RESCUE_DISK_PROMPT_RESOURCE_SET_VALUE_NAME L"EfiBootLoaderRescueDiskPromptResourceSet" +#define VC_EFI_BOOT_LOADER_RESCUE_DISK_RESOURCE_SET_VALUE_NAME L"EfiBootLoaderRescueDiskResourceSet" + #define VC_FILENAME_RENAMED_SUFFIX L"_old" /* customer service control code to build device list */