diff --git a/src/Boot/EFI/ARM64/.gitignore b/src/Boot/EFI/ARM64/.gitignore new file mode 100644 index 0000000000..950e96735d --- /dev/null +++ b/src/Boot/EFI/ARM64/.gitignore @@ -0,0 +1,3 @@ +# Release EFI resources are versioned so clean Setup builds are self-contained. +*.map +*.pdb diff --git a/src/Boot/EFI/ARM64/DcsBml.efi b/src/Boot/EFI/ARM64/DcsBml.efi new file mode 100644 index 0000000000..ef5ba6343d Binary files /dev/null and b/src/Boot/EFI/ARM64/DcsBml.efi differ diff --git a/src/Boot/EFI/ARM64/DcsBoot.efi b/src/Boot/EFI/ARM64/DcsBoot.efi new file mode 100644 index 0000000000..c9157b30f7 Binary files /dev/null and b/src/Boot/EFI/ARM64/DcsBoot.efi differ diff --git a/src/Boot/EFI/ARM64/DcsCfg.dcs b/src/Boot/EFI/ARM64/DcsCfg.dcs new file mode 100644 index 0000000000..d9d2d19ca0 Binary files /dev/null and b/src/Boot/EFI/ARM64/DcsCfg.dcs differ diff --git a/src/Boot/EFI/ARM64/DcsInfo.dcs b/src/Boot/EFI/ARM64/DcsInfo.dcs new file mode 100644 index 0000000000..a29effed09 Binary files /dev/null and b/src/Boot/EFI/ARM64/DcsInfo.dcs differ diff --git a/src/Boot/EFI/ARM64/DcsInt.dcs b/src/Boot/EFI/ARM64/DcsInt.dcs new file mode 100644 index 0000000000..e70402bac4 Binary files /dev/null and b/src/Boot/EFI/ARM64/DcsInt.dcs differ diff --git a/src/Boot/EFI/ARM64/DcsRe.efi b/src/Boot/EFI/ARM64/DcsRe.efi new file mode 100644 index 0000000000..af6aeba962 Binary files /dev/null and b/src/Boot/EFI/ARM64/DcsRe.efi differ diff --git a/src/Boot/EFI/ARM64/LegacySpeaker.dcs b/src/Boot/EFI/ARM64/LegacySpeaker.dcs new file mode 100644 index 0000000000..4fd9777db5 Binary files /dev/null and b/src/Boot/EFI/ARM64/LegacySpeaker.dcs differ diff --git a/src/Boot/EFI/ARM64/README.txt b/src/Boot/EFI/ARM64/README.txt new file mode 100644 index 0000000000..1abe3f82bf --- /dev/null +++ b/src/Boot/EFI/ARM64/README.txt @@ -0,0 +1,19 @@ +ARM64 VeraCrypt-DCS staging directory +===================================== + +The release EFI resources in this directory are versioned, as are the +existing x64 DCS resources, so a clean VeraCrypt checkout can build Setup +without an unrecorded staging dependency. + +Regenerate them from the companion VeraCrypt-DCS repository with: + + Dcs_bld.bat ARM64Rel VS2022 + +Then stage and validate the AArch64 outputs before building VeraCrypt: + + powershell -ExecutionPolicy Bypass -File Stage-Dcs.ps1 ` + -BuildOutput C:\path\to\VeraCrypt-DCS\Build\DcsPkg\RELEASE_VS2022\AARCH64 + +The staging script rejects missing, malformed, or non-AArch64 PE images and +prints the SHA-256 hash of every staged resource. Commit all seven refreshed +resources together with the source revisions that produced them. diff --git a/src/Boot/EFI/ARM64/Stage-Dcs.ps1 b/src/Boot/EFI/ARM64/Stage-Dcs.ps1 new file mode 100644 index 0000000000..b4cc6bdbb7 --- /dev/null +++ b/src/Boot/EFI/ARM64/Stage-Dcs.ps1 @@ -0,0 +1,59 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)] + [string] $BuildOutput, + + [string] $Destination +) + +$ErrorActionPreference = "Stop" + +if ([string]::IsNullOrWhiteSpace($Destination)) { + $Destination = $PSScriptRoot +} + +$files = [ordered]@{ + "DcsBml.efi" = "DcsBml.efi" + "DcsBoot.efi" = "DcsBoot.efi" + "DcsCfg.efi" = "DcsCfg.dcs" + "DcsInfo.efi" = "DcsInfo.dcs" + "DcsInt.efi" = "DcsInt.dcs" + "DcsRe.efi" = "DcsRe.efi" + "LegacySpeaker.efi" = "LegacySpeaker.dcs" +} + +function Assert-AArch64PeImage { + param([Parameter(Mandatory = $true)][string] $Path) + + $bytes = [System.IO.File]::ReadAllBytes($Path) + if (($bytes.Length -lt 64) -or ($bytes[0] -ne 0x4d) -or ($bytes[1] -ne 0x5a)) { + throw "'$Path' is not a PE image." + } + + $peOffset = [BitConverter]::ToInt32($bytes, 0x3c) + if (($peOffset -lt 0) -or (($peOffset + 6) -gt $bytes.Length) -or ($bytes[$peOffset] -ne 0x50) -or ($bytes[$peOffset + 1] -ne 0x45) -or ($bytes[$peOffset + 2] -ne 0) -or ($bytes[$peOffset + 3] -ne 0)) { + throw "'$Path' has an invalid PE header." + } + + $machine = [BitConverter]::ToUInt16($bytes, $peOffset + 4) + if ($machine -ne 0xaa64) { + throw "'$Path' targets PE machine 0x$($machine.ToString('x4')), not AArch64 (0xaa64)." + } +} + +$buildOutputPath = (Resolve-Path -LiteralPath $BuildOutput).Path +New-Item -ItemType Directory -Force -Path $Destination | Out-Null + +foreach ($entry in $files.GetEnumerator()) { + $source = Join-Path $buildOutputPath $entry.Key + if (-not (Test-Path -LiteralPath $source -PathType Leaf)) { + throw "Missing VeraCrypt-DCS output '$source'." + } + + Assert-AArch64PeImage -Path $source + $target = Join-Path $Destination $entry.Value + Copy-Item -LiteralPath $source -Destination $target -Force + + $hash = (Get-FileHash -LiteralPath $target -Algorithm SHA256).Hash + Write-Host "$($entry.Value) $hash" +} diff --git a/src/Boot/Windows/BootDefs.h b/src/Boot/Windows/BootDefs.h index 6ce547bdad..cf0de98e97 100644 --- a/src/Boot/Windows/BootDefs.h +++ b/src/Boot/Windows/BootDefs.h @@ -208,4 +208,83 @@ TC_HIDDEN_OS_CREATION_PHASE_WIPED = TC__HIDDEN_OS_CREATION_PHASE_WIPED #define EFI_BOOTARGS_REGIONS_DEFAULT EFI_BOOTARGS_REGIONS_LOW, EFI_BOOTARGS_REGIONS_HIGH #define EFI_BOOTARGS_REGIONS_EFI EFI_BOOTARGS_REGIONS_HIGH, EFI_BOOTARGS_REGIONS_LOW +#if !defined(TC_ASM_PREPROCESS) +#define VC_ARM64_BOOT_ARGS_HANDOFF_REQUIRED_REG_VALUE_NAME L"Arm64BootArgsHandoffRequired" +#endif + +#if !defined(TC_ASM_PREPROCESS) && (defined(_M_ARM64) || defined(MDE_CPU_AARCH64)) +#define VC_ARM64_BOOT_ARGS_HANDOFF_VARIABLE_NAME L"VeraCryptArm64BootArgsHandoffPayload" +#define VC_ARM64_BOOT_ARGS_HANDOFF_GUID_INIT \ +{ 0x101f8560, 0xd73a, 0x4ff7, { 0x89, 0xf6, 0x81, 0x70, 0xf6, 0x61, 0x55, 0x87 } } +#define VC_ARM64_BOOT_ARGS_HANDOFF_DESCRIPTOR_MAGIC 0x5643414844534332ULL +#define VC_ARM64_BOOT_ARGS_HANDOFF_PAYLOAD_MAGIC 0x56434148504C4431ULL +#define VC_ARM64_BOOT_ARGS_HANDOFF_ALLOCATION_TAG_MAGIC 0x564341484F574E31ULL +#define VC_ARM64_BOOT_ARGS_HANDOFF_VERSION 2 +#define VC_ARM64_BOOT_ARGS_HANDOFF_VARIABLE_ATTRIBUTES 0x00000006UL +#define VC_ARM64_BOOT_ARGS_HANDOFF_REGION_LENGTH 4096UL +#define VC_ARM64_BOOT_ARGS_HANDOFF_BOOT_PARAMS_LENGTH 158UL +#define VC_ARM64_RESCUE_DECRYPTION_COMPLETE_VARIABLE_NAME L"VeraCryptArm64RescueDecryptionComplete" +#define VC_ARM64_RESCUE_DECRYPTION_COMPLETE_MAGIC 0x5643414852444331ULL +#define VC_ARM64_RESCUE_DECRYPTION_COMPLETE_VERSION 1 +#define VC_ARM64_RESCUE_DECRYPTION_COMPLETE_VARIABLE_ATTRIBUTES 0x00000007UL + +#pragma pack (push) +#pragma pack (1) +typedef struct +{ + uint64 Magic; + uint32 Version; + uint32 Size; + uint32 BootArgsOffset; + uint32 PayloadLength; + uint32 PayloadCrc32; + uint32 Crc32; +} VeraCryptArm64BootArgsHandoffPayloadHeader; + +typedef struct +{ + uint64 Magic; + uint32 Version; + uint32 Size; + uint64 PhysicalAddress; + uint32 RegionLength; + uint32 PayloadLength; + uint32 PayloadCrc32; + uint32 Crc32; +} VeraCryptArm64BootArgsHandoffDescriptor; + +typedef struct +{ + uint64 Magic; + uint32 Version; + uint32 Size; + uint64 PhysicalAddress; + uint32 RegionLength; + uint32 Crc32; +} VeraCryptArm64BootArgsHandoffAllocationTag; + +typedef struct +{ + uint64 Magic; + uint32 Version; + uint32 Size; + uint32 HeaderSaltCrc32; + uint32 Crc32; +} VeraCryptArm64RescueDecryptionComplete; +#pragma pack (pop) + +typedef char VeraCryptArm64BootArgsHandoffPayloadHeaderSizeCheck[ + sizeof (VeraCryptArm64BootArgsHandoffPayloadHeader) == 32 ? 1 : -1]; +typedef char VeraCryptArm64BootArgsHandoffDescriptorSizeCheck[ + sizeof (VeraCryptArm64BootArgsHandoffDescriptor) == 40 ? 1 : -1]; +typedef char VeraCryptArm64BootArgsHandoffAllocationTagSizeCheck[ + sizeof (VeraCryptArm64BootArgsHandoffAllocationTag) == 32 ? 1 : -1]; +typedef char VeraCryptArm64RescueDecryptionCompleteSizeCheck[ + sizeof (VeraCryptArm64RescueDecryptionComplete) == 24 ? 1 : -1]; +#define VC_ARM64_BOOT_ARGS_HANDOFF_PAYLOAD_LENGTH \ + (sizeof (VeraCryptArm64BootArgsHandoffPayloadHeader) + VC_ARM64_BOOT_ARGS_HANDOFF_BOOT_PARAMS_LENGTH) +#define VC_ARM64_BOOT_ARGS_HANDOFF_ALLOCATION_TAG_OFFSET \ + (VC_ARM64_BOOT_ARGS_HANDOFF_REGION_LENGTH - sizeof (VeraCryptArm64BootArgsHandoffAllocationTag)) +#endif + #endif // TC_HEADER_Boot_BootDefs diff --git a/src/Common/BootEncryption.cpp b/src/Common/BootEncryption.cpp index bd7e2c0476..e9db14a18f 100644 --- a/src/Common/BootEncryption.cpp +++ b/src/Common/BootEncryption.cpp @@ -1367,6 +1367,29 @@ namespace VeraCrypt // ChangeServiceConfig() rejects SERVICE_BOOT_START with ERROR_INVALID_PARAMETER throw_sys_if (!WriteLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", L"Start", startType)); +#if defined(_M_ARM64) || defined(SETUP) + if (IsARM() && !startOnBoot) + { + wchar_t serviceKeyPath[] = L"SYSTEM\\CurrentControlSet\\Services\\veracrypt"; + throw_sys_if (!WriteLocalMachineRegistryDword ( + serviceKeyPath, + VC_ARM64_BOOT_ARGS_HANDOFF_REQUIRED_REG_VALUE_NAME, + 0)); + + HKEY serviceKey; + LONG result = RegOpenKeyExW (HKEY_LOCAL_MACHINE, serviceKeyPath, 0, KEY_QUERY_VALUE, &serviceKey); + if (result == ERROR_SUCCESS) + { + result = RegFlushKey (serviceKey); + RegCloseKey (serviceKey); + } + if (result != ERROR_SUCCESS) + { + SetLastError (result); + throw SystemException (SRC_POS); + } + } +#endif } @@ -2663,8 +2686,79 @@ namespace VeraCrypt IDR_EFI_DCSINFO_2023 }; +#if defined(_M_ARM64) || defined(SETUP) + static const EfiBootLoaderResourceSet EfiBootLoaderResourcesArm64 = + { + IDR_EFI_DCSBOOT_ARM64, + IDR_EFI_DCSINT_ARM64, + IDR_EFI_DCSCFG_ARM64, + IDR_EFI_LEGACYSPEAKER_ARM64, + IDR_EFI_DCSRE_ARM64, + IDR_EFI_DCSINFO_ARM64 + }; +#endif + + static bool IsArm64BootTarget () + { +#if defined(_M_ARM64) || defined(SETUP) + return IsARM () != FALSE; +#else + return false; +#endif + } + static const wchar_t *EfiBootLoaderDiagnosticsRegistryKey = VC_EFI_BOOT_LOADER_DIAGNOSTICS_REGISTRY_KEY; +#ifdef VC_EFI_CUSTOM_MODE + static int GetEfiBootMenuLockerResourceId () + { + return IsArm64BootTarget () ? IDR_EFI_DCSBML_ARM64 : IDR_EFI_DCSBML; + } +#endif + + static const wchar_t *GetEfiFallbackBootLoaderPath () + { + return IsArm64BootTarget () ? L"\\EFI\\Boot\\bootaa64.efi" : L"\\EFI\\Boot\\bootx64.efi"; + } + + static const wchar_t *GetEfiFallbackBootLoaderBackupPath () + { + return IsArm64BootTarget () + ? L"\\EFI\\Boot\\original_bootaa64.vc_backup" + : L"\\EFI\\Boot\\original_bootx64.vc_backup"; + } + + static const wchar_t *GetLegacyEfiFallbackBootLoaderBackupPath () + { + return IsArm64BootTarget () + ? L"\\EFI\\Boot\\original_bootaa64_vc_backup.efi" + : L"\\EFI\\Boot\\original_bootx64_vc_backup.efi"; + } + + static const char *GetEfiFallbackBootLoaderZipPath () + { + return IsArm64BootTarget () ? "EFI/Boot/bootaa64.efi" : "EFI/Boot/bootx64.efi"; + } + + static const wchar_t *GetEfiFallbackBootLoaderZipPathW () + { + return IsArm64BootTarget () ? L"EFI/Boot/bootaa64.efi" : L"EFI/Boot/bootx64.efi"; + } + + static const char *GetEfiFallbackBootLoaderBackupZipPath () + { + return IsArm64BootTarget () + ? "EFI/Boot/original_bootaa64.vc_backup" + : "EFI/Boot/original_bootx64.vc_backup"; + } + + static const wchar_t *GetEfiFallbackBootLoaderBackupZipPathW () + { + return IsArm64BootTarget () + ? L"EFI/Boot/original_bootaa64.vc_backup" + : L"EFI/Boot/original_bootx64.vc_backup"; + } + static bool ReadFirmwareEnvironmentVariableBuffer (const wchar_t* name, const wchar_t* guid, std::vector& value, DWORD* pLastError = NULL) { bool bRet = false; @@ -3303,6 +3397,30 @@ namespace VeraCrypt static EfiBootLoaderResourceSelection GetPreferredEfiBootLoaderResourceSet () { +#if defined(_M_ARM64) || defined(SETUP) + if (IsArm64BootTarget ()) + { + bool bSecureBootEnabled = false; + if (!TryFirmwareSecureBootEnabled (bSecureBootEnabled)) + { + ThrowUnsupportedEfiSecureBootDb ( + L"ARM64 Secure Boot state could not be read; refusing to select an unsigned AA64 EFI resource set", + GetLastError ()); + } + if (bSecureBootEnabled) + { + ThrowUnsupportedEfiSecureBootDb ( + L"Secure Boot is enabled; the AA64 EFI resource set is not signed by a firmware-trusted CA", + ERROR_SUCCESS); + } + return MakeEfiBootLoaderResourceSelection ( + EfiBootLoaderResourcesArm64, + VC_EFI_BOOT_LOADER_RESOURCE_SET_ARM64, + L"ARM64 firmware with Secure Boot disabled; using the AA64 DCS resource set", + ERROR_SUCCESS); + } +#endif + // The current 2023 DCS set uses both Microsoft UEFI CA 2023 and Microsoft Option ROM UEFI CA 2023: // DcsInt.dcs and LegacySpeaker.dcs are signed through the Option ROM UEFI CA 2023 chain. // If Secure Boot is enabled (or its state cannot be established), only select a loader set whose @@ -3478,6 +3596,12 @@ namespace VeraCrypt return MapEfiBootLoaderImages (MakeEfiBootLoaderResourceSelection ( EfiBootLoaderResources2023, resourceSet, L"explicit 2023 resource-set inspection", ERROR_SUCCESS), rescueDisk); +#if defined(_M_ARM64) || defined(SETUP) + if (resourceSet == VC_EFI_BOOT_LOADER_RESOURCE_SET_ARM64) + return MapEfiBootLoaderImages (MakeEfiBootLoaderResourceSelection ( + EfiBootLoaderResourcesArm64, resourceSet, L"explicit ARM64 resource-set inspection", ERROR_SUCCESS), rescueDisk); +#endif + throw ParameterIncorrect (SRC_POS); } @@ -4369,7 +4493,7 @@ namespace VeraCrypt const wchar_t *standardPaths[] = { L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi", - L"\\EFI\\Boot\\bootx64.efi" + GetEfiFallbackBootLoaderPath () }; for (size_t pathIndex = 0; pathIndex < ARRAYSIZE (standardPaths); ++pathIndex) @@ -4881,12 +5005,12 @@ namespace VeraCrypt } } EfiBootLoaderImages efiImages = MapEfiBootLoaderImages (false); - // Kept as aliases for the legacy EFI\Boot\bootx64.efi replacement block below. + // Kept as aliases for the UEFI fallback-loader replacement block below. DWORD sizeDcsBoot = efiImages.SizeDcsBoot; uint8 *dcsBootImg = efiImages.DcsBoot; #ifdef VC_EFI_CUSTOM_MODE DWORD sizeBootMenuLocker; - uint8 *BootMenuLockerImg = MapResource(L"BIN", IDR_EFI_DCSBML, &sizeBootMenuLocker); + uint8 *BootMenuLockerImg = MapResource(L"BIN", GetEfiBootMenuLockerResourceId (), &sizeBootMenuLocker); if (!BootMenuLockerImg) throw ErrorException(L"Out of resource DcsBml", SRC_POS); #endif @@ -4901,8 +5025,8 @@ namespace VeraCrypt unsigned __int64 loaderSize = 0; const wchar_t * szStdMsBootloader = L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi"; const wchar_t * szBackupMsBootloader = L"\\EFI\\Microsoft\\Boot\\bootmgfw_ms.vc"; - const wchar_t * szStdEfiBootloader = L"\\EFI\\Boot\\bootx64.efi"; - const wchar_t * szBackupEfiBootloader = L"\\EFI\\Boot\\original_bootx64.vc_backup"; + const wchar_t * szStdEfiBootloader = GetEfiFallbackBootLoaderPath (); + const wchar_t * szBackupEfiBootloader = GetEfiFallbackBootLoaderBackupPath (); const bool bCanRefreshWindowsLoaderFromOs = !hiddenOSCreation && !IsHiddenOSRunning (); if (preserveUserConfig) @@ -5108,7 +5232,10 @@ namespace VeraCrypt // move the original bootloader backup from old location (if it exists) to new location // we don't force the move operation if the new location already exists - EfiBootInst.RenameFile (L"\\EFI\\Boot\\original_bootx64_vc_backup.efi", L"\\EFI\\Boot\\original_bootx64.vc_backup", FALSE); + EfiBootInst.RenameFile ( + GetLegacyEfiFallbackBootLoaderBackupPath (), + GetEfiFallbackBootLoaderBackupPath (), + FALSE); // Clean beta9 EfiBootInst.DelFile(L"\\DcsBoot.efi"); @@ -5289,7 +5416,7 @@ namespace VeraCrypt EfiBootLoaderImages efiImages = MapEfiBootLoaderImages (true); #ifdef VC_EFI_CUSTOM_MODE DWORD sizeBootMenuLocker; - uint8 *BootMenuLockerImg = MapResource(L"BIN", IDR_EFI_DCSBML, &sizeBootMenuLocker); + uint8 *BootMenuLockerImg = MapResource(L"BIN", GetEfiBootMenuLockerResourceId (), &sizeBootMenuLocker); if (!BootMenuLockerImg) throw ParameterIncorrect (SRC_POS); #endif @@ -5316,7 +5443,7 @@ namespace VeraCrypt finally_do_arg (zip_t**, &z, { if (*finally_arg) zip_discard (*finally_arg);}); - if (!ZipAdd (z, "EFI/Boot/bootx64.efi", efiImages.DcsRescue, efiImages.SizeDcsRescue)) + if (!ZipAdd (z, GetEfiFallbackBootLoaderZipPath (), efiImages.DcsRescue, efiImages.SizeDcsRescue)) throw ParameterIncorrect (SRC_POS); #ifdef VC_EFI_CUSTOM_MODE if (!ZipAdd (z, "EFI/VeraCrypt/DcsBml.dcs", BootMenuLockerImg, sizeBootMenuLocker)) @@ -5365,7 +5492,7 @@ namespace VeraCrypt sysBakFile.GetFileSize(fileSize); fileBuf.Resize ((DWORD) fileSize); DWORD sizeLoader = sysBakFile.Read (fileBuf.Ptr (), fileSize); - bLoadAdded = ZipAdd (z, "EFI/Boot/original_bootx64.vc_backup", fileBuf.Ptr (), sizeLoader); + bLoadAdded = ZipAdd (z, GetEfiFallbackBootLoaderBackupZipPath (), fileBuf.Ptr (), sizeLoader); } catch (Exception &e) { @@ -5582,7 +5709,7 @@ namespace VeraCrypt if (bIsGPT) { const wchar_t* efi64Files[] = { - L"EFI/Boot/bootx64.efi", + GetEfiFallbackBootLoaderZipPathW (), #ifdef VC_EFI_CUSTOM_MODE L"EFI/VeraCrypt/DcsBml.dcs", #endif @@ -5591,7 +5718,7 @@ namespace VeraCrypt L"EFI/VeraCrypt/DcsInt.dcs", L"EFI/VeraCrypt/LegacySpeaker.dcs", L"EFI/VeraCrypt/svh_bak", - L"EFI/Boot/original_bootx64.vc_backup" + GetEfiFallbackBootLoaderBackupZipPathW () }; zip_error_t zerr; @@ -5764,7 +5891,7 @@ namespace VeraCrypt finally_do_arg (zip_t*, zMem, { zip_close (finally_arg); }); const wchar_t* efi64Files[] = { - L"EFI/Boot/bootx64.efi", + GetEfiFallbackBootLoaderZipPathW (), #ifdef VC_EFI_CUSTOM_MODE L"EFI/VeraCrypt/DcsBml.dcs", #endif @@ -5773,7 +5900,7 @@ namespace VeraCrypt L"EFI/VeraCrypt/DcsInt.dcs", L"EFI/VeraCrypt/LegacySpeaker.dcs", L"EFI/VeraCrypt/svh_bak", - L"EFI/Boot/original_bootx64.vc_backup" + GetEfiFallbackBootLoaderBackupZipPathW () }; int i; @@ -6061,9 +6188,8 @@ namespace VeraCrypt const wchar_t * szStdMsBootloader = L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi"; const wchar_t * szBackupMsBootloader = L"\\EFI\\Microsoft\\Boot\\bootmgfw_ms.vc"; - // EFI system encryption currently ships x64 EFI loaders and the UEFI fallback path is bootx64.efi - const wchar_t * szStdEfiBootloader = L"\\EFI\\Boot\\bootx64.efi"; - const wchar_t * szBackupEfiBootloader = L"\\EFI\\Boot\\original_bootx64.vc_backup"; + const wchar_t * szStdEfiBootloader = GetEfiFallbackBootLoaderPath (); + const wchar_t * szBackupEfiBootloader = GetEfiFallbackBootLoaderBackupPath (); if (!EfiBootInst.FileExists (szStdEfiBootloader) || !EfiBootInst.IsWindowsBootLoader (szStdEfiBootloader)) EfiBootInst.RenameFile(szBackupEfiBootloader, szStdEfiBootloader, TRUE); @@ -6820,16 +6946,31 @@ namespace VeraCrypt { EfiBootInst.PrepareBootPartition (true); - EfiBootLoaderImages images2011 = MapEfiBootLoaderImages (VC_EFI_BOOT_LOADER_RESOURCE_SET_2011, false); - EfiBootLoaderImages images2023 = MapEfiBootLoaderImages (VC_EFI_BOOT_LOADER_RESOURCE_SET_2023, false); - bool bMatches2011 = EfiBootLoaderImagesMatch (EfiBootInst, images2011); - bool bMatches2023 = EfiBootLoaderImagesMatch (EfiBootInst, images2023); const EfiBootLoaderImages *installedImages = NULL; - if (bMatches2011 != bMatches2023) +#if defined(_M_ARM64) || defined(SETUP) + if (IsArm64BootTarget ()) + { + EfiBootLoaderImages imagesArm64 = MapEfiBootLoaderImages (VC_EFI_BOOT_LOADER_RESOURCE_SET_ARM64, false); + if (EfiBootLoaderImagesMatch (EfiBootInst, imagesArm64)) + { + installedImages = &imagesArm64; + status.InstalledResourceSet = installedImages->ResourceSet; + status.VeraCryptLoaderFilesValid = EfiBootLoaderStandardCopiesMatch (EfiBootInst, *installedImages); + } + } + else +#endif { - installedImages = bMatches2023 ? &images2023 : &images2011; - status.InstalledResourceSet = installedImages->ResourceSet; - status.VeraCryptLoaderFilesValid = EfiBootLoaderStandardCopiesMatch (EfiBootInst, *installedImages); + EfiBootLoaderImages images2011 = MapEfiBootLoaderImages (VC_EFI_BOOT_LOADER_RESOURCE_SET_2011, false); + EfiBootLoaderImages images2023 = MapEfiBootLoaderImages (VC_EFI_BOOT_LOADER_RESOURCE_SET_2023, false); + bool bMatches2011 = EfiBootLoaderImagesMatch (EfiBootInst, images2011); + bool bMatches2023 = EfiBootLoaderImagesMatch (EfiBootInst, images2023); + if (bMatches2011 != bMatches2023) + { + installedImages = bMatches2023 ? &images2023 : &images2011; + status.InstalledResourceSet = installedImages->ResourceSet; + status.VeraCryptLoaderFilesValid = EfiBootLoaderStandardCopiesMatch (EfiBootInst, *installedImages); + } } if (status.VeraCryptLoaderFilesValid && status.InstalledResourceSet == VC_EFI_BOOT_LOADER_RESOURCE_SET_2023) @@ -6897,8 +7038,10 @@ namespace VeraCrypt if (CurrentOSMajor == 6 && CurrentOSMinor == 0 && CurrentOSServicePack < 1) throw ErrorException ("SYS_ENCRYPTION_UNSUPPORTED_ON_VISTA_SP0", SRC_POS); +#ifndef _M_ARM64 if (IsARM()) throw ErrorException ("SYS_ENCRYPTION_UNSUPPORTED_ON_CURRENT_OS", SRC_POS); +#endif if (IsNonInstallMode()) throw ErrorException ("FEATURE_REQUIRES_INSTALLATION", SRC_POS); @@ -6911,6 +7054,11 @@ namespace VeraCrypt SystemDriveConfiguration config = GetSystemDriveConfiguration (); +#ifdef _M_ARM64 + if (!config.SystemPartition.IsGPT) + throw ErrorException ("SYS_ENCRYPTION_UNSUPPORTED_ON_CURRENT_OS", SRC_POS); +#endif + if (SystemDriveIsDynamic()) throw ErrorException ("SYSENC_UNSUPPORTED_FOR_DYNAMIC_DISK", SRC_POS); @@ -6966,10 +7114,14 @@ namespace VeraCrypt { // It is assumed that CheckRequirements() had been called (so we don't check e.g. whether it's GPT). +#ifdef _M_ARM64 + throw ErrorException ("SYS_ENCRYPTION_UNSUPPORTED_ON_CURRENT_OS", SRC_POS); +#else // The user may have modified/added/deleted partitions since the partition table was last scanned. InvalidateCachedSysDriveProperties (); GetPartitionForHiddenOS (); +#endif } @@ -7322,6 +7474,11 @@ namespace VeraCrypt if (encStatus.DriveMounted) throw ParameterIncorrect (SRC_POS); +#ifdef _M_ARM64 + if (hiddenSystem) + throw ErrorException ("SYS_ENCRYPTION_UNSUPPORTED_ON_CURRENT_OS", SRC_POS); +#endif + try { InstallBootLoader (false, hiddenSystem, -1, hashAlgo); @@ -7351,6 +7508,9 @@ namespace VeraCrypt void BootEncryption::PrepareHiddenOSCreation (int ea, int mode, int pkcs5) { +#ifdef _M_ARM64 + throw ErrorException ("SYS_ENCRYPTION_UNSUPPORTED_ON_CURRENT_OS", SRC_POS); +#else BootEncryptionStatus encStatus = GetStatus(); if (encStatus.DriveMounted) throw ParameterIncorrect (SRC_POS); @@ -7360,6 +7520,7 @@ namespace VeraCrypt SelectedEncryptionAlgorithmId = ea; SelectedPrfAlgorithmId = pkcs5; +#endif } diff --git a/src/Common/Common.rc b/src/Common/Common.rc index f619690566..04d3eee461 100644 --- a/src/Common/Common.rc +++ b/src/Common/Common.rc @@ -575,6 +575,19 @@ IDR_EFI_LEGACYSPEAKER_2023 BIN "..\\Boot\\EFI\\2023UEFICA\\Lega IDR_EFI_DCSRE_2023 BIN "..\\Boot\\EFI\\2023UEFICA\\DcsRe.efi" IDR_EFI_DCSINFO_2023 BIN "..\\Boot\\EFI\\2023UEFICA\\DcsInfo.efi" #endif + +#if defined(ARM64) || defined(VC_SETUP_RESOURCE) +IDR_EFI_DCSBOOT_ARM64 BIN "..\\Boot\\EFI\\ARM64\\DcsBoot.efi" +IDR_EFI_DCSINT_ARM64 BIN "..\\Boot\\EFI\\ARM64\\DcsInt.dcs" +IDR_EFI_DCSCFG_ARM64 BIN "..\\Boot\\EFI\\ARM64\\DcsCfg.dcs" +IDR_EFI_LEGACYSPEAKER_ARM64 BIN "..\\Boot\\EFI\\ARM64\\LegacySpeaker.dcs" +#ifdef VC_EFI_CUSTOM_MODE +IDR_EFI_DCSBML_ARM64 BIN "..\\Boot\\EFI\\ARM64\\DcsBml.efi" +#endif +IDR_EFI_DCSRE_ARM64 BIN "..\\Boot\\EFI\\ARM64\\DcsRe.efi" +IDR_EFI_DCSINFO_ARM64 BIN "..\\Boot\\EFI\\ARM64\\DcsInfo.dcs" +#endif + ///////////////////////////////////////////////////////////////////////////// // // XML diff --git a/src/Common/Crypto.h b/src/Common/Crypto.h index 3a378c090d..f482453964 100644 --- a/src/Common/Crypto.h +++ b/src/Common/Crypto.h @@ -304,6 +304,11 @@ typedef struct CRYPTO_INFO_t } CRYPTO_INFO, *PCRYPTO_INFO; +typedef struct CRYPTO_INFO_SCRATCH_t +{ + CRYPTO_INFO CryptoInfo; +} CRYPTO_INFO_SCRATCH, *PCRYPTO_INFO_SCRATCH; + #if defined(_WIN32) || defined(_UEFI) #pragma pack (push) @@ -415,8 +420,8 @@ void VcProtectMemory (uint64 encID, unsigned char* pbData, size_t cbData, uint64 VcGetEncryptionID (PCRYPTO_INFO pCryptoInfo); void VcProtectKeys (PCRYPTO_INFO pCryptoInfo, uint64 encID); void VcUnprotectKeys (PCRYPTO_INFO pCryptoInfo, uint64 encID); -void EncryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci); -void DecryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci); +void EncryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci, PCRYPTO_INFO_SCRATCH scratch); +void DecryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci, PCRYPTO_INFO_SCRATCH scratch); #else #define EncryptDataUnitsCurrentThreadEx EncryptDataUnitsCurrentThread #define DecryptDataUnitsCurrentThreadEx DecryptDataUnitsCurrentThread diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c index ed03e5b4df..1601b5cc53 100644 --- a/src/Common/Dlgcode.c +++ b/src/Common/Dlgcode.c @@ -4068,7 +4068,7 @@ void InitApp (HINSTANCE hInstance, wchar_t *lpszCommandLine) AbortProcess("OUTOFMEMORY"); } - if (!EncryptionThreadPoolStart (ReadEncryptionThreadPoolFreeCpuCountLimit())) + if (!EncryptionThreadPoolStart (ReadEncryptionThreadPoolFreeCpuCountLimit(), FALSE)) { handleWin32Error (NULL, SRC_POS); exit (1); diff --git a/src/Common/Dlgcode.h b/src/Common/Dlgcode.h index 6ebb6c538c..0bee116464 100644 --- a/src/Common/Dlgcode.h +++ b/src/Common/Dlgcode.h @@ -85,6 +85,7 @@ enum #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_ARM64 6464 #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" diff --git a/src/Common/EncryptionThreadPool.c b/src/Common/EncryptionThreadPool.c index 6124497d06..d761bb7d5f 100644 --- a/src/Common/EncryptionThreadPool.c +++ b/src/Common/EncryptionThreadPool.c @@ -126,13 +126,26 @@ typedef struct EncryptionThreadPoolWorkItemStruct } EncryptionThreadPoolWorkItem; +typedef struct +{ + WORD ProcessorGroup; + BOOL ApplyProcessorGroupAffinity; + PCRYPTO_INFO_SCRATCH CryptoScratch; +} EncryptionThreadContext; + static volatile BOOL ThreadPoolRunning = FALSE; static volatile BOOL StopPending = FALSE; static uint32 ThreadCount; static TC_THREAD_HANDLE ThreadHandles[TC_ENC_THREAD_POOL_MAX_THREAD_COUNT]; -static WORD ThreadProcessorGroups[TC_ENC_THREAD_POOL_MAX_THREAD_COUNT]; +static EncryptionThreadContext ThreadContexts[TC_ENC_THREAD_POOL_MAX_THREAD_COUNT]; + +#ifdef TC_WINDOWS_DRIVER +#define TC_ENC_THREAD_POOL_SCRATCH_TAG 'sCtV' +static PCRYPTO_INFO_SCRATCH ThreadCryptoScratch; +static size_t ThreadCryptoScratchCount; +#endif static EncryptionThreadPoolWorkItem WorkItemQueue[TC_ENC_THREAD_POOL_QUEUE_SIZE]; @@ -145,33 +158,55 @@ static TC_MUTEX DequeueMutex; static TC_EVENT WorkItemReadyEvent; static TC_EVENT WorkItemCompletedEvent; -void EncryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) +void EncryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci, PCRYPTO_INFO_SCRATCH scratch) { if (IsRamEncryptionEnabled()) { - CRYPTO_INFO tmpCI; - memcpy (&tmpCI, ci, sizeof (CRYPTO_INFO)); - VcUnprotectKeys (&tmpCI, VcGetEncryptionID (ci)); +#ifdef TC_WINDOWS_DRIVER + PCRYPTO_INFO tmpCI; - EncryptDataUnitsCurrentThread (buf, structUnitNo, nbrUnits, &tmpCI); + if (!scratch) + TC_THROW_FATAL_EXCEPTION; - burn (&tmpCI, sizeof(CRYPTO_INFO)); + tmpCI = &scratch->CryptoInfo; +#else + CRYPTO_INFO localScratch; + PCRYPTO_INFO tmpCI = &localScratch; + (void) scratch; +#endif + memcpy (tmpCI, ci, sizeof (CRYPTO_INFO)); + VcUnprotectKeys (tmpCI, VcGetEncryptionID (ci)); + + EncryptDataUnitsCurrentThread (buf, structUnitNo, nbrUnits, tmpCI); + + burn (tmpCI, sizeof (CRYPTO_INFO)); } else EncryptDataUnitsCurrentThread (buf, structUnitNo, nbrUnits, ci); } -void DecryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) +void DecryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci, PCRYPTO_INFO_SCRATCH scratch) { if (IsRamEncryptionEnabled()) { - CRYPTO_INFO tmpCI; - memcpy (&tmpCI, ci, sizeof (CRYPTO_INFO)); - VcUnprotectKeys (&tmpCI, VcGetEncryptionID (ci)); +#ifdef TC_WINDOWS_DRIVER + PCRYPTO_INFO tmpCI; + + if (!scratch) + TC_THROW_FATAL_EXCEPTION; - DecryptDataUnitsCurrentThread (buf, structUnitNo, nbrUnits, &tmpCI); + tmpCI = &scratch->CryptoInfo; +#else + CRYPTO_INFO localScratch; + PCRYPTO_INFO tmpCI = &localScratch; + (void) scratch; +#endif + memcpy (tmpCI, ci, sizeof (CRYPTO_INFO)); + VcUnprotectKeys (tmpCI, VcGetEncryptionID (ci)); + + DecryptDataUnitsCurrentThread (buf, structUnitNo, nbrUnits, tmpCI); - burn (&tmpCI, sizeof(CRYPTO_INFO)); + burn (tmpCI, sizeof (CRYPTO_INFO)); } else DecryptDataUnitsCurrentThread (buf, structUnitNo, nbrUnits, ci); @@ -192,23 +227,24 @@ static void SetWorkItemState (EncryptionThreadPoolWorkItem *workItem, WorkItemSt static TC_THREAD_PROC EncryptionThreadProc (void *threadArg) { EncryptionThreadPoolWorkItem *workItem; - if (threadArg) + EncryptionThreadContext *threadContext = (EncryptionThreadContext *) threadArg; + + if (!threadContext) + TC_THROW_FATAL_EXCEPTION; + + if (threadContext->ApplyProcessorGroupAffinity) { #ifdef DEVICE_DRIVER - SetThreadCpuGroupAffinity ((USHORT) *(WORD*)(threadArg)); + SetThreadCpuGroupAffinity ((USHORT) threadContext->ProcessorGroup); #else - if (threadArg) - { - GROUP_AFFINITY oldAffinity; - GROUP_AFFINITY groupAffinity = {0}; - WORD groupIndex = *(WORD*)(threadArg); - DWORD activeProcessorCount = GetActiveProcessorCount(groupIndex); - KAFFINITY mask = (activeProcessorCount >= 64) ? ~0ULL : ((1ULL << activeProcessorCount) - 1); - groupAffinity.Mask = mask; - groupAffinity.Group = groupIndex; - SetThreadGroupAffinity(GetCurrentThread(), &groupAffinity, &oldAffinity); - } - + GROUP_AFFINITY oldAffinity; + GROUP_AFFINITY groupAffinity = {0}; + WORD groupIndex = threadContext->ProcessorGroup; + DWORD activeProcessorCount = GetActiveProcessorCount(groupIndex); + KAFFINITY mask = (activeProcessorCount >= 64) ? ~0ULL : ((1ULL << activeProcessorCount) - 1); + groupAffinity.Mask = mask; + groupAffinity.Group = groupIndex; + SetThreadGroupAffinity(GetCurrentThread(), &groupAffinity, &oldAffinity); #endif } @@ -237,11 +273,11 @@ static TC_THREAD_PROC EncryptionThreadProc (void *threadArg) switch (workItem->Type) { case DecryptDataUnitsWork: - DecryptDataUnitsCurrentThreadEx (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo); + DecryptDataUnitsCurrentThreadEx (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo, threadContext->CryptoScratch); break; case EncryptDataUnitsWork: - EncryptDataUnitsCurrentThreadEx (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo); + EncryptDataUnitsCurrentThreadEx (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo, threadContext->CryptoScratch); break; case DeriveKeyWork: @@ -385,7 +421,45 @@ size_t GetCpuCount (WORD* pGroupCount) #endif -BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount) +#ifdef TC_WINDOWS_DRIVER +static void FreeThreadCryptoScratch () +{ + if (ThreadCryptoScratch) + { + RtlSecureZeroMemory (ThreadCryptoScratch, ThreadCryptoScratchCount * sizeof (*ThreadCryptoScratch)); + ExFreePoolWithTag (ThreadCryptoScratch, TC_ENC_THREAD_POOL_SCRATCH_TAG); + ThreadCryptoScratch = NULL; + ThreadCryptoScratchCount = 0; + } +} +#endif + + +static void StopEncryptionThreads () +{ + size_t i; + + StopPending = TRUE; + TC_SET_EVENT (WorkItemReadyEvent); + + for (i = 0; i < ThreadCount; ++i) + { +#ifdef DEVICE_DRIVER + TCStopThread (ThreadHandles[i], &WorkItemReadyEvent); +#else + TC_WAIT_EVENT (ThreadHandles[i]); +#endif + } + + ThreadCount = 0; + +#ifdef TC_WINDOWS_DRIVER + FreeThreadCryptoScratch (); +#endif +} + + +BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount, BOOL requireRamEncryptionScratch) { size_t cpuCount = 0, i = 0; WORD groupCount = 1; @@ -393,7 +467,13 @@ BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount) cpuCount = GetCpuCount(&groupCount); if (ThreadPoolRunning) + { +#ifdef TC_WINDOWS_DRIVER + if (requireRamEncryptionScratch && !ThreadCryptoScratch) + return FALSE; +#endif return TRUE; + } if (groupCount > 1) { @@ -405,7 +485,15 @@ BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount) cpuCount -= encryptionFreeCpuCount; if (cpuCount < 2) - return TRUE; + { + if (!requireRamEncryptionScratch) + return TRUE; + + if (cpuCount == 0) + return FALSE; + + cpuCount = 1; + } if (cpuCount > ThreadPoolCount) cpuCount = ThreadPoolCount; @@ -441,6 +529,7 @@ BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount) #endif memset (WorkItemQueue, 0, sizeof (WorkItemQueue)); + memset (ThreadContexts, 0, sizeof (ThreadContexts)); for (i = 0; i < sizeof (WorkItemQueue) / sizeof (WorkItemQueue[0]); ++i) { @@ -458,13 +547,36 @@ BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount) #endif } +#ifdef TC_WINDOWS_DRIVER + if (requireRamEncryptionScratch) + { + size_t scratchSize = cpuCount * sizeof (*ThreadCryptoScratch); + + ThreadCryptoScratch = (PCRYPTO_INFO_SCRATCH) ExAllocatePoolUninitialized ( + NonPagedPoolNx, scratchSize, TC_ENC_THREAD_POOL_SCRATCH_TAG); + if (!ThreadCryptoScratch) + return FALSE; + + ThreadCryptoScratchCount = cpuCount; + RtlSecureZeroMemory (ThreadCryptoScratch, scratchSize); + } +#else + (void) requireRamEncryptionScratch; +#endif + for (ThreadCount = 0; ThreadCount < cpuCount; ++ThreadCount) { - WORD* pThreadArg = NULL; + EncryptionThreadContext *threadContext = &ThreadContexts[ThreadCount]; + +#ifdef TC_WINDOWS_DRIVER + if (ThreadCryptoScratch) + threadContext->CryptoScratch = &ThreadCryptoScratch[ThreadCount]; +#endif + if (groupCount > 1) { #ifdef DEVICE_DRIVER - ThreadProcessorGroups[ThreadCount] = GetCpuGroup ((size_t) ThreadCount); + threadContext->ProcessorGroup = GetCpuGroup ((size_t) ThreadCount); #else GetActiveProcessorCountFn GetActiveProcessorCountPtr = (GetActiveProcessorCountFn) GetProcAddress (GetModuleHandle (L"Kernel32.dll"), "GetActiveProcessorCount"); // Determine which processor group to bind the thread to. @@ -477,25 +589,25 @@ BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount) totalProcessors += (uint32) GetActiveProcessorCountPtr(j); if (totalProcessors > ThreadCount) { - ThreadProcessorGroups[ThreadCount] = j; + threadContext->ProcessorGroup = j; break; } } } else - ThreadProcessorGroups[ThreadCount] = 0; + threadContext->ProcessorGroup = 0; #endif - pThreadArg = &ThreadProcessorGroups[ThreadCount]; + threadContext->ApplyProcessorGroupAffinity = TRUE; } #ifdef DEVICE_DRIVER - if (!NT_SUCCESS(TCStartThread(EncryptionThreadProc, (void*) pThreadArg, &ThreadHandles[ThreadCount]))) + if (!NT_SUCCESS(TCStartThread(EncryptionThreadProc, threadContext, &ThreadHandles[ThreadCount]))) #else - if (!(ThreadHandles[ThreadCount] = (HANDLE)_beginthreadex(NULL, 0, EncryptionThreadProc, (void*) pThreadArg, 0, NULL))) + if (!(ThreadHandles[ThreadCount] = (HANDLE)_beginthreadex(NULL, 0, EncryptionThreadProc, threadContext, 0, NULL))) #endif { - EncryptionThreadPoolStop(); + StopEncryptionThreads (); return FALSE; } } @@ -507,24 +619,14 @@ BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount) void EncryptionThreadPoolStop () { +#ifndef DEVICE_DRIVER size_t i; +#endif if (!ThreadPoolRunning) return; - StopPending = TRUE; - TC_SET_EVENT (WorkItemReadyEvent); - - for (i = 0; i < ThreadCount; ++i) - { -#ifdef DEVICE_DRIVER - TCStopThread (ThreadHandles[i], &WorkItemReadyEvent); -#else - TC_WAIT_EVENT (ThreadHandles[i]); -#endif - } - - ThreadCount = 0; + StopEncryptionThreads (); #ifndef DEVICE_DRIVER CloseHandle (DequeueMutex); @@ -635,16 +737,23 @@ void EncryptionThreadPoolDoWork (EncryptionThreadPoolWorkType type, uint8 *data, if (unitCount == 0) return; +#ifdef TC_WINDOWS_DRIVER + if (!ThreadPoolRunning && IsRamEncryptionEnabled()) + TC_THROW_FATAL_EXCEPTION; + + if (!ThreadPoolRunning || (unitCount == 1 && !IsRamEncryptionEnabled())) +#else if (!ThreadPoolRunning || unitCount == 1) +#endif { switch (type) { case DecryptDataUnitsWork: - DecryptDataUnitsCurrentThreadEx (data, startUnitNo, unitCount, cryptoInfo); + DecryptDataUnitsCurrentThreadEx (data, startUnitNo, unitCount, cryptoInfo, NULL); break; case EncryptDataUnitsWork: - EncryptDataUnitsCurrentThreadEx (data, startUnitNo, unitCount, cryptoInfo); + EncryptDataUnitsCurrentThreadEx (data, startUnitNo, unitCount, cryptoInfo, NULL); break; default: diff --git a/src/Common/EncryptionThreadPool.h b/src/Common/EncryptionThreadPool.h index d9ed44a5bf..e56a12b75b 100644 --- a/src/Common/EncryptionThreadPool.h +++ b/src/Common/EncryptionThreadPool.h @@ -36,7 +36,7 @@ size_t GetCpuCount (WORD* pGroupCount); void EncryptionThreadPoolBeginKeyDerivation (TC_EVENT *completionEvent, TC_EVENT *noOutstandingWorkItemEvent, LONG *completionFlag, LONG *outstandingWorkItemCount, int pkcs5Prf, unsigned char *password, int passwordLength, unsigned char *salt, int iterationCount, int memoryCost, unsigned char *derivedKey, LONG *derivationResult, LONG volatile *pAbortKeyDerivation); void EncryptionThreadPoolBeginReadVolumeHeaderFinalization (TC_EVENT *keyDerivationCompletedEvent, TC_EVENT *noOutstandingWorkItemEvent, LONG* outstandingWorkItemCount, void* keyInfoBuffer, int keyInfoBufferSize, void* keyDerivationWorkItems, int keyDerivationWorkItemsSize); void EncryptionThreadPoolDoWork (EncryptionThreadPoolWorkType type, uint8 *data, const UINT64_STRUCT *startUnitNo, uint32 unitCount, PCRYPTO_INFO cryptoInfo); -BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount); +BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount, BOOL requireRamEncryptionScratch); void EncryptionThreadPoolStop (); size_t GetEncryptionThreadCount (); size_t GetMaxEncryptionThreadCount (); diff --git a/src/Common/Resource.h b/src/Common/Resource.h index bc5dd32a6f..61c28dbb2a 100644 --- a/src/Common/Resource.h +++ b/src/Common/Resource.h @@ -80,6 +80,13 @@ #define IDR_EFI_LEGACYSPEAKER_2023 582 #define IDR_EFI_DCSRE_2023 583 #define IDR_EFI_DCSINFO_2023 584 +#define IDR_EFI_DCSBOOT_ARM64 585 +#define IDR_EFI_DCSINT_ARM64 586 +#define IDR_EFI_DCSCFG_ARM64 587 +#define IDR_EFI_LEGACYSPEAKER_ARM64 588 +#define IDR_EFI_DCSRE_ARM64 589 +#define IDR_EFI_DCSINFO_ARM64 590 +#define IDR_EFI_DCSBML_ARM64 591 #define IDC_HW_AES_LABEL_LINK 5000 #define IDC_HW_AES 5001 #define IDC_PARALLELIZATION_LABEL_LINK 5002 @@ -234,7 +241,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 585 +#define _APS_NEXT_RESOURCE_VALUE 592 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 5148 #define _APS_NEXT_SYMED_VALUE 101 diff --git a/src/Common/Volumes.c b/src/Common/Volumes.c index 2f4c3f7929..d48cad1acf 100644 --- a/src/Common/Volumes.c +++ b/src/Common/Volumes.c @@ -199,7 +199,6 @@ int ReadVolumeHeaderWithAbort (BOOL bBoot, unsigned char *encryptedHeader, Passw uint16 headerVersion; int status = ERR_PARAMETER_INCORRECT; int primaryKeyOffset; - int pkcs5PrfCount = LAST_PRF_ID - FIRST_PRF_ID + 1; int iterationsCount = 0; int memoryCost = 0; LONG volatile abortKeyDerivation = 0; @@ -208,6 +207,7 @@ int ReadVolumeHeaderWithAbort (BOOL bBoot, unsigned char *encryptedHeader, Passw int lastArgon2DerivationResult = 0; #endif #if !defined(_UEFI) + int pkcs5PrfCount = LAST_PRF_ID - FIRST_PRF_ID + 1; TC_EVENT *keyDerivationCompletedEvent = NULL; TC_EVENT *noOutstandingWorkItemEvent = NULL; KeyDerivationWorkItem *keyDerivationWorkItems = NULL; diff --git a/src/Crypto/cpu.c b/src/Crypto/cpu.c index 90c9741620..58c89e2e41 100644 --- a/src/Crypto/cpu.c +++ b/src/Crypto/cpu.c @@ -10,7 +10,7 @@ #define EXCEPTION_EXECUTE_HANDLER 1 #endif -#ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY +#if !defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) && !defined(_UEFI) #include #include #endif @@ -31,7 +31,7 @@ int CpuId(uint32 input, uint32 output[4]) #else -#ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY +#if !defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) && !defined(_UEFI) #if defined(__cplusplus) extern "C" { @@ -290,7 +290,7 @@ static int Detect_MS_HyperV_AES () #endif -#if defined(__SHA__) || defined(__INTEL_COMPILER) || CRYPTOPP_SHANI_AVAILABLE +#if !defined(_UEFI) && (defined(__SHA__) || defined(__INTEL_COMPILER) || CRYPTOPP_SHANI_AVAILABLE) extern int TrySHA256(); #endif @@ -366,7 +366,7 @@ void DetectX86Features() } #endif -#if defined(__SHA__) || defined(__INTEL_COMPILER) || CRYPTOPP_SHANI_AVAILABLE +#if !defined(_UEFI) && (defined(__SHA__) || defined(__INTEL_COMPILER) || CRYPTOPP_SHANI_AVAILABLE) if (!g_hasSHA256) { g_hasSHA256 = TrySHA256(); diff --git a/src/Driver/DriveFilter.c b/src/Driver/DriveFilter.c index 27c6a75759..b57f9b84ff 100644 --- a/src/Driver/DriveFilter.c +++ b/src/Driver/DriveFilter.c @@ -74,6 +74,281 @@ static NTSTATUS DecoySystemWipeResult; static uint64 BootArgsRegionsDefault[] = { EFI_BOOTARGS_REGIONS_DEFAULT }; static uint64 BootArgsRegionsEFI[] = { EFI_BOOTARGS_REGIONS_EFI }; +#ifdef _M_ARM64 +typedef char VeraCryptArm64BootArgsPayloadSizeCheck[ + (TC_BOOT_LOADER_ARGS_OFFSET + sizeof (BootArguments) + sizeof (BOOT_CRYPTO_HEADER) + + 2 + sizeof (SECREGION_BOOT_PARAMS)) == VC_ARM64_BOOT_ARGS_HANDOFF_BOOT_PARAMS_LENGTH ? 1 : -1]; + +static BOOL BootArgsFromArm64Payload = FALSE; +static volatile LONG BootArgsPayloadReadAttempted = FALSE; + +static NTSTATUS ClearArm64RescueDecryptionComplete (void) +{ + UNICODE_STRING variableName; + GUID variableGuid = VC_ARM64_BOOT_ARGS_HANDOFF_GUID_INIT; + uint8 emptyValue = 0; + NTSTATUS status; + + RtlInitUnicodeString ( + &variableName, + VC_ARM64_RESCUE_DECRYPTION_COMPLETE_VARIABLE_NAME); + status = ExSetFirmwareEnvironmentVariable ( + &variableName, + &variableGuid, + &emptyValue, + 0, + VC_ARM64_RESCUE_DECRYPTION_COMPLETE_VARIABLE_ATTRIBUTES); + if (status == STATUS_VARIABLE_NOT_FOUND) + return STATUS_SUCCESS; + + return status; +} + + +static NTSTATUS CheckArm64RescueDecryptionComplete ( + uint32 headerSaltCrc32, + BOOL *complete) +{ + UNICODE_STRING variableName; + GUID variableGuid = VC_ARM64_BOOT_ARGS_HANDOFF_GUID_INIT; + VeraCryptArm64RescueDecryptionComplete marker; + ULONG attributes = 0; + ULONG variableLength = sizeof (marker); + BOOL valid = FALSE; + NTSTATUS status; + + if (!complete) + return STATUS_INVALID_PARAMETER; + + *complete = FALSE; + memset (&marker, 0, sizeof (marker)); + RtlInitUnicodeString ( + &variableName, + VC_ARM64_RESCUE_DECRYPTION_COMPLETE_VARIABLE_NAME); + status = ExGetFirmwareEnvironmentVariable ( + &variableName, + &variableGuid, + &marker, + &variableLength, + &attributes); + if (status == STATUS_VARIABLE_NOT_FOUND) + return STATUS_SUCCESS; + if (NT_SUCCESS (status)) + { + valid = variableLength == sizeof (marker) + && attributes == VC_ARM64_RESCUE_DECRYPTION_COMPLETE_VARIABLE_ATTRIBUTES + && marker.Magic == VC_ARM64_RESCUE_DECRYPTION_COMPLETE_MAGIC + && marker.Version == VC_ARM64_RESCUE_DECRYPTION_COMPLETE_VERSION + && marker.Size == sizeof (marker) + && marker.HeaderSaltCrc32 == headerSaltCrc32 + && marker.Crc32 == GetCrc32 ( + (uint8 *) &marker, + (int) FIELD_OFFSET (VeraCryptArm64RescueDecryptionComplete, Crc32)); + } + else if (status != STATUS_BUFFER_TOO_SMALL) + { + burn (&marker, sizeof (marker)); + return status; + } + + if (!valid) + { + /* + * Invalid or mismatched records are discarded without relaxing the + * fail-closed registry requirement. + */ + status = ClearArm64RescueDecryptionComplete (); + } + else + { + *complete = TRUE; + status = STATUS_SUCCESS; + } + + burn (&marker, sizeof (marker)); + return status; +} + + +static NTSTATUS LoadArm64BootArgumentsPayload (void) +{ + UNICODE_STRING variableName; + GUID variableGuid = VC_ARM64_BOOT_ARGS_HANDOFF_GUID_INIT; + ULONG attributes = 0; + ULONG variableLength = sizeof (VeraCryptArm64BootArgsHandoffDescriptor); + VeraCryptArm64BootArgsHandoffDescriptor descriptor; + PHYSICAL_ADDRESS payloadAddress; + uint8 *mappedRegion = NULL; + uint8 variable[VC_ARM64_BOOT_ARGS_HANDOFF_PAYLOAD_LENGTH]; + uint8 *payload; + VeraCryptArm64BootArgsHandoffPayloadHeader header; + VeraCryptArm64BootArgsHandoffAllocationTag allocationTag; + BootArguments bootArguments; + BOOT_CRYPTO_HEADER bootCryptoInfo; + SECREGION_BOOT_PARAMS secRegionParams; + Hash *bootHash; + NTSTATUS status; + + memset (&descriptor, 0, sizeof (descriptor)); + memset (variable, 0, sizeof (variable)); + memset (&header, 0, sizeof (header)); + memset (&allocationTag, 0, sizeof (allocationTag)); + memset (&bootArguments, 0, sizeof (bootArguments)); + memset (&bootCryptoInfo, 0, sizeof (bootCryptoInfo)); + memset (&secRegionParams, 0, sizeof (secRegionParams)); + + if (InterlockedCompareExchange (&BootArgsPayloadReadAttempted, TRUE, FALSE) != FALSE) + return STATUS_INVALID_DEVICE_STATE; + + RtlInitUnicodeString (&variableName, VC_ARM64_BOOT_ARGS_HANDOFF_VARIABLE_NAME); + status = ExGetFirmwareEnvironmentVariable ( + &variableName, + &variableGuid, + &descriptor, + &variableLength, + &attributes); + if (!NT_SUCCESS (status)) + goto ret; + + if (variableLength != sizeof (descriptor) + || attributes != VC_ARM64_BOOT_ARGS_HANDOFF_VARIABLE_ATTRIBUTES) + { + status = STATUS_INVALID_PARAMETER; + goto ret; + } + + if (descriptor.Magic != VC_ARM64_BOOT_ARGS_HANDOFF_DESCRIPTOR_MAGIC + || descriptor.Version != VC_ARM64_BOOT_ARGS_HANDOFF_VERSION + || descriptor.Size != sizeof (descriptor) + || descriptor.PhysicalAddress == 0 + || (descriptor.PhysicalAddress & (VC_ARM64_BOOT_ARGS_HANDOFF_REGION_LENGTH - 1)) != 0 + || descriptor.PhysicalAddress + VC_ARM64_BOOT_ARGS_HANDOFF_REGION_LENGTH < descriptor.PhysicalAddress + || descriptor.RegionLength != VC_ARM64_BOOT_ARGS_HANDOFF_REGION_LENGTH + || descriptor.PayloadLength != VC_ARM64_BOOT_ARGS_HANDOFF_PAYLOAD_LENGTH + || descriptor.PayloadLength > VC_ARM64_BOOT_ARGS_HANDOFF_ALLOCATION_TAG_OFFSET + || descriptor.Crc32 != GetCrc32 ( + (uint8 *) &descriptor, + (int) FIELD_OFFSET (VeraCryptArm64BootArgsHandoffDescriptor, Crc32))) + { + status = STATUS_CRC_ERROR; + goto ret; + } + + payloadAddress.QuadPart = descriptor.PhysicalAddress; + mappedRegion = MmMapIoSpace ( + payloadAddress, + VC_ARM64_BOOT_ARGS_HANDOFF_REGION_LENGTH, + MmCached); + if (!mappedRegion) + { + status = STATUS_INSUFFICIENT_RESOURCES; + goto ret; + } + + memcpy ( + &allocationTag, + mappedRegion + VC_ARM64_BOOT_ARGS_HANDOFF_ALLOCATION_TAG_OFFSET, + sizeof (allocationTag)); + if (allocationTag.Magic != VC_ARM64_BOOT_ARGS_HANDOFF_ALLOCATION_TAG_MAGIC + || allocationTag.Version != VC_ARM64_BOOT_ARGS_HANDOFF_VERSION + || allocationTag.Size != sizeof (allocationTag) + || allocationTag.PhysicalAddress != descriptor.PhysicalAddress + || allocationTag.RegionLength != descriptor.RegionLength + || allocationTag.Crc32 != GetCrc32 ( + (uint8 *) &allocationTag, + (int) FIELD_OFFSET (VeraCryptArm64BootArgsHandoffAllocationTag, Crc32))) + { + status = STATUS_CRC_ERROR; + goto ret; + } + + memcpy (variable, mappedRegion, VC_ARM64_BOOT_ARGS_HANDOFF_PAYLOAD_LENGTH); + burn (mappedRegion, VC_ARM64_BOOT_ARGS_HANDOFF_REGION_LENGTH); + memcpy (&header, variable, sizeof (header)); + payload = variable + sizeof (header); + + if (header.Magic != VC_ARM64_BOOT_ARGS_HANDOFF_PAYLOAD_MAGIC + || header.Version != VC_ARM64_BOOT_ARGS_HANDOFF_VERSION + || header.Size != sizeof (header) + || header.BootArgsOffset != TC_BOOT_LOADER_ARGS_OFFSET + || header.PayloadLength != VC_ARM64_BOOT_ARGS_HANDOFF_BOOT_PARAMS_LENGTH + || header.Crc32 != GetCrc32 (variable, (int) FIELD_OFFSET (VeraCryptArm64BootArgsHandoffPayloadHeader, Crc32)) + || descriptor.PayloadCrc32 != GetCrc32 ( + variable, + (int) descriptor.PayloadLength) + || header.PayloadCrc32 != GetCrc32 (payload, (int) header.PayloadLength)) + { + status = STATUS_CRC_ERROR; + goto ret; + } + memcpy (&bootArguments, payload + TC_BOOT_LOADER_ARGS_OFFSET, sizeof (bootArguments)); + if (!TC_IS_BOOT_ARGUMENTS_SIGNATURE (bootArguments.Signature) + || bootArguments.BootLoaderVersion != VERSION_NUM + || bootArguments.BootArgumentsCrc32 != GetCrc32 ( + (uint8 *) &bootArguments, + (int) FIELD_OFFSET (BootArguments, BootArgumentsCrc32)) + || bootArguments.BootPassword.Length > MAX_LEGACY_PASSWORD + || ((bootArguments.Flags & 0xffffUL) & ~TC_BOOT_ARGS_FLAG_EXTRA_BOOT_PARTITION) != 0 + || bootArguments.CryptoInfoOffset != TC_BOOT_LOADER_ARGS_OFFSET + sizeof (BootArguments) + || bootArguments.CryptoInfoLength != sizeof (BOOT_CRYPTO_HEADER) + 2 + sizeof (SECREGION_BOOT_PARAMS)) + { + status = STATUS_INVALID_PARAMETER; + goto ret; + } + + memcpy (&bootCryptoInfo, payload + bootArguments.CryptoInfoOffset, sizeof (bootCryptoInfo)); + memcpy ( + &secRegionParams, + payload + bootArguments.CryptoInfoOffset + sizeof (bootCryptoInfo) + 2, + sizeof (secRegionParams)); + + bootHash = HashGet (bootCryptoInfo.pkcs5); + if (bootCryptoInfo.ea < EAGetFirst () + || bootCryptoInfo.ea > EAGetCount () + || EAGetFirstCipher (bootCryptoInfo.ea) == 0 + || EAGetFirstMode (bootCryptoInfo.ea) != bootCryptoInfo.mode + || bootCryptoInfo.mode != XTS + || bootHash == NULL + || payload[bootArguments.CryptoInfoOffset + sizeof (bootCryptoInfo)] != 0 + || payload[bootArguments.CryptoInfoOffset + sizeof (bootCryptoInfo) + 1] != 0 + || secRegionParams.Ptr != 0 + || secRegionParams.Size != 0 + || secRegionParams.Crc != GetCrc32 ((uint8 *) &secRegionParams, 12)) + { + status = STATUS_INVALID_PARAMETER; + goto ret; + } + + status = STATUS_SUCCESS; + +ret: + if (NT_SUCCESS (status)) + { + BootLoaderArgsPtr = 0; + BootArgs = bootArguments; + BootArgs.CryptoInfoLength = 0; + BootArgsValid = TRUE; + BootArgsFromArm64Payload = TRUE; + BootDriveSignatureValid = TRUE; + BootPkcs5 = bootCryptoInfo.pkcs5; + BootSecRegionData = NULL; + BootSecRegionSize = 0; + burn (BootLoaderFingerprint, sizeof (BootLoaderFingerprint)); + } + + burn (&secRegionParams, sizeof (secRegionParams)); + burn (&bootCryptoInfo, sizeof (bootCryptoInfo)); + burn (&bootArguments, sizeof (bootArguments)); + burn (&allocationTag, sizeof (allocationTag)); + burn (&header, sizeof (header)); + burn (&descriptor, sizeof (descriptor)); + burn (variable, sizeof (variable)); + if (mappedRegion) + MmUnmapIoSpace (mappedRegion, VC_ARM64_BOOT_ARGS_HANDOFF_REGION_LENGTH); + return status; +} +#endif + static BOOL GetHiddenSystemPartitionOffset (uint64 *hiddenPartitionOffset) { uint64 hiddenOffset = BootArgs.HiddenSystemPartitionStart; @@ -162,6 +437,11 @@ NTSTATUS LoadBootArguments (BOOL bIsEfi) KeInitializeMutex (&MountMutex, 0); // __debugbreak(); +#ifdef _M_ARM64 + if (bIsEfi) + return LoadArm64BootArgumentsPayload (); +#endif + for (bootLoaderArgsIndex = 0; bootLoaderArgsIndex < BootArgsRegionsCount && status != STATUS_SUCCESS; ++bootLoaderArgsIndex) @@ -483,6 +763,349 @@ static void ComputeBootLoaderFingerprint(PDEVICE_OBJECT LowerDeviceObject, uint8 } +static void PublishBootDriveState (DriveFilterExtension *Extension) +{ +#ifdef _M_ARM64 + Extension->MagicNumber = TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER; + Extension->VolumeHeaderPresent = TRUE; + Extension->DriveMounted = TRUE; + BootDriveFilterExtension = Extension; + + KeMemoryBarrier (); + InterlockedExchange ((volatile LONG *) &Extension->BootDrive, TRUE); + KeMemoryBarrier (); + InterlockedExchange ((volatile LONG *) &BootDriveFound, TRUE); +#else + BootDriveFilterExtension = Extension; + BootDriveFound = Extension->BootDrive = Extension->DriveMounted = Extension->VolumeHeaderPresent = TRUE; + BootDriveFilterExtension->MagicNumber = TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER; +#endif +} + + +static BOOL IsBootDriveStatePublished (DriveFilterExtension *Extension) +{ +#ifdef _M_ARM64 + return InterlockedCompareExchangeAcquire ((volatile LONG *) &Extension->BootDrive, FALSE, FALSE) != FALSE; +#else + return Extension->BootDrive; +#endif +} + + +#ifdef _M_ARM64 +static NTSTATUS VcMapArm64BootWriteBuffer (PIRP irp, ULONG length, PUCHAR *outVa, PMDL *outTempMdl) +{ + ULONG mapFlags = HighPagePriority | MdlMappingNoExecute | MdlMappingNoWrite; + PUCHAR va = NULL; + PMDL mdl = NULL; + + ASSERT (outVa && outTempMdl); + *outVa = NULL; + *outTempMdl = NULL; + + if (length == 0) + return STATUS_INVALID_PARAMETER; + + if (irp->MdlAddress) + { + if (MmGetMdlByteCount (irp->MdlAddress) < length) + return STATUS_INVALID_USER_BUFFER; + + va = (PUCHAR) MmGetSystemAddressForMdlSafe (irp->MdlAddress, mapFlags); + if (!va) + return STATUS_INSUFFICIENT_RESOURCES; + + *outVa = va; + return STATUS_SUCCESS; + } + + if (irp->AssociatedIrp.SystemBuffer) + { + *outVa = (PUCHAR) irp->AssociatedIrp.SystemBuffer; + return STATUS_SUCCESS; + } + + if (!irp->UserBuffer) + return STATUS_INVALID_USER_BUFFER; + + mdl = IoAllocateMdl (irp->UserBuffer, length, FALSE, FALSE, NULL); + if (!mdl) + return STATUS_INSUFFICIENT_RESOURCES; + + __try + { + MmProbeAndLockPages (mdl, irp->RequestorMode, IoReadAccess); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + IoFreeMdl (mdl); + return STATUS_INVALID_USER_BUFFER; + } + + va = (PUCHAR) MmGetSystemAddressForMdlSafe (mdl, mapFlags); + if (!va) + { + MmUnlockPages (mdl); + IoFreeMdl (mdl); + return STATUS_INSUFFICIENT_RESOURCES; + } + + *outTempMdl = mdl; + *outVa = va; + return STATUS_SUCCESS; +} + + +static void VcUnmapArm64BootWriteBuffer (PMDL tempMdl) +{ + if (tempMdl) + { + MmUnlockPages (tempMdl); + IoFreeMdl (tempMdl); + } +} + + +static BOOL VcArm64BootWriteRangeValid (LONGLONG offset, ULONG length, ULONGLONG *endExclusive) +{ + if (length == 0 || offset < 0) + return FALSE; + + if ((ULONGLONG) offset > ((ULONGLONG) -1) - length) + return FALSE; + + *endExclusive = (ULONGLONG) offset + length; + return TRUE; +} + + +static BOOL VcArm64BootWriteBaseReady (DriveFilterExtension *Extension) +{ + EncryptedIoQueue *queue = &Extension->Queue; + + if (!BootArgsFromArm64Payload || Extension != BootDriveFilterExtension) + return FALSE; + + if (KeGetCurrentIrql() > APC_LEVEL) + return FALSE; + + if (!Extension->BootDrive || !Extension->DriveMounted || Extension->HiddenSystem) + return FALSE; + + if (!queue->CryptoInfo || !queue->LowerDeviceObject) + return FALSE; + + if (queue->ThreadBlockReadWrite || queue->EncryptedAreaEndUpdatePending) + return FALSE; + + if (queue->RemapEncryptedArea || queue->CryptoInfo->bPartitionInInactiveSysEncScope) + return FALSE; + + return TRUE; +} + + +static BOOL VcArm64BootWriteBlocked (DriveFilterExtension *Extension, LONGLONG offset, ULONG length, NTSTATUS *status) +{ + EncryptedIoQueue *queue = &Extension->Queue; + ULONGLONG endExclusive; + ULONGLONG endInclusive; + + if (!VcArm64BootWriteRangeValid (offset, length, &endExclusive)) + { + *status = STATUS_INVALID_PARAMETER; + return TRUE; + } + + endInclusive = endExclusive - 1; + if (RegionsOverlap (offset, endInclusive, + TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, + TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET + TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE - 1)) + { + *status = STATUS_MEDIA_WRITE_PROTECTED; + return TRUE; + } + + if (IsHiddenSystemRunning () + && (RegionsOverlap (offset, endInclusive, + TC_SECTOR_SIZE_BIOS, + TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS - 1) + || RegionsOverlap (offset, endInclusive, GetBootDriveLength (), _I64_MAX))) + { + *status = STATUS_MEDIA_WRITE_PROTECTED; + return TRUE; + } + + if (queue->SecRegionData != NULL && queue->SecRegionSize > 512 + && UpdateBuffer (NULL, queue->SecRegionData, queue->SecRegionSize, + (uint64) offset, length, FALSE)) + { + *status = STATUS_MEDIA_WRITE_PROTECTED; + return TRUE; + } + + return FALSE; +} + + +static void VcEncryptArm64BootWrite (EncryptedIoQueue *queue, PUCHAR buffer, LONGLONG offset, ULONG length) +{ + uint64 intersectStart; + uint32 intersectLength; + + if (queue->EncryptedAreaStart != -1 && queue->EncryptedAreaEnd != -1) + { + GetIntersection ((uint64) offset, length, + queue->EncryptedAreaStart, queue->EncryptedAreaEnd, + &intersectStart, &intersectLength); + if (intersectLength > 0) + { + UINT64_STRUCT dataUnit; + + ASSERT (intersectStart >= (uint64) offset); + ASSERT ((intersectStart - (uint64) offset) + intersectLength <= length); + dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE; + EncryptDataUnits (buffer + (intersectStart - (uint64) offset), + &dataUnit, intersectLength / ENCRYPTION_DATA_UNIT_SIZE, + queue->CryptoInfo); + } + } +} + + +static void VcDecryptArm64BootWrite (EncryptedIoQueue *queue, PUCHAR buffer, LONGLONG offset, ULONG length) +{ + uint64 intersectStart; + uint32 intersectLength; + + if (queue->EncryptedAreaStart != -1 && queue->EncryptedAreaEnd != -1) + { + GetIntersection ((uint64) offset, length, + queue->EncryptedAreaStart, queue->EncryptedAreaEnd, + &intersectStart, &intersectLength); + if (intersectLength > 0) + { + UINT64_STRUCT dataUnit; + + ASSERT (intersectStart >= (uint64) offset); + ASSERT ((intersectStart - (uint64) offset) + intersectLength <= length); + dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE; + DecryptDataUnits (buffer + (intersectStart - (uint64) offset), + &dataUnit, intersectLength / ENCRYPTION_DATA_UNIT_SIZE, + queue->CryptoInfo); + } + } + + if (queue->SecRegionData != NULL && queue->SecRegionSize > 512) + UpdateBuffer (buffer, queue->SecRegionData, queue->SecRegionSize, + (uint64) offset, length, TRUE); +} + + +static NTSTATUS VcArm64BootWrite (PVOID context, PIRP Irp, PIO_STACK_LOCATION irpSp) +{ + DriveFilterExtension *Extension = (DriveFilterExtension *) context; + EncryptedIoQueue *queue = &Extension->Queue; + LARGE_INTEGER offset = irpSp->Parameters.Write.ByteOffset; + ULONG length = irpSp->Parameters.Write.Length; + PUCHAR dataBuffer = NULL; + PUCHAR writeBuffer = NULL; + PMDL tempMdl = NULL; + NTSTATUS status; + + if (!VcArm64BootWriteBaseReady (Extension)) + status = STATUS_DEVICE_NOT_READY; + else if (!VcArm64BootWriteBlocked (Extension, offset.QuadPart, length, &status)) + status = VcMapArm64BootWriteBuffer (Irp, length, &dataBuffer, &tempMdl); + + if (NT_SUCCESS (status)) + { + if ((length & (ENCRYPTION_DATA_UNIT_SIZE - 1)) == 0 + && (offset.QuadPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)) == 0) + { + writeBuffer = TCalloc (length); + if (!writeBuffer) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + memcpy (writeBuffer, dataBuffer, length); + VcEncryptArm64BootWrite (queue, writeBuffer, offset.QuadPart, length); + status = TCWriteDevice (Extension->LowerDeviceObject, writeBuffer, offset, length); + TCfree (writeBuffer); + } + } + else + { + LARGE_INTEGER alignedOffset; + ULONGLONG endExclusive = (ULONGLONG) offset.QuadPart + length; + ULONGLONG alignedStart = (ULONGLONG) offset.QuadPart + & ~((ULONGLONG) ENCRYPTION_DATA_UNIT_SIZE - 1); + ULONGLONG alignedEnd; + ULONGLONG alignedSpan; + ULONG alignedLength; + + if (endExclusive > ((ULONGLONG) -1) - (ENCRYPTION_DATA_UNIT_SIZE - 1)) + { + status = STATUS_INVALID_PARAMETER; + } + else + { + alignedEnd = (endExclusive + ENCRYPTION_DATA_UNIT_SIZE - 1) + & ~((ULONGLONG) ENCRYPTION_DATA_UNIT_SIZE - 1); + alignedSpan = alignedEnd - alignedStart; + if (alignedSpan < length || alignedSpan > MAXULONG) + { + status = STATUS_INVALID_PARAMETER; + } + else + { + alignedLength = (ULONG) alignedSpan; + alignedOffset.QuadPart = (LONGLONG) alignedStart; + if (!VcArm64BootWriteBlocked ( + Extension, alignedOffset.QuadPart, alignedLength, &status)) + { + writeBuffer = TCalloc (alignedLength); + if (!writeBuffer) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + status = TCReadDevice ( + Extension->LowerDeviceObject, + writeBuffer, alignedOffset, alignedLength); + if (NT_SUCCESS (status)) + { + VcDecryptArm64BootWrite ( + queue, writeBuffer, + alignedOffset.QuadPart, alignedLength); + memcpy ( + writeBuffer + (offset.QuadPart - alignedOffset.QuadPart), + dataBuffer, length); + VcEncryptArm64BootWrite ( + queue, writeBuffer, + alignedOffset.QuadPart, alignedLength); + status = TCWriteDevice ( + Extension->LowerDeviceObject, + writeBuffer, alignedOffset, alignedLength); + } + TCfree (writeBuffer); + } + } + } + } + } + } + + VcUnmapArm64BootWriteBuffer (tempMdl); + return status; +} +#endif + + static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password, __unaligned uint32 *headerSaltCrc32) { BOOL hiddenVolume = (BootArgs.HiddenSystemPartitionStart != 0); @@ -651,6 +1274,29 @@ static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password, { Extension->Queue.EncryptedAreaStart = -1; Extension->Queue.EncryptedAreaEnd = -1; +#ifdef _M_ARM64 + if (BootArgsFromArm64Payload) + { + BOOL rescueDecryptionComplete = FALSE; + + status = CheckArm64RescueDecryptionComplete ( + Extension->VolumeHeaderSaltCrc32, + &rescueDecryptionComplete); + if (!NT_SUCCESS (status)) + goto ret; + + if (rescueDecryptionComplete) + { + status = SetArm64BootArgsHandoffRequired (FALSE); + if (!NT_SUCCESS (status)) + goto ret; + + status = ClearArm64RescueDecryptionComplete (); + if (!NT_SUCCESS (status)) + goto ret; + } + } +#endif } Dump ("Loaded: ConfiguredEncryptedAreaStart=%I64d (%I64d) ConfiguredEncryptedAreaEnd=%I64d (%I64d)\n", Extension->ConfiguredEncryptedAreaStart / 1024 / 1024, Extension->ConfiguredEncryptedAreaStart, Extension->ConfiguredEncryptedAreaEnd / 1024 / 1024, Extension->ConfiguredEncryptedAreaEnd); @@ -658,9 +1304,10 @@ static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password, // at this stage, we have already erased boot loader scheduled keys - BootDriveFilterExtension = Extension; - BootDriveFound = Extension->BootDrive = Extension->DriveMounted = Extension->VolumeHeaderPresent = TRUE; - BootDriveFilterExtension->MagicNumber = TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER; +#ifdef _M_ARM64 + if (!BootArgsFromArm64Payload) +#endif + PublishBootDriveState (Extension); // Try to load password cached if saved in SecRegion if (BootSecRegionData != NULL && BootSecRegionSize > 1024) { @@ -740,7 +1387,20 @@ static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password, VcProtectKeys (Extension->HeaderCryptoInfo, VcGetEncryptionID (Extension->HeaderCryptoInfo)); VcProtectKeys (Extension->Queue.CryptoInfo, VcGetEncryptionID (Extension->Queue.CryptoInfo)); } - + +#ifdef _M_ARM64 + { + BOOL useArm64BootWrite = BootArgsFromArm64Payload + && !Extension->HiddenSystem + && !Extension->Queue.RemapEncryptedArea; + + Extension->Queue.Arm64BootWrite = + useArm64BootWrite ? VcArm64BootWrite : NULL; + Extension->Queue.Arm64BootWriteContext = + useArm64BootWrite ? Extension : NULL; + } +#endif + status = EncryptedIoQueueStart (&Extension->Queue); if (!NT_SUCCESS (status)) TC_BUG_CHECK (status); @@ -753,7 +1413,7 @@ static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password, } // Hidden system hibernation is not supported if an extra boot partition is present as the system is not allowed to update the boot partition - if (IsHiddenSystemRunning() && (BootArgs.Flags & TC_BOOT_ARGS_FLAG_EXTRA_BOOT_PARTITION)) + if (Extension->HiddenSystem && (BootArgs.Flags & TC_BOOT_ARGS_FLAG_EXTRA_BOOT_PARTITION)) { CrashDumpEnabled = FALSE; HibernationEnabled = FALSE; @@ -779,6 +1439,7 @@ static NTSTATUS SaveDriveVolumeHeader (DriveFilterExtension *Extension) NTSTATUS status = STATUS_SUCCESS; LARGE_INTEGER offset; uint8 *header; + PCRYPTO_INFO temporaryCryptoInfo = NULL; header = TCalloc (TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE); if (!header) @@ -811,12 +1472,18 @@ static NTSTATUS SaveDriveVolumeHeader (DriveFilterExtension *Extension) uint64 encryptedAreaLength = Extension->Queue.EncryptedAreaEnd + 1 - Extension->Queue.EncryptedAreaStart; uint8 *fieldPos = header + TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH; PCRYPTO_INFO pCryptoInfo = Extension->HeaderCryptoInfo; - CRYPTO_INFO tmpCI; if (IsRamEncryptionEnabled()) { - memcpy (&tmpCI, pCryptoInfo, sizeof (CRYPTO_INFO)); - VcUnprotectKeys (&tmpCI, VcGetEncryptionID (pCryptoInfo)); - pCryptoInfo = &tmpCI; + temporaryCryptoInfo = crypto_open (); + if (!temporaryCryptoInfo) + { + status = STATUS_INSUFFICIENT_RESOURCES; + goto ret; + } + + memcpy (temporaryCryptoInfo, pCryptoInfo, sizeof (CRYPTO_INFO)); + VcUnprotectKeys (temporaryCryptoInfo, VcGetEncryptionID (pCryptoInfo)); + pCryptoInfo = temporaryCryptoInfo; } DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, pCryptoInfo); @@ -835,10 +1502,6 @@ static NTSTATUS SaveDriveVolumeHeader (DriveFilterExtension *Extension) mputLong (fieldPos, headerCrc32); EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, pCryptoInfo); - if (IsRamEncryptionEnabled()) - { - burn (&tmpCI, sizeof (CRYPTO_INFO)); - } } status = TCWriteDevice (Extension->LowerDeviceObject, header, offset, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE); @@ -849,11 +1512,51 @@ static NTSTATUS SaveDriveVolumeHeader (DriveFilterExtension *Extension) } ret: + if (temporaryCryptoInfo) + crypto_close (temporaryCryptoInfo); + TCfree (header); return status; } +#ifdef _M_ARM64 +static NTSTATUS VerifyDriveVolumeHeaderErased (DriveFilterExtension *Extension) +{ + LARGE_INTEGER offset; + NTSTATUS status; + uint8 *header; + size_t i; + + header = TCalloc (TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE); + if (!header) + return STATUS_INSUFFICIENT_RESOURCES; + + offset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET; + status = TCReadDevice ( + Extension->LowerDeviceObject, + header, + offset, + TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE); + if (NT_SUCCESS (status)) + { + for (i = 0; i < TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE; ++i) + { + if (header[i] != 0) + { + status = STATUS_DATA_ERROR; + break; + } + } + } + + burn (header, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE); + TCfree (header); + return status; +} +#endif + + static NTSTATUS PassIrp (PDEVICE_OBJECT deviceObject, PIRP irp) { IoSkipCurrentIrpStackLocation (irp); @@ -924,10 +1627,17 @@ static void CheckDeviceTypeAndMount (DriveFilterExtension *filterExtension) if (!BootDriveFound) { Password bootPass = {0}; + NTSTATUS mountStatus; bootPass.Length = BootArgs.BootPassword.Length; memcpy (bootPass.Text, BootArgs.BootPassword.Text, BootArgs.BootPassword.Length); - MountDrive (filterExtension, &bootPass, &BootArgs.HeaderSaltCrc32); + mountStatus = MountDrive (filterExtension, &bootPass, &BootArgs.HeaderSaltCrc32); burn (&bootPass, sizeof (bootPass)); +#ifdef _M_ARM64 + if (NT_SUCCESS (mountStatus) && BootArgsFromArm64Payload) + PublishBootDriveState (filterExtension); +#else + UNREFERENCED_PARAMETER (mountStatus); +#endif } KeReleaseMutex (&MountMutex, FALSE); @@ -1149,7 +1859,7 @@ NTSTATUS DriveFilterDispatchIrp (PDEVICE_OBJECT DeviceObject, PIRP Irp) { case IRP_MJ_READ: case IRP_MJ_WRITE: - if (Extension->BootDrive) + if (IsBootDriveStatePublished (Extension)) { status = EncryptedIoQueueAddIrp (&Extension->Queue, Irp); @@ -1400,7 +2110,8 @@ static NTSTATUS HiberDriverWriteFunctionFilter (int filterNumber, PLARGE_INTEGER EncryptDataUnitsCurrentThreadEx (HibernationWriteBuffer + (intersectStart - offset), &dataUnit, intersectLength / ENCRYPTION_DATA_UNIT_SIZE, - BootDriveFilterExtension->Queue.CryptoInfo); + BootDriveFilterExtension->Queue.CryptoInfo, + NULL); encryptedDataMdl = HibernationWriteBufferMdl; MmInitializeMdl (encryptedDataMdl, HibernationWriteBuffer, dataLength); @@ -1657,6 +2368,25 @@ static VOID SetupThreadProc (PVOID threadArg) } TransformWaitingForIdle = FALSE; +#ifdef _M_ARM64 + if (SetupRequest.SetupMode == SetupEncryption) + { + status = ClearArm64RescueDecryptionComplete (); + if (!NT_SUCCESS (status)) + { + SetupResult = status; + goto err; + } + + status = SetArm64BootArgsHandoffRequired (TRUE); + if (!NT_SUCCESS (status)) + { + SetupResult = status; + goto err; + } + } +#endif + switch (SetupRequest.SetupMode) { case SetupEncryption: @@ -1905,6 +2635,23 @@ static VOID SetupThreadProc (PVOID threadArg) SetupResult = status; } +#ifdef _M_ARM64 + if (SetupRequest.SetupMode == SetupDecryption + && Extension->ConfiguredEncryptedAreaEnd == -1 + && NT_SUCCESS (SetupResult)) + { + status = TCFlushDevice (Extension->LowerDeviceObject); + if (NT_SUCCESS (status)) + status = VerifyDriveVolumeHeaderErased (Extension); + if (NT_SUCCESS (status)) + status = SetArm64BootArgsHandoffRequired (FALSE); + if (NT_SUCCESS (status)) + status = ClearArm64RescueDecryptionComplete (); + if (!NT_SUCCESS (status)) + SetupResult = status; + } +#endif + if (SetupRequest.SetupMode == SetupDecryption && Extension->ConfiguredEncryptedAreaEnd == -1 && Extension->DriveMounted) { while (!RootDeviceControlMutexAcquireNoWait() && !EncryptionSetupThreadAbortRequested) diff --git a/src/Driver/DumpFilter.c b/src/Driver/DumpFilter.c index f26b583037..bf88e78229 100644 --- a/src/Driver/DumpFilter.c +++ b/src/Driver/DumpFilter.c @@ -23,6 +23,7 @@ typedef struct _DumpFilterContext uint8* WriteFilterBuffer; SIZE_T WriteFilterBufferSize; PMDL WriteFilterBufferMdl; + CRYPTO_INFO_SCRATCH CryptoScratch; } DumpFilterContext; // In crash/hibernate paths, execution can be at HIGH_LEVEL and many memory manager @@ -311,7 +312,8 @@ static NTSTATUS DumpFilterWrite (PFILTER_EXTENSION filterExtension, PLARGE_INTEG EncryptDataUnitsCurrentThreadEx (dumpContext->WriteFilterBuffer + (intersectStart - offset), &dataUnit, intersectLength / ENCRYPTION_DATA_UNIT_SIZE, - dumpContext->BootDriveFilterExtension->Queue.CryptoInfo); + dumpContext->BootDriveFilterExtension->Queue.CryptoInfo, + &dumpContext->CryptoScratch); } // diff --git a/src/Driver/EncryptedIoQueue.c b/src/Driver/EncryptedIoQueue.c index ec7f5a9a8b..ac2967a109 100644 --- a/src/Driver/EncryptedIoQueue.c +++ b/src/Driver/EncryptedIoQueue.c @@ -410,6 +410,9 @@ static VOID CompleteIrpWorkItemRoutine(PDEVICE_OBJECT DeviceObject, PVOID Contex EncryptedIoQueueItem* item = (EncryptedIoQueueItem * ) workItem->Item; EncryptedIoQueue* queue = item->Queue; KIRQL oldIrql; +#ifdef _M_ARM64 + BOOL dynamicallyAllocated = workItem->DynamicallyAllocated; +#endif UNREFERENCED_PARAMETER(DeviceObject); __try @@ -422,17 +425,37 @@ static VOID CompleteIrpWorkItemRoutine(PDEVICE_OBJECT DeviceObject, PVOID Contex } __finally { - // Return the work item to the free list - KeAcquireSpinLock(&queue->WorkItemLock, &oldIrql); - InsertTailList(&queue->FreeWorkItemsList, &workItem->ListEntry); - KeReleaseSpinLock(&queue->WorkItemLock, oldIrql); +#ifdef _M_ARM64 + if (dynamicallyAllocated) + { + IoFreeWorkItem (workItem->WorkItem); + TCfree (workItem); + } + else +#endif + { + // Return the work item to the free list + KeAcquireSpinLock(&queue->WorkItemLock, &oldIrql); + InsertTailList(&queue->FreeWorkItemsList, &workItem->ListEntry); + KeReleaseSpinLock(&queue->WorkItemLock, oldIrql); - // Release the semaphore to signal that a work item is available - KeReleaseSemaphore(&queue->WorkItemSemaphore, IO_DISK_INCREMENT, 1, FALSE); + // Release the semaphore to signal that a work item is available + KeReleaseSemaphore(&queue->WorkItemSemaphore, IO_DISK_INCREMENT, 1, FALSE); + } // Free the item ReleasePoolBuffer(queue, item); +#ifdef _M_ARM64 + if (InterlockedCompareExchange( + &queue->Arm64BootWriteCompletionDeferred, + FALSE, + FALSE) != FALSE) + { + KeSetEvent(&queue->CompletionThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE); + } +#endif + // Decrement ActiveWorkItems last: once it reaches zero, // EncryptedIoQueueStop frees the work item pool and buffer pools, so // this routine must not touch queue resources afterwards. The @@ -448,10 +471,96 @@ static VOID CompleteIrpWorkItemRoutine(PDEVICE_OBJECT DeviceObject, PVOID Contex } } -// Handles the completion of the original IRP. -static VOID HandleCompleteOriginalIrp(EncryptedIoQueue* queue, EncryptedIoRequest* request) +static VOID SubmitCompleteOriginalIrpWorkItem ( + EncryptedIoQueue *queue, + EncryptedIoQueueItem *item, + PCOMPLETE_IRP_WORK_ITEM workItem) { - NTSTATUS status = KeWaitForSingleObject(&queue->WorkItemSemaphore, Executive, KernelMode, FALSE, NULL); + InterlockedIncrement(&queue->ActiveWorkItems); + KeResetEvent(&queue->NoActiveWorkItemsEvent); + + workItem->Irp = item->OriginalIrp; + workItem->Status = item->Status; + workItem->Information = NT_SUCCESS(item->Status) ? item->OriginalLength : 0; + workItem->Item = item; + + IoQueueWorkItem( + workItem->WorkItem, + CompleteIrpWorkItemRoutine, + DelayedWorkQueue, + workItem); +} + +#ifdef _M_ARM64 +static BOOL TryQueueCompleteOriginalIrp ( + EncryptedIoQueue *queue, + EncryptedIoQueueItem *item) +{ + PCOMPLETE_IRP_WORK_ITEM workItem; + LARGE_INTEGER noWait; + NTSTATUS status; + + noWait.QuadPart = 0; + status = KeWaitForSingleObject( + &queue->WorkItemSemaphore, + Executive, + KernelMode, + FALSE, + &noWait); + if (status == STATUS_SUCCESS) + { + KIRQL oldIrql; + PLIST_ENTRY freeEntry; + + KeAcquireSpinLock(&queue->WorkItemLock, &oldIrql); + freeEntry = RemoveHeadList(&queue->FreeWorkItemsList); + KeReleaseSpinLock(&queue->WorkItemLock, oldIrql); + + workItem = CONTAINING_RECORD( + freeEntry, + COMPLETE_IRP_WORK_ITEM, + ListEntry); + workItem->DynamicallyAllocated = FALSE; + } + else if (status == STATUS_TIMEOUT) + { + workItem = TCalloc(sizeof(COMPLETE_IRP_WORK_ITEM)); + if (!workItem) + return FALSE; + + workItem->WorkItem = IoAllocateWorkItem(queue->DeviceObject); + if (!workItem->WorkItem) + { + TCfree(workItem); + return FALSE; + } + workItem->DynamicallyAllocated = TRUE; + } + else + { + return FALSE; + } + + SubmitCompleteOriginalIrpWorkItem(queue, item, workItem); + return TRUE; +} +#endif + + +// Completes an original IRP on a fresh stack. +static VOID QueueCompleteOriginalIrp(EncryptedIoQueue* queue, EncryptedIoQueueItem* item) +{ + NTSTATUS status; + KIRQL oldIrql; + PLIST_ENTRY freeEntry; + PCOMPLETE_IRP_WORK_ITEM workItem; + +#ifdef _M_ARM64 + if (TryQueueCompleteOriginalIrp(queue, item)) + return; +#endif + + status = KeWaitForSingleObject(&queue->WorkItemSemaphore, Executive, KernelMode, FALSE, NULL); if (queue->ThreadExitRequested) return; @@ -459,30 +568,22 @@ static VOID HandleCompleteOriginalIrp(EncryptedIoQueue* queue, EncryptedIoReques { // Handle wait failure: we call the completion routine directly. // This is not ideal since it can cause deadlock that we are trying to fix but it is better than losing the IRP. - CompleteOriginalIrp(request->Item, STATUS_INSUFFICIENT_RESOURCES, 0); + CompleteOriginalIrp(item, STATUS_INSUFFICIENT_RESOURCES, 0); } else { - // Obtain a work item from the free list. - KIRQL oldIrql; KeAcquireSpinLock(&queue->WorkItemLock, &oldIrql); - PLIST_ENTRY freeEntry = RemoveHeadList(&queue->FreeWorkItemsList); + freeEntry = RemoveHeadList(&queue->FreeWorkItemsList); KeReleaseSpinLock(&queue->WorkItemLock, oldIrql); - PCOMPLETE_IRP_WORK_ITEM workItem = CONTAINING_RECORD(freeEntry, COMPLETE_IRP_WORK_ITEM, ListEntry); - - // Increment ActiveWorkItems. - InterlockedIncrement(&queue->ActiveWorkItems); - KeResetEvent(&queue->NoActiveWorkItemsEvent); - - // Prepare the work item. - workItem->Irp = request->Item->OriginalIrp; - workItem->Status = request->Item->Status; - workItem->Information = NT_SUCCESS(request->Item->Status) ? request->Item->OriginalLength : 0; - workItem->Item = request->Item; - - // Queue the work item. - IoQueueWorkItem(workItem->WorkItem, CompleteIrpWorkItemRoutine, DelayedWorkQueue, workItem); + workItem = CONTAINING_RECORD( + freeEntry, + COMPLETE_IRP_WORK_ITEM, + ListEntry); +#ifdef _M_ARM64 + workItem->DynamicallyAllocated = FALSE; +#endif + SubmitCompleteOriginalIrpWorkItem(queue, item, workItem); } } @@ -492,6 +593,10 @@ static VOID CompletionThreadProc(PVOID threadArg) PLIST_ENTRY listEntry; EncryptedIoRequest* request; UINT64_STRUCT dataUnit; +#ifdef _M_ARM64 + LIST_ENTRY deferredArm64BootWriteCompletions; + InitializeListHead(&deferredArm64BootWriteCompletions); +#endif if (IsEncryptionThreadPoolRunning()) KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); @@ -504,10 +609,64 @@ static VOID CompletionThreadProc(PVOID threadArg) if (queue->ThreadExitRequested) break; - while ((listEntry = ExInterlockedRemoveHeadList(&queue->CompletionThreadQueue, &queue->CompletionThreadQueueLock))) + while (TRUE) { +#ifdef _M_ARM64 + if (!IsListEmpty(&deferredArm64BootWriteCompletions)) + { + request = CONTAINING_RECORD( + deferredArm64BootWriteCompletions.Flink, + EncryptedIoRequest, + CompletionListEntry); + if (TryQueueCompleteOriginalIrp(queue, request->Item)) + { + RemoveHeadList(&deferredArm64BootWriteCompletions); + if (IsListEmpty(&deferredArm64BootWriteCompletions)) + { + InterlockedExchange( + &queue->Arm64BootWriteCompletionDeferred, + FALSE); + } + ReleasePoolBuffer(queue, request); + continue; + } + } +#endif + + listEntry = ExInterlockedRemoveHeadList( + &queue->CompletionThreadQueue, + &queue->CompletionThreadQueueLock); + if (!listEntry) + break; + request = CONTAINING_RECORD(listEntry, EncryptedIoRequest, CompletionListEntry); +#ifdef _M_ARM64 + if (request->Arm64BootWriteBarrier) + { + KeSetEvent (&request->Arm64BootWriteBarrierCompleted, IO_DISK_INCREMENT, FALSE); + continue; + } + + if (request->Arm64BootWriteCompletion) + { + if (TryQueueCompleteOriginalIrp(queue, request->Item)) + { + ReleasePoolBuffer(queue, request); + } + else + { + InsertTailList( + &deferredArm64BootWriteCompletions, + &request->CompletionListEntry); + InterlockedExchange( + &queue->Arm64BootWriteCompletionDeferred, + TRUE); + } + continue; + } +#endif + if (request->EncryptedLength > 0 && NT_SUCCESS(request->Item->Status)) { ASSERT(request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length); @@ -528,7 +687,7 @@ static VOID CompletionThreadProc(PVOID threadArg) if (request->CompleteOriginalIrp) { - HandleCompleteOriginalIrp(queue, request); + QueueCompleteOriginalIrp(queue, request->Item); } ReleasePoolBuffer(queue, request); @@ -594,6 +753,18 @@ static VOID IoThreadProc (PVOID threadArg) InterlockedDecrement (&queue->IoThreadPendingRequestCount); request = CONTAINING_RECORD (listEntry, EncryptedIoRequest, ListEntry); +#ifdef _M_ARM64 + if (request->Arm64BootWriteBarrier) + { + ExInterlockedInsertTailList ( + &queue->CompletionThreadQueue, + &request->CompletionListEntry, + &queue->CompletionThreadQueueLock); + KeSetEvent (&queue->CompletionThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE); + continue; + } +#endif + if (request->Item->Flush) { #ifdef TC_TRACE_IO_QUEUE @@ -612,7 +783,7 @@ static VOID IoThreadProc (PVOID threadArg) } } - HandleCompleteOriginalIrp (queue, request); + QueueCompleteOriginalIrp (queue, request->Item); ReleasePoolBuffer (queue, request); continue; } @@ -712,7 +883,7 @@ static VOID IoThreadProc (PVOID threadArg) if (request->CompleteOriginalIrp) { - HandleCompleteOriginalIrp(queue, request); + QueueCompleteOriginalIrp(queue, request->Item); } ReleasePoolBuffer (queue, request); @@ -772,6 +943,44 @@ static VOID IoThreadProc (PVOID threadArg) } +#ifdef _M_ARM64 +static NTSTATUS WaitForArm64BootWriteBarrier (EncryptedIoQueue *queue) +{ + EncryptedIoRequest *request; + NTSTATUS status; + + // Crossing both worker queues preserves FIFO order for the boot-write RMW. + request = GetPoolBuffer (queue, sizeof (EncryptedIoRequest)); + if (!request) + return STATUS_INSUFFICIENT_RESOURCES; + + request->Arm64BootWriteBarrier = TRUE; + request->Arm64BootWriteCompletion = FALSE; + KeInitializeEvent ( + &request->Arm64BootWriteBarrierCompleted, + SynchronizationEvent, + FALSE); + + InterlockedIncrement (&queue->IoThreadPendingRequestCount); + ExInterlockedInsertTailList ( + &queue->IoThreadQueue, + &request->ListEntry, + &queue->IoThreadQueueLock); + KeSetEvent (&queue->IoThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE); + + status = KeWaitForSingleObject ( + &request->Arm64BootWriteBarrierCompleted, + Executive, + KernelMode, + FALSE, + NULL); + ReleasePoolBuffer (queue, request); + + return status; +} +#endif + + static VOID MainThreadProc (PVOID threadArg) { EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg; @@ -877,12 +1086,52 @@ static VOID MainThreadProc (PVOID threadArg) request->Length = 0; request->EncryptedOffset = 0; request->EncryptedLength = 0; +#ifdef _M_ARM64 + request->Arm64BootWriteBarrier = FALSE; + request->Arm64BootWriteCompletion = FALSE; +#endif ExInterlockedInsertTailList (&queue->IoThreadQueue, &request->ListEntry, &queue->IoThreadQueueLock); KeSetEvent (&queue->IoThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE); continue; } +#ifdef _M_ARM64 + if (item->Write && queue->Arm64BootWrite) + { + item->Status = WaitForArm64BootWriteBarrier (queue); + if (NT_SUCCESS (item->Status)) + { + queue->ReadAheadBufferValid = FALSE; + item->Status = queue->Arm64BootWrite ( + queue->Arm64BootWriteContext, + irp, + irpSp); + queue->ReadAheadBufferValid = FALSE; + } + + request = GetPoolBuffer (queue, sizeof (EncryptedIoRequest)); + if (!request) + { + CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0); + continue; + } + + request->Item = item; + request->Arm64BootWriteBarrier = FALSE; + request->Arm64BootWriteCompletion = TRUE; + ExInterlockedInsertTailList ( + &queue->CompletionThreadQueue, + &request->CompletionListEntry, + &queue->CompletionThreadQueueLock); + KeSetEvent ( + &queue->CompletionThreadQueueNotEmptyEvent, + IO_DISK_INCREMENT, + FALSE); + continue; + } +#endif + // Handle misaligned read operations to work around a bug in Windows System Assessment Tool which does not follow FILE_FLAG_NO_BUFFERING requirements when benchmarking disk devices if (queue->IsFilterDevice && !item->Write @@ -1083,6 +1332,10 @@ static VOID MainThreadProc (PVOID threadArg) request->Data = activeFragmentBuffer; request->OrigDataBufferFragment = dataBuffer; request->Length = dataFragmentLength; +#ifdef _M_ARM64 + request->Arm64BootWriteBarrier = FALSE; + request->Arm64BootWriteCompletion = FALSE; +#endif if (queue->IsFilterDevice || queue->bSupportPartialEncryption) { @@ -1279,6 +1532,9 @@ NTSTATUS EncryptedIoQueueStart (EncryptedIoQueue *queue) queue->OutstandingIoCount = 0; queue->IoThreadPendingRequestCount = 0; +#ifdef _M_ARM64 + queue->Arm64BootWriteCompletionDeferred = FALSE; +#endif queue->FirstPoolBuffer = NULL; KeInitializeMutex (&queue->BufferPoolMutex, 0); diff --git a/src/Driver/EncryptedIoQueue.h b/src/Driver/EncryptedIoQueue.h index 93f946d491..bb05198a06 100644 --- a/src/Driver/EncryptedIoQueue.h +++ b/src/Driver/EncryptedIoQueue.h @@ -28,6 +28,13 @@ #define VC_MAX_WORK_ITEMS 1024 +#ifdef _M_ARM64 +typedef NTSTATUS (*Arm64BootWriteHandler) ( + PVOID context, + PIRP irp, + PIO_STACK_LOCATION irpSp); +#endif + typedef struct EncryptedIoQueueBufferStruct { struct EncryptedIoQueueBufferStruct *NextBuffer; @@ -45,6 +52,9 @@ typedef struct _COMPLETE_IRP_WORK_ITEM NTSTATUS Status; ULONG_PTR Information; void* Item; +#ifdef _M_ARM64 + BOOL DynamicallyAllocated; +#endif LIST_ENTRY ListEntry; // For managing free work items } COMPLETE_IRP_WORK_ITEM, * PCOMPLETE_IRP_WORK_ITEM; @@ -66,6 +76,11 @@ typedef struct // Filter device BOOL IsFilterDevice; PDEVICE_OBJECT LowerDeviceObject; +#ifdef _M_ARM64 + Arm64BootWriteHandler Arm64BootWrite; + PVOID Arm64BootWriteContext; + volatile LONG Arm64BootWriteCompletionDeferred; +#endif int64 EncryptedAreaStart; volatile int64 EncryptedAreaEnd; volatile BOOL EncryptedAreaEndUpdatePending; @@ -178,12 +193,21 @@ typedef struct uint8 *Data; uint8 *OrigDataBufferFragment; +#ifdef _M_ARM64 + BOOL Arm64BootWriteBarrier; + BOOL Arm64BootWriteCompletion; + KEVENT Arm64BootWriteBarrierCompleted; +#endif + LIST_ENTRY ListEntry; LIST_ENTRY CompletionListEntry; } EncryptedIoRequest; NTSTATUS EncryptedIoQueueAddIrp (EncryptedIoQueue *queue, PIRP irp); +#ifdef _M_ARM64 +BOOL UpdateBuffer (uint8 *buffer, uint8 *secRegion, SIZE_T secRegionSize, uint64 bufferDiskOffset, uint32 bufferLength, BOOL doUpdate); +#endif BOOL EncryptedIoQueueIsRunning (EncryptedIoQueue *queue); BOOL EncryptedIoQueueIsSuspended (EncryptedIoQueue *queue); NTSTATUS EncryptedIoQueueResumeFromHold (EncryptedIoQueue *queue); diff --git a/src/Driver/Ntdriver.c b/src/Driver/Ntdriver.c index 5b32992ec1..1a601362fc 100644 --- a/src/Driver/Ntdriver.c +++ b/src/Driver/Ntdriver.c @@ -204,6 +204,81 @@ BOOL IsUefiBoot () return bStatus; } +#ifdef _M_ARM64 +static NTSTATUS ReadArm64BootArgsHandoffRequired (BOOL *required) +{ + PKEY_VALUE_PARTIAL_INFORMATION data = NULL; + UNICODE_STRING serviceKey; + NTSTATUS status; + + if (!required) + return STATUS_INVALID_PARAMETER; + + *required = FALSE; + RtlInitUnicodeString ( + &serviceKey, + L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\veracrypt"); + status = TCReadRegistryKey ( + &serviceKey, + VC_ARM64_BOOT_ARGS_HANDOFF_REQUIRED_REG_VALUE_NAME, + &data); + if (status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NO_DATA_DETECTED) + return STATUS_SUCCESS; + if (!NT_SUCCESS (status)) + return status; + + if (data->Type != REG_DWORD || data->DataLength != sizeof (uint32)) + { + TCfree (data); + return STATUS_INVALID_PARAMETER; + } + + *required = (*(uint32 *) data->Data != 0); + TCfree (data); + return STATUS_SUCCESS; +} + + +NTSTATUS SetArm64BootArgsHandoffRequired (BOOL required) +{ + OBJECT_ATTRIBUTES regObjAttribs; + HANDLE regKeyHandle; + UNICODE_STRING serviceKey; + UNICODE_STRING valueName; + NTSTATUS status; + uint32 value = required ? 1 : 0; + + RtlInitUnicodeString ( + &serviceKey, + L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\veracrypt"); + RtlInitUnicodeString (&valueName, VC_ARM64_BOOT_ARGS_HANDOFF_REQUIRED_REG_VALUE_NAME); + InitializeObjectAttributes ( + ®ObjAttribs, + &serviceKey, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + status = ZwOpenKey (®KeyHandle, KEY_SET_VALUE, ®ObjAttribs); + if (!NT_SUCCESS (status)) + return status; + + status = ZwSetValueKey ( + regKeyHandle, + &valueName, + 0, + REG_DWORD, + &value, + sizeof (value)); + if (NT_SUCCESS (status)) + status = ZwFlushKey (regKeyHandle); + + ZwClose (regKeyHandle); + return status; +} +#endif + + void GetDriverRandomSeed (unsigned char* pbRandSeed, size_t cbRandSeed) { LARGE_INTEGER iSeed, iSeed2; @@ -272,6 +347,10 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) PKEY_VALUE_PARTIAL_INFORMATION startKeyValue; LONG version; int i; +#ifdef _M_ARM64 + NTSTATUS bootArgumentsStatus; + BOOL bootArgumentsRequired; +#endif Dump("DriverEntry " TC_APP_NAME " " VERSION_STRING VERSION_STRING_SUFFIX "\n"); @@ -293,7 +372,11 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) memset(VirtualVolumeDeviceObjects, 0, sizeof(VirtualVolumeDeviceObjects)); ReadRegistryConfigFlags(TRUE); - EncryptionThreadPoolStart(EncryptionThreadPoolFreeCpuCountLimit); + if (!EncryptionThreadPoolStart (EncryptionThreadPoolFreeCpuCountLimit, RamEncryptionActivated) + && RamEncryptionActivated) + { + TC_BUG_CHECK (STATUS_INSUFFICIENT_RESOURCES); + } SelfTestsPassed = AutoTestAlgorithms(); // Enable device class filters and load boot arguments if the driver is set to start at system boot @@ -318,7 +401,25 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) TC_BUG_CHECK(STATUS_INVALID_PARAMETER); } +#ifdef _M_ARM64 + bootArgumentsStatus = ReadArm64BootArgsHandoffRequired (&bootArgumentsRequired); + if (!NT_SUCCESS (bootArgumentsStatus)) + TC_BUG_CHECK (bootArgumentsStatus); + + bootArgumentsStatus = LoadBootArguments(IsUefiBoot()); + /* + * A missing handoff is allowed only before system encryption writes + * its first block. Corrupt handoff data is never accepted. + */ + if (!NT_SUCCESS (bootArgumentsStatus) + && (bootArgumentsRequired + || bootArgumentsStatus != STATUS_VARIABLE_NOT_FOUND)) + { + TC_BUG_CHECK (bootArgumentsStatus); + } +#else LoadBootArguments(IsUefiBoot()); +#endif VolumeClassFilterRegistered = IsVolumeClassFilterRegistered(); DriverObject->DriverExtension->AddDevice = DriverAddDevice; @@ -4033,6 +4134,42 @@ NTSTATUS TCWriteDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER } +NTSTATUS TCFlushDevice (PDEVICE_OBJECT deviceObject) +{ + NTSTATUS status; + IO_STATUS_BLOCK ioStatusBlock; + PIRP irp; + KEVENT completionEvent; + + ASSERT (KeGetCurrentIrql() <= APC_LEVEL); + + KeInitializeEvent (&completionEvent, NotificationEvent, FALSE); + irp = IoBuildSynchronousFsdRequest ( + IRP_MJ_FLUSH_BUFFERS, + deviceObject, + NULL, + 0, + NULL, + &completionEvent, + &ioStatusBlock); + if (!irp) + return STATUS_INSUFFICIENT_RESOURCES; + + ObReferenceObject (deviceObject); + status = IoCallDriver (deviceObject, irp); + + if (status == STATUS_PENDING) + { + status = KeWaitForSingleObject (&completionEvent, Executive, KernelMode, FALSE, NULL); + if (NT_SUCCESS (status)) + status = ioStatusBlock.Status; + } + + ObDereferenceObject (deviceObject); + return status; +} + + NTSTATUS TCFsctlCall (PFILE_OBJECT fileObject, LONG IoControlCode, void *InputBuffer, int InputBufferSize, void *OutputBuffer, int OutputBufferSize) { diff --git a/src/Driver/Ntdriver.h b/src/Driver/Ntdriver.h index b367c87ae9..48608d344f 100644 --- a/src/Driver/Ntdriver.h +++ b/src/Driver/Ntdriver.h @@ -162,6 +162,7 @@ NTSTATUS TCCreateRootDeviceObject (PDRIVER_OBJECT DriverObject); NTSTATUS TCCreateDeviceObject (PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT * ppDeviceObject, MOUNT_STRUCT * mount); NTSTATUS TCReadDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length); NTSTATUS TCWriteDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length); +NTSTATUS TCFlushDevice (PDEVICE_OBJECT deviceObject); NTSTATUS TCStartThread (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread); NTSTATUS TCStartThreadInProcess (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread, PEPROCESS process); NTSTATUS TCStartVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, MOUNT_STRUCT * mount); @@ -204,6 +205,9 @@ void *AllocateMemoryWithTimeout (size_t size, int retryDelay, int timeout); BOOL IsDriveLetterAvailable (int nDosDriveNo, DeviceNamespaceType namespaceType); NTSTATUS TCReadRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, PKEY_VALUE_PARTIAL_INFORMATION *keyData); NTSTATUS TCWriteRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, ULONG keyValueType, void *valueData, ULONG valueSize); +#ifdef _M_ARM64 +NTSTATUS SetArm64BootArgsHandoffRequired (BOOL required); +#endif BOOL IsVolumeClassFilterRegistered (); NTSTATUS ReadRegistryConfigFlags (BOOL driverEntry); NTSTATUS WriteRegistryConfigFlags (uint32 flags); diff --git a/src/Format/Format.vcxproj b/src/Format/Format.vcxproj index 1562b5db0f..87277e15c2 100644 --- a/src/Format/Format.vcxproj +++ b/src/Format/Format.vcxproj @@ -364,7 +364,7 @@ copy $(TargetPath) "..\Debug\Setup Files\VeraCrypt Format-arm64.exe" >NUL: 4057;4100;4127;4201;4204;4701;4706;4131;%(DisableSpecificWarnings) - ..\Crypto\x64\Release\crypto.lib;..\Common\x64\Release\Zip.lib;mpr.lib;%(AdditionalDependencies) + ..\Crypto\ARM64\Release\crypto.lib;..\Common\ARM64\Release\Zip.lib;mpr.lib;%(AdditionalDependencies) $(OutDir)VeraCryptFormat.exe false mpr.dll;bcrypt.dll;user32.dll;gdi32.dll;advapi32.dll;shell32.dll;ole32.dll;oleaut32.dll;shlwapi.dll;setupapi.dll;wintrust.dll;comctl32.dll;%(DelayLoadDLLs) diff --git a/src/Mount/Mount.vcxproj b/src/Mount/Mount.vcxproj index 47efaf314b..9eb2d173bd 100644 --- a/src/Mount/Mount.vcxproj +++ b/src/Mount/Mount.vcxproj @@ -396,7 +396,7 @@ copy $(TargetPath) "..\Debug\Setup Files\VeraCrypt-arm64.exe" >NUL: 4057;4100;4127;4201;4701;4706;4131;%(DisableSpecificWarnings) - ..\Crypto\x64\Release\crypto.lib;..\Common\x64\Release\Zip.lib;mpr.lib;%(AdditionalDependencies) + ..\Crypto\ARM64\Release\crypto.lib;..\Common\ARM64\Release\Zip.lib;mpr.lib;%(AdditionalDependencies) $(OutDir)VeraCrypt.exe false mpr.dll;bcrypt.dll;user32.dll;gdi32.dll;advapi32.dll;shell32.dll;ole32.dll;oleaut32.dll;shlwapi.dll;setupapi.dll;wintrust.dll;comctl32.dll;%(DelayLoadDLLs) @@ -612,4 +612,4 @@ copy $(TargetPath) "..\Debug\Setup Files\VeraCrypt-arm64.exe" >NUL: - \ No newline at end of file + diff --git a/src/Setup/Setup.rc b/src/Setup/Setup.rc index c4c730ca9c..291c28b813 100644 --- a/src/Setup/Setup.rc +++ b/src/Setup/Setup.rc @@ -392,6 +392,7 @@ IDB_SETUP_WIZARD_BKG BITMAP "VeraCrypt_setup_background.bmp" // // Generated from the TEXTINCLUDE 3 resource. // +#define VC_SETUP_RESOURCE #include "..\\common\\common.rc" ///////////////////////////////////////////////////////////////////////////// diff --git a/src/SetupDLL/Setup.rc b/src/SetupDLL/Setup.rc index adee936619..34e1a7f8a7 100644 --- a/src/SetupDLL/Setup.rc +++ b/src/SetupDLL/Setup.rc @@ -387,6 +387,7 @@ IDB_SETUP_WIZARD_BKG BITMAP "VeraCrypt_setup_background.bmp" // // Generated from the TEXTINCLUDE 3 resource. // +#define VC_SETUP_RESOURCE #include "..\\common\\common.rc" /////////////////////////////////////////////////////////////////////////////