VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Driver/DriveFilter.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Driver/DriveFilter.c')
-rw-r--r--src/Driver/DriveFilter.c4306
1 files changed, 2153 insertions, 2153 deletions
diff --git a/src/Driver/DriveFilter.c b/src/Driver/DriveFilter.c
index a8752a5f..c090ee8c 100644
--- a/src/Driver/DriveFilter.c
+++ b/src/Driver/DriveFilter.c
@@ -1,2153 +1,2153 @@
-/*
- Derived from source code of TrueCrypt 7.1a, which is
- Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
- by the TrueCrypt License 3.0.
-
- Modifications and additions to the original source code (contained in this file)
- and all other portions of this file are Copyright (c) 2013-2016 IDRIX
- and are governed by the Apache License 2.0 the full text of which is
- contained in the file License.txt included in VeraCrypt binary and source
- code distribution packages.
-*/
-
-#include "TCdefs.h"
-#include <ntddk.h>
-#include <ntddvol.h>
-#include <Ntstrsafe.h>
-#include "Cache.h"
-#include "Crc.h"
-#include "Crypto.h"
-#include "Apidrvr.h"
-#include "EncryptedIoQueue.h"
-#include "Common/Endian.h"
-#include "Ntdriver.h"
-#include "Ntvol.h"
-#include "Volumes.h"
-#include "VolumeFilter.h"
-#include "Wipe.h"
-#include "DriveFilter.h"
-#include "Boot/Windows/BootCommon.h"
-
-static BOOL DeviceFilterActive = FALSE;
-
-BOOL BootArgsValid = FALSE;
-BootArguments BootArgs;
-static uint16 BootLoaderSegment;
-static BOOL BootDriveSignatureValid = FALSE;
-
-static KMUTEX MountMutex;
-
-static volatile BOOL BootDriveFound = FALSE;
-static DriveFilterExtension *BootDriveFilterExtension = NULL;
-static LARGE_INTEGER BootDriveLength;
-static byte BootLoaderFingerprint[WHIRLPOOL_DIGESTSIZE + SHA512_DIGESTSIZE];
-
-static BOOL CrashDumpEnabled = FALSE;
-static BOOL HibernationEnabled = FALSE;
-
-static BOOL LegacyHibernationDriverFilterActive = FALSE;
-static byte *HibernationWriteBuffer = NULL;
-static MDL *HibernationWriteBufferMdl = NULL;
-
-static uint32 HibernationPreventionCount = 0;
-
-static BootEncryptionSetupRequest SetupRequest;
-static volatile BOOL SetupInProgress = FALSE;
-PKTHREAD EncryptionSetupThread = NULL;
-static volatile BOOL EncryptionSetupThreadAbortRequested;
-static KSPIN_LOCK SetupStatusSpinLock;
-static int64 SetupStatusEncryptedAreaEnd;
-static BOOL TransformWaitingForIdle;
-static NTSTATUS SetupResult;
-
-static WipeDecoySystemRequest WipeDecoyRequest;
-static volatile BOOL DecoySystemWipeInProgress = FALSE;
-static volatile BOOL DecoySystemWipeThreadAbortRequested;
-static KSPIN_LOCK DecoySystemWipeStatusSpinLock;
-static int64 DecoySystemWipedAreaEnd;
-PKTHREAD DecoySystemWipeThread = NULL;
-static NTSTATUS DecoySystemWipeResult;
-
-
-NTSTATUS LoadBootArguments ()
-{
- NTSTATUS status = STATUS_UNSUCCESSFUL;
- PHYSICAL_ADDRESS bootArgsAddr;
- byte *mappedBootArgs;
- uint16 bootLoaderSegment;
-
- KeInitializeMutex (&MountMutex, 0);
-
- for (bootLoaderSegment = TC_BOOT_LOADER_SEGMENT;
- bootLoaderSegment >= TC_BOOT_LOADER_SEGMENT - 64 * 1024 / 16 && status != STATUS_SUCCESS;
- bootLoaderSegment -= 32 * 1024 / 16)
- {
- bootArgsAddr.QuadPart = (bootLoaderSegment << 4) + TC_BOOT_LOADER_ARGS_OFFSET;
- Dump ("Checking BootArguments at 0x%x\n", bootArgsAddr.LowPart);
-
- mappedBootArgs = MmMapIoSpace (bootArgsAddr, sizeof (BootArguments), MmCached);
- if (!mappedBootArgs)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- if (TC_IS_BOOT_ARGUMENTS_SIGNATURE (mappedBootArgs))
- {
- BootArguments *bootArguments = (BootArguments *) mappedBootArgs;
- Dump ("BootArguments found at 0x%x\n", bootArgsAddr.LowPart);
-
- DumpMem (mappedBootArgs, sizeof (BootArguments));
-
- if (bootArguments->BootLoaderVersion == VERSION_NUM
- && bootArguments->BootArgumentsCrc32 != GetCrc32 ((byte *) bootArguments, (int) ((byte *) &bootArguments->BootArgumentsCrc32 - (byte *) bootArguments)))
- {
- Dump ("BootArguments CRC incorrect\n");
- TC_BUG_CHECK (STATUS_CRC_ERROR);
- }
-
- // Sanity check: for valid boot argument, the password is less than 64 bytes long
- if (bootArguments->BootPassword.Length <= MAX_PASSWORD)
- {
- BootLoaderSegment = bootLoaderSegment;
-
- BootArgs = *bootArguments;
- BootArgsValid = TRUE;
- burn (bootArguments, sizeof (*bootArguments));
-
- BootDriveSignatureValid = TRUE;
-
- Dump ("BootLoaderVersion = %x\n", (int) BootArgs.BootLoaderVersion);
- Dump ("HeaderSaltCrc32 = %x\n", (int) BootArgs.HeaderSaltCrc32);
- Dump ("CryptoInfoOffset = %x\n", (int) BootArgs.CryptoInfoOffset);
- Dump ("CryptoInfoLength = %d\n", (int) BootArgs.CryptoInfoLength);
- Dump ("HiddenSystemPartitionStart = %I64u\n", BootArgs.HiddenSystemPartitionStart);
- Dump ("DecoySystemPartitionStart = %I64u\n", BootArgs.DecoySystemPartitionStart);
- Dump ("Flags = %x\n", BootArgs.Flags);
- Dump ("BootDriveSignature = %x\n", BootArgs.BootDriveSignature);
- Dump ("BootArgumentsCrc32 = %x\n", BootArgs.BootArgumentsCrc32);
-
- if (CacheBootPassword && BootArgs.BootPassword.Length > 0)
- {
- int pim = CacheBootPim? (int) (BootArgs.Flags >> 16) : 0;
- AddPasswordToCache (&BootArgs.BootPassword, pim);
- }
-
- // clear fingerprint
- burn (BootLoaderFingerprint, sizeof (BootLoaderFingerprint));
-
- status = STATUS_SUCCESS;
- }
- }
-
- MmUnmapIoSpace (mappedBootArgs, sizeof (BootArguments));
- }
-
- return status;
-}
-
-
-NTSTATUS DriveFilterAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo)
-{
- DriveFilterExtension *Extension;
- NTSTATUS status;
- PDEVICE_OBJECT filterDeviceObject = NULL;
- PDEVICE_OBJECT attachedDeviceObject;
-
- Dump ("DriveFilterAddDevice pdo=%p\n", pdo);
-
- attachedDeviceObject = IoGetAttachedDeviceReference (pdo);
- status = IoCreateDevice (driverObject, sizeof (DriveFilterExtension), NULL, attachedDeviceObject->DeviceType, 0, FALSE, &filterDeviceObject);
-
- ObDereferenceObject (attachedDeviceObject);
-
- if (!NT_SUCCESS (status))
- {
- filterDeviceObject = NULL;
- goto err;
- }
-
- Extension = (DriveFilterExtension *) filterDeviceObject->DeviceExtension;
- memset (Extension, 0, sizeof (DriveFilterExtension));
-
- status = IoAttachDeviceToDeviceStackSafe (filterDeviceObject, pdo, &(Extension->LowerDeviceObject));
- if (!NT_SUCCESS (status))
- {
- goto err;
- }
-
- if (!Extension->LowerDeviceObject)
- {
- status = STATUS_DEVICE_REMOVED;
- goto err;
- }
-
- Extension->IsDriveFilterDevice = Extension->Queue.IsFilterDevice = TRUE;
- Extension->DeviceObject = Extension->Queue.DeviceObject = filterDeviceObject;
- Extension->Pdo = pdo;
-
- Extension->Queue.LowerDeviceObject = Extension->LowerDeviceObject;
- IoInitializeRemoveLock (&Extension->Queue.RemoveLock, 'LRCV', 0, 0);
-
- Extension->ConfiguredEncryptedAreaStart = -1;
- Extension->ConfiguredEncryptedAreaEnd = -1;
- Extension->Queue.EncryptedAreaStart = -1;
- Extension->Queue.EncryptedAreaEnd = -1;
- Extension->Queue.EncryptedAreaEndUpdatePending = FALSE;
-
- filterDeviceObject->Flags |= Extension->LowerDeviceObject->Flags & (DO_DIRECT_IO | DO_BUFFERED_IO | DO_POWER_PAGABLE);
- filterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
-
- DeviceFilterActive = TRUE;
- return status;
-
-err:
- if (filterDeviceObject)
- {
- if (Extension->LowerDeviceObject)
- IoDetachDevice (Extension->LowerDeviceObject);
-
- IoDeleteDevice (filterDeviceObject);
- }
-
- return status;
-}
-
-
-static void DismountDrive (DriveFilterExtension *Extension, BOOL stopIoQueue)
-{
- Dump ("Dismounting drive\n");
- ASSERT (Extension->DriveMounted);
-
- if (stopIoQueue && EncryptedIoQueueIsRunning (&Extension->Queue))
- EncryptedIoQueueStop (&Extension->Queue);
-
- crypto_close (Extension->Queue.CryptoInfo);
- Extension->Queue.CryptoInfo = NULL;
-
- crypto_close (Extension->HeaderCryptoInfo);
- Extension->HeaderCryptoInfo = NULL;
-
- Extension->DriveMounted = FALSE;
-}
-
-static void ComputeBootLoaderFingerprint(PDEVICE_OBJECT LowerDeviceObject, byte* ioBuffer /* ioBuffer must be at least 512 bytes long */)
-{
- NTSTATUS status;
- LARGE_INTEGER offset;
- WHIRLPOOL_CTX whirlpool;
- sha512_ctx sha2;
- ULONG bytesToRead, remainingBytes, bootloaderTotalSize = TC_BOOT_LOADER_AREA_SIZE - TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE;
-
- // clear fingerprint
- burn (BootLoaderFingerprint, sizeof (BootLoaderFingerprint));
-
- // compute Whirlpool+SHA512 fingerprint of bootloader including MBR
- // we skip user configuration fields:
- // TC_BOOT_SECTOR_PIM_VALUE_OFFSET = 400
- // TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET = 402
- // => TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE = 4
- // TC_BOOT_SECTOR_USER_MESSAGE_OFFSET = 406
- // => TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH = 24
- // TC_BOOT_SECTOR_USER_CONFIG_OFFSET = 438
- //
- // we have: TC_BOOT_SECTOR_USER_MESSAGE_OFFSET = TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE
-
- WHIRLPOOL_init (&whirlpool);
- sha512_begin (&sha2);
- // read the first 512 bytes
- offset.QuadPart = 0;
-
- status = TCReadDevice (LowerDeviceObject, ioBuffer, offset, TC_SECTOR_SIZE_BIOS);
- if (NT_SUCCESS (status))
- {
- WHIRLPOOL_add (ioBuffer, TC_BOOT_SECTOR_PIM_VALUE_OFFSET * 8, &whirlpool);
- WHIRLPOOL_add (ioBuffer + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH, (TC_BOOT_SECTOR_USER_CONFIG_OFFSET - (TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)) * 8, &whirlpool);
- WHIRLPOOL_add (ioBuffer + TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1, (TC_MAX_MBR_BOOT_CODE_SIZE - (TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1)) * 8, &whirlpool);
-
- sha512_hash (ioBuffer, TC_BOOT_SECTOR_PIM_VALUE_OFFSET, &sha2);
- sha512_hash (ioBuffer + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH, (TC_BOOT_SECTOR_USER_CONFIG_OFFSET - (TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)), &sha2);
- sha512_hash (ioBuffer + TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1, (TC_MAX_MBR_BOOT_CODE_SIZE - (TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1)), &sha2);
-
- // we has the reste of the bootloader, 512 bytes at a time
- offset.QuadPart = TC_SECTOR_SIZE_BIOS;
- remainingBytes = bootloaderTotalSize - TC_SECTOR_SIZE_BIOS;
-
- while (NT_SUCCESS (status) && (remainingBytes > 0))
- {
- bytesToRead = (remainingBytes >= TC_SECTOR_SIZE_BIOS)? TC_SECTOR_SIZE_BIOS : remainingBytes;
- status = TCReadDevice (LowerDeviceObject, ioBuffer, offset, bytesToRead);
- if (NT_SUCCESS (status))
- {
- remainingBytes -= bytesToRead;
- offset.QuadPart += bytesToRead;
- WHIRLPOOL_add (ioBuffer, bytesToRead * 8, &whirlpool);
- sha512_hash (ioBuffer, bytesToRead, &sha2);
- }
- else
- {
- Dump ("TCReadDevice error %x during ComputeBootLoaderFingerprint call\n", status);
- break;
- }
- }
-
- if (NT_SUCCESS (status))
- {
- WHIRLPOOL_finalize (&whirlpool, BootLoaderFingerprint);
- sha512_end (&BootLoaderFingerprint [WHIRLPOOL_DIGESTSIZE], &sha2);
- }
- }
- else
- {
- Dump ("TCReadDevice error %x during ComputeBootLoaderFingerprint call\n", status);
- }
-}
-
-
-static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password, uint32 *headerSaltCrc32)
-{
- BOOL hiddenVolume = (BootArgs.HiddenSystemPartitionStart != 0);
- int64 hiddenHeaderOffset = BootArgs.HiddenSystemPartitionStart + TC_HIDDEN_VOLUME_HEADER_OFFSET;
- NTSTATUS status;
- LARGE_INTEGER offset;
- char *header;
- int pkcs5_prf = 0, pim = 0;
- byte *mappedCryptoInfo = NULL;
-
- Dump ("MountDrive pdo=%p\n", Extension->Pdo);
- ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
-
- // Check boot drive signature first (header CRC search could fail if a user restored the header to a non-boot drive)
- if (BootDriveSignatureValid)
- {
- byte mbr[TC_SECTOR_SIZE_BIOS];
-
- offset.QuadPart = 0;
- status = TCReadDevice (Extension->LowerDeviceObject, mbr, offset, TC_SECTOR_SIZE_BIOS);
-
- if (NT_SUCCESS (status) && BootArgs.BootDriveSignature != *(uint32 *) (mbr + 0x1b8))
- return STATUS_UNSUCCESSFUL;
- }
-
- header = TCalloc (TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
- if (!header)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- offset.QuadPart = hiddenVolume ? hiddenHeaderOffset : TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
- Dump ("Reading volume header at %I64u\n", offset.QuadPart);
-
- status = TCReadDevice (Extension->LowerDeviceObject, header, offset, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
- if (!NT_SUCCESS (status))
- {
- Dump ("TCReadDevice error %x\n", status);
- goto ret;
- }
-
- if (headerSaltCrc32)
- {
- uint32 saltCrc = GetCrc32 (header, PKCS5_SALT_SIZE);
-
- if (saltCrc != *headerSaltCrc32)
- {
- status = STATUS_UNSUCCESSFUL;
- goto ret;
- }
-
- Extension->VolumeHeaderSaltCrc32 = saltCrc;
- }
-
- Extension->HeaderCryptoInfo = crypto_open();
- if (!Extension->HeaderCryptoInfo)
- {
- status = STATUS_INSUFFICIENT_RESOURCES;
- goto ret;
- }
-
- if (BootArgs.CryptoInfoLength > 0)
- {
- PHYSICAL_ADDRESS cryptoInfoAddress;
-
- cryptoInfoAddress.QuadPart = (BootLoaderSegment << 4) + BootArgs.CryptoInfoOffset;
-#ifdef DEBUG
- Dump ("Wiping memory %x %d\n", cryptoInfoAddress.LowPart, BootArgs.CryptoInfoLength);
-#endif
- mappedCryptoInfo = MmMapIoSpace (cryptoInfoAddress, BootArgs.CryptoInfoLength, MmCached);
- if (mappedCryptoInfo)
- {
- /* Get the parameters used for booting to speed up driver startup and avoid testing irrelevant PRFs */
- BOOT_CRYPTO_HEADER* pBootCryptoInfo = (BOOT_CRYPTO_HEADER*) mappedCryptoInfo;
- Hash* pHash = HashGet(pBootCryptoInfo->pkcs5);
- if (pHash && pHash->SystemEncryption)
- pkcs5_prf = pBootCryptoInfo->pkcs5;
- }
- }
-
- pim = (int) (BootArgs.Flags >> 16);
-
- if (ReadVolumeHeader (!hiddenVolume, header, password, pkcs5_prf, pim, FALSE, &Extension->Queue.CryptoInfo, Extension->HeaderCryptoInfo) == 0)
- {
- // Header decrypted
- status = STATUS_SUCCESS;
- Dump ("Header decrypted\n");
-
- // calculate Fingerprint
- ComputeBootLoaderFingerprint (Extension->LowerDeviceObject, header);
-
- if (Extension->Queue.CryptoInfo->hiddenVolume)
- {
- int64 hiddenPartitionOffset = BootArgs.HiddenSystemPartitionStart;
- Dump ("Hidden volume start offset = %I64d\n", Extension->Queue.CryptoInfo->EncryptedAreaStart.Value + hiddenPartitionOffset);
-
- Extension->HiddenSystem = TRUE;
-
- Extension->Queue.RemapEncryptedArea = TRUE;
- Extension->Queue.RemappedAreaOffset = hiddenPartitionOffset + Extension->Queue.CryptoInfo->EncryptedAreaStart.Value - BootArgs.DecoySystemPartitionStart;
- Extension->Queue.RemappedAreaDataUnitOffset = Extension->Queue.CryptoInfo->EncryptedAreaStart.Value / ENCRYPTION_DATA_UNIT_SIZE - BootArgs.DecoySystemPartitionStart / ENCRYPTION_DATA_UNIT_SIZE;
-
- Extension->Queue.CryptoInfo->EncryptedAreaStart.Value = BootArgs.DecoySystemPartitionStart;
-
- if (Extension->Queue.CryptoInfo->VolumeSize.Value > hiddenPartitionOffset - BootArgs.DecoySystemPartitionStart)
- TC_THROW_FATAL_EXCEPTION;
-
- Dump ("RemappedAreaOffset = %I64d\n", Extension->Queue.RemappedAreaOffset);
- Dump ("RemappedAreaDataUnitOffset = %I64d\n", Extension->Queue.RemappedAreaDataUnitOffset);
- }
- else
- {
- Extension->HiddenSystem = FALSE;
- Extension->Queue.RemapEncryptedArea = FALSE;
- }
-
- Extension->ConfiguredEncryptedAreaStart = Extension->Queue.CryptoInfo->EncryptedAreaStart.Value;
- Extension->ConfiguredEncryptedAreaEnd = Extension->Queue.CryptoInfo->EncryptedAreaStart.Value + Extension->Queue.CryptoInfo->VolumeSize.Value - 1;
-
- Extension->Queue.EncryptedAreaStart = Extension->Queue.CryptoInfo->EncryptedAreaStart.Value;
- Extension->Queue.EncryptedAreaEnd = Extension->Queue.CryptoInfo->EncryptedAreaStart.Value + Extension->Queue.CryptoInfo->EncryptedAreaLength.Value - 1;
-
- if (Extension->Queue.CryptoInfo->EncryptedAreaLength.Value == 0)
- {
- Extension->Queue.EncryptedAreaStart = -1;
- Extension->Queue.EncryptedAreaEnd = -1;
- }
-
- Dump ("Loaded: ConfiguredEncryptedAreaStart=%I64d (%I64d) ConfiguredEncryptedAreaEnd=%I64d (%I64d)\n", Extension->ConfiguredEncryptedAreaStart / 1024 / 1024, Extension->ConfiguredEncryptedAreaStart, Extension->ConfiguredEncryptedAreaEnd / 1024 / 1024, Extension->ConfiguredEncryptedAreaEnd);
- Dump ("Loaded: EncryptedAreaStart=%I64d (%I64d) EncryptedAreaEnd=%I64d (%I64d)\n", Extension->Queue.EncryptedAreaStart / 1024 / 1024, Extension->Queue.EncryptedAreaStart, Extension->Queue.EncryptedAreaEnd / 1024 / 1024, Extension->Queue.EncryptedAreaEnd);
-
- // Erase boot loader scheduled keys
- if (mappedCryptoInfo)
- {
- burn (mappedCryptoInfo, BootArgs.CryptoInfoLength);
- MmUnmapIoSpace (mappedCryptoInfo, BootArgs.CryptoInfoLength);
- BootArgs.CryptoInfoLength = 0;
- }
-
- BootDriveFilterExtension = Extension;
- BootDriveFound = Extension->BootDrive = Extension->DriveMounted = Extension->VolumeHeaderPresent = TRUE;
- BootDriveFilterExtension->MagicNumber = TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER;
-
- burn (&BootArgs.BootPassword, sizeof (BootArgs.BootPassword));
-
- {
- STORAGE_DEVICE_NUMBER storageDeviceNumber;
- status = SendDeviceIoControlRequest (Extension->LowerDeviceObject, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &storageDeviceNumber, sizeof (storageDeviceNumber));
-
- if (!NT_SUCCESS (status))
- {
- Dump ("Failed to get drive number - error %x\n", status);
- Extension->SystemStorageDeviceNumberValid = FALSE;
- }
- else
- {
- Extension->SystemStorageDeviceNumber = storageDeviceNumber.DeviceNumber;
- Extension->SystemStorageDeviceNumberValid = TRUE;
- }
- }
-
- status = SendDeviceIoControlRequest (Extension->LowerDeviceObject, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &BootDriveLength, sizeof (BootDriveLength));
-
- if (!NT_SUCCESS (status))
- {
- Dump ("Failed to get drive length - error %x\n", status);
- BootDriveLength.QuadPart = 0;
- Extension->Queue.MaxReadAheadOffset.QuadPart = 0;
- }
- else
- Extension->Queue.MaxReadAheadOffset = BootDriveLength;
-
- status = EncryptedIoQueueStart (&Extension->Queue);
- if (!NT_SUCCESS (status))
- TC_BUG_CHECK (status);
-
- if (IsOSAtLeast (WIN_VISTA))
- {
- CrashDumpEnabled = TRUE;
- HibernationEnabled = TRUE;
- }
- else if (!LegacyHibernationDriverFilterActive)
- StartLegacyHibernationDriverFilter();
-
- // 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))
- {
- CrashDumpEnabled = FALSE;
- HibernationEnabled = FALSE;
- }
- }
- else
- {
- Dump ("Header not decrypted\n");
- crypto_close (Extension->HeaderCryptoInfo);
- Extension->HeaderCryptoInfo = NULL;
-
- status = STATUS_UNSUCCESSFUL;
- }
-
-ret:
- TCfree (header);
- return status;
-}
-
-
-static NTSTATUS SaveDriveVolumeHeader (DriveFilterExtension *Extension)
-{
- NTSTATUS status = STATUS_SUCCESS;
- LARGE_INTEGER offset;
- byte *header;
-
- 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))
- {
- Dump ("TCReadDevice error %x", status);
- goto ret;
- }
-
- Dump ("Saving: ConfiguredEncryptedAreaStart=%I64d (%I64d) ConfiguredEncryptedAreaEnd=%I64d (%I64d)\n", Extension->ConfiguredEncryptedAreaStart / 1024 / 1024, Extension->ConfiguredEncryptedAreaStart, Extension->ConfiguredEncryptedAreaEnd / 1024 / 1024, Extension->ConfiguredEncryptedAreaEnd);
- Dump ("Saving: EncryptedAreaStart=%I64d (%I64d) EncryptedAreaEnd=%I64d (%I64d)\n", Extension->Queue.EncryptedAreaStart / 1024 / 1024, Extension->Queue.EncryptedAreaStart, Extension->Queue.EncryptedAreaEnd / 1024 / 1024, Extension->Queue.EncryptedAreaEnd);
-
- if (Extension->Queue.EncryptedAreaStart == -1 || Extension->Queue.EncryptedAreaEnd == -1
- || Extension->Queue.EncryptedAreaEnd <= Extension->Queue.EncryptedAreaStart)
- {
- if (SetupRequest.SetupMode == SetupDecryption)
- {
- memset (header, 0, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
- Extension->VolumeHeaderPresent = FALSE;
- }
- }
- else
- {
- uint32 headerCrc32;
- uint64 encryptedAreaLength = Extension->Queue.EncryptedAreaEnd + 1 - Extension->Queue.EncryptedAreaStart;
- byte *fieldPos = header + TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH;
-
- DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, Extension->HeaderCryptoInfo);
-
- if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x56455241)
- {
- Dump ("Header not decrypted");
- status = STATUS_UNKNOWN_REVISION;
- goto ret;
- }
-
- mputInt64 (fieldPos, encryptedAreaLength);
-
- headerCrc32 = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
- fieldPos = header + TC_HEADER_OFFSET_HEADER_CRC;
- mputLong (fieldPos, headerCrc32);
-
- EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, Extension->HeaderCryptoInfo);
- }
-
- status = TCWriteDevice (Extension->LowerDeviceObject, header, offset, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
- if (!NT_SUCCESS (status))
- {
- Dump ("TCWriteDevice error %x", status);
- goto ret;
- }
-
-ret:
- TCfree (header);
- return status;
-}
-
-
-static NTSTATUS PassIrp (PDEVICE_OBJECT deviceObject, PIRP irp)
-{
- IoSkipCurrentIrpStackLocation (irp);
- return IoCallDriver (deviceObject, irp);
-}
-
-
-static NTSTATUS PassFilteredIrp (PDEVICE_OBJECT deviceObject, PIRP irp, PIO_COMPLETION_ROUTINE completionRoutine, PVOID completionRoutineArg)
-{
- IoCopyCurrentIrpStackLocationToNext (irp);
-
- if (completionRoutine)
- IoSetCompletionRoutine (irp, completionRoutine, completionRoutineArg, TRUE, TRUE, TRUE);
-
- return IoCallDriver (deviceObject, irp);
-}
-
-
-static NTSTATUS OnDeviceUsageNotificationCompleted (PDEVICE_OBJECT filterDeviceObject, PIRP Irp, DriveFilterExtension *Extension)
-{
- if (Irp->PendingReturned)
- IoMarkIrpPending (Irp);
-
- if (!(Extension->LowerDeviceObject->Flags & DO_POWER_PAGABLE))
- filterDeviceObject->Flags &= ~DO_POWER_PAGABLE;
-
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
- return STATUS_CONTINUE_COMPLETION;
-}
-
-
-static BOOL IsVolumeDevice (PDEVICE_OBJECT deviceObject)
-{
- VOLUME_NUMBER volNumber;
- VOLUME_DISK_EXTENTS extents[2];
- NTSTATUS extentStatus = SendDeviceIoControlRequest (deviceObject, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, extents, sizeof (extents));
-
- return NT_SUCCESS (SendDeviceIoControlRequest (deviceObject, IOCTL_VOLUME_SUPPORTS_ONLINE_OFFLINE, NULL, 0, NULL, 0))
- || NT_SUCCESS (SendDeviceIoControlRequest (deviceObject, IOCTL_VOLUME_IS_OFFLINE, NULL, 0, NULL, 0))
- || NT_SUCCESS (SendDeviceIoControlRequest (deviceObject, IOCTL_VOLUME_IS_IO_CAPABLE, NULL, 0, NULL, 0))
- || NT_SUCCESS (SendDeviceIoControlRequest (deviceObject, IOCTL_VOLUME_IS_PARTITION, NULL, 0, NULL, 0))
- || NT_SUCCESS (SendDeviceIoControlRequest (deviceObject, IOCTL_VOLUME_QUERY_VOLUME_NUMBER, NULL, 0, &volNumber, sizeof (volNumber)))
- || NT_SUCCESS (extentStatus) || extentStatus == STATUS_BUFFER_OVERFLOW || extentStatus == STATUS_BUFFER_TOO_SMALL;
-}
-
-
-static void CheckDeviceTypeAndMount (DriveFilterExtension *filterExtension)
-{
- if (BootArgsValid)
- {
- // Windows sometimes merges a removable drive PDO and its volume PDO to a single PDO having no volume interface (GUID_DEVINTERFACE_VOLUME).
- // Therefore, we need to test whether the device supports volume IOCTLs.
- if (VolumeClassFilterRegistered
- && BootArgs.HiddenSystemPartitionStart != 0
- && IsVolumeDevice (filterExtension->LowerDeviceObject))
- {
- Dump ("Drive and volume merged pdo=%p", filterExtension->Pdo);
-
- filterExtension->IsVolumeFilterDevice = TRUE;
- filterExtension->IsDriveFilterDevice = FALSE;
- }
- else
- {
- NTSTATUS status = KeWaitForMutexObject (&MountMutex, Executive, KernelMode, FALSE, NULL);
- if (!NT_SUCCESS (status))
- TC_BUG_CHECK (status);
-
- if (!BootDriveFound)
- MountDrive (filterExtension, &BootArgs.BootPassword, &BootArgs.HeaderSaltCrc32);
-
- KeReleaseMutex (&MountMutex, FALSE);
- }
- }
-}
-
-
-static VOID MountDriveWorkItemRoutine (PDEVICE_OBJECT deviceObject, DriveFilterExtension *filterExtension)
-{
- CheckDeviceTypeAndMount (filterExtension);
- KeSetEvent (&filterExtension->MountWorkItemCompletedEvent, IO_NO_INCREMENT, FALSE);
-}
-
-
-static NTSTATUS OnStartDeviceCompleted (PDEVICE_OBJECT filterDeviceObject, PIRP Irp, DriveFilterExtension *Extension)
-{
- if (Irp->PendingReturned)
- IoMarkIrpPending (Irp);
-
- if (Extension->LowerDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
- filterDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
-
- if (KeGetCurrentIrql() == PASSIVE_LEVEL)
- {
- CheckDeviceTypeAndMount (Extension);
- }
- else
- {
- PIO_WORKITEM workItem = IoAllocateWorkItem (filterDeviceObject);
- if (!workItem)
- {
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- KeInitializeEvent (&Extension->MountWorkItemCompletedEvent, SynchronizationEvent, FALSE);
- IoQueueWorkItem (workItem, MountDriveWorkItemRoutine, DelayedWorkQueue, Extension);
-
- KeWaitForSingleObject (&Extension->MountWorkItemCompletedEvent, Executive, KernelMode, FALSE, NULL);
- IoFreeWorkItem (workItem);
- }
-
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
- return STATUS_CONTINUE_COMPLETION;
-}
-
-
-static NTSTATUS DispatchPnp (PDEVICE_OBJECT DeviceObject, PIRP Irp, DriveFilterExtension *Extension, PIO_STACK_LOCATION irpSp)
-{
- NTSTATUS status;
-
- status = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp);
- if (!NT_SUCCESS (status))
- return TCCompleteIrp (Irp, status, 0);
-
- switch (irpSp->MinorFunction)
- {
- case IRP_MN_START_DEVICE:
- Dump ("IRP_MN_START_DEVICE pdo=%p\n", Extension->Pdo);
- return PassFilteredIrp (Extension->LowerDeviceObject, Irp, OnStartDeviceCompleted, Extension);
-
-
- case IRP_MN_DEVICE_USAGE_NOTIFICATION:
- Dump ("IRP_MN_DEVICE_USAGE_NOTIFICATION type=%d\n", (int) irpSp->Parameters.UsageNotification.Type);
-
- {
- PDEVICE_OBJECT attachedDevice = IoGetAttachedDeviceReference (DeviceObject);
-
- if (attachedDevice == DeviceObject || (attachedDevice->Flags & DO_POWER_PAGABLE))
- DeviceObject->Flags |= DO_POWER_PAGABLE;
-
- ObDereferenceObject (attachedDevice);
- }
-
- // Prevent creation of hibernation and crash dump files if required
- if (irpSp->Parameters.UsageNotification.InPath
- && (
- (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeDumpFile && !CrashDumpEnabled)
- || (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeHibernation && !HibernationEnabled)
- )
- )
- {
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
-
- if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeHibernation)
- ++HibernationPreventionCount;
-
- Dump ("Preventing dump type=%d\n", (int) irpSp->Parameters.UsageNotification.Type);
- return TCCompleteIrp (Irp, STATUS_UNSUCCESSFUL, 0);
- }
-
- return PassFilteredIrp (Extension->LowerDeviceObject, Irp, OnDeviceUsageNotificationCompleted, Extension);
-
-
- case IRP_MN_REMOVE_DEVICE:
- Dump ("IRP_MN_REMOVE_DEVICE pdo=%p\n", Extension->Pdo);
-
- IoReleaseRemoveLockAndWait (&Extension->Queue.RemoveLock, Irp);
- status = PassIrp (Extension->LowerDeviceObject, Irp);
-
- IoDetachDevice (Extension->LowerDeviceObject);
-
- if (Extension->DriveMounted)
- DismountDrive (Extension, TRUE);
-
- if (Extension->BootDrive)
- {
- BootDriveFound = FALSE;
- BootDriveFilterExtension = NULL;
- }
-
- IoDeleteDevice (DeviceObject);
- return status;
-
-
- default:
- status = PassIrp (Extension->LowerDeviceObject, Irp);
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
- }
- return status;
-}
-
-
-static NTSTATUS DispatchPower (PDEVICE_OBJECT DeviceObject, PIRP Irp, DriveFilterExtension *Extension, PIO_STACK_LOCATION irpSp)
-{
- NTSTATUS status;
- Dump ("IRP_MJ_POWER minor=%d type=%d shutdown=%d\n", (int) irpSp->MinorFunction, (int) irpSp->Parameters.Power.Type, (int) irpSp->Parameters.Power.ShutdownType);
-
- if (SetupInProgress
- && irpSp->MinorFunction == IRP_MN_SET_POWER
- && irpSp->Parameters.Power.ShutdownType == PowerActionHibernate)
- {
- while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES);
- }
-
-#if 0 // Dismount of the system drive is disabled until there is a way to do it without causing system errors (see the documentation for more info)
- if (DriverShuttingDown
- && Extension->BootDrive
- && Extension->DriveMounted
- && irpSp->MinorFunction == IRP_MN_SET_POWER
- && irpSp->Parameters.Power.Type == DevicePowerState)
- {
- DismountDrive (Extension, TRUE);
- }
-#endif // 0
-
- PoStartNextPowerIrp (Irp);
-
- status = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp);
- if (!NT_SUCCESS (status))
- return TCCompleteIrp (Irp, status, 0);
-
- IoSkipCurrentIrpStackLocation (Irp);
- status = PoCallDriver (Extension->LowerDeviceObject, Irp);
-
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
- return status;
-}
-
-
-NTSTATUS DriveFilterDispatchIrp (PDEVICE_OBJECT DeviceObject, PIRP Irp)
-{
- DriveFilterExtension *Extension = (DriveFilterExtension *) DeviceObject->DeviceExtension;
- PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
- NTSTATUS status;
-
- ASSERT (!Extension->bRootDevice && Extension->IsDriveFilterDevice);
-
- switch (irpSp->MajorFunction)
- {
- case IRP_MJ_READ:
- case IRP_MJ_WRITE:
- if (Extension->BootDrive)
- {
- status = EncryptedIoQueueAddIrp (&Extension->Queue, Irp);
-
- if (status != STATUS_PENDING)
- TCCompleteDiskIrp (Irp, status, 0);
-
- return status;
- }
- break;
-
- case IRP_MJ_PNP:
- return DispatchPnp (DeviceObject, Irp, Extension, irpSp);
-
- case IRP_MJ_POWER:
- return DispatchPower (DeviceObject, Irp, Extension, irpSp);
- }
-
- status = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp);
- if (!NT_SUCCESS (status))
- return TCCompleteIrp (Irp, status, 0);
-
- status = PassIrp (Extension->LowerDeviceObject, Irp);
-
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
- return status;
-}
-
-
-void ReopenBootVolumeHeader (PIRP irp, PIO_STACK_LOCATION irpSp)
-{
- LARGE_INTEGER offset;
- char *header;
- ReopenBootVolumeHeaderRequest *request = (ReopenBootVolumeHeaderRequest *) irp->AssociatedIrp.SystemBuffer;
-
- irp->IoStatus.Information = 0;
-
- if (!IoIsSystemThread (PsGetCurrentThread()) && !UserCanAccessDriveDevice())
- {
- irp->IoStatus.Status = STATUS_ACCESS_DENIED;
- return;
- }
-
- if (!ValidateIOBufferSize (irp, sizeof (ReopenBootVolumeHeaderRequest), ValidateInput))
- return;
-
- if (!BootDriveFound || !BootDriveFilterExtension || !BootDriveFilterExtension->DriveMounted || !BootDriveFilterExtension->HeaderCryptoInfo
- || request->VolumePassword.Length > MAX_PASSWORD
- || request->pkcs5_prf < 0
- || request->pkcs5_prf > LAST_PRF_ID
- || request->pim < 0
- || request->pim > 65535
- )
- {
- irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- goto wipe;
- }
-
- header = TCalloc (TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
- if (!header)
- {
- irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- goto wipe;
- }
-
- if (BootDriveFilterExtension->HiddenSystem)
- offset.QuadPart = BootArgs.HiddenSystemPartitionStart + TC_HIDDEN_VOLUME_HEADER_OFFSET;
- else
- offset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
-
- irp->IoStatus.Status = TCReadDevice (BootDriveFilterExtension->LowerDeviceObject, header, offset, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
- if (!NT_SUCCESS (irp->IoStatus.Status))
- {
- Dump ("TCReadDevice error %x\n", irp->IoStatus.Status);
- goto ret;
- }
-
- if (ReadVolumeHeader (!BootDriveFilterExtension->HiddenSystem, header, &request->VolumePassword, request->pkcs5_prf, request->pim, FALSE, NULL, BootDriveFilterExtension->HeaderCryptoInfo) == 0)
- {
- Dump ("Header reopened\n");
- ComputeBootLoaderFingerprint (BootDriveFilterExtension->LowerDeviceObject, header);
-
- BootDriveFilterExtension->Queue.CryptoInfo->header_creation_time = BootDriveFilterExtension->HeaderCryptoInfo->header_creation_time;
- BootDriveFilterExtension->Queue.CryptoInfo->pkcs5 = BootDriveFilterExtension->HeaderCryptoInfo->pkcs5;
- BootDriveFilterExtension->Queue.CryptoInfo->noIterations = BootDriveFilterExtension->HeaderCryptoInfo->noIterations;
- BootDriveFilterExtension->Queue.CryptoInfo->volumePim = BootDriveFilterExtension->HeaderCryptoInfo->volumePim;
-
- irp->IoStatus.Status = STATUS_SUCCESS;
- }
- else
- {
- crypto_close (BootDriveFilterExtension->HeaderCryptoInfo);
- BootDriveFilterExtension->HeaderCryptoInfo = NULL;
-
- Dump ("Header not reopened\n");
- irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- }
-
-ret:
- TCfree (header);
-wipe:
- burn (request, sizeof (*request));
-}
-
-
-// Legacy Windows XP/2003 hibernation dump filter
-
-typedef NTSTATUS (*HiberDriverWriteFunctionA) (ULONG arg0, PLARGE_INTEGER writeOffset, PMDL dataMdl, PVOID arg3);
-typedef NTSTATUS (*HiberDriverWriteFunctionB) (PLARGE_INTEGER writeOffset, PMDL dataMdl);
-
-typedef struct
-{
-#ifdef _WIN64
- byte FieldPad1[64];
- HiberDriverWriteFunctionB WriteFunctionB;
- byte FieldPad2[56];
-#else
- byte FieldPad1[48];
- HiberDriverWriteFunctionB WriteFunctionB;
- byte FieldPad2[32];
-#endif
- HiberDriverWriteFunctionA WriteFunctionA;
- byte FieldPad3[24];
- LARGE_INTEGER PartitionStartOffset;
-} HiberDriverContext;
-
-typedef NTSTATUS (*HiberDriverEntry) (PVOID arg0, HiberDriverContext *hiberDriverContext);
-
-typedef struct
-{
- LIST_ENTRY ModuleList;
-#ifdef _WIN64
- byte FieldPad1[32];
-#else
- byte FieldPad1[16];
-#endif
- PVOID ModuleBaseAddress;
- HiberDriverEntry ModuleEntryAddress;
-#ifdef _WIN64
- byte FieldPad2[24];
-#else
- byte FieldPad2[12];
-#endif
- UNICODE_STRING ModuleName;
-} ModuleTableItem;
-
-
-#define TC_MAX_HIBER_FILTER_COUNT 3
-static int LastHiberFilterNumber = 0;
-
-static HiberDriverEntry OriginalHiberDriverEntries[TC_MAX_HIBER_FILTER_COUNT];
-static HiberDriverWriteFunctionA OriginalHiberDriverWriteFunctionsA[TC_MAX_HIBER_FILTER_COUNT];
-static HiberDriverWriteFunctionB OriginalHiberDriverWriteFunctionsB[TC_MAX_HIBER_FILTER_COUNT];
-
-static LARGE_INTEGER HiberPartitionOffset;
-
-
-static NTSTATUS HiberDriverWriteFunctionFilter (int filterNumber, PLARGE_INTEGER writeOffset, PMDL dataMdl, BOOL writeB, ULONG arg0WriteA, PVOID arg3WriteA)
-{
- MDL *encryptedDataMdl = dataMdl;
-
- if (writeOffset && dataMdl && BootDriveFilterExtension && BootDriveFilterExtension->DriveMounted)
- {
- ULONG dataLength = MmGetMdlByteCount (dataMdl);
-
- if (dataMdl->MappedSystemVa && dataLength > 0)
- {
- uint64 offset = HiberPartitionOffset.QuadPart + writeOffset->QuadPart;
- uint64 intersectStart;
- uint32 intersectLength;
-
- if (dataLength > TC_HIBERNATION_WRITE_BUFFER_SIZE)
- TC_BUG_CHECK (STATUS_BUFFER_OVERFLOW);
-
- if ((dataLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0)
- TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
-
- if ((offset & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0)
- TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
-
- GetIntersection (offset,
- dataLength,
- BootDriveFilterExtension->Queue.EncryptedAreaStart,
- BootDriveFilterExtension->Queue.EncryptedAreaEnd,
- &intersectStart,
- &intersectLength);
-
- if (intersectLength > 0)
- {
- UINT64_STRUCT dataUnit;
- dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE;
-
- memcpy (HibernationWriteBuffer, dataMdl->MappedSystemVa, dataLength);
-
- if (BootDriveFilterExtension->Queue.RemapEncryptedArea)
- dataUnit.Value += BootDriveFilterExtension->Queue.RemappedAreaDataUnitOffset;
-
- EncryptDataUnitsCurrentThread (HibernationWriteBuffer + (intersectStart - offset),
- &dataUnit,
- intersectLength / ENCRYPTION_DATA_UNIT_SIZE,
- BootDriveFilterExtension->Queue.CryptoInfo);
-
- encryptedDataMdl = HibernationWriteBufferMdl;
- MmInitializeMdl (encryptedDataMdl, HibernationWriteBuffer, dataLength);
- encryptedDataMdl->MdlFlags = dataMdl->MdlFlags;
- }
- }
- }
-
- if (writeB)
- return (*OriginalHiberDriverWriteFunctionsB[filterNumber]) (writeOffset, encryptedDataMdl);
-
- return (*OriginalHiberDriverWriteFunctionsA[filterNumber]) (arg0WriteA, writeOffset, encryptedDataMdl, arg3WriteA);
-}
-
-
-static NTSTATUS HiberDriverWriteFunctionAFilter0 (ULONG arg0, PLARGE_INTEGER writeOffset, PMDL dataMdl, PVOID arg3)
-{
- return HiberDriverWriteFunctionFilter (0, writeOffset, dataMdl, FALSE, arg0, arg3);
-}
-
-static NTSTATUS HiberDriverWriteFunctionAFilter1 (ULONG arg0, PLARGE_INTEGER writeOffset, PMDL dataMdl, PVOID arg3)
-{
- return HiberDriverWriteFunctionFilter (1, writeOffset, dataMdl, FALSE, arg0, arg3);
-}
-
-static NTSTATUS HiberDriverWriteFunctionAFilter2 (ULONG arg0, PLARGE_INTEGER writeOffset, PMDL dataMdl, PVOID arg3)
-{
- return HiberDriverWriteFunctionFilter (2, writeOffset, dataMdl, FALSE, arg0, arg3);
-}
-
-
-static NTSTATUS HiberDriverWriteFunctionBFilter0 (PLARGE_INTEGER writeOffset, PMDL dataMdl)
-{
- return HiberDriverWriteFunctionFilter (0, writeOffset, dataMdl, TRUE, 0, NULL);
-}
-
-static NTSTATUS HiberDriverWriteFunctionBFilter1 (PLARGE_INTEGER writeOffset, PMDL dataMdl)
-{
- return HiberDriverWriteFunctionFilter (1, writeOffset, dataMdl, TRUE, 0, NULL);
-}
-
-static NTSTATUS HiberDriverWriteFunctionBFilter2 (PLARGE_INTEGER writeOffset, PMDL dataMdl)
-{
- return HiberDriverWriteFunctionFilter (2, writeOffset, dataMdl, TRUE, 0, NULL);
-}
-
-
-static NTSTATUS HiberDriverEntryFilter (int filterNumber, PVOID arg0, HiberDriverContext *hiberDriverContext)
-{
- BOOL filterInstalled = FALSE;
- NTSTATUS status;
-
- if (!OriginalHiberDriverEntries[filterNumber])
- return STATUS_UNSUCCESSFUL;
-
- status = (*OriginalHiberDriverEntries[filterNumber]) (arg0, hiberDriverContext);
-
- if (!NT_SUCCESS (status) || !hiberDriverContext)
- return status;
-
- if (SetupInProgress)
- TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
-
- if (hiberDriverContext->WriteFunctionA)
- {
- Dump ("Filtering WriteFunctionA %d\n", filterNumber);
- OriginalHiberDriverWriteFunctionsA[filterNumber] = hiberDriverContext->WriteFunctionA;
-
- switch (filterNumber)
- {
- case 0: hiberDriverContext->WriteFunctionA = HiberDriverWriteFunctionAFilter0; break;
- case 1: hiberDriverContext->WriteFunctionA = HiberDriverWriteFunctionAFilter1; break;
- case 2: hiberDriverContext->WriteFunctionA = HiberDriverWriteFunctionAFilter2; break;
- default: TC_THROW_FATAL_EXCEPTION;
- }
-
- filterInstalled = TRUE;
- }
-
- if (hiberDriverContext->WriteFunctionB)
- {
- Dump ("Filtering WriteFunctionB %d\n", filterNumber);
- OriginalHiberDriverWriteFunctionsB[filterNumber] = hiberDriverContext->WriteFunctionB;
-
- switch (filterNumber)
- {
- case 0: hiberDriverContext->WriteFunctionB = HiberDriverWriteFunctionBFilter0; break;
- case 1: hiberDriverContext->WriteFunctionB = HiberDriverWriteFunctionBFilter1; break;
- case 2: hiberDriverContext->WriteFunctionB = HiberDriverWriteFunctionBFilter2; break;
- default: TC_THROW_FATAL_EXCEPTION;
- }
-
- filterInstalled = TRUE;
- }
-
- if (filterInstalled && hiberDriverContext->PartitionStartOffset.QuadPart != 0)
- {
- HiberPartitionOffset = hiberDriverContext->PartitionStartOffset;
-
- if (BootDriveFilterExtension->Queue.RemapEncryptedArea)
- hiberDriverContext->PartitionStartOffset.QuadPart += BootDriveFilterExtension->Queue.RemappedAreaOffset;
- }
-
- return STATUS_SUCCESS;
-}
-
-
-static NTSTATUS HiberDriverEntryFilter0 (PVOID arg0, HiberDriverContext *hiberDriverContext)
-{
- return HiberDriverEntryFilter (0, arg0, hiberDriverContext);
-}
-
-
-static NTSTATUS HiberDriverEntryFilter1 (PVOID arg0, HiberDriverContext *hiberDriverContext)
-{
- return HiberDriverEntryFilter (1, arg0, hiberDriverContext);
-}
-
-
-static NTSTATUS HiberDriverEntryFilter2 (PVOID arg0, HiberDriverContext *hiberDriverContext)
-{
- return HiberDriverEntryFilter (2, arg0, hiberDriverContext);
-}
-
-
-static VOID LoadImageNotifyRoutine (PUNICODE_STRING fullImageName, HANDLE processId, PIMAGE_INFO imageInfo)
-{
- ModuleTableItem *moduleItem;
- LIST_ENTRY *listEntry;
- KIRQL origIrql;
-
- if (!imageInfo || !imageInfo->SystemModeImage || !imageInfo->ImageBase || !TCDriverObject->DriverSection)
- return;
-
- moduleItem = *(ModuleTableItem **) TCDriverObject->DriverSection;
- if (!moduleItem || !moduleItem->ModuleList.Flink)
- return;
-
- // Search loaded system modules for hibernation driver
- origIrql = KeRaiseIrqlToDpcLevel();
-
- for (listEntry = moduleItem->ModuleList.Flink->Blink;
- listEntry && listEntry != TCDriverObject->DriverSection;
- listEntry = listEntry->Flink)
- {
- moduleItem = CONTAINING_RECORD (listEntry, ModuleTableItem, ModuleList);
-
- if (moduleItem && imageInfo->ImageBase == moduleItem->ModuleBaseAddress)
- {
- if (moduleItem->ModuleName.Buffer && moduleItem->ModuleName.Length >= 5 * sizeof (wchar_t))
- {
- if (memcmp (moduleItem->ModuleName.Buffer, L"hiber", 5 * sizeof (wchar_t)) == 0
- || memcmp (moduleItem->ModuleName.Buffer, L"Hiber", 5 * sizeof (wchar_t)) == 0
- || memcmp (moduleItem->ModuleName.Buffer, L"HIBER", 5 * sizeof (wchar_t)) == 0)
- {
- HiberDriverEntry filterEntry;
-
- switch (LastHiberFilterNumber)
- {
- case 0: filterEntry = HiberDriverEntryFilter0; break;
- case 1: filterEntry = HiberDriverEntryFilter1; break;
- case 2: filterEntry = HiberDriverEntryFilter2; break;
- default: TC_THROW_FATAL_EXCEPTION;
- }
-
- if (moduleItem->ModuleEntryAddress != filterEntry)
- {
- // Install filter
- OriginalHiberDriverEntries[LastHiberFilterNumber] = moduleItem->ModuleEntryAddress;
- moduleItem->ModuleEntryAddress = filterEntry;
-
- if (++LastHiberFilterNumber > TC_MAX_HIBER_FILTER_COUNT - 1)
- LastHiberFilterNumber = 0;
- }
- }
- }
- break;
- }
- }
-
- KeLowerIrql (origIrql);
-}
-
-
-void StartLegacyHibernationDriverFilter ()
-{
- PHYSICAL_ADDRESS highestAcceptableWriteBufferAddr;
- NTSTATUS status;
-
- ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
- ASSERT (!IsOSAtLeast (WIN_VISTA));
-
- if (!TCDriverObject->DriverSection || !*(ModuleTableItem **) TCDriverObject->DriverSection)
- goto err;
-
- // All buffers required for hibernation must be allocated here
-#ifdef _WIN64
- highestAcceptableWriteBufferAddr.QuadPart = 0x7FFffffFFFFULL;
-#else
- highestAcceptableWriteBufferAddr.QuadPart = 0xffffFFFFULL;
-#endif
-
- HibernationWriteBuffer = MmAllocateContiguousMemory (TC_HIBERNATION_WRITE_BUFFER_SIZE, highestAcceptableWriteBufferAddr);
- if (!HibernationWriteBuffer)
- goto err;
-
- HibernationWriteBufferMdl = IoAllocateMdl (HibernationWriteBuffer, TC_HIBERNATION_WRITE_BUFFER_SIZE, FALSE, FALSE, NULL);
- if (!HibernationWriteBufferMdl)
- goto err;
-
- MmBuildMdlForNonPagedPool (HibernationWriteBufferMdl);
-
- status = PsSetLoadImageNotifyRoutine (LoadImageNotifyRoutine);
- if (!NT_SUCCESS (status))
- goto err;
-
- LegacyHibernationDriverFilterActive = TRUE;
- CrashDumpEnabled = FALSE;
- HibernationEnabled = TRUE;
- return;
-
-err:
- LegacyHibernationDriverFilterActive = FALSE;
- CrashDumpEnabled = FALSE;
- HibernationEnabled = FALSE;
-
- if (HibernationWriteBufferMdl)
- {
- IoFreeMdl (HibernationWriteBufferMdl);
- HibernationWriteBufferMdl = NULL;
- }
-
- if (HibernationWriteBuffer)
- {
- MmFreeContiguousMemory (HibernationWriteBuffer);
- HibernationWriteBuffer = NULL;
- }
-}
-
-
-static VOID SetupThreadProc (PVOID threadArg)
-{
- DriveFilterExtension *Extension = BootDriveFilterExtension;
-
- LARGE_INTEGER offset;
- UINT64_STRUCT dataUnit;
- ULONG setupBlockSize = TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE;
- BOOL headerUpdateRequired = FALSE;
- int64 bytesWrittenSinceHeaderUpdate = 0;
-
- byte *buffer = NULL;
- byte *wipeBuffer = NULL;
- byte wipeRandChars[TC_WIPE_RAND_CHAR_COUNT];
- byte wipeRandCharsUpdate[TC_WIPE_RAND_CHAR_COUNT];
-
- KIRQL irql;
- NTSTATUS status;
-
- // generate real random values for wipeRandChars and
- // wipeRandCharsUpdate instead of relying on uninitialized stack memory
- LARGE_INTEGER iSeed;
- KeQuerySystemTime( &iSeed );
- if (KeGetCurrentIrql() < DISPATCH_LEVEL)
- {
- ULONG ulRandom;
- ulRandom = RtlRandomEx( &iSeed.LowPart );
- memcpy (wipeRandChars, &ulRandom, TC_WIPE_RAND_CHAR_COUNT);
- ulRandom = RtlRandomEx( &ulRandom );
- memcpy (wipeRandCharsUpdate, &ulRandom, TC_WIPE_RAND_CHAR_COUNT);
- burn (&ulRandom, sizeof(ulRandom));
- }
- else
- {
- byte digest[SHA512_DIGESTSIZE];
- sha512_ctx tctx;
- sha512_begin (&tctx);
- sha512_hash ((unsigned char *) &(iSeed.QuadPart), sizeof(iSeed.QuadPart), &tctx);
- sha512_end (digest, &tctx);
-
- memcpy (wipeRandChars, digest, TC_WIPE_RAND_CHAR_COUNT);
- memcpy (wipeRandCharsUpdate, &digest[SHA512_DIGESTSIZE - TC_WIPE_RAND_CHAR_COUNT], TC_WIPE_RAND_CHAR_COUNT);
-
- burn (digest, SHA512_DIGESTSIZE);
- burn (&tctx, sizeof (tctx));
- }
-
- burn (&iSeed, sizeof(iSeed));
-
- SetupResult = STATUS_UNSUCCESSFUL;
-
- // Make sure volume header can be updated
- if (Extension->HeaderCryptoInfo == NULL)
- {
- SetupResult = STATUS_INVALID_PARAMETER;
- goto ret;
- }
-
- buffer = TCalloc (TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE);
- if (!buffer)
- {
- SetupResult = STATUS_INSUFFICIENT_RESOURCES;
- goto ret;
- }
-
- if (SetupRequest.SetupMode == SetupEncryption && SetupRequest.WipeAlgorithm != TC_WIPE_NONE)
- {
- wipeBuffer = TCalloc (TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE);
- if (!wipeBuffer)
- {
- SetupResult = STATUS_INSUFFICIENT_RESOURCES;
- goto ret;
- }
- }
-
- while (!NT_SUCCESS (EncryptedIoQueueHoldWhenIdle (&Extension->Queue, 1000)))
- {
- if (EncryptionSetupThreadAbortRequested)
- goto abort;
-
- TransformWaitingForIdle = TRUE;
- }
- TransformWaitingForIdle = FALSE;
-
- switch (SetupRequest.SetupMode)
- {
- case SetupEncryption:
- Dump ("Encrypting...\n");
- if (Extension->Queue.EncryptedAreaStart == -1 || Extension->Queue.EncryptedAreaEnd == -1)
- {
- // Start encryption
- Extension->Queue.EncryptedAreaStart = Extension->ConfiguredEncryptedAreaStart;
- Extension->Queue.EncryptedAreaEnd = -1;
- offset.QuadPart = Extension->ConfiguredEncryptedAreaStart;
- }
- else
- {
- // Resume aborted encryption
- if (Extension->Queue.EncryptedAreaEnd == Extension->ConfiguredEncryptedAreaEnd)
- goto err;
-
- offset.QuadPart = Extension->Queue.EncryptedAreaEnd + 1;
- }
-
- break;
-
- case SetupDecryption:
- Dump ("Decrypting...\n");
- if (Extension->Queue.EncryptedAreaStart == -1 || Extension->Queue.EncryptedAreaEnd == -1)
- {
- SetupResult = STATUS_SUCCESS;
- goto abort;
- }
-
- offset.QuadPart = Extension->Queue.EncryptedAreaEnd + 1;
- break;
-
- default:
- goto err;
- }
-
- EncryptedIoQueueResumeFromHold (&Extension->Queue);
-
- Dump ("EncryptedAreaStart=%I64d\n", Extension->Queue.EncryptedAreaStart);
- Dump ("EncryptedAreaEnd=%I64d\n", Extension->Queue.EncryptedAreaEnd);
- Dump ("ConfiguredEncryptedAreaStart=%I64d\n", Extension->ConfiguredEncryptedAreaStart);
- Dump ("ConfiguredEncryptedAreaEnd=%I64d\n", Extension->ConfiguredEncryptedAreaEnd);
- Dump ("offset=%I64d\n", offset.QuadPart);
- Dump ("EncryptedAreaStart=%I64d (%I64d) EncryptedAreaEnd=%I64d\n", Extension->Queue.EncryptedAreaStart / 1024 / 1024, Extension->Queue.EncryptedAreaStart, Extension->Queue.EncryptedAreaEnd / 1024 / 1024);
-
- while (!EncryptionSetupThreadAbortRequested)
- {
- if (SetupRequest.SetupMode == SetupEncryption)
- {
- if (offset.QuadPart + setupBlockSize > Extension->ConfiguredEncryptedAreaEnd + 1)
- setupBlockSize = (ULONG) (Extension->ConfiguredEncryptedAreaEnd + 1 - offset.QuadPart);
-
- if (offset.QuadPart > Extension->ConfiguredEncryptedAreaEnd)
- break;
- }
- else
- {
- if (offset.QuadPart - setupBlockSize < Extension->Queue.EncryptedAreaStart)
- setupBlockSize = (ULONG) (offset.QuadPart - Extension->Queue.EncryptedAreaStart);
-
- offset.QuadPart -= setupBlockSize;
-
- if (setupBlockSize == 0 || offset.QuadPart < Extension->Queue.EncryptedAreaStart)
- break;
- }
-
- while (!NT_SUCCESS (EncryptedIoQueueHoldWhenIdle (&Extension->Queue, 500)))
- {
- if (EncryptionSetupThreadAbortRequested)
- goto abort;
-
- TransformWaitingForIdle = TRUE;
- }
- TransformWaitingForIdle = FALSE;
-
- status = TCReadDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize);
- if (!NT_SUCCESS (status))
- {
- Dump ("TCReadDevice error %x offset=%I64d\n", status, offset.QuadPart);
-
- if (SetupRequest.ZeroUnreadableSectors && SetupRequest.SetupMode == SetupEncryption)
- {
- // Zero unreadable sectors
- uint64 zeroedSectorCount;
-
- status = ZeroUnreadableSectors (BootDriveFilterExtension->LowerDeviceObject, offset, setupBlockSize, &zeroedSectorCount);
- if (!NT_SUCCESS (status))
- {
- SetupResult = status;
- goto err;
- }
-
- // Retry read
- status = TCReadDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize);
- if (!NT_SUCCESS (status))
- {
- SetupResult = status;
- goto err;
- }
- }
- else if (SetupRequest.DiscardUnreadableEncryptedSectors && SetupRequest.SetupMode == SetupDecryption)
- {
- // Discard unreadable encrypted sectors
- uint64 badSectorCount;
-
- status = ReadDeviceSkipUnreadableSectors (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize, &badSectorCount);
- if (!NT_SUCCESS (status))
- {
- SetupResult = status;
- goto err;
- }
- }
- else
- {
- SetupResult = status;
- goto err;
- }
- }
-
- dataUnit.Value = offset.QuadPart / ENCRYPTION_DATA_UNIT_SIZE;
-
- if (SetupRequest.SetupMode == SetupEncryption)
- {
- EncryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo);
-
- if (SetupRequest.WipeAlgorithm != TC_WIPE_NONE)
- {
- byte wipePass;
- int wipePassCount = GetWipePassCount (SetupRequest.WipeAlgorithm);
- if (wipePassCount <= 0)
- {
- SetupResult = STATUS_INVALID_PARAMETER;
- goto err;
- }
-
- for (wipePass = 1; wipePass <= wipePassCount; ++wipePass)
- {
- if (!WipeBuffer (SetupRequest.WipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, setupBlockSize))
- {
- ULONG i;
- for (i = 0; i < setupBlockSize; ++i)
- {
- wipeBuffer[i] = buffer[i] + wipePass;
- }
-
- EncryptDataUnits (wipeBuffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo);
- memcpy (wipeRandCharsUpdate, wipeBuffer, sizeof (wipeRandCharsUpdate));
- }
-
- status = TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, wipeBuffer, offset, setupBlockSize);
- if (!NT_SUCCESS (status))
- {
- // Undo failed write operation
- DecryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo);
- TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize);
-
- SetupResult = status;
- goto err;
- }
- }
-
- memcpy (wipeRandChars, wipeRandCharsUpdate, sizeof (wipeRandCharsUpdate));
- }
- }
- else
- {
- DecryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo);
- }
-
- status = TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize);
- if (!NT_SUCCESS (status))
- {
- Dump ("TCWriteDevice error %x\n", status);
-
- // Undo failed write operation
- if (SetupRequest.SetupMode == SetupEncryption)
- DecryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo);
- else
- EncryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo);
-
- TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize);
-
- SetupResult = status;
- goto err;
- }
-
- if (SetupRequest.SetupMode == SetupEncryption)
- offset.QuadPart += setupBlockSize;
-
- Extension->Queue.EncryptedAreaEndUpdatePending = TRUE;
- Extension->Queue.EncryptedAreaEnd = offset.QuadPart - 1;
- Extension->Queue.EncryptedAreaEndUpdatePending = FALSE;
-
- headerUpdateRequired = TRUE;
-
- EncryptedIoQueueResumeFromHold (&Extension->Queue);
-
- KeAcquireSpinLock (&SetupStatusSpinLock, &irql);
- SetupStatusEncryptedAreaEnd = Extension->Queue.EncryptedAreaEnd;
- KeReleaseSpinLock (&SetupStatusSpinLock, irql);
-
- // Update volume header
- bytesWrittenSinceHeaderUpdate += setupBlockSize;
- if (bytesWrittenSinceHeaderUpdate >= TC_ENCRYPTION_SETUP_HEADER_UPDATE_THRESHOLD)
- {
- status = SaveDriveVolumeHeader (Extension);
- ASSERT (NT_SUCCESS (status));
- if (NT_SUCCESS (status))
- {
- headerUpdateRequired = FALSE;
- bytesWrittenSinceHeaderUpdate = 0;
- }
- }
- }
-
-abort:
- SetupResult = STATUS_SUCCESS;
-err:
-
- if (Extension->Queue.EncryptedAreaEnd == -1)
- Extension->Queue.EncryptedAreaStart = -1;
-
- if (EncryptedIoQueueIsSuspended (&Extension->Queue))
- EncryptedIoQueueResumeFromHold (&Extension->Queue);
-
- if (SetupRequest.SetupMode == SetupDecryption && Extension->Queue.EncryptedAreaStart >= Extension->Queue.EncryptedAreaEnd)
- {
- while (!NT_SUCCESS (EncryptedIoQueueHoldWhenIdle (&Extension->Queue, 0)));
-
- Extension->ConfiguredEncryptedAreaStart = Extension->ConfiguredEncryptedAreaEnd = -1;
- Extension->Queue.EncryptedAreaStart = Extension->Queue.EncryptedAreaEnd = -1;
-
- EncryptedIoQueueResumeFromHold (&Extension->Queue);
-
- headerUpdateRequired = TRUE;
- }
-
- Dump ("Setup completed: EncryptedAreaStart=%I64d (%I64d) EncryptedAreaEnd=%I64d (%I64d)\n", Extension->Queue.EncryptedAreaStart / 1024 / 1024, Extension->Queue.EncryptedAreaStart, Extension->Queue.EncryptedAreaEnd / 1024 / 1024, Extension->Queue.EncryptedAreaEnd);
-
- if (headerUpdateRequired)
- {
- status = SaveDriveVolumeHeader (Extension);
-
- if (!NT_SUCCESS (status) && NT_SUCCESS (SetupResult))
- SetupResult = status;
- }
-
- if (SetupRequest.SetupMode == SetupDecryption && Extension->ConfiguredEncryptedAreaEnd == -1 && Extension->DriveMounted)
- {
- while (!RootDeviceControlMutexAcquireNoWait() && !EncryptionSetupThreadAbortRequested)
- {
- TCSleep (10);
- }
-
- // Disable hibernation (resume would fail due to a change in the system memory map)
- HibernationEnabled = FALSE;
-
- DismountDrive (Extension, FALSE);
-
- if (!EncryptionSetupThreadAbortRequested)
- RootDeviceControlMutexRelease();
- }
-
-ret:
- if (buffer)
- {
- burn (buffer, TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE);
- TCfree (buffer);
- }
- if (wipeBuffer)
- {
- burn (wipeBuffer, TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE);
- TCfree (wipeBuffer);
- }
-
- burn (wipeRandChars, TC_WIPE_RAND_CHAR_COUNT);
- burn (wipeRandCharsUpdate, TC_WIPE_RAND_CHAR_COUNT);
-
- SetupInProgress = FALSE;
- PsTerminateSystemThread (SetupResult);
-}
-
-
-NTSTATUS StartBootEncryptionSetup (PDEVICE_OBJECT DeviceObject, PIRP irp, PIO_STACK_LOCATION irpSp)
-{
- NTSTATUS status;
-
- if (!UserCanAccessDriveDevice())
- return STATUS_ACCESS_DENIED;
-
- if (SetupInProgress || !BootDriveFound || !BootDriveFilterExtension
- || !BootDriveFilterExtension->DriveMounted
- || BootDriveFilterExtension->HiddenSystem
- || irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (BootEncryptionSetupRequest))
- return STATUS_INVALID_PARAMETER;
-
- if (EncryptionSetupThread)
- AbortBootEncryptionSetup();
-
- SetupRequest = *(BootEncryptionSetupRequest *) irp->AssociatedIrp.SystemBuffer;
-
- EncryptionSetupThreadAbortRequested = FALSE;
- KeInitializeSpinLock (&SetupStatusSpinLock);
- SetupStatusEncryptedAreaEnd = BootDriveFilterExtension ? BootDriveFilterExtension->Queue.EncryptedAreaEnd : -1;
-
- SetupInProgress = TRUE;
- status = TCStartThread (SetupThreadProc, DeviceObject, &EncryptionSetupThread);
-
- if (!NT_SUCCESS (status))
- SetupInProgress = FALSE;
-
- return status;
-}
-
-
-void GetBootDriveVolumeProperties (PIRP irp, PIO_STACK_LOCATION irpSp)
-{
- if (ValidateIOBufferSize (irp, sizeof (VOLUME_PROPERTIES_STRUCT), ValidateOutput))
- {
- DriveFilterExtension *Extension = BootDriveFilterExtension;
- VOLUME_PROPERTIES_STRUCT *prop = (VOLUME_PROPERTIES_STRUCT *) irp->AssociatedIrp.SystemBuffer;
- memset (prop, 0, sizeof (*prop));
-
- if (!BootDriveFound || !Extension || !Extension->DriveMounted)
- {
- irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- irp->IoStatus.Information = 0;
- }
- else
- {
- prop->hiddenVolume = Extension->Queue.CryptoInfo->hiddenVolume;
- prop->diskLength = Extension->ConfiguredEncryptedAreaEnd + 1 - Extension->ConfiguredEncryptedAreaStart;
- prop->ea = Extension->Queue.CryptoInfo->ea;
- prop->mode = Extension->Queue.CryptoInfo->mode;
- prop->pkcs5 = Extension->Queue.CryptoInfo->pkcs5;
- prop->pkcs5Iterations = Extension->Queue.CryptoInfo->noIterations;
- prop->volumePim = Extension->Queue.CryptoInfo->volumePim;
-#if 0
- prop->volumeCreationTime = Extension->Queue.CryptoInfo->volume_creation_time;
- prop->headerCreationTime = Extension->Queue.CryptoInfo->header_creation_time;
-#endif
- prop->volFormatVersion = Extension->Queue.CryptoInfo->LegacyVolume ? TC_VOLUME_FORMAT_VERSION_PRE_6_0 : TC_VOLUME_FORMAT_VERSION;
-
- prop->totalBytesRead = Extension->Queue.TotalBytesRead;
- prop->totalBytesWritten = Extension->Queue.TotalBytesWritten;
-
- irp->IoStatus.Information = sizeof (VOLUME_PROPERTIES_STRUCT);
- irp->IoStatus.Status = STATUS_SUCCESS;
- }
- }
-}
-
-
-void GetBootEncryptionStatus (PIRP irp, PIO_STACK_LOCATION irpSp)
-{
- /* IMPORTANT: Do NOT add any potentially time-consuming operations to this function. */
-
- if (ValidateIOBufferSize (irp, sizeof (BootEncryptionStatus), ValidateOutput))
- {
- DriveFilterExtension *Extension = BootDriveFilterExtension;
- BootEncryptionStatus *bootEncStatus = (BootEncryptionStatus *) irp->AssociatedIrp.SystemBuffer;
- memset (bootEncStatus, 0, sizeof (*bootEncStatus));
-
- if (BootArgsValid)
- bootEncStatus->BootLoaderVersion = BootArgs.BootLoaderVersion;
-
- bootEncStatus->DeviceFilterActive = DeviceFilterActive;
- bootEncStatus->SetupInProgress = SetupInProgress;
- bootEncStatus->SetupMode = SetupRequest.SetupMode;
- bootEncStatus->TransformWaitingForIdle = TransformWaitingForIdle;
-
- if (!BootDriveFound || !Extension || !Extension->DriveMounted)
- {
- bootEncStatus->DriveEncrypted = FALSE;
- bootEncStatus->DriveMounted = FALSE;
- bootEncStatus->VolumeHeaderPresent = FALSE;
- }
- else
- {
- bootEncStatus->DriveMounted = Extension->DriveMounted;
- bootEncStatus->VolumeHeaderPresent = Extension->VolumeHeaderPresent;
- bootEncStatus->DriveEncrypted = Extension->Queue.EncryptedAreaStart != -1;
- bootEncStatus->BootDriveLength = BootDriveLength;
-
- bootEncStatus->ConfiguredEncryptedAreaStart = Extension->ConfiguredEncryptedAreaStart;
- bootEncStatus->ConfiguredEncryptedAreaEnd = Extension->ConfiguredEncryptedAreaEnd;
- bootEncStatus->EncryptedAreaStart = Extension->Queue.EncryptedAreaStart;
-
- if (SetupInProgress)
- {
- KIRQL irql;
- KeAcquireSpinLock (&SetupStatusSpinLock, &irql);
- bootEncStatus->EncryptedAreaEnd = SetupStatusEncryptedAreaEnd;
- KeReleaseSpinLock (&SetupStatusSpinLock, irql);
- }
- else
- bootEncStatus->EncryptedAreaEnd = Extension->Queue.EncryptedAreaEnd;
-
- bootEncStatus->VolumeHeaderSaltCrc32 = Extension->VolumeHeaderSaltCrc32;
- bootEncStatus->HibernationPreventionCount = HibernationPreventionCount;
- bootEncStatus->HiddenSysLeakProtectionCount = HiddenSysLeakProtectionCount;
-
- bootEncStatus->HiddenSystem = Extension->HiddenSystem;
-
- if (Extension->HiddenSystem)
- bootEncStatus->HiddenSystemPartitionStart = BootArgs.HiddenSystemPartitionStart;
- }
-
- irp->IoStatus.Information = sizeof (BootEncryptionStatus);
- irp->IoStatus.Status = STATUS_SUCCESS;
- }
-}
-
-
-void GetBootLoaderVersion (PIRP irp, PIO_STACK_LOCATION irpSp)
-{
- if (ValidateIOBufferSize (irp, sizeof (uint16), ValidateOutput))
- {
- if (BootArgsValid)
- {
- *(uint16 *) irp->AssociatedIrp.SystemBuffer = BootArgs.BootLoaderVersion;
- irp->IoStatus.Information = sizeof (uint16);
- irp->IoStatus.Status = STATUS_SUCCESS;
- }
- else
- {
- irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- irp->IoStatus.Information = 0;
- }
- }
-}
-
-void GetBootLoaderFingerprint (PIRP irp, PIO_STACK_LOCATION irpSp)
-{
- if (ValidateIOBufferSize (irp, sizeof (BootLoaderFingerprintRequest), ValidateOutput))
- {
- irp->IoStatus.Information = 0;
- if (BootArgsValid && BootDriveFound && BootDriveFilterExtension && BootDriveFilterExtension->DriveMounted && BootDriveFilterExtension->HeaderCryptoInfo)
- {
- BootLoaderFingerprintRequest *bootLoaderFingerprint = (BootLoaderFingerprintRequest *) irp->AssociatedIrp.SystemBuffer;
-
- /* compute the fingerprint again and check if it is the same as the one retrieved during boot */
- char *header = TCalloc (TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
- if (!header)
- {
- irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- }
- else
- {
- memcpy (bootLoaderFingerprint->Fingerprint, BootLoaderFingerprint, sizeof (BootLoaderFingerprint));
- ComputeBootLoaderFingerprint (BootDriveFilterExtension->LowerDeviceObject, header);
-
- burn (header, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
- TCfree (header);
-
- if (0 == memcmp (bootLoaderFingerprint->Fingerprint, BootLoaderFingerprint, sizeof (BootLoaderFingerprint)))
- {
- irp->IoStatus.Information = sizeof (BootLoaderFingerprintRequest);
- irp->IoStatus.Status = STATUS_SUCCESS;
- }
- else
- {
- /* fingerprint mismatch.*/
- irp->IoStatus.Status = STATUS_INVALID_IMAGE_HASH;
- }
- }
- }
- else
- {
- irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- }
- }
-}
-
-void GetBootEncryptionAlgorithmName (PIRP irp, PIO_STACK_LOCATION irpSp)
-{
- if (ValidateIOBufferSize (irp, sizeof (GetBootEncryptionAlgorithmNameRequest), ValidateOutput))
- {
- if (BootDriveFilterExtension && BootDriveFilterExtension->DriveMounted)
- {
- wchar_t BootEncryptionAlgorithmNameW[256];
- wchar_t BootPrfAlgorithmNameW[256];
- GetBootEncryptionAlgorithmNameRequest *request = (GetBootEncryptionAlgorithmNameRequest *) irp->AssociatedIrp.SystemBuffer;
- EAGetName (BootEncryptionAlgorithmNameW, BootDriveFilterExtension->Queue.CryptoInfo->ea, 0);
- HashGetName2 (BootPrfAlgorithmNameW, BootDriveFilterExtension->Queue.CryptoInfo->pkcs5);
-
- RtlStringCbPrintfA (request->BootEncryptionAlgorithmName, sizeof (request->BootEncryptionAlgorithmName), "%S", BootEncryptionAlgorithmNameW);
- RtlStringCbPrintfA (request->BootPrfAlgorithmName, sizeof (request->BootPrfAlgorithmName), "%S", BootPrfAlgorithmNameW);
-
- irp->IoStatus.Information = sizeof (GetBootEncryptionAlgorithmNameRequest);
- irp->IoStatus.Status = STATUS_SUCCESS;
- }
- else
- {
- irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- irp->IoStatus.Information = 0;
- }
- }
-}
-
-
-NTSTATUS GetSetupResult()
-{
- return SetupResult;
-}
-
-
-BOOL IsBootDriveMounted ()
-{
- return BootDriveFilterExtension && BootDriveFilterExtension->DriveMounted;
-}
-
-
-BOOL IsBootEncryptionSetupInProgress ()
-{
- return SetupInProgress;
-}
-
-
-BOOL IsHiddenSystemRunning ()
-{
- return BootDriveFilterExtension && BootDriveFilterExtension->HiddenSystem;
-}
-
-
-DriveFilterExtension *GetBootDriveFilterExtension ()
-{
- return BootDriveFilterExtension;
-}
-
-
-CRYPTO_INFO *GetSystemDriveCryptoInfo ()
-{
- return BootDriveFilterExtension->Queue.CryptoInfo;
-}
-
-
-NTSTATUS AbortBootEncryptionSetup ()
-{
- if (!IoIsSystemThread (PsGetCurrentThread()) && !UserCanAccessDriveDevice())
- return STATUS_ACCESS_DENIED;
-
- if (EncryptionSetupThread)
- {
- EncryptionSetupThreadAbortRequested = TRUE;
-
- TCStopThread (EncryptionSetupThread, NULL);
- EncryptionSetupThread = NULL;
- }
-
- return STATUS_SUCCESS;
-}
-
-
-static VOID DecoySystemWipeThreadProc (PVOID threadArg)
-{
- DriveFilterExtension *Extension = BootDriveFilterExtension;
-
- LARGE_INTEGER offset;
- UINT64_STRUCT dataUnit;
- ULONG wipeBlockSize = TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE;
-
- CRYPTO_INFO *wipeCryptoInfo = NULL;
- byte *wipeBuffer = NULL;
- byte *wipeRandBuffer = NULL;
- byte wipeRandChars[TC_WIPE_RAND_CHAR_COUNT];
- int wipePass, wipePassCount;
- int ea = Extension->Queue.CryptoInfo->ea;
-
- KIRQL irql;
- NTSTATUS status;
-
- DecoySystemWipeResult = STATUS_UNSUCCESSFUL;
-
- wipeBuffer = TCalloc (TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE);
- if (!wipeBuffer)
- {
- DecoySystemWipeResult = STATUS_INSUFFICIENT_RESOURCES;
- goto ret;
- }
-
- wipeRandBuffer = TCalloc (TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE);
- if (!wipeRandBuffer)
- {
- DecoySystemWipeResult = STATUS_INSUFFICIENT_RESOURCES;
- goto ret;
- }
-
- wipeCryptoInfo = crypto_open();
- if (!wipeCryptoInfo)
- {
- DecoySystemWipeResult = STATUS_INSUFFICIENT_RESOURCES;
- goto ret;
- }
-
- wipeCryptoInfo->ea = ea;
- wipeCryptoInfo->mode = Extension->Queue.CryptoInfo->mode;
-
- if (EAInit (ea, WipeDecoyRequest.WipeKey, wipeCryptoInfo->ks) != ERR_SUCCESS)
- {
- DecoySystemWipeResult = STATUS_INVALID_PARAMETER;
- goto ret;
- }
-
- memcpy (wipeCryptoInfo->k2, WipeDecoyRequest.WipeKey + EAGetKeySize (ea), EAGetKeySize (ea));
-
- if (!EAInitMode (wipeCryptoInfo))
- {
- DecoySystemWipeResult = STATUS_INVALID_PARAMETER;
- goto err;
- }
-
- EncryptDataUnits (wipeRandBuffer, &dataUnit, wipeBlockSize / ENCRYPTION_DATA_UNIT_SIZE, wipeCryptoInfo);
- memcpy (wipeRandChars, wipeRandBuffer, sizeof (wipeRandChars));
-
- burn (WipeDecoyRequest.WipeKey, sizeof (WipeDecoyRequest.WipeKey));
-
- offset.QuadPart = Extension->ConfiguredEncryptedAreaStart;
-
- Dump ("Wiping decoy system: start offset = %I64d\n", offset.QuadPart);
-
- while (!DecoySystemWipeThreadAbortRequested)
- {
- if (offset.QuadPart + wipeBlockSize > Extension->ConfiguredEncryptedAreaEnd + 1)
- wipeBlockSize = (ULONG) (Extension->ConfiguredEncryptedAreaEnd + 1 - offset.QuadPart);
-
- if (offset.QuadPart > Extension->ConfiguredEncryptedAreaEnd)
- break;
-
- wipePassCount = GetWipePassCount (WipeDecoyRequest.WipeAlgorithm);
- if (wipePassCount <= 0)
- {
- DecoySystemWipeResult = STATUS_INVALID_PARAMETER;
- goto err;
- }
-
- for (wipePass = 1; wipePass <= wipePassCount; ++wipePass)
- {
- if (!WipeBuffer (WipeDecoyRequest.WipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, wipeBlockSize))
- {
- dataUnit.Value = offset.QuadPart / ENCRYPTION_DATA_UNIT_SIZE;
- EncryptDataUnits (wipeRandBuffer, &dataUnit, wipeBlockSize / ENCRYPTION_DATA_UNIT_SIZE, wipeCryptoInfo);
- memcpy (wipeBuffer, wipeRandBuffer, wipeBlockSize);
- }
-
- while (!NT_SUCCESS (EncryptedIoQueueHoldWhenIdle (&Extension->Queue, 500)))
- {
- if (DecoySystemWipeThreadAbortRequested)
- goto abort;
- }
-
- status = TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, wipeBuffer, offset, wipeBlockSize);
-
- if (!NT_SUCCESS (status))
- {
- DecoySystemWipeResult = status;
- goto err;
- }
-
- EncryptedIoQueueResumeFromHold (&Extension->Queue);
- }
-
- offset.QuadPart += wipeBlockSize;
-
- KeAcquireSpinLock (&DecoySystemWipeStatusSpinLock, &irql);
- DecoySystemWipedAreaEnd = offset.QuadPart - 1;
- KeReleaseSpinLock (&DecoySystemWipeStatusSpinLock, irql);
- }
-
-abort:
- DecoySystemWipeResult = STATUS_SUCCESS;
-err:
-
- if (EncryptedIoQueueIsSuspended (&Extension->Queue))
- EncryptedIoQueueResumeFromHold (&Extension->Queue);
-
- Dump ("Wipe end: DecoySystemWipedAreaEnd=%I64d (%I64d)\n", DecoySystemWipedAreaEnd, DecoySystemWipedAreaEnd / 1024 / 1024);
-
-ret:
- if (wipeCryptoInfo)
- crypto_close (wipeCryptoInfo);
-
- if (wipeRandBuffer)
- TCfree (wipeRandBuffer);
-
- if (wipeBuffer)
- TCfree (wipeBuffer);
-
- DecoySystemWipeInProgress = FALSE;
- PsTerminateSystemThread (DecoySystemWipeResult);
-}
-
-
-NTSTATUS StartDecoySystemWipe (PDEVICE_OBJECT DeviceObject, PIRP irp, PIO_STACK_LOCATION irpSp)
-{
- NTSTATUS status;
- WipeDecoySystemRequest *request;
-
- if (!UserCanAccessDriveDevice())
- return STATUS_ACCESS_DENIED;
-
- if (!IsHiddenSystemRunning()
- || irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (WipeDecoySystemRequest))
- return STATUS_INVALID_PARAMETER;
-
- if (DecoySystemWipeInProgress)
- return STATUS_SUCCESS;
-
- if (DecoySystemWipeThread)
- AbortDecoySystemWipe();
-
- request = (WipeDecoySystemRequest *) irp->AssociatedIrp.SystemBuffer;
- WipeDecoyRequest = *request;
-
- burn (request->WipeKey, sizeof (request->WipeKey));
-
- DecoySystemWipeThreadAbortRequested = FALSE;
- KeInitializeSpinLock (&DecoySystemWipeStatusSpinLock);
- DecoySystemWipedAreaEnd = BootDriveFilterExtension->ConfiguredEncryptedAreaStart;
-
- DecoySystemWipeInProgress = TRUE;
- status = TCStartThread (DecoySystemWipeThreadProc, DeviceObject, &DecoySystemWipeThread);
-
- if (!NT_SUCCESS (status))
- DecoySystemWipeInProgress = FALSE;
-
- return status;
-}
-
-
-BOOL IsDecoySystemWipeInProgress()
-{
- return DecoySystemWipeInProgress;
-}
-
-
-void GetDecoySystemWipeStatus (PIRP irp, PIO_STACK_LOCATION irpSp)
-{
- if (ValidateIOBufferSize (irp, sizeof (DecoySystemWipeStatus), ValidateOutput))
- {
- DecoySystemWipeStatus *wipeStatus = (DecoySystemWipeStatus *) irp->AssociatedIrp.SystemBuffer;
-
- if (!IsHiddenSystemRunning())
- {
- irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- irp->IoStatus.Information = 0;
- }
- else
- {
- wipeStatus->WipeInProgress = DecoySystemWipeInProgress;
- wipeStatus->WipeAlgorithm = WipeDecoyRequest.WipeAlgorithm;
-
- if (DecoySystemWipeInProgress)
- {
- KIRQL irql;
- KeAcquireSpinLock (&DecoySystemWipeStatusSpinLock, &irql);
- wipeStatus->WipedAreaEnd = DecoySystemWipedAreaEnd;
- KeReleaseSpinLock (&DecoySystemWipeStatusSpinLock, irql);
- }
- else
- wipeStatus->WipedAreaEnd = DecoySystemWipedAreaEnd;
-
- irp->IoStatus.Information = sizeof (DecoySystemWipeStatus);
- irp->IoStatus.Status = STATUS_SUCCESS;
- }
- }
-}
-
-
-NTSTATUS GetDecoySystemWipeResult()
-{
- return DecoySystemWipeResult;
-}
-
-
-NTSTATUS AbortDecoySystemWipe ()
-{
- if (!IoIsSystemThread (PsGetCurrentThread()) && !UserCanAccessDriveDevice())
- return STATUS_ACCESS_DENIED;
-
- if (DecoySystemWipeThread)
- {
- DecoySystemWipeThreadAbortRequested = TRUE;
-
- TCStopThread (DecoySystemWipeThread, NULL);
- DecoySystemWipeThread = NULL;
- }
-
- return STATUS_SUCCESS;
-}
-
-
-uint64 GetBootDriveLength ()
-{
- return BootDriveLength.QuadPart;
-}
-
-
-NTSTATUS WriteBootDriveSector (PIRP irp, PIO_STACK_LOCATION irpSp)
-{
- WriteBootDriveSectorRequest *request;
-
- if (!UserCanAccessDriveDevice())
- return STATUS_ACCESS_DENIED;
-
- if (!BootDriveFilterExtension
- || irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (WriteBootDriveSectorRequest))
- return STATUS_INVALID_PARAMETER;
-
- request = (WriteBootDriveSectorRequest *) irp->AssociatedIrp.SystemBuffer;
- return TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, request->Data, request->Offset, sizeof (request->Data));
-}
+/*
+ Derived from source code of TrueCrypt 7.1a, which is
+ Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
+ by the TrueCrypt License 3.0.
+
+ Modifications and additions to the original source code (contained in this file)
+ and all other portions of this file are Copyright (c) 2013-2016 IDRIX
+ and are governed by the Apache License 2.0 the full text of which is
+ contained in the file License.txt included in VeraCrypt binary and source
+ code distribution packages.
+*/
+
+#include "TCdefs.h"
+#include <ntddk.h>
+#include <ntddvol.h>
+#include <Ntstrsafe.h>
+#include "Cache.h"
+#include "Crc.h"
+#include "Crypto.h"
+#include "Apidrvr.h"
+#include "EncryptedIoQueue.h"
+#include "Common/Endian.h"
+#include "Ntdriver.h"
+#include "Ntvol.h"
+#include "Volumes.h"
+#include "VolumeFilter.h"
+#include "Wipe.h"
+#include "DriveFilter.h"
+#include "Boot/Windows/BootCommon.h"
+
+static BOOL DeviceFilterActive = FALSE;
+
+BOOL BootArgsValid = FALSE;
+BootArguments BootArgs;
+static uint16 BootLoaderSegment;
+static BOOL BootDriveSignatureValid = FALSE;
+
+static KMUTEX MountMutex;
+
+static volatile BOOL BootDriveFound = FALSE;
+static DriveFilterExtension *BootDriveFilterExtension = NULL;
+static LARGE_INTEGER BootDriveLength;
+static byte BootLoaderFingerprint[WHIRLPOOL_DIGESTSIZE + SHA512_DIGESTSIZE];
+
+static BOOL CrashDumpEnabled = FALSE;
+static BOOL HibernationEnabled = FALSE;
+
+static BOOL LegacyHibernationDriverFilterActive = FALSE;
+static byte *HibernationWriteBuffer = NULL;
+static MDL *HibernationWriteBufferMdl = NULL;
+
+static uint32 HibernationPreventionCount = 0;
+
+static BootEncryptionSetupRequest SetupRequest;
+static volatile BOOL SetupInProgress = FALSE;
+PKTHREAD EncryptionSetupThread = NULL;
+static volatile BOOL EncryptionSetupThreadAbortRequested;
+static KSPIN_LOCK SetupStatusSpinLock;
+static int64 SetupStatusEncryptedAreaEnd;
+static BOOL TransformWaitingForIdle;
+static NTSTATUS SetupResult;
+
+static WipeDecoySystemRequest WipeDecoyRequest;
+static volatile BOOL DecoySystemWipeInProgress = FALSE;
+static volatile BOOL DecoySystemWipeThreadAbortRequested;
+static KSPIN_LOCK DecoySystemWipeStatusSpinLock;
+static int64 DecoySystemWipedAreaEnd;
+PKTHREAD DecoySystemWipeThread = NULL;
+static NTSTATUS DecoySystemWipeResult;
+
+
+NTSTATUS LoadBootArguments ()
+{
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+ PHYSICAL_ADDRESS bootArgsAddr;
+ byte *mappedBootArgs;
+ uint16 bootLoaderSegment;
+
+ KeInitializeMutex (&MountMutex, 0);
+
+ for (bootLoaderSegment = TC_BOOT_LOADER_SEGMENT;
+ bootLoaderSegment >= TC_BOOT_LOADER_SEGMENT - 64 * 1024 / 16 && status != STATUS_SUCCESS;
+ bootLoaderSegment -= 32 * 1024 / 16)
+ {
+ bootArgsAddr.QuadPart = (bootLoaderSegment << 4) + TC_BOOT_LOADER_ARGS_OFFSET;
+ Dump ("Checking BootArguments at 0x%x\n", bootArgsAddr.LowPart);
+
+ mappedBootArgs = MmMapIoSpace (bootArgsAddr, sizeof (BootArguments), MmCached);
+ if (!mappedBootArgs)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ if (TC_IS_BOOT_ARGUMENTS_SIGNATURE (mappedBootArgs))
+ {
+ BootArguments *bootArguments = (BootArguments *) mappedBootArgs;
+ Dump ("BootArguments found at 0x%x\n", bootArgsAddr.LowPart);
+
+ DumpMem (mappedBootArgs, sizeof (BootArguments));
+
+ if (bootArguments->BootLoaderVersion == VERSION_NUM
+ && bootArguments->BootArgumentsCrc32 != GetCrc32 ((byte *) bootArguments, (int) ((byte *) &bootArguments->BootArgumentsCrc32 - (byte *) bootArguments)))
+ {
+ Dump ("BootArguments CRC incorrect\n");
+ TC_BUG_CHECK (STATUS_CRC_ERROR);
+ }
+
+ // Sanity check: for valid boot argument, the password is less than 64 bytes long
+ if (bootArguments->BootPassword.Length <= MAX_PASSWORD)
+ {
+ BootLoaderSegment = bootLoaderSegment;
+
+ BootArgs = *bootArguments;
+ BootArgsValid = TRUE;
+ burn (bootArguments, sizeof (*bootArguments));
+
+ BootDriveSignatureValid = TRUE;
+
+ Dump ("BootLoaderVersion = %x\n", (int) BootArgs.BootLoaderVersion);
+ Dump ("HeaderSaltCrc32 = %x\n", (int) BootArgs.HeaderSaltCrc32);
+ Dump ("CryptoInfoOffset = %x\n", (int) BootArgs.CryptoInfoOffset);
+ Dump ("CryptoInfoLength = %d\n", (int) BootArgs.CryptoInfoLength);
+ Dump ("HiddenSystemPartitionStart = %I64u\n", BootArgs.HiddenSystemPartitionStart);
+ Dump ("DecoySystemPartitionStart = %I64u\n", BootArgs.DecoySystemPartitionStart);
+ Dump ("Flags = %x\n", BootArgs.Flags);
+ Dump ("BootDriveSignature = %x\n", BootArgs.BootDriveSignature);
+ Dump ("BootArgumentsCrc32 = %x\n", BootArgs.BootArgumentsCrc32);
+
+ if (CacheBootPassword && BootArgs.BootPassword.Length > 0)
+ {
+ int pim = CacheBootPim? (int) (BootArgs.Flags >> 16) : 0;
+ AddPasswordToCache (&BootArgs.BootPassword, pim);
+ }
+
+ // clear fingerprint
+ burn (BootLoaderFingerprint, sizeof (BootLoaderFingerprint));
+
+ status = STATUS_SUCCESS;
+ }
+ }
+
+ MmUnmapIoSpace (mappedBootArgs, sizeof (BootArguments));
+ }
+
+ return status;
+}
+
+
+NTSTATUS DriveFilterAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo)
+{
+ DriveFilterExtension *Extension;
+ NTSTATUS status;
+ PDEVICE_OBJECT filterDeviceObject = NULL;
+ PDEVICE_OBJECT attachedDeviceObject;
+
+ Dump ("DriveFilterAddDevice pdo=%p\n", pdo);
+
+ attachedDeviceObject = IoGetAttachedDeviceReference (pdo);
+ status = IoCreateDevice (driverObject, sizeof (DriveFilterExtension), NULL, attachedDeviceObject->DeviceType, 0, FALSE, &filterDeviceObject);
+
+ ObDereferenceObject (attachedDeviceObject);
+
+ if (!NT_SUCCESS (status))
+ {
+ filterDeviceObject = NULL;
+ goto err;
+ }
+
+ Extension = (DriveFilterExtension *) filterDeviceObject->DeviceExtension;
+ memset (Extension, 0, sizeof (DriveFilterExtension));
+
+ status = IoAttachDeviceToDeviceStackSafe (filterDeviceObject, pdo, &(Extension->LowerDeviceObject));
+ if (!NT_SUCCESS (status))
+ {
+ goto err;
+ }
+
+ if (!Extension->LowerDeviceObject)
+ {
+ status = STATUS_DEVICE_REMOVED;
+ goto err;
+ }
+
+ Extension->IsDriveFilterDevice = Extension->Queue.IsFilterDevice = TRUE;
+ Extension->DeviceObject = Extension->Queue.DeviceObject = filterDeviceObject;
+ Extension->Pdo = pdo;
+
+ Extension->Queue.LowerDeviceObject = Extension->LowerDeviceObject;
+ IoInitializeRemoveLock (&Extension->Queue.RemoveLock, 'LRCV', 0, 0);
+
+ Extension->ConfiguredEncryptedAreaStart = -1;
+ Extension->ConfiguredEncryptedAreaEnd = -1;
+ Extension->Queue.EncryptedAreaStart = -1;
+ Extension->Queue.EncryptedAreaEnd = -1;
+ Extension->Queue.EncryptedAreaEndUpdatePending = FALSE;
+
+ filterDeviceObject->Flags |= Extension->LowerDeviceObject->Flags & (DO_DIRECT_IO | DO_BUFFERED_IO | DO_POWER_PAGABLE);
+ filterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ DeviceFilterActive = TRUE;
+ return status;
+
+err:
+ if (filterDeviceObject)
+ {
+ if (Extension->LowerDeviceObject)
+ IoDetachDevice (Extension->LowerDeviceObject);
+
+ IoDeleteDevice (filterDeviceObject);
+ }
+
+ return status;
+}
+
+
+static void DismountDrive (DriveFilterExtension *Extension, BOOL stopIoQueue)
+{
+ Dump ("Dismounting drive\n");
+ ASSERT (Extension->DriveMounted);
+
+ if (stopIoQueue && EncryptedIoQueueIsRunning (&Extension->Queue))
+ EncryptedIoQueueStop (&Extension->Queue);
+
+ crypto_close (Extension->Queue.CryptoInfo);
+ Extension->Queue.CryptoInfo = NULL;
+
+ crypto_close (Extension->HeaderCryptoInfo);
+ Extension->HeaderCryptoInfo = NULL;
+
+ Extension->DriveMounted = FALSE;
+}
+
+static void ComputeBootLoaderFingerprint(PDEVICE_OBJECT LowerDeviceObject, byte* ioBuffer /* ioBuffer must be at least 512 bytes long */)
+{
+ NTSTATUS status;
+ LARGE_INTEGER offset;
+ WHIRLPOOL_CTX whirlpool;
+ sha512_ctx sha2;
+ ULONG bytesToRead, remainingBytes, bootloaderTotalSize = TC_BOOT_LOADER_AREA_SIZE - TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE;
+
+ // clear fingerprint
+ burn (BootLoaderFingerprint, sizeof (BootLoaderFingerprint));
+
+ // compute Whirlpool+SHA512 fingerprint of bootloader including MBR
+ // we skip user configuration fields:
+ // TC_BOOT_SECTOR_PIM_VALUE_OFFSET = 400
+ // TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET = 402
+ // => TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE = 4
+ // TC_BOOT_SECTOR_USER_MESSAGE_OFFSET = 406
+ // => TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH = 24
+ // TC_BOOT_SECTOR_USER_CONFIG_OFFSET = 438
+ //
+ // we have: TC_BOOT_SECTOR_USER_MESSAGE_OFFSET = TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE
+
+ WHIRLPOOL_init (&whirlpool);
+ sha512_begin (&sha2);
+ // read the first 512 bytes
+ offset.QuadPart = 0;
+
+ status = TCReadDevice (LowerDeviceObject, ioBuffer, offset, TC_SECTOR_SIZE_BIOS);
+ if (NT_SUCCESS (status))
+ {
+ WHIRLPOOL_add (ioBuffer, TC_BOOT_SECTOR_PIM_VALUE_OFFSET * 8, &whirlpool);
+ WHIRLPOOL_add (ioBuffer + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH, (TC_BOOT_SECTOR_USER_CONFIG_OFFSET - (TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)) * 8, &whirlpool);
+ WHIRLPOOL_add (ioBuffer + TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1, (TC_MAX_MBR_BOOT_CODE_SIZE - (TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1)) * 8, &whirlpool);
+
+ sha512_hash (ioBuffer, TC_BOOT_SECTOR_PIM_VALUE_OFFSET, &sha2);
+ sha512_hash (ioBuffer + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH, (TC_BOOT_SECTOR_USER_CONFIG_OFFSET - (TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)), &sha2);
+ sha512_hash (ioBuffer + TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1, (TC_MAX_MBR_BOOT_CODE_SIZE - (TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1)), &sha2);
+
+ // we has the reste of the bootloader, 512 bytes at a time
+ offset.QuadPart = TC_SECTOR_SIZE_BIOS;
+ remainingBytes = bootloaderTotalSize - TC_SECTOR_SIZE_BIOS;
+
+ while (NT_SUCCESS (status) && (remainingBytes > 0))
+ {
+ bytesToRead = (remainingBytes >= TC_SECTOR_SIZE_BIOS)? TC_SECTOR_SIZE_BIOS : remainingBytes;
+ status = TCReadDevice (LowerDeviceObject, ioBuffer, offset, bytesToRead);
+ if (NT_SUCCESS (status))
+ {
+ remainingBytes -= bytesToRead;
+ offset.QuadPart += bytesToRead;
+ WHIRLPOOL_add (ioBuffer, bytesToRead * 8, &whirlpool);
+ sha512_hash (ioBuffer, bytesToRead, &sha2);
+ }
+ else
+ {
+ Dump ("TCReadDevice error %x during ComputeBootLoaderFingerprint call\n", status);
+ break;
+ }
+ }
+
+ if (NT_SUCCESS (status))
+ {
+ WHIRLPOOL_finalize (&whirlpool, BootLoaderFingerprint);
+ sha512_end (&BootLoaderFingerprint [WHIRLPOOL_DIGESTSIZE], &sha2);
+ }
+ }
+ else
+ {
+ Dump ("TCReadDevice error %x during ComputeBootLoaderFingerprint call\n", status);
+ }
+}
+
+
+static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password, uint32 *headerSaltCrc32)
+{
+ BOOL hiddenVolume = (BootArgs.HiddenSystemPartitionStart != 0);
+ int64 hiddenHeaderOffset = BootArgs.HiddenSystemPartitionStart + TC_HIDDEN_VOLUME_HEADER_OFFSET;
+ NTSTATUS status;
+ LARGE_INTEGER offset;
+ char *header;
+ int pkcs5_prf = 0, pim = 0;
+ byte *mappedCryptoInfo = NULL;
+
+ Dump ("MountDrive pdo=%p\n", Extension->Pdo);
+ ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ // Check boot drive signature first (header CRC search could fail if a user restored the header to a non-boot drive)
+ if (BootDriveSignatureValid)
+ {
+ byte mbr[TC_SECTOR_SIZE_BIOS];
+
+ offset.QuadPart = 0;
+ status = TCReadDevice (Extension->LowerDeviceObject, mbr, offset, TC_SECTOR_SIZE_BIOS);
+
+ if (NT_SUCCESS (status) && BootArgs.BootDriveSignature != *(uint32 *) (mbr + 0x1b8))
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ header = TCalloc (TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
+ if (!header)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ offset.QuadPart = hiddenVolume ? hiddenHeaderOffset : TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
+ Dump ("Reading volume header at %I64u\n", offset.QuadPart);
+
+ status = TCReadDevice (Extension->LowerDeviceObject, header, offset, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
+ if (!NT_SUCCESS (status))
+ {
+ Dump ("TCReadDevice error %x\n", status);
+ goto ret;
+ }
+
+ if (headerSaltCrc32)
+ {
+ uint32 saltCrc = GetCrc32 (header, PKCS5_SALT_SIZE);
+
+ if (saltCrc != *headerSaltCrc32)
+ {
+ status = STATUS_UNSUCCESSFUL;
+ goto ret;
+ }
+
+ Extension->VolumeHeaderSaltCrc32 = saltCrc;
+ }
+
+ Extension->HeaderCryptoInfo = crypto_open();
+ if (!Extension->HeaderCryptoInfo)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ret;
+ }
+
+ if (BootArgs.CryptoInfoLength > 0)
+ {
+ PHYSICAL_ADDRESS cryptoInfoAddress;
+
+ cryptoInfoAddress.QuadPart = (BootLoaderSegment << 4) + BootArgs.CryptoInfoOffset;
+#ifdef DEBUG
+ Dump ("Wiping memory %x %d\n", cryptoInfoAddress.LowPart, BootArgs.CryptoInfoLength);
+#endif
+ mappedCryptoInfo = MmMapIoSpace (cryptoInfoAddress, BootArgs.CryptoInfoLength, MmCached);
+ if (mappedCryptoInfo)
+ {
+ /* Get the parameters used for booting to speed up driver startup and avoid testing irrelevant PRFs */
+ BOOT_CRYPTO_HEADER* pBootCryptoInfo = (BOOT_CRYPTO_HEADER*) mappedCryptoInfo;
+ Hash* pHash = HashGet(pBootCryptoInfo->pkcs5);
+ if (pHash && pHash->SystemEncryption)
+ pkcs5_prf = pBootCryptoInfo->pkcs5;
+ }
+ }
+
+ pim = (int) (BootArgs.Flags >> 16);
+
+ if (ReadVolumeHeader (!hiddenVolume, header, password, pkcs5_prf, pim, FALSE, &Extension->Queue.CryptoInfo, Extension->HeaderCryptoInfo) == 0)
+ {
+ // Header decrypted
+ status = STATUS_SUCCESS;
+ Dump ("Header decrypted\n");
+
+ // calculate Fingerprint
+ ComputeBootLoaderFingerprint (Extension->LowerDeviceObject, header);
+
+ if (Extension->Queue.CryptoInfo->hiddenVolume)
+ {
+ int64 hiddenPartitionOffset = BootArgs.HiddenSystemPartitionStart;
+ Dump ("Hidden volume start offset = %I64d\n", Extension->Queue.CryptoInfo->EncryptedAreaStart.Value + hiddenPartitionOffset);
+
+ Extension->HiddenSystem = TRUE;
+
+ Extension->Queue.RemapEncryptedArea = TRUE;
+ Extension->Queue.RemappedAreaOffset = hiddenPartitionOffset + Extension->Queue.CryptoInfo->EncryptedAreaStart.Value - BootArgs.DecoySystemPartitionStart;
+ Extension->Queue.RemappedAreaDataUnitOffset = Extension->Queue.CryptoInfo->EncryptedAreaStart.Value / ENCRYPTION_DATA_UNIT_SIZE - BootArgs.DecoySystemPartitionStart / ENCRYPTION_DATA_UNIT_SIZE;
+
+ Extension->Queue.CryptoInfo->EncryptedAreaStart.Value = BootArgs.DecoySystemPartitionStart;
+
+ if (Extension->Queue.CryptoInfo->VolumeSize.Value > hiddenPartitionOffset - BootArgs.DecoySystemPartitionStart)
+ TC_THROW_FATAL_EXCEPTION;
+
+ Dump ("RemappedAreaOffset = %I64d\n", Extension->Queue.RemappedAreaOffset);
+ Dump ("RemappedAreaDataUnitOffset = %I64d\n", Extension->Queue.RemappedAreaDataUnitOffset);
+ }
+ else
+ {
+ Extension->HiddenSystem = FALSE;
+ Extension->Queue.RemapEncryptedArea = FALSE;
+ }
+
+ Extension->ConfiguredEncryptedAreaStart = Extension->Queue.CryptoInfo->EncryptedAreaStart.Value;
+ Extension->ConfiguredEncryptedAreaEnd = Extension->Queue.CryptoInfo->EncryptedAreaStart.Value + Extension->Queue.CryptoInfo->VolumeSize.Value - 1;
+
+ Extension->Queue.EncryptedAreaStart = Extension->Queue.CryptoInfo->EncryptedAreaStart.Value;
+ Extension->Queue.EncryptedAreaEnd = Extension->Queue.CryptoInfo->EncryptedAreaStart.Value + Extension->Queue.CryptoInfo->EncryptedAreaLength.Value - 1;
+
+ if (Extension->Queue.CryptoInfo->EncryptedAreaLength.Value == 0)
+ {
+ Extension->Queue.EncryptedAreaStart = -1;
+ Extension->Queue.EncryptedAreaEnd = -1;
+ }
+
+ Dump ("Loaded: ConfiguredEncryptedAreaStart=%I64d (%I64d) ConfiguredEncryptedAreaEnd=%I64d (%I64d)\n", Extension->ConfiguredEncryptedAreaStart / 1024 / 1024, Extension->ConfiguredEncryptedAreaStart, Extension->ConfiguredEncryptedAreaEnd / 1024 / 1024, Extension->ConfiguredEncryptedAreaEnd);
+ Dump ("Loaded: EncryptedAreaStart=%I64d (%I64d) EncryptedAreaEnd=%I64d (%I64d)\n", Extension->Queue.EncryptedAreaStart / 1024 / 1024, Extension->Queue.EncryptedAreaStart, Extension->Queue.EncryptedAreaEnd / 1024 / 1024, Extension->Queue.EncryptedAreaEnd);
+
+ // Erase boot loader scheduled keys
+ if (mappedCryptoInfo)
+ {
+ burn (mappedCryptoInfo, BootArgs.CryptoInfoLength);
+ MmUnmapIoSpace (mappedCryptoInfo, BootArgs.CryptoInfoLength);
+ BootArgs.CryptoInfoLength = 0;
+ }
+
+ BootDriveFilterExtension = Extension;
+ BootDriveFound = Extension->BootDrive = Extension->DriveMounted = Extension->VolumeHeaderPresent = TRUE;
+ BootDriveFilterExtension->MagicNumber = TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER;
+
+ burn (&BootArgs.BootPassword, sizeof (BootArgs.BootPassword));
+
+ {
+ STORAGE_DEVICE_NUMBER storageDeviceNumber;
+ status = SendDeviceIoControlRequest (Extension->LowerDeviceObject, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &storageDeviceNumber, sizeof (storageDeviceNumber));
+
+ if (!NT_SUCCESS (status))
+ {
+ Dump ("Failed to get drive number - error %x\n", status);
+ Extension->SystemStorageDeviceNumberValid = FALSE;
+ }
+ else
+ {
+ Extension->SystemStorageDeviceNumber = storageDeviceNumber.DeviceNumber;
+ Extension->SystemStorageDeviceNumberValid = TRUE;
+ }
+ }
+
+ status = SendDeviceIoControlRequest (Extension->LowerDeviceObject, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &BootDriveLength, sizeof (BootDriveLength));
+
+ if (!NT_SUCCESS (status))
+ {
+ Dump ("Failed to get drive length - error %x\n", status);
+ BootDriveLength.QuadPart = 0;
+ Extension->Queue.MaxReadAheadOffset.QuadPart = 0;
+ }
+ else
+ Extension->Queue.MaxReadAheadOffset = BootDriveLength;
+
+ status = EncryptedIoQueueStart (&Extension->Queue);
+ if (!NT_SUCCESS (status))
+ TC_BUG_CHECK (status);
+
+ if (IsOSAtLeast (WIN_VISTA))
+ {
+ CrashDumpEnabled = TRUE;
+ HibernationEnabled = TRUE;
+ }
+ else if (!LegacyHibernationDriverFilterActive)
+ StartLegacyHibernationDriverFilter();
+
+ // 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))
+ {
+ CrashDumpEnabled = FALSE;
+ HibernationEnabled = FALSE;
+ }
+ }
+ else
+ {
+ Dump ("Header not decrypted\n");
+ crypto_close (Extension->HeaderCryptoInfo);
+ Extension->HeaderCryptoInfo = NULL;
+
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ret:
+ TCfree (header);
+ return status;
+}
+
+
+static NTSTATUS SaveDriveVolumeHeader (DriveFilterExtension *Extension)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ LARGE_INTEGER offset;
+ byte *header;
+
+ 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))
+ {
+ Dump ("TCReadDevice error %x", status);
+ goto ret;
+ }
+
+ Dump ("Saving: ConfiguredEncryptedAreaStart=%I64d (%I64d) ConfiguredEncryptedAreaEnd=%I64d (%I64d)\n", Extension->ConfiguredEncryptedAreaStart / 1024 / 1024, Extension->ConfiguredEncryptedAreaStart, Extension->ConfiguredEncryptedAreaEnd / 1024 / 1024, Extension->ConfiguredEncryptedAreaEnd);
+ Dump ("Saving: EncryptedAreaStart=%I64d (%I64d) EncryptedAreaEnd=%I64d (%I64d)\n", Extension->Queue.EncryptedAreaStart / 1024 / 1024, Extension->Queue.EncryptedAreaStart, Extension->Queue.EncryptedAreaEnd / 1024 / 1024, Extension->Queue.EncryptedAreaEnd);
+
+ if (Extension->Queue.EncryptedAreaStart == -1 || Extension->Queue.EncryptedAreaEnd == -1
+ || Extension->Queue.EncryptedAreaEnd <= Extension->Queue.EncryptedAreaStart)
+ {
+ if (SetupRequest.SetupMode == SetupDecryption)
+ {
+ memset (header, 0, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
+ Extension->VolumeHeaderPresent = FALSE;
+ }
+ }
+ else
+ {
+ uint32 headerCrc32;
+ uint64 encryptedAreaLength = Extension->Queue.EncryptedAreaEnd + 1 - Extension->Queue.EncryptedAreaStart;
+ byte *fieldPos = header + TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH;
+
+ DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, Extension->HeaderCryptoInfo);
+
+ if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x56455241)
+ {
+ Dump ("Header not decrypted");
+ status = STATUS_UNKNOWN_REVISION;
+ goto ret;
+ }
+
+ mputInt64 (fieldPos, encryptedAreaLength);
+
+ headerCrc32 = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
+ fieldPos = header + TC_HEADER_OFFSET_HEADER_CRC;
+ mputLong (fieldPos, headerCrc32);
+
+ EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, Extension->HeaderCryptoInfo);
+ }
+
+ status = TCWriteDevice (Extension->LowerDeviceObject, header, offset, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
+ if (!NT_SUCCESS (status))
+ {
+ Dump ("TCWriteDevice error %x", status);
+ goto ret;
+ }
+
+ret:
+ TCfree (header);
+ return status;
+}
+
+
+static NTSTATUS PassIrp (PDEVICE_OBJECT deviceObject, PIRP irp)
+{
+ IoSkipCurrentIrpStackLocation (irp);
+ return IoCallDriver (deviceObject, irp);
+}
+
+
+static NTSTATUS PassFilteredIrp (PDEVICE_OBJECT deviceObject, PIRP irp, PIO_COMPLETION_ROUTINE completionRoutine, PVOID completionRoutineArg)
+{
+ IoCopyCurrentIrpStackLocationToNext (irp);
+
+ if (completionRoutine)
+ IoSetCompletionRoutine (irp, completionRoutine, completionRoutineArg, TRUE, TRUE, TRUE);
+
+ return IoCallDriver (deviceObject, irp);
+}
+
+
+static NTSTATUS OnDeviceUsageNotificationCompleted (PDEVICE_OBJECT filterDeviceObject, PIRP Irp, DriveFilterExtension *Extension)
+{
+ if (Irp->PendingReturned)
+ IoMarkIrpPending (Irp);
+
+ if (!(Extension->LowerDeviceObject->Flags & DO_POWER_PAGABLE))
+ filterDeviceObject->Flags &= ~DO_POWER_PAGABLE;
+
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ return STATUS_CONTINUE_COMPLETION;
+}
+
+
+static BOOL IsVolumeDevice (PDEVICE_OBJECT deviceObject)
+{
+ VOLUME_NUMBER volNumber;
+ VOLUME_DISK_EXTENTS extents[2];
+ NTSTATUS extentStatus = SendDeviceIoControlRequest (deviceObject, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, extents, sizeof (extents));
+
+ return NT_SUCCESS (SendDeviceIoControlRequest (deviceObject, IOCTL_VOLUME_SUPPORTS_ONLINE_OFFLINE, NULL, 0, NULL, 0))
+ || NT_SUCCESS (SendDeviceIoControlRequest (deviceObject, IOCTL_VOLUME_IS_OFFLINE, NULL, 0, NULL, 0))
+ || NT_SUCCESS (SendDeviceIoControlRequest (deviceObject, IOCTL_VOLUME_IS_IO_CAPABLE, NULL, 0, NULL, 0))
+ || NT_SUCCESS (SendDeviceIoControlRequest (deviceObject, IOCTL_VOLUME_IS_PARTITION, NULL, 0, NULL, 0))
+ || NT_SUCCESS (SendDeviceIoControlRequest (deviceObject, IOCTL_VOLUME_QUERY_VOLUME_NUMBER, NULL, 0, &volNumber, sizeof (volNumber)))
+ || NT_SUCCESS (extentStatus) || extentStatus == STATUS_BUFFER_OVERFLOW || extentStatus == STATUS_BUFFER_TOO_SMALL;
+}
+
+
+static void CheckDeviceTypeAndMount (DriveFilterExtension *filterExtension)
+{
+ if (BootArgsValid)
+ {
+ // Windows sometimes merges a removable drive PDO and its volume PDO to a single PDO having no volume interface (GUID_DEVINTERFACE_VOLUME).
+ // Therefore, we need to test whether the device supports volume IOCTLs.
+ if (VolumeClassFilterRegistered
+ && BootArgs.HiddenSystemPartitionStart != 0
+ && IsVolumeDevice (filterExtension->LowerDeviceObject))
+ {
+ Dump ("Drive and volume merged pdo=%p", filterExtension->Pdo);
+
+ filterExtension->IsVolumeFilterDevice = TRUE;
+ filterExtension->IsDriveFilterDevice = FALSE;
+ }
+ else
+ {
+ NTSTATUS status = KeWaitForMutexObject (&MountMutex, Executive, KernelMode, FALSE, NULL);
+ if (!NT_SUCCESS (status))
+ TC_BUG_CHECK (status);
+
+ if (!BootDriveFound)
+ MountDrive (filterExtension, &BootArgs.BootPassword, &BootArgs.HeaderSaltCrc32);
+
+ KeReleaseMutex (&MountMutex, FALSE);
+ }
+ }
+}
+
+
+static VOID MountDriveWorkItemRoutine (PDEVICE_OBJECT deviceObject, DriveFilterExtension *filterExtension)
+{
+ CheckDeviceTypeAndMount (filterExtension);
+ KeSetEvent (&filterExtension->MountWorkItemCompletedEvent, IO_NO_INCREMENT, FALSE);
+}
+
+
+static NTSTATUS OnStartDeviceCompleted (PDEVICE_OBJECT filterDeviceObject, PIRP Irp, DriveFilterExtension *Extension)
+{
+ if (Irp->PendingReturned)
+ IoMarkIrpPending (Irp);
+
+ if (Extension->LowerDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
+ filterDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
+
+ if (KeGetCurrentIrql() == PASSIVE_LEVEL)
+ {
+ CheckDeviceTypeAndMount (Extension);
+ }
+ else
+ {
+ PIO_WORKITEM workItem = IoAllocateWorkItem (filterDeviceObject);
+ if (!workItem)
+ {
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ KeInitializeEvent (&Extension->MountWorkItemCompletedEvent, SynchronizationEvent, FALSE);
+ IoQueueWorkItem (workItem, MountDriveWorkItemRoutine, DelayedWorkQueue, Extension);
+
+ KeWaitForSingleObject (&Extension->MountWorkItemCompletedEvent, Executive, KernelMode, FALSE, NULL);
+ IoFreeWorkItem (workItem);
+ }
+
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ return STATUS_CONTINUE_COMPLETION;
+}
+
+
+static NTSTATUS DispatchPnp (PDEVICE_OBJECT DeviceObject, PIRP Irp, DriveFilterExtension *Extension, PIO_STACK_LOCATION irpSp)
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ if (!NT_SUCCESS (status))
+ return TCCompleteIrp (Irp, status, 0);
+
+ switch (irpSp->MinorFunction)
+ {
+ case IRP_MN_START_DEVICE:
+ Dump ("IRP_MN_START_DEVICE pdo=%p\n", Extension->Pdo);
+ return PassFilteredIrp (Extension->LowerDeviceObject, Irp, OnStartDeviceCompleted, Extension);
+
+
+ case IRP_MN_DEVICE_USAGE_NOTIFICATION:
+ Dump ("IRP_MN_DEVICE_USAGE_NOTIFICATION type=%d\n", (int) irpSp->Parameters.UsageNotification.Type);
+
+ {
+ PDEVICE_OBJECT attachedDevice = IoGetAttachedDeviceReference (DeviceObject);
+
+ if (attachedDevice == DeviceObject || (attachedDevice->Flags & DO_POWER_PAGABLE))
+ DeviceObject->Flags |= DO_POWER_PAGABLE;
+
+ ObDereferenceObject (attachedDevice);
+ }
+
+ // Prevent creation of hibernation and crash dump files if required
+ if (irpSp->Parameters.UsageNotification.InPath
+ && (
+ (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeDumpFile && !CrashDumpEnabled)
+ || (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeHibernation && !HibernationEnabled)
+ )
+ )
+ {
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+
+ if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeHibernation)
+ ++HibernationPreventionCount;
+
+ Dump ("Preventing dump type=%d\n", (int) irpSp->Parameters.UsageNotification.Type);
+ return TCCompleteIrp (Irp, STATUS_UNSUCCESSFUL, 0);
+ }
+
+ return PassFilteredIrp (Extension->LowerDeviceObject, Irp, OnDeviceUsageNotificationCompleted, Extension);
+
+
+ case IRP_MN_REMOVE_DEVICE:
+ Dump ("IRP_MN_REMOVE_DEVICE pdo=%p\n", Extension->Pdo);
+
+ IoReleaseRemoveLockAndWait (&Extension->Queue.RemoveLock, Irp);
+ status = PassIrp (Extension->LowerDeviceObject, Irp);
+
+ IoDetachDevice (Extension->LowerDeviceObject);
+
+ if (Extension->DriveMounted)
+ DismountDrive (Extension, TRUE);
+
+ if (Extension->BootDrive)
+ {
+ BootDriveFound = FALSE;
+ BootDriveFilterExtension = NULL;
+ }
+
+ IoDeleteDevice (DeviceObject);
+ return status;
+
+
+ default:
+ status = PassIrp (Extension->LowerDeviceObject, Irp);
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ }
+ return status;
+}
+
+
+static NTSTATUS DispatchPower (PDEVICE_OBJECT DeviceObject, PIRP Irp, DriveFilterExtension *Extension, PIO_STACK_LOCATION irpSp)
+{
+ NTSTATUS status;
+ Dump ("IRP_MJ_POWER minor=%d type=%d shutdown=%d\n", (int) irpSp->MinorFunction, (int) irpSp->Parameters.Power.Type, (int) irpSp->Parameters.Power.ShutdownType);
+
+ if (SetupInProgress
+ && irpSp->MinorFunction == IRP_MN_SET_POWER
+ && irpSp->Parameters.Power.ShutdownType == PowerActionHibernate)
+ {
+ while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+#if 0 // Dismount of the system drive is disabled until there is a way to do it without causing system errors (see the documentation for more info)
+ if (DriverShuttingDown
+ && Extension->BootDrive
+ && Extension->DriveMounted
+ && irpSp->MinorFunction == IRP_MN_SET_POWER
+ && irpSp->Parameters.Power.Type == DevicePowerState)
+ {
+ DismountDrive (Extension, TRUE);
+ }
+#endif // 0
+
+ PoStartNextPowerIrp (Irp);
+
+ status = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ if (!NT_SUCCESS (status))
+ return TCCompleteIrp (Irp, status, 0);
+
+ IoSkipCurrentIrpStackLocation (Irp);
+ status = PoCallDriver (Extension->LowerDeviceObject, Irp);
+
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ return status;
+}
+
+
+NTSTATUS DriveFilterDispatchIrp (PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ DriveFilterExtension *Extension = (DriveFilterExtension *) DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
+ NTSTATUS status;
+
+ ASSERT (!Extension->bRootDevice && Extension->IsDriveFilterDevice);
+
+ switch (irpSp->MajorFunction)
+ {
+ case IRP_MJ_READ:
+ case IRP_MJ_WRITE:
+ if (Extension->BootDrive)
+ {
+ status = EncryptedIoQueueAddIrp (&Extension->Queue, Irp);
+
+ if (status != STATUS_PENDING)
+ TCCompleteDiskIrp (Irp, status, 0);
+
+ return status;
+ }
+ break;
+
+ case IRP_MJ_PNP:
+ return DispatchPnp (DeviceObject, Irp, Extension, irpSp);
+
+ case IRP_MJ_POWER:
+ return DispatchPower (DeviceObject, Irp, Extension, irpSp);
+ }
+
+ status = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ if (!NT_SUCCESS (status))
+ return TCCompleteIrp (Irp, status, 0);
+
+ status = PassIrp (Extension->LowerDeviceObject, Irp);
+
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ return status;
+}
+
+
+void ReopenBootVolumeHeader (PIRP irp, PIO_STACK_LOCATION irpSp)
+{
+ LARGE_INTEGER offset;
+ char *header;
+ ReopenBootVolumeHeaderRequest *request = (ReopenBootVolumeHeaderRequest *) irp->AssociatedIrp.SystemBuffer;
+
+ irp->IoStatus.Information = 0;
+
+ if (!IoIsSystemThread (PsGetCurrentThread()) && !UserCanAccessDriveDevice())
+ {
+ irp->IoStatus.Status = STATUS_ACCESS_DENIED;
+ return;
+ }
+
+ if (!ValidateIOBufferSize (irp, sizeof (ReopenBootVolumeHeaderRequest), ValidateInput))
+ return;
+
+ if (!BootDriveFound || !BootDriveFilterExtension || !BootDriveFilterExtension->DriveMounted || !BootDriveFilterExtension->HeaderCryptoInfo
+ || request->VolumePassword.Length > MAX_PASSWORD
+ || request->pkcs5_prf < 0
+ || request->pkcs5_prf > LAST_PRF_ID
+ || request->pim < 0
+ || request->pim > 65535
+ )
+ {
+ irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ goto wipe;
+ }
+
+ header = TCalloc (TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
+ if (!header)
+ {
+ irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto wipe;
+ }
+
+ if (BootDriveFilterExtension->HiddenSystem)
+ offset.QuadPart = BootArgs.HiddenSystemPartitionStart + TC_HIDDEN_VOLUME_HEADER_OFFSET;
+ else
+ offset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
+
+ irp->IoStatus.Status = TCReadDevice (BootDriveFilterExtension->LowerDeviceObject, header, offset, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
+ if (!NT_SUCCESS (irp->IoStatus.Status))
+ {
+ Dump ("TCReadDevice error %x\n", irp->IoStatus.Status);
+ goto ret;
+ }
+
+ if (ReadVolumeHeader (!BootDriveFilterExtension->HiddenSystem, header, &request->VolumePassword, request->pkcs5_prf, request->pim, FALSE, NULL, BootDriveFilterExtension->HeaderCryptoInfo) == 0)
+ {
+ Dump ("Header reopened\n");
+ ComputeBootLoaderFingerprint (BootDriveFilterExtension->LowerDeviceObject, header);
+
+ BootDriveFilterExtension->Queue.CryptoInfo->header_creation_time = BootDriveFilterExtension->HeaderCryptoInfo->header_creation_time;
+ BootDriveFilterExtension->Queue.CryptoInfo->pkcs5 = BootDriveFilterExtension->HeaderCryptoInfo->pkcs5;
+ BootDriveFilterExtension->Queue.CryptoInfo->noIterations = BootDriveFilterExtension->HeaderCryptoInfo->noIterations;
+ BootDriveFilterExtension->Queue.CryptoInfo->volumePim = BootDriveFilterExtension->HeaderCryptoInfo->volumePim;
+
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ crypto_close (BootDriveFilterExtension->HeaderCryptoInfo);
+ BootDriveFilterExtension->HeaderCryptoInfo = NULL;
+
+ Dump ("Header not reopened\n");
+ irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ }
+
+ret:
+ TCfree (header);
+wipe:
+ burn (request, sizeof (*request));
+}
+
+
+// Legacy Windows XP/2003 hibernation dump filter
+
+typedef NTSTATUS (*HiberDriverWriteFunctionA) (ULONG arg0, PLARGE_INTEGER writeOffset, PMDL dataMdl, PVOID arg3);
+typedef NTSTATUS (*HiberDriverWriteFunctionB) (PLARGE_INTEGER writeOffset, PMDL dataMdl);
+
+typedef struct
+{
+#ifdef _WIN64
+ byte FieldPad1[64];
+ HiberDriverWriteFunctionB WriteFunctionB;
+ byte FieldPad2[56];
+#else
+ byte FieldPad1[48];
+ HiberDriverWriteFunctionB WriteFunctionB;
+ byte FieldPad2[32];
+#endif
+ HiberDriverWriteFunctionA WriteFunctionA;
+ byte FieldPad3[24];
+ LARGE_INTEGER PartitionStartOffset;
+} HiberDriverContext;
+
+typedef NTSTATUS (*HiberDriverEntry) (PVOID arg0, HiberDriverContext *hiberDriverContext);
+
+typedef struct
+{
+ LIST_ENTRY ModuleList;
+#ifdef _WIN64
+ byte FieldPad1[32];
+#else
+ byte FieldPad1[16];
+#endif
+ PVOID ModuleBaseAddress;
+ HiberDriverEntry ModuleEntryAddress;
+#ifdef _WIN64
+ byte FieldPad2[24];
+#else
+ byte FieldPad2[12];
+#endif
+ UNICODE_STRING ModuleName;
+} ModuleTableItem;
+
+
+#define TC_MAX_HIBER_FILTER_COUNT 3
+static int LastHiberFilterNumber = 0;
+
+static HiberDriverEntry OriginalHiberDriverEntries[TC_MAX_HIBER_FILTER_COUNT];
+static HiberDriverWriteFunctionA OriginalHiberDriverWriteFunctionsA[TC_MAX_HIBER_FILTER_COUNT];
+static HiberDriverWriteFunctionB OriginalHiberDriverWriteFunctionsB[TC_MAX_HIBER_FILTER_COUNT];
+
+static LARGE_INTEGER HiberPartitionOffset;
+
+
+static NTSTATUS HiberDriverWriteFunctionFilter (int filterNumber, PLARGE_INTEGER writeOffset, PMDL dataMdl, BOOL writeB, ULONG arg0WriteA, PVOID arg3WriteA)
+{
+ MDL *encryptedDataMdl = dataMdl;
+
+ if (writeOffset && dataMdl && BootDriveFilterExtension && BootDriveFilterExtension->DriveMounted)
+ {
+ ULONG dataLength = MmGetMdlByteCount (dataMdl);
+
+ if (dataMdl->MappedSystemVa && dataLength > 0)
+ {
+ uint64 offset = HiberPartitionOffset.QuadPart + writeOffset->QuadPart;
+ uint64 intersectStart;
+ uint32 intersectLength;
+
+ if (dataLength > TC_HIBERNATION_WRITE_BUFFER_SIZE)
+ TC_BUG_CHECK (STATUS_BUFFER_OVERFLOW);
+
+ if ((dataLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0)
+ TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
+
+ if ((offset & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0)
+ TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
+
+ GetIntersection (offset,
+ dataLength,
+ BootDriveFilterExtension->Queue.EncryptedAreaStart,
+ BootDriveFilterExtension->Queue.EncryptedAreaEnd,
+ &intersectStart,
+ &intersectLength);
+
+ if (intersectLength > 0)
+ {
+ UINT64_STRUCT dataUnit;
+ dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE;
+
+ memcpy (HibernationWriteBuffer, dataMdl->MappedSystemVa, dataLength);
+
+ if (BootDriveFilterExtension->Queue.RemapEncryptedArea)
+ dataUnit.Value += BootDriveFilterExtension->Queue.RemappedAreaDataUnitOffset;
+
+ EncryptDataUnitsCurrentThread (HibernationWriteBuffer + (intersectStart - offset),
+ &dataUnit,
+ intersectLength / ENCRYPTION_DATA_UNIT_SIZE,
+ BootDriveFilterExtension->Queue.CryptoInfo);
+
+ encryptedDataMdl = HibernationWriteBufferMdl;
+ MmInitializeMdl (encryptedDataMdl, HibernationWriteBuffer, dataLength);
+ encryptedDataMdl->MdlFlags = dataMdl->MdlFlags;
+ }
+ }
+ }
+
+ if (writeB)
+ return (*OriginalHiberDriverWriteFunctionsB[filterNumber]) (writeOffset, encryptedDataMdl);
+
+ return (*OriginalHiberDriverWriteFunctionsA[filterNumber]) (arg0WriteA, writeOffset, encryptedDataMdl, arg3WriteA);
+}
+
+
+static NTSTATUS HiberDriverWriteFunctionAFilter0 (ULONG arg0, PLARGE_INTEGER writeOffset, PMDL dataMdl, PVOID arg3)
+{
+ return HiberDriverWriteFunctionFilter (0, writeOffset, dataMdl, FALSE, arg0, arg3);
+}
+
+static NTSTATUS HiberDriverWriteFunctionAFilter1 (ULONG arg0, PLARGE_INTEGER writeOffset, PMDL dataMdl, PVOID arg3)
+{
+ return HiberDriverWriteFunctionFilter (1, writeOffset, dataMdl, FALSE, arg0, arg3);
+}
+
+static NTSTATUS HiberDriverWriteFunctionAFilter2 (ULONG arg0, PLARGE_INTEGER writeOffset, PMDL dataMdl, PVOID arg3)
+{
+ return HiberDriverWriteFunctionFilter (2, writeOffset, dataMdl, FALSE, arg0, arg3);
+}
+
+
+static NTSTATUS HiberDriverWriteFunctionBFilter0 (PLARGE_INTEGER writeOffset, PMDL dataMdl)
+{
+ return HiberDriverWriteFunctionFilter (0, writeOffset, dataMdl, TRUE, 0, NULL);
+}
+
+static NTSTATUS HiberDriverWriteFunctionBFilter1 (PLARGE_INTEGER writeOffset, PMDL dataMdl)
+{
+ return HiberDriverWriteFunctionFilter (1, writeOffset, dataMdl, TRUE, 0, NULL);
+}
+
+static NTSTATUS HiberDriverWriteFunctionBFilter2 (PLARGE_INTEGER writeOffset, PMDL dataMdl)
+{
+ return HiberDriverWriteFunctionFilter (2, writeOffset, dataMdl, TRUE, 0, NULL);
+}
+
+
+static NTSTATUS HiberDriverEntryFilter (int filterNumber, PVOID arg0, HiberDriverContext *hiberDriverContext)
+{
+ BOOL filterInstalled = FALSE;
+ NTSTATUS status;
+
+ if (!OriginalHiberDriverEntries[filterNumber])
+ return STATUS_UNSUCCESSFUL;
+
+ status = (*OriginalHiberDriverEntries[filterNumber]) (arg0, hiberDriverContext);
+
+ if (!NT_SUCCESS (status) || !hiberDriverContext)
+ return status;
+
+ if (SetupInProgress)
+ TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
+
+ if (hiberDriverContext->WriteFunctionA)
+ {
+ Dump ("Filtering WriteFunctionA %d\n", filterNumber);
+ OriginalHiberDriverWriteFunctionsA[filterNumber] = hiberDriverContext->WriteFunctionA;
+
+ switch (filterNumber)
+ {
+ case 0: hiberDriverContext->WriteFunctionA = HiberDriverWriteFunctionAFilter0; break;
+ case 1: hiberDriverContext->WriteFunctionA = HiberDriverWriteFunctionAFilter1; break;
+ case 2: hiberDriverContext->WriteFunctionA = HiberDriverWriteFunctionAFilter2; break;
+ default: TC_THROW_FATAL_EXCEPTION;
+ }
+
+ filterInstalled = TRUE;
+ }
+
+ if (hiberDriverContext->WriteFunctionB)
+ {
+ Dump ("Filtering WriteFunctionB %d\n", filterNumber);
+ OriginalHiberDriverWriteFunctionsB[filterNumber] = hiberDriverContext->WriteFunctionB;
+
+ switch (filterNumber)
+ {
+ case 0: hiberDriverContext->WriteFunctionB = HiberDriverWriteFunctionBFilter0; break;
+ case 1: hiberDriverContext->WriteFunctionB = HiberDriverWriteFunctionBFilter1; break;
+ case 2: hiberDriverContext->WriteFunctionB = HiberDriverWriteFunctionBFilter2; break;
+ default: TC_THROW_FATAL_EXCEPTION;
+ }
+
+ filterInstalled = TRUE;
+ }
+
+ if (filterInstalled && hiberDriverContext->PartitionStartOffset.QuadPart != 0)
+ {
+ HiberPartitionOffset = hiberDriverContext->PartitionStartOffset;
+
+ if (BootDriveFilterExtension->Queue.RemapEncryptedArea)
+ hiberDriverContext->PartitionStartOffset.QuadPart += BootDriveFilterExtension->Queue.RemappedAreaOffset;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS HiberDriverEntryFilter0 (PVOID arg0, HiberDriverContext *hiberDriverContext)
+{
+ return HiberDriverEntryFilter (0, arg0, hiberDriverContext);
+}
+
+
+static NTSTATUS HiberDriverEntryFilter1 (PVOID arg0, HiberDriverContext *hiberDriverContext)
+{
+ return HiberDriverEntryFilter (1, arg0, hiberDriverContext);
+}
+
+
+static NTSTATUS HiberDriverEntryFilter2 (PVOID arg0, HiberDriverContext *hiberDriverContext)
+{
+ return HiberDriverEntryFilter (2, arg0, hiberDriverContext);
+}
+
+
+static VOID LoadImageNotifyRoutine (PUNICODE_STRING fullImageName, HANDLE processId, PIMAGE_INFO imageInfo)
+{
+ ModuleTableItem *moduleItem;
+ LIST_ENTRY *listEntry;
+ KIRQL origIrql;
+
+ if (!imageInfo || !imageInfo->SystemModeImage || !imageInfo->ImageBase || !TCDriverObject->DriverSection)
+ return;
+
+ moduleItem = *(ModuleTableItem **) TCDriverObject->DriverSection;
+ if (!moduleItem || !moduleItem->ModuleList.Flink)
+ return;
+
+ // Search loaded system modules for hibernation driver
+ origIrql = KeRaiseIrqlToDpcLevel();
+
+ for (listEntry = moduleItem->ModuleList.Flink->Blink;
+ listEntry && listEntry != TCDriverObject->DriverSection;
+ listEntry = listEntry->Flink)
+ {
+ moduleItem = CONTAINING_RECORD (listEntry, ModuleTableItem, ModuleList);
+
+ if (moduleItem && imageInfo->ImageBase == moduleItem->ModuleBaseAddress)
+ {
+ if (moduleItem->ModuleName.Buffer && moduleItem->ModuleName.Length >= 5 * sizeof (wchar_t))
+ {
+ if (memcmp (moduleItem->ModuleName.Buffer, L"hiber", 5 * sizeof (wchar_t)) == 0
+ || memcmp (moduleItem->ModuleName.Buffer, L"Hiber", 5 * sizeof (wchar_t)) == 0
+ || memcmp (moduleItem->ModuleName.Buffer, L"HIBER", 5 * sizeof (wchar_t)) == 0)
+ {
+ HiberDriverEntry filterEntry;
+
+ switch (LastHiberFilterNumber)
+ {
+ case 0: filterEntry = HiberDriverEntryFilter0; break;
+ case 1: filterEntry = HiberDriverEntryFilter1; break;
+ case 2: filterEntry = HiberDriverEntryFilter2; break;
+ default: TC_THROW_FATAL_EXCEPTION;
+ }
+
+ if (moduleItem->ModuleEntryAddress != filterEntry)
+ {
+ // Install filter
+ OriginalHiberDriverEntries[LastHiberFilterNumber] = moduleItem->ModuleEntryAddress;
+ moduleItem->ModuleEntryAddress = filterEntry;
+
+ if (++LastHiberFilterNumber > TC_MAX_HIBER_FILTER_COUNT - 1)
+ LastHiberFilterNumber = 0;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ KeLowerIrql (origIrql);
+}
+
+
+void StartLegacyHibernationDriverFilter ()
+{
+ PHYSICAL_ADDRESS highestAcceptableWriteBufferAddr;
+ NTSTATUS status;
+
+ ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
+ ASSERT (!IsOSAtLeast (WIN_VISTA));
+
+ if (!TCDriverObject->DriverSection || !*(ModuleTableItem **) TCDriverObject->DriverSection)
+ goto err;
+
+ // All buffers required for hibernation must be allocated here
+#ifdef _WIN64
+ highestAcceptableWriteBufferAddr.QuadPart = 0x7FFffffFFFFULL;
+#else
+ highestAcceptableWriteBufferAddr.QuadPart = 0xffffFFFFULL;
+#endif
+
+ HibernationWriteBuffer = MmAllocateContiguousMemory (TC_HIBERNATION_WRITE_BUFFER_SIZE, highestAcceptableWriteBufferAddr);
+ if (!HibernationWriteBuffer)
+ goto err;
+
+ HibernationWriteBufferMdl = IoAllocateMdl (HibernationWriteBuffer, TC_HIBERNATION_WRITE_BUFFER_SIZE, FALSE, FALSE, NULL);
+ if (!HibernationWriteBufferMdl)
+ goto err;
+
+ MmBuildMdlForNonPagedPool (HibernationWriteBufferMdl);
+
+ status = PsSetLoadImageNotifyRoutine (LoadImageNotifyRoutine);
+ if (!NT_SUCCESS (status))
+ goto err;
+
+ LegacyHibernationDriverFilterActive = TRUE;
+ CrashDumpEnabled = FALSE;
+ HibernationEnabled = TRUE;
+ return;
+
+err:
+ LegacyHibernationDriverFilterActive = FALSE;
+ CrashDumpEnabled = FALSE;
+ HibernationEnabled = FALSE;
+
+ if (HibernationWriteBufferMdl)
+ {
+ IoFreeMdl (HibernationWriteBufferMdl);
+ HibernationWriteBufferMdl = NULL;
+ }
+
+ if (HibernationWriteBuffer)
+ {
+ MmFreeContiguousMemory (HibernationWriteBuffer);
+ HibernationWriteBuffer = NULL;
+ }
+}
+
+
+static VOID SetupThreadProc (PVOID threadArg)
+{
+ DriveFilterExtension *Extension = BootDriveFilterExtension;
+
+ LARGE_INTEGER offset;
+ UINT64_STRUCT dataUnit;
+ ULONG setupBlockSize = TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE;
+ BOOL headerUpdateRequired = FALSE;
+ int64 bytesWrittenSinceHeaderUpdate = 0;
+
+ byte *buffer = NULL;
+ byte *wipeBuffer = NULL;
+ byte wipeRandChars[TC_WIPE_RAND_CHAR_COUNT];
+ byte wipeRandCharsUpdate[TC_WIPE_RAND_CHAR_COUNT];
+
+ KIRQL irql;
+ NTSTATUS status;
+
+ // generate real random values for wipeRandChars and
+ // wipeRandCharsUpdate instead of relying on uninitialized stack memory
+ LARGE_INTEGER iSeed;
+ KeQuerySystemTime( &iSeed );
+ if (KeGetCurrentIrql() < DISPATCH_LEVEL)
+ {
+ ULONG ulRandom;
+ ulRandom = RtlRandomEx( &iSeed.LowPart );
+ memcpy (wipeRandChars, &ulRandom, TC_WIPE_RAND_CHAR_COUNT);
+ ulRandom = RtlRandomEx( &ulRandom );
+ memcpy (wipeRandCharsUpdate, &ulRandom, TC_WIPE_RAND_CHAR_COUNT);
+ burn (&ulRandom, sizeof(ulRandom));
+ }
+ else
+ {
+ byte digest[SHA512_DIGESTSIZE];
+ sha512_ctx tctx;
+ sha512_begin (&tctx);
+ sha512_hash ((unsigned char *) &(iSeed.QuadPart), sizeof(iSeed.QuadPart), &tctx);
+ sha512_end (digest, &tctx);
+
+ memcpy (wipeRandChars, digest, TC_WIPE_RAND_CHAR_COUNT);
+ memcpy (wipeRandCharsUpdate, &digest[SHA512_DIGESTSIZE - TC_WIPE_RAND_CHAR_COUNT], TC_WIPE_RAND_CHAR_COUNT);
+
+ burn (digest, SHA512_DIGESTSIZE);
+ burn (&tctx, sizeof (tctx));
+ }
+
+ burn (&iSeed, sizeof(iSeed));
+
+ SetupResult = STATUS_UNSUCCESSFUL;
+
+ // Make sure volume header can be updated
+ if (Extension->HeaderCryptoInfo == NULL)
+ {
+ SetupResult = STATUS_INVALID_PARAMETER;
+ goto ret;
+ }
+
+ buffer = TCalloc (TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE);
+ if (!buffer)
+ {
+ SetupResult = STATUS_INSUFFICIENT_RESOURCES;
+ goto ret;
+ }
+
+ if (SetupRequest.SetupMode == SetupEncryption && SetupRequest.WipeAlgorithm != TC_WIPE_NONE)
+ {
+ wipeBuffer = TCalloc (TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE);
+ if (!wipeBuffer)
+ {
+ SetupResult = STATUS_INSUFFICIENT_RESOURCES;
+ goto ret;
+ }
+ }
+
+ while (!NT_SUCCESS (EncryptedIoQueueHoldWhenIdle (&Extension->Queue, 1000)))
+ {
+ if (EncryptionSetupThreadAbortRequested)
+ goto abort;
+
+ TransformWaitingForIdle = TRUE;
+ }
+ TransformWaitingForIdle = FALSE;
+
+ switch (SetupRequest.SetupMode)
+ {
+ case SetupEncryption:
+ Dump ("Encrypting...\n");
+ if (Extension->Queue.EncryptedAreaStart == -1 || Extension->Queue.EncryptedAreaEnd == -1)
+ {
+ // Start encryption
+ Extension->Queue.EncryptedAreaStart = Extension->ConfiguredEncryptedAreaStart;
+ Extension->Queue.EncryptedAreaEnd = -1;
+ offset.QuadPart = Extension->ConfiguredEncryptedAreaStart;
+ }
+ else
+ {
+ // Resume aborted encryption
+ if (Extension->Queue.EncryptedAreaEnd == Extension->ConfiguredEncryptedAreaEnd)
+ goto err;
+
+ offset.QuadPart = Extension->Queue.EncryptedAreaEnd + 1;
+ }
+
+ break;
+
+ case SetupDecryption:
+ Dump ("Decrypting...\n");
+ if (Extension->Queue.EncryptedAreaStart == -1 || Extension->Queue.EncryptedAreaEnd == -1)
+ {
+ SetupResult = STATUS_SUCCESS;
+ goto abort;
+ }
+
+ offset.QuadPart = Extension->Queue.EncryptedAreaEnd + 1;
+ break;
+
+ default:
+ goto err;
+ }
+
+ EncryptedIoQueueResumeFromHold (&Extension->Queue);
+
+ Dump ("EncryptedAreaStart=%I64d\n", Extension->Queue.EncryptedAreaStart);
+ Dump ("EncryptedAreaEnd=%I64d\n", Extension->Queue.EncryptedAreaEnd);
+ Dump ("ConfiguredEncryptedAreaStart=%I64d\n", Extension->ConfiguredEncryptedAreaStart);
+ Dump ("ConfiguredEncryptedAreaEnd=%I64d\n", Extension->ConfiguredEncryptedAreaEnd);
+ Dump ("offset=%I64d\n", offset.QuadPart);
+ Dump ("EncryptedAreaStart=%I64d (%I64d) EncryptedAreaEnd=%I64d\n", Extension->Queue.EncryptedAreaStart / 1024 / 1024, Extension->Queue.EncryptedAreaStart, Extension->Queue.EncryptedAreaEnd / 1024 / 1024);
+
+ while (!EncryptionSetupThreadAbortRequested)
+ {
+ if (SetupRequest.SetupMode == SetupEncryption)
+ {
+ if (offset.QuadPart + setupBlockSize > Extension->ConfiguredEncryptedAreaEnd + 1)
+ setupBlockSize = (ULONG) (Extension->ConfiguredEncryptedAreaEnd + 1 - offset.QuadPart);
+
+ if (offset.QuadPart > Extension->ConfiguredEncryptedAreaEnd)
+ break;
+ }
+ else
+ {
+ if (offset.QuadPart - setupBlockSize < Extension->Queue.EncryptedAreaStart)
+ setupBlockSize = (ULONG) (offset.QuadPart - Extension->Queue.EncryptedAreaStart);
+
+ offset.QuadPart -= setupBlockSize;
+
+ if (setupBlockSize == 0 || offset.QuadPart < Extension->Queue.EncryptedAreaStart)
+ break;
+ }
+
+ while (!NT_SUCCESS (EncryptedIoQueueHoldWhenIdle (&Extension->Queue, 500)))
+ {
+ if (EncryptionSetupThreadAbortRequested)
+ goto abort;
+
+ TransformWaitingForIdle = TRUE;
+ }
+ TransformWaitingForIdle = FALSE;
+
+ status = TCReadDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize);
+ if (!NT_SUCCESS (status))
+ {
+ Dump ("TCReadDevice error %x offset=%I64d\n", status, offset.QuadPart);
+
+ if (SetupRequest.ZeroUnreadableSectors && SetupRequest.SetupMode == SetupEncryption)
+ {
+ // Zero unreadable sectors
+ uint64 zeroedSectorCount;
+
+ status = ZeroUnreadableSectors (BootDriveFilterExtension->LowerDeviceObject, offset, setupBlockSize, &zeroedSectorCount);
+ if (!NT_SUCCESS (status))
+ {
+ SetupResult = status;
+ goto err;
+ }
+
+ // Retry read
+ status = TCReadDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize);
+ if (!NT_SUCCESS (status))
+ {
+ SetupResult = status;
+ goto err;
+ }
+ }
+ else if (SetupRequest.DiscardUnreadableEncryptedSectors && SetupRequest.SetupMode == SetupDecryption)
+ {
+ // Discard unreadable encrypted sectors
+ uint64 badSectorCount;
+
+ status = ReadDeviceSkipUnreadableSectors (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize, &badSectorCount);
+ if (!NT_SUCCESS (status))
+ {
+ SetupResult = status;
+ goto err;
+ }
+ }
+ else
+ {
+ SetupResult = status;
+ goto err;
+ }
+ }
+
+ dataUnit.Value = offset.QuadPart / ENCRYPTION_DATA_UNIT_SIZE;
+
+ if (SetupRequest.SetupMode == SetupEncryption)
+ {
+ EncryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo);
+
+ if (SetupRequest.WipeAlgorithm != TC_WIPE_NONE)
+ {
+ byte wipePass;
+ int wipePassCount = GetWipePassCount (SetupRequest.WipeAlgorithm);
+ if (wipePassCount <= 0)
+ {
+ SetupResult = STATUS_INVALID_PARAMETER;
+ goto err;
+ }
+
+ for (wipePass = 1; wipePass <= wipePassCount; ++wipePass)
+ {
+ if (!WipeBuffer (SetupRequest.WipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, setupBlockSize))
+ {
+ ULONG i;
+ for (i = 0; i < setupBlockSize; ++i)
+ {
+ wipeBuffer[i] = buffer[i] + wipePass;
+ }
+
+ EncryptDataUnits (wipeBuffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo);
+ memcpy (wipeRandCharsUpdate, wipeBuffer, sizeof (wipeRandCharsUpdate));
+ }
+
+ status = TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, wipeBuffer, offset, setupBlockSize);
+ if (!NT_SUCCESS (status))
+ {
+ // Undo failed write operation
+ DecryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo);
+ TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize);
+
+ SetupResult = status;
+ goto err;
+ }
+ }
+
+ memcpy (wipeRandChars, wipeRandCharsUpdate, sizeof (wipeRandCharsUpdate));
+ }
+ }
+ else
+ {
+ DecryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo);
+ }
+
+ status = TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize);
+ if (!NT_SUCCESS (status))
+ {
+ Dump ("TCWriteDevice error %x\n", status);
+
+ // Undo failed write operation
+ if (SetupRequest.SetupMode == SetupEncryption)
+ DecryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo);
+ else
+ EncryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo);
+
+ TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize);
+
+ SetupResult = status;
+ goto err;
+ }
+
+ if (SetupRequest.SetupMode == SetupEncryption)
+ offset.QuadPart += setupBlockSize;
+
+ Extension->Queue.EncryptedAreaEndUpdatePending = TRUE;
+ Extension->Queue.EncryptedAreaEnd = offset.QuadPart - 1;
+ Extension->Queue.EncryptedAreaEndUpdatePending = FALSE;
+
+ headerUpdateRequired = TRUE;
+
+ EncryptedIoQueueResumeFromHold (&Extension->Queue);
+
+ KeAcquireSpinLock (&SetupStatusSpinLock, &irql);
+ SetupStatusEncryptedAreaEnd = Extension->Queue.EncryptedAreaEnd;
+ KeReleaseSpinLock (&SetupStatusSpinLock, irql);
+
+ // Update volume header
+ bytesWrittenSinceHeaderUpdate += setupBlockSize;
+ if (bytesWrittenSinceHeaderUpdate >= TC_ENCRYPTION_SETUP_HEADER_UPDATE_THRESHOLD)
+ {
+ status = SaveDriveVolumeHeader (Extension);
+ ASSERT (NT_SUCCESS (status));
+ if (NT_SUCCESS (status))
+ {
+ headerUpdateRequired = FALSE;
+ bytesWrittenSinceHeaderUpdate = 0;
+ }
+ }
+ }
+
+abort:
+ SetupResult = STATUS_SUCCESS;
+err:
+
+ if (Extension->Queue.EncryptedAreaEnd == -1)
+ Extension->Queue.EncryptedAreaStart = -1;
+
+ if (EncryptedIoQueueIsSuspended (&Extension->Queue))
+ EncryptedIoQueueResumeFromHold (&Extension->Queue);
+
+ if (SetupRequest.SetupMode == SetupDecryption && Extension->Queue.EncryptedAreaStart >= Extension->Queue.EncryptedAreaEnd)
+ {
+ while (!NT_SUCCESS (EncryptedIoQueueHoldWhenIdle (&Extension->Queue, 0)));
+
+ Extension->ConfiguredEncryptedAreaStart = Extension->ConfiguredEncryptedAreaEnd = -1;
+ Extension->Queue.EncryptedAreaStart = Extension->Queue.EncryptedAreaEnd = -1;
+
+ EncryptedIoQueueResumeFromHold (&Extension->Queue);
+
+ headerUpdateRequired = TRUE;
+ }
+
+ Dump ("Setup completed: EncryptedAreaStart=%I64d (%I64d) EncryptedAreaEnd=%I64d (%I64d)\n", Extension->Queue.EncryptedAreaStart / 1024 / 1024, Extension->Queue.EncryptedAreaStart, Extension->Queue.EncryptedAreaEnd / 1024 / 1024, Extension->Queue.EncryptedAreaEnd);
+
+ if (headerUpdateRequired)
+ {
+ status = SaveDriveVolumeHeader (Extension);
+
+ if (!NT_SUCCESS (status) && NT_SUCCESS (SetupResult))
+ SetupResult = status;
+ }
+
+ if (SetupRequest.SetupMode == SetupDecryption && Extension->ConfiguredEncryptedAreaEnd == -1 && Extension->DriveMounted)
+ {
+ while (!RootDeviceControlMutexAcquireNoWait() && !EncryptionSetupThreadAbortRequested)
+ {
+ TCSleep (10);
+ }
+
+ // Disable hibernation (resume would fail due to a change in the system memory map)
+ HibernationEnabled = FALSE;
+
+ DismountDrive (Extension, FALSE);
+
+ if (!EncryptionSetupThreadAbortRequested)
+ RootDeviceControlMutexRelease();
+ }
+
+ret:
+ if (buffer)
+ {
+ burn (buffer, TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE);
+ TCfree (buffer);
+ }
+ if (wipeBuffer)
+ {
+ burn (wipeBuffer, TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE);
+ TCfree (wipeBuffer);
+ }
+
+ burn (wipeRandChars, TC_WIPE_RAND_CHAR_COUNT);
+ burn (wipeRandCharsUpdate, TC_WIPE_RAND_CHAR_COUNT);
+
+ SetupInProgress = FALSE;
+ PsTerminateSystemThread (SetupResult);
+}
+
+
+NTSTATUS StartBootEncryptionSetup (PDEVICE_OBJECT DeviceObject, PIRP irp, PIO_STACK_LOCATION irpSp)
+{
+ NTSTATUS status;
+
+ if (!UserCanAccessDriveDevice())
+ return STATUS_ACCESS_DENIED;
+
+ if (SetupInProgress || !BootDriveFound || !BootDriveFilterExtension
+ || !BootDriveFilterExtension->DriveMounted
+ || BootDriveFilterExtension->HiddenSystem
+ || irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (BootEncryptionSetupRequest))
+ return STATUS_INVALID_PARAMETER;
+
+ if (EncryptionSetupThread)
+ AbortBootEncryptionSetup();
+
+ SetupRequest = *(BootEncryptionSetupRequest *) irp->AssociatedIrp.SystemBuffer;
+
+ EncryptionSetupThreadAbortRequested = FALSE;
+ KeInitializeSpinLock (&SetupStatusSpinLock);
+ SetupStatusEncryptedAreaEnd = BootDriveFilterExtension ? BootDriveFilterExtension->Queue.EncryptedAreaEnd : -1;
+
+ SetupInProgress = TRUE;
+ status = TCStartThread (SetupThreadProc, DeviceObject, &EncryptionSetupThread);
+
+ if (!NT_SUCCESS (status))
+ SetupInProgress = FALSE;
+
+ return status;
+}
+
+
+void GetBootDriveVolumeProperties (PIRP irp, PIO_STACK_LOCATION irpSp)
+{
+ if (ValidateIOBufferSize (irp, sizeof (VOLUME_PROPERTIES_STRUCT), ValidateOutput))
+ {
+ DriveFilterExtension *Extension = BootDriveFilterExtension;
+ VOLUME_PROPERTIES_STRUCT *prop = (VOLUME_PROPERTIES_STRUCT *) irp->AssociatedIrp.SystemBuffer;
+ memset (prop, 0, sizeof (*prop));
+
+ if (!BootDriveFound || !Extension || !Extension->DriveMounted)
+ {
+ irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ irp->IoStatus.Information = 0;
+ }
+ else
+ {
+ prop->hiddenVolume = Extension->Queue.CryptoInfo->hiddenVolume;
+ prop->diskLength = Extension->ConfiguredEncryptedAreaEnd + 1 - Extension->ConfiguredEncryptedAreaStart;
+ prop->ea = Extension->Queue.CryptoInfo->ea;
+ prop->mode = Extension->Queue.CryptoInfo->mode;
+ prop->pkcs5 = Extension->Queue.CryptoInfo->pkcs5;
+ prop->pkcs5Iterations = Extension->Queue.CryptoInfo->noIterations;
+ prop->volumePim = Extension->Queue.CryptoInfo->volumePim;
+#if 0
+ prop->volumeCreationTime = Extension->Queue.CryptoInfo->volume_creation_time;
+ prop->headerCreationTime = Extension->Queue.CryptoInfo->header_creation_time;
+#endif
+ prop->volFormatVersion = Extension->Queue.CryptoInfo->LegacyVolume ? TC_VOLUME_FORMAT_VERSION_PRE_6_0 : TC_VOLUME_FORMAT_VERSION;
+
+ prop->totalBytesRead = Extension->Queue.TotalBytesRead;
+ prop->totalBytesWritten = Extension->Queue.TotalBytesWritten;
+
+ irp->IoStatus.Information = sizeof (VOLUME_PROPERTIES_STRUCT);
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ }
+}
+
+
+void GetBootEncryptionStatus (PIRP irp, PIO_STACK_LOCATION irpSp)
+{
+ /* IMPORTANT: Do NOT add any potentially time-consuming operations to this function. */
+
+ if (ValidateIOBufferSize (irp, sizeof (BootEncryptionStatus), ValidateOutput))
+ {
+ DriveFilterExtension *Extension = BootDriveFilterExtension;
+ BootEncryptionStatus *bootEncStatus = (BootEncryptionStatus *) irp->AssociatedIrp.SystemBuffer;
+ memset (bootEncStatus, 0, sizeof (*bootEncStatus));
+
+ if (BootArgsValid)
+ bootEncStatus->BootLoaderVersion = BootArgs.BootLoaderVersion;
+
+ bootEncStatus->DeviceFilterActive = DeviceFilterActive;
+ bootEncStatus->SetupInProgress = SetupInProgress;
+ bootEncStatus->SetupMode = SetupRequest.SetupMode;
+ bootEncStatus->TransformWaitingForIdle = TransformWaitingForIdle;
+
+ if (!BootDriveFound || !Extension || !Extension->DriveMounted)
+ {
+ bootEncStatus->DriveEncrypted = FALSE;
+ bootEncStatus->DriveMounted = FALSE;
+ bootEncStatus->VolumeHeaderPresent = FALSE;
+ }
+ else
+ {
+ bootEncStatus->DriveMounted = Extension->DriveMounted;
+ bootEncStatus->VolumeHeaderPresent = Extension->VolumeHeaderPresent;
+ bootEncStatus->DriveEncrypted = Extension->Queue.EncryptedAreaStart != -1;
+ bootEncStatus->BootDriveLength = BootDriveLength;
+
+ bootEncStatus->ConfiguredEncryptedAreaStart = Extension->ConfiguredEncryptedAreaStart;
+ bootEncStatus->ConfiguredEncryptedAreaEnd = Extension->ConfiguredEncryptedAreaEnd;
+ bootEncStatus->EncryptedAreaStart = Extension->Queue.EncryptedAreaStart;
+
+ if (SetupInProgress)
+ {
+ KIRQL irql;
+ KeAcquireSpinLock (&SetupStatusSpinLock, &irql);
+ bootEncStatus->EncryptedAreaEnd = SetupStatusEncryptedAreaEnd;
+ KeReleaseSpinLock (&SetupStatusSpinLock, irql);
+ }
+ else
+ bootEncStatus->EncryptedAreaEnd = Extension->Queue.EncryptedAreaEnd;
+
+ bootEncStatus->VolumeHeaderSaltCrc32 = Extension->VolumeHeaderSaltCrc32;
+ bootEncStatus->HibernationPreventionCount = HibernationPreventionCount;
+ bootEncStatus->HiddenSysLeakProtectionCount = HiddenSysLeakProtectionCount;
+
+ bootEncStatus->HiddenSystem = Extension->HiddenSystem;
+
+ if (Extension->HiddenSystem)
+ bootEncStatus->HiddenSystemPartitionStart = BootArgs.HiddenSystemPartitionStart;
+ }
+
+ irp->IoStatus.Information = sizeof (BootEncryptionStatus);
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+}
+
+
+void GetBootLoaderVersion (PIRP irp, PIO_STACK_LOCATION irpSp)
+{
+ if (ValidateIOBufferSize (irp, sizeof (uint16), ValidateOutput))
+ {
+ if (BootArgsValid)
+ {
+ *(uint16 *) irp->AssociatedIrp.SystemBuffer = BootArgs.BootLoaderVersion;
+ irp->IoStatus.Information = sizeof (uint16);
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ irp->IoStatus.Information = 0;
+ }
+ }
+}
+
+void GetBootLoaderFingerprint (PIRP irp, PIO_STACK_LOCATION irpSp)
+{
+ if (ValidateIOBufferSize (irp, sizeof (BootLoaderFingerprintRequest), ValidateOutput))
+ {
+ irp->IoStatus.Information = 0;
+ if (BootArgsValid && BootDriveFound && BootDriveFilterExtension && BootDriveFilterExtension->DriveMounted && BootDriveFilterExtension->HeaderCryptoInfo)
+ {
+ BootLoaderFingerprintRequest *bootLoaderFingerprint = (BootLoaderFingerprintRequest *) irp->AssociatedIrp.SystemBuffer;
+
+ /* compute the fingerprint again and check if it is the same as the one retrieved during boot */
+ char *header = TCalloc (TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
+ if (!header)
+ {
+ irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ memcpy (bootLoaderFingerprint->Fingerprint, BootLoaderFingerprint, sizeof (BootLoaderFingerprint));
+ ComputeBootLoaderFingerprint (BootDriveFilterExtension->LowerDeviceObject, header);
+
+ burn (header, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
+ TCfree (header);
+
+ if (0 == memcmp (bootLoaderFingerprint->Fingerprint, BootLoaderFingerprint, sizeof (BootLoaderFingerprint)))
+ {
+ irp->IoStatus.Information = sizeof (BootLoaderFingerprintRequest);
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ /* fingerprint mismatch.*/
+ irp->IoStatus.Status = STATUS_INVALID_IMAGE_HASH;
+ }
+ }
+ }
+ else
+ {
+ irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+}
+
+void GetBootEncryptionAlgorithmName (PIRP irp, PIO_STACK_LOCATION irpSp)
+{
+ if (ValidateIOBufferSize (irp, sizeof (GetBootEncryptionAlgorithmNameRequest), ValidateOutput))
+ {
+ if (BootDriveFilterExtension && BootDriveFilterExtension->DriveMounted)
+ {
+ wchar_t BootEncryptionAlgorithmNameW[256];
+ wchar_t BootPrfAlgorithmNameW[256];
+ GetBootEncryptionAlgorithmNameRequest *request = (GetBootEncryptionAlgorithmNameRequest *) irp->AssociatedIrp.SystemBuffer;
+ EAGetName (BootEncryptionAlgorithmNameW, BootDriveFilterExtension->Queue.CryptoInfo->ea, 0);
+ HashGetName2 (BootPrfAlgorithmNameW, BootDriveFilterExtension->Queue.CryptoInfo->pkcs5);
+
+ RtlStringCbPrintfA (request->BootEncryptionAlgorithmName, sizeof (request->BootEncryptionAlgorithmName), "%S", BootEncryptionAlgorithmNameW);
+ RtlStringCbPrintfA (request->BootPrfAlgorithmName, sizeof (request->BootPrfAlgorithmName), "%S", BootPrfAlgorithmNameW);
+
+ irp->IoStatus.Information = sizeof (GetBootEncryptionAlgorithmNameRequest);
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ irp->IoStatus.Information = 0;
+ }
+ }
+}
+
+
+NTSTATUS GetSetupResult()
+{
+ return SetupResult;
+}
+
+
+BOOL IsBootDriveMounted ()
+{
+ return BootDriveFilterExtension && BootDriveFilterExtension->DriveMounted;
+}
+
+
+BOOL IsBootEncryptionSetupInProgress ()
+{
+ return SetupInProgress;
+}
+
+
+BOOL IsHiddenSystemRunning ()
+{
+ return BootDriveFilterExtension && BootDriveFilterExtension->HiddenSystem;
+}
+
+
+DriveFilterExtension *GetBootDriveFilterExtension ()
+{
+ return BootDriveFilterExtension;
+}
+
+
+CRYPTO_INFO *GetSystemDriveCryptoInfo ()
+{
+ return BootDriveFilterExtension->Queue.CryptoInfo;
+}
+
+
+NTSTATUS AbortBootEncryptionSetup ()
+{
+ if (!IoIsSystemThread (PsGetCurrentThread()) && !UserCanAccessDriveDevice())
+ return STATUS_ACCESS_DENIED;
+
+ if (EncryptionSetupThread)
+ {
+ EncryptionSetupThreadAbortRequested = TRUE;
+
+ TCStopThread (EncryptionSetupThread, NULL);
+ EncryptionSetupThread = NULL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+static VOID DecoySystemWipeThreadProc (PVOID threadArg)
+{
+ DriveFilterExtension *Extension = BootDriveFilterExtension;
+
+ LARGE_INTEGER offset;
+ UINT64_STRUCT dataUnit;
+ ULONG wipeBlockSize = TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE;
+
+ CRYPTO_INFO *wipeCryptoInfo = NULL;
+ byte *wipeBuffer = NULL;
+ byte *wipeRandBuffer = NULL;
+ byte wipeRandChars[TC_WIPE_RAND_CHAR_COUNT];
+ int wipePass, wipePassCount;
+ int ea = Extension->Queue.CryptoInfo->ea;
+
+ KIRQL irql;
+ NTSTATUS status;
+
+ DecoySystemWipeResult = STATUS_UNSUCCESSFUL;
+
+ wipeBuffer = TCalloc (TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE);
+ if (!wipeBuffer)
+ {
+ DecoySystemWipeResult = STATUS_INSUFFICIENT_RESOURCES;
+ goto ret;
+ }
+
+ wipeRandBuffer = TCalloc (TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE);
+ if (!wipeRandBuffer)
+ {
+ DecoySystemWipeResult = STATUS_INSUFFICIENT_RESOURCES;
+ goto ret;
+ }
+
+ wipeCryptoInfo = crypto_open();
+ if (!wipeCryptoInfo)
+ {
+ DecoySystemWipeResult = STATUS_INSUFFICIENT_RESOURCES;
+ goto ret;
+ }
+
+ wipeCryptoInfo->ea = ea;
+ wipeCryptoInfo->mode = Extension->Queue.CryptoInfo->mode;
+
+ if (EAInit (ea, WipeDecoyRequest.WipeKey, wipeCryptoInfo->ks) != ERR_SUCCESS)
+ {
+ DecoySystemWipeResult = STATUS_INVALID_PARAMETER;
+ goto ret;
+ }
+
+ memcpy (wipeCryptoInfo->k2, WipeDecoyRequest.WipeKey + EAGetKeySize (ea), EAGetKeySize (ea));
+
+ if (!EAInitMode (wipeCryptoInfo))
+ {
+ DecoySystemWipeResult = STATUS_INVALID_PARAMETER;
+ goto err;
+ }
+
+ EncryptDataUnits (wipeRandBuffer, &dataUnit, wipeBlockSize / ENCRYPTION_DATA_UNIT_SIZE, wipeCryptoInfo);
+ memcpy (wipeRandChars, wipeRandBuffer, sizeof (wipeRandChars));
+
+ burn (WipeDecoyRequest.WipeKey, sizeof (WipeDecoyRequest.WipeKey));
+
+ offset.QuadPart = Extension->ConfiguredEncryptedAreaStart;
+
+ Dump ("Wiping decoy system: start offset = %I64d\n", offset.QuadPart);
+
+ while (!DecoySystemWipeThreadAbortRequested)
+ {
+ if (offset.QuadPart + wipeBlockSize > Extension->ConfiguredEncryptedAreaEnd + 1)
+ wipeBlockSize = (ULONG) (Extension->ConfiguredEncryptedAreaEnd + 1 - offset.QuadPart);
+
+ if (offset.QuadPart > Extension->ConfiguredEncryptedAreaEnd)
+ break;
+
+ wipePassCount = GetWipePassCount (WipeDecoyRequest.WipeAlgorithm);
+ if (wipePassCount <= 0)
+ {
+ DecoySystemWipeResult = STATUS_INVALID_PARAMETER;
+ goto err;
+ }
+
+ for (wipePass = 1; wipePass <= wipePassCount; ++wipePass)
+ {
+ if (!WipeBuffer (WipeDecoyRequest.WipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, wipeBlockSize))
+ {
+ dataUnit.Value = offset.QuadPart / ENCRYPTION_DATA_UNIT_SIZE;
+ EncryptDataUnits (wipeRandBuffer, &dataUnit, wipeBlockSize / ENCRYPTION_DATA_UNIT_SIZE, wipeCryptoInfo);
+ memcpy (wipeBuffer, wipeRandBuffer, wipeBlockSize);
+ }
+
+ while (!NT_SUCCESS (EncryptedIoQueueHoldWhenIdle (&Extension->Queue, 500)))
+ {
+ if (DecoySystemWipeThreadAbortRequested)
+ goto abort;
+ }
+
+ status = TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, wipeBuffer, offset, wipeBlockSize);
+
+ if (!NT_SUCCESS (status))
+ {
+ DecoySystemWipeResult = status;
+ goto err;
+ }
+
+ EncryptedIoQueueResumeFromHold (&Extension->Queue);
+ }
+
+ offset.QuadPart += wipeBlockSize;
+
+ KeAcquireSpinLock (&DecoySystemWipeStatusSpinLock, &irql);
+ DecoySystemWipedAreaEnd = offset.QuadPart - 1;
+ KeReleaseSpinLock (&DecoySystemWipeStatusSpinLock, irql);
+ }
+
+abort:
+ DecoySystemWipeResult = STATUS_SUCCESS;
+err:
+
+ if (EncryptedIoQueueIsSuspended (&Extension->Queue))
+ EncryptedIoQueueResumeFromHold (&Extension->Queue);
+
+ Dump ("Wipe end: DecoySystemWipedAreaEnd=%I64d (%I64d)\n", DecoySystemWipedAreaEnd, DecoySystemWipedAreaEnd / 1024 / 1024);
+
+ret:
+ if (wipeCryptoInfo)
+ crypto_close (wipeCryptoInfo);
+
+ if (wipeRandBuffer)
+ TCfree (wipeRandBuffer);
+
+ if (wipeBuffer)
+ TCfree (wipeBuffer);
+
+ DecoySystemWipeInProgress = FALSE;
+ PsTerminateSystemThread (DecoySystemWipeResult);
+}
+
+
+NTSTATUS StartDecoySystemWipe (PDEVICE_OBJECT DeviceObject, PIRP irp, PIO_STACK_LOCATION irpSp)
+{
+ NTSTATUS status;
+ WipeDecoySystemRequest *request;
+
+ if (!UserCanAccessDriveDevice())
+ return STATUS_ACCESS_DENIED;
+
+ if (!IsHiddenSystemRunning()
+ || irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (WipeDecoySystemRequest))
+ return STATUS_INVALID_PARAMETER;
+
+ if (DecoySystemWipeInProgress)
+ return STATUS_SUCCESS;
+
+ if (DecoySystemWipeThread)
+ AbortDecoySystemWipe();
+
+ request = (WipeDecoySystemRequest *) irp->AssociatedIrp.SystemBuffer;
+ WipeDecoyRequest = *request;
+
+ burn (request->WipeKey, sizeof (request->WipeKey));
+
+ DecoySystemWipeThreadAbortRequested = FALSE;
+ KeInitializeSpinLock (&DecoySystemWipeStatusSpinLock);
+ DecoySystemWipedAreaEnd = BootDriveFilterExtension->ConfiguredEncryptedAreaStart;
+
+ DecoySystemWipeInProgress = TRUE;
+ status = TCStartThread (DecoySystemWipeThreadProc, DeviceObject, &DecoySystemWipeThread);
+
+ if (!NT_SUCCESS (status))
+ DecoySystemWipeInProgress = FALSE;
+
+ return status;
+}
+
+
+BOOL IsDecoySystemWipeInProgress()
+{
+ return DecoySystemWipeInProgress;
+}
+
+
+void GetDecoySystemWipeStatus (PIRP irp, PIO_STACK_LOCATION irpSp)
+{
+ if (ValidateIOBufferSize (irp, sizeof (DecoySystemWipeStatus), ValidateOutput))
+ {
+ DecoySystemWipeStatus *wipeStatus = (DecoySystemWipeStatus *) irp->AssociatedIrp.SystemBuffer;
+
+ if (!IsHiddenSystemRunning())
+ {
+ irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ irp->IoStatus.Information = 0;
+ }
+ else
+ {
+ wipeStatus->WipeInProgress = DecoySystemWipeInProgress;
+ wipeStatus->WipeAlgorithm = WipeDecoyRequest.WipeAlgorithm;
+
+ if (DecoySystemWipeInProgress)
+ {
+ KIRQL irql;
+ KeAcquireSpinLock (&DecoySystemWipeStatusSpinLock, &irql);
+ wipeStatus->WipedAreaEnd = DecoySystemWipedAreaEnd;
+ KeReleaseSpinLock (&DecoySystemWipeStatusSpinLock, irql);
+ }
+ else
+ wipeStatus->WipedAreaEnd = DecoySystemWipedAreaEnd;
+
+ irp->IoStatus.Information = sizeof (DecoySystemWipeStatus);
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ }
+}
+
+
+NTSTATUS GetDecoySystemWipeResult()
+{
+ return DecoySystemWipeResult;
+}
+
+
+NTSTATUS AbortDecoySystemWipe ()
+{
+ if (!IoIsSystemThread (PsGetCurrentThread()) && !UserCanAccessDriveDevice())
+ return STATUS_ACCESS_DENIED;
+
+ if (DecoySystemWipeThread)
+ {
+ DecoySystemWipeThreadAbortRequested = TRUE;
+
+ TCStopThread (DecoySystemWipeThread, NULL);
+ DecoySystemWipeThread = NULL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+uint64 GetBootDriveLength ()
+{
+ return BootDriveLength.QuadPart;
+}
+
+
+NTSTATUS WriteBootDriveSector (PIRP irp, PIO_STACK_LOCATION irpSp)
+{
+ WriteBootDriveSectorRequest *request;
+
+ if (!UserCanAccessDriveDevice())
+ return STATUS_ACCESS_DENIED;
+
+ if (!BootDriveFilterExtension
+ || irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (WriteBootDriveSectorRequest))
+ return STATUS_INVALID_PARAMETER;
+
+ request = (WriteBootDriveSectorRequest *) irp->AssociatedIrp.SystemBuffer;
+ return TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, request->Data, request->Offset, sizeof (request->Data));
+}