diff options
author | David Foerster <david.foerster@informatik.hu-berlin.de> | 2016-05-10 20:20:14 +0200 |
---|---|---|
committer | David Foerster <david.foerster@informatik.hu-berlin.de> | 2016-05-10 20:20:14 +0200 |
commit | fc37cc4a02ed13d1a73b941a9f80975600fd1b99 (patch) | |
tree | ad9e5ac81111402b5c47dc06944cc5243824c4b5 /src/Driver/DriveFilter.c | |
parent | 98b04198c6ea5bc07cca50956809068adf1fea82 (diff) | |
download | VeraCrypt-fc37cc4a02ed13d1a73b941a9f80975600fd1b99.tar.gz VeraCrypt-fc37cc4a02ed13d1a73b941a9f80975600fd1b99.zip |
Normalize all line terminators
Diffstat (limited to 'src/Driver/DriveFilter.c')
-rw-r--r-- | src/Driver/DriveFilter.c | 4306 |
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)); +} |