VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Driver
diff options
context:
space:
mode:
authorDavid Foerster <david.foerster@informatik.hu-berlin.de>2016-05-10 20:20:14 +0200
committerDavid Foerster <david.foerster@informatik.hu-berlin.de>2016-05-10 20:20:14 +0200
commitfc37cc4a02ed13d1a73b941a9f80975600fd1b99 (patch)
treead9e5ac81111402b5c47dc06944cc5243824c4b5 /src/Driver
parent98b04198c6ea5bc07cca50956809068adf1fea82 (diff)
downloadVeraCrypt-fc37cc4a02ed13d1a73b941a9f80975600fd1b99.tar.gz
VeraCrypt-fc37cc4a02ed13d1a73b941a9f80975600fd1b99.zip
Normalize all line terminators
Diffstat (limited to 'src/Driver')
-rw-r--r--src/Driver/BuildDriver.cmd332
-rw-r--r--src/Driver/DriveFilter.c4306
-rw-r--r--src/Driver/DriveFilter.h180
-rw-r--r--src/Driver/Driver.rc202
-rw-r--r--src/Driver/Driver.vcproj796
-rw-r--r--src/Driver/DumpFilter.c496
-rw-r--r--src/Driver/DumpFilter.h50
-rw-r--r--src/Driver/EncryptedIoQueue.c2098
-rw-r--r--src/Driver/EncryptedIoQueue.h330
-rw-r--r--src/Driver/Makefile2
-rw-r--r--src/Driver/Ntdriver.c7126
-rw-r--r--src/Driver/Ntdriver.h378
-rw-r--r--src/Driver/Ntvol.c1800
-rw-r--r--src/Driver/Ntvol.h44
-rw-r--r--src/Driver/Resource.h32
-rw-r--r--src/Driver/Sources42
-rw-r--r--src/Driver/VolumeFilter.c598
-rw-r--r--src/Driver/VolumeFilter.h46
18 files changed, 9429 insertions, 9429 deletions
diff --git a/src/Driver/BuildDriver.cmd b/src/Driver/BuildDriver.cmd
index 99fe554b..bfeee2db 100644
--- a/src/Driver/BuildDriver.cmd
+++ b/src/Driver/BuildDriver.cmd
@@ -1,166 +1,166 @@
-::
-:: 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.
-::
-
-:: Usage: BuildDriver <-build|-rebuild|-clean> <-release|-debug> <-x86|-x64> <dir1> [dir2] ...
-
-@echo off
-set TC_ARG_CMD=%~1
-shift
-set TC_ARG_TYPE=%~1
-shift
-set TC_ARG_ARCH=%~1
-shift
-
-
-:: Windows Driver Kit build number
-
-set TC_WINDDK_BUILD=7600.16385.1
-
-
-:: Check for spaces in the current directory path
-
-cd | find " " >NUL:
-
-if %ERRORLEVEL% == 0 (
- echo BuildDriver.cmd: error: MS Build does not support building of projects stored in a path containing spaces. >&2
- exit /B 1
-)
-
-
-:: Build options
-
-set TC_C_DEFINES=-D_WIN32 -DTC_WINDOWS_DRIVER
-set TC_C_FLAGS=-nologo -I..
-set TC_C_WARNING_LEVEL=-W4
-set TC_C_DISABLED_WARNINGS=-wd4057 -wd4100 -wd4127 -wd4152 -wd4201 -wd4701 -wd4702 -wd4706
-set TC_LIBRARIAN_FLAGS=-nologo
-set TC_LINKER_FLAGS=-nologo
-set TC_TEST_SIGN=0
-
-
-:: Windows Driver Kit root
-
-set TC_WINDDK_ROOT=%SYSTEMDRIVE%\WinDDK\%TC_WINDDK_BUILD%
-if exist "%TC_WINDDK_ROOT%\bin\setenv.bat" goto ddk_found
-
-set TC_WINDDK_ROOT=%WINDDK_ROOT%\%TC_WINDDK_BUILD%
-if exist "%TC_WINDDK_ROOT%\bin\setenv.bat" goto ddk_found
-
-set TC_WINDDK_ROOT=%WINDDK_ROOT%
-if exist "%TC_WINDDK_ROOT%\bin\setenv.bat" goto ddk_found
-
-echo BuildDriver.cmd: error: Windows Driver Development Kit not found in the default directory. Set WINDDK_ROOT environment variable to point to your Windows DDK installation directory. >&2
-exit /B 1
-
-:ddk_found
-
-
-:: CPU architecture
-
-if "%TC_ARG_ARCH%"=="-x64" (
- set TC_BUILD_ARCH=x64 WNET
- set TC_BUILD_ARCH_DIR=amd64
- set TC_ARCH=x64
- set TC_ARCH_SUFFIX=-x64
- set TC_C_DISABLED_WARNINGS=%TC_C_DISABLED_WARNINGS% -wd4328 -wd4366
- set TC_LINKER_FLAGS=%TC_LINKER_FLAGS% -LTCG
- if defined TC_KERNEL_TEST_CERTIFICATE_NAME set TC_TEST_SIGN=1
-) else (
- set TC_BUILD_ARCH=WXP
- set TC_BUILD_ARCH_DIR=i386
- set TC_ARCH=x86
- set TC_ARCH_SUFFIX=
-)
-
-
-:: Build type
-
-if "%TC_ARG_TYPE%"=="-debug" (
- set TC_BUILD_TYPE=chk
- set TC_C_DEFINES=%TC_C_DEFINES% -DDEBUG -D_DEBUG
- set TC_BUILD_ALT_DIR=_driver_debug
- set TC_COPY_DIR="..\Debug"
-) else (
- set TC_BUILD_TYPE=fre
- set TC_BUILD_ALT_DIR=_driver_release
- set TC_COPY_DIR="..\Release"
- set TC_TEST_SIGN=0
-)
-
-
-:: WDK environment
-
-pushd .
-call %TC_WINDDK_ROOT%\bin\setenv %TC_WINDDK_ROOT% %TC_BUILD_TYPE% %TC_BUILD_ARCH% no_oacr || exit /B %errorlevel%
-popd
-
-
-:: Build
-
-if "%TC_ARG_CMD%"=="-rebuild" (set TC_BUILD_OPTS=-c -Z)
-
-pushd .
-:build_dirs
-
- if "%~1"=="" goto done
- cd /D "%~1" || exit /B %errorlevel%
-
- if "%TC_ARG_CMD%"=="-clean" (
- rd /s /q obj%TC_BUILD_ALT_DIR%\%TC_BUILD_ARCH_DIR% 2>NUL:
- rd /q obj%TC_BUILD_ALT_DIR% 2>NUL:
- ) else (
-
- set USER_C_FLAGS=%TC_C_FLAGS% %TC_C_DISABLED_WARNINGS% -FAcs -Fa%~1\obj%TC_BUILD_ALT_DIR%\%TC_BUILD_ARCH_DIR%\
- set MSC_WARNING_LEVEL=%TC_C_WARNING_LEVEL%
- set C_DEFINES=%TC_C_DEFINES%
- set RCOPTIONS=/I %MFC_INC_PATH%
- set LIBRARIAN_FLAGS=%TC_LIBRARIAN_FLAGS%
- set LINKER_FLAGS=%TC_LINKER_FLAGS%
- set BUILD_ALT_DIR=%TC_BUILD_ALT_DIR%
-
- build %TC_BUILD_OPTS% -w -nmake /S -nmake /C 2>build_errors.log 1>&2
-
- if errorlevel 1 (
- type build_errors.log
- type build_errors_asm.log 2>NUL:
- exit /B 1
- )
- del /q build_errors.log build_errors_asm.log build%BUILD_ALT_DIR%.* 2>NUL:
- )
-
- shift
-
-goto build_dirs
-:done
-popd
-
-
-if "%TC_ARG_CMD%"=="-clean" exit /B 0
-
-md "%TC_COPY_DIR%\Setup Files" >NUL: 2>NUL:
-copy /B /Y obj%TC_BUILD_ALT_DIR%\%TC_BUILD_ARCH_DIR%\veracrypt.sys "%TC_COPY_DIR%\Setup Files\veracrypt%TC_ARCH_SUFFIX%.sys" >NUL:
-
-if errorlevel 1 (
- echo BuildDriver.cmd: error: Cannot copy target. >&2
- exit /B 1
-)
-
-if %TC_TEST_SIGN% equ 1 (
- signtool sign /s "%TC_KERNEL_TEST_CERTIFICATE_STORE%" /n "%TC_KERNEL_TEST_CERTIFICATE_NAME%" "%TC_COPY_DIR%\Setup Files\veracrypt%TC_ARCH_SUFFIX%.sys" >NUL:
-
- if errorlevel 1 (
- echo BuildDriver.cmd: error: Cannot test-sign target. >&2
- exit /B 1
- )
-)
-
-exit /B 0
+::
+:: 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.
+::
+
+:: Usage: BuildDriver <-build|-rebuild|-clean> <-release|-debug> <-x86|-x64> <dir1> [dir2] ...
+
+@echo off
+set TC_ARG_CMD=%~1
+shift
+set TC_ARG_TYPE=%~1
+shift
+set TC_ARG_ARCH=%~1
+shift
+
+
+:: Windows Driver Kit build number
+
+set TC_WINDDK_BUILD=7600.16385.1
+
+
+:: Check for spaces in the current directory path
+
+cd | find " " >NUL:
+
+if %ERRORLEVEL% == 0 (
+ echo BuildDriver.cmd: error: MS Build does not support building of projects stored in a path containing spaces. >&2
+ exit /B 1
+)
+
+
+:: Build options
+
+set TC_C_DEFINES=-D_WIN32 -DTC_WINDOWS_DRIVER
+set TC_C_FLAGS=-nologo -I..
+set TC_C_WARNING_LEVEL=-W4
+set TC_C_DISABLED_WARNINGS=-wd4057 -wd4100 -wd4127 -wd4152 -wd4201 -wd4701 -wd4702 -wd4706
+set TC_LIBRARIAN_FLAGS=-nologo
+set TC_LINKER_FLAGS=-nologo
+set TC_TEST_SIGN=0
+
+
+:: Windows Driver Kit root
+
+set TC_WINDDK_ROOT=%SYSTEMDRIVE%\WinDDK\%TC_WINDDK_BUILD%
+if exist "%TC_WINDDK_ROOT%\bin\setenv.bat" goto ddk_found
+
+set TC_WINDDK_ROOT=%WINDDK_ROOT%\%TC_WINDDK_BUILD%
+if exist "%TC_WINDDK_ROOT%\bin\setenv.bat" goto ddk_found
+
+set TC_WINDDK_ROOT=%WINDDK_ROOT%
+if exist "%TC_WINDDK_ROOT%\bin\setenv.bat" goto ddk_found
+
+echo BuildDriver.cmd: error: Windows Driver Development Kit not found in the default directory. Set WINDDK_ROOT environment variable to point to your Windows DDK installation directory. >&2
+exit /B 1
+
+:ddk_found
+
+
+:: CPU architecture
+
+if "%TC_ARG_ARCH%"=="-x64" (
+ set TC_BUILD_ARCH=x64 WNET
+ set TC_BUILD_ARCH_DIR=amd64
+ set TC_ARCH=x64
+ set TC_ARCH_SUFFIX=-x64
+ set TC_C_DISABLED_WARNINGS=%TC_C_DISABLED_WARNINGS% -wd4328 -wd4366
+ set TC_LINKER_FLAGS=%TC_LINKER_FLAGS% -LTCG
+ if defined TC_KERNEL_TEST_CERTIFICATE_NAME set TC_TEST_SIGN=1
+) else (
+ set TC_BUILD_ARCH=WXP
+ set TC_BUILD_ARCH_DIR=i386
+ set TC_ARCH=x86
+ set TC_ARCH_SUFFIX=
+)
+
+
+:: Build type
+
+if "%TC_ARG_TYPE%"=="-debug" (
+ set TC_BUILD_TYPE=chk
+ set TC_C_DEFINES=%TC_C_DEFINES% -DDEBUG -D_DEBUG
+ set TC_BUILD_ALT_DIR=_driver_debug
+ set TC_COPY_DIR="..\Debug"
+) else (
+ set TC_BUILD_TYPE=fre
+ set TC_BUILD_ALT_DIR=_driver_release
+ set TC_COPY_DIR="..\Release"
+ set TC_TEST_SIGN=0
+)
+
+
+:: WDK environment
+
+pushd .
+call %TC_WINDDK_ROOT%\bin\setenv %TC_WINDDK_ROOT% %TC_BUILD_TYPE% %TC_BUILD_ARCH% no_oacr || exit /B %errorlevel%
+popd
+
+
+:: Build
+
+if "%TC_ARG_CMD%"=="-rebuild" (set TC_BUILD_OPTS=-c -Z)
+
+pushd .
+:build_dirs
+
+ if "%~1"=="" goto done
+ cd /D "%~1" || exit /B %errorlevel%
+
+ if "%TC_ARG_CMD%"=="-clean" (
+ rd /s /q obj%TC_BUILD_ALT_DIR%\%TC_BUILD_ARCH_DIR% 2>NUL:
+ rd /q obj%TC_BUILD_ALT_DIR% 2>NUL:
+ ) else (
+
+ set USER_C_FLAGS=%TC_C_FLAGS% %TC_C_DISABLED_WARNINGS% -FAcs -Fa%~1\obj%TC_BUILD_ALT_DIR%\%TC_BUILD_ARCH_DIR%\
+ set MSC_WARNING_LEVEL=%TC_C_WARNING_LEVEL%
+ set C_DEFINES=%TC_C_DEFINES%
+ set RCOPTIONS=/I %MFC_INC_PATH%
+ set LIBRARIAN_FLAGS=%TC_LIBRARIAN_FLAGS%
+ set LINKER_FLAGS=%TC_LINKER_FLAGS%
+ set BUILD_ALT_DIR=%TC_BUILD_ALT_DIR%
+
+ build %TC_BUILD_OPTS% -w -nmake /S -nmake /C 2>build_errors.log 1>&2
+
+ if errorlevel 1 (
+ type build_errors.log
+ type build_errors_asm.log 2>NUL:
+ exit /B 1
+ )
+ del /q build_errors.log build_errors_asm.log build%BUILD_ALT_DIR%.* 2>NUL:
+ )
+
+ shift
+
+goto build_dirs
+:done
+popd
+
+
+if "%TC_ARG_CMD%"=="-clean" exit /B 0
+
+md "%TC_COPY_DIR%\Setup Files" >NUL: 2>NUL:
+copy /B /Y obj%TC_BUILD_ALT_DIR%\%TC_BUILD_ARCH_DIR%\veracrypt.sys "%TC_COPY_DIR%\Setup Files\veracrypt%TC_ARCH_SUFFIX%.sys" >NUL:
+
+if errorlevel 1 (
+ echo BuildDriver.cmd: error: Cannot copy target. >&2
+ exit /B 1
+)
+
+if %TC_TEST_SIGN% equ 1 (
+ signtool sign /s "%TC_KERNEL_TEST_CERTIFICATE_STORE%" /n "%TC_KERNEL_TEST_CERTIFICATE_NAME%" "%TC_COPY_DIR%\Setup Files\veracrypt%TC_ARCH_SUFFIX%.sys" >NUL:
+
+ if errorlevel 1 (
+ echo BuildDriver.cmd: error: Cannot test-sign target. >&2
+ exit /B 1
+ )
+)
+
+exit /B 0
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));
+}
diff --git a/src/Driver/DriveFilter.h b/src/Driver/DriveFilter.h
index 50dcabfd..e0c1bdff 100644
--- a/src/Driver/DriveFilter.h
+++ b/src/Driver/DriveFilter.h
@@ -1,90 +1,90 @@
-/*
- 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.
-*/
-
-#ifndef TC_HEADER_DRIVER_DRIVE_FILTER
-#define TC_HEADER_DRIVER_DRIVE_FILTER
-
-#include "TCdefs.h"
-#include "Boot/Windows/BootCommon.h"
-#include "EncryptedIoQueue.h"
-
-typedef struct _DriveFilterExtension
-{
- BOOL bRootDevice;
- BOOL IsVolumeDevice;
- BOOL IsDriveFilterDevice;
- BOOL IsVolumeFilterDevice;
- uint64 MagicNumber;
-
- PDEVICE_OBJECT DeviceObject;
- PDEVICE_OBJECT LowerDeviceObject;
- PDEVICE_OBJECT Pdo;
-
- ULONG SystemStorageDeviceNumber;
- BOOL SystemStorageDeviceNumberValid;
-
- int64 ConfiguredEncryptedAreaStart;
- int64 ConfiguredEncryptedAreaEnd;
-
- uint32 VolumeHeaderSaltCrc32;
- EncryptedIoQueue Queue;
-
- BOOL BootDrive;
- BOOL VolumeHeaderPresent;
- BOOL DriveMounted;
-
- KEVENT MountWorkItemCompletedEvent;
-
- CRYPTO_INFO *HeaderCryptoInfo;
- BOOL HiddenSystem;
-
-} DriveFilterExtension;
-
-#define TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER 0x5645524142455854
-
-extern BOOL BootArgsValid;
-extern BootArguments BootArgs;
-extern PKTHREAD EncryptionSetupThread;
-extern PKTHREAD DecoySystemWipeThread;
-
-NTSTATUS AbortBootEncryptionSetup ();
-NTSTATUS DriveFilterAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo);
-NTSTATUS DriveFilterDispatchIrp (PDEVICE_OBJECT DeviceObject, PIRP Irp);
-void GetBootDriveVolumeProperties (PIRP irp, PIO_STACK_LOCATION irpSp);
-void GetBootEncryptionAlgorithmName (PIRP irp, PIO_STACK_LOCATION irpSp);
-void GetBootEncryptionStatus (PIRP irp, PIO_STACK_LOCATION irpSp);
-void GetBootLoaderVersion (PIRP irp, PIO_STACK_LOCATION irpSp);
-void GetBootLoaderFingerprint (PIRP irp, PIO_STACK_LOCATION irpSp);
-NTSTATUS GetSetupResult ();
-DriveFilterExtension *GetBootDriveFilterExtension ();
-CRYPTO_INFO *GetSystemDriveCryptoInfo ();
-BOOL IsBootDriveMounted ();
-BOOL IsBootEncryptionSetupInProgress ();
-BOOL IsHiddenSystemRunning ();
-NTSTATUS LoadBootArguments ();
-static NTSTATUS SaveDriveVolumeHeader (DriveFilterExtension *Extension);
-NTSTATUS StartBootEncryptionSetup (PDEVICE_OBJECT DeviceObject, PIRP irp, PIO_STACK_LOCATION irpSp);
-void ReopenBootVolumeHeader (PIRP irp, PIO_STACK_LOCATION irpSp);
-NTSTATUS StartDecoySystemWipe (PDEVICE_OBJECT DeviceObject, PIRP irp, PIO_STACK_LOCATION irpSp);
-void StartLegacyHibernationDriverFilter ();
-NTSTATUS AbortDecoySystemWipe ();
-BOOL IsDecoySystemWipeInProgress();
-NTSTATUS GetDecoySystemWipeResult();
-void GetDecoySystemWipeStatus (PIRP irp, PIO_STACK_LOCATION irpSp);
-uint64 GetBootDriveLength ();
-NTSTATUS WriteBootDriveSector (PIRP irp, PIO_STACK_LOCATION irpSp);
-
-#define TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE (1536 * 1024)
-#define TC_ENCRYPTION_SETUP_HEADER_UPDATE_THRESHOLD (64 * 1024 * 1024)
-#define TC_HIBERNATION_WRITE_BUFFER_SIZE (128 * 1024)
-
-#endif // TC_HEADER_DRIVER_DRIVE_FILTER
+/*
+ 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.
+*/
+
+#ifndef TC_HEADER_DRIVER_DRIVE_FILTER
+#define TC_HEADER_DRIVER_DRIVE_FILTER
+
+#include "TCdefs.h"
+#include "Boot/Windows/BootCommon.h"
+#include "EncryptedIoQueue.h"
+
+typedef struct _DriveFilterExtension
+{
+ BOOL bRootDevice;
+ BOOL IsVolumeDevice;
+ BOOL IsDriveFilterDevice;
+ BOOL IsVolumeFilterDevice;
+ uint64 MagicNumber;
+
+ PDEVICE_OBJECT DeviceObject;
+ PDEVICE_OBJECT LowerDeviceObject;
+ PDEVICE_OBJECT Pdo;
+
+ ULONG SystemStorageDeviceNumber;
+ BOOL SystemStorageDeviceNumberValid;
+
+ int64 ConfiguredEncryptedAreaStart;
+ int64 ConfiguredEncryptedAreaEnd;
+
+ uint32 VolumeHeaderSaltCrc32;
+ EncryptedIoQueue Queue;
+
+ BOOL BootDrive;
+ BOOL VolumeHeaderPresent;
+ BOOL DriveMounted;
+
+ KEVENT MountWorkItemCompletedEvent;
+
+ CRYPTO_INFO *HeaderCryptoInfo;
+ BOOL HiddenSystem;
+
+} DriveFilterExtension;
+
+#define TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER 0x5645524142455854
+
+extern BOOL BootArgsValid;
+extern BootArguments BootArgs;
+extern PKTHREAD EncryptionSetupThread;
+extern PKTHREAD DecoySystemWipeThread;
+
+NTSTATUS AbortBootEncryptionSetup ();
+NTSTATUS DriveFilterAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo);
+NTSTATUS DriveFilterDispatchIrp (PDEVICE_OBJECT DeviceObject, PIRP Irp);
+void GetBootDriveVolumeProperties (PIRP irp, PIO_STACK_LOCATION irpSp);
+void GetBootEncryptionAlgorithmName (PIRP irp, PIO_STACK_LOCATION irpSp);
+void GetBootEncryptionStatus (PIRP irp, PIO_STACK_LOCATION irpSp);
+void GetBootLoaderVersion (PIRP irp, PIO_STACK_LOCATION irpSp);
+void GetBootLoaderFingerprint (PIRP irp, PIO_STACK_LOCATION irpSp);
+NTSTATUS GetSetupResult ();
+DriveFilterExtension *GetBootDriveFilterExtension ();
+CRYPTO_INFO *GetSystemDriveCryptoInfo ();
+BOOL IsBootDriveMounted ();
+BOOL IsBootEncryptionSetupInProgress ();
+BOOL IsHiddenSystemRunning ();
+NTSTATUS LoadBootArguments ();
+static NTSTATUS SaveDriveVolumeHeader (DriveFilterExtension *Extension);
+NTSTATUS StartBootEncryptionSetup (PDEVICE_OBJECT DeviceObject, PIRP irp, PIO_STACK_LOCATION irpSp);
+void ReopenBootVolumeHeader (PIRP irp, PIO_STACK_LOCATION irpSp);
+NTSTATUS StartDecoySystemWipe (PDEVICE_OBJECT DeviceObject, PIRP irp, PIO_STACK_LOCATION irpSp);
+void StartLegacyHibernationDriverFilter ();
+NTSTATUS AbortDecoySystemWipe ();
+BOOL IsDecoySystemWipeInProgress();
+NTSTATUS GetDecoySystemWipeResult();
+void GetDecoySystemWipeStatus (PIRP irp, PIO_STACK_LOCATION irpSp);
+uint64 GetBootDriveLength ();
+NTSTATUS WriteBootDriveSector (PIRP irp, PIO_STACK_LOCATION irpSp);
+
+#define TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE (1536 * 1024)
+#define TC_ENCRYPTION_SETUP_HEADER_UPDATE_THRESHOLD (64 * 1024 * 1024)
+#define TC_HIBERNATION_WRITE_BUFFER_SIZE (128 * 1024)
+
+#endif // TC_HEADER_DRIVER_DRIVE_FILTER
diff --git a/src/Driver/Driver.rc b/src/Driver/Driver.rc
index d9591d51..51030c5c 100644
--- a/src/Driver/Driver.rc
+++ b/src/Driver/Driver.rc
@@ -1,101 +1,101 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,17,22,0
- PRODUCTVERSION 1,17,22,0
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x3L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "CompanyName", "IDRIX"
- VALUE "FileDescription", "VeraCrypt Driver"
- VALUE "FileVersion", "1.17"
- VALUE "LegalTrademarks", "VeraCrypt"
- VALUE "OriginalFilename", "veracrypt.sys"
- VALUE "ProductName", "VeraCrypt"
- VALUE "ProductVersion", "1.17"
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE
-BEGIN
- "resource.h\0"
-END
-
-2 TEXTINCLUDE
-BEGIN
- "#include ""afxres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,17,22,0
+ PRODUCTVERSION 1,17,22,0
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x3L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "IDRIX"
+ VALUE "FileDescription", "VeraCrypt Driver"
+ VALUE "FileVersion", "1.17"
+ VALUE "LegalTrademarks", "VeraCrypt"
+ VALUE "OriginalFilename", "veracrypt.sys"
+ VALUE "ProductName", "VeraCrypt"
+ VALUE "ProductVersion", "1.17"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/Driver/Driver.vcproj b/src/Driver/Driver.vcproj
index 8d28d753..4c474c36 100644
--- a/src/Driver/Driver.vcproj
+++ b/src/Driver/Driver.vcproj
@@ -1,398 +1,398 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="Driver"
- ProjectGUID="{EF5EF444-18D0-40D7-8DFA-775EC4448602}"
- RootNamespace="Driver"
- Keyword="MakeFileProj"
- TargetFrameworkVersion="131072"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="Debug"
- ConfigurationType="0"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- >
- <Tool
- Name="VCNMakeTool"
- BuildCommandLine="echo ------ Building veracrypt.sys: Debug x86 ------&#x0D;&#x0A;cmd.exe /c BuildDriver.cmd -build -debug -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit %errorlevel%&#x0D;&#x0A;echo.&#x0D;&#x0A;echo ------ Building veracrypt.sys: Debug x64 ------&#x0D;&#x0A;BuildDriver.cmd -build -debug -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- ReBuildCommandLine="echo ------ Rebuilding veracrypt.sys: Debug x86 ------&#x0D;&#x0A;cmd.exe /c BuildDriver.cmd -rebuild -debug -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit %errorlevel%&#x0D;&#x0A;echo.&#x0D;&#x0A;echo ------ Rebuilding veracrypt.sys: Debug x64 ------&#x0D;&#x0A;BuildDriver.cmd -rebuild -debug -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- CleanCommandLine="echo ------ Cleaning veracrypt.sys: Debug x86 ------&#x0D;&#x0A;cmd.exe /c BuildDriver.cmd -clean -debug -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit %errorlevel%&#x0D;&#x0A;echo.&#x0D;&#x0A;echo ------ Cleaning veracrypt.sys: Debug x64 ------&#x0D;&#x0A;BuildDriver.cmd -clean -debug -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- Output=""
- PreprocessorDefinitions="DEBUG;_DEBUG;TC_WINDOWS_DRIVER"
- IncludeSearchPath="&quot;$(ProjectDir)&quot;;&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(WINDDK_ROOT)\inc\ddk&quot;;&quot;$(WINDDK_ROOT)\inc\api&quot;"
- ForcedIncludes=""
- AssemblySearchPath=""
- ForcedUsingAssemblies=""
- CompileAsManaged=""
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="Release"
- ConfigurationType="0"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- >
- <Tool
- Name="VCNMakeTool"
- BuildCommandLine="echo ------ Building veracrypt.sys: Release x86 ------&#x0D;&#x0A;cmd.exe /c BuildDriver.cmd -build -release -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit %errorlevel%&#x0D;&#x0A;echo.&#x0D;&#x0A;echo ------ Building veracrypt.sys: Release x64 ------&#x0D;&#x0A;BuildDriver.cmd -build -release -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- ReBuildCommandLine="echo ------ Rebuilding veracrypt.sys: Release x86 ------&#x0D;&#x0A;cmd.exe /c BuildDriver.cmd -rebuild -release -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit %errorlevel%&#x0D;&#x0A;echo.&#x0D;&#x0A;echo ------ Rebuilding veracrypt.sys: Release x64 ------&#x0D;&#x0A;BuildDriver.cmd -rebuild -release -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- CleanCommandLine="echo ------ Cleaning veracrypt.sys: Release x86 ------&#x0D;&#x0A;cmd.exe /c BuildDriver.cmd -clean -release -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit %errorlevel%&#x0D;&#x0A;echo.&#x0D;&#x0A;echo ------ Cleaning veracrypt.sys: Release x64 ------&#x0D;&#x0A;BuildDriver.cmd -clean -release -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- Output=""
- PreprocessorDefinitions="TC_WINDOWS_DRIVER"
- IncludeSearchPath="&quot;$(ProjectDir)&quot;;&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(WINDDK_ROOT)\inc\ddk&quot;;&quot;$(WINDDK_ROOT)\inc\api&quot;"
- ForcedIncludes=""
- AssemblySearchPath=""
- ForcedUsingAssemblies=""
- CompileAsManaged=""
- />
- </Configuration>
- <Configuration
- Name="Release x86|Win32"
- OutputDirectory="$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="0"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- >
- <Tool
- Name="VCNMakeTool"
- BuildCommandLine="BuildDriver.cmd -build -release -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- ReBuildCommandLine="BuildDriver.cmd -rebuild -release -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- CleanCommandLine="BuildDriver.cmd -clean -release -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- Output=""
- PreprocessorDefinitions="TC_WINDOWS_DRIVER"
- IncludeSearchPath="&quot;$(ProjectDir)&quot;;&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(WINDDK_ROOT)\inc\ddk&quot;;&quot;$(WINDDK_ROOT)\inc\api&quot;"
- ForcedIncludes=""
- AssemblySearchPath=""
- ForcedUsingAssemblies=""
- CompileAsManaged=""
- />
- </Configuration>
- <Configuration
- Name="Debug x86|Win32"
- OutputDirectory="$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="0"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- >
- <Tool
- Name="VCNMakeTool"
- BuildCommandLine="if exist $(SolutionDir)\Mount\Debug\VeraCrypt.exe ( copy $(SolutionDir)\Mount\Debug\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\i386\VeraCrypt.exe &gt;NUL:&#x0D;&#x0A;) else ( copy $(SolutionDir)\Mount\Release\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\i386\VeraCrypt.exe &gt;NUL: )&#x0D;&#x0A;&#x0D;&#x0A;BuildDriver.cmd -build -debug -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- ReBuildCommandLine="if exist $(SolutionDir)\Mount\Debug\VeraCrypt.exe ( copy $(SolutionDir)\Mount\Debug\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\i386\VeraCrypt.exe &gt;NUL:&#x0D;&#x0A;) else ( copy $(SolutionDir)\Mount\Release\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\i386\VeraCrypt.exe &gt;NUL: )&#x0D;&#x0A;&#x0D;&#x0A;BuildDriver.cmd -rebuild -debug -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- CleanCommandLine="BuildDriver.cmd -clean -debug -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- Output="$(ProjectDir)\obj_driver_debug\i386\VeraCrypt.exe"
- PreprocessorDefinitions="DEBUG;_DEBUG;TC_WINDOWS_DRIVER"
- IncludeSearchPath="&quot;$(ProjectDir)&quot;;&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(WINDDK_ROOT)\inc\ddk&quot;;&quot;$(WINDDK_ROOT)\inc\api&quot;"
- ForcedIncludes=""
- AssemblySearchPath=""
- ForcedUsingAssemblies=""
- CompileAsManaged=""
- />
- </Configuration>
- <Configuration
- Name="Release x64|Win32"
- OutputDirectory="$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="0"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- >
- <Tool
- Name="VCNMakeTool"
- BuildCommandLine="BuildDriver.cmd -build -release -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- ReBuildCommandLine="BuildDriver.cmd -rebuild -release -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- CleanCommandLine="BuildDriver.cmd -clean -release -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- Output=""
- PreprocessorDefinitions="TC_WINDOWS_DRIVER"
- IncludeSearchPath="&quot;$(ProjectDir)&quot;;&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(WINDDK_ROOT)\inc\ddk&quot;;&quot;$(WINDDK_ROOT)\inc\api&quot;"
- ForcedIncludes=""
- AssemblySearchPath=""
- ForcedUsingAssemblies=""
- CompileAsManaged=""
- />
- </Configuration>
- <Configuration
- Name="Debug x64|Win32"
- OutputDirectory="$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="0"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- >
- <Tool
- Name="VCNMakeTool"
- BuildCommandLine="if exist $(SolutionDir)\Mount\Debug\VeraCrypt.exe ( copy $(SolutionDir)\Mount\Debug\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\amd64\VeraCrypt.exe &gt;NUL:&#x0D;&#x0A;) else ( copy $(SolutionDir)\Mount\Release\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\amd64\VeraCrypt.exe &gt;NUL: )&#x0D;&#x0A;&#x0D;&#x0A;BuildDriver.cmd -build -debug -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- ReBuildCommandLine="if exist $(SolutionDir)\Mount\Debug\VeraCrypt.exe ( copy $(SolutionDir)\Mount\Debug\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\amd64\VeraCrypt.exe &gt;NUL:&#x0D;&#x0A;) else ( copy $(SolutionDir)\Mount\Release\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\amd64\VeraCrypt.exe &gt;NUL: )&#x0D;&#x0A;&#x0D;&#x0A;BuildDriver.cmd -rebuild -debug -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- CleanCommandLine="BuildDriver.cmd -clean -debug -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
- Output="$(ProjectDir)\obj_driver_debug\amd64\VeraCrypt.exe"
- PreprocessorDefinitions="DEBUG;_DEBUG;TC_WINDOWS_DRIVER"
- IncludeSearchPath="&quot;$(ProjectDir)&quot;;&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(WINDDK_ROOT)\inc\ddk&quot;;&quot;$(WINDDK_ROOT)\inc\api&quot;"
- ForcedIncludes=""
- AssemblySearchPath=""
- ForcedUsingAssemblies=""
- CompileAsManaged=""
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
- >
- <File
- RelativePath=".\DriveFilter.c"
- >
- </File>
- <File
- RelativePath=".\DumpFilter.c"
- >
- </File>
- <File
- RelativePath=".\EncryptedIoQueue.c"
- >
- </File>
- <File
- RelativePath=".\Ntdriver.c"
- >
- </File>
- <File
- RelativePath=".\Ntvol.c"
- >
- </File>
- <File
- RelativePath=".\VolumeFilter.c"
- >
- </File>
- <Filter
- Name="Common"
- >
- <File
- RelativePath="..\Common\Cache.c"
- >
- </File>
- <File
- RelativePath="..\Common\Crc.c"
- >
- </File>
- <File
- RelativePath="..\Common\Crypto.c"
- >
- </File>
- <File
- RelativePath="..\Common\EncryptionThreadPool.c"
- >
- </File>
- <File
- RelativePath="..\Common\Endian.c"
- >
- </File>
- <File
- RelativePath="..\Common\GfMul.c"
- >
- </File>
- <File
- RelativePath="..\Common\Pkcs5.c"
- >
- </File>
- <File
- RelativePath="..\Common\Tests.c"
- >
- </File>
- <File
- RelativePath="..\Common\Volumes.c"
- >
- </File>
- <File
- RelativePath="..\Common\Wipe.c"
- >
- </File>
- <File
- RelativePath="..\Common\Xts.c"
- >
- </File>
- </Filter>
- <Filter
- Name="Crypto"
- >
- <File
- RelativePath="..\Crypto\Aes_hw_cpu.asm"
- >
- </File>
- <File
- RelativePath="..\Crypto\Aes_x64.asm"
- >
- </File>
- <File
- RelativePath="..\Crypto\Aes_x86.asm"
- >
- </File>
- <File
- RelativePath="..\Crypto\Aeskey.c"
- >
- </File>
- <File
- RelativePath="..\Crypto\Aestab.c"
- >
- </File>
- <File
- RelativePath="..\Crypto\Rmd160.c"
- >
- </File>
- <File
- RelativePath="..\Crypto\Serpent.c"
- >
- </File>
- <File
- RelativePath="..\Crypto\Sha2.c"
- >
- </File>
- <File
- RelativePath="..\Crypto\Twofish.c"
- >
- </File>
- <File
- RelativePath="..\Crypto\Whirlpool.c"
- >
- </File>
- </Filter>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl;inc;xsd"
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
- >
- <File
- RelativePath="..\Common\Apidrvr.h"
- >
- </File>
- <File
- RelativePath="..\Common\Cache.h"
- >
- </File>
- <File
- RelativePath="..\Common\Common.h"
- >
- </File>
- <File
- RelativePath=".\DriveFilter.h"
- >
- </File>
- <File
- RelativePath=".\DumpFilter.h"
- >
- </File>
- <File
- RelativePath=".\EncryptedIoQueue.h"
- >
- </File>
- <File
- RelativePath="..\Common\EncryptionThreadPool.h"
- >
- </File>
- <File
- RelativePath="..\Common\GfMul.h"
- >
- </File>
- <File
- RelativePath=".\Ntdriver.h"
- >
- </File>
- <File
- RelativePath=".\Ntvol.h"
- >
- </File>
- <File
- RelativePath=".\resource.h"
- >
- </File>
- <File
- RelativePath="..\Common\Tcdefs.h"
- >
- </File>
- <File
- RelativePath=".\VolumeFilter.h"
- >
- </File>
- <File
- RelativePath="..\Common\Volumes.h"
- >
- </File>
- <File
- RelativePath="..\Common\Wipe.h"
- >
- </File>
- <File
- RelativePath="..\Common\Xts.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
- >
- <File
- RelativePath=".\Driver.rc"
- >
- </File>
- </Filter>
- <Filter
- Name="Build Files"
- >
- <File
- RelativePath=".\BuildDriver.cmd"
- >
- </File>
- <File
- RelativePath=".\Makefile"
- >
- </File>
- <File
- RelativePath=".\Sources"
- >
- </File>
- <Filter
- Name="Common"
- >
- <File
- RelativePath="..\Common\Makefile"
- >
- </File>
- <File
- RelativePath="..\Common\Sources"
- >
- </File>
- </Filter>
- <Filter
- Name="Crypto"
- >
- <File
- RelativePath="..\Crypto\Makefile"
- >
- </File>
- <File
- RelativePath="..\Crypto\Makefile.inc"
- >
- </File>
- <File
- RelativePath="..\Crypto\Sources"
- >
- </File>
- </Filter>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="Driver"
+ ProjectGUID="{EF5EF444-18D0-40D7-8DFA-775EC4448602}"
+ RootNamespace="Driver"
+ Keyword="MakeFileProj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="0"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="echo ------ Building veracrypt.sys: Debug x86 ------&#x0D;&#x0A;cmd.exe /c BuildDriver.cmd -build -debug -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit %errorlevel%&#x0D;&#x0A;echo.&#x0D;&#x0A;echo ------ Building veracrypt.sys: Debug x64 ------&#x0D;&#x0A;BuildDriver.cmd -build -debug -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ ReBuildCommandLine="echo ------ Rebuilding veracrypt.sys: Debug x86 ------&#x0D;&#x0A;cmd.exe /c BuildDriver.cmd -rebuild -debug -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit %errorlevel%&#x0D;&#x0A;echo.&#x0D;&#x0A;echo ------ Rebuilding veracrypt.sys: Debug x64 ------&#x0D;&#x0A;BuildDriver.cmd -rebuild -debug -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ CleanCommandLine="echo ------ Cleaning veracrypt.sys: Debug x86 ------&#x0D;&#x0A;cmd.exe /c BuildDriver.cmd -clean -debug -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit %errorlevel%&#x0D;&#x0A;echo.&#x0D;&#x0A;echo ------ Cleaning veracrypt.sys: Debug x64 ------&#x0D;&#x0A;BuildDriver.cmd -clean -debug -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ Output=""
+ PreprocessorDefinitions="DEBUG;_DEBUG;TC_WINDOWS_DRIVER"
+ IncludeSearchPath="&quot;$(ProjectDir)&quot;;&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(WINDDK_ROOT)\inc\ddk&quot;;&quot;$(WINDDK_ROOT)\inc\api&quot;"
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="0"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="echo ------ Building veracrypt.sys: Release x86 ------&#x0D;&#x0A;cmd.exe /c BuildDriver.cmd -build -release -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit %errorlevel%&#x0D;&#x0A;echo.&#x0D;&#x0A;echo ------ Building veracrypt.sys: Release x64 ------&#x0D;&#x0A;BuildDriver.cmd -build -release -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ ReBuildCommandLine="echo ------ Rebuilding veracrypt.sys: Release x86 ------&#x0D;&#x0A;cmd.exe /c BuildDriver.cmd -rebuild -release -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit %errorlevel%&#x0D;&#x0A;echo.&#x0D;&#x0A;echo ------ Rebuilding veracrypt.sys: Release x64 ------&#x0D;&#x0A;BuildDriver.cmd -rebuild -release -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ CleanCommandLine="echo ------ Cleaning veracrypt.sys: Release x86 ------&#x0D;&#x0A;cmd.exe /c BuildDriver.cmd -clean -release -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit %errorlevel%&#x0D;&#x0A;echo.&#x0D;&#x0A;echo ------ Cleaning veracrypt.sys: Release x64 ------&#x0D;&#x0A;BuildDriver.cmd -clean -release -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ Output=""
+ PreprocessorDefinitions="TC_WINDOWS_DRIVER"
+ IncludeSearchPath="&quot;$(ProjectDir)&quot;;&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(WINDDK_ROOT)\inc\ddk&quot;;&quot;$(WINDDK_ROOT)\inc\api&quot;"
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release x86|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="0"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="BuildDriver.cmd -build -release -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ ReBuildCommandLine="BuildDriver.cmd -rebuild -release -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ CleanCommandLine="BuildDriver.cmd -clean -release -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ Output=""
+ PreprocessorDefinitions="TC_WINDOWS_DRIVER"
+ IncludeSearchPath="&quot;$(ProjectDir)&quot;;&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(WINDDK_ROOT)\inc\ddk&quot;;&quot;$(WINDDK_ROOT)\inc\api&quot;"
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug x86|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="0"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="if exist $(SolutionDir)\Mount\Debug\VeraCrypt.exe ( copy $(SolutionDir)\Mount\Debug\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\i386\VeraCrypt.exe &gt;NUL:&#x0D;&#x0A;) else ( copy $(SolutionDir)\Mount\Release\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\i386\VeraCrypt.exe &gt;NUL: )&#x0D;&#x0A;&#x0D;&#x0A;BuildDriver.cmd -build -debug -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ ReBuildCommandLine="if exist $(SolutionDir)\Mount\Debug\VeraCrypt.exe ( copy $(SolutionDir)\Mount\Debug\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\i386\VeraCrypt.exe &gt;NUL:&#x0D;&#x0A;) else ( copy $(SolutionDir)\Mount\Release\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\i386\VeraCrypt.exe &gt;NUL: )&#x0D;&#x0A;&#x0D;&#x0A;BuildDriver.cmd -rebuild -debug -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ CleanCommandLine="BuildDriver.cmd -clean -debug -x86 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ Output="$(ProjectDir)\obj_driver_debug\i386\VeraCrypt.exe"
+ PreprocessorDefinitions="DEBUG;_DEBUG;TC_WINDOWS_DRIVER"
+ IncludeSearchPath="&quot;$(ProjectDir)&quot;;&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(WINDDK_ROOT)\inc\ddk&quot;;&quot;$(WINDDK_ROOT)\inc\api&quot;"
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release x64|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="0"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="BuildDriver.cmd -build -release -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ ReBuildCommandLine="BuildDriver.cmd -rebuild -release -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ CleanCommandLine="BuildDriver.cmd -clean -release -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ Output=""
+ PreprocessorDefinitions="TC_WINDOWS_DRIVER"
+ IncludeSearchPath="&quot;$(ProjectDir)&quot;;&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(WINDDK_ROOT)\inc\ddk&quot;;&quot;$(WINDDK_ROOT)\inc\api&quot;"
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug x64|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="0"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="if exist $(SolutionDir)\Mount\Debug\VeraCrypt.exe ( copy $(SolutionDir)\Mount\Debug\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\amd64\VeraCrypt.exe &gt;NUL:&#x0D;&#x0A;) else ( copy $(SolutionDir)\Mount\Release\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\amd64\VeraCrypt.exe &gt;NUL: )&#x0D;&#x0A;&#x0D;&#x0A;BuildDriver.cmd -build -debug -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ ReBuildCommandLine="if exist $(SolutionDir)\Mount\Debug\VeraCrypt.exe ( copy $(SolutionDir)\Mount\Debug\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\amd64\VeraCrypt.exe &gt;NUL:&#x0D;&#x0A;) else ( copy $(SolutionDir)\Mount\Release\VeraCrypt.exe $(ProjectDir)\obj_driver_debug\amd64\VeraCrypt.exe &gt;NUL: )&#x0D;&#x0A;&#x0D;&#x0A;BuildDriver.cmd -rebuild -debug -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ CleanCommandLine="BuildDriver.cmd -clean -debug -x64 &quot;$(SolutionDir)\Common&quot; &quot;$(SolutionDir)\Crypto&quot; &quot;$(ProjectDir)&quot;"
+ Output="$(ProjectDir)\obj_driver_debug\amd64\VeraCrypt.exe"
+ PreprocessorDefinitions="DEBUG;_DEBUG;TC_WINDOWS_DRIVER"
+ IncludeSearchPath="&quot;$(ProjectDir)&quot;;&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(WINDDK_ROOT)\inc\ddk&quot;;&quot;$(WINDDK_ROOT)\inc\api&quot;"
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\DriveFilter.c"
+ >
+ </File>
+ <File
+ RelativePath=".\DumpFilter.c"
+ >
+ </File>
+ <File
+ RelativePath=".\EncryptedIoQueue.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Ntdriver.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Ntvol.c"
+ >
+ </File>
+ <File
+ RelativePath=".\VolumeFilter.c"
+ >
+ </File>
+ <Filter
+ Name="Common"
+ >
+ <File
+ RelativePath="..\Common\Cache.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Crc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Crypto.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\EncryptionThreadPool.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Endian.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\GfMul.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Pkcs5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Tests.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Volumes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Wipe.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Xts.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Crypto"
+ >
+ <File
+ RelativePath="..\Crypto\Aes_hw_cpu.asm"
+ >
+ </File>
+ <File
+ RelativePath="..\Crypto\Aes_x64.asm"
+ >
+ </File>
+ <File
+ RelativePath="..\Crypto\Aes_x86.asm"
+ >
+ </File>
+ <File
+ RelativePath="..\Crypto\Aeskey.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Crypto\Aestab.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Crypto\Rmd160.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Crypto\Serpent.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Crypto\Sha2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Crypto\Twofish.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Crypto\Whirlpool.c"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\Common\Apidrvr.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Cache.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Common.h"
+ >
+ </File>
+ <File
+ RelativePath=".\DriveFilter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\DumpFilter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\EncryptedIoQueue.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\EncryptionThreadPool.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\GfMul.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Ntdriver.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Ntvol.h"
+ >
+ </File>
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Tcdefs.h"
+ >
+ </File>
+ <File
+ RelativePath=".\VolumeFilter.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Volumes.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Wipe.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Xts.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\Driver.rc"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Build Files"
+ >
+ <File
+ RelativePath=".\BuildDriver.cmd"
+ >
+ </File>
+ <File
+ RelativePath=".\Makefile"
+ >
+ </File>
+ <File
+ RelativePath=".\Sources"
+ >
+ </File>
+ <Filter
+ Name="Common"
+ >
+ <File
+ RelativePath="..\Common\Makefile"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\Sources"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Crypto"
+ >
+ <File
+ RelativePath="..\Crypto\Makefile"
+ >
+ </File>
+ <File
+ RelativePath="..\Crypto\Makefile.inc"
+ >
+ </File>
+ <File
+ RelativePath="..\Crypto\Sources"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/Driver/DumpFilter.c b/src/Driver/DumpFilter.c
index 16d1d37c..d67b1654 100644
--- a/src/Driver/DumpFilter.c
+++ b/src/Driver/DumpFilter.c
@@ -1,248 +1,248 @@
-/*
- 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 "DumpFilter.h"
-#include "DriveFilter.h"
-#include "Ntdriver.h"
-#include "Tests.h"
-
-static DriveFilterExtension *BootDriveFilterExtension = NULL;
-static LARGE_INTEGER DumpPartitionOffset;
-static byte *WriteFilterBuffer = NULL;
-static SIZE_T WriteFilterBufferSize;
-
-
-NTSTATUS DumpFilterEntry (PFILTER_EXTENSION filterExtension, PFILTER_INITIALIZATION_DATA filterInitData)
-{
- GetSystemDriveDumpConfigRequest dumpConfig;
- PHYSICAL_ADDRESS highestAcceptableWriteBufferAddr;
- STORAGE_DEVICE_NUMBER storageDeviceNumber;
- PARTITION_INFORMATION partitionInfo;
- LONG version;
- NTSTATUS status;
-
- Dump ("DumpFilterEntry type=%d\n", filterExtension->DumpType);
-
- filterInitData->MajorVersion = DUMP_FILTER_MAJOR_VERSION;
- filterInitData->MinorVersion = DUMP_FILTER_MINOR_VERSION;
- filterInitData->Flags |= DUMP_FILTER_CRITICAL;
-
- // Check driver version of the main device
- status = TCDeviceIoControl (NT_ROOT_PREFIX, TC_IOCTL_GET_DRIVER_VERSION, NULL, 0, &version, sizeof (version));
- if (!NT_SUCCESS (status))
- goto err;
-
- if (version != VERSION_NUM)
- {
- status = STATUS_INVALID_PARAMETER;
- goto err;
- }
-
- // Get dump configuration from the main device
- status = TCDeviceIoControl (NT_ROOT_PREFIX, TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG, NULL, 0, &dumpConfig, sizeof (dumpConfig));
- if (!NT_SUCCESS (status))
- goto err;
-
- BootDriveFilterExtension = dumpConfig.BootDriveFilterExtension;
-
- if (BootDriveFilterExtension->MagicNumber != TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER)
- {
- status = STATUS_CRC_ERROR;
- goto err;
- }
-
- // KeSaveFloatingPointState() may generate a bug check during crash dump
-#if !defined (_WIN64)
- if (filterExtension->DumpType == DumpTypeCrashdump)
- dumpConfig.HwEncryptionEnabled = FALSE;
-#endif
-
- EnableHwEncryption (dumpConfig.HwEncryptionEnabled);
-
- if (!AutoTestAlgorithms())
- {
- status = STATUS_INVALID_PARAMETER;
- goto err;
- }
-
- // Check dump volume is located on the system drive
- status = SendDeviceIoControlRequest (filterExtension->DeviceObject, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &storageDeviceNumber, sizeof (storageDeviceNumber));
- if (!NT_SUCCESS (status))
- goto err;
-
- if (!BootDriveFilterExtension->SystemStorageDeviceNumberValid)
- {
- status = STATUS_INVALID_PARAMETER;
- goto err;
- }
-
- if (storageDeviceNumber.DeviceNumber != BootDriveFilterExtension->SystemStorageDeviceNumber)
- {
- status = STATUS_ACCESS_DENIED;
- goto err;
- }
-
- // Check dump volume is located within the scope of system encryption
- status = SendDeviceIoControlRequest (filterExtension->DeviceObject, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &partitionInfo, sizeof (partitionInfo));
- if (!NT_SUCCESS (status))
- goto err;
-
- DumpPartitionOffset = partitionInfo.StartingOffset;
-
- if (DumpPartitionOffset.QuadPart < BootDriveFilterExtension->ConfiguredEncryptedAreaStart
- || DumpPartitionOffset.QuadPart > BootDriveFilterExtension->ConfiguredEncryptedAreaEnd)
- {
- status = STATUS_ACCESS_DENIED;
- goto err;
- }
-
- // Allocate buffer for encryption
- if (filterInitData->MaxPagesPerWrite == 0)
- {
- status = STATUS_INVALID_PARAMETER;
- goto err;
- }
-
- WriteFilterBufferSize = filterInitData->MaxPagesPerWrite * PAGE_SIZE;
-
-#ifdef _WIN64
- highestAcceptableWriteBufferAddr.QuadPart = 0x7FFffffFFFFLL;
-#else
- highestAcceptableWriteBufferAddr.QuadPart = 0xffffFFFFLL;
-#endif
-
- WriteFilterBuffer = MmAllocateContiguousMemory (WriteFilterBufferSize, highestAcceptableWriteBufferAddr);
- if (!WriteFilterBuffer)
- {
- status = STATUS_INSUFFICIENT_RESOURCES;
- goto err;
- }
-
- filterInitData->DumpStart = DumpFilterStart;
- filterInitData->DumpWrite = DumpFilterWrite;
- filterInitData->DumpFinish = DumpFilterFinish;
- filterInitData->DumpUnload = DumpFilterUnload;
-
- Dump ("Dump filter loaded type=%d\n", filterExtension->DumpType);
- return STATUS_SUCCESS;
-
-err:
- Dump ("DumpFilterEntry error %x\n", status);
- return status;
-}
-
-
-static NTSTATUS DumpFilterStart (PFILTER_EXTENSION filterExtension)
-{
- Dump ("DumpFilterStart type=%d\n", filterExtension->DumpType);
-
- if (BootDriveFilterExtension->MagicNumber != TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER)
- TC_BUG_CHECK (STATUS_CRC_ERROR);
-
- return BootDriveFilterExtension->DriveMounted ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
-}
-
-
-static NTSTATUS DumpFilterWrite (PFILTER_EXTENSION filterExtension, PLARGE_INTEGER diskWriteOffset, PMDL writeMdl)
-{
- ULONG dataLength = MmGetMdlByteCount (writeMdl);
- uint64 offset = DumpPartitionOffset.QuadPart + diskWriteOffset->QuadPart;
- uint64 intersectStart;
- uint32 intersectLength;
- PVOID writeBuffer;
- CSHORT origMdlFlags;
-
- if (BootDriveFilterExtension->MagicNumber != TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER)
- TC_BUG_CHECK (STATUS_CRC_ERROR);
-
- if (BootDriveFilterExtension->Queue.EncryptedAreaEndUpdatePending) // Hibernation should always abort the setup thread
- TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
-
- if (BootDriveFilterExtension->Queue.EncryptedAreaStart == -1 || BootDriveFilterExtension->Queue.EncryptedAreaEnd == -1)
- return STATUS_SUCCESS;
-
- if (dataLength > WriteFilterBufferSize)
- TC_BUG_CHECK (STATUS_BUFFER_OVERFLOW); // Bug check is required as returning an error does not prevent data from being written to disk
-
- 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);
-
- writeBuffer = MmGetSystemAddressForMdlSafe (writeMdl, HighPagePriority);
- if (!writeBuffer)
- TC_BUG_CHECK (STATUS_INSUFFICIENT_RESOURCES);
-
- memcpy (WriteFilterBuffer, writeBuffer, dataLength);
-
- GetIntersection (offset,
- dataLength,
- BootDriveFilterExtension->Queue.EncryptedAreaStart,
- BootDriveFilterExtension->Queue.EncryptedAreaEnd,
- &intersectStart,
- &intersectLength);
-
- if (intersectLength > 0)
- {
- UINT64_STRUCT dataUnit;
- dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE;
-
- if (BootDriveFilterExtension->Queue.RemapEncryptedArea)
- {
- diskWriteOffset->QuadPart += BootDriveFilterExtension->Queue.RemappedAreaOffset;
- dataUnit.Value += BootDriveFilterExtension->Queue.RemappedAreaDataUnitOffset;
- }
-
- EncryptDataUnitsCurrentThread (WriteFilterBuffer + (intersectStart - offset),
- &dataUnit,
- intersectLength / ENCRYPTION_DATA_UNIT_SIZE,
- BootDriveFilterExtension->Queue.CryptoInfo);
- }
-
- origMdlFlags = writeMdl->MdlFlags;
-
- MmInitializeMdl (writeMdl, WriteFilterBuffer, dataLength);
- MmBuildMdlForNonPagedPool (writeMdl);
-
- // Instead of using MmGetSystemAddressForMdlSafe(), some buggy custom storage drivers may directly test MDL_MAPPED_TO_SYSTEM_VA flag,
- // disregarding the fact that other MDL flags may be set by the system or a dump filter (e.g. MDL_SOURCE_IS_NONPAGED_POOL flag only).
- // Therefore, to work around this issue, the original flags will be restored even if they do not match the new MDL.
- // MS BitLocker also uses this hack/workaround (it should be safe to use until the MDL structure is changed).
-
- writeMdl->MdlFlags = origMdlFlags;
-
- return STATUS_SUCCESS;
-}
-
-
-static NTSTATUS DumpFilterFinish (PFILTER_EXTENSION filterExtension)
-{
- Dump ("DumpFilterFinish type=%d\n", filterExtension->DumpType);
-
- return STATUS_SUCCESS;
-}
-
-
-static NTSTATUS DumpFilterUnload (PFILTER_EXTENSION filterExtension)
-{
- Dump ("DumpFilterUnload type=%d\n", filterExtension->DumpType);
-
- if (WriteFilterBuffer)
- {
- memset (WriteFilterBuffer, 0, WriteFilterBufferSize);
- MmFreeContiguousMemory (WriteFilterBuffer);
- WriteFilterBuffer = NULL;
- }
-
- return STATUS_SUCCESS;
-}
+/*
+ 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 "DumpFilter.h"
+#include "DriveFilter.h"
+#include "Ntdriver.h"
+#include "Tests.h"
+
+static DriveFilterExtension *BootDriveFilterExtension = NULL;
+static LARGE_INTEGER DumpPartitionOffset;
+static byte *WriteFilterBuffer = NULL;
+static SIZE_T WriteFilterBufferSize;
+
+
+NTSTATUS DumpFilterEntry (PFILTER_EXTENSION filterExtension, PFILTER_INITIALIZATION_DATA filterInitData)
+{
+ GetSystemDriveDumpConfigRequest dumpConfig;
+ PHYSICAL_ADDRESS highestAcceptableWriteBufferAddr;
+ STORAGE_DEVICE_NUMBER storageDeviceNumber;
+ PARTITION_INFORMATION partitionInfo;
+ LONG version;
+ NTSTATUS status;
+
+ Dump ("DumpFilterEntry type=%d\n", filterExtension->DumpType);
+
+ filterInitData->MajorVersion = DUMP_FILTER_MAJOR_VERSION;
+ filterInitData->MinorVersion = DUMP_FILTER_MINOR_VERSION;
+ filterInitData->Flags |= DUMP_FILTER_CRITICAL;
+
+ // Check driver version of the main device
+ status = TCDeviceIoControl (NT_ROOT_PREFIX, TC_IOCTL_GET_DRIVER_VERSION, NULL, 0, &version, sizeof (version));
+ if (!NT_SUCCESS (status))
+ goto err;
+
+ if (version != VERSION_NUM)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ goto err;
+ }
+
+ // Get dump configuration from the main device
+ status = TCDeviceIoControl (NT_ROOT_PREFIX, TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG, NULL, 0, &dumpConfig, sizeof (dumpConfig));
+ if (!NT_SUCCESS (status))
+ goto err;
+
+ BootDriveFilterExtension = dumpConfig.BootDriveFilterExtension;
+
+ if (BootDriveFilterExtension->MagicNumber != TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER)
+ {
+ status = STATUS_CRC_ERROR;
+ goto err;
+ }
+
+ // KeSaveFloatingPointState() may generate a bug check during crash dump
+#if !defined (_WIN64)
+ if (filterExtension->DumpType == DumpTypeCrashdump)
+ dumpConfig.HwEncryptionEnabled = FALSE;
+#endif
+
+ EnableHwEncryption (dumpConfig.HwEncryptionEnabled);
+
+ if (!AutoTestAlgorithms())
+ {
+ status = STATUS_INVALID_PARAMETER;
+ goto err;
+ }
+
+ // Check dump volume is located on the system drive
+ status = SendDeviceIoControlRequest (filterExtension->DeviceObject, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &storageDeviceNumber, sizeof (storageDeviceNumber));
+ if (!NT_SUCCESS (status))
+ goto err;
+
+ if (!BootDriveFilterExtension->SystemStorageDeviceNumberValid)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ goto err;
+ }
+
+ if (storageDeviceNumber.DeviceNumber != BootDriveFilterExtension->SystemStorageDeviceNumber)
+ {
+ status = STATUS_ACCESS_DENIED;
+ goto err;
+ }
+
+ // Check dump volume is located within the scope of system encryption
+ status = SendDeviceIoControlRequest (filterExtension->DeviceObject, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &partitionInfo, sizeof (partitionInfo));
+ if (!NT_SUCCESS (status))
+ goto err;
+
+ DumpPartitionOffset = partitionInfo.StartingOffset;
+
+ if (DumpPartitionOffset.QuadPart < BootDriveFilterExtension->ConfiguredEncryptedAreaStart
+ || DumpPartitionOffset.QuadPart > BootDriveFilterExtension->ConfiguredEncryptedAreaEnd)
+ {
+ status = STATUS_ACCESS_DENIED;
+ goto err;
+ }
+
+ // Allocate buffer for encryption
+ if (filterInitData->MaxPagesPerWrite == 0)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ goto err;
+ }
+
+ WriteFilterBufferSize = filterInitData->MaxPagesPerWrite * PAGE_SIZE;
+
+#ifdef _WIN64
+ highestAcceptableWriteBufferAddr.QuadPart = 0x7FFffffFFFFLL;
+#else
+ highestAcceptableWriteBufferAddr.QuadPart = 0xffffFFFFLL;
+#endif
+
+ WriteFilterBuffer = MmAllocateContiguousMemory (WriteFilterBufferSize, highestAcceptableWriteBufferAddr);
+ if (!WriteFilterBuffer)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto err;
+ }
+
+ filterInitData->DumpStart = DumpFilterStart;
+ filterInitData->DumpWrite = DumpFilterWrite;
+ filterInitData->DumpFinish = DumpFilterFinish;
+ filterInitData->DumpUnload = DumpFilterUnload;
+
+ Dump ("Dump filter loaded type=%d\n", filterExtension->DumpType);
+ return STATUS_SUCCESS;
+
+err:
+ Dump ("DumpFilterEntry error %x\n", status);
+ return status;
+}
+
+
+static NTSTATUS DumpFilterStart (PFILTER_EXTENSION filterExtension)
+{
+ Dump ("DumpFilterStart type=%d\n", filterExtension->DumpType);
+
+ if (BootDriveFilterExtension->MagicNumber != TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER)
+ TC_BUG_CHECK (STATUS_CRC_ERROR);
+
+ return BootDriveFilterExtension->DriveMounted ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
+}
+
+
+static NTSTATUS DumpFilterWrite (PFILTER_EXTENSION filterExtension, PLARGE_INTEGER diskWriteOffset, PMDL writeMdl)
+{
+ ULONG dataLength = MmGetMdlByteCount (writeMdl);
+ uint64 offset = DumpPartitionOffset.QuadPart + diskWriteOffset->QuadPart;
+ uint64 intersectStart;
+ uint32 intersectLength;
+ PVOID writeBuffer;
+ CSHORT origMdlFlags;
+
+ if (BootDriveFilterExtension->MagicNumber != TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER)
+ TC_BUG_CHECK (STATUS_CRC_ERROR);
+
+ if (BootDriveFilterExtension->Queue.EncryptedAreaEndUpdatePending) // Hibernation should always abort the setup thread
+ TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
+
+ if (BootDriveFilterExtension->Queue.EncryptedAreaStart == -1 || BootDriveFilterExtension->Queue.EncryptedAreaEnd == -1)
+ return STATUS_SUCCESS;
+
+ if (dataLength > WriteFilterBufferSize)
+ TC_BUG_CHECK (STATUS_BUFFER_OVERFLOW); // Bug check is required as returning an error does not prevent data from being written to disk
+
+ 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);
+
+ writeBuffer = MmGetSystemAddressForMdlSafe (writeMdl, HighPagePriority);
+ if (!writeBuffer)
+ TC_BUG_CHECK (STATUS_INSUFFICIENT_RESOURCES);
+
+ memcpy (WriteFilterBuffer, writeBuffer, dataLength);
+
+ GetIntersection (offset,
+ dataLength,
+ BootDriveFilterExtension->Queue.EncryptedAreaStart,
+ BootDriveFilterExtension->Queue.EncryptedAreaEnd,
+ &intersectStart,
+ &intersectLength);
+
+ if (intersectLength > 0)
+ {
+ UINT64_STRUCT dataUnit;
+ dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE;
+
+ if (BootDriveFilterExtension->Queue.RemapEncryptedArea)
+ {
+ diskWriteOffset->QuadPart += BootDriveFilterExtension->Queue.RemappedAreaOffset;
+ dataUnit.Value += BootDriveFilterExtension->Queue.RemappedAreaDataUnitOffset;
+ }
+
+ EncryptDataUnitsCurrentThread (WriteFilterBuffer + (intersectStart - offset),
+ &dataUnit,
+ intersectLength / ENCRYPTION_DATA_UNIT_SIZE,
+ BootDriveFilterExtension->Queue.CryptoInfo);
+ }
+
+ origMdlFlags = writeMdl->MdlFlags;
+
+ MmInitializeMdl (writeMdl, WriteFilterBuffer, dataLength);
+ MmBuildMdlForNonPagedPool (writeMdl);
+
+ // Instead of using MmGetSystemAddressForMdlSafe(), some buggy custom storage drivers may directly test MDL_MAPPED_TO_SYSTEM_VA flag,
+ // disregarding the fact that other MDL flags may be set by the system or a dump filter (e.g. MDL_SOURCE_IS_NONPAGED_POOL flag only).
+ // Therefore, to work around this issue, the original flags will be restored even if they do not match the new MDL.
+ // MS BitLocker also uses this hack/workaround (it should be safe to use until the MDL structure is changed).
+
+ writeMdl->MdlFlags = origMdlFlags;
+
+ return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS DumpFilterFinish (PFILTER_EXTENSION filterExtension)
+{
+ Dump ("DumpFilterFinish type=%d\n", filterExtension->DumpType);
+
+ return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS DumpFilterUnload (PFILTER_EXTENSION filterExtension)
+{
+ Dump ("DumpFilterUnload type=%d\n", filterExtension->DumpType);
+
+ if (WriteFilterBuffer)
+ {
+ memset (WriteFilterBuffer, 0, WriteFilterBufferSize);
+ MmFreeContiguousMemory (WriteFilterBuffer);
+ WriteFilterBuffer = NULL;
+ }
+
+ return STATUS_SUCCESS;
+}
diff --git a/src/Driver/DumpFilter.h b/src/Driver/DumpFilter.h
index f288107e..ea6599a5 100644
--- a/src/Driver/DumpFilter.h
+++ b/src/Driver/DumpFilter.h
@@ -1,25 +1,25 @@
-/*
- 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.
-*/
-
-#ifndef TC_HEADER_DRIVER_DUMP_FILTER
-#define TC_HEADER_DRIVER_DUMP_FILTER
-
-#include "Tcdefs.h"
-#include <ntdddump.h>
-
-NTSTATUS DumpFilterEntry (PFILTER_EXTENSION filterExtension, PFILTER_INITIALIZATION_DATA filterInitData);
-static NTSTATUS DumpFilterStart (PFILTER_EXTENSION filterExtension);
-static NTSTATUS DumpFilterWrite (PFILTER_EXTENSION filterExtension, PLARGE_INTEGER diskWriteOffset, PMDL writeMdl);
-static NTSTATUS DumpFilterFinish (PFILTER_EXTENSION filterExtension);
-static NTSTATUS DumpFilterUnload (PFILTER_EXTENSION filterExtension);
-
-#endif // TC_HEADER_DRIVER_DUMP_FILTER
+/*
+ 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.
+*/
+
+#ifndef TC_HEADER_DRIVER_DUMP_FILTER
+#define TC_HEADER_DRIVER_DUMP_FILTER
+
+#include "Tcdefs.h"
+#include <ntdddump.h>
+
+NTSTATUS DumpFilterEntry (PFILTER_EXTENSION filterExtension, PFILTER_INITIALIZATION_DATA filterInitData);
+static NTSTATUS DumpFilterStart (PFILTER_EXTENSION filterExtension);
+static NTSTATUS DumpFilterWrite (PFILTER_EXTENSION filterExtension, PLARGE_INTEGER diskWriteOffset, PMDL writeMdl);
+static NTSTATUS DumpFilterFinish (PFILTER_EXTENSION filterExtension);
+static NTSTATUS DumpFilterUnload (PFILTER_EXTENSION filterExtension);
+
+#endif // TC_HEADER_DRIVER_DUMP_FILTER
diff --git a/src/Driver/EncryptedIoQueue.c b/src/Driver/EncryptedIoQueue.c
index 1f57ad5c..637f8504 100644
--- a/src/Driver/EncryptedIoQueue.c
+++ b/src/Driver/EncryptedIoQueue.c
@@ -1,1049 +1,1049 @@
-/*
- 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 "Apidrvr.h"
-#include "Ntdriver.h"
-#include "DriveFilter.h"
-#include "EncryptedIoQueue.h"
-#include "EncryptionThreadPool.h"
-#include "Volumes.h"
-#include <IntSafe.h>
-
-
-static void AcquireBufferPoolMutex (EncryptedIoQueue *queue)
-{
- NTSTATUS status;
-
- status = KeWaitForMutexObject (&queue->BufferPoolMutex, Executive, KernelMode, FALSE, NULL);
- if (!NT_SUCCESS (status))
- TC_BUG_CHECK (status);
-}
-
-
-static void ReleaseBufferPoolMutex (EncryptedIoQueue *queue)
-{
- KeReleaseMutex (&queue->BufferPoolMutex, FALSE);
-}
-
-
-static void *GetPoolBuffer (EncryptedIoQueue *queue, ULONG requestedSize)
-{
- EncryptedIoQueueBuffer *buffer;
- void *bufferAddress = NULL;
- BOOL requestedSizePresentInPool = FALSE;
-
- while (TRUE)
- {
- AcquireBufferPoolMutex (queue);
-
- for (buffer = queue->FirstPoolBuffer; ; buffer = buffer->NextBuffer)
- {
- if (buffer && buffer->Size == requestedSize)
- {
- requestedSizePresentInPool = TRUE;
-
- if (!buffer->InUse)
- {
- // Reuse a free buffer
- buffer->InUse = TRUE;
- bufferAddress = buffer->Address;
- break;
- }
- }
-
- if (!buffer || !buffer->NextBuffer)
- {
- EncryptedIoQueueBuffer *newBuffer;
-
- if (requestedSizePresentInPool && !queue->StartPending)
- break;
-
- // Allocate a new buffer
- newBuffer = TCalloc (sizeof (EncryptedIoQueueBuffer));
- if (!newBuffer)
- {
- bufferAddress = NULL;
- break;
- }
-
- bufferAddress = TCalloc (requestedSize);
- if (bufferAddress)
- {
- newBuffer->NextBuffer = NULL;
- newBuffer->Address = bufferAddress;
- newBuffer->Size = requestedSize;
- newBuffer->InUse = TRUE;
-
- if (!buffer)
- queue->FirstPoolBuffer = newBuffer;
- else
- buffer->NextBuffer = newBuffer;
- }
- else
- TCfree (newBuffer);
-
- break;
- }
- }
-
- ReleaseBufferPoolMutex (queue);
-
- if (bufferAddress || !requestedSizePresentInPool || queue->StartPending)
- break;
-
- KeWaitForSingleObject (&queue->PoolBufferFreeEvent, Executive, KernelMode, FALSE, NULL);
- }
-
- return bufferAddress;
-}
-
-
-static void ReleasePoolBuffer (EncryptedIoQueue *queue, void *address)
-{
- EncryptedIoQueueBuffer *buffer;
- AcquireBufferPoolMutex (queue);
-
- for (buffer = queue->FirstPoolBuffer; buffer != NULL; buffer = buffer->NextBuffer)
- {
- if (buffer->Address == address)
- {
- ASSERT (buffer->InUse);
-
- buffer->InUse = FALSE;
- break;
- }
- }
-
- ReleaseBufferPoolMutex (queue);
- KeSetEvent (&queue->PoolBufferFreeEvent, IO_DISK_INCREMENT, FALSE);
-}
-
-
-static void FreePoolBuffers (EncryptedIoQueue *queue)
-{
- EncryptedIoQueueBuffer *buffer;
- AcquireBufferPoolMutex (queue);
-
- for (buffer = queue->FirstPoolBuffer; buffer != NULL; )
- {
- EncryptedIoQueueBuffer *nextBuffer = buffer->NextBuffer;
-
- ASSERT (!buffer->InUse || queue->StartPending);
-
- TCfree (buffer->Address);
- TCfree (buffer);
-
- buffer = nextBuffer;
- }
-
- queue->FirstPoolBuffer = NULL;
- ReleaseBufferPoolMutex (queue);
-}
-
-
-static void DecrementOutstandingIoCount (EncryptedIoQueue *queue)
-{
- if (InterlockedDecrement (&queue->OutstandingIoCount) == 0 && (queue->SuspendPending || queue->StopPending))
- KeSetEvent (&queue->NoOutstandingIoEvent, IO_DISK_INCREMENT, FALSE);
-}
-
-
-static void OnItemCompleted (EncryptedIoQueueItem *item, BOOL freeItem)
-{
- DecrementOutstandingIoCount (item->Queue);
- IoReleaseRemoveLock (&item->Queue->RemoveLock, item->OriginalIrp);
-
- if (NT_SUCCESS (item->Status))
- {
- if (item->Write)
- item->Queue->TotalBytesWritten += item->OriginalLength;
- else
- item->Queue->TotalBytesRead += item->OriginalLength;
- }
-
- if (freeItem)
- ReleasePoolBuffer (item->Queue, item);
-}
-
-
-static NTSTATUS CompleteOriginalIrp (EncryptedIoQueueItem *item, NTSTATUS status, ULONG_PTR information)
-{
-#ifdef TC_TRACE_IO_QUEUE
- Dump ("< %I64d [%I64d] %c status=%x info=%I64d\n", item->OriginalIrpOffset, GetElapsedTime (&item->Queue->LastPerformanceCounter), item->Write ? 'W' : 'R', status, (int64) information);
-#endif
-
- TCCompleteDiskIrp (item->OriginalIrp, status, information);
-
- item->Status = status;
- OnItemCompleted (item, TRUE);
-
- return status;
-}
-
-
-static void AcquireFragmentBuffer (EncryptedIoQueue *queue, byte *buffer)
-{
- NTSTATUS status = STATUS_INVALID_PARAMETER;
-
- if (buffer == queue->FragmentBufferA)
- {
- status = KeWaitForSingleObject (&queue->FragmentBufferAFreeEvent, Executive, KernelMode, FALSE, NULL);
- }
- else if (buffer == queue->FragmentBufferB)
- {
- status = KeWaitForSingleObject (&queue->FragmentBufferBFreeEvent, Executive, KernelMode, FALSE, NULL);
- }
-
- if (!NT_SUCCESS (status))
- TC_BUG_CHECK (status);
-}
-
-
-static void ReleaseFragmentBuffer (EncryptedIoQueue *queue, byte *buffer)
-{
- if (buffer == queue->FragmentBufferA)
- {
- KeSetEvent (&queue->FragmentBufferAFreeEvent, IO_DISK_INCREMENT, FALSE);
- }
- else if (buffer == queue->FragmentBufferB)
- {
- KeSetEvent (&queue->FragmentBufferBFreeEvent, IO_DISK_INCREMENT, FALSE);
- }
- else
- {
- TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
- }
-}
-
-
-static VOID CompletionThreadProc (PVOID threadArg)
-{
- EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
- PLIST_ENTRY listEntry;
- EncryptedIoRequest *request;
- UINT64_STRUCT dataUnit;
-
- if (IsEncryptionThreadPoolRunning())
- KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
-
- while (!queue->ThreadExitRequested)
- {
- if (!NT_SUCCESS (KeWaitForSingleObject (&queue->CompletionThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL)))
- continue;
-
- if (queue->ThreadExitRequested)
- break;
-
- while ((listEntry = ExInterlockedRemoveHeadList (&queue->CompletionThreadQueue, &queue->CompletionThreadQueueLock)))
- {
- request = CONTAINING_RECORD (listEntry, EncryptedIoRequest, CompletionListEntry);
-
- if (request->EncryptedLength > 0 && NT_SUCCESS (request->Item->Status))
- {
- ASSERT (request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length);
- dataUnit.Value = (request->Offset.QuadPart + request->EncryptedOffset) / ENCRYPTION_DATA_UNIT_SIZE;
-
- if (queue->CryptoInfo->bPartitionInInactiveSysEncScope)
- dataUnit.Value += queue->CryptoInfo->FirstDataUnitNo.Value;
- else if (queue->RemapEncryptedArea)
- dataUnit.Value += queue->RemappedAreaDataUnitOffset;
-
- DecryptDataUnits (request->Data + request->EncryptedOffset, &dataUnit, request->EncryptedLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
- }
-
- if (request->CompleteOriginalIrp)
- {
- CompleteOriginalIrp (request->Item, request->Item->Status,
- NT_SUCCESS (request->Item->Status) ? request->Item->OriginalLength : 0);
- }
-
- ReleasePoolBuffer (queue, request);
- }
- }
-
- PsTerminateSystemThread (STATUS_SUCCESS);
-}
-
-
-static NTSTATUS TCCachedRead (EncryptedIoQueue *queue, IO_STATUS_BLOCK *ioStatus, PVOID buffer, LARGE_INTEGER offset, ULONG length)
-{
- queue->LastReadOffset = offset;
- queue->LastReadLength = length;
-
- if (queue->ReadAheadBufferValid && queue->ReadAheadOffset.QuadPart == offset.QuadPart && queue->ReadAheadLength >= length)
- {
- memcpy (buffer, queue->ReadAheadBuffer, length);
-
- if (!queue->IsFilterDevice)
- {
- ioStatus->Information = length;
- ioStatus->Status = STATUS_SUCCESS;
- }
-
- return STATUS_SUCCESS;
- }
-
- if (queue->IsFilterDevice)
- return TCReadDevice (queue->LowerDeviceObject, buffer, offset, length);
-
- return ZwReadFile (queue->HostFileHandle, NULL, NULL, NULL, ioStatus, buffer, length, &offset, NULL);
-}
-
-
-static VOID IoThreadProc (PVOID threadArg)
-{
- EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
- PLIST_ENTRY listEntry;
- EncryptedIoRequest *request;
-
- KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
-
- if (!queue->IsFilterDevice && queue->SecurityClientContext)
- {
-#ifdef DEBUG
- NTSTATUS status =
-#endif
- SeImpersonateClientEx (queue->SecurityClientContext, NULL);
- ASSERT (NT_SUCCESS (status));
- }
-
- while (!queue->ThreadExitRequested)
- {
- if (!NT_SUCCESS (KeWaitForSingleObject (&queue->IoThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL)))
- continue;
-
- if (queue->ThreadExitRequested)
- break;
-
- while ((listEntry = ExInterlockedRemoveHeadList (&queue->IoThreadQueue, &queue->IoThreadQueueLock)))
- {
- InterlockedDecrement (&queue->IoThreadPendingRequestCount);
- request = CONTAINING_RECORD (listEntry, EncryptedIoRequest, ListEntry);
-
-#ifdef TC_TRACE_IO_QUEUE
- Dump ("%c %I64d [%I64d] roff=%I64d rlen=%d\n", request->Item->Write ? 'W' : 'R', request->Item->OriginalIrpOffset.QuadPart, GetElapsedTime (&queue->LastPerformanceCounter), request->Offset.QuadPart, request->Length);
-#endif
-
- // Perform IO request if no preceding request of the item failed
- if (NT_SUCCESS (request->Item->Status))
- {
- if (queue->IsFilterDevice)
- {
- if (queue->RemapEncryptedArea && request->EncryptedLength > 0)
- {
- if (request->EncryptedLength != request->Length)
- {
- // Up to three subfragments may be required to handle a partially remapped fragment
- int subFragment;
- byte *subFragmentData = request->Data;
-
- for (subFragment = 0 ; subFragment < 3; ++subFragment)
- {
- LARGE_INTEGER subFragmentOffset;
- ULONG subFragmentLength;
- subFragmentOffset.QuadPart = request->Offset.QuadPart;
-
- switch (subFragment)
- {
- case 0:
- subFragmentLength = (ULONG) request->EncryptedOffset;
- break;
-
- case 1:
- subFragmentOffset.QuadPart += request->EncryptedOffset + queue->RemappedAreaOffset;
- subFragmentLength = request->EncryptedLength;
- break;
-
- case 2:
- subFragmentOffset.QuadPart += request->EncryptedOffset + request->EncryptedLength;
- subFragmentLength = (ULONG) (request->Length - (request->EncryptedOffset + request->EncryptedLength));
- break;
- }
-
- if (subFragmentLength > 0)
- {
- if (request->Item->Write)
- request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, subFragmentData, subFragmentOffset, subFragmentLength);
- else
- request->Item->Status = TCCachedRead (queue, NULL, subFragmentData, subFragmentOffset, subFragmentLength);
-
- subFragmentData += subFragmentLength;
- }
- }
- }
- else
- {
- // Remap the fragment
- LARGE_INTEGER remappedOffset;
- remappedOffset.QuadPart = request->Offset.QuadPart + queue->RemappedAreaOffset;
-
- if (request->Item->Write)
- request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, request->Data, remappedOffset, request->Length);
- else
- request->Item->Status = TCCachedRead (queue, NULL, request->Data, remappedOffset, request->Length);
- }
- }
- else
- {
- if (request->Item->Write)
- request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, request->Data, request->Offset, request->Length);
- else
- request->Item->Status = TCCachedRead (queue, NULL, request->Data, request->Offset, request->Length);
- }
- }
- else
- {
- IO_STATUS_BLOCK ioStatus;
-
- if (request->Item->Write)
- request->Item->Status = ZwWriteFile (queue->HostFileHandle, NULL, NULL, NULL, &ioStatus, request->Data, request->Length, &request->Offset, NULL);
- else
- request->Item->Status = TCCachedRead (queue, &ioStatus, request->Data, request->Offset, request->Length);
-
- if (NT_SUCCESS (request->Item->Status) && ioStatus.Information != request->Length)
- request->Item->Status = STATUS_END_OF_FILE;
- }
- }
-
- if (request->Item->Write)
- {
- queue->ReadAheadBufferValid = FALSE;
-
- ReleaseFragmentBuffer (queue, request->Data);
-
- if (request->CompleteOriginalIrp)
- {
- CompleteOriginalIrp (request->Item, request->Item->Status,
- NT_SUCCESS (request->Item->Status) ? request->Item->OriginalLength : 0);
- }
-
- ReleasePoolBuffer (queue, request);
- }
- else
- {
- BOOL readAhead = FALSE;
-
- if (NT_SUCCESS (request->Item->Status))
- memcpy (request->OrigDataBufferFragment, request->Data, request->Length);
-
- ReleaseFragmentBuffer (queue, request->Data);
- request->Data = request->OrigDataBufferFragment;
-
- if (request->CompleteOriginalIrp
- && queue->LastReadLength > 0
- && NT_SUCCESS (request->Item->Status)
- && InterlockedExchangeAdd (&queue->IoThreadPendingRequestCount, 0) == 0)
- {
- readAhead = TRUE;
- InterlockedIncrement (&queue->OutstandingIoCount);
- }
-
- ExInterlockedInsertTailList (&queue->CompletionThreadQueue, &request->CompletionListEntry, &queue->CompletionThreadQueueLock);
- KeSetEvent (&queue->CompletionThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
-
- if (readAhead)
- {
- queue->ReadAheadBufferValid = FALSE;
- queue->ReadAheadOffset.QuadPart = queue->LastReadOffset.QuadPart + queue->LastReadLength;
- queue->ReadAheadLength = queue->LastReadLength;
-
- if (queue->ReadAheadOffset.QuadPart + queue->ReadAheadLength <= queue->MaxReadAheadOffset.QuadPart)
- {
-#ifdef TC_TRACE_IO_QUEUE
- Dump ("A %I64d [%I64d] roff=%I64d rlen=%d\n", request->Item->OriginalIrpOffset.QuadPart, GetElapsedTime (&queue->LastPerformanceCounter), queue->ReadAheadOffset, queue->ReadAheadLength);
-#endif
- if (queue->IsFilterDevice)
- {
- queue->ReadAheadBufferValid = NT_SUCCESS (TCReadDevice (queue->LowerDeviceObject, queue->ReadAheadBuffer, queue->ReadAheadOffset, queue->ReadAheadLength));
- }
- else
- {
- IO_STATUS_BLOCK ioStatus;
- queue->ReadAheadBufferValid = NT_SUCCESS (ZwReadFile (queue->HostFileHandle, NULL, NULL, NULL, &ioStatus, queue->ReadAheadBuffer, queue->ReadAheadLength, &queue->ReadAheadOffset, NULL));
- queue->ReadAheadLength = (ULONG) ioStatus.Information;
- }
- }
-
- DecrementOutstandingIoCount (queue);
- }
- }
- }
- }
-
- PsTerminateSystemThread (STATUS_SUCCESS);
-}
-
-
-static VOID MainThreadProc (PVOID threadArg)
-{
- EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
- PLIST_ENTRY listEntry;
- EncryptedIoQueueItem *item;
-
- LARGE_INTEGER fragmentOffset;
- ULONG dataRemaining;
- PUCHAR activeFragmentBuffer = queue->FragmentBufferA;
- PUCHAR dataBuffer;
- EncryptedIoRequest *request;
- uint64 intersectStart;
- uint32 intersectLength;
- ULONGLONG addResult;
- HRESULT hResult;
-
- if (IsEncryptionThreadPoolRunning())
- KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
-
- while (!queue->ThreadExitRequested)
- {
- if (!NT_SUCCESS (KeWaitForSingleObject (&queue->MainThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL)))
- continue;
-
- while ((listEntry = ExInterlockedRemoveHeadList (&queue->MainThreadQueue, &queue->MainThreadQueueLock)))
- {
- PIRP irp = CONTAINING_RECORD (listEntry, IRP, Tail.Overlay.ListEntry);
- PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
-
- if (queue->Suspended)
- KeWaitForSingleObject (&queue->QueueResumedEvent, Executive, KernelMode, FALSE, NULL);
-
- item = GetPoolBuffer (queue, sizeof (EncryptedIoQueueItem));
- if (!item)
- {
- TCCompleteDiskIrp (irp, STATUS_INSUFFICIENT_RESOURCES, 0);
- DecrementOutstandingIoCount (queue);
- IoReleaseRemoveLock (&queue->RemoveLock, irp);
-
- continue;
- }
-
- item->Queue = queue;
- item->OriginalIrp = irp;
- item->Status = STATUS_SUCCESS;
-
- IoSetCancelRoutine (irp, NULL);
- if (irp->Cancel)
- {
- CompleteOriginalIrp (item, STATUS_CANCELLED, 0);
- continue;
- }
-
- switch (irpSp->MajorFunction)
- {
- case IRP_MJ_READ:
- item->Write = FALSE;
- item->OriginalOffset = irpSp->Parameters.Read.ByteOffset;
- item->OriginalLength = irpSp->Parameters.Read.Length;
- break;
-
- case IRP_MJ_WRITE:
- item->Write = TRUE;
- item->OriginalOffset = irpSp->Parameters.Write.ByteOffset;
- item->OriginalLength = irpSp->Parameters.Write.Length;
- break;
-
- default:
- CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
- continue;
- }
-
-#ifdef TC_TRACE_IO_QUEUE
- item->OriginalIrpOffset = item->OriginalOffset;
-#endif
-
- // Handle misaligned read operations to work around a bug in Windows System Assessment Tool which does not follow FILE_FLAG_NO_BUFFERING requirements when benchmarking disk devices
- if (queue->IsFilterDevice
- && !item->Write
- && item->OriginalLength > 0
- && (item->OriginalLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) == 0
- && (item->OriginalOffset.QuadPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0)
- {
- byte *buffer;
- ULONG alignedLength;
- LARGE_INTEGER alignedOffset;
- hResult = ULongAdd(item->OriginalLength, ENCRYPTION_DATA_UNIT_SIZE, &alignedLength);
- if (hResult != S_OK)
- {
- CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
- continue;
- }
-
- alignedOffset.QuadPart = item->OriginalOffset.QuadPart & ~((LONGLONG) ENCRYPTION_DATA_UNIT_SIZE - 1);
-
- buffer = TCalloc (alignedLength);
- if (!buffer)
- {
- CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
- continue;
- }
-
- item->Status = TCReadDevice (queue->LowerDeviceObject, buffer, alignedOffset, alignedLength);
-
- if (NT_SUCCESS (item->Status))
- {
- UINT64_STRUCT dataUnit;
-
- dataBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe (irp->MdlAddress, HighPagePriority);
- if (!dataBuffer)
- {
- TCfree (buffer);
- CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
- continue;
- }
-
- if (queue->EncryptedAreaStart != -1 && queue->EncryptedAreaEnd != -1)
- {
- GetIntersection (alignedOffset.QuadPart, alignedLength, queue->EncryptedAreaStart, queue->EncryptedAreaEnd, &intersectStart, &intersectLength);
- if (intersectLength > 0)
- {
- dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE;
- DecryptDataUnits (buffer + (intersectStart - alignedOffset.QuadPart), &dataUnit, intersectLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
- }
- }
-
- memcpy (dataBuffer, buffer + (item->OriginalOffset.LowPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)), item->OriginalLength);
- }
-
- TCfree (buffer);
- CompleteOriginalIrp (item, item->Status, NT_SUCCESS (item->Status) ? item->OriginalLength : 0);
- continue;
- }
-
- // Validate offset and length
- if (item->OriginalLength == 0
- || (item->OriginalLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0
- || (item->OriginalOffset.QuadPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0
- || ( !queue->IsFilterDevice &&
- ( (S_OK != ULongLongAdd(item->OriginalOffset.QuadPart, item->OriginalLength, &addResult))
- || (addResult > (ULONGLONG) queue->VirtualDeviceLength)
- )
- )
- )
- {
- CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
- continue;
- }
-
-#ifdef TC_TRACE_IO_QUEUE
- Dump ("Q %I64d [%I64d] %c len=%d\n", item->OriginalOffset.QuadPart, GetElapsedTime (&queue->LastPerformanceCounter), item->Write ? 'W' : 'R', item->OriginalLength);
-#endif
-
- if (!queue->IsFilterDevice)
- {
- // Adjust the offset for host file or device
- if (queue->CryptoInfo->hiddenVolume)
- hResult = ULongLongAdd(item->OriginalOffset.QuadPart, queue->CryptoInfo->hiddenVolumeOffset, &addResult);
- else
- hResult = ULongLongAdd(item->OriginalOffset.QuadPart, queue->CryptoInfo->volDataAreaOffset, &addResult);
-
- if (hResult != S_OK)
- {
- CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
- continue;
- }
- else
- item->OriginalOffset.QuadPart = addResult;
-
- // Hidden volume protection
- if (item->Write && queue->CryptoInfo->bProtectHiddenVolume)
- {
- // If there has already been a write operation denied in order to protect the
- // hidden volume (since the volume mount time)
- if (queue->CryptoInfo->bHiddenVolProtectionAction)
- {
- // Do not allow writing to this volume anymore. This is to fake a complete volume
- // or system failure (otherwise certain kinds of inconsistency within the file
- // system could indicate that this volume has used hidden volume protection).
- CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
- continue;
- }
-
- // Verify that no byte is going to be written to the hidden volume area
- if (RegionsOverlap ((unsigned __int64) item->OriginalOffset.QuadPart,
- (unsigned __int64) item->OriginalOffset.QuadPart + item->OriginalLength - 1,
- queue->CryptoInfo->hiddenVolumeOffset,
- (unsigned __int64) queue->CryptoInfo->hiddenVolumeOffset + queue->CryptoInfo->hiddenVolumeProtectedSize - 1))
- {
- Dump ("Hidden volume protection triggered: write %I64d-%I64d (protected %I64d-%I64d)\n", item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, queue->CryptoInfo->hiddenVolumeOffset, queue->CryptoInfo->hiddenVolumeOffset + queue->CryptoInfo->hiddenVolumeProtectedSize - 1);
- queue->CryptoInfo->bHiddenVolProtectionAction = TRUE;
-
- // Deny this write operation to prevent the hidden volume from being overwritten
- CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
- continue;
- }
- }
- }
- else if (item->Write
- && RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET + TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE - 1))
- {
- // Prevent inappropriately designed software from damaging important data that may be out of sync with the backup on the Rescue Disk (such as the end of the encrypted area).
- Dump ("Preventing write to the system encryption key data area\n");
- CompleteOriginalIrp (item, STATUS_MEDIA_WRITE_PROTECTED, 0);
- continue;
- }
- else if (item->Write && IsHiddenSystemRunning()
- && (RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, TC_SECTOR_SIZE_BIOS, TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS - 1)
- || RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, GetBootDriveLength(), _I64_MAX)))
- {
- Dump ("Preventing write to boot loader or host protected area\n");
- CompleteOriginalIrp (item, STATUS_MEDIA_WRITE_PROTECTED, 0);
- continue;
- }
-
- dataBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe (irp->MdlAddress, HighPagePriority);
-
- if (dataBuffer == NULL)
- {
- CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
- continue;
- }
-
- // Divide data block to fragments to enable efficient overlapping of encryption and IO operations
-
- dataRemaining = item->OriginalLength;
- fragmentOffset = item->OriginalOffset;
-
- while (dataRemaining > 0)
- {
- BOOL isLastFragment = dataRemaining <= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
-
- ULONG dataFragmentLength = isLastFragment ? dataRemaining : TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
- activeFragmentBuffer = (activeFragmentBuffer == queue->FragmentBufferA ? queue->FragmentBufferB : queue->FragmentBufferA);
-
- InterlockedIncrement (&queue->IoThreadPendingRequestCount);
-
- // Create IO request
- request = GetPoolBuffer (queue, sizeof (EncryptedIoRequest));
- if (!request)
- {
- CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
- break;
- }
- request->Item = item;
- request->CompleteOriginalIrp = isLastFragment;
- request->Offset = fragmentOffset;
- request->Data = activeFragmentBuffer;
- request->OrigDataBufferFragment = dataBuffer;
- request->Length = dataFragmentLength;
-
- if (queue->IsFilterDevice)
- {
- if (queue->EncryptedAreaStart == -1 || queue->EncryptedAreaEnd == -1)
- {
- request->EncryptedLength = 0;
- }
- else
- {
- // Get intersection of data fragment with encrypted area
- GetIntersection (fragmentOffset.QuadPart, dataFragmentLength, queue->EncryptedAreaStart, queue->EncryptedAreaEnd, &intersectStart, &intersectLength);
-
- request->EncryptedOffset = intersectStart - fragmentOffset.QuadPart;
- request->EncryptedLength = intersectLength;
- }
- }
- else
- {
- request->EncryptedOffset = 0;
- request->EncryptedLength = dataFragmentLength;
- }
-
- AcquireFragmentBuffer (queue, activeFragmentBuffer);
-
- if (item->Write)
- {
- // Encrypt data
- memcpy (activeFragmentBuffer, dataBuffer, dataFragmentLength);
-
- if (request->EncryptedLength > 0)
- {
- UINT64_STRUCT dataUnit;
- ASSERT (request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length);
-
- dataUnit.Value = (request->Offset.QuadPart + request->EncryptedOffset) / ENCRYPTION_DATA_UNIT_SIZE;
-
- if (queue->CryptoInfo->bPartitionInInactiveSysEncScope)
- dataUnit.Value += queue->CryptoInfo->FirstDataUnitNo.Value;
- else if (queue->RemapEncryptedArea)
- dataUnit.Value += queue->RemappedAreaDataUnitOffset;
-
- EncryptDataUnits (activeFragmentBuffer + request->EncryptedOffset, &dataUnit, request->EncryptedLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
- }
- }
-
- // Queue IO request
- ExInterlockedInsertTailList (&queue->IoThreadQueue, &request->ListEntry, &queue->IoThreadQueueLock);
- KeSetEvent (&queue->IoThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
-
- if (isLastFragment)
- break;
-
- dataRemaining -= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
- dataBuffer += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
- fragmentOffset.QuadPart += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
- }
- }
- }
-
- PsTerminateSystemThread (STATUS_SUCCESS);
-}
-
-
-NTSTATUS EncryptedIoQueueAddIrp (EncryptedIoQueue *queue, PIRP irp)
-{
- NTSTATUS status;
-
- InterlockedIncrement (&queue->OutstandingIoCount);
- if (queue->StopPending)
- {
- Dump ("STATUS_DEVICE_NOT_READY out=%d\n", queue->OutstandingIoCount);
- status = STATUS_DEVICE_NOT_READY;
- goto err;
- }
-
- status = IoAcquireRemoveLock (&queue->RemoveLock, irp);
- if (!NT_SUCCESS (status))
- goto err;
-
-#ifdef TC_TRACE_IO_QUEUE
- {
- PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
- Dump ("* %I64d [%I64d] %c len=%d out=%d\n", irpSp->MajorFunction == IRP_MJ_WRITE ? irpSp->Parameters.Write.ByteOffset : irpSp->Parameters.Read.ByteOffset, GetElapsedTime (&queue->LastPerformanceCounter), irpSp->MajorFunction == IRP_MJ_WRITE ? 'W' : 'R', irpSp->MajorFunction == IRP_MJ_WRITE ? irpSp->Parameters.Write.Length : irpSp->Parameters.Read.Length, queue->OutstandingIoCount);
- }
-#endif
-
- IoMarkIrpPending (irp);
-
- ExInterlockedInsertTailList (&queue->MainThreadQueue, &irp->Tail.Overlay.ListEntry, &queue->MainThreadQueueLock);
- KeSetEvent (&queue->MainThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
-
- return STATUS_PENDING;
-
-err:
- DecrementOutstandingIoCount (queue);
- return status;
-}
-
-
-NTSTATUS EncryptedIoQueueHoldWhenIdle (EncryptedIoQueue *queue, int64 timeout)
-{
- NTSTATUS status;
- ASSERT (!queue->Suspended);
-
- queue->SuspendPending = TRUE;
-
- while (TRUE)
- {
- while (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0)
- {
- LARGE_INTEGER waitTimeout;
-
- waitTimeout.QuadPart = timeout * -10000;
- status = KeWaitForSingleObject (&queue->NoOutstandingIoEvent, Executive, KernelMode, FALSE, timeout != 0 ? &waitTimeout : NULL);
-
- if (status == STATUS_TIMEOUT)
- status = STATUS_UNSUCCESSFUL;
-
- if (!NT_SUCCESS (status))
- {
- queue->SuspendPending = FALSE;
- return status;
- }
-
- TCSleep (1);
- if (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0)
- {
- queue->SuspendPending = FALSE;
- return STATUS_UNSUCCESSFUL;
- }
- }
-
- KeClearEvent (&queue->QueueResumedEvent);
- queue->Suspended = TRUE;
-
- if (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) == 0)
- break;
-
- queue->Suspended = FALSE;
- KeSetEvent (&queue->QueueResumedEvent, IO_DISK_INCREMENT, FALSE);
- }
-
- queue->ReadAheadBufferValid = FALSE;
-
- queue->SuspendPending = FALSE;
- return STATUS_SUCCESS;
-}
-
-
-BOOL EncryptedIoQueueIsSuspended (EncryptedIoQueue *queue)
-{
- return queue->Suspended;
-}
-
-
-BOOL EncryptedIoQueueIsRunning (EncryptedIoQueue *queue)
-{
- return !queue->StopPending;
-}
-
-
-NTSTATUS EncryptedIoQueueResumeFromHold (EncryptedIoQueue *queue)
-{
- ASSERT (queue->Suspended);
-
- queue->Suspended = FALSE;
- KeSetEvent (&queue->QueueResumedEvent, IO_DISK_INCREMENT, FALSE);
-
- return STATUS_SUCCESS;
-}
-
-
-NTSTATUS EncryptedIoQueueStart (EncryptedIoQueue *queue)
-{
- NTSTATUS status;
- EncryptedIoQueueBuffer *buffer;
- int i;
-
- queue->StartPending = TRUE;
- queue->ThreadExitRequested = FALSE;
-
- queue->OutstandingIoCount = 0;
- queue->IoThreadPendingRequestCount = 0;
-
- queue->FirstPoolBuffer = NULL;
- KeInitializeMutex (&queue->BufferPoolMutex, 0);
-
- KeInitializeEvent (&queue->NoOutstandingIoEvent, SynchronizationEvent, FALSE);
- KeInitializeEvent (&queue->PoolBufferFreeEvent, SynchronizationEvent, FALSE);
- KeInitializeEvent (&queue->QueueResumedEvent, SynchronizationEvent, FALSE);
-
- queue->FragmentBufferA = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
- if (!queue->FragmentBufferA)
- goto noMemory;
-
- queue->FragmentBufferB = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
- if (!queue->FragmentBufferB)
- goto noMemory;
-
- KeInitializeEvent (&queue->FragmentBufferAFreeEvent, SynchronizationEvent, TRUE);
- KeInitializeEvent (&queue->FragmentBufferBFreeEvent, SynchronizationEvent, TRUE);
-
- queue->ReadAheadBufferValid = FALSE;
- queue->ReadAheadBuffer = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
- if (!queue->ReadAheadBuffer)
- goto noMemory;
-
- // Preallocate buffers
- for (i = 0; i < TC_ENC_IO_QUEUE_PREALLOCATED_IO_REQUEST_COUNT; ++i)
- {
- if (i < TC_ENC_IO_QUEUE_PREALLOCATED_ITEM_COUNT && !GetPoolBuffer (queue, sizeof (EncryptedIoQueueItem)))
- goto noMemory;
-
- if (!GetPoolBuffer (queue, sizeof (EncryptedIoRequest)))
- goto noMemory;
- }
-
- for (buffer = queue->FirstPoolBuffer; buffer != NULL; buffer = buffer->NextBuffer)
- {
- buffer->InUse = FALSE;
- }
-
- // Main thread
- InitializeListHead (&queue->MainThreadQueue);
- KeInitializeSpinLock (&queue->MainThreadQueueLock);
- KeInitializeEvent (&queue->MainThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
-
- status = TCStartThread (MainThreadProc, queue, &queue->MainThread);
- if (!NT_SUCCESS (status))
- goto err;
-
- // IO thread
- InitializeListHead (&queue->IoThreadQueue);
- KeInitializeSpinLock (&queue->IoThreadQueueLock);
- KeInitializeEvent (&queue->IoThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
-
- status = TCStartThread (IoThreadProc, queue, &queue->IoThread);
- if (!NT_SUCCESS (status))
- {
- queue->ThreadExitRequested = TRUE;
- TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
- goto err;
- }
-
- // Completion thread
- InitializeListHead (&queue->CompletionThreadQueue);
- KeInitializeSpinLock (&queue->CompletionThreadQueueLock);
- KeInitializeEvent (&queue->CompletionThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
-
- status = TCStartThread (CompletionThreadProc, queue, &queue->CompletionThread);
- if (!NT_SUCCESS (status))
- {
- queue->ThreadExitRequested = TRUE;
- TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
- TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent);
- goto err;
- }
-
-#ifdef TC_TRACE_IO_QUEUE
- GetElapsedTimeInit (&queue->LastPerformanceCounter);
-#endif
-
- queue->StopPending = FALSE;
- queue->StartPending = FALSE;
-
- Dump ("Queue started\n");
- return STATUS_SUCCESS;
-
-noMemory:
- status = STATUS_INSUFFICIENT_RESOURCES;
-
-err:
- if (queue->FragmentBufferA)
- TCfree (queue->FragmentBufferA);
- if (queue->FragmentBufferB)
- TCfree (queue->FragmentBufferB);
- if (queue->ReadAheadBuffer)
- TCfree (queue->ReadAheadBuffer);
-
- FreePoolBuffers (queue);
-
- queue->StartPending = FALSE;
- return status;
-}
-
-
-NTSTATUS EncryptedIoQueueStop (EncryptedIoQueue *queue)
-{
- ASSERT (!queue->StopPending);
- queue->StopPending = TRUE;
-
- while (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0)
- {
- KeWaitForSingleObject (&queue->NoOutstandingIoEvent, Executive, KernelMode, FALSE, NULL);
- }
-
- Dump ("Queue stopping out=%d\n", queue->OutstandingIoCount);
-
- queue->ThreadExitRequested = TRUE;
-
- TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
- TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent);
- TCStopThread (queue->CompletionThread, &queue->CompletionThreadQueueNotEmptyEvent);
-
- TCfree (queue->FragmentBufferA);
- TCfree (queue->FragmentBufferB);
- TCfree (queue->ReadAheadBuffer);
-
- FreePoolBuffers (queue);
-
- Dump ("Queue stopped out=%d\n", queue->OutstandingIoCount);
- return STATUS_SUCCESS;
-}
+/*
+ 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 "Apidrvr.h"
+#include "Ntdriver.h"
+#include "DriveFilter.h"
+#include "EncryptedIoQueue.h"
+#include "EncryptionThreadPool.h"
+#include "Volumes.h"
+#include <IntSafe.h>
+
+
+static void AcquireBufferPoolMutex (EncryptedIoQueue *queue)
+{
+ NTSTATUS status;
+
+ status = KeWaitForMutexObject (&queue->BufferPoolMutex, Executive, KernelMode, FALSE, NULL);
+ if (!NT_SUCCESS (status))
+ TC_BUG_CHECK (status);
+}
+
+
+static void ReleaseBufferPoolMutex (EncryptedIoQueue *queue)
+{
+ KeReleaseMutex (&queue->BufferPoolMutex, FALSE);
+}
+
+
+static void *GetPoolBuffer (EncryptedIoQueue *queue, ULONG requestedSize)
+{
+ EncryptedIoQueueBuffer *buffer;
+ void *bufferAddress = NULL;
+ BOOL requestedSizePresentInPool = FALSE;
+
+ while (TRUE)
+ {
+ AcquireBufferPoolMutex (queue);
+
+ for (buffer = queue->FirstPoolBuffer; ; buffer = buffer->NextBuffer)
+ {
+ if (buffer && buffer->Size == requestedSize)
+ {
+ requestedSizePresentInPool = TRUE;
+
+ if (!buffer->InUse)
+ {
+ // Reuse a free buffer
+ buffer->InUse = TRUE;
+ bufferAddress = buffer->Address;
+ break;
+ }
+ }
+
+ if (!buffer || !buffer->NextBuffer)
+ {
+ EncryptedIoQueueBuffer *newBuffer;
+
+ if (requestedSizePresentInPool && !queue->StartPending)
+ break;
+
+ // Allocate a new buffer
+ newBuffer = TCalloc (sizeof (EncryptedIoQueueBuffer));
+ if (!newBuffer)
+ {
+ bufferAddress = NULL;
+ break;
+ }
+
+ bufferAddress = TCalloc (requestedSize);
+ if (bufferAddress)
+ {
+ newBuffer->NextBuffer = NULL;
+ newBuffer->Address = bufferAddress;
+ newBuffer->Size = requestedSize;
+ newBuffer->InUse = TRUE;
+
+ if (!buffer)
+ queue->FirstPoolBuffer = newBuffer;
+ else
+ buffer->NextBuffer = newBuffer;
+ }
+ else
+ TCfree (newBuffer);
+
+ break;
+ }
+ }
+
+ ReleaseBufferPoolMutex (queue);
+
+ if (bufferAddress || !requestedSizePresentInPool || queue->StartPending)
+ break;
+
+ KeWaitForSingleObject (&queue->PoolBufferFreeEvent, Executive, KernelMode, FALSE, NULL);
+ }
+
+ return bufferAddress;
+}
+
+
+static void ReleasePoolBuffer (EncryptedIoQueue *queue, void *address)
+{
+ EncryptedIoQueueBuffer *buffer;
+ AcquireBufferPoolMutex (queue);
+
+ for (buffer = queue->FirstPoolBuffer; buffer != NULL; buffer = buffer->NextBuffer)
+ {
+ if (buffer->Address == address)
+ {
+ ASSERT (buffer->InUse);
+
+ buffer->InUse = FALSE;
+ break;
+ }
+ }
+
+ ReleaseBufferPoolMutex (queue);
+ KeSetEvent (&queue->PoolBufferFreeEvent, IO_DISK_INCREMENT, FALSE);
+}
+
+
+static void FreePoolBuffers (EncryptedIoQueue *queue)
+{
+ EncryptedIoQueueBuffer *buffer;
+ AcquireBufferPoolMutex (queue);
+
+ for (buffer = queue->FirstPoolBuffer; buffer != NULL; )
+ {
+ EncryptedIoQueueBuffer *nextBuffer = buffer->NextBuffer;
+
+ ASSERT (!buffer->InUse || queue->StartPending);
+
+ TCfree (buffer->Address);
+ TCfree (buffer);
+
+ buffer = nextBuffer;
+ }
+
+ queue->FirstPoolBuffer = NULL;
+ ReleaseBufferPoolMutex (queue);
+}
+
+
+static void DecrementOutstandingIoCount (EncryptedIoQueue *queue)
+{
+ if (InterlockedDecrement (&queue->OutstandingIoCount) == 0 && (queue->SuspendPending || queue->StopPending))
+ KeSetEvent (&queue->NoOutstandingIoEvent, IO_DISK_INCREMENT, FALSE);
+}
+
+
+static void OnItemCompleted (EncryptedIoQueueItem *item, BOOL freeItem)
+{
+ DecrementOutstandingIoCount (item->Queue);
+ IoReleaseRemoveLock (&item->Queue->RemoveLock, item->OriginalIrp);
+
+ if (NT_SUCCESS (item->Status))
+ {
+ if (item->Write)
+ item->Queue->TotalBytesWritten += item->OriginalLength;
+ else
+ item->Queue->TotalBytesRead += item->OriginalLength;
+ }
+
+ if (freeItem)
+ ReleasePoolBuffer (item->Queue, item);
+}
+
+
+static NTSTATUS CompleteOriginalIrp (EncryptedIoQueueItem *item, NTSTATUS status, ULONG_PTR information)
+{
+#ifdef TC_TRACE_IO_QUEUE
+ Dump ("< %I64d [%I64d] %c status=%x info=%I64d\n", item->OriginalIrpOffset, GetElapsedTime (&item->Queue->LastPerformanceCounter), item->Write ? 'W' : 'R', status, (int64) information);
+#endif
+
+ TCCompleteDiskIrp (item->OriginalIrp, status, information);
+
+ item->Status = status;
+ OnItemCompleted (item, TRUE);
+
+ return status;
+}
+
+
+static void AcquireFragmentBuffer (EncryptedIoQueue *queue, byte *buffer)
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (buffer == queue->FragmentBufferA)
+ {
+ status = KeWaitForSingleObject (&queue->FragmentBufferAFreeEvent, Executive, KernelMode, FALSE, NULL);
+ }
+ else if (buffer == queue->FragmentBufferB)
+ {
+ status = KeWaitForSingleObject (&queue->FragmentBufferBFreeEvent, Executive, KernelMode, FALSE, NULL);
+ }
+
+ if (!NT_SUCCESS (status))
+ TC_BUG_CHECK (status);
+}
+
+
+static void ReleaseFragmentBuffer (EncryptedIoQueue *queue, byte *buffer)
+{
+ if (buffer == queue->FragmentBufferA)
+ {
+ KeSetEvent (&queue->FragmentBufferAFreeEvent, IO_DISK_INCREMENT, FALSE);
+ }
+ else if (buffer == queue->FragmentBufferB)
+ {
+ KeSetEvent (&queue->FragmentBufferBFreeEvent, IO_DISK_INCREMENT, FALSE);
+ }
+ else
+ {
+ TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
+ }
+}
+
+
+static VOID CompletionThreadProc (PVOID threadArg)
+{
+ EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
+ PLIST_ENTRY listEntry;
+ EncryptedIoRequest *request;
+ UINT64_STRUCT dataUnit;
+
+ if (IsEncryptionThreadPoolRunning())
+ KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
+
+ while (!queue->ThreadExitRequested)
+ {
+ if (!NT_SUCCESS (KeWaitForSingleObject (&queue->CompletionThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL)))
+ continue;
+
+ if (queue->ThreadExitRequested)
+ break;
+
+ while ((listEntry = ExInterlockedRemoveHeadList (&queue->CompletionThreadQueue, &queue->CompletionThreadQueueLock)))
+ {
+ request = CONTAINING_RECORD (listEntry, EncryptedIoRequest, CompletionListEntry);
+
+ if (request->EncryptedLength > 0 && NT_SUCCESS (request->Item->Status))
+ {
+ ASSERT (request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length);
+ dataUnit.Value = (request->Offset.QuadPart + request->EncryptedOffset) / ENCRYPTION_DATA_UNIT_SIZE;
+
+ if (queue->CryptoInfo->bPartitionInInactiveSysEncScope)
+ dataUnit.Value += queue->CryptoInfo->FirstDataUnitNo.Value;
+ else if (queue->RemapEncryptedArea)
+ dataUnit.Value += queue->RemappedAreaDataUnitOffset;
+
+ DecryptDataUnits (request->Data + request->EncryptedOffset, &dataUnit, request->EncryptedLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
+ }
+
+ if (request->CompleteOriginalIrp)
+ {
+ CompleteOriginalIrp (request->Item, request->Item->Status,
+ NT_SUCCESS (request->Item->Status) ? request->Item->OriginalLength : 0);
+ }
+
+ ReleasePoolBuffer (queue, request);
+ }
+ }
+
+ PsTerminateSystemThread (STATUS_SUCCESS);
+}
+
+
+static NTSTATUS TCCachedRead (EncryptedIoQueue *queue, IO_STATUS_BLOCK *ioStatus, PVOID buffer, LARGE_INTEGER offset, ULONG length)
+{
+ queue->LastReadOffset = offset;
+ queue->LastReadLength = length;
+
+ if (queue->ReadAheadBufferValid && queue->ReadAheadOffset.QuadPart == offset.QuadPart && queue->ReadAheadLength >= length)
+ {
+ memcpy (buffer, queue->ReadAheadBuffer, length);
+
+ if (!queue->IsFilterDevice)
+ {
+ ioStatus->Information = length;
+ ioStatus->Status = STATUS_SUCCESS;
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ if (queue->IsFilterDevice)
+ return TCReadDevice (queue->LowerDeviceObject, buffer, offset, length);
+
+ return ZwReadFile (queue->HostFileHandle, NULL, NULL, NULL, ioStatus, buffer, length, &offset, NULL);
+}
+
+
+static VOID IoThreadProc (PVOID threadArg)
+{
+ EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
+ PLIST_ENTRY listEntry;
+ EncryptedIoRequest *request;
+
+ KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
+
+ if (!queue->IsFilterDevice && queue->SecurityClientContext)
+ {
+#ifdef DEBUG
+ NTSTATUS status =
+#endif
+ SeImpersonateClientEx (queue->SecurityClientContext, NULL);
+ ASSERT (NT_SUCCESS (status));
+ }
+
+ while (!queue->ThreadExitRequested)
+ {
+ if (!NT_SUCCESS (KeWaitForSingleObject (&queue->IoThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL)))
+ continue;
+
+ if (queue->ThreadExitRequested)
+ break;
+
+ while ((listEntry = ExInterlockedRemoveHeadList (&queue->IoThreadQueue, &queue->IoThreadQueueLock)))
+ {
+ InterlockedDecrement (&queue->IoThreadPendingRequestCount);
+ request = CONTAINING_RECORD (listEntry, EncryptedIoRequest, ListEntry);
+
+#ifdef TC_TRACE_IO_QUEUE
+ Dump ("%c %I64d [%I64d] roff=%I64d rlen=%d\n", request->Item->Write ? 'W' : 'R', request->Item->OriginalIrpOffset.QuadPart, GetElapsedTime (&queue->LastPerformanceCounter), request->Offset.QuadPart, request->Length);
+#endif
+
+ // Perform IO request if no preceding request of the item failed
+ if (NT_SUCCESS (request->Item->Status))
+ {
+ if (queue->IsFilterDevice)
+ {
+ if (queue->RemapEncryptedArea && request->EncryptedLength > 0)
+ {
+ if (request->EncryptedLength != request->Length)
+ {
+ // Up to three subfragments may be required to handle a partially remapped fragment
+ int subFragment;
+ byte *subFragmentData = request->Data;
+
+ for (subFragment = 0 ; subFragment < 3; ++subFragment)
+ {
+ LARGE_INTEGER subFragmentOffset;
+ ULONG subFragmentLength;
+ subFragmentOffset.QuadPart = request->Offset.QuadPart;
+
+ switch (subFragment)
+ {
+ case 0:
+ subFragmentLength = (ULONG) request->EncryptedOffset;
+ break;
+
+ case 1:
+ subFragmentOffset.QuadPart += request->EncryptedOffset + queue->RemappedAreaOffset;
+ subFragmentLength = request->EncryptedLength;
+ break;
+
+ case 2:
+ subFragmentOffset.QuadPart += request->EncryptedOffset + request->EncryptedLength;
+ subFragmentLength = (ULONG) (request->Length - (request->EncryptedOffset + request->EncryptedLength));
+ break;
+ }
+
+ if (subFragmentLength > 0)
+ {
+ if (request->Item->Write)
+ request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, subFragmentData, subFragmentOffset, subFragmentLength);
+ else
+ request->Item->Status = TCCachedRead (queue, NULL, subFragmentData, subFragmentOffset, subFragmentLength);
+
+ subFragmentData += subFragmentLength;
+ }
+ }
+ }
+ else
+ {
+ // Remap the fragment
+ LARGE_INTEGER remappedOffset;
+ remappedOffset.QuadPart = request->Offset.QuadPart + queue->RemappedAreaOffset;
+
+ if (request->Item->Write)
+ request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, request->Data, remappedOffset, request->Length);
+ else
+ request->Item->Status = TCCachedRead (queue, NULL, request->Data, remappedOffset, request->Length);
+ }
+ }
+ else
+ {
+ if (request->Item->Write)
+ request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, request->Data, request->Offset, request->Length);
+ else
+ request->Item->Status = TCCachedRead (queue, NULL, request->Data, request->Offset, request->Length);
+ }
+ }
+ else
+ {
+ IO_STATUS_BLOCK ioStatus;
+
+ if (request->Item->Write)
+ request->Item->Status = ZwWriteFile (queue->HostFileHandle, NULL, NULL, NULL, &ioStatus, request->Data, request->Length, &request->Offset, NULL);
+ else
+ request->Item->Status = TCCachedRead (queue, &ioStatus, request->Data, request->Offset, request->Length);
+
+ if (NT_SUCCESS (request->Item->Status) && ioStatus.Information != request->Length)
+ request->Item->Status = STATUS_END_OF_FILE;
+ }
+ }
+
+ if (request->Item->Write)
+ {
+ queue->ReadAheadBufferValid = FALSE;
+
+ ReleaseFragmentBuffer (queue, request->Data);
+
+ if (request->CompleteOriginalIrp)
+ {
+ CompleteOriginalIrp (request->Item, request->Item->Status,
+ NT_SUCCESS (request->Item->Status) ? request->Item->OriginalLength : 0);
+ }
+
+ ReleasePoolBuffer (queue, request);
+ }
+ else
+ {
+ BOOL readAhead = FALSE;
+
+ if (NT_SUCCESS (request->Item->Status))
+ memcpy (request->OrigDataBufferFragment, request->Data, request->Length);
+
+ ReleaseFragmentBuffer (queue, request->Data);
+ request->Data = request->OrigDataBufferFragment;
+
+ if (request->CompleteOriginalIrp
+ && queue->LastReadLength > 0
+ && NT_SUCCESS (request->Item->Status)
+ && InterlockedExchangeAdd (&queue->IoThreadPendingRequestCount, 0) == 0)
+ {
+ readAhead = TRUE;
+ InterlockedIncrement (&queue->OutstandingIoCount);
+ }
+
+ ExInterlockedInsertTailList (&queue->CompletionThreadQueue, &request->CompletionListEntry, &queue->CompletionThreadQueueLock);
+ KeSetEvent (&queue->CompletionThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
+
+ if (readAhead)
+ {
+ queue->ReadAheadBufferValid = FALSE;
+ queue->ReadAheadOffset.QuadPart = queue->LastReadOffset.QuadPart + queue->LastReadLength;
+ queue->ReadAheadLength = queue->LastReadLength;
+
+ if (queue->ReadAheadOffset.QuadPart + queue->ReadAheadLength <= queue->MaxReadAheadOffset.QuadPart)
+ {
+#ifdef TC_TRACE_IO_QUEUE
+ Dump ("A %I64d [%I64d] roff=%I64d rlen=%d\n", request->Item->OriginalIrpOffset.QuadPart, GetElapsedTime (&queue->LastPerformanceCounter), queue->ReadAheadOffset, queue->ReadAheadLength);
+#endif
+ if (queue->IsFilterDevice)
+ {
+ queue->ReadAheadBufferValid = NT_SUCCESS (TCReadDevice (queue->LowerDeviceObject, queue->ReadAheadBuffer, queue->ReadAheadOffset, queue->ReadAheadLength));
+ }
+ else
+ {
+ IO_STATUS_BLOCK ioStatus;
+ queue->ReadAheadBufferValid = NT_SUCCESS (ZwReadFile (queue->HostFileHandle, NULL, NULL, NULL, &ioStatus, queue->ReadAheadBuffer, queue->ReadAheadLength, &queue->ReadAheadOffset, NULL));
+ queue->ReadAheadLength = (ULONG) ioStatus.Information;
+ }
+ }
+
+ DecrementOutstandingIoCount (queue);
+ }
+ }
+ }
+ }
+
+ PsTerminateSystemThread (STATUS_SUCCESS);
+}
+
+
+static VOID MainThreadProc (PVOID threadArg)
+{
+ EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
+ PLIST_ENTRY listEntry;
+ EncryptedIoQueueItem *item;
+
+ LARGE_INTEGER fragmentOffset;
+ ULONG dataRemaining;
+ PUCHAR activeFragmentBuffer = queue->FragmentBufferA;
+ PUCHAR dataBuffer;
+ EncryptedIoRequest *request;
+ uint64 intersectStart;
+ uint32 intersectLength;
+ ULONGLONG addResult;
+ HRESULT hResult;
+
+ if (IsEncryptionThreadPoolRunning())
+ KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
+
+ while (!queue->ThreadExitRequested)
+ {
+ if (!NT_SUCCESS (KeWaitForSingleObject (&queue->MainThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL)))
+ continue;
+
+ while ((listEntry = ExInterlockedRemoveHeadList (&queue->MainThreadQueue, &queue->MainThreadQueueLock)))
+ {
+ PIRP irp = CONTAINING_RECORD (listEntry, IRP, Tail.Overlay.ListEntry);
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
+
+ if (queue->Suspended)
+ KeWaitForSingleObject (&queue->QueueResumedEvent, Executive, KernelMode, FALSE, NULL);
+
+ item = GetPoolBuffer (queue, sizeof (EncryptedIoQueueItem));
+ if (!item)
+ {
+ TCCompleteDiskIrp (irp, STATUS_INSUFFICIENT_RESOURCES, 0);
+ DecrementOutstandingIoCount (queue);
+ IoReleaseRemoveLock (&queue->RemoveLock, irp);
+
+ continue;
+ }
+
+ item->Queue = queue;
+ item->OriginalIrp = irp;
+ item->Status = STATUS_SUCCESS;
+
+ IoSetCancelRoutine (irp, NULL);
+ if (irp->Cancel)
+ {
+ CompleteOriginalIrp (item, STATUS_CANCELLED, 0);
+ continue;
+ }
+
+ switch (irpSp->MajorFunction)
+ {
+ case IRP_MJ_READ:
+ item->Write = FALSE;
+ item->OriginalOffset = irpSp->Parameters.Read.ByteOffset;
+ item->OriginalLength = irpSp->Parameters.Read.Length;
+ break;
+
+ case IRP_MJ_WRITE:
+ item->Write = TRUE;
+ item->OriginalOffset = irpSp->Parameters.Write.ByteOffset;
+ item->OriginalLength = irpSp->Parameters.Write.Length;
+ break;
+
+ default:
+ CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
+ continue;
+ }
+
+#ifdef TC_TRACE_IO_QUEUE
+ item->OriginalIrpOffset = item->OriginalOffset;
+#endif
+
+ // Handle misaligned read operations to work around a bug in Windows System Assessment Tool which does not follow FILE_FLAG_NO_BUFFERING requirements when benchmarking disk devices
+ if (queue->IsFilterDevice
+ && !item->Write
+ && item->OriginalLength > 0
+ && (item->OriginalLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) == 0
+ && (item->OriginalOffset.QuadPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0)
+ {
+ byte *buffer;
+ ULONG alignedLength;
+ LARGE_INTEGER alignedOffset;
+ hResult = ULongAdd(item->OriginalLength, ENCRYPTION_DATA_UNIT_SIZE, &alignedLength);
+ if (hResult != S_OK)
+ {
+ CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
+ continue;
+ }
+
+ alignedOffset.QuadPart = item->OriginalOffset.QuadPart & ~((LONGLONG) ENCRYPTION_DATA_UNIT_SIZE - 1);
+
+ buffer = TCalloc (alignedLength);
+ if (!buffer)
+ {
+ CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
+ continue;
+ }
+
+ item->Status = TCReadDevice (queue->LowerDeviceObject, buffer, alignedOffset, alignedLength);
+
+ if (NT_SUCCESS (item->Status))
+ {
+ UINT64_STRUCT dataUnit;
+
+ dataBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe (irp->MdlAddress, HighPagePriority);
+ if (!dataBuffer)
+ {
+ TCfree (buffer);
+ CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
+ continue;
+ }
+
+ if (queue->EncryptedAreaStart != -1 && queue->EncryptedAreaEnd != -1)
+ {
+ GetIntersection (alignedOffset.QuadPart, alignedLength, queue->EncryptedAreaStart, queue->EncryptedAreaEnd, &intersectStart, &intersectLength);
+ if (intersectLength > 0)
+ {
+ dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE;
+ DecryptDataUnits (buffer + (intersectStart - alignedOffset.QuadPart), &dataUnit, intersectLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
+ }
+ }
+
+ memcpy (dataBuffer, buffer + (item->OriginalOffset.LowPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)), item->OriginalLength);
+ }
+
+ TCfree (buffer);
+ CompleteOriginalIrp (item, item->Status, NT_SUCCESS (item->Status) ? item->OriginalLength : 0);
+ continue;
+ }
+
+ // Validate offset and length
+ if (item->OriginalLength == 0
+ || (item->OriginalLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0
+ || (item->OriginalOffset.QuadPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0
+ || ( !queue->IsFilterDevice &&
+ ( (S_OK != ULongLongAdd(item->OriginalOffset.QuadPart, item->OriginalLength, &addResult))
+ || (addResult > (ULONGLONG) queue->VirtualDeviceLength)
+ )
+ )
+ )
+ {
+ CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
+ continue;
+ }
+
+#ifdef TC_TRACE_IO_QUEUE
+ Dump ("Q %I64d [%I64d] %c len=%d\n", item->OriginalOffset.QuadPart, GetElapsedTime (&queue->LastPerformanceCounter), item->Write ? 'W' : 'R', item->OriginalLength);
+#endif
+
+ if (!queue->IsFilterDevice)
+ {
+ // Adjust the offset for host file or device
+ if (queue->CryptoInfo->hiddenVolume)
+ hResult = ULongLongAdd(item->OriginalOffset.QuadPart, queue->CryptoInfo->hiddenVolumeOffset, &addResult);
+ else
+ hResult = ULongLongAdd(item->OriginalOffset.QuadPart, queue->CryptoInfo->volDataAreaOffset, &addResult);
+
+ if (hResult != S_OK)
+ {
+ CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
+ continue;
+ }
+ else
+ item->OriginalOffset.QuadPart = addResult;
+
+ // Hidden volume protection
+ if (item->Write && queue->CryptoInfo->bProtectHiddenVolume)
+ {
+ // If there has already been a write operation denied in order to protect the
+ // hidden volume (since the volume mount time)
+ if (queue->CryptoInfo->bHiddenVolProtectionAction)
+ {
+ // Do not allow writing to this volume anymore. This is to fake a complete volume
+ // or system failure (otherwise certain kinds of inconsistency within the file
+ // system could indicate that this volume has used hidden volume protection).
+ CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
+ continue;
+ }
+
+ // Verify that no byte is going to be written to the hidden volume area
+ if (RegionsOverlap ((unsigned __int64) item->OriginalOffset.QuadPart,
+ (unsigned __int64) item->OriginalOffset.QuadPart + item->OriginalLength - 1,
+ queue->CryptoInfo->hiddenVolumeOffset,
+ (unsigned __int64) queue->CryptoInfo->hiddenVolumeOffset + queue->CryptoInfo->hiddenVolumeProtectedSize - 1))
+ {
+ Dump ("Hidden volume protection triggered: write %I64d-%I64d (protected %I64d-%I64d)\n", item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, queue->CryptoInfo->hiddenVolumeOffset, queue->CryptoInfo->hiddenVolumeOffset + queue->CryptoInfo->hiddenVolumeProtectedSize - 1);
+ queue->CryptoInfo->bHiddenVolProtectionAction = TRUE;
+
+ // Deny this write operation to prevent the hidden volume from being overwritten
+ CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
+ continue;
+ }
+ }
+ }
+ else if (item->Write
+ && RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET + TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE - 1))
+ {
+ // Prevent inappropriately designed software from damaging important data that may be out of sync with the backup on the Rescue Disk (such as the end of the encrypted area).
+ Dump ("Preventing write to the system encryption key data area\n");
+ CompleteOriginalIrp (item, STATUS_MEDIA_WRITE_PROTECTED, 0);
+ continue;
+ }
+ else if (item->Write && IsHiddenSystemRunning()
+ && (RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, TC_SECTOR_SIZE_BIOS, TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS - 1)
+ || RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, GetBootDriveLength(), _I64_MAX)))
+ {
+ Dump ("Preventing write to boot loader or host protected area\n");
+ CompleteOriginalIrp (item, STATUS_MEDIA_WRITE_PROTECTED, 0);
+ continue;
+ }
+
+ dataBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe (irp->MdlAddress, HighPagePriority);
+
+ if (dataBuffer == NULL)
+ {
+ CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
+ continue;
+ }
+
+ // Divide data block to fragments to enable efficient overlapping of encryption and IO operations
+
+ dataRemaining = item->OriginalLength;
+ fragmentOffset = item->OriginalOffset;
+
+ while (dataRemaining > 0)
+ {
+ BOOL isLastFragment = dataRemaining <= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
+
+ ULONG dataFragmentLength = isLastFragment ? dataRemaining : TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
+ activeFragmentBuffer = (activeFragmentBuffer == queue->FragmentBufferA ? queue->FragmentBufferB : queue->FragmentBufferA);
+
+ InterlockedIncrement (&queue->IoThreadPendingRequestCount);
+
+ // Create IO request
+ request = GetPoolBuffer (queue, sizeof (EncryptedIoRequest));
+ if (!request)
+ {
+ CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
+ break;
+ }
+ request->Item = item;
+ request->CompleteOriginalIrp = isLastFragment;
+ request->Offset = fragmentOffset;
+ request->Data = activeFragmentBuffer;
+ request->OrigDataBufferFragment = dataBuffer;
+ request->Length = dataFragmentLength;
+
+ if (queue->IsFilterDevice)
+ {
+ if (queue->EncryptedAreaStart == -1 || queue->EncryptedAreaEnd == -1)
+ {
+ request->EncryptedLength = 0;
+ }
+ else
+ {
+ // Get intersection of data fragment with encrypted area
+ GetIntersection (fragmentOffset.QuadPart, dataFragmentLength, queue->EncryptedAreaStart, queue->EncryptedAreaEnd, &intersectStart, &intersectLength);
+
+ request->EncryptedOffset = intersectStart - fragmentOffset.QuadPart;
+ request->EncryptedLength = intersectLength;
+ }
+ }
+ else
+ {
+ request->EncryptedOffset = 0;
+ request->EncryptedLength = dataFragmentLength;
+ }
+
+ AcquireFragmentBuffer (queue, activeFragmentBuffer);
+
+ if (item->Write)
+ {
+ // Encrypt data
+ memcpy (activeFragmentBuffer, dataBuffer, dataFragmentLength);
+
+ if (request->EncryptedLength > 0)
+ {
+ UINT64_STRUCT dataUnit;
+ ASSERT (request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length);
+
+ dataUnit.Value = (request->Offset.QuadPart + request->EncryptedOffset) / ENCRYPTION_DATA_UNIT_SIZE;
+
+ if (queue->CryptoInfo->bPartitionInInactiveSysEncScope)
+ dataUnit.Value += queue->CryptoInfo->FirstDataUnitNo.Value;
+ else if (queue->RemapEncryptedArea)
+ dataUnit.Value += queue->RemappedAreaDataUnitOffset;
+
+ EncryptDataUnits (activeFragmentBuffer + request->EncryptedOffset, &dataUnit, request->EncryptedLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
+ }
+ }
+
+ // Queue IO request
+ ExInterlockedInsertTailList (&queue->IoThreadQueue, &request->ListEntry, &queue->IoThreadQueueLock);
+ KeSetEvent (&queue->IoThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
+
+ if (isLastFragment)
+ break;
+
+ dataRemaining -= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
+ dataBuffer += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
+ fragmentOffset.QuadPart += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
+ }
+ }
+ }
+
+ PsTerminateSystemThread (STATUS_SUCCESS);
+}
+
+
+NTSTATUS EncryptedIoQueueAddIrp (EncryptedIoQueue *queue, PIRP irp)
+{
+ NTSTATUS status;
+
+ InterlockedIncrement (&queue->OutstandingIoCount);
+ if (queue->StopPending)
+ {
+ Dump ("STATUS_DEVICE_NOT_READY out=%d\n", queue->OutstandingIoCount);
+ status = STATUS_DEVICE_NOT_READY;
+ goto err;
+ }
+
+ status = IoAcquireRemoveLock (&queue->RemoveLock, irp);
+ if (!NT_SUCCESS (status))
+ goto err;
+
+#ifdef TC_TRACE_IO_QUEUE
+ {
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
+ Dump ("* %I64d [%I64d] %c len=%d out=%d\n", irpSp->MajorFunction == IRP_MJ_WRITE ? irpSp->Parameters.Write.ByteOffset : irpSp->Parameters.Read.ByteOffset, GetElapsedTime (&queue->LastPerformanceCounter), irpSp->MajorFunction == IRP_MJ_WRITE ? 'W' : 'R', irpSp->MajorFunction == IRP_MJ_WRITE ? irpSp->Parameters.Write.Length : irpSp->Parameters.Read.Length, queue->OutstandingIoCount);
+ }
+#endif
+
+ IoMarkIrpPending (irp);
+
+ ExInterlockedInsertTailList (&queue->MainThreadQueue, &irp->Tail.Overlay.ListEntry, &queue->MainThreadQueueLock);
+ KeSetEvent (&queue->MainThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
+
+ return STATUS_PENDING;
+
+err:
+ DecrementOutstandingIoCount (queue);
+ return status;
+}
+
+
+NTSTATUS EncryptedIoQueueHoldWhenIdle (EncryptedIoQueue *queue, int64 timeout)
+{
+ NTSTATUS status;
+ ASSERT (!queue->Suspended);
+
+ queue->SuspendPending = TRUE;
+
+ while (TRUE)
+ {
+ while (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0)
+ {
+ LARGE_INTEGER waitTimeout;
+
+ waitTimeout.QuadPart = timeout * -10000;
+ status = KeWaitForSingleObject (&queue->NoOutstandingIoEvent, Executive, KernelMode, FALSE, timeout != 0 ? &waitTimeout : NULL);
+
+ if (status == STATUS_TIMEOUT)
+ status = STATUS_UNSUCCESSFUL;
+
+ if (!NT_SUCCESS (status))
+ {
+ queue->SuspendPending = FALSE;
+ return status;
+ }
+
+ TCSleep (1);
+ if (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0)
+ {
+ queue->SuspendPending = FALSE;
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ KeClearEvent (&queue->QueueResumedEvent);
+ queue->Suspended = TRUE;
+
+ if (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) == 0)
+ break;
+
+ queue->Suspended = FALSE;
+ KeSetEvent (&queue->QueueResumedEvent, IO_DISK_INCREMENT, FALSE);
+ }
+
+ queue->ReadAheadBufferValid = FALSE;
+
+ queue->SuspendPending = FALSE;
+ return STATUS_SUCCESS;
+}
+
+
+BOOL EncryptedIoQueueIsSuspended (EncryptedIoQueue *queue)
+{
+ return queue->Suspended;
+}
+
+
+BOOL EncryptedIoQueueIsRunning (EncryptedIoQueue *queue)
+{
+ return !queue->StopPending;
+}
+
+
+NTSTATUS EncryptedIoQueueResumeFromHold (EncryptedIoQueue *queue)
+{
+ ASSERT (queue->Suspended);
+
+ queue->Suspended = FALSE;
+ KeSetEvent (&queue->QueueResumedEvent, IO_DISK_INCREMENT, FALSE);
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS EncryptedIoQueueStart (EncryptedIoQueue *queue)
+{
+ NTSTATUS status;
+ EncryptedIoQueueBuffer *buffer;
+ int i;
+
+ queue->StartPending = TRUE;
+ queue->ThreadExitRequested = FALSE;
+
+ queue->OutstandingIoCount = 0;
+ queue->IoThreadPendingRequestCount = 0;
+
+ queue->FirstPoolBuffer = NULL;
+ KeInitializeMutex (&queue->BufferPoolMutex, 0);
+
+ KeInitializeEvent (&queue->NoOutstandingIoEvent, SynchronizationEvent, FALSE);
+ KeInitializeEvent (&queue->PoolBufferFreeEvent, SynchronizationEvent, FALSE);
+ KeInitializeEvent (&queue->QueueResumedEvent, SynchronizationEvent, FALSE);
+
+ queue->FragmentBufferA = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
+ if (!queue->FragmentBufferA)
+ goto noMemory;
+
+ queue->FragmentBufferB = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
+ if (!queue->FragmentBufferB)
+ goto noMemory;
+
+ KeInitializeEvent (&queue->FragmentBufferAFreeEvent, SynchronizationEvent, TRUE);
+ KeInitializeEvent (&queue->FragmentBufferBFreeEvent, SynchronizationEvent, TRUE);
+
+ queue->ReadAheadBufferValid = FALSE;
+ queue->ReadAheadBuffer = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
+ if (!queue->ReadAheadBuffer)
+ goto noMemory;
+
+ // Preallocate buffers
+ for (i = 0; i < TC_ENC_IO_QUEUE_PREALLOCATED_IO_REQUEST_COUNT; ++i)
+ {
+ if (i < TC_ENC_IO_QUEUE_PREALLOCATED_ITEM_COUNT && !GetPoolBuffer (queue, sizeof (EncryptedIoQueueItem)))
+ goto noMemory;
+
+ if (!GetPoolBuffer (queue, sizeof (EncryptedIoRequest)))
+ goto noMemory;
+ }
+
+ for (buffer = queue->FirstPoolBuffer; buffer != NULL; buffer = buffer->NextBuffer)
+ {
+ buffer->InUse = FALSE;
+ }
+
+ // Main thread
+ InitializeListHead (&queue->MainThreadQueue);
+ KeInitializeSpinLock (&queue->MainThreadQueueLock);
+ KeInitializeEvent (&queue->MainThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
+
+ status = TCStartThread (MainThreadProc, queue, &queue->MainThread);
+ if (!NT_SUCCESS (status))
+ goto err;
+
+ // IO thread
+ InitializeListHead (&queue->IoThreadQueue);
+ KeInitializeSpinLock (&queue->IoThreadQueueLock);
+ KeInitializeEvent (&queue->IoThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
+
+ status = TCStartThread (IoThreadProc, queue, &queue->IoThread);
+ if (!NT_SUCCESS (status))
+ {
+ queue->ThreadExitRequested = TRUE;
+ TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
+ goto err;
+ }
+
+ // Completion thread
+ InitializeListHead (&queue->CompletionThreadQueue);
+ KeInitializeSpinLock (&queue->CompletionThreadQueueLock);
+ KeInitializeEvent (&queue->CompletionThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
+
+ status = TCStartThread (CompletionThreadProc, queue, &queue->CompletionThread);
+ if (!NT_SUCCESS (status))
+ {
+ queue->ThreadExitRequested = TRUE;
+ TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
+ TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent);
+ goto err;
+ }
+
+#ifdef TC_TRACE_IO_QUEUE
+ GetElapsedTimeInit (&queue->LastPerformanceCounter);
+#endif
+
+ queue->StopPending = FALSE;
+ queue->StartPending = FALSE;
+
+ Dump ("Queue started\n");
+ return STATUS_SUCCESS;
+
+noMemory:
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+err:
+ if (queue->FragmentBufferA)
+ TCfree (queue->FragmentBufferA);
+ if (queue->FragmentBufferB)
+ TCfree (queue->FragmentBufferB);
+ if (queue->ReadAheadBuffer)
+ TCfree (queue->ReadAheadBuffer);
+
+ FreePoolBuffers (queue);
+
+ queue->StartPending = FALSE;
+ return status;
+}
+
+
+NTSTATUS EncryptedIoQueueStop (EncryptedIoQueue *queue)
+{
+ ASSERT (!queue->StopPending);
+ queue->StopPending = TRUE;
+
+ while (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0)
+ {
+ KeWaitForSingleObject (&queue->NoOutstandingIoEvent, Executive, KernelMode, FALSE, NULL);
+ }
+
+ Dump ("Queue stopping out=%d\n", queue->OutstandingIoCount);
+
+ queue->ThreadExitRequested = TRUE;
+
+ TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
+ TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent);
+ TCStopThread (queue->CompletionThread, &queue->CompletionThreadQueueNotEmptyEvent);
+
+ TCfree (queue->FragmentBufferA);
+ TCfree (queue->FragmentBufferB);
+ TCfree (queue->ReadAheadBuffer);
+
+ FreePoolBuffers (queue);
+
+ Dump ("Queue stopped out=%d\n", queue->OutstandingIoCount);
+ return STATUS_SUCCESS;
+}
diff --git a/src/Driver/EncryptedIoQueue.h b/src/Driver/EncryptedIoQueue.h
index de9fce07..044009b7 100644
--- a/src/Driver/EncryptedIoQueue.h
+++ b/src/Driver/EncryptedIoQueue.h
@@ -1,165 +1,165 @@
-/*
- 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.
-*/
-
-#ifndef TC_HEADER_DRIVER_ENCRYPTED_IO_QUEUE
-#define TC_HEADER_DRIVER_ENCRYPTED_IO_QUEUE
-
-#include "TCdefs.h"
-#include "Apidrvr.h"
-
-#if 0
-# define TC_TRACE_IO_QUEUE
-#endif
-
-#define TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE (256 * 1024)
-
-#define TC_ENC_IO_QUEUE_PREALLOCATED_ITEM_COUNT 8
-#define TC_ENC_IO_QUEUE_PREALLOCATED_IO_REQUEST_COUNT 16
-
-
-typedef struct EncryptedIoQueueBufferStruct
-{
- struct EncryptedIoQueueBufferStruct *NextBuffer;
-
- void *Address;
- ULONG Size;
- BOOL InUse;
-
-} EncryptedIoQueueBuffer;
-
-
-typedef struct
-{
- PDEVICE_OBJECT DeviceObject;
-
- KMUTEX BufferPoolMutex;
- EncryptedIoQueueBuffer *FirstPoolBuffer;
-
- CRYPTO_INFO *CryptoInfo;
-
- // File-handle-based IO
- HANDLE HostFileHandle;
- int64 VirtualDeviceLength;
- SECURITY_CLIENT_CONTEXT *SecurityClientContext;
-
- // Filter device
- BOOL IsFilterDevice;
- PDEVICE_OBJECT LowerDeviceObject;
- int64 EncryptedAreaStart;
- volatile int64 EncryptedAreaEnd;
- volatile BOOL EncryptedAreaEndUpdatePending;
- BOOL RemapEncryptedArea;
- int64 RemappedAreaOffset;
- int64 RemappedAreaDataUnitOffset;
- IO_REMOVE_LOCK RemoveLock;
-
- // Main tread
- PKTHREAD MainThread;
- LIST_ENTRY MainThreadQueue;
- KSPIN_LOCK MainThreadQueueLock;
- KEVENT MainThreadQueueNotEmptyEvent;
-
- // IO thread
- PKTHREAD IoThread;
- LIST_ENTRY IoThreadQueue;
- KSPIN_LOCK IoThreadQueueLock;
- KEVENT IoThreadQueueNotEmptyEvent;
-
- // Completion thread
- PKTHREAD CompletionThread;
- LIST_ENTRY CompletionThreadQueue;
- KSPIN_LOCK CompletionThreadQueueLock;
- KEVENT CompletionThreadQueueNotEmptyEvent;
-
- // Fragment buffers
- byte *FragmentBufferA;
- byte *FragmentBufferB;
- KEVENT FragmentBufferAFreeEvent;
- KEVENT FragmentBufferBFreeEvent;
-
- // Read-ahead buffer
- BOOL ReadAheadBufferValid;
- LARGE_INTEGER LastReadOffset;
- ULONG LastReadLength;
- LARGE_INTEGER ReadAheadOffset;
- ULONG ReadAheadLength;
- byte *ReadAheadBuffer;
- LARGE_INTEGER MaxReadAheadOffset;
-
- LONG OutstandingIoCount;
- KEVENT NoOutstandingIoEvent;
- LONG IoThreadPendingRequestCount;
-
- KEVENT PoolBufferFreeEvent;
-
- __int64 TotalBytesRead;
- __int64 TotalBytesWritten;
-
- volatile BOOL StartPending;
- volatile BOOL ThreadExitRequested;
-
- volatile BOOL Suspended;
- volatile BOOL SuspendPending;
- volatile BOOL StopPending;
-
- KEVENT QueueResumedEvent;
-
-#ifdef TC_TRACE_IO_QUEUE
- LARGE_INTEGER LastPerformanceCounter;
-#endif
-
-} EncryptedIoQueue;
-
-
-typedef struct
-{
- EncryptedIoQueue *Queue;
- PIRP OriginalIrp;
- BOOL Write;
- ULONG OriginalLength;
- LARGE_INTEGER OriginalOffset;
- NTSTATUS Status;
-
-#ifdef TC_TRACE_IO_QUEUE
- LARGE_INTEGER OriginalIrpOffset;
-#endif
-
-} EncryptedIoQueueItem;
-
-
-typedef struct
-{
- EncryptedIoQueueItem *Item;
-
- BOOL CompleteOriginalIrp;
- LARGE_INTEGER Offset;
- ULONG Length;
- int64 EncryptedOffset;
- ULONG EncryptedLength;
- byte *Data;
- byte *OrigDataBufferFragment;
-
- LIST_ENTRY ListEntry;
- LIST_ENTRY CompletionListEntry;
-} EncryptedIoRequest;
-
-
-NTSTATUS EncryptedIoQueueAddIrp (EncryptedIoQueue *queue, PIRP irp);
-BOOL EncryptedIoQueueIsRunning (EncryptedIoQueue *queue);
-BOOL EncryptedIoQueueIsSuspended (EncryptedIoQueue *queue);
-NTSTATUS EncryptedIoQueueResumeFromHold (EncryptedIoQueue *queue);
-NTSTATUS EncryptedIoQueueStart (EncryptedIoQueue *queue);
-NTSTATUS EncryptedIoQueueStop (EncryptedIoQueue *queue);
-NTSTATUS EncryptedIoQueueHoldWhenIdle (EncryptedIoQueue *queue, int64 timeout);
-
-
-#endif // TC_HEADER_DRIVER_ENCRYPTED_IO_QUEUE
+/*
+ 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.
+*/
+
+#ifndef TC_HEADER_DRIVER_ENCRYPTED_IO_QUEUE
+#define TC_HEADER_DRIVER_ENCRYPTED_IO_QUEUE
+
+#include "TCdefs.h"
+#include "Apidrvr.h"
+
+#if 0
+# define TC_TRACE_IO_QUEUE
+#endif
+
+#define TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE (256 * 1024)
+
+#define TC_ENC_IO_QUEUE_PREALLOCATED_ITEM_COUNT 8
+#define TC_ENC_IO_QUEUE_PREALLOCATED_IO_REQUEST_COUNT 16
+
+
+typedef struct EncryptedIoQueueBufferStruct
+{
+ struct EncryptedIoQueueBufferStruct *NextBuffer;
+
+ void *Address;
+ ULONG Size;
+ BOOL InUse;
+
+} EncryptedIoQueueBuffer;
+
+
+typedef struct
+{
+ PDEVICE_OBJECT DeviceObject;
+
+ KMUTEX BufferPoolMutex;
+ EncryptedIoQueueBuffer *FirstPoolBuffer;
+
+ CRYPTO_INFO *CryptoInfo;
+
+ // File-handle-based IO
+ HANDLE HostFileHandle;
+ int64 VirtualDeviceLength;
+ SECURITY_CLIENT_CONTEXT *SecurityClientContext;
+
+ // Filter device
+ BOOL IsFilterDevice;
+ PDEVICE_OBJECT LowerDeviceObject;
+ int64 EncryptedAreaStart;
+ volatile int64 EncryptedAreaEnd;
+ volatile BOOL EncryptedAreaEndUpdatePending;
+ BOOL RemapEncryptedArea;
+ int64 RemappedAreaOffset;
+ int64 RemappedAreaDataUnitOffset;
+ IO_REMOVE_LOCK RemoveLock;
+
+ // Main tread
+ PKTHREAD MainThread;
+ LIST_ENTRY MainThreadQueue;
+ KSPIN_LOCK MainThreadQueueLock;
+ KEVENT MainThreadQueueNotEmptyEvent;
+
+ // IO thread
+ PKTHREAD IoThread;
+ LIST_ENTRY IoThreadQueue;
+ KSPIN_LOCK IoThreadQueueLock;
+ KEVENT IoThreadQueueNotEmptyEvent;
+
+ // Completion thread
+ PKTHREAD CompletionThread;
+ LIST_ENTRY CompletionThreadQueue;
+ KSPIN_LOCK CompletionThreadQueueLock;
+ KEVENT CompletionThreadQueueNotEmptyEvent;
+
+ // Fragment buffers
+ byte *FragmentBufferA;
+ byte *FragmentBufferB;
+ KEVENT FragmentBufferAFreeEvent;
+ KEVENT FragmentBufferBFreeEvent;
+
+ // Read-ahead buffer
+ BOOL ReadAheadBufferValid;
+ LARGE_INTEGER LastReadOffset;
+ ULONG LastReadLength;
+ LARGE_INTEGER ReadAheadOffset;
+ ULONG ReadAheadLength;
+ byte *ReadAheadBuffer;
+ LARGE_INTEGER MaxReadAheadOffset;
+
+ LONG OutstandingIoCount;
+ KEVENT NoOutstandingIoEvent;
+ LONG IoThreadPendingRequestCount;
+
+ KEVENT PoolBufferFreeEvent;
+
+ __int64 TotalBytesRead;
+ __int64 TotalBytesWritten;
+
+ volatile BOOL StartPending;
+ volatile BOOL ThreadExitRequested;
+
+ volatile BOOL Suspended;
+ volatile BOOL SuspendPending;
+ volatile BOOL StopPending;
+
+ KEVENT QueueResumedEvent;
+
+#ifdef TC_TRACE_IO_QUEUE
+ LARGE_INTEGER LastPerformanceCounter;
+#endif
+
+} EncryptedIoQueue;
+
+
+typedef struct
+{
+ EncryptedIoQueue *Queue;
+ PIRP OriginalIrp;
+ BOOL Write;
+ ULONG OriginalLength;
+ LARGE_INTEGER OriginalOffset;
+ NTSTATUS Status;
+
+#ifdef TC_TRACE_IO_QUEUE
+ LARGE_INTEGER OriginalIrpOffset;
+#endif
+
+} EncryptedIoQueueItem;
+
+
+typedef struct
+{
+ EncryptedIoQueueItem *Item;
+
+ BOOL CompleteOriginalIrp;
+ LARGE_INTEGER Offset;
+ ULONG Length;
+ int64 EncryptedOffset;
+ ULONG EncryptedLength;
+ byte *Data;
+ byte *OrigDataBufferFragment;
+
+ LIST_ENTRY ListEntry;
+ LIST_ENTRY CompletionListEntry;
+} EncryptedIoRequest;
+
+
+NTSTATUS EncryptedIoQueueAddIrp (EncryptedIoQueue *queue, PIRP irp);
+BOOL EncryptedIoQueueIsRunning (EncryptedIoQueue *queue);
+BOOL EncryptedIoQueueIsSuspended (EncryptedIoQueue *queue);
+NTSTATUS EncryptedIoQueueResumeFromHold (EncryptedIoQueue *queue);
+NTSTATUS EncryptedIoQueueStart (EncryptedIoQueue *queue);
+NTSTATUS EncryptedIoQueueStop (EncryptedIoQueue *queue);
+NTSTATUS EncryptedIoQueueHoldWhenIdle (EncryptedIoQueue *queue, int64 timeout);
+
+
+#endif // TC_HEADER_DRIVER_ENCRYPTED_IO_QUEUE
diff --git a/src/Driver/Makefile b/src/Driver/Makefile
index 53b9a3d6..5acbbd24 100644
--- a/src/Driver/Makefile
+++ b/src/Driver/Makefile
@@ -1 +1 @@
-!INCLUDE $(NTMAKEENV)\makefile.def
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/src/Driver/Ntdriver.c b/src/Driver/Ntdriver.c
index eeea7815..c771b3ce 100644
--- a/src/Driver/Ntdriver.c
+++ b/src/Driver/Ntdriver.c
@@ -1,3563 +1,3563 @@
-/*
- Legal Notice: Some portions of the source code contained in this file were
- derived from the source code of TrueCrypt 7.1a, which is
- Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
- governed by the TrueCrypt License 3.0, also from the source code of
- Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
- and which is governed by the 'License Agreement for Encryption for the Masses'
- 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 "Crypto.h"
-#include "Fat.h"
-#include "Tests.h"
-#include "cpu.h"
-
-#include "Apidrvr.h"
-#include "Boot/Windows/BootDefs.h"
-#include "EncryptedIoQueue.h"
-#include "EncryptionThreadPool.h"
-#include "Ntdriver.h"
-#include "Ntvol.h"
-#include "DriveFilter.h"
-#include "DumpFilter.h"
-#include "Cache.h"
-#include "Volumes.h"
-#include "VolumeFilter.h"
-
-#include <tchar.h>
-#include <initguid.h>
-#include <mountmgr.h>
-#include <mountdev.h>
-#include <ntddvol.h>
-
-#include <Ntstrsafe.h>
-#include <Intsafe.h>
-
-/* Init section, which is thrown away as soon as DriverEntry returns */
-#pragma alloc_text(INIT,DriverEntry)
-#pragma alloc_text(INIT,TCCreateRootDeviceObject)
-
-PDRIVER_OBJECT TCDriverObject;
-PDEVICE_OBJECT RootDeviceObject = NULL;
-static KMUTEX RootDeviceControlMutex;
-BOOL DriverShuttingDown = FALSE;
-BOOL SelfTestsPassed;
-int LastUniqueVolumeId;
-ULONG OsMajorVersion = 0;
-ULONG OsMinorVersion;
-BOOL DriverUnloadDisabled = FALSE;
-BOOL PortableMode = FALSE;
-BOOL VolumeClassFilterRegistered = FALSE;
-BOOL CacheBootPassword = FALSE;
-BOOL CacheBootPim = FALSE;
-BOOL NonAdminSystemFavoritesAccessDisabled = FALSE;
-static size_t EncryptionThreadPoolFreeCpuCountLimit = 0;
-static BOOL SystemFavoriteVolumeDirty = FALSE;
-static BOOL PagingFileCreationPrevented = FALSE;
-static BOOL EnableExtendedIoctlSupport = FALSE;
-
-PDEVICE_OBJECT VirtualVolumeDeviceObjects[MAX_MOUNTED_VOLUME_DRIVE_NUMBER + 1];
-
-
-NTSTATUS DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
-{
- PKEY_VALUE_PARTIAL_INFORMATION startKeyValue;
- LONG version;
- int i;
-
- Dump ("DriverEntry " TC_APP_NAME " " VERSION_STRING "\n");
-
- DetectX86Features ();
-
- PsGetVersion (&OsMajorVersion, &OsMinorVersion, NULL, NULL);
-
- // Load dump filter if the main driver is already loaded
- if (NT_SUCCESS (TCDeviceIoControl (NT_ROOT_PREFIX, TC_IOCTL_GET_DRIVER_VERSION, NULL, 0, &version, sizeof (version))))
- return DumpFilterEntry ((PFILTER_EXTENSION) DriverObject, (PFILTER_INITIALIZATION_DATA) RegistryPath);
-
- TCDriverObject = DriverObject;
- memset (VirtualVolumeDeviceObjects, 0, sizeof (VirtualVolumeDeviceObjects));
-
- ReadRegistryConfigFlags (TRUE);
- EncryptionThreadPoolStart (EncryptionThreadPoolFreeCpuCountLimit);
- SelfTestsPassed = AutoTestAlgorithms();
-
- // Enable device class filters and load boot arguments if the driver is set to start at system boot
-
- if (NT_SUCCESS (TCReadRegistryKey (RegistryPath, L"Start", &startKeyValue)))
- {
- if (startKeyValue->Type == REG_DWORD && *((uint32 *) startKeyValue->Data) == SERVICE_BOOT_START)
- {
- if (!SelfTestsPassed)
- TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
-
- LoadBootArguments();
- VolumeClassFilterRegistered = IsVolumeClassFilterRegistered();
-
- DriverObject->DriverExtension->AddDevice = DriverAddDevice;
- }
-
- TCfree (startKeyValue);
- }
-
- for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
- {
- DriverObject->MajorFunction[i] = TCDispatchQueueIRP;
- }
-
- DriverObject->DriverUnload = TCUnloadDriver;
- return TCCreateRootDeviceObject (DriverObject);
-}
-
-
-NTSTATUS DriverAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo)
-{
-#ifdef DEBUG
- char nameInfoBuffer[128];
- POBJECT_NAME_INFORMATION nameInfo = (POBJECT_NAME_INFORMATION) nameInfoBuffer;
- ULONG nameInfoSize;
- Dump ("AddDevice pdo=%p type=%x name=%ws\n", pdo, pdo->DeviceType, NT_SUCCESS (ObQueryNameString (pdo, nameInfo, sizeof (nameInfoBuffer), &nameInfoSize)) ? nameInfo->Name.Buffer : L"?");
-#endif
-
- if (VolumeClassFilterRegistered && BootArgsValid && BootArgs.HiddenSystemPartitionStart != 0)
- {
- PWSTR interfaceLinks = NULL;
- if (NT_SUCCESS (IoGetDeviceInterfaces (&GUID_DEVINTERFACE_VOLUME, pdo, DEVICE_INTERFACE_INCLUDE_NONACTIVE, &interfaceLinks)) && interfaceLinks)
- {
- if (interfaceLinks[0] != UNICODE_NULL)
- {
- Dump ("Volume pdo=%p interface=%ws\n", pdo, interfaceLinks);
- ExFreePool (interfaceLinks);
-
- return VolumeFilterAddDevice (driverObject, pdo);
- }
-
- ExFreePool (interfaceLinks);
- }
- }
-
- return DriveFilterAddDevice (driverObject, pdo);
-}
-
-
-// Dumps a memory region to debug output
-void DumpMemory (void *mem, int size)
-{
- unsigned char str[20];
- unsigned char *m = mem;
- int i,j;
-
- for (j = 0; j < size / 8; j++)
- {
- memset (str,0,sizeof str);
- for (i = 0; i < 8; i++)
- {
- if (m[i] > ' ' && m[i] <= '~')
- str[i]=m[i];
- else
- str[i]='.';
- }
-
- Dump ("0x%08p %02x %02x %02x %02x %02x %02x %02x %02x %s\n",
- m, m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], str);
-
- m+=8;
- }
-}
-
-
-BOOL ValidateIOBufferSize (PIRP irp, size_t requiredBufferSize, ValidateIOBufferSizeType type)
-{
- PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
- BOOL input = (type == ValidateInput || type == ValidateInputOutput);
- BOOL output = (type == ValidateOutput || type == ValidateInputOutput);
-
- if ((input && irpSp->Parameters.DeviceIoControl.InputBufferLength < requiredBufferSize)
- || (output && irpSp->Parameters.DeviceIoControl.OutputBufferLength < requiredBufferSize))
- {
- Dump ("STATUS_BUFFER_TOO_SMALL ioctl=0x%x,%d in=%d out=%d reqsize=%d insize=%d outsize=%d\n", (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16), (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2), input, output, requiredBufferSize, irpSp->Parameters.DeviceIoControl.InputBufferLength, irpSp->Parameters.DeviceIoControl.OutputBufferLength);
-
- irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
- irp->IoStatus.Information = 0;
- return FALSE;
- }
-
- if (!input && output)
- memset (irp->AssociatedIrp.SystemBuffer, 0, irpSp->Parameters.DeviceIoControl.OutputBufferLength);
-
- return TRUE;
-}
-
-
-PDEVICE_OBJECT GetVirtualVolumeDeviceObject (int driveNumber)
-{
- if (driveNumber < MIN_MOUNTED_VOLUME_DRIVE_NUMBER || driveNumber > MAX_MOUNTED_VOLUME_DRIVE_NUMBER)
- return NULL;
-
- return VirtualVolumeDeviceObjects[driveNumber];
-}
-
-
-/* TCDispatchQueueIRP queues any IRP's so that they can be processed later
- by the thread -- or in some cases handles them immediately! */
-NTSTATUS TCDispatchQueueIRP (PDEVICE_OBJECT DeviceObject, PIRP Irp)
-{
- PEXTENSION Extension = (PEXTENSION) DeviceObject->DeviceExtension;
- PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
- NTSTATUS ntStatus;
-
-#ifdef _DEBUG
- if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL && (Extension->bRootDevice || Extension->IsVolumeDevice))
- {
- switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
- {
- case TC_IOCTL_GET_MOUNTED_VOLUMES:
- case TC_IOCTL_GET_PASSWORD_CACHE_STATUS:
- case TC_IOCTL_GET_PORTABLE_MODE_STATUS:
- case TC_IOCTL_SET_PORTABLE_MODE_STATUS:
- case TC_IOCTL_OPEN_TEST:
- case TC_IOCTL_GET_RESOLVED_SYMLINK:
- case TC_IOCTL_GET_DEVICE_REFCOUNT:
- case TC_IOCTL_GET_DRIVE_PARTITION_INFO:
- case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES:
- case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS:
- case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS:
- case TC_IOCTL_GET_WARNING_FLAGS:
- case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING:
- case IOCTL_DISK_CHECK_VERIFY:
- break;
-
- default:
- Dump ("%ls (0x%x %d)\n",
- TCTranslateCode (irpSp->Parameters.DeviceIoControl.IoControlCode),
- (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16),
- (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2));
- }
- }
-#endif
-
- if (!Extension->bRootDevice)
- {
- // Drive filter IRP
- if (Extension->IsDriveFilterDevice)
- return DriveFilterDispatchIrp (DeviceObject, Irp);
-
- // Volume filter IRP
- if (Extension->IsVolumeFilterDevice)
- return VolumeFilterDispatchIrp (DeviceObject, Irp);
- }
-
- switch (irpSp->MajorFunction)
- {
- case IRP_MJ_CLOSE:
- case IRP_MJ_CREATE:
- case IRP_MJ_CLEANUP:
- return COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0);
-
- case IRP_MJ_SHUTDOWN:
- if (Extension->bRootDevice)
- {
- Dump ("Driver shutting down\n");
- DriverShuttingDown = TRUE;
-
- if (EncryptionSetupThread)
- while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES);
-
- if (DecoySystemWipeThread)
- while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES);
-
- OnShutdownPending();
- }
-
- return COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0);
-
- case IRP_MJ_FLUSH_BUFFERS:
- case IRP_MJ_READ:
- case IRP_MJ_WRITE:
- case IRP_MJ_DEVICE_CONTROL:
-
- if (Extension->bRootDevice)
- {
- if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
- {
- NTSTATUS status = KeWaitForMutexObject (&RootDeviceControlMutex, Executive, KernelMode, FALSE, NULL);
- if (!NT_SUCCESS (status))
- return status;
-
- status = ProcessMainDeviceControlIrp (DeviceObject, Extension, Irp);
-
- KeReleaseMutex (&RootDeviceControlMutex, FALSE);
- return status;
- }
- break;
- }
-
- if (Extension->bShuttingDown)
- {
- Dump ("Device %d shutting down: STATUS_DELETE_PENDING\n", Extension->nDosDriveNo);
- return TCCompleteDiskIrp (Irp, STATUS_DELETE_PENDING, 0);
- }
-
- if (Extension->bRemovable
- && (DeviceObject->Flags & DO_VERIFY_VOLUME)
- && !(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME)
- && irpSp->MajorFunction != IRP_MJ_FLUSH_BUFFERS)
- {
- Dump ("Removable device %d has DO_VERIFY_VOLUME flag: STATUS_DEVICE_NOT_READY\n", Extension->nDosDriveNo);
- return TCCompleteDiskIrp (Irp, STATUS_DEVICE_NOT_READY, 0);
- }
-
- switch (irpSp->MajorFunction)
- {
- case IRP_MJ_READ:
- case IRP_MJ_WRITE:
- ntStatus = EncryptedIoQueueAddIrp (&Extension->Queue, Irp);
-
- if (ntStatus != STATUS_PENDING)
- TCCompleteDiskIrp (Irp, ntStatus, 0);
-
- return ntStatus;
-
- case IRP_MJ_DEVICE_CONTROL:
- ntStatus = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp);
- if (!NT_SUCCESS (ntStatus))
- return TCCompleteIrp (Irp, ntStatus, 0);
-
- IoMarkIrpPending (Irp);
-
- ExInterlockedInsertTailList (&Extension->ListEntry, &Irp->Tail.Overlay.ListEntry, &Extension->ListSpinLock);
- KeReleaseSemaphore (&Extension->RequestSemaphore, IO_DISK_INCREMENT, 1, FALSE);
-
- return STATUS_PENDING;
-
- case IRP_MJ_FLUSH_BUFFERS:
- return TCCompleteDiskIrp (Irp, STATUS_SUCCESS, 0);
- }
-
- break;
-
- case IRP_MJ_PNP:
- if (!Extension->bRootDevice
- && Extension->IsVolumeDevice
- && irpSp->MinorFunction == IRP_MN_DEVICE_USAGE_NOTIFICATION
- && irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging
- && irpSp->Parameters.UsageNotification.InPath)
- {
- PagingFileCreationPrevented = TRUE;
- return TCCompleteIrp (Irp, STATUS_UNSUCCESSFUL, 0);
- }
- break;
- }
-
- return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
-}
-
-NTSTATUS TCCreateRootDeviceObject (PDRIVER_OBJECT DriverObject)
-{
- UNICODE_STRING Win32NameString, ntUnicodeString;
- WCHAR dosname[32], ntname[32];
- PDEVICE_OBJECT DeviceObject;
- NTSTATUS ntStatus;
- BOOL *bRootExtension;
-
- Dump ("TCCreateRootDeviceObject BEGIN\n");
- ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
-
- RtlStringCbCopyW (dosname, sizeof(dosname),(LPWSTR) DOS_ROOT_PREFIX);
- RtlStringCbCopyW (ntname, sizeof(ntname),(LPWSTR) NT_ROOT_PREFIX);
- RtlInitUnicodeString (&ntUnicodeString, ntname);
- RtlInitUnicodeString (&Win32NameString, dosname);
-
- Dump ("Creating root device nt=%ls dos=%ls\n", ntname, dosname);
-
- ntStatus = IoCreateDevice (
- DriverObject,
- sizeof (BOOL),
- &ntUnicodeString,
- FILE_DEVICE_UNKNOWN,
- FILE_DEVICE_SECURE_OPEN,
- FALSE,
- &DeviceObject);
-
- if (!NT_SUCCESS (ntStatus))
- {
- Dump ("TCCreateRootDeviceObject NTSTATUS = 0x%08x END\n", ntStatus);
- return ntStatus;/* Failed to create DeviceObject */
- }
-
- DeviceObject->Flags |= DO_DIRECT_IO;
- DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
-
- /* Setup the device extension */
- bRootExtension = (BOOL *) DeviceObject->DeviceExtension;
- *bRootExtension = TRUE;
-
- KeInitializeMutex (&RootDeviceControlMutex, 0);
-
- ntStatus = IoCreateSymbolicLink (&Win32NameString, &ntUnicodeString);
-
- if (!NT_SUCCESS (ntStatus))
- {
- Dump ("TCCreateRootDeviceObject NTSTATUS = 0x%08x END\n", ntStatus);
- IoDeleteDevice (DeviceObject);
- return ntStatus;
- }
-
- IoRegisterShutdownNotification (DeviceObject);
- RootDeviceObject = DeviceObject;
-
- Dump ("TCCreateRootDeviceObject STATUS_SUCCESS END\n");
- return STATUS_SUCCESS;
-}
-
-NTSTATUS TCCreateDeviceObject (PDRIVER_OBJECT DriverObject,
- PDEVICE_OBJECT * ppDeviceObject,
- MOUNT_STRUCT * mount)
-{
- UNICODE_STRING ntUnicodeString;
- WCHAR ntname[32];
- PEXTENSION Extension;
- NTSTATUS ntStatus;
- ULONG devChars = 0;
-#if defined (DEBUG)
- WCHAR dosname[32];
-#endif
-
- Dump ("TCCreateDeviceObject BEGIN\n");
- ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
-
- TCGetNTNameFromNumber (ntname, sizeof(ntname),mount->nDosDriveNo);
- RtlInitUnicodeString (&ntUnicodeString, ntname);
-#if defined (DEBUG)
- TCGetDosNameFromNumber (dosname, sizeof(dosname),mount->nDosDriveNo, DeviceNamespaceDefault);
-#endif
-
- devChars = FILE_DEVICE_SECURE_OPEN;
- devChars |= mount->bMountReadOnly ? FILE_READ_ONLY_DEVICE : 0;
- devChars |= mount->bMountRemovable ? FILE_REMOVABLE_MEDIA : 0;
-
- Dump ("Creating device nt=%ls dos=%ls\n", ntname, dosname);
-
- ntStatus = IoCreateDevice (
- DriverObject, /* Our Driver Object */
- sizeof (EXTENSION), /* Size of state information */
- &ntUnicodeString, /* Device name "\Device\Name" */
- FILE_DEVICE_DISK, /* Device type */
- devChars, /* Device characteristics */
- FALSE, /* Exclusive device */
- ppDeviceObject); /* Returned ptr to Device Object */
-
- if (!NT_SUCCESS (ntStatus))
- {
- Dump ("TCCreateDeviceObject NTSTATUS = 0x%08x END\n", ntStatus);
- return ntStatus;/* Failed to create DeviceObject */
- }
- /* Initialize device object and extension. */
-
- (*ppDeviceObject)->Flags |= DO_DIRECT_IO;
- (*ppDeviceObject)->StackSize += 6; // Reduce occurrence of NO_MORE_IRP_STACK_LOCATIONS bug check caused by buggy drivers
-
- /* Setup the device extension */
- Extension = (PEXTENSION) (*ppDeviceObject)->DeviceExtension;
- memset (Extension, 0, sizeof (EXTENSION));
-
- Extension->IsVolumeDevice = TRUE;
- Extension->nDosDriveNo = mount->nDosDriveNo;
- Extension->bRemovable = mount->bMountRemovable;
- Extension->PartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope;
- Extension->SystemFavorite = mount->SystemFavorite;
-
- KeInitializeEvent (&Extension->keCreateEvent, SynchronizationEvent, FALSE);
- KeInitializeSemaphore (&Extension->RequestSemaphore, 0L, MAXLONG);
- KeInitializeSpinLock (&Extension->ListSpinLock);
- InitializeListHead (&Extension->ListEntry);
- IoInitializeRemoveLock (&Extension->Queue.RemoveLock, 'LRCV', 0, 0);
-
- VirtualVolumeDeviceObjects[mount->nDosDriveNo] = *ppDeviceObject;
-
- Dump ("TCCreateDeviceObject STATUS_SUCCESS END\n");
-
- return STATUS_SUCCESS;
-}
-
-
-BOOL RootDeviceControlMutexAcquireNoWait ()
-{
- NTSTATUS status;
- LARGE_INTEGER timeout;
- timeout.QuadPart = 0;
-
- status = KeWaitForMutexObject (&RootDeviceControlMutex, Executive, KernelMode, FALSE, &timeout);
- return NT_SUCCESS (status) && status != STATUS_TIMEOUT;
-}
-
-
-void RootDeviceControlMutexRelease ()
-{
- KeReleaseMutex (&RootDeviceControlMutex, FALSE);
-}
-
-
-NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp)
-{
- PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
-
- switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
- {
-
- case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
- if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_NAME), ValidateOutput))
- {
- Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME);
- Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
- }
- else
- {
- ULONG outLength;
- UNICODE_STRING ntUnicodeString;
- WCHAR ntName[256];
- PMOUNTDEV_NAME outputBuffer = (PMOUNTDEV_NAME) Irp->AssociatedIrp.SystemBuffer;
-
- TCGetNTNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo);
- RtlInitUnicodeString (&ntUnicodeString, ntName);
-
- outputBuffer->NameLength = ntUnicodeString.Length;
- outLength = ntUnicodeString.Length + sizeof(USHORT);
-
- if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength)
- {
- Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME);
- Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
-
- break;
- }
-
- RtlCopyMemory ((PCHAR)outputBuffer->Name,ntUnicodeString.Buffer, ntUnicodeString.Length);
-
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = outLength;
-
- Dump ("name = %ls\n",ntName);
- }
- break;
-
- case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
- if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_UNIQUE_ID), ValidateOutput))
- {
- Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID);
- Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
- }
- else
- {
- ULONG outLength;
- UCHAR volId[128], tmp[] = { 0,0 };
- PMOUNTDEV_UNIQUE_ID outputBuffer = (PMOUNTDEV_UNIQUE_ID) Irp->AssociatedIrp.SystemBuffer;
-
- RtlStringCbCopyA (volId, sizeof(volId),TC_UNIQUE_ID_PREFIX);
- tmp[0] = 'A' + (UCHAR) Extension->nDosDriveNo;
- RtlStringCbCatA (volId, sizeof(volId),tmp);
-
- outputBuffer->UniqueIdLength = (USHORT) strlen (volId);
- outLength = (ULONG) (strlen (volId) + sizeof (USHORT));
-
- if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength)
- {
- Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID);
- Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
- break;
- }
-
- RtlCopyMemory ((PCHAR)outputBuffer->UniqueId, volId, strlen (volId));
-
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = outLength;
-
- Dump ("id = %s\n",volId);
- }
- break;
-
- case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME:
- {
- ULONG outLength;
- UNICODE_STRING ntUnicodeString;
- WCHAR ntName[256];
- PMOUNTDEV_SUGGESTED_LINK_NAME outputBuffer = (PMOUNTDEV_SUGGESTED_LINK_NAME) Irp->AssociatedIrp.SystemBuffer;
-
- if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_SUGGESTED_LINK_NAME), ValidateOutput))
- {
- Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- Irp->IoStatus.Information = 0;
- break;
- }
-
- TCGetDosNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo, DeviceNamespaceDefault);
- RtlInitUnicodeString (&ntUnicodeString, ntName);
-
- outLength = FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME,Name) + ntUnicodeString.Length;
-
- outputBuffer->UseOnlyIfThereAreNoOtherLinks = FALSE;
- outputBuffer->NameLength = ntUnicodeString.Length;
-
- if(irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength)
- {
- Irp->IoStatus.Information = sizeof (MOUNTDEV_SUGGESTED_LINK_NAME);
- Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
- break;
- }
-
- RtlCopyMemory ((PCHAR)outputBuffer->Name,ntUnicodeString.Buffer, ntUnicodeString.Length);
-
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = outLength;
-
- Dump ("link = %ls\n",ntName);
- }
- break;
-
- case IOCTL_DISK_GET_MEDIA_TYPES:
- case IOCTL_DISK_GET_DRIVE_GEOMETRY:
- /* Return the drive geometry for the disk. Note that we
- return values which were made up to suit the disk size. */
- if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY), ValidateOutput))
- {
- PDISK_GEOMETRY outputBuffer = (PDISK_GEOMETRY)
- Irp->AssociatedIrp.SystemBuffer;
-
- outputBuffer->MediaType = Extension->bRemovable ? RemovableMedia : FixedMedia;
- outputBuffer->Cylinders.QuadPart = Extension->NumberOfCylinders;
- outputBuffer->TracksPerCylinder = Extension->TracksPerCylinder;
- outputBuffer->SectorsPerTrack = Extension->SectorsPerTrack;
- outputBuffer->BytesPerSector = Extension->BytesPerSector;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = sizeof (DISK_GEOMETRY);
- }
- break;
-
- case IOCTL_STORAGE_QUERY_PROPERTY:
- if (EnableExtendedIoctlSupport)
- {
- if (ValidateIOBufferSize (Irp, sizeof (STORAGE_PROPERTY_QUERY), ValidateInput))
- {
- PSTORAGE_PROPERTY_QUERY pStoragePropQuery = (PSTORAGE_PROPERTY_QUERY) Irp->AssociatedIrp.SystemBuffer;
- STORAGE_QUERY_TYPE type = pStoragePropQuery->QueryType;
-
- /* return error if an unsupported type is encountered */
- Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
- Irp->IoStatus.Information = 0;
-
- if ( (pStoragePropQuery->PropertyId == StorageAccessAlignmentProperty)
- || (pStoragePropQuery->PropertyId == StorageDeviceProperty)
- )
- {
- if (type == PropertyExistsQuery)
- {
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
- }
- else if (type == PropertyStandardQuery)
- {
- switch (pStoragePropQuery->PropertyId)
- {
- case StorageDeviceProperty:
- {
- if (ValidateIOBufferSize (Irp, sizeof (STORAGE_DEVICE_DESCRIPTOR), ValidateOutput))
- {
- PSTORAGE_DEVICE_DESCRIPTOR outputBuffer = (PSTORAGE_DEVICE_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer;
-
- outputBuffer->Version = sizeof(STORAGE_DEVICE_DESCRIPTOR);
- outputBuffer->Size = sizeof(STORAGE_DEVICE_DESCRIPTOR);
- outputBuffer->DeviceType = FILE_DEVICE_DISK;
- outputBuffer->RemovableMedia = Extension->bRemovable? TRUE : FALSE;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = sizeof (STORAGE_DEVICE_DESCRIPTOR);
- }
- }
- break;
- case StorageAccessAlignmentProperty:
- {
- if (ValidateIOBufferSize (Irp, sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), ValidateOutput))
- {
- PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR outputBuffer = (PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer;
-
- outputBuffer->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
- outputBuffer->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
- outputBuffer->BytesPerLogicalSector = Extension->BytesPerSector;
- outputBuffer->BytesPerPhysicalSector = Extension->HostBytesPerPhysicalSector;
- outputBuffer->BytesOffsetForSectorAlignment = Extension->BytesOffsetForSectorAlignment;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
- }
- }
- break;
- }
- }
- }
- }
- }
- else
- return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
-
- break;
-
- case IOCTL_DISK_GET_PARTITION_INFO:
- if (ValidateIOBufferSize (Irp, sizeof (PARTITION_INFORMATION), ValidateOutput))
- {
- PPARTITION_INFORMATION outputBuffer = (PPARTITION_INFORMATION)
- Irp->AssociatedIrp.SystemBuffer;
-
- outputBuffer->PartitionType = Extension->PartitionType;
- outputBuffer->BootIndicator = FALSE;
- outputBuffer->RecognizedPartition = TRUE;
- outputBuffer->RewritePartition = FALSE;
- outputBuffer->StartingOffset.QuadPart = Extension->BytesPerSector;
- outputBuffer->PartitionLength.QuadPart= Extension->DiskLength;
- outputBuffer->HiddenSectors = 0;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION);
- }
- break;
-
- case IOCTL_DISK_GET_PARTITION_INFO_EX:
- if (ValidateIOBufferSize (Irp, sizeof (PARTITION_INFORMATION_EX), ValidateOutput))
- {
- PPARTITION_INFORMATION_EX outputBuffer = (PPARTITION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer;
-
- outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
- outputBuffer->RewritePartition = FALSE;
- outputBuffer->StartingOffset.QuadPart = Extension->BytesPerSector;
- outputBuffer->PartitionLength.QuadPart= Extension->DiskLength;
- outputBuffer->Mbr.PartitionType = Extension->PartitionType;
- outputBuffer->Mbr.BootIndicator = FALSE;
- outputBuffer->Mbr.RecognizedPartition = TRUE;
- outputBuffer->Mbr.HiddenSectors = 0;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION_EX);
- }
- break;
-
- case IOCTL_DISK_GET_DRIVE_LAYOUT:
- if (ValidateIOBufferSize (Irp, sizeof (DRIVE_LAYOUT_INFORMATION), ValidateOutput))
- {
- PDRIVE_LAYOUT_INFORMATION outputBuffer = (PDRIVE_LAYOUT_INFORMATION)
- Irp->AssociatedIrp.SystemBuffer;
-
- outputBuffer->PartitionCount = 1;
- outputBuffer->Signature = 0;
-
- outputBuffer->PartitionEntry->PartitionType = Extension->PartitionType;
- outputBuffer->PartitionEntry->BootIndicator = FALSE;
- outputBuffer->PartitionEntry->RecognizedPartition = TRUE;
- outputBuffer->PartitionEntry->RewritePartition = FALSE;
- outputBuffer->PartitionEntry->StartingOffset.QuadPart = Extension->BytesPerSector;
- outputBuffer->PartitionEntry->PartitionLength.QuadPart = Extension->DiskLength;
- outputBuffer->PartitionEntry->HiddenSectors = 0;
-
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION);
- }
- break;
-
- case IOCTL_DISK_GET_LENGTH_INFO:
- if (!ValidateIOBufferSize (Irp, sizeof (GET_LENGTH_INFORMATION), ValidateOutput))
- {
- Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
- Irp->IoStatus.Information = sizeof (GET_LENGTH_INFORMATION);
- }
- else
- {
- PGET_LENGTH_INFORMATION outputBuffer = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
-
- outputBuffer->Length.QuadPart = Extension->DiskLength;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = sizeof (GET_LENGTH_INFORMATION);
- }
- break;
-
- case IOCTL_DISK_VERIFY:
- if (ValidateIOBufferSize (Irp, sizeof (VERIFY_INFORMATION), ValidateInput))
- {
- HRESULT hResult;
- ULONGLONG ullStartingOffset, ullNewOffset, ullEndOffset;
- PVERIFY_INFORMATION pVerifyInformation;
- pVerifyInformation = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
-
- ullStartingOffset = (ULONGLONG) pVerifyInformation->StartingOffset.QuadPart;
- hResult = ULongLongAdd(ullStartingOffset,
- (ULONGLONG) Extension->cryptoInfo->hiddenVolume ? Extension->cryptoInfo->hiddenVolumeOffset : Extension->cryptoInfo->volDataAreaOffset,
- &ullNewOffset);
- if (hResult != S_OK)
- Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- else if (S_OK != ULongLongAdd(ullStartingOffset, (ULONGLONG) pVerifyInformation->Length, &ullEndOffset))
- Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- else if (ullEndOffset > (ULONGLONG) Extension->DiskLength)
- Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- else
- {
- IO_STATUS_BLOCK ioStatus;
- PVOID buffer = TCalloc (max (pVerifyInformation->Length, PAGE_SIZE));
-
- if (!buffer)
- {
- Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- }
- else
- {
- LARGE_INTEGER offset = pVerifyInformation->StartingOffset;
- offset.QuadPart = ullNewOffset;
-
- Irp->IoStatus.Status = ZwReadFile (Extension->hDeviceFile, NULL, NULL, NULL, &ioStatus, buffer, pVerifyInformation->Length, &offset, NULL);
- TCfree (buffer);
-
- if (NT_SUCCESS (Irp->IoStatus.Status) && ioStatus.Information != pVerifyInformation->Length)
- Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- }
- }
-
- Irp->IoStatus.Information = 0;
- }
- break;
-
- case IOCTL_DISK_CHECK_VERIFY:
- case IOCTL_STORAGE_CHECK_VERIFY:
- {
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
-
- if (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof (ULONG))
- {
- *((ULONG *) Irp->AssociatedIrp.SystemBuffer) = 0;
- Irp->IoStatus.Information = sizeof (ULONG);
- }
- }
- break;
-
- case IOCTL_DISK_IS_WRITABLE:
- {
- if (Extension->bReadOnly)
- Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
- else
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
-
- }
- break;
-
- case IOCTL_VOLUME_ONLINE:
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
- break;
-
- case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
-
- // Vista's filesystem defragmenter fails if IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS does not succeed.
- if (!(OsMajorVersion == 6 && OsMinorVersion == 0))
- {
- Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
- Irp->IoStatus.Information = 0;
- }
- else if (ValidateIOBufferSize (Irp, sizeof (VOLUME_DISK_EXTENTS), ValidateOutput))
- {
- VOLUME_DISK_EXTENTS *extents = (VOLUME_DISK_EXTENTS *) Irp->AssociatedIrp.SystemBuffer;
-
- // No extent data can be returned as this is not a physical drive.
- memset (extents, 0, sizeof (*extents));
- extents->NumberOfDiskExtents = 0;
-
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = sizeof (*extents);
- }
- break;
-
- default:
- return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
- }
-
-#ifdef DEBUG
- if (!NT_SUCCESS (Irp->IoStatus.Status))
- {
- Dump ("IOCTL error 0x%08x (0x%x %d)\n",
- Irp->IoStatus.Status,
- (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16),
- (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2));
- }
-#endif
-
- return TCCompleteDiskIrp (Irp, Irp->IoStatus.Status, Irp->IoStatus.Information);
-}
-
-
-NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp)
-{
- PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
- NTSTATUS ntStatus;
-
- switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
- {
- case TC_IOCTL_GET_DRIVER_VERSION:
- case TC_IOCTL_LEGACY_GET_DRIVER_VERSION:
- if (ValidateIOBufferSize (Irp, sizeof (LONG), ValidateOutput))
- {
- LONG tmp = VERSION_NUM;
- memcpy (Irp->AssociatedIrp.SystemBuffer, &tmp, 4);
- Irp->IoStatus.Information = sizeof (LONG);
- Irp->IoStatus.Status = STATUS_SUCCESS;
- }
- break;
-
- case TC_IOCTL_GET_DEVICE_REFCOUNT:
- if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput))
- {
- *(int *) Irp->AssociatedIrp.SystemBuffer = DeviceObject->ReferenceCount;
- Irp->IoStatus.Information = sizeof (int);
- Irp->IoStatus.Status = STATUS_SUCCESS;
- }
- break;
-
- case TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED:
- if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput))
- {
- LONG deviceObjectCount = 0;
-
- *(int *) Irp->AssociatedIrp.SystemBuffer = DriverUnloadDisabled;
-
- if (IoEnumerateDeviceObjectList (TCDriverObject, NULL, 0, &deviceObjectCount) == STATUS_BUFFER_TOO_SMALL && deviceObjectCount > 1)
- *(int *) Irp->AssociatedIrp.SystemBuffer = TRUE;
-
- Irp->IoStatus.Information = sizeof (int);
- Irp->IoStatus.Status = STATUS_SUCCESS;
- }
- break;
-
- case TC_IOCTL_IS_ANY_VOLUME_MOUNTED:
- if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput))
- {
- int drive;
- *(int *) Irp->AssociatedIrp.SystemBuffer = 0;
-
- for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive)
- {
- if (GetVirtualVolumeDeviceObject (drive))
- {
- *(int *) Irp->AssociatedIrp.SystemBuffer = 1;
- break;
- }
- }
-
- if (IsBootDriveMounted())
- *(int *) Irp->AssociatedIrp.SystemBuffer = 1;
-
- Irp->IoStatus.Information = sizeof (int);
- Irp->IoStatus.Status = STATUS_SUCCESS;
- }
- break;
-
- case TC_IOCTL_OPEN_TEST:
- {
- OPEN_TEST_STRUCT *opentest = (OPEN_TEST_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
- OBJECT_ATTRIBUTES ObjectAttributes;
- HANDLE NtFileHandle;
- UNICODE_STRING FullFileName;
- IO_STATUS_BLOCK IoStatus;
- LARGE_INTEGER offset;
- ACCESS_MASK access = FILE_READ_ATTRIBUTES;
-
- if (!ValidateIOBufferSize (Irp, sizeof (OPEN_TEST_STRUCT), ValidateInputOutput))
- break;
-
- EnsureNullTerminatedString (opentest->wszFileName, sizeof (opentest->wszFileName));
- RtlInitUnicodeString (&FullFileName, opentest->wszFileName);
-
- InitializeObjectAttributes (&ObjectAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
-
- if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem || opentest->bMatchVolumeID)
- access |= FILE_READ_DATA;
-
- ntStatus = ZwCreateFile (&NtFileHandle,
- SYNCHRONIZE | access, &ObjectAttributes, &IoStatus, NULL,
- 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
-
- if (NT_SUCCESS (ntStatus))
- {
- opentest->TCBootLoaderDetected = FALSE;
- opentest->FilesystemDetected = FALSE;
- opentest->VolumeIDMatched = FALSE;
-
- if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem || opentest->bMatchVolumeID)
- {
- byte *readBuffer = TCalloc (TC_MAX_VOLUME_SECTOR_SIZE);
- if (!readBuffer)
- {
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- }
- else
- {
- if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem)
- {
- // Determine if the first sector contains a portion of the VeraCrypt Boot Loader
-
- offset.QuadPart = 0;
-
- ntStatus = ZwReadFile (NtFileHandle,
- NULL,
- NULL,
- NULL,
- &IoStatus,
- readBuffer,
- TC_MAX_VOLUME_SECTOR_SIZE,
- &offset,
- NULL);
-
- if (NT_SUCCESS (ntStatus))
- {
- size_t i;
-
- if (opentest->bDetectTCBootLoader && IoStatus.Information >= TC_SECTOR_SIZE_BIOS)
- {
- // Search for the string "VeraCrypt"
- for (i = 0; i < TC_SECTOR_SIZE_BIOS - strlen (TC_APP_NAME); ++i)
- {
- if (memcmp (readBuffer + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0)
- {
- opentest->TCBootLoaderDetected = TRUE;
- break;
- }
- }
- }
-
- if (opentest->DetectFilesystem && IoStatus.Information >= sizeof (int64))
- {
- switch (BE64 (*(uint64 *) readBuffer))
- {
- case 0xEB52904E54465320: // NTFS
- case 0xEB3C904D53444F53: // FAT16
- case 0xEB58904D53444F53: // FAT32
- case 0xEB76904558464154: // exFAT
-
- opentest->FilesystemDetected = TRUE;
- break;
- }
- }
- }
- }
-
- if (opentest->bMatchVolumeID)
- {
- int volumeType;
- BYTE volumeID[VOLUME_ID_SIZE];
-
- // Go through all volume types (e.g., normal, hidden)
- for (volumeType = TC_VOLUME_TYPE_NORMAL;
- volumeType < TC_VOLUME_TYPE_COUNT;
- volumeType++)
- {
- /* Read the volume header */
- switch (volumeType)
- {
- case TC_VOLUME_TYPE_NORMAL:
- offset.QuadPart = TC_VOLUME_HEADER_OFFSET;
- break;
-
- case TC_VOLUME_TYPE_HIDDEN:
-
- offset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET;
- break;
- }
-
- ntStatus = ZwReadFile (NtFileHandle,
- NULL,
- NULL,
- NULL,
- &IoStatus,
- readBuffer,
- TC_MAX_VOLUME_SECTOR_SIZE,
- &offset,
- NULL);
-
- if (NT_SUCCESS (ntStatus))
- {
- /* compute the ID of this volume: SHA-256 of the effective header */
- sha256 (volumeID, readBuffer, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
-
- if (0 == memcmp (volumeID, opentest->volumeID, VOLUME_ID_SIZE))
- {
- opentest->VolumeIDMatched = TRUE;
- break;
- }
- }
- }
- }
-
- TCfree (readBuffer);
- }
- }
-
- ZwClose (NtFileHandle);
- Dump ("Open test on file %ls success.\n", opentest->wszFileName);
- }
- else
- {
-#if 0
- Dump ("Open test on file %ls failed NTSTATUS 0x%08x\n", opentest->wszFileName, ntStatus);
-#endif
- }
-
- Irp->IoStatus.Information = NT_SUCCESS (ntStatus) ? sizeof (OPEN_TEST_STRUCT) : 0;
- Irp->IoStatus.Status = ntStatus;
- }
- break;
-
- case TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG:
- {
- GetSystemDriveConfigurationRequest *request = (GetSystemDriveConfigurationRequest *) Irp->AssociatedIrp.SystemBuffer;
- OBJECT_ATTRIBUTES ObjectAttributes;
- HANDLE NtFileHandle;
- UNICODE_STRING FullFileName;
- IO_STATUS_BLOCK IoStatus;
- LARGE_INTEGER offset;
- byte readBuffer [TC_SECTOR_SIZE_BIOS];
-
- if (!ValidateIOBufferSize (Irp, sizeof (GetSystemDriveConfigurationRequest), ValidateInputOutput))
- break;
-
- EnsureNullTerminatedString (request->DevicePath, sizeof (request->DevicePath));
- RtlInitUnicodeString (&FullFileName, request->DevicePath);
-
- InitializeObjectAttributes (&ObjectAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
-
- ntStatus = ZwCreateFile (&NtFileHandle,
- SYNCHRONIZE | GENERIC_READ, &ObjectAttributes, &IoStatus, NULL,
- FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_RANDOM_ACCESS, NULL, 0);
-
- if (NT_SUCCESS (ntStatus))
- {
- // Determine if the first sector contains a portion of the VeraCrypt Boot Loader
- offset.QuadPart = 0; // MBR
-
- ntStatus = ZwReadFile (NtFileHandle,
- NULL,
- NULL,
- NULL,
- &IoStatus,
- readBuffer,
- sizeof(readBuffer),
- &offset,
- NULL);
-
- if (NT_SUCCESS (ntStatus))
- {
- size_t i;
-
- // Check for dynamic drive
- request->DriveIsDynamic = FALSE;
-
- if (readBuffer[510] == 0x55 && readBuffer[511] == 0xaa)
- {
- int i;
- for (i = 0; i < 4; ++i)
- {
- if (readBuffer[446 + i * 16 + 4] == PARTITION_LDM)
- {
- request->DriveIsDynamic = TRUE;
- break;
- }
- }
- }
-
- request->BootLoaderVersion = 0;
- request->Configuration = 0;
- request->UserConfiguration = 0;
- request->CustomUserMessage[0] = 0;
-
- // Search for the string "VeraCrypt"
- for (i = 0; i < sizeof (readBuffer) - strlen (TC_APP_NAME); ++i)
- {
- if (memcmp (readBuffer + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0)
- {
- request->BootLoaderVersion = BE16 (*(uint16 *) (readBuffer + TC_BOOT_SECTOR_VERSION_OFFSET));
- request->Configuration = readBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET];
-
- if (request->BootLoaderVersion != 0 && request->BootLoaderVersion <= VERSION_NUM)
- {
- request->UserConfiguration = readBuffer[TC_BOOT_SECTOR_USER_CONFIG_OFFSET];
- memcpy (request->CustomUserMessage, readBuffer + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH);
- }
- break;
- }
- }
-
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = sizeof (*request);
- }
- else
- {
- Irp->IoStatus.Status = ntStatus;
- Irp->IoStatus.Information = 0;
- }
-
- ZwClose (NtFileHandle);
-
- }
- else
- {
- Irp->IoStatus.Status = ntStatus;
- Irp->IoStatus.Information = 0;
- }
- }
- break;
-
- case TC_IOCTL_WIPE_PASSWORD_CACHE:
- WipeCache ();
-
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
- break;
-
- case TC_IOCTL_GET_PASSWORD_CACHE_STATUS:
- Irp->IoStatus.Status = cacheEmpty ? STATUS_PIPE_EMPTY : STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
- break;
-
- case TC_IOCTL_SET_PORTABLE_MODE_STATUS:
- if (!UserCanAccessDriveDevice())
- {
- Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
- Irp->IoStatus.Information = 0;
- }
- else
- {
- PortableMode = TRUE;
- Dump ("Setting portable mode\n");
- }
- break;
-
- case TC_IOCTL_GET_PORTABLE_MODE_STATUS:
- Irp->IoStatus.Status = PortableMode ? STATUS_SUCCESS : STATUS_PIPE_EMPTY;
- Irp->IoStatus.Information = 0;
- break;
-
- case TC_IOCTL_GET_MOUNTED_VOLUMES:
-
- if (ValidateIOBufferSize (Irp, sizeof (MOUNT_LIST_STRUCT), ValidateOutput))
- {
- MOUNT_LIST_STRUCT *list = (MOUNT_LIST_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
- PDEVICE_OBJECT ListDevice;
- int drive;
-
- list->ulMountedDrives = 0;
-
- for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive)
- {
- PEXTENSION ListExtension;
-
- ListDevice = GetVirtualVolumeDeviceObject (drive);
- if (!ListDevice)
- continue;
-
- ListExtension = (PEXTENSION) ListDevice->DeviceExtension;
- if (IsVolumeAccessibleByCurrentUser (ListExtension))
- {
- list->ulMountedDrives |= (1 << ListExtension->nDosDriveNo);
- RtlStringCbCopyW (list->wszVolume[ListExtension->nDosDriveNo], sizeof(list->wszVolume[ListExtension->nDosDriveNo]),ListExtension->wszVolume);
- RtlStringCbCopyW (list->wszLabel[ListExtension->nDosDriveNo], sizeof(list->wszLabel[ListExtension->nDosDriveNo]),ListExtension->wszLabel);
- memcpy (list->volumeID[ListExtension->nDosDriveNo], ListExtension->volumeID, VOLUME_ID_SIZE);
- list->diskLength[ListExtension->nDosDriveNo] = ListExtension->DiskLength;
- list->ea[ListExtension->nDosDriveNo] = ListExtension->cryptoInfo->ea;
- if (ListExtension->cryptoInfo->hiddenVolume)
- list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_HIDDEN; // Hidden volume
- else if (ListExtension->cryptoInfo->bHiddenVolProtectionAction)
- list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_OUTER_VOL_WRITE_PREVENTED; // Normal/outer volume (hidden volume protected AND write already prevented)
- else if (ListExtension->cryptoInfo->bProtectHiddenVolume)
- list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_OUTER; // Normal/outer volume (hidden volume protected)
- else
- list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_NORMAL; // Normal volume
- list->truecryptMode[ListExtension->nDosDriveNo] = ListExtension->cryptoInfo->bTrueCryptMode;
- }
- }
-
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = sizeof (MOUNT_LIST_STRUCT);
- }
- break;
-
- case TC_IOCTL_LEGACY_GET_MOUNTED_VOLUMES:
- if (ValidateIOBufferSize (Irp, sizeof (uint32), ValidateOutput))
- {
- // Prevent the user from downgrading to versions lower than 5.0 by faking mounted volumes.
- // The user could render the system unbootable by downgrading when boot encryption
- // is active or being set up.
-
- memset (Irp->AssociatedIrp.SystemBuffer, 0, irpSp->Parameters.DeviceIoControl.OutputBufferLength);
- *(uint32 *) Irp->AssociatedIrp.SystemBuffer = 0xffffFFFF;
-
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
- }
- break;
-
- case TC_IOCTL_GET_VOLUME_PROPERTIES:
- if (ValidateIOBufferSize (Irp, sizeof (VOLUME_PROPERTIES_STRUCT), ValidateInputOutput))
- {
- VOLUME_PROPERTIES_STRUCT *prop = (VOLUME_PROPERTIES_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
- PDEVICE_OBJECT ListDevice = GetVirtualVolumeDeviceObject (prop->driveNo);
-
- Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- Irp->IoStatus.Information = 0;
-
- if (ListDevice)
- {
- PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension;
- if (IsVolumeAccessibleByCurrentUser (ListExtension))
- {
- prop->uniqueId = ListExtension->UniqueVolumeId;
- RtlStringCbCopyW (prop->wszVolume, sizeof(prop->wszVolume),ListExtension->wszVolume);
- RtlStringCbCopyW (prop->wszLabel, sizeof(prop->wszLabel),ListExtension->wszLabel);
- memcpy (prop->volumeID, ListExtension->volumeID, VOLUME_ID_SIZE);
- prop->bDriverSetLabel = ListExtension->bDriverSetLabel;
- prop->diskLength = ListExtension->DiskLength;
- prop->ea = ListExtension->cryptoInfo->ea;
- prop->mode = ListExtension->cryptoInfo->mode;
- prop->pkcs5 = ListExtension->cryptoInfo->pkcs5;
- prop->pkcs5Iterations = ListExtension->cryptoInfo->noIterations;
- prop->volumePim = ListExtension->cryptoInfo->volumePim;
-#if 0
- prop->volumeCreationTime = ListExtension->cryptoInfo->volume_creation_time;
- prop->headerCreationTime = ListExtension->cryptoInfo->header_creation_time;
-#endif
- prop->volumeHeaderFlags = ListExtension->cryptoInfo->HeaderFlags;
- prop->readOnly = ListExtension->bReadOnly;
- prop->removable = ListExtension->bRemovable;
- prop->partitionInInactiveSysEncScope = ListExtension->PartitionInInactiveSysEncScope;
- prop->hiddenVolume = ListExtension->cryptoInfo->hiddenVolume;
-
- if (ListExtension->cryptoInfo->bProtectHiddenVolume)
- prop->hiddenVolProtection = ListExtension->cryptoInfo->bHiddenVolProtectionAction ? HIDVOL_PROT_STATUS_ACTION_TAKEN : HIDVOL_PROT_STATUS_ACTIVE;
- else
- prop->hiddenVolProtection = HIDVOL_PROT_STATUS_NONE;
-
- prop->totalBytesRead = ListExtension->Queue.TotalBytesRead;
- prop->totalBytesWritten = ListExtension->Queue.TotalBytesWritten;
-
- prop->volFormatVersion = ListExtension->cryptoInfo->LegacyVolume ? TC_VOLUME_FORMAT_VERSION_PRE_6_0 : TC_VOLUME_FORMAT_VERSION;
-
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = sizeof (VOLUME_PROPERTIES_STRUCT);
- }
- }
- }
- break;
-
- case TC_IOCTL_GET_RESOLVED_SYMLINK:
- if (ValidateIOBufferSize (Irp, sizeof (RESOLVE_SYMLINK_STRUCT), ValidateInputOutput))
- {
- RESOLVE_SYMLINK_STRUCT *resolve = (RESOLVE_SYMLINK_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
- {
- NTSTATUS ntStatus;
-
- EnsureNullTerminatedString (resolve->symLinkName, sizeof (resolve->symLinkName));
-
- ntStatus = SymbolicLinkToTarget (resolve->symLinkName,
- resolve->targetName,
- sizeof (resolve->targetName));
-
- Irp->IoStatus.Information = sizeof (RESOLVE_SYMLINK_STRUCT);
- Irp->IoStatus.Status = ntStatus;
- }
- }
- break;
-
- case TC_IOCTL_GET_DRIVE_PARTITION_INFO:
- if (ValidateIOBufferSize (Irp, sizeof (DISK_PARTITION_INFO_STRUCT), ValidateInputOutput))
- {
- DISK_PARTITION_INFO_STRUCT *info = (DISK_PARTITION_INFO_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
- {
- PARTITION_INFORMATION_EX pi;
- NTSTATUS ntStatus;
-
- EnsureNullTerminatedString (info->deviceName, sizeof (info->deviceName));
-
- ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &pi, sizeof (pi));
- if (NT_SUCCESS(ntStatus))
- {
- memset (&info->partInfo, 0, sizeof (info->partInfo));
-
- info->partInfo.PartitionLength = pi.PartitionLength;
- info->partInfo.PartitionNumber = pi.PartitionNumber;
- info->partInfo.StartingOffset = pi.StartingOffset;
-
- if (pi.PartitionStyle == PARTITION_STYLE_MBR)
- {
- info->partInfo.PartitionType = pi.Mbr.PartitionType;
- info->partInfo.BootIndicator = pi.Mbr.BootIndicator;
- }
-
- info->IsGPT = pi.PartitionStyle == PARTITION_STYLE_GPT;
- }
- else
- {
- // Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX
- ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &info->partInfo, sizeof (info->partInfo));
- info->IsGPT = FALSE;
- }
-
- if (!NT_SUCCESS (ntStatus))
- {
- GET_LENGTH_INFORMATION lengthInfo;
- ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &lengthInfo, sizeof (lengthInfo));
-
- if (NT_SUCCESS (ntStatus))
- {
- memset (&info->partInfo, 0, sizeof (info->partInfo));
- info->partInfo.PartitionLength = lengthInfo.Length;
- }
- }
-
- info->IsDynamic = FALSE;
-
- if (NT_SUCCESS (ntStatus) && OsMajorVersion >= 6)
- {
-# define IOCTL_VOLUME_IS_DYNAMIC CTL_CODE(IOCTL_VOLUME_BASE, 18, METHOD_BUFFERED, FILE_ANY_ACCESS)
- if (!NT_SUCCESS (TCDeviceIoControl (info->deviceName, IOCTL_VOLUME_IS_DYNAMIC, NULL, 0, &info->IsDynamic, sizeof (info->IsDynamic))))
- info->IsDynamic = FALSE;
- }
-
- Irp->IoStatus.Information = sizeof (DISK_PARTITION_INFO_STRUCT);
- Irp->IoStatus.Status = ntStatus;
- }
- }
- break;
-
- case TC_IOCTL_GET_DRIVE_GEOMETRY:
- if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY_STRUCT), ValidateInputOutput))
- {
- DISK_GEOMETRY_STRUCT *g = (DISK_GEOMETRY_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
- {
- NTSTATUS ntStatus;
-
- EnsureNullTerminatedString (g->deviceName, sizeof (g->deviceName));
-
- ntStatus = TCDeviceIoControl (g->deviceName,
- IOCTL_DISK_GET_DRIVE_GEOMETRY,
- NULL, 0, &g->diskGeometry, sizeof (g->diskGeometry));
-
- Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_STRUCT);
- Irp->IoStatus.Status = ntStatus;
- }
- }
- break;
-
- case TC_IOCTL_PROBE_REAL_DRIVE_SIZE:
- if (ValidateIOBufferSize (Irp, sizeof (ProbeRealDriveSizeRequest), ValidateInputOutput))
- {
- ProbeRealDriveSizeRequest *request = (ProbeRealDriveSizeRequest *) Irp->AssociatedIrp.SystemBuffer;
- NTSTATUS status;
- UNICODE_STRING name;
- PFILE_OBJECT fileObject;
- PDEVICE_OBJECT deviceObject;
-
- EnsureNullTerminatedString (request->DeviceName, sizeof (request->DeviceName));
-
- RtlInitUnicodeString (&name, request->DeviceName);
- status = IoGetDeviceObjectPointer (&name, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject);
- if (!NT_SUCCESS (status))
- {
- Irp->IoStatus.Information = 0;
- Irp->IoStatus.Status = status;
- break;
- }
-
- status = ProbeRealDriveSize (deviceObject, &request->RealDriveSize);
- ObDereferenceObject (fileObject);
-
- if (status == STATUS_TIMEOUT)
- {
- request->TimeOut = TRUE;
- Irp->IoStatus.Information = sizeof (ProbeRealDriveSizeRequest);
- Irp->IoStatus.Status = STATUS_SUCCESS;
- }
- else if (!NT_SUCCESS (status))
- {
- Irp->IoStatus.Information = 0;
- Irp->IoStatus.Status = status;
- }
- else
- {
- request->TimeOut = FALSE;
- Irp->IoStatus.Information = sizeof (ProbeRealDriveSizeRequest);
- Irp->IoStatus.Status = status;
- }
- }
- break;
-
- case TC_IOCTL_MOUNT_VOLUME:
- if (ValidateIOBufferSize (Irp, sizeof (MOUNT_STRUCT), ValidateInputOutput))
- {
- MOUNT_STRUCT *mount = (MOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
-
- if (mount->VolumePassword.Length > MAX_PASSWORD || mount->ProtectedHidVolPassword.Length > MAX_PASSWORD
- || mount->pkcs5_prf < 0 || mount->pkcs5_prf > LAST_PRF_ID
- || mount->VolumePim < -1 || mount->VolumePim == INT_MAX
- || mount->ProtectedHidVolPkcs5Prf < 0 || mount->ProtectedHidVolPkcs5Prf > LAST_PRF_ID
- || (mount->bTrueCryptMode != FALSE && mount->bTrueCryptMode != TRUE)
- )
- {
- Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- Irp->IoStatus.Information = 0;
- break;
- }
-
- EnsureNullTerminatedString (mount->wszVolume, sizeof (mount->wszVolume));
- EnsureNullTerminatedString (mount->wszLabel, sizeof (mount->wszLabel));
-
- Irp->IoStatus.Information = sizeof (MOUNT_STRUCT);
- Irp->IoStatus.Status = MountDevice (DeviceObject, mount);
-
- burn (&mount->VolumePassword, sizeof (mount->VolumePassword));
- burn (&mount->ProtectedHidVolPassword, sizeof (mount->ProtectedHidVolPassword));
- burn (&mount->pkcs5_prf, sizeof (mount->pkcs5_prf));
- burn (&mount->VolumePim, sizeof (mount->VolumePim));
- burn (&mount->bTrueCryptMode, sizeof (mount->bTrueCryptMode));
- burn (&mount->ProtectedHidVolPkcs5Prf, sizeof (mount->ProtectedHidVolPkcs5Prf));
- burn (&mount->ProtectedHidVolPim, sizeof (mount->ProtectedHidVolPim));
- }
- break;
-
- case TC_IOCTL_DISMOUNT_VOLUME:
- if (ValidateIOBufferSize (Irp, sizeof (UNMOUNT_STRUCT), ValidateInputOutput))
- {
- UNMOUNT_STRUCT *unmount = (UNMOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
- PDEVICE_OBJECT ListDevice = GetVirtualVolumeDeviceObject (unmount->nDosDriveNo);
-
- unmount->nReturnCode = ERR_DRIVE_NOT_FOUND;
-
- if (ListDevice)
- {
- PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension;
-
- if (IsVolumeAccessibleByCurrentUser (ListExtension))
- unmount->nReturnCode = UnmountDevice (unmount, ListDevice, unmount->ignoreOpenFiles);
- }
-
- Irp->IoStatus.Information = sizeof (UNMOUNT_STRUCT);
- Irp->IoStatus.Status = STATUS_SUCCESS;
- }
- break;
-
- case TC_IOCTL_DISMOUNT_ALL_VOLUMES:
- if (ValidateIOBufferSize (Irp, sizeof (UNMOUNT_STRUCT), ValidateInputOutput))
- {
- UNMOUNT_STRUCT *unmount = (UNMOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
-
- unmount->nReturnCode = UnmountAllDevices (unmount, unmount->ignoreOpenFiles);
-
- Irp->IoStatus.Information = sizeof (UNMOUNT_STRUCT);
- Irp->IoStatus.Status = STATUS_SUCCESS;
- }
- break;
-
- case TC_IOCTL_BOOT_ENCRYPTION_SETUP:
- Irp->IoStatus.Status = StartBootEncryptionSetup (DeviceObject, Irp, irpSp);
- Irp->IoStatus.Information = 0;
- break;
-
- case TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP:
- Irp->IoStatus.Status = AbortBootEncryptionSetup();
- Irp->IoStatus.Information = 0;
- break;
-
- case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS:
- GetBootEncryptionStatus (Irp, irpSp);
- break;
-
- case TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT:
- Irp->IoStatus.Information = 0;
- Irp->IoStatus.Status = GetSetupResult();
- break;
-
- case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES:
- GetBootDriveVolumeProperties (Irp, irpSp);
- break;
-
- case TC_IOCTL_GET_BOOT_LOADER_VERSION:
- GetBootLoaderVersion (Irp, irpSp);
- break;
-
- case TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER:
- ReopenBootVolumeHeader (Irp, irpSp);
- break;
-
- case VC_IOCTL_GET_BOOT_LOADER_FINGERPRINT:
- GetBootLoaderFingerprint (Irp, irpSp);
- break;
-
- case TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME:
- GetBootEncryptionAlgorithmName (Irp, irpSp);
- break;
-
- case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING:
- if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput))
- {
- *(int *) Irp->AssociatedIrp.SystemBuffer = IsHiddenSystemRunning() ? 1 : 0;
- Irp->IoStatus.Information = sizeof (int);
- Irp->IoStatus.Status = STATUS_SUCCESS;
- }
- break;
-
- case TC_IOCTL_START_DECOY_SYSTEM_WIPE:
- Irp->IoStatus.Status = StartDecoySystemWipe (DeviceObject, Irp, irpSp);
- Irp->IoStatus.Information = 0;
- break;
-
- case TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE:
- Irp->IoStatus.Status = AbortDecoySystemWipe();
- Irp->IoStatus.Information = 0;
- break;
-
- case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT:
- Irp->IoStatus.Status = GetDecoySystemWipeResult();
- Irp->IoStatus.Information = 0;
- break;
-
- case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS:
- GetDecoySystemWipeStatus (Irp, irpSp);
- break;
-
- case TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR:
- Irp->IoStatus.Status = WriteBootDriveSector (Irp, irpSp);
- Irp->IoStatus.Information = 0;
- break;
-
- case TC_IOCTL_GET_WARNING_FLAGS:
- if (ValidateIOBufferSize (Irp, sizeof (GetWarningFlagsRequest), ValidateOutput))
- {
- GetWarningFlagsRequest *flags = (GetWarningFlagsRequest *) Irp->AssociatedIrp.SystemBuffer;
-
- flags->PagingFileCreationPrevented = PagingFileCreationPrevented;
- PagingFileCreationPrevented = FALSE;
- flags->SystemFavoriteVolumeDirty = SystemFavoriteVolumeDirty;
- SystemFavoriteVolumeDirty = FALSE;
-
- Irp->IoStatus.Information = sizeof (GetWarningFlagsRequest);
- Irp->IoStatus.Status = STATUS_SUCCESS;
- }
- break;
-
- case TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY:
- if (UserCanAccessDriveDevice())
- {
- SystemFavoriteVolumeDirty = TRUE;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- }
- else
- Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
-
- Irp->IoStatus.Information = 0;
- break;
-
- case TC_IOCTL_REREAD_DRIVER_CONFIG:
- Irp->IoStatus.Status = ReadRegistryConfigFlags (FALSE);
- Irp->IoStatus.Information = 0;
- break;
-
- case TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG:
- if ( (ValidateIOBufferSize (Irp, sizeof (GetSystemDriveDumpConfigRequest), ValidateOutput))
- && (Irp->RequestorMode == KernelMode)
- )
- {
- GetSystemDriveDumpConfigRequest *request = (GetSystemDriveDumpConfigRequest *) Irp->AssociatedIrp.SystemBuffer;
-
- request->BootDriveFilterExtension = GetBootDriveFilterExtension();
- if (IsBootDriveMounted() && request->BootDriveFilterExtension)
- {
- request->HwEncryptionEnabled = IsHwEncryptionEnabled();
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = sizeof (*request);
- }
- else
- {
- Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- Irp->IoStatus.Information = 0;
- }
- }
- break;
-
- default:
- return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
- }
-
-
-#ifdef DEBUG
- if (!NT_SUCCESS (Irp->IoStatus.Status))
- {
- switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
- {
- case TC_IOCTL_GET_MOUNTED_VOLUMES:
- case TC_IOCTL_GET_PASSWORD_CACHE_STATUS:
- case TC_IOCTL_GET_PORTABLE_MODE_STATUS:
- case TC_IOCTL_SET_PORTABLE_MODE_STATUS:
- case TC_IOCTL_OPEN_TEST:
- case TC_IOCTL_GET_RESOLVED_SYMLINK:
- case TC_IOCTL_GET_DRIVE_PARTITION_INFO:
- case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES:
- case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS:
- case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING:
- break;
-
- default:
- Dump ("IOCTL error 0x%08x\n", Irp->IoStatus.Status);
- }
- }
-#endif
-
- return TCCompleteIrp (Irp, Irp->IoStatus.Status, Irp->IoStatus.Information);
-}
-
-
-NTSTATUS TCStartThread (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread)
-{
- return TCStartThreadInProcess (threadProc, threadArg, kThread, NULL);
-}
-
-
-NTSTATUS TCStartThreadInProcess (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread, PEPROCESS process)
-{
- NTSTATUS status;
- HANDLE threadHandle;
- HANDLE processHandle = NULL;
- OBJECT_ATTRIBUTES threadObjAttributes;
-
- if (process)
- {
- status = ObOpenObjectByPointer (process, OBJ_KERNEL_HANDLE, NULL, 0, NULL, KernelMode, &processHandle);
- if (!NT_SUCCESS (status))
- return status;
- }
-
- InitializeObjectAttributes (&threadObjAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
-
- status = PsCreateSystemThread (&threadHandle, THREAD_ALL_ACCESS, &threadObjAttributes, processHandle, NULL, threadProc, threadArg);
- if (!NT_SUCCESS (status))
- return status;
-
- status = ObReferenceObjectByHandle (threadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID *) kThread, NULL);
- if (!NT_SUCCESS (status))
- {
- ZwClose (threadHandle);
- *kThread = NULL;
- return status;
- }
-
- if (processHandle)
- ZwClose (processHandle);
-
- ZwClose (threadHandle);
- return STATUS_SUCCESS;
-}
-
-
-void TCStopThread (PKTHREAD kThread, PKEVENT wakeUpEvent)
-{
- if (wakeUpEvent)
- KeSetEvent (wakeUpEvent, 0, FALSE);
-
- KeWaitForSingleObject (kThread, Executive, KernelMode, FALSE, NULL);
- ObDereferenceObject (kThread);
-}
-
-
-NTSTATUS TCStartVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, MOUNT_STRUCT * mount)
-{
- PTHREAD_BLOCK pThreadBlock = TCalloc (sizeof (THREAD_BLOCK));
- HANDLE hThread;
- NTSTATUS ntStatus;
- OBJECT_ATTRIBUTES threadObjAttributes;
- SECURITY_QUALITY_OF_SERVICE qos;
-
- Dump ("Starting thread...\n");
-
- if (pThreadBlock == NULL)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- else
- {
- pThreadBlock->DeviceObject = DeviceObject;
- pThreadBlock->mount = mount;
- }
-
- qos.Length = sizeof (qos);
- qos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
- qos.EffectiveOnly = TRUE;
- qos.ImpersonationLevel = SecurityImpersonation;
-
- ntStatus = SeCreateClientSecurity (PsGetCurrentThread(), &qos, FALSE, &Extension->SecurityClientContext);
- if (!NT_SUCCESS (ntStatus))
- goto ret;
-
- Extension->SecurityClientContextValid = TRUE;
-
- Extension->bThreadShouldQuit = FALSE;
-
- InitializeObjectAttributes (&threadObjAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
-
- ntStatus = PsCreateSystemThread (&hThread,
- THREAD_ALL_ACCESS,
- &threadObjAttributes,
- NULL,
- NULL,
- VolumeThreadProc,
- pThreadBlock);
-
- if (!NT_SUCCESS (ntStatus))
- {
- Dump ("PsCreateSystemThread Failed END\n");
- goto ret;
- }
-
- ntStatus = ObReferenceObjectByHandle (hThread,
- THREAD_ALL_ACCESS,
- NULL,
- KernelMode,
- &Extension->peThread,
- NULL);
-
- ZwClose (hThread);
-
- if (!NT_SUCCESS (ntStatus))
- goto ret;
-
- Dump ("Waiting for thread to initialize...\n");
-
- KeWaitForSingleObject (&Extension->keCreateEvent,
- Executive,
- KernelMode,
- FALSE,
- NULL);
-
- Dump ("Waiting completed! Thread returns 0x%08x\n", pThreadBlock->ntCreateStatus);
- ntStatus = pThreadBlock->ntCreateStatus;
-
-ret:
- TCfree (pThreadBlock);
- return ntStatus;
-}
-
-void TCStopVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
-{
- NTSTATUS ntStatus;
-
- UNREFERENCED_PARAMETER (DeviceObject); /* Remove compiler warning */
-
- Dump ("Signalling thread to quit...\n");
-
- Extension->bThreadShouldQuit = TRUE;
-
- KeReleaseSemaphore (&Extension->RequestSemaphore,
- 0,
- 1,
- TRUE);
-
- ntStatus = KeWaitForSingleObject (Extension->peThread,
- Executive,
- KernelMode,
- FALSE,
- NULL);
-
- ASSERT (NT_SUCCESS (ntStatus));
-
- ObDereferenceObject (Extension->peThread);
- Extension->peThread = NULL;
-
- Dump ("Thread exited\n");
-}
-
-
-// Suspend current thread for a number of milliseconds
-void TCSleep (int milliSeconds)
-{
- PKTIMER timer = (PKTIMER) TCalloc (sizeof (KTIMER));
- LARGE_INTEGER duetime;
-
- if (!timer)
- return;
-
- duetime.QuadPart = (__int64) milliSeconds * -10000;
- KeInitializeTimerEx(timer, NotificationTimer);
- KeSetTimerEx(timer, duetime, 0, NULL);
-
- KeWaitForSingleObject (timer, Executive, KernelMode, FALSE, NULL);
-
- TCfree (timer);
-}
-
-BOOL IsDeviceName(wchar_t wszVolume[TC_MAX_PATH])
-{
- if ( (wszVolume[0] == '\\')
- && (wszVolume[1] == 'D' || wszVolume[1] == 'd')
- && (wszVolume[2] == 'E' || wszVolume[2] == 'e')
- && (wszVolume[3] == 'V' || wszVolume[3] == 'v')
- && (wszVolume[4] == 'I' || wszVolume[4] == 'i')
- && (wszVolume[5] == 'C' || wszVolume[5] == 'c')
- && (wszVolume[6] == 'E' || wszVolume[6] == 'e')
- )
- {
- return TRUE;
- }
- else
- return FALSE;
-}
-
-/* VolumeThreadProc does all the work of processing IRP's, and dispatching them
- to either the ReadWrite function or the DeviceControl function */
-VOID VolumeThreadProc (PVOID Context)
-{
- PTHREAD_BLOCK pThreadBlock = (PTHREAD_BLOCK) Context;
- PDEVICE_OBJECT DeviceObject = pThreadBlock->DeviceObject;
- PEXTENSION Extension = (PEXTENSION) DeviceObject->DeviceExtension;
- BOOL bDevice;
-
- /* Set thread priority to lowest realtime level. */
- KeSetPriorityThread (KeGetCurrentThread (), LOW_REALTIME_PRIORITY);
-
- Dump ("Mount THREAD OPENING VOLUME BEGIN\n");
-
- if ( !IsDeviceName (pThreadBlock->mount->wszVolume))
- {
- RtlStringCbCopyW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),WIDE ("\\??\\"));
- RtlStringCbCatW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),pThreadBlock->mount->wszVolume);
- bDevice = FALSE;
- }
- else
- {
- pThreadBlock->wszMountVolume[0] = 0;
- RtlStringCbCatW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),pThreadBlock->mount->wszVolume);
- bDevice = TRUE;
- }
-
- Dump ("Mount THREAD request for File %ls DriveNumber %d Device = %d\n",
- pThreadBlock->wszMountVolume, pThreadBlock->mount->nDosDriveNo, bDevice);
-
- pThreadBlock->ntCreateStatus = TCOpenVolume (DeviceObject,
- Extension,
- pThreadBlock->mount,
- pThreadBlock->wszMountVolume,
- bDevice);
-
- if (!NT_SUCCESS (pThreadBlock->ntCreateStatus) || pThreadBlock->mount->nReturnCode != 0)
- {
- KeSetEvent (&Extension->keCreateEvent, 0, FALSE);
- PsTerminateSystemThread (STATUS_SUCCESS);
- }
-
- // Start IO queue
- Extension->Queue.IsFilterDevice = FALSE;
- Extension->Queue.DeviceObject = DeviceObject;
- Extension->Queue.CryptoInfo = Extension->cryptoInfo;
- Extension->Queue.HostFileHandle = Extension->hDeviceFile;
- Extension->Queue.VirtualDeviceLength = Extension->DiskLength;
- Extension->Queue.MaxReadAheadOffset.QuadPart = Extension->HostLength;
-
- if (Extension->SecurityClientContextValid)
- Extension->Queue.SecurityClientContext = &Extension->SecurityClientContext;
- else
- Extension->Queue.SecurityClientContext = NULL;
-
- pThreadBlock->ntCreateStatus = EncryptedIoQueueStart (&Extension->Queue);
-
- if (!NT_SUCCESS (pThreadBlock->ntCreateStatus))
- {
- TCCloseVolume (DeviceObject, Extension);
-
- pThreadBlock->mount->nReturnCode = ERR_OS_ERROR;
- KeSetEvent (&Extension->keCreateEvent, 0, FALSE);
- PsTerminateSystemThread (STATUS_SUCCESS);
- }
-
- KeSetEvent (&Extension->keCreateEvent, 0, FALSE);
- /* From this point on pThreadBlock cannot be used as it will have been released! */
- pThreadBlock = NULL;
-
- for (;;)
- {
- /* Wait for a request from the dispatch routines. */
- KeWaitForSingleObject ((PVOID) & Extension->RequestSemaphore, Executive, KernelMode, FALSE, NULL);
-
- for (;;)
- {
- PIO_STACK_LOCATION irpSp;
- PLIST_ENTRY request;
- PIRP irp;
-
- request = ExInterlockedRemoveHeadList (&Extension->ListEntry, &Extension->ListSpinLock);
- if (request == NULL)
- break;
-
- irp = CONTAINING_RECORD (request, IRP, Tail.Overlay.ListEntry);
- irpSp = IoGetCurrentIrpStackLocation (irp);
-
- ASSERT (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
-
- ProcessVolumeDeviceControlIrp (DeviceObject, Extension, irp);
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, irp);
- }
-
- if (Extension->bThreadShouldQuit)
- {
- Dump ("Closing volume\n");
- EncryptedIoQueueStop (&Extension->Queue);
-
- TCCloseVolume (DeviceObject, Extension);
- PsTerminateSystemThread (STATUS_SUCCESS);
- }
- }
-}
-
-void TCGetNTNameFromNumber (LPWSTR ntname, int cbNtName, int nDriveNo)
-{
- WCHAR tmp[2] =
- {0, 0};
- int j = nDriveNo + (WCHAR) 'A';
-
- tmp[0] = (short) j;
- RtlStringCbCopyW (ntname, cbNtName,(LPWSTR) NT_MOUNT_PREFIX);
- RtlStringCbCatW (ntname, cbNtName, tmp);
-}
-
-void TCGetDosNameFromNumber (LPWSTR dosname,int cbDosName, int nDriveNo, DeviceNamespaceType namespaceType)
-{
- WCHAR tmp[3] =
- {0, ':', 0};
- int j = nDriveNo + (WCHAR) 'A';
-
- tmp[0] = (short) j;
-
- if (DeviceNamespaceGlobal == namespaceType)
- {
- RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX_GLOBAL);
- }
- else
- {
- RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX_DEFAULT);
- }
-
- RtlStringCbCatW (dosname, cbDosName, tmp);
-}
-
-#ifdef _DEBUG
-LPWSTR TCTranslateCode (ULONG ulCode)
-{
- switch (ulCode)
- {
-#define TC_CASE_RET_NAME(CODE) case CODE : return L###CODE
-
- TC_CASE_RET_NAME (TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP);
- TC_CASE_RET_NAME (TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE);
- TC_CASE_RET_NAME (TC_IOCTL_BOOT_ENCRYPTION_SETUP);
- TC_CASE_RET_NAME (TC_IOCTL_DISMOUNT_ALL_VOLUMES);
- TC_CASE_RET_NAME (TC_IOCTL_DISMOUNT_VOLUME);
- TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES);
- TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME);
- TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT);
- TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS);
- TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_LOADER_VERSION);
- TC_CASE_RET_NAME (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT);
- TC_CASE_RET_NAME (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS);
- TC_CASE_RET_NAME (TC_IOCTL_GET_DEVICE_REFCOUNT);
- TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVE_GEOMETRY);
- TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVE_PARTITION_INFO);
- TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVER_VERSION);
- TC_CASE_RET_NAME (TC_IOCTL_GET_MOUNTED_VOLUMES);
- TC_CASE_RET_NAME (TC_IOCTL_GET_PASSWORD_CACHE_STATUS);
- TC_CASE_RET_NAME (TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG);
- TC_CASE_RET_NAME (TC_IOCTL_GET_PORTABLE_MODE_STATUS);
- TC_CASE_RET_NAME (TC_IOCTL_SET_PORTABLE_MODE_STATUS);
- TC_CASE_RET_NAME (TC_IOCTL_GET_RESOLVED_SYMLINK);
- TC_CASE_RET_NAME (TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG);
- TC_CASE_RET_NAME (TC_IOCTL_GET_VOLUME_PROPERTIES);
- TC_CASE_RET_NAME (TC_IOCTL_GET_WARNING_FLAGS);
- TC_CASE_RET_NAME (TC_IOCTL_DISK_IS_WRITABLE);
- TC_CASE_RET_NAME (TC_IOCTL_IS_ANY_VOLUME_MOUNTED);
- TC_CASE_RET_NAME (TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED);
- TC_CASE_RET_NAME (TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING);
- TC_CASE_RET_NAME (TC_IOCTL_MOUNT_VOLUME);
- TC_CASE_RET_NAME (TC_IOCTL_OPEN_TEST);
- TC_CASE_RET_NAME (TC_IOCTL_PROBE_REAL_DRIVE_SIZE);
- TC_CASE_RET_NAME (TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER);
- TC_CASE_RET_NAME (TC_IOCTL_REREAD_DRIVER_CONFIG);
- TC_CASE_RET_NAME (TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY);
- TC_CASE_RET_NAME (TC_IOCTL_START_DECOY_SYSTEM_WIPE);
- TC_CASE_RET_NAME (TC_IOCTL_WIPE_PASSWORD_CACHE);
- TC_CASE_RET_NAME (TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR);
-
- TC_CASE_RET_NAME (IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS);
-
-#undef TC_CASE_RET_NAME
- }
-
- if (ulCode == IOCTL_DISK_GET_DRIVE_GEOMETRY)
- return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_GEOMETRY");
- else if (ulCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX)
- return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX");
- else if (ulCode == IOCTL_MOUNTDEV_QUERY_DEVICE_NAME)
- return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME");
- else if (ulCode == IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME)
- return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME");
- else if (ulCode == IOCTL_MOUNTDEV_QUERY_UNIQUE_ID)
- return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_UNIQUE_ID");
- else if (ulCode == IOCTL_VOLUME_ONLINE)
- return (LPWSTR) _T ("IOCTL_VOLUME_ONLINE");
- else if (ulCode == IOCTL_MOUNTDEV_LINK_CREATED)
- return (LPWSTR) _T ("IOCTL_MOUNTDEV_LINK_CREATED");
- else if (ulCode == IOCTL_MOUNTDEV_LINK_DELETED)
- return (LPWSTR) _T ("IOCTL_MOUNTDEV_LINK_DELETED");
- else if (ulCode == IOCTL_MOUNTMGR_QUERY_POINTS)
- return (LPWSTR) _T ("IOCTL_MOUNTMGR_QUERY_POINTS");
- else if (ulCode == IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED)
- return (LPWSTR) _T ("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED");
- else if (ulCode == IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED)
- return (LPWSTR) _T ("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED");
- else if (ulCode == IOCTL_DISK_GET_LENGTH_INFO)
- return (LPWSTR) _T ("IOCTL_DISK_GET_LENGTH_INFO");
- else if (ulCode == IOCTL_STORAGE_GET_DEVICE_NUMBER)
- return (LPWSTR) _T ("IOCTL_STORAGE_GET_DEVICE_NUMBER");
- else if (ulCode == IOCTL_DISK_GET_PARTITION_INFO)
- return (LPWSTR) _T ("IOCTL_DISK_GET_PARTITION_INFO");
- else if (ulCode == IOCTL_DISK_GET_PARTITION_INFO_EX)
- return (LPWSTR) _T ("IOCTL_DISK_GET_PARTITION_INFO_EX");
- else if (ulCode == IOCTL_DISK_SET_PARTITION_INFO)
- return (LPWSTR) _T ("IOCTL_DISK_SET_PARTITION_INFO");
- else if (ulCode == IOCTL_DISK_GET_DRIVE_LAYOUT)
- return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_LAYOUT");
- else if (ulCode == IOCTL_DISK_SET_DRIVE_LAYOUT_EX)
- return (LPWSTR) _T ("IOCTL_DISK_SET_DRIVE_LAYOUT_EX");
- else if (ulCode == IOCTL_DISK_VERIFY)
- return (LPWSTR) _T ("IOCTL_DISK_VERIFY");
- else if (ulCode == IOCTL_DISK_FORMAT_TRACKS)
- return (LPWSTR) _T ("IOCTL_DISK_FORMAT_TRACKS");
- else if (ulCode == IOCTL_DISK_REASSIGN_BLOCKS)
- return (LPWSTR) _T ("IOCTL_DISK_REASSIGN_BLOCKS");
- else if (ulCode == IOCTL_DISK_PERFORMANCE)
- return (LPWSTR) _T ("IOCTL_DISK_PERFORMANCE");
- else if (ulCode == IOCTL_DISK_IS_WRITABLE)
- return (LPWSTR) _T ("IOCTL_DISK_IS_WRITABLE");
- else if (ulCode == IOCTL_DISK_LOGGING)
- return (LPWSTR) _T ("IOCTL_DISK_LOGGING");
- else if (ulCode == IOCTL_DISK_FORMAT_TRACKS_EX)
- return (LPWSTR) _T ("IOCTL_DISK_FORMAT_TRACKS_EX");
- else if (ulCode == IOCTL_DISK_HISTOGRAM_STRUCTURE)
- return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_STRUCTURE");
- else if (ulCode == IOCTL_DISK_HISTOGRAM_DATA)
- return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_DATA");
- else if (ulCode == IOCTL_DISK_HISTOGRAM_RESET)
- return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_RESET");
- else if (ulCode == IOCTL_DISK_REQUEST_STRUCTURE)
- return (LPWSTR) _T ("IOCTL_DISK_REQUEST_STRUCTURE");
- else if (ulCode == IOCTL_DISK_REQUEST_DATA)
- return (LPWSTR) _T ("IOCTL_DISK_REQUEST_DATA");
- else if (ulCode == IOCTL_DISK_CONTROLLER_NUMBER)
- return (LPWSTR) _T ("IOCTL_DISK_CONTROLLER_NUMBER");
- else if (ulCode == SMART_GET_VERSION)
- return (LPWSTR) _T ("SMART_GET_VERSION");
- else if (ulCode == SMART_SEND_DRIVE_COMMAND)
- return (LPWSTR) _T ("SMART_SEND_DRIVE_COMMAND");
- else if (ulCode == SMART_RCV_DRIVE_DATA)
- return (LPWSTR) _T ("SMART_RCV_DRIVE_DATA");
- else if (ulCode == IOCTL_DISK_INTERNAL_SET_VERIFY)
- return (LPWSTR) _T ("IOCTL_DISK_INTERNAL_SET_VERIFY");
- else if (ulCode == IOCTL_DISK_INTERNAL_CLEAR_VERIFY)
- return (LPWSTR) _T ("IOCTL_DISK_INTERNAL_CLEAR_VERIFY");
- else if (ulCode == IOCTL_DISK_CHECK_VERIFY)
- return (LPWSTR) _T ("IOCTL_DISK_CHECK_VERIFY");
- else if (ulCode == IOCTL_DISK_MEDIA_REMOVAL)
- return (LPWSTR) _T ("IOCTL_DISK_MEDIA_REMOVAL");
- else if (ulCode == IOCTL_DISK_EJECT_MEDIA)
- return (LPWSTR) _T ("IOCTL_DISK_EJECT_MEDIA");
- else if (ulCode == IOCTL_DISK_LOAD_MEDIA)
- return (LPWSTR) _T ("IOCTL_DISK_LOAD_MEDIA");
- else if (ulCode == IOCTL_DISK_RESERVE)
- return (LPWSTR) _T ("IOCTL_DISK_RESERVE");
- else if (ulCode == IOCTL_DISK_RELEASE)
- return (LPWSTR) _T ("IOCTL_DISK_RELEASE");
- else if (ulCode == IOCTL_DISK_FIND_NEW_DEVICES)
- return (LPWSTR) _T ("IOCTL_DISK_FIND_NEW_DEVICES");
- else if (ulCode == IOCTL_DISK_GET_MEDIA_TYPES)
- return (LPWSTR) _T ("IOCTL_DISK_GET_MEDIA_TYPES");
- else if (ulCode == IOCTL_STORAGE_SET_HOTPLUG_INFO)
- return (LPWSTR) _T ("IOCTL_STORAGE_SET_HOTPLUG_INFO");
- else if (ulCode == IRP_MJ_READ)
- return (LPWSTR) _T ("IRP_MJ_READ");
- else if (ulCode == IRP_MJ_WRITE)
- return (LPWSTR) _T ("IRP_MJ_WRITE");
- else if (ulCode == IRP_MJ_CREATE)
- return (LPWSTR) _T ("IRP_MJ_CREATE");
- else if (ulCode == IRP_MJ_CLOSE)
- return (LPWSTR) _T ("IRP_MJ_CLOSE");
- else if (ulCode == IRP_MJ_CLEANUP)
- return (LPWSTR) _T ("IRP_MJ_CLEANUP");
- else if (ulCode == IRP_MJ_FLUSH_BUFFERS)
- return (LPWSTR) _T ("IRP_MJ_FLUSH_BUFFERS");
- else if (ulCode == IRP_MJ_SHUTDOWN)
- return (LPWSTR) _T ("IRP_MJ_SHUTDOWN");
- else if (ulCode == IRP_MJ_DEVICE_CONTROL)
- return (LPWSTR) _T ("IRP_MJ_DEVICE_CONTROL");
- else
- {
- return (LPWSTR) _T ("IOCTL");
- }
-}
-
-#endif
-
-void TCDeleteDeviceObject (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
-{
- UNICODE_STRING Win32NameString;
- NTSTATUS ntStatus;
-
- Dump ("TCDeleteDeviceObject BEGIN\n");
-
- if (Extension->bRootDevice)
- {
- RtlInitUnicodeString (&Win32NameString, (LPWSTR) DOS_ROOT_PREFIX);
- ntStatus = IoDeleteSymbolicLink (&Win32NameString);
- if (!NT_SUCCESS (ntStatus))
- Dump ("IoDeleteSymbolicLink failed ntStatus = 0x%08x\n", ntStatus);
-
- RootDeviceObject = NULL;
- }
- else
- {
- if (Extension->peThread != NULL)
- TCStopVolumeThread (DeviceObject, Extension);
-
- if (Extension->UserSid)
- TCfree (Extension->UserSid);
-
- if (Extension->SecurityClientContextValid)
- {
- if (OsMajorVersion == 5 && OsMinorVersion == 0)
- {
- ObDereferenceObject (Extension->SecurityClientContext.ClientToken);
- }
- else
- {
- // Windows 2000 does not support PsDereferenceImpersonationToken() used by SeDeleteClientSecurity().
- // TODO: Use only SeDeleteClientSecurity() once support for Windows 2000 is dropped.
-
- VOID (*PsDereferenceImpersonationTokenD) (PACCESS_TOKEN ImpersonationToken);
- UNICODE_STRING name;
- RtlInitUnicodeString (&name, L"PsDereferenceImpersonationToken");
-
- PsDereferenceImpersonationTokenD = MmGetSystemRoutineAddress (&name);
- if (!PsDereferenceImpersonationTokenD)
- TC_BUG_CHECK (STATUS_NOT_IMPLEMENTED);
-
-# define PsDereferencePrimaryToken
-# define PsDereferenceImpersonationToken PsDereferenceImpersonationTokenD
-
- SeDeleteClientSecurity (&Extension->SecurityClientContext);
-
-# undef PsDereferencePrimaryToken
-# undef PsDereferenceImpersonationToken
- }
- }
-
- VirtualVolumeDeviceObjects[Extension->nDosDriveNo] = NULL;
- }
-
- IoDeleteDevice (DeviceObject);
-
- Dump ("TCDeleteDeviceObject END\n");
-}
-
-
-VOID TCUnloadDriver (PDRIVER_OBJECT DriverObject)
-{
- Dump ("TCUnloadDriver BEGIN\n");
-
- OnShutdownPending();
-
- if (IsBootDriveMounted())
- TC_BUG_CHECK (STATUS_INVALID_DEVICE_STATE);
-
- EncryptionThreadPoolStop();
- TCDeleteDeviceObject (RootDeviceObject, (PEXTENSION) RootDeviceObject->DeviceExtension);
-
- Dump ("TCUnloadDriver END\n");
-}
-
-
-void OnShutdownPending ()
-{
- UNMOUNT_STRUCT unmount;
- memset (&unmount, 0, sizeof (unmount));
- unmount.ignoreOpenFiles = TRUE;
-
- while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_DISMOUNT_ALL_VOLUMES, &unmount, sizeof (unmount), &unmount, sizeof (unmount)) == STATUS_INSUFFICIENT_RESOURCES || unmount.HiddenVolumeProtectionTriggered)
- unmount.HiddenVolumeProtectionTriggered = FALSE;
-
- while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_WIPE_PASSWORD_CACHE, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES);
-}
-
-
-NTSTATUS TCDeviceIoControl (PWSTR deviceName, ULONG IoControlCode, void *InputBuffer, ULONG InputBufferSize, void *OutputBuffer, ULONG OutputBufferSize)
-{
- IO_STATUS_BLOCK ioStatusBlock;
- NTSTATUS ntStatus;
- PIRP irp;
- PFILE_OBJECT fileObject;
- PDEVICE_OBJECT deviceObject;
- KEVENT event;
- UNICODE_STRING name;
-
- RtlInitUnicodeString(&name, deviceName);
- ntStatus = IoGetDeviceObjectPointer (&name, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject);
-
- if (!NT_SUCCESS (ntStatus))
- return ntStatus;
-
- KeInitializeEvent(&event, NotificationEvent, FALSE);
-
- irp = IoBuildDeviceIoControlRequest (IoControlCode,
- deviceObject,
- InputBuffer, InputBufferSize,
- OutputBuffer, OutputBufferSize,
- FALSE,
- &event,
- &ioStatusBlock);
-
- if (irp == NULL)
- {
- Dump ("IRP allocation failed\n");
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- goto ret;
- }
-
- IoGetNextIrpStackLocation (irp)->FileObject = fileObject;
-
- ntStatus = IoCallDriver (deviceObject, irp);
- if (ntStatus == STATUS_PENDING)
- {
- KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
- ntStatus = ioStatusBlock.Status;
- }
-
-ret:
- ObDereferenceObject (fileObject);
- return ntStatus;
-}
-
-
-typedef struct
-{
- PDEVICE_OBJECT deviceObject; ULONG ioControlCode; void *inputBuffer; int inputBufferSize; void *outputBuffer; int outputBufferSize;
- NTSTATUS Status;
- KEVENT WorkItemCompletedEvent;
-} SendDeviceIoControlRequestWorkItemArgs;
-
-
-static VOID SendDeviceIoControlRequestWorkItemRoutine (PDEVICE_OBJECT rootDeviceObject, SendDeviceIoControlRequestWorkItemArgs *arg)
-{
- arg->Status = SendDeviceIoControlRequest (arg->deviceObject, arg->ioControlCode, arg->inputBuffer, arg->inputBufferSize, arg->outputBuffer, arg->outputBufferSize);
- KeSetEvent (&arg->WorkItemCompletedEvent, IO_NO_INCREMENT, FALSE);
-}
-
-
-NTSTATUS SendDeviceIoControlRequest (PDEVICE_OBJECT deviceObject, ULONG ioControlCode, void *inputBuffer, int inputBufferSize, void *outputBuffer, int outputBufferSize)
-{
- IO_STATUS_BLOCK ioStatusBlock;
- NTSTATUS status;
- PIRP irp;
- KEVENT event;
-
- if (KeGetCurrentIrql() > APC_LEVEL)
- {
- SendDeviceIoControlRequestWorkItemArgs args;
-
- PIO_WORKITEM workItem = IoAllocateWorkItem (RootDeviceObject);
- if (!workItem)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- args.deviceObject = deviceObject;
- args.ioControlCode = ioControlCode;
- args.inputBuffer = inputBuffer;
- args.inputBufferSize = inputBufferSize;
- args.outputBuffer = outputBuffer;
- args.outputBufferSize = outputBufferSize;
-
- KeInitializeEvent (&args.WorkItemCompletedEvent, SynchronizationEvent, FALSE);
- IoQueueWorkItem (workItem, SendDeviceIoControlRequestWorkItemRoutine, DelayedWorkQueue, &args);
-
- KeWaitForSingleObject (&args.WorkItemCompletedEvent, Executive, KernelMode, FALSE, NULL);
- IoFreeWorkItem (workItem);
-
- return args.Status;
- }
-
- KeInitializeEvent (&event, NotificationEvent, FALSE);
-
- irp = IoBuildDeviceIoControlRequest (ioControlCode, deviceObject, inputBuffer, inputBufferSize,
- outputBuffer, outputBufferSize, FALSE, &event, &ioStatusBlock);
-
- if (!irp)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- ObReferenceObject (deviceObject);
-
- status = IoCallDriver (deviceObject, irp);
- if (status == STATUS_PENDING)
- {
- KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
- status = ioStatusBlock.Status;
- }
-
- ObDereferenceObject (deviceObject);
- return status;
-}
-
-
-NTSTATUS ProbeRealDriveSize (PDEVICE_OBJECT driveDeviceObject, LARGE_INTEGER *driveSize)
-{
- NTSTATUS status;
- LARGE_INTEGER sysLength;
- LARGE_INTEGER offset;
- byte *sectorBuffer;
- ULONGLONG startTime;
-
- if (!UserCanAccessDriveDevice())
- return STATUS_ACCESS_DENIED;
-
- sectorBuffer = TCalloc (TC_SECTOR_SIZE_BIOS);
- if (!sectorBuffer)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- status = SendDeviceIoControlRequest (driveDeviceObject, IOCTL_DISK_GET_LENGTH_INFO,
- NULL, 0, &sysLength, sizeof (sysLength));
-
- if (!NT_SUCCESS (status))
- {
- Dump ("Failed to get drive size - error %x\n", status);
- TCfree (sectorBuffer);
- return status;
- }
-
- startTime = KeQueryInterruptTime ();
- for (offset.QuadPart = sysLength.QuadPart; ; offset.QuadPart += TC_SECTOR_SIZE_BIOS)
- {
- status = TCReadDevice (driveDeviceObject, sectorBuffer, offset, TC_SECTOR_SIZE_BIOS);
-
- if (NT_SUCCESS (status))
- status = TCWriteDevice (driveDeviceObject, sectorBuffer, offset, TC_SECTOR_SIZE_BIOS);
-
- if (!NT_SUCCESS (status))
- {
- driveSize->QuadPart = offset.QuadPart;
- Dump ("Real drive size = %I64d bytes (%I64d hidden)\n", driveSize->QuadPart, driveSize->QuadPart - sysLength.QuadPart);
- TCfree (sectorBuffer);
- return STATUS_SUCCESS;
- }
-
- if (KeQueryInterruptTime() - startTime > 3ULL * 60 * 1000 * 1000 * 10)
- {
- // Abort if probing for more than 3 minutes
- driveSize->QuadPart = sysLength.QuadPart;
- TCfree (sectorBuffer);
- return STATUS_TIMEOUT;
- }
- }
-}
-
-
-NTSTATUS TCOpenFsVolume (PEXTENSION Extension, PHANDLE volumeHandle, PFILE_OBJECT * fileObject)
-{
- NTSTATUS ntStatus;
- OBJECT_ATTRIBUTES objectAttributes;
- UNICODE_STRING fullFileName;
- IO_STATUS_BLOCK ioStatus;
- WCHAR volumeName[TC_MAX_PATH];
-
- TCGetNTNameFromNumber (volumeName, sizeof(volumeName),Extension->nDosDriveNo);
- RtlInitUnicodeString (&fullFileName, volumeName);
- InitializeObjectAttributes (&objectAttributes, &fullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
-
- ntStatus = ZwCreateFile (volumeHandle,
- SYNCHRONIZE | GENERIC_READ,
- &objectAttributes,
- &ioStatus,
- NULL,
- FILE_ATTRIBUTE_NORMAL,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- FILE_OPEN,
- FILE_SYNCHRONOUS_IO_NONALERT,
- NULL,
- 0);
-
- Dump ("Volume %ls open NTSTATUS 0x%08x\n", volumeName, ntStatus);
-
- if (!NT_SUCCESS (ntStatus))
- return ntStatus;
-
- ntStatus = ObReferenceObjectByHandle (*volumeHandle,
- FILE_READ_DATA,
- NULL,
- KernelMode,
- fileObject,
- NULL);
-
- if (!NT_SUCCESS (ntStatus))
- ZwClose (*volumeHandle);
-
- return ntStatus;
-}
-
-
-void TCCloseFsVolume (HANDLE volumeHandle, PFILE_OBJECT fileObject)
-{
- ObDereferenceObject (fileObject);
- ZwClose (volumeHandle);
-}
-
-
-static NTSTATUS TCReadWriteDevice (BOOL write, PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length)
-{
- NTSTATUS status;
- IO_STATUS_BLOCK ioStatusBlock;
- PIRP irp;
- KEVENT completionEvent;
-
- ASSERT (KeGetCurrentIrql() <= APC_LEVEL);
-
- KeInitializeEvent (&completionEvent, NotificationEvent, FALSE);
- irp = IoBuildSynchronousFsdRequest (write ? IRP_MJ_WRITE : IRP_MJ_READ, deviceObject, buffer, length, &offset, &completionEvent, &ioStatusBlock);
- if (!irp)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- ObReferenceObject (deviceObject);
- status = IoCallDriver (deviceObject, irp);
-
- if (status == STATUS_PENDING)
- {
- status = KeWaitForSingleObject (&completionEvent, Executive, KernelMode, FALSE, NULL);
- if (NT_SUCCESS (status))
- status = ioStatusBlock.Status;
- }
-
- ObDereferenceObject (deviceObject);
- return status;
-}
-
-
-NTSTATUS TCReadDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length)
-{
- return TCReadWriteDevice (FALSE, deviceObject, buffer, offset, length);
-}
-
-
-NTSTATUS TCWriteDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length)
-{
- return TCReadWriteDevice (TRUE, deviceObject, buffer, offset, length);
-}
-
-
-NTSTATUS TCFsctlCall (PFILE_OBJECT fileObject, LONG IoControlCode,
- void *InputBuffer, int InputBufferSize, void *OutputBuffer, int OutputBufferSize)
-{
- IO_STATUS_BLOCK ioStatusBlock;
- NTSTATUS ntStatus;
- PIRP irp;
- KEVENT event;
- PIO_STACK_LOCATION stack;
- PDEVICE_OBJECT deviceObject = IoGetRelatedDeviceObject (fileObject);
-
- KeInitializeEvent(&event, NotificationEvent, FALSE);
-
- irp = IoBuildDeviceIoControlRequest (IoControlCode,
- deviceObject,
- InputBuffer, InputBufferSize,
- OutputBuffer, OutputBufferSize,
- FALSE,
- &event,
- &ioStatusBlock);
-
- if (irp == NULL)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- stack = IoGetNextIrpStackLocation(irp);
-
- stack->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
- stack->MinorFunction = IRP_MN_USER_FS_REQUEST;
- stack->FileObject = fileObject;
-
- ntStatus = IoCallDriver (deviceObject, irp);
- if (ntStatus == STATUS_PENDING)
- {
- KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
- ntStatus = ioStatusBlock.Status;
- }
-
- return ntStatus;
-}
-
-
-NTSTATUS CreateDriveLink (int nDosDriveNo)
-{
- WCHAR dev[128], link[128];
- UNICODE_STRING deviceName, symLink;
- NTSTATUS ntStatus;
-
- TCGetNTNameFromNumber (dev, sizeof(dev),nDosDriveNo);
- TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault);
-
- RtlInitUnicodeString (&deviceName, dev);
- RtlInitUnicodeString (&symLink, link);
-
- ntStatus = IoCreateSymbolicLink (&symLink, &deviceName);
- Dump ("IoCreateSymbolicLink returned %X\n", ntStatus);
- return ntStatus;
-}
-
-
-NTSTATUS RemoveDriveLink (int nDosDriveNo)
-{
- WCHAR link[256];
- UNICODE_STRING symLink;
- NTSTATUS ntStatus;
-
- TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault);
- RtlInitUnicodeString (&symLink, link);
-
- ntStatus = IoDeleteSymbolicLink (&symLink);
- Dump ("IoDeleteSymbolicLink returned %X\n", ntStatus);
- return ntStatus;
-}
-
-
-NTSTATUS MountManagerMount (MOUNT_STRUCT *mount)
-{
- NTSTATUS ntStatus;
- WCHAR arrVolume[256];
- char buf[200];
- PMOUNTMGR_TARGET_NAME in = (PMOUNTMGR_TARGET_NAME) buf;
- PMOUNTMGR_CREATE_POINT_INPUT point = (PMOUNTMGR_CREATE_POINT_INPUT) buf;
-
- TCGetNTNameFromNumber (arrVolume, sizeof(arrVolume),mount->nDosDriveNo);
- in->DeviceNameLength = (USHORT) wcslen (arrVolume) * 2;
- RtlStringCbCopyW(in->DeviceName, sizeof(buf) - sizeof(in->DeviceNameLength),arrVolume);
-
- ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
- in, (ULONG) (sizeof (in->DeviceNameLength) + wcslen (arrVolume) * 2), 0, 0);
-
- memset (buf, 0, sizeof buf);
- TCGetDosNameFromNumber ((PWSTR) &point[1], sizeof(buf) - sizeof(MOUNTMGR_CREATE_POINT_INPUT),mount->nDosDriveNo, DeviceNamespaceDefault);
-
- point->SymbolicLinkNameOffset = sizeof (MOUNTMGR_CREATE_POINT_INPUT);
- point->SymbolicLinkNameLength = (USHORT) wcslen ((PWSTR) &point[1]) * 2;
-
- point->DeviceNameOffset = point->SymbolicLinkNameOffset + point->SymbolicLinkNameLength;
- TCGetNTNameFromNumber ((PWSTR) (buf + point->DeviceNameOffset), sizeof(buf) - point->DeviceNameOffset,mount->nDosDriveNo);
- point->DeviceNameLength = (USHORT) wcslen ((PWSTR) (buf + point->DeviceNameOffset)) * 2;
-
- ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_CREATE_POINT, point,
- point->DeviceNameOffset + point->DeviceNameLength, 0, 0);
-
- return ntStatus;
-}
-
-
-NTSTATUS MountManagerUnmount (int nDosDriveNo)
-{
- NTSTATUS ntStatus;
- char buf[256], out[300];
- PMOUNTMGR_MOUNT_POINT in = (PMOUNTMGR_MOUNT_POINT) buf;
-
- memset (buf, 0, sizeof buf);
-
- TCGetDosNameFromNumber ((PWSTR) &in[1], sizeof(buf) - sizeof(MOUNTMGR_MOUNT_POINT),nDosDriveNo, DeviceNamespaceDefault);
-
- // Only symbolic link can be deleted with IOCTL_MOUNTMGR_DELETE_POINTS. If any other entry is specified, the mount manager will ignore subsequent IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION for the same volume ID.
- in->SymbolicLinkNameOffset = sizeof (MOUNTMGR_MOUNT_POINT);
- in->SymbolicLinkNameLength = (USHORT) wcslen ((PWCHAR) &in[1]) * 2;
-
- ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_DELETE_POINTS,
- in, sizeof(MOUNTMGR_MOUNT_POINT) + in->SymbolicLinkNameLength, out, sizeof out);
-
- Dump ("IOCTL_MOUNTMGR_DELETE_POINTS returned 0x%08x\n", ntStatus);
-
- return ntStatus;
-}
-
-
-NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount)
-{
- PDEVICE_OBJECT NewDeviceObject;
- NTSTATUS ntStatus;
-
- // Make sure the user is asking for a reasonable nDosDriveNo
- if (mount->nDosDriveNo >= 0 && mount->nDosDriveNo <= 25
- && IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceDefault) // drive letter must not exist both locally and globally
- && IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceGlobal)
- )
- {
- Dump ("Mount request looks valid\n");
- }
- else
- {
- Dump ("WARNING: MOUNT DRIVE LETTER INVALID\n");
- mount->nReturnCode = ERR_DRIVE_NOT_FOUND;
- return ERR_DRIVE_NOT_FOUND;
- }
-
- if (!SelfTestsPassed)
- {
- mount->nReturnCode = ERR_SELF_TESTS_FAILED;
- return ERR_SELF_TESTS_FAILED;
- }
-
- ntStatus = TCCreateDeviceObject (DeviceObject->DriverObject, &NewDeviceObject, mount);
-
- if (!NT_SUCCESS (ntStatus))
- {
- Dump ("Mount CREATE DEVICE ERROR, ntStatus = 0x%08x\n", ntStatus);
- return ntStatus;
- }
- else
- {
- PEXTENSION NewExtension = (PEXTENSION) NewDeviceObject->DeviceExtension;
- SECURITY_SUBJECT_CONTEXT subContext;
- PACCESS_TOKEN accessToken;
-
- SeCaptureSubjectContext (&subContext);
- SeLockSubjectContext(&subContext);
- if (subContext.ClientToken && subContext.ImpersonationLevel >= SecurityImpersonation)
- accessToken = subContext.ClientToken;
- else
- accessToken = subContext.PrimaryToken;
-
- if (!accessToken)
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- else
- {
- PTOKEN_USER tokenUser;
-
- ntStatus = SeQueryInformationToken (accessToken, TokenUser, &tokenUser);
- if (NT_SUCCESS (ntStatus))
- {
- ULONG sidLength = RtlLengthSid (tokenUser->User.Sid);
-
- NewExtension->UserSid = TCalloc (sidLength);
- if (!NewExtension->UserSid)
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- else
- ntStatus = RtlCopySid (sidLength, NewExtension->UserSid, tokenUser->User.Sid);
-
- ExFreePool (tokenUser); // Documented in newer versions of WDK
- }
- }
-
- SeUnlockSubjectContext(&subContext);
- SeReleaseSubjectContext (&subContext);
-
- if (NT_SUCCESS (ntStatus))
- ntStatus = TCStartVolumeThread (NewDeviceObject, NewExtension, mount);
-
- if (!NT_SUCCESS (ntStatus))
- {
- Dump ("Mount FAILURE NT ERROR, ntStatus = 0x%08x\n", ntStatus);
- TCDeleteDeviceObject (NewDeviceObject, NewExtension);
- return ntStatus;
- }
- else
- {
- if (mount->nReturnCode == 0)
- {
- HANDLE volumeHandle;
- PFILE_OBJECT volumeFileObject;
- ULONG labelLen = (ULONG) wcslen (mount->wszLabel);
- BOOL bIsNTFS = FALSE;
- ULONG labelMaxLen, labelEffectiveLen;
-
- Dump ("Mount SUCCESS TC code = 0x%08x READ-ONLY = %d\n", mount->nReturnCode, NewExtension->bReadOnly);
-
- if (NewExtension->bReadOnly)
- NewDeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
-
- NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
-
- NewExtension->UniqueVolumeId = LastUniqueVolumeId++;
-
- // check again that the drive letter is available globally and locally
- if ( !IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceDefault)
- || !IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceGlobal)
- )
- {
- TCDeleteDeviceObject (NewDeviceObject, NewExtension);
- mount->nReturnCode = ERR_DRIVE_NOT_FOUND;
- return ERR_DRIVE_NOT_FOUND;
- }
-
- if (mount->bMountManager)
- MountManagerMount (mount);
-
- NewExtension->bMountManager = mount->bMountManager;
-
- // We create symbolic link even if mount manager is notified of
- // arriving volume as it apparently sometimes fails to create the link
- CreateDriveLink (mount->nDosDriveNo);
-
- mount->FilesystemDirty = FALSE;
-
- if (NT_SUCCESS (TCOpenFsVolume (NewExtension, &volumeHandle, &volumeFileObject)))
- {
- __try
- {
- ULONG fsStatus;
-
- if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_IS_VOLUME_DIRTY, NULL, 0, &fsStatus, sizeof (fsStatus)))
- && (fsStatus & VOLUME_IS_DIRTY))
- {
- mount->FilesystemDirty = TRUE;
- }
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- mount->FilesystemDirty = TRUE;
- }
-
- // detect if the filesystem is NTFS or FAT
- __try
- {
- NTFS_VOLUME_DATA_BUFFER ntfsData;
- if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &ntfsData, sizeof (ntfsData))))
- {
- bIsNTFS = TRUE;
- }
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- bIsNTFS = FALSE;
- }
-
- NewExtension->bIsNTFS = bIsNTFS;
- mount->bIsNTFS = bIsNTFS;
-
- if (labelLen > 0)
- {
- if (bIsNTFS)
- labelMaxLen = 32; // NTFS maximum label length
- else
- labelMaxLen = 11; // FAT maximum label length
-
- // calculate label effective length
- labelEffectiveLen = labelLen > labelMaxLen? labelMaxLen : labelLen;
-
- // correct the label in the device
- memset (&NewExtension->wszLabel[labelEffectiveLen], 0, 33 - labelEffectiveLen);
- memcpy (mount->wszLabel, NewExtension->wszLabel, 33);
-
- // set the volume label
- __try
- {
- IO_STATUS_BLOCK ioblock;
- ULONG labelInfoSize = sizeof(FILE_FS_LABEL_INFORMATION) + (labelEffectiveLen * sizeof(WCHAR));
- FILE_FS_LABEL_INFORMATION* labelInfo = (FILE_FS_LABEL_INFORMATION*) TCalloc (labelInfoSize);
- labelInfo->VolumeLabelLength = labelEffectiveLen * sizeof(WCHAR);
- memcpy (labelInfo->VolumeLabel, mount->wszLabel, labelInfo->VolumeLabelLength);
-
- if (STATUS_SUCCESS == ZwSetVolumeInformationFile (volumeHandle, &ioblock, labelInfo, labelInfoSize, FileFsLabelInformation))
- {
- mount->bDriverSetLabel = TRUE;
- NewExtension->bDriverSetLabel = TRUE;
- }
-
- TCfree(labelInfo);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
-
- }
- }
-
- TCCloseFsVolume (volumeHandle, volumeFileObject);
- }
- }
- else
- {
- Dump ("Mount FAILURE TC code = 0x%08x\n", mount->nReturnCode);
- TCDeleteDeviceObject (NewDeviceObject, NewExtension);
- }
-
- return STATUS_SUCCESS;
- }
- }
-}
-
-NTSTATUS UnmountDevice (UNMOUNT_STRUCT *unmountRequest, PDEVICE_OBJECT deviceObject, BOOL ignoreOpenFiles)
-{
- PEXTENSION extension = deviceObject->DeviceExtension;
- NTSTATUS ntStatus;
- HANDLE volumeHandle;
- PFILE_OBJECT volumeFileObject;
-
- Dump ("UnmountDevice %d\n", extension->nDosDriveNo);
-
- ntStatus = TCOpenFsVolume (extension, &volumeHandle, &volumeFileObject);
-
- if (NT_SUCCESS (ntStatus))
- {
- int dismountRetry;
-
- // Dismounting a writable NTFS filesystem prevents the driver from being unloaded on Windows 7
- if (IsOSAtLeast (WIN_7) && !extension->bReadOnly)
- {
- NTFS_VOLUME_DATA_BUFFER ntfsData;
-
- if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &ntfsData, sizeof (ntfsData))))
- DriverUnloadDisabled = TRUE;
- }
-
- // Lock volume
- ntStatus = TCFsctlCall (volumeFileObject, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0);
- Dump ("FSCTL_LOCK_VOLUME returned %X\n", ntStatus);
-
- if (!NT_SUCCESS (ntStatus) && !ignoreOpenFiles)
- {
- TCCloseFsVolume (volumeHandle, volumeFileObject);
- return ERR_FILES_OPEN;
- }
-
- // Dismount volume
- for (dismountRetry = 0; dismountRetry < 200; ++dismountRetry)
- {
- ntStatus = TCFsctlCall (volumeFileObject, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0);
- Dump ("FSCTL_DISMOUNT_VOLUME returned %X\n", ntStatus);
-
- if (NT_SUCCESS (ntStatus) || ntStatus == STATUS_VOLUME_DISMOUNTED)
- break;
-
- if (!ignoreOpenFiles)
- {
- TCCloseFsVolume (volumeHandle, volumeFileObject);
- return ERR_FILES_OPEN;
- }
-
- TCSleep (100);
- }
- }
- else
- {
- // Volume cannot be opened => force dismount if allowed
- if (!ignoreOpenFiles)
- return ERR_FILES_OPEN;
- else
- volumeHandle = NULL;
- }
-
- if (extension->bMountManager)
- MountManagerUnmount (extension->nDosDriveNo);
-
- // We always remove symbolic link as mount manager might fail to do so
- RemoveDriveLink (extension->nDosDriveNo);
-
- extension->bShuttingDown = TRUE;
-
- ntStatus = IoAcquireRemoveLock (&extension->Queue.RemoveLock, NULL);
- ASSERT (NT_SUCCESS (ntStatus));
- IoReleaseRemoveLockAndWait (&extension->Queue.RemoveLock, NULL);
-
- if (volumeHandle != NULL)
- TCCloseFsVolume (volumeHandle, volumeFileObject);
-
- if (unmountRequest)
- {
- PCRYPTO_INFO cryptoInfo = ((PEXTENSION) deviceObject->DeviceExtension)->cryptoInfo;
- unmountRequest->HiddenVolumeProtectionTriggered = (cryptoInfo->bProtectHiddenVolume && cryptoInfo->bHiddenVolProtectionAction);
- }
-
- TCDeleteDeviceObject (deviceObject, (PEXTENSION) deviceObject->DeviceExtension);
- return 0;
-}
-
-
-static PDEVICE_OBJECT FindVolumeWithHighestUniqueId (int maxUniqueId)
-{
- PDEVICE_OBJECT highestIdDevice = NULL;
- int highestId = -1;
- int drive;
-
- for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive)
- {
- PDEVICE_OBJECT device = GetVirtualVolumeDeviceObject (drive);
- if (device)
- {
- PEXTENSION extension = (PEXTENSION) device->DeviceExtension;
- if (extension->UniqueVolumeId > highestId && extension->UniqueVolumeId <= maxUniqueId)
- {
- highestId = extension->UniqueVolumeId;
- highestIdDevice = device;
- }
- }
- }
-
- return highestIdDevice;
-}
-
-
-NTSTATUS UnmountAllDevices (UNMOUNT_STRUCT *unmountRequest, BOOL ignoreOpenFiles)
-{
- NTSTATUS status = 0;
- PDEVICE_OBJECT ListDevice;
- int maxUniqueId = LastUniqueVolumeId;
-
- Dump ("Unmounting all volumes\n");
-
- if (unmountRequest)
- unmountRequest->HiddenVolumeProtectionTriggered = FALSE;
-
- // Dismount volumes in the reverse order they were mounted to properly dismount nested volumes
- while ((ListDevice = FindVolumeWithHighestUniqueId (maxUniqueId)) != NULL)
- {
- PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension;
- maxUniqueId = ListExtension->UniqueVolumeId - 1;
-
- if (IsVolumeAccessibleByCurrentUser (ListExtension))
- {
- NTSTATUS ntStatus;
-
- if (unmountRequest)
- unmountRequest->nDosDriveNo = ListExtension->nDosDriveNo;
-
- ntStatus = UnmountDevice (unmountRequest, ListDevice, ignoreOpenFiles);
- status = ntStatus == 0 ? status : ntStatus;
-
- if (unmountRequest && unmountRequest->HiddenVolumeProtectionTriggered)
- break;
- }
- }
-
- return status;
-}
-
-// Resolves symbolic link name to its target name
-NTSTATUS SymbolicLinkToTarget (PWSTR symlinkName, PWSTR targetName, USHORT maxTargetNameLength)
-{
- NTSTATUS ntStatus;
- OBJECT_ATTRIBUTES objectAttributes;
- UNICODE_STRING fullFileName;
- HANDLE handle;
-
- RtlInitUnicodeString (&fullFileName, symlinkName);
- InitializeObjectAttributes (&objectAttributes, &fullFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
-
- ntStatus = ZwOpenSymbolicLinkObject (&handle, GENERIC_READ, &objectAttributes);
-
- if (NT_SUCCESS (ntStatus))
- {
- UNICODE_STRING target;
- target.Buffer = targetName;
- target.Length = 0;
- target.MaximumLength = maxTargetNameLength;
- memset (targetName, 0, maxTargetNameLength);
-
- ntStatus = ZwQuerySymbolicLinkObject (handle, &target, NULL);
-
- ZwClose (handle);
- }
-
- return ntStatus;
-}
-
-
-// Checks if two regions overlap (borders are parts of regions)
-BOOL RegionsOverlap (unsigned __int64 start1, unsigned __int64 end1, unsigned __int64 start2, unsigned __int64 end2)
-{
- return (start1 < start2) ? (end1 >= start2) : (start1 <= end2);
-}
-
-
-void GetIntersection (uint64 start1, uint32 length1, uint64 start2, uint64 end2, uint64 *intersectStart, uint32 *intersectLength)
-{
- uint64 end1 = start1 + length1 - 1;
- uint64 intersectEnd = (end1 <= end2) ? end1 : end2;
-
- *intersectStart = (start1 >= start2) ? start1 : start2;
- *intersectLength = (uint32) ((*intersectStart > intersectEnd) ? 0 : intersectEnd + 1 - *intersectStart);
-
- if (*intersectLength == 0)
- *intersectStart = start1;
-}
-
-
-BOOL IsAccessibleByUser (PUNICODE_STRING objectFileName, BOOL readOnly)
-{
- OBJECT_ATTRIBUTES fileObjAttributes;
- IO_STATUS_BLOCK ioStatusBlock;
- HANDLE fileHandle;
- NTSTATUS status;
-
- ASSERT (!IoIsSystemThread (PsGetCurrentThread()));
-
- InitializeObjectAttributes (&fileObjAttributes, objectFileName, OBJ_CASE_INSENSITIVE | OBJ_FORCE_ACCESS_CHECK | OBJ_KERNEL_HANDLE, NULL, NULL);
-
- status = ZwCreateFile (&fileHandle,
- readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
- &fileObjAttributes,
- &ioStatusBlock,
- NULL,
- FILE_ATTRIBUTE_NORMAL,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- FILE_OPEN,
- FILE_SYNCHRONOUS_IO_NONALERT,
- NULL,
- 0);
-
- if (NT_SUCCESS (status))
- {
- ZwClose (fileHandle);
- return TRUE;
- }
-
- return FALSE;
-}
-
-
-BOOL UserCanAccessDriveDevice ()
-{
- UNICODE_STRING name;
- RtlInitUnicodeString (&name, L"\\Device\\MountPointManager");
-
- return IsAccessibleByUser (&name, FALSE);
-}
-
-BOOL IsDriveLetterAvailable (int nDosDriveNo, DeviceNamespaceType namespaceType)
-{
- OBJECT_ATTRIBUTES objectAttributes;
- UNICODE_STRING objectName;
- WCHAR link[128];
- HANDLE handle;
- NTSTATUS ntStatus;
-
- TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, namespaceType);
- RtlInitUnicodeString (&objectName, link);
- InitializeObjectAttributes (&objectAttributes, &objectName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
-
- if (NT_SUCCESS (ntStatus = ZwOpenSymbolicLinkObject (&handle, GENERIC_READ, &objectAttributes)))
- {
- ZwClose (handle);
- return FALSE;
- }
-
- return (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND)? TRUE : FALSE;
-}
-
-
-NTSTATUS TCCompleteIrp (PIRP irp, NTSTATUS status, ULONG_PTR information)
-{
- irp->IoStatus.Status = status;
- irp->IoStatus.Information = information;
- IoCompleteRequest (irp, IO_NO_INCREMENT);
- return status;
-}
-
-
-NTSTATUS TCCompleteDiskIrp (PIRP irp, NTSTATUS status, ULONG_PTR information)
-{
- irp->IoStatus.Status = status;
- irp->IoStatus.Information = information;
- IoCompleteRequest (irp, NT_SUCCESS (status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
- return status;
-}
-
-
-size_t GetCpuCount ()
-{
- KAFFINITY activeCpuMap = KeQueryActiveProcessors();
- size_t mapSize = sizeof (activeCpuMap) * 8;
- size_t cpuCount = 0;
-
- while (mapSize--)
- {
- if (activeCpuMap & 1)
- ++cpuCount;
-
- activeCpuMap >>= 1;
- }
-
- if (cpuCount == 0)
- return 1;
-
- return cpuCount;
-}
-
-
-void EnsureNullTerminatedString (wchar_t *str, size_t maxSizeInBytes)
-{
- ASSERT ((maxSizeInBytes & 1) == 0);
- str[maxSizeInBytes / sizeof (wchar_t) - 1] = 0;
-}
-
-
-void *AllocateMemoryWithTimeout (size_t size, int retryDelay, int timeout)
-{
- LARGE_INTEGER waitInterval;
- waitInterval.QuadPart = retryDelay * -10000;
-
- ASSERT (KeGetCurrentIrql() <= APC_LEVEL);
- ASSERT (retryDelay > 0 && retryDelay <= timeout);
-
- while (TRUE)
- {
- void *memory = TCalloc (size);
- if (memory)
- return memory;
-
- timeout -= retryDelay;
- if (timeout <= 0)
- break;
-
- KeDelayExecutionThread (KernelMode, FALSE, &waitInterval);
- }
-
- return NULL;
-}
-
-
-NTSTATUS TCReadRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, PKEY_VALUE_PARTIAL_INFORMATION *keyData)
-{
- OBJECT_ATTRIBUTES regObjAttribs;
- HANDLE regKeyHandle;
- NTSTATUS status;
- UNICODE_STRING valName;
- ULONG size = 0;
- ULONG resultSize;
-
- InitializeObjectAttributes (&regObjAttribs, keyPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
- status = ZwOpenKey (&regKeyHandle, KEY_READ, &regObjAttribs);
- if (!NT_SUCCESS (status))
- return status;
-
- RtlInitUnicodeString (&valName, keyValueName);
- status = ZwQueryValueKey (regKeyHandle, &valName, KeyValuePartialInformation, NULL, 0, &size);
-
- if (!NT_SUCCESS (status) && status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL)
- {
- ZwClose (regKeyHandle);
- return status;
- }
-
- if (size == 0)
- {
- ZwClose (regKeyHandle);
- return STATUS_NO_DATA_DETECTED;
- }
-
- *keyData = (PKEY_VALUE_PARTIAL_INFORMATION) TCalloc (size);
- if (!*keyData)
- {
- ZwClose (regKeyHandle);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- status = ZwQueryValueKey (regKeyHandle, &valName, KeyValuePartialInformation, *keyData, size, &resultSize);
-
- ZwClose (regKeyHandle);
- return status;
-}
-
-
-NTSTATUS TCWriteRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, ULONG keyValueType, void *valueData, ULONG valueSize)
-{
- OBJECT_ATTRIBUTES regObjAttribs;
- HANDLE regKeyHandle;
- NTSTATUS status;
- UNICODE_STRING valName;
-
- InitializeObjectAttributes (&regObjAttribs, keyPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
- status = ZwOpenKey (&regKeyHandle, KEY_READ | KEY_WRITE, &regObjAttribs);
- if (!NT_SUCCESS (status))
- return status;
-
- RtlInitUnicodeString (&valName, keyValueName);
-
- status = ZwSetValueKey (regKeyHandle, &valName, 0, keyValueType, valueData, valueSize);
-
- ZwClose (regKeyHandle);
- return status;
-}
-
-
-BOOL IsVolumeClassFilterRegistered ()
-{
- UNICODE_STRING name;
- NTSTATUS status;
- BOOL registered = FALSE;
-
- PKEY_VALUE_PARTIAL_INFORMATION data;
-
- RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class\\{71A27CDD-812A-11D0-BEC7-08002BE2092F}");
- status = TCReadRegistryKey (&name, L"UpperFilters", &data);
-
- if (NT_SUCCESS (status))
- {
- if (data->Type == REG_MULTI_SZ && data->DataLength >= 9 * sizeof (wchar_t))
- {
- // Search for the string "veracrypt"
- ULONG i;
- for (i = 0; i <= data->DataLength - 9 * sizeof (wchar_t); ++i)
- {
- if (memcmp (data->Data + i, L"veracrypt", 9 * sizeof (wchar_t)) == 0)
- {
- Dump ("Volume class filter active\n");
- registered = TRUE;
- break;
- }
- }
- }
-
- TCfree (data);
- }
-
- return registered;
-}
-
-
-NTSTATUS ReadRegistryConfigFlags (BOOL driverEntry)
-{
- PKEY_VALUE_PARTIAL_INFORMATION data;
- UNICODE_STRING name;
- NTSTATUS status;
- uint32 flags = 0;
-
- RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\veracrypt");
- status = TCReadRegistryKey (&name, TC_DRIVER_CONFIG_REG_VALUE_NAME, &data);
-
- if (NT_SUCCESS (status))
- {
- if (data->Type == REG_DWORD)
- {
- flags = *(uint32 *) data->Data;
- Dump ("Configuration flags = 0x%x\n", flags);
-
- if (driverEntry)
- {
- if (flags & (TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD | TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES))
- CacheBootPassword = TRUE;
-
- if (flags & TC_DRIVER_CONFIG_DISABLE_NONADMIN_SYS_FAVORITES_ACCESS)
- NonAdminSystemFavoritesAccessDisabled = TRUE;
-
- if (flags & TC_DRIVER_CONFIG_CACHE_BOOT_PIM)
- CacheBootPim = TRUE;
- }
-
- EnableHwEncryption ((flags & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION) ? FALSE : TRUE);
-
- EnableExtendedIoctlSupport = (flags & TC_DRIVER_CONFIG_ENABLE_EXTENDED_IOCTL)? TRUE : FALSE;
- }
- else
- status = STATUS_INVALID_PARAMETER;
-
- TCfree (data);
- }
-
- if (driverEntry && NT_SUCCESS (TCReadRegistryKey (&name, TC_ENCRYPTION_FREE_CPU_COUNT_REG_VALUE_NAME, &data)))
- {
- if (data->Type == REG_DWORD)
- EncryptionThreadPoolFreeCpuCountLimit = *(uint32 *) data->Data;
-
- TCfree (data);
- }
-
- return status;
-}
-
-
-NTSTATUS WriteRegistryConfigFlags (uint32 flags)
-{
- UNICODE_STRING name;
- RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\veracrypt");
-
- return TCWriteRegistryKey (&name, TC_DRIVER_CONFIG_REG_VALUE_NAME, REG_DWORD, &flags, sizeof (flags));
-}
-
-
-NTSTATUS GetDeviceSectorSize (PDEVICE_OBJECT deviceObject, ULONG *bytesPerSector)
-{
- NTSTATUS status;
- DISK_GEOMETRY geometry;
-
- status = SendDeviceIoControlRequest (deviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry));
-
- if (!NT_SUCCESS (status))
- return status;
-
- *bytesPerSector = geometry.BytesPerSector;
- return STATUS_SUCCESS;
-}
-
-
-NTSTATUS ZeroUnreadableSectors (PDEVICE_OBJECT deviceObject, LARGE_INTEGER startOffset, ULONG size, uint64 *zeroedSectorCount)
-{
- NTSTATUS status;
- ULONG sectorSize;
- ULONG sectorCount;
- byte *sectorBuffer = NULL;
-
- *zeroedSectorCount = 0;
-
- status = GetDeviceSectorSize (deviceObject, &sectorSize);
- if (!NT_SUCCESS (status))
- return status;
-
- sectorBuffer = TCalloc (sectorSize);
- if (!sectorBuffer)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount, startOffset.QuadPart += sectorSize)
- {
- status = TCReadDevice (deviceObject, sectorBuffer, startOffset, sectorSize);
- if (!NT_SUCCESS (status))
- {
- Dump ("Zeroing sector at %I64d\n", startOffset.QuadPart);
- memset (sectorBuffer, 0, sectorSize);
-
- status = TCWriteDevice (deviceObject, sectorBuffer, startOffset, sectorSize);
- if (!NT_SUCCESS (status))
- goto err;
-
- ++(*zeroedSectorCount);
- }
- }
-
- status = STATUS_SUCCESS;
-
-err:
- if (sectorBuffer)
- TCfree (sectorBuffer);
-
- return status;
-}
-
-
-NTSTATUS ReadDeviceSkipUnreadableSectors (PDEVICE_OBJECT deviceObject, byte *buffer, LARGE_INTEGER startOffset, ULONG size, uint64 *badSectorCount)
-{
- NTSTATUS status;
- ULONG sectorSize;
- ULONG sectorCount;
-
- *badSectorCount = 0;
-
- status = GetDeviceSectorSize (deviceObject, &sectorSize);
- if (!NT_SUCCESS (status))
- return status;
-
- for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount, startOffset.QuadPart += sectorSize, buffer += sectorSize)
- {
- status = TCReadDevice (deviceObject, buffer, startOffset, sectorSize);
- if (!NT_SUCCESS (status))
- {
- Dump ("Skipping bad sector at %I64d\n", startOffset.QuadPart);
- memset (buffer, 0, sectorSize);
- ++(*badSectorCount);
- }
- }
-
- return STATUS_SUCCESS;
-}
-
-
-BOOL IsVolumeAccessibleByCurrentUser (PEXTENSION volumeDeviceExtension)
-{
- SECURITY_SUBJECT_CONTEXT subContext;
- PACCESS_TOKEN accessToken;
- PTOKEN_USER tokenUser;
- BOOL result = FALSE;
-
- if (IoIsSystemThread (PsGetCurrentThread())
- || UserCanAccessDriveDevice()
- || !volumeDeviceExtension->UserSid
- || (volumeDeviceExtension->SystemFavorite && !NonAdminSystemFavoritesAccessDisabled))
- {
- return TRUE;
- }
-
- SeCaptureSubjectContext (&subContext);
- SeLockSubjectContext(&subContext);
- if (subContext.ClientToken && subContext.ImpersonationLevel >= SecurityImpersonation)
- accessToken = subContext.ClientToken;
- else
- accessToken = subContext.PrimaryToken;
-
- if (!accessToken)
- goto ret;
-
- if (SeTokenIsAdmin (accessToken))
- {
- result = TRUE;
- goto ret;
- }
-
- if (!NT_SUCCESS (SeQueryInformationToken (accessToken, TokenUser, &tokenUser)))
- goto ret;
-
- result = RtlEqualSid (volumeDeviceExtension->UserSid, tokenUser->User.Sid);
- ExFreePool (tokenUser); // Documented in newer versions of WDK
-
-ret:
- SeUnlockSubjectContext(&subContext);
- SeReleaseSubjectContext (&subContext);
- return result;
-}
-
-
-void GetElapsedTimeInit (LARGE_INTEGER *lastPerfCounter)
-{
- *lastPerfCounter = KeQueryPerformanceCounter (NULL);
-}
-
-
-// Returns elapsed time in microseconds since last call
-int64 GetElapsedTime (LARGE_INTEGER *lastPerfCounter)
-{
- LARGE_INTEGER freq;
- LARGE_INTEGER counter = KeQueryPerformanceCounter (&freq);
-
- int64 elapsed = (counter.QuadPart - lastPerfCounter->QuadPart) * 1000000LL / freq.QuadPart;
- *lastPerfCounter = counter;
-
- return elapsed;
-}
-
-
-BOOL IsOSAtLeast (OSVersionEnum reqMinOS)
-{
- /* When updating this function, update IsOSVersionAtLeast() in Dlgcode.c too. */
-
- ULONG major = 0, minor = 0;
-
- ASSERT (OsMajorVersion != 0);
-
- switch (reqMinOS)
- {
- case WIN_2000: major = 5; minor = 0; break;
- case WIN_XP: major = 5; minor = 1; break;
- case WIN_SERVER_2003: major = 5; minor = 2; break;
- case WIN_VISTA: major = 6; minor = 0; break;
- case WIN_7: major = 6; minor = 1; break;
- case WIN_8: major = 6; minor = 2; break;
- case WIN_8_1: major = 6; minor = 3; break;
- case WIN_10: major = 10; minor = 0; break;
-
- default:
- TC_THROW_FATAL_EXCEPTION;
- break;
- }
-
- return ((OsMajorVersion << 16 | OsMinorVersion << 8)
- >= (major << 16 | minor << 8));
-}
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of TrueCrypt 7.1a, which is
+ Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
+ governed by the TrueCrypt License 3.0, also from the source code of
+ Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
+ and which is governed by the 'License Agreement for Encryption for the Masses'
+ 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 "Crypto.h"
+#include "Fat.h"
+#include "Tests.h"
+#include "cpu.h"
+
+#include "Apidrvr.h"
+#include "Boot/Windows/BootDefs.h"
+#include "EncryptedIoQueue.h"
+#include "EncryptionThreadPool.h"
+#include "Ntdriver.h"
+#include "Ntvol.h"
+#include "DriveFilter.h"
+#include "DumpFilter.h"
+#include "Cache.h"
+#include "Volumes.h"
+#include "VolumeFilter.h"
+
+#include <tchar.h>
+#include <initguid.h>
+#include <mountmgr.h>
+#include <mountdev.h>
+#include <ntddvol.h>
+
+#include <Ntstrsafe.h>
+#include <Intsafe.h>
+
+/* Init section, which is thrown away as soon as DriverEntry returns */
+#pragma alloc_text(INIT,DriverEntry)
+#pragma alloc_text(INIT,TCCreateRootDeviceObject)
+
+PDRIVER_OBJECT TCDriverObject;
+PDEVICE_OBJECT RootDeviceObject = NULL;
+static KMUTEX RootDeviceControlMutex;
+BOOL DriverShuttingDown = FALSE;
+BOOL SelfTestsPassed;
+int LastUniqueVolumeId;
+ULONG OsMajorVersion = 0;
+ULONG OsMinorVersion;
+BOOL DriverUnloadDisabled = FALSE;
+BOOL PortableMode = FALSE;
+BOOL VolumeClassFilterRegistered = FALSE;
+BOOL CacheBootPassword = FALSE;
+BOOL CacheBootPim = FALSE;
+BOOL NonAdminSystemFavoritesAccessDisabled = FALSE;
+static size_t EncryptionThreadPoolFreeCpuCountLimit = 0;
+static BOOL SystemFavoriteVolumeDirty = FALSE;
+static BOOL PagingFileCreationPrevented = FALSE;
+static BOOL EnableExtendedIoctlSupport = FALSE;
+
+PDEVICE_OBJECT VirtualVolumeDeviceObjects[MAX_MOUNTED_VOLUME_DRIVE_NUMBER + 1];
+
+
+NTSTATUS DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
+{
+ PKEY_VALUE_PARTIAL_INFORMATION startKeyValue;
+ LONG version;
+ int i;
+
+ Dump ("DriverEntry " TC_APP_NAME " " VERSION_STRING "\n");
+
+ DetectX86Features ();
+
+ PsGetVersion (&OsMajorVersion, &OsMinorVersion, NULL, NULL);
+
+ // Load dump filter if the main driver is already loaded
+ if (NT_SUCCESS (TCDeviceIoControl (NT_ROOT_PREFIX, TC_IOCTL_GET_DRIVER_VERSION, NULL, 0, &version, sizeof (version))))
+ return DumpFilterEntry ((PFILTER_EXTENSION) DriverObject, (PFILTER_INITIALIZATION_DATA) RegistryPath);
+
+ TCDriverObject = DriverObject;
+ memset (VirtualVolumeDeviceObjects, 0, sizeof (VirtualVolumeDeviceObjects));
+
+ ReadRegistryConfigFlags (TRUE);
+ EncryptionThreadPoolStart (EncryptionThreadPoolFreeCpuCountLimit);
+ SelfTestsPassed = AutoTestAlgorithms();
+
+ // Enable device class filters and load boot arguments if the driver is set to start at system boot
+
+ if (NT_SUCCESS (TCReadRegistryKey (RegistryPath, L"Start", &startKeyValue)))
+ {
+ if (startKeyValue->Type == REG_DWORD && *((uint32 *) startKeyValue->Data) == SERVICE_BOOT_START)
+ {
+ if (!SelfTestsPassed)
+ TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
+
+ LoadBootArguments();
+ VolumeClassFilterRegistered = IsVolumeClassFilterRegistered();
+
+ DriverObject->DriverExtension->AddDevice = DriverAddDevice;
+ }
+
+ TCfree (startKeyValue);
+ }
+
+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
+ {
+ DriverObject->MajorFunction[i] = TCDispatchQueueIRP;
+ }
+
+ DriverObject->DriverUnload = TCUnloadDriver;
+ return TCCreateRootDeviceObject (DriverObject);
+}
+
+
+NTSTATUS DriverAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo)
+{
+#ifdef DEBUG
+ char nameInfoBuffer[128];
+ POBJECT_NAME_INFORMATION nameInfo = (POBJECT_NAME_INFORMATION) nameInfoBuffer;
+ ULONG nameInfoSize;
+ Dump ("AddDevice pdo=%p type=%x name=%ws\n", pdo, pdo->DeviceType, NT_SUCCESS (ObQueryNameString (pdo, nameInfo, sizeof (nameInfoBuffer), &nameInfoSize)) ? nameInfo->Name.Buffer : L"?");
+#endif
+
+ if (VolumeClassFilterRegistered && BootArgsValid && BootArgs.HiddenSystemPartitionStart != 0)
+ {
+ PWSTR interfaceLinks = NULL;
+ if (NT_SUCCESS (IoGetDeviceInterfaces (&GUID_DEVINTERFACE_VOLUME, pdo, DEVICE_INTERFACE_INCLUDE_NONACTIVE, &interfaceLinks)) && interfaceLinks)
+ {
+ if (interfaceLinks[0] != UNICODE_NULL)
+ {
+ Dump ("Volume pdo=%p interface=%ws\n", pdo, interfaceLinks);
+ ExFreePool (interfaceLinks);
+
+ return VolumeFilterAddDevice (driverObject, pdo);
+ }
+
+ ExFreePool (interfaceLinks);
+ }
+ }
+
+ return DriveFilterAddDevice (driverObject, pdo);
+}
+
+
+// Dumps a memory region to debug output
+void DumpMemory (void *mem, int size)
+{
+ unsigned char str[20];
+ unsigned char *m = mem;
+ int i,j;
+
+ for (j = 0; j < size / 8; j++)
+ {
+ memset (str,0,sizeof str);
+ for (i = 0; i < 8; i++)
+ {
+ if (m[i] > ' ' && m[i] <= '~')
+ str[i]=m[i];
+ else
+ str[i]='.';
+ }
+
+ Dump ("0x%08p %02x %02x %02x %02x %02x %02x %02x %02x %s\n",
+ m, m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], str);
+
+ m+=8;
+ }
+}
+
+
+BOOL ValidateIOBufferSize (PIRP irp, size_t requiredBufferSize, ValidateIOBufferSizeType type)
+{
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
+ BOOL input = (type == ValidateInput || type == ValidateInputOutput);
+ BOOL output = (type == ValidateOutput || type == ValidateInputOutput);
+
+ if ((input && irpSp->Parameters.DeviceIoControl.InputBufferLength < requiredBufferSize)
+ || (output && irpSp->Parameters.DeviceIoControl.OutputBufferLength < requiredBufferSize))
+ {
+ Dump ("STATUS_BUFFER_TOO_SMALL ioctl=0x%x,%d in=%d out=%d reqsize=%d insize=%d outsize=%d\n", (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16), (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2), input, output, requiredBufferSize, irpSp->Parameters.DeviceIoControl.InputBufferLength, irpSp->Parameters.DeviceIoControl.OutputBufferLength);
+
+ irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+ irp->IoStatus.Information = 0;
+ return FALSE;
+ }
+
+ if (!input && output)
+ memset (irp->AssociatedIrp.SystemBuffer, 0, irpSp->Parameters.DeviceIoControl.OutputBufferLength);
+
+ return TRUE;
+}
+
+
+PDEVICE_OBJECT GetVirtualVolumeDeviceObject (int driveNumber)
+{
+ if (driveNumber < MIN_MOUNTED_VOLUME_DRIVE_NUMBER || driveNumber > MAX_MOUNTED_VOLUME_DRIVE_NUMBER)
+ return NULL;
+
+ return VirtualVolumeDeviceObjects[driveNumber];
+}
+
+
+/* TCDispatchQueueIRP queues any IRP's so that they can be processed later
+ by the thread -- or in some cases handles them immediately! */
+NTSTATUS TCDispatchQueueIRP (PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ PEXTENSION Extension = (PEXTENSION) DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
+ NTSTATUS ntStatus;
+
+#ifdef _DEBUG
+ if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL && (Extension->bRootDevice || Extension->IsVolumeDevice))
+ {
+ switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case TC_IOCTL_GET_MOUNTED_VOLUMES:
+ case TC_IOCTL_GET_PASSWORD_CACHE_STATUS:
+ case TC_IOCTL_GET_PORTABLE_MODE_STATUS:
+ case TC_IOCTL_SET_PORTABLE_MODE_STATUS:
+ case TC_IOCTL_OPEN_TEST:
+ case TC_IOCTL_GET_RESOLVED_SYMLINK:
+ case TC_IOCTL_GET_DEVICE_REFCOUNT:
+ case TC_IOCTL_GET_DRIVE_PARTITION_INFO:
+ case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES:
+ case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS:
+ case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS:
+ case TC_IOCTL_GET_WARNING_FLAGS:
+ case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING:
+ case IOCTL_DISK_CHECK_VERIFY:
+ break;
+
+ default:
+ Dump ("%ls (0x%x %d)\n",
+ TCTranslateCode (irpSp->Parameters.DeviceIoControl.IoControlCode),
+ (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16),
+ (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2));
+ }
+ }
+#endif
+
+ if (!Extension->bRootDevice)
+ {
+ // Drive filter IRP
+ if (Extension->IsDriveFilterDevice)
+ return DriveFilterDispatchIrp (DeviceObject, Irp);
+
+ // Volume filter IRP
+ if (Extension->IsVolumeFilterDevice)
+ return VolumeFilterDispatchIrp (DeviceObject, Irp);
+ }
+
+ switch (irpSp->MajorFunction)
+ {
+ case IRP_MJ_CLOSE:
+ case IRP_MJ_CREATE:
+ case IRP_MJ_CLEANUP:
+ return COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0);
+
+ case IRP_MJ_SHUTDOWN:
+ if (Extension->bRootDevice)
+ {
+ Dump ("Driver shutting down\n");
+ DriverShuttingDown = TRUE;
+
+ if (EncryptionSetupThread)
+ while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES);
+
+ if (DecoySystemWipeThread)
+ while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES);
+
+ OnShutdownPending();
+ }
+
+ return COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0);
+
+ case IRP_MJ_FLUSH_BUFFERS:
+ case IRP_MJ_READ:
+ case IRP_MJ_WRITE:
+ case IRP_MJ_DEVICE_CONTROL:
+
+ if (Extension->bRootDevice)
+ {
+ if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
+ {
+ NTSTATUS status = KeWaitForMutexObject (&RootDeviceControlMutex, Executive, KernelMode, FALSE, NULL);
+ if (!NT_SUCCESS (status))
+ return status;
+
+ status = ProcessMainDeviceControlIrp (DeviceObject, Extension, Irp);
+
+ KeReleaseMutex (&RootDeviceControlMutex, FALSE);
+ return status;
+ }
+ break;
+ }
+
+ if (Extension->bShuttingDown)
+ {
+ Dump ("Device %d shutting down: STATUS_DELETE_PENDING\n", Extension->nDosDriveNo);
+ return TCCompleteDiskIrp (Irp, STATUS_DELETE_PENDING, 0);
+ }
+
+ if (Extension->bRemovable
+ && (DeviceObject->Flags & DO_VERIFY_VOLUME)
+ && !(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME)
+ && irpSp->MajorFunction != IRP_MJ_FLUSH_BUFFERS)
+ {
+ Dump ("Removable device %d has DO_VERIFY_VOLUME flag: STATUS_DEVICE_NOT_READY\n", Extension->nDosDriveNo);
+ return TCCompleteDiskIrp (Irp, STATUS_DEVICE_NOT_READY, 0);
+ }
+
+ switch (irpSp->MajorFunction)
+ {
+ case IRP_MJ_READ:
+ case IRP_MJ_WRITE:
+ ntStatus = EncryptedIoQueueAddIrp (&Extension->Queue, Irp);
+
+ if (ntStatus != STATUS_PENDING)
+ TCCompleteDiskIrp (Irp, ntStatus, 0);
+
+ return ntStatus;
+
+ case IRP_MJ_DEVICE_CONTROL:
+ ntStatus = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ if (!NT_SUCCESS (ntStatus))
+ return TCCompleteIrp (Irp, ntStatus, 0);
+
+ IoMarkIrpPending (Irp);
+
+ ExInterlockedInsertTailList (&Extension->ListEntry, &Irp->Tail.Overlay.ListEntry, &Extension->ListSpinLock);
+ KeReleaseSemaphore (&Extension->RequestSemaphore, IO_DISK_INCREMENT, 1, FALSE);
+
+ return STATUS_PENDING;
+
+ case IRP_MJ_FLUSH_BUFFERS:
+ return TCCompleteDiskIrp (Irp, STATUS_SUCCESS, 0);
+ }
+
+ break;
+
+ case IRP_MJ_PNP:
+ if (!Extension->bRootDevice
+ && Extension->IsVolumeDevice
+ && irpSp->MinorFunction == IRP_MN_DEVICE_USAGE_NOTIFICATION
+ && irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging
+ && irpSp->Parameters.UsageNotification.InPath)
+ {
+ PagingFileCreationPrevented = TRUE;
+ return TCCompleteIrp (Irp, STATUS_UNSUCCESSFUL, 0);
+ }
+ break;
+ }
+
+ return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
+}
+
+NTSTATUS TCCreateRootDeviceObject (PDRIVER_OBJECT DriverObject)
+{
+ UNICODE_STRING Win32NameString, ntUnicodeString;
+ WCHAR dosname[32], ntname[32];
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS ntStatus;
+ BOOL *bRootExtension;
+
+ Dump ("TCCreateRootDeviceObject BEGIN\n");
+ ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ RtlStringCbCopyW (dosname, sizeof(dosname),(LPWSTR) DOS_ROOT_PREFIX);
+ RtlStringCbCopyW (ntname, sizeof(ntname),(LPWSTR) NT_ROOT_PREFIX);
+ RtlInitUnicodeString (&ntUnicodeString, ntname);
+ RtlInitUnicodeString (&Win32NameString, dosname);
+
+ Dump ("Creating root device nt=%ls dos=%ls\n", ntname, dosname);
+
+ ntStatus = IoCreateDevice (
+ DriverObject,
+ sizeof (BOOL),
+ &ntUnicodeString,
+ FILE_DEVICE_UNKNOWN,
+ FILE_DEVICE_SECURE_OPEN,
+ FALSE,
+ &DeviceObject);
+
+ if (!NT_SUCCESS (ntStatus))
+ {
+ Dump ("TCCreateRootDeviceObject NTSTATUS = 0x%08x END\n", ntStatus);
+ return ntStatus;/* Failed to create DeviceObject */
+ }
+
+ DeviceObject->Flags |= DO_DIRECT_IO;
+ DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
+
+ /* Setup the device extension */
+ bRootExtension = (BOOL *) DeviceObject->DeviceExtension;
+ *bRootExtension = TRUE;
+
+ KeInitializeMutex (&RootDeviceControlMutex, 0);
+
+ ntStatus = IoCreateSymbolicLink (&Win32NameString, &ntUnicodeString);
+
+ if (!NT_SUCCESS (ntStatus))
+ {
+ Dump ("TCCreateRootDeviceObject NTSTATUS = 0x%08x END\n", ntStatus);
+ IoDeleteDevice (DeviceObject);
+ return ntStatus;
+ }
+
+ IoRegisterShutdownNotification (DeviceObject);
+ RootDeviceObject = DeviceObject;
+
+ Dump ("TCCreateRootDeviceObject STATUS_SUCCESS END\n");
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS TCCreateDeviceObject (PDRIVER_OBJECT DriverObject,
+ PDEVICE_OBJECT * ppDeviceObject,
+ MOUNT_STRUCT * mount)
+{
+ UNICODE_STRING ntUnicodeString;
+ WCHAR ntname[32];
+ PEXTENSION Extension;
+ NTSTATUS ntStatus;
+ ULONG devChars = 0;
+#if defined (DEBUG)
+ WCHAR dosname[32];
+#endif
+
+ Dump ("TCCreateDeviceObject BEGIN\n");
+ ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ TCGetNTNameFromNumber (ntname, sizeof(ntname),mount->nDosDriveNo);
+ RtlInitUnicodeString (&ntUnicodeString, ntname);
+#if defined (DEBUG)
+ TCGetDosNameFromNumber (dosname, sizeof(dosname),mount->nDosDriveNo, DeviceNamespaceDefault);
+#endif
+
+ devChars = FILE_DEVICE_SECURE_OPEN;
+ devChars |= mount->bMountReadOnly ? FILE_READ_ONLY_DEVICE : 0;
+ devChars |= mount->bMountRemovable ? FILE_REMOVABLE_MEDIA : 0;
+
+ Dump ("Creating device nt=%ls dos=%ls\n", ntname, dosname);
+
+ ntStatus = IoCreateDevice (
+ DriverObject, /* Our Driver Object */
+ sizeof (EXTENSION), /* Size of state information */
+ &ntUnicodeString, /* Device name "\Device\Name" */
+ FILE_DEVICE_DISK, /* Device type */
+ devChars, /* Device characteristics */
+ FALSE, /* Exclusive device */
+ ppDeviceObject); /* Returned ptr to Device Object */
+
+ if (!NT_SUCCESS (ntStatus))
+ {
+ Dump ("TCCreateDeviceObject NTSTATUS = 0x%08x END\n", ntStatus);
+ return ntStatus;/* Failed to create DeviceObject */
+ }
+ /* Initialize device object and extension. */
+
+ (*ppDeviceObject)->Flags |= DO_DIRECT_IO;
+ (*ppDeviceObject)->StackSize += 6; // Reduce occurrence of NO_MORE_IRP_STACK_LOCATIONS bug check caused by buggy drivers
+
+ /* Setup the device extension */
+ Extension = (PEXTENSION) (*ppDeviceObject)->DeviceExtension;
+ memset (Extension, 0, sizeof (EXTENSION));
+
+ Extension->IsVolumeDevice = TRUE;
+ Extension->nDosDriveNo = mount->nDosDriveNo;
+ Extension->bRemovable = mount->bMountRemovable;
+ Extension->PartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope;
+ Extension->SystemFavorite = mount->SystemFavorite;
+
+ KeInitializeEvent (&Extension->keCreateEvent, SynchronizationEvent, FALSE);
+ KeInitializeSemaphore (&Extension->RequestSemaphore, 0L, MAXLONG);
+ KeInitializeSpinLock (&Extension->ListSpinLock);
+ InitializeListHead (&Extension->ListEntry);
+ IoInitializeRemoveLock (&Extension->Queue.RemoveLock, 'LRCV', 0, 0);
+
+ VirtualVolumeDeviceObjects[mount->nDosDriveNo] = *ppDeviceObject;
+
+ Dump ("TCCreateDeviceObject STATUS_SUCCESS END\n");
+
+ return STATUS_SUCCESS;
+}
+
+
+BOOL RootDeviceControlMutexAcquireNoWait ()
+{
+ NTSTATUS status;
+ LARGE_INTEGER timeout;
+ timeout.QuadPart = 0;
+
+ status = KeWaitForMutexObject (&RootDeviceControlMutex, Executive, KernelMode, FALSE, &timeout);
+ return NT_SUCCESS (status) && status != STATUS_TIMEOUT;
+}
+
+
+void RootDeviceControlMutexRelease ()
+{
+ KeReleaseMutex (&RootDeviceControlMutex, FALSE);
+}
+
+
+NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp)
+{
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+
+ case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
+ if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_NAME), ValidateOutput))
+ {
+ Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME);
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ ULONG outLength;
+ UNICODE_STRING ntUnicodeString;
+ WCHAR ntName[256];
+ PMOUNTDEV_NAME outputBuffer = (PMOUNTDEV_NAME) Irp->AssociatedIrp.SystemBuffer;
+
+ TCGetNTNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo);
+ RtlInitUnicodeString (&ntUnicodeString, ntName);
+
+ outputBuffer->NameLength = ntUnicodeString.Length;
+ outLength = ntUnicodeString.Length + sizeof(USHORT);
+
+ if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength)
+ {
+ Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME);
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+
+ break;
+ }
+
+ RtlCopyMemory ((PCHAR)outputBuffer->Name,ntUnicodeString.Buffer, ntUnicodeString.Length);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = outLength;
+
+ Dump ("name = %ls\n",ntName);
+ }
+ break;
+
+ case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
+ if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_UNIQUE_ID), ValidateOutput))
+ {
+ Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID);
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ ULONG outLength;
+ UCHAR volId[128], tmp[] = { 0,0 };
+ PMOUNTDEV_UNIQUE_ID outputBuffer = (PMOUNTDEV_UNIQUE_ID) Irp->AssociatedIrp.SystemBuffer;
+
+ RtlStringCbCopyA (volId, sizeof(volId),TC_UNIQUE_ID_PREFIX);
+ tmp[0] = 'A' + (UCHAR) Extension->nDosDriveNo;
+ RtlStringCbCatA (volId, sizeof(volId),tmp);
+
+ outputBuffer->UniqueIdLength = (USHORT) strlen (volId);
+ outLength = (ULONG) (strlen (volId) + sizeof (USHORT));
+
+ if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength)
+ {
+ Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID);
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ RtlCopyMemory ((PCHAR)outputBuffer->UniqueId, volId, strlen (volId));
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = outLength;
+
+ Dump ("id = %s\n",volId);
+ }
+ break;
+
+ case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME:
+ {
+ ULONG outLength;
+ UNICODE_STRING ntUnicodeString;
+ WCHAR ntName[256];
+ PMOUNTDEV_SUGGESTED_LINK_NAME outputBuffer = (PMOUNTDEV_SUGGESTED_LINK_NAME) Irp->AssociatedIrp.SystemBuffer;
+
+ if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_SUGGESTED_LINK_NAME), ValidateOutput))
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+ break;
+ }
+
+ TCGetDosNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo, DeviceNamespaceDefault);
+ RtlInitUnicodeString (&ntUnicodeString, ntName);
+
+ outLength = FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME,Name) + ntUnicodeString.Length;
+
+ outputBuffer->UseOnlyIfThereAreNoOtherLinks = FALSE;
+ outputBuffer->NameLength = ntUnicodeString.Length;
+
+ if(irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength)
+ {
+ Irp->IoStatus.Information = sizeof (MOUNTDEV_SUGGESTED_LINK_NAME);
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ RtlCopyMemory ((PCHAR)outputBuffer->Name,ntUnicodeString.Buffer, ntUnicodeString.Length);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = outLength;
+
+ Dump ("link = %ls\n",ntName);
+ }
+ break;
+
+ case IOCTL_DISK_GET_MEDIA_TYPES:
+ case IOCTL_DISK_GET_DRIVE_GEOMETRY:
+ /* Return the drive geometry for the disk. Note that we
+ return values which were made up to suit the disk size. */
+ if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY), ValidateOutput))
+ {
+ PDISK_GEOMETRY outputBuffer = (PDISK_GEOMETRY)
+ Irp->AssociatedIrp.SystemBuffer;
+
+ outputBuffer->MediaType = Extension->bRemovable ? RemovableMedia : FixedMedia;
+ outputBuffer->Cylinders.QuadPart = Extension->NumberOfCylinders;
+ outputBuffer->TracksPerCylinder = Extension->TracksPerCylinder;
+ outputBuffer->SectorsPerTrack = Extension->SectorsPerTrack;
+ outputBuffer->BytesPerSector = Extension->BytesPerSector;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof (DISK_GEOMETRY);
+ }
+ break;
+
+ case IOCTL_STORAGE_QUERY_PROPERTY:
+ if (EnableExtendedIoctlSupport)
+ {
+ if (ValidateIOBufferSize (Irp, sizeof (STORAGE_PROPERTY_QUERY), ValidateInput))
+ {
+ PSTORAGE_PROPERTY_QUERY pStoragePropQuery = (PSTORAGE_PROPERTY_QUERY) Irp->AssociatedIrp.SystemBuffer;
+ STORAGE_QUERY_TYPE type = pStoragePropQuery->QueryType;
+
+ /* return error if an unsupported type is encountered */
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ Irp->IoStatus.Information = 0;
+
+ if ( (pStoragePropQuery->PropertyId == StorageAccessAlignmentProperty)
+ || (pStoragePropQuery->PropertyId == StorageDeviceProperty)
+ )
+ {
+ if (type == PropertyExistsQuery)
+ {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ }
+ else if (type == PropertyStandardQuery)
+ {
+ switch (pStoragePropQuery->PropertyId)
+ {
+ case StorageDeviceProperty:
+ {
+ if (ValidateIOBufferSize (Irp, sizeof (STORAGE_DEVICE_DESCRIPTOR), ValidateOutput))
+ {
+ PSTORAGE_DEVICE_DESCRIPTOR outputBuffer = (PSTORAGE_DEVICE_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer;
+
+ outputBuffer->Version = sizeof(STORAGE_DEVICE_DESCRIPTOR);
+ outputBuffer->Size = sizeof(STORAGE_DEVICE_DESCRIPTOR);
+ outputBuffer->DeviceType = FILE_DEVICE_DISK;
+ outputBuffer->RemovableMedia = Extension->bRemovable? TRUE : FALSE;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof (STORAGE_DEVICE_DESCRIPTOR);
+ }
+ }
+ break;
+ case StorageAccessAlignmentProperty:
+ {
+ if (ValidateIOBufferSize (Irp, sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), ValidateOutput))
+ {
+ PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR outputBuffer = (PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer;
+
+ outputBuffer->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
+ outputBuffer->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
+ outputBuffer->BytesPerLogicalSector = Extension->BytesPerSector;
+ outputBuffer->BytesPerPhysicalSector = Extension->HostBytesPerPhysicalSector;
+ outputBuffer->BytesOffsetForSectorAlignment = Extension->BytesOffsetForSectorAlignment;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
+
+ break;
+
+ case IOCTL_DISK_GET_PARTITION_INFO:
+ if (ValidateIOBufferSize (Irp, sizeof (PARTITION_INFORMATION), ValidateOutput))
+ {
+ PPARTITION_INFORMATION outputBuffer = (PPARTITION_INFORMATION)
+ Irp->AssociatedIrp.SystemBuffer;
+
+ outputBuffer->PartitionType = Extension->PartitionType;
+ outputBuffer->BootIndicator = FALSE;
+ outputBuffer->RecognizedPartition = TRUE;
+ outputBuffer->RewritePartition = FALSE;
+ outputBuffer->StartingOffset.QuadPart = Extension->BytesPerSector;
+ outputBuffer->PartitionLength.QuadPart= Extension->DiskLength;
+ outputBuffer->HiddenSectors = 0;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION);
+ }
+ break;
+
+ case IOCTL_DISK_GET_PARTITION_INFO_EX:
+ if (ValidateIOBufferSize (Irp, sizeof (PARTITION_INFORMATION_EX), ValidateOutput))
+ {
+ PPARTITION_INFORMATION_EX outputBuffer = (PPARTITION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer;
+
+ outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
+ outputBuffer->RewritePartition = FALSE;
+ outputBuffer->StartingOffset.QuadPart = Extension->BytesPerSector;
+ outputBuffer->PartitionLength.QuadPart= Extension->DiskLength;
+ outputBuffer->Mbr.PartitionType = Extension->PartitionType;
+ outputBuffer->Mbr.BootIndicator = FALSE;
+ outputBuffer->Mbr.RecognizedPartition = TRUE;
+ outputBuffer->Mbr.HiddenSectors = 0;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION_EX);
+ }
+ break;
+
+ case IOCTL_DISK_GET_DRIVE_LAYOUT:
+ if (ValidateIOBufferSize (Irp, sizeof (DRIVE_LAYOUT_INFORMATION), ValidateOutput))
+ {
+ PDRIVE_LAYOUT_INFORMATION outputBuffer = (PDRIVE_LAYOUT_INFORMATION)
+ Irp->AssociatedIrp.SystemBuffer;
+
+ outputBuffer->PartitionCount = 1;
+ outputBuffer->Signature = 0;
+
+ outputBuffer->PartitionEntry->PartitionType = Extension->PartitionType;
+ outputBuffer->PartitionEntry->BootIndicator = FALSE;
+ outputBuffer->PartitionEntry->RecognizedPartition = TRUE;
+ outputBuffer->PartitionEntry->RewritePartition = FALSE;
+ outputBuffer->PartitionEntry->StartingOffset.QuadPart = Extension->BytesPerSector;
+ outputBuffer->PartitionEntry->PartitionLength.QuadPart = Extension->DiskLength;
+ outputBuffer->PartitionEntry->HiddenSectors = 0;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION);
+ }
+ break;
+
+ case IOCTL_DISK_GET_LENGTH_INFO:
+ if (!ValidateIOBufferSize (Irp, sizeof (GET_LENGTH_INFORMATION), ValidateOutput))
+ {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ Irp->IoStatus.Information = sizeof (GET_LENGTH_INFORMATION);
+ }
+ else
+ {
+ PGET_LENGTH_INFORMATION outputBuffer = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
+
+ outputBuffer->Length.QuadPart = Extension->DiskLength;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof (GET_LENGTH_INFORMATION);
+ }
+ break;
+
+ case IOCTL_DISK_VERIFY:
+ if (ValidateIOBufferSize (Irp, sizeof (VERIFY_INFORMATION), ValidateInput))
+ {
+ HRESULT hResult;
+ ULONGLONG ullStartingOffset, ullNewOffset, ullEndOffset;
+ PVERIFY_INFORMATION pVerifyInformation;
+ pVerifyInformation = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
+
+ ullStartingOffset = (ULONGLONG) pVerifyInformation->StartingOffset.QuadPart;
+ hResult = ULongLongAdd(ullStartingOffset,
+ (ULONGLONG) Extension->cryptoInfo->hiddenVolume ? Extension->cryptoInfo->hiddenVolumeOffset : Extension->cryptoInfo->volDataAreaOffset,
+ &ullNewOffset);
+ if (hResult != S_OK)
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ else if (S_OK != ULongLongAdd(ullStartingOffset, (ULONGLONG) pVerifyInformation->Length, &ullEndOffset))
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ else if (ullEndOffset > (ULONGLONG) Extension->DiskLength)
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ else
+ {
+ IO_STATUS_BLOCK ioStatus;
+ PVOID buffer = TCalloc (max (pVerifyInformation->Length, PAGE_SIZE));
+
+ if (!buffer)
+ {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ LARGE_INTEGER offset = pVerifyInformation->StartingOffset;
+ offset.QuadPart = ullNewOffset;
+
+ Irp->IoStatus.Status = ZwReadFile (Extension->hDeviceFile, NULL, NULL, NULL, &ioStatus, buffer, pVerifyInformation->Length, &offset, NULL);
+ TCfree (buffer);
+
+ if (NT_SUCCESS (Irp->IoStatus.Status) && ioStatus.Information != pVerifyInformation->Length)
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ Irp->IoStatus.Information = 0;
+ }
+ break;
+
+ case IOCTL_DISK_CHECK_VERIFY:
+ case IOCTL_STORAGE_CHECK_VERIFY:
+ {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+ if (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof (ULONG))
+ {
+ *((ULONG *) Irp->AssociatedIrp.SystemBuffer) = 0;
+ Irp->IoStatus.Information = sizeof (ULONG);
+ }
+ }
+ break;
+
+ case IOCTL_DISK_IS_WRITABLE:
+ {
+ if (Extension->bReadOnly)
+ Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
+ else
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+ }
+ break;
+
+ case IOCTL_VOLUME_ONLINE:
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ break;
+
+ case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
+
+ // Vista's filesystem defragmenter fails if IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS does not succeed.
+ if (!(OsMajorVersion == 6 && OsMinorVersion == 0))
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ Irp->IoStatus.Information = 0;
+ }
+ else if (ValidateIOBufferSize (Irp, sizeof (VOLUME_DISK_EXTENTS), ValidateOutput))
+ {
+ VOLUME_DISK_EXTENTS *extents = (VOLUME_DISK_EXTENTS *) Irp->AssociatedIrp.SystemBuffer;
+
+ // No extent data can be returned as this is not a physical drive.
+ memset (extents, 0, sizeof (*extents));
+ extents->NumberOfDiskExtents = 0;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof (*extents);
+ }
+ break;
+
+ default:
+ return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
+ }
+
+#ifdef DEBUG
+ if (!NT_SUCCESS (Irp->IoStatus.Status))
+ {
+ Dump ("IOCTL error 0x%08x (0x%x %d)\n",
+ Irp->IoStatus.Status,
+ (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16),
+ (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2));
+ }
+#endif
+
+ return TCCompleteDiskIrp (Irp, Irp->IoStatus.Status, Irp->IoStatus.Information);
+}
+
+
+NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp)
+{
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
+ NTSTATUS ntStatus;
+
+ switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case TC_IOCTL_GET_DRIVER_VERSION:
+ case TC_IOCTL_LEGACY_GET_DRIVER_VERSION:
+ if (ValidateIOBufferSize (Irp, sizeof (LONG), ValidateOutput))
+ {
+ LONG tmp = VERSION_NUM;
+ memcpy (Irp->AssociatedIrp.SystemBuffer, &tmp, 4);
+ Irp->IoStatus.Information = sizeof (LONG);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ break;
+
+ case TC_IOCTL_GET_DEVICE_REFCOUNT:
+ if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput))
+ {
+ *(int *) Irp->AssociatedIrp.SystemBuffer = DeviceObject->ReferenceCount;
+ Irp->IoStatus.Information = sizeof (int);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ break;
+
+ case TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED:
+ if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput))
+ {
+ LONG deviceObjectCount = 0;
+
+ *(int *) Irp->AssociatedIrp.SystemBuffer = DriverUnloadDisabled;
+
+ if (IoEnumerateDeviceObjectList (TCDriverObject, NULL, 0, &deviceObjectCount) == STATUS_BUFFER_TOO_SMALL && deviceObjectCount > 1)
+ *(int *) Irp->AssociatedIrp.SystemBuffer = TRUE;
+
+ Irp->IoStatus.Information = sizeof (int);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ break;
+
+ case TC_IOCTL_IS_ANY_VOLUME_MOUNTED:
+ if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput))
+ {
+ int drive;
+ *(int *) Irp->AssociatedIrp.SystemBuffer = 0;
+
+ for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive)
+ {
+ if (GetVirtualVolumeDeviceObject (drive))
+ {
+ *(int *) Irp->AssociatedIrp.SystemBuffer = 1;
+ break;
+ }
+ }
+
+ if (IsBootDriveMounted())
+ *(int *) Irp->AssociatedIrp.SystemBuffer = 1;
+
+ Irp->IoStatus.Information = sizeof (int);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ break;
+
+ case TC_IOCTL_OPEN_TEST:
+ {
+ OPEN_TEST_STRUCT *opentest = (OPEN_TEST_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE NtFileHandle;
+ UNICODE_STRING FullFileName;
+ IO_STATUS_BLOCK IoStatus;
+ LARGE_INTEGER offset;
+ ACCESS_MASK access = FILE_READ_ATTRIBUTES;
+
+ if (!ValidateIOBufferSize (Irp, sizeof (OPEN_TEST_STRUCT), ValidateInputOutput))
+ break;
+
+ EnsureNullTerminatedString (opentest->wszFileName, sizeof (opentest->wszFileName));
+ RtlInitUnicodeString (&FullFileName, opentest->wszFileName);
+
+ InitializeObjectAttributes (&ObjectAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem || opentest->bMatchVolumeID)
+ access |= FILE_READ_DATA;
+
+ ntStatus = ZwCreateFile (&NtFileHandle,
+ SYNCHRONIZE | access, &ObjectAttributes, &IoStatus, NULL,
+ 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
+
+ if (NT_SUCCESS (ntStatus))
+ {
+ opentest->TCBootLoaderDetected = FALSE;
+ opentest->FilesystemDetected = FALSE;
+ opentest->VolumeIDMatched = FALSE;
+
+ if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem || opentest->bMatchVolumeID)
+ {
+ byte *readBuffer = TCalloc (TC_MAX_VOLUME_SECTOR_SIZE);
+ if (!readBuffer)
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem)
+ {
+ // Determine if the first sector contains a portion of the VeraCrypt Boot Loader
+
+ offset.QuadPart = 0;
+
+ ntStatus = ZwReadFile (NtFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ readBuffer,
+ TC_MAX_VOLUME_SECTOR_SIZE,
+ &offset,
+ NULL);
+
+ if (NT_SUCCESS (ntStatus))
+ {
+ size_t i;
+
+ if (opentest->bDetectTCBootLoader && IoStatus.Information >= TC_SECTOR_SIZE_BIOS)
+ {
+ // Search for the string "VeraCrypt"
+ for (i = 0; i < TC_SECTOR_SIZE_BIOS - strlen (TC_APP_NAME); ++i)
+ {
+ if (memcmp (readBuffer + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0)
+ {
+ opentest->TCBootLoaderDetected = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (opentest->DetectFilesystem && IoStatus.Information >= sizeof (int64))
+ {
+ switch (BE64 (*(uint64 *) readBuffer))
+ {
+ case 0xEB52904E54465320: // NTFS
+ case 0xEB3C904D53444F53: // FAT16
+ case 0xEB58904D53444F53: // FAT32
+ case 0xEB76904558464154: // exFAT
+
+ opentest->FilesystemDetected = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ if (opentest->bMatchVolumeID)
+ {
+ int volumeType;
+ BYTE volumeID[VOLUME_ID_SIZE];
+
+ // Go through all volume types (e.g., normal, hidden)
+ for (volumeType = TC_VOLUME_TYPE_NORMAL;
+ volumeType < TC_VOLUME_TYPE_COUNT;
+ volumeType++)
+ {
+ /* Read the volume header */
+ switch (volumeType)
+ {
+ case TC_VOLUME_TYPE_NORMAL:
+ offset.QuadPart = TC_VOLUME_HEADER_OFFSET;
+ break;
+
+ case TC_VOLUME_TYPE_HIDDEN:
+
+ offset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET;
+ break;
+ }
+
+ ntStatus = ZwReadFile (NtFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ readBuffer,
+ TC_MAX_VOLUME_SECTOR_SIZE,
+ &offset,
+ NULL);
+
+ if (NT_SUCCESS (ntStatus))
+ {
+ /* compute the ID of this volume: SHA-256 of the effective header */
+ sha256 (volumeID, readBuffer, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
+
+ if (0 == memcmp (volumeID, opentest->volumeID, VOLUME_ID_SIZE))
+ {
+ opentest->VolumeIDMatched = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ TCfree (readBuffer);
+ }
+ }
+
+ ZwClose (NtFileHandle);
+ Dump ("Open test on file %ls success.\n", opentest->wszFileName);
+ }
+ else
+ {
+#if 0
+ Dump ("Open test on file %ls failed NTSTATUS 0x%08x\n", opentest->wszFileName, ntStatus);
+#endif
+ }
+
+ Irp->IoStatus.Information = NT_SUCCESS (ntStatus) ? sizeof (OPEN_TEST_STRUCT) : 0;
+ Irp->IoStatus.Status = ntStatus;
+ }
+ break;
+
+ case TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG:
+ {
+ GetSystemDriveConfigurationRequest *request = (GetSystemDriveConfigurationRequest *) Irp->AssociatedIrp.SystemBuffer;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE NtFileHandle;
+ UNICODE_STRING FullFileName;
+ IO_STATUS_BLOCK IoStatus;
+ LARGE_INTEGER offset;
+ byte readBuffer [TC_SECTOR_SIZE_BIOS];
+
+ if (!ValidateIOBufferSize (Irp, sizeof (GetSystemDriveConfigurationRequest), ValidateInputOutput))
+ break;
+
+ EnsureNullTerminatedString (request->DevicePath, sizeof (request->DevicePath));
+ RtlInitUnicodeString (&FullFileName, request->DevicePath);
+
+ InitializeObjectAttributes (&ObjectAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ ntStatus = ZwCreateFile (&NtFileHandle,
+ SYNCHRONIZE | GENERIC_READ, &ObjectAttributes, &IoStatus, NULL,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_RANDOM_ACCESS, NULL, 0);
+
+ if (NT_SUCCESS (ntStatus))
+ {
+ // Determine if the first sector contains a portion of the VeraCrypt Boot Loader
+ offset.QuadPart = 0; // MBR
+
+ ntStatus = ZwReadFile (NtFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ readBuffer,
+ sizeof(readBuffer),
+ &offset,
+ NULL);
+
+ if (NT_SUCCESS (ntStatus))
+ {
+ size_t i;
+
+ // Check for dynamic drive
+ request->DriveIsDynamic = FALSE;
+
+ if (readBuffer[510] == 0x55 && readBuffer[511] == 0xaa)
+ {
+ int i;
+ for (i = 0; i < 4; ++i)
+ {
+ if (readBuffer[446 + i * 16 + 4] == PARTITION_LDM)
+ {
+ request->DriveIsDynamic = TRUE;
+ break;
+ }
+ }
+ }
+
+ request->BootLoaderVersion = 0;
+ request->Configuration = 0;
+ request->UserConfiguration = 0;
+ request->CustomUserMessage[0] = 0;
+
+ // Search for the string "VeraCrypt"
+ for (i = 0; i < sizeof (readBuffer) - strlen (TC_APP_NAME); ++i)
+ {
+ if (memcmp (readBuffer + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0)
+ {
+ request->BootLoaderVersion = BE16 (*(uint16 *) (readBuffer + TC_BOOT_SECTOR_VERSION_OFFSET));
+ request->Configuration = readBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET];
+
+ if (request->BootLoaderVersion != 0 && request->BootLoaderVersion <= VERSION_NUM)
+ {
+ request->UserConfiguration = readBuffer[TC_BOOT_SECTOR_USER_CONFIG_OFFSET];
+ memcpy (request->CustomUserMessage, readBuffer + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH);
+ }
+ break;
+ }
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof (*request);
+ }
+ else
+ {
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ }
+
+ ZwClose (NtFileHandle);
+
+ }
+ else
+ {
+ Irp->IoStatus.Status = ntStatus;
+ Irp->IoStatus.Information = 0;
+ }
+ }
+ break;
+
+ case TC_IOCTL_WIPE_PASSWORD_CACHE:
+ WipeCache ();
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ break;
+
+ case TC_IOCTL_GET_PASSWORD_CACHE_STATUS:
+ Irp->IoStatus.Status = cacheEmpty ? STATUS_PIPE_EMPTY : STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ break;
+
+ case TC_IOCTL_SET_PORTABLE_MODE_STATUS:
+ if (!UserCanAccessDriveDevice())
+ {
+ Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
+ Irp->IoStatus.Information = 0;
+ }
+ else
+ {
+ PortableMode = TRUE;
+ Dump ("Setting portable mode\n");
+ }
+ break;
+
+ case TC_IOCTL_GET_PORTABLE_MODE_STATUS:
+ Irp->IoStatus.Status = PortableMode ? STATUS_SUCCESS : STATUS_PIPE_EMPTY;
+ Irp->IoStatus.Information = 0;
+ break;
+
+ case TC_IOCTL_GET_MOUNTED_VOLUMES:
+
+ if (ValidateIOBufferSize (Irp, sizeof (MOUNT_LIST_STRUCT), ValidateOutput))
+ {
+ MOUNT_LIST_STRUCT *list = (MOUNT_LIST_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
+ PDEVICE_OBJECT ListDevice;
+ int drive;
+
+ list->ulMountedDrives = 0;
+
+ for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive)
+ {
+ PEXTENSION ListExtension;
+
+ ListDevice = GetVirtualVolumeDeviceObject (drive);
+ if (!ListDevice)
+ continue;
+
+ ListExtension = (PEXTENSION) ListDevice->DeviceExtension;
+ if (IsVolumeAccessibleByCurrentUser (ListExtension))
+ {
+ list->ulMountedDrives |= (1 << ListExtension->nDosDriveNo);
+ RtlStringCbCopyW (list->wszVolume[ListExtension->nDosDriveNo], sizeof(list->wszVolume[ListExtension->nDosDriveNo]),ListExtension->wszVolume);
+ RtlStringCbCopyW (list->wszLabel[ListExtension->nDosDriveNo], sizeof(list->wszLabel[ListExtension->nDosDriveNo]),ListExtension->wszLabel);
+ memcpy (list->volumeID[ListExtension->nDosDriveNo], ListExtension->volumeID, VOLUME_ID_SIZE);
+ list->diskLength[ListExtension->nDosDriveNo] = ListExtension->DiskLength;
+ list->ea[ListExtension->nDosDriveNo] = ListExtension->cryptoInfo->ea;
+ if (ListExtension->cryptoInfo->hiddenVolume)
+ list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_HIDDEN; // Hidden volume
+ else if (ListExtension->cryptoInfo->bHiddenVolProtectionAction)
+ list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_OUTER_VOL_WRITE_PREVENTED; // Normal/outer volume (hidden volume protected AND write already prevented)
+ else if (ListExtension->cryptoInfo->bProtectHiddenVolume)
+ list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_OUTER; // Normal/outer volume (hidden volume protected)
+ else
+ list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_NORMAL; // Normal volume
+ list->truecryptMode[ListExtension->nDosDriveNo] = ListExtension->cryptoInfo->bTrueCryptMode;
+ }
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof (MOUNT_LIST_STRUCT);
+ }
+ break;
+
+ case TC_IOCTL_LEGACY_GET_MOUNTED_VOLUMES:
+ if (ValidateIOBufferSize (Irp, sizeof (uint32), ValidateOutput))
+ {
+ // Prevent the user from downgrading to versions lower than 5.0 by faking mounted volumes.
+ // The user could render the system unbootable by downgrading when boot encryption
+ // is active or being set up.
+
+ memset (Irp->AssociatedIrp.SystemBuffer, 0, irpSp->Parameters.DeviceIoControl.OutputBufferLength);
+ *(uint32 *) Irp->AssociatedIrp.SystemBuffer = 0xffffFFFF;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ }
+ break;
+
+ case TC_IOCTL_GET_VOLUME_PROPERTIES:
+ if (ValidateIOBufferSize (Irp, sizeof (VOLUME_PROPERTIES_STRUCT), ValidateInputOutput))
+ {
+ VOLUME_PROPERTIES_STRUCT *prop = (VOLUME_PROPERTIES_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
+ PDEVICE_OBJECT ListDevice = GetVirtualVolumeDeviceObject (prop->driveNo);
+
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+
+ if (ListDevice)
+ {
+ PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension;
+ if (IsVolumeAccessibleByCurrentUser (ListExtension))
+ {
+ prop->uniqueId = ListExtension->UniqueVolumeId;
+ RtlStringCbCopyW (prop->wszVolume, sizeof(prop->wszVolume),ListExtension->wszVolume);
+ RtlStringCbCopyW (prop->wszLabel, sizeof(prop->wszLabel),ListExtension->wszLabel);
+ memcpy (prop->volumeID, ListExtension->volumeID, VOLUME_ID_SIZE);
+ prop->bDriverSetLabel = ListExtension->bDriverSetLabel;
+ prop->diskLength = ListExtension->DiskLength;
+ prop->ea = ListExtension->cryptoInfo->ea;
+ prop->mode = ListExtension->cryptoInfo->mode;
+ prop->pkcs5 = ListExtension->cryptoInfo->pkcs5;
+ prop->pkcs5Iterations = ListExtension->cryptoInfo->noIterations;
+ prop->volumePim = ListExtension->cryptoInfo->volumePim;
+#if 0
+ prop->volumeCreationTime = ListExtension->cryptoInfo->volume_creation_time;
+ prop->headerCreationTime = ListExtension->cryptoInfo->header_creation_time;
+#endif
+ prop->volumeHeaderFlags = ListExtension->cryptoInfo->HeaderFlags;
+ prop->readOnly = ListExtension->bReadOnly;
+ prop->removable = ListExtension->bRemovable;
+ prop->partitionInInactiveSysEncScope = ListExtension->PartitionInInactiveSysEncScope;
+ prop->hiddenVolume = ListExtension->cryptoInfo->hiddenVolume;
+
+ if (ListExtension->cryptoInfo->bProtectHiddenVolume)
+ prop->hiddenVolProtection = ListExtension->cryptoInfo->bHiddenVolProtectionAction ? HIDVOL_PROT_STATUS_ACTION_TAKEN : HIDVOL_PROT_STATUS_ACTIVE;
+ else
+ prop->hiddenVolProtection = HIDVOL_PROT_STATUS_NONE;
+
+ prop->totalBytesRead = ListExtension->Queue.TotalBytesRead;
+ prop->totalBytesWritten = ListExtension->Queue.TotalBytesWritten;
+
+ prop->volFormatVersion = ListExtension->cryptoInfo->LegacyVolume ? TC_VOLUME_FORMAT_VERSION_PRE_6_0 : TC_VOLUME_FORMAT_VERSION;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof (VOLUME_PROPERTIES_STRUCT);
+ }
+ }
+ }
+ break;
+
+ case TC_IOCTL_GET_RESOLVED_SYMLINK:
+ if (ValidateIOBufferSize (Irp, sizeof (RESOLVE_SYMLINK_STRUCT), ValidateInputOutput))
+ {
+ RESOLVE_SYMLINK_STRUCT *resolve = (RESOLVE_SYMLINK_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
+ {
+ NTSTATUS ntStatus;
+
+ EnsureNullTerminatedString (resolve->symLinkName, sizeof (resolve->symLinkName));
+
+ ntStatus = SymbolicLinkToTarget (resolve->symLinkName,
+ resolve->targetName,
+ sizeof (resolve->targetName));
+
+ Irp->IoStatus.Information = sizeof (RESOLVE_SYMLINK_STRUCT);
+ Irp->IoStatus.Status = ntStatus;
+ }
+ }
+ break;
+
+ case TC_IOCTL_GET_DRIVE_PARTITION_INFO:
+ if (ValidateIOBufferSize (Irp, sizeof (DISK_PARTITION_INFO_STRUCT), ValidateInputOutput))
+ {
+ DISK_PARTITION_INFO_STRUCT *info = (DISK_PARTITION_INFO_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
+ {
+ PARTITION_INFORMATION_EX pi;
+ NTSTATUS ntStatus;
+
+ EnsureNullTerminatedString (info->deviceName, sizeof (info->deviceName));
+
+ ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &pi, sizeof (pi));
+ if (NT_SUCCESS(ntStatus))
+ {
+ memset (&info->partInfo, 0, sizeof (info->partInfo));
+
+ info->partInfo.PartitionLength = pi.PartitionLength;
+ info->partInfo.PartitionNumber = pi.PartitionNumber;
+ info->partInfo.StartingOffset = pi.StartingOffset;
+
+ if (pi.PartitionStyle == PARTITION_STYLE_MBR)
+ {
+ info->partInfo.PartitionType = pi.Mbr.PartitionType;
+ info->partInfo.BootIndicator = pi.Mbr.BootIndicator;
+ }
+
+ info->IsGPT = pi.PartitionStyle == PARTITION_STYLE_GPT;
+ }
+ else
+ {
+ // Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX
+ ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &info->partInfo, sizeof (info->partInfo));
+ info->IsGPT = FALSE;
+ }
+
+ if (!NT_SUCCESS (ntStatus))
+ {
+ GET_LENGTH_INFORMATION lengthInfo;
+ ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &lengthInfo, sizeof (lengthInfo));
+
+ if (NT_SUCCESS (ntStatus))
+ {
+ memset (&info->partInfo, 0, sizeof (info->partInfo));
+ info->partInfo.PartitionLength = lengthInfo.Length;
+ }
+ }
+
+ info->IsDynamic = FALSE;
+
+ if (NT_SUCCESS (ntStatus) && OsMajorVersion >= 6)
+ {
+# define IOCTL_VOLUME_IS_DYNAMIC CTL_CODE(IOCTL_VOLUME_BASE, 18, METHOD_BUFFERED, FILE_ANY_ACCESS)
+ if (!NT_SUCCESS (TCDeviceIoControl (info->deviceName, IOCTL_VOLUME_IS_DYNAMIC, NULL, 0, &info->IsDynamic, sizeof (info->IsDynamic))))
+ info->IsDynamic = FALSE;
+ }
+
+ Irp->IoStatus.Information = sizeof (DISK_PARTITION_INFO_STRUCT);
+ Irp->IoStatus.Status = ntStatus;
+ }
+ }
+ break;
+
+ case TC_IOCTL_GET_DRIVE_GEOMETRY:
+ if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY_STRUCT), ValidateInputOutput))
+ {
+ DISK_GEOMETRY_STRUCT *g = (DISK_GEOMETRY_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
+ {
+ NTSTATUS ntStatus;
+
+ EnsureNullTerminatedString (g->deviceName, sizeof (g->deviceName));
+
+ ntStatus = TCDeviceIoControl (g->deviceName,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL, 0, &g->diskGeometry, sizeof (g->diskGeometry));
+
+ Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_STRUCT);
+ Irp->IoStatus.Status = ntStatus;
+ }
+ }
+ break;
+
+ case TC_IOCTL_PROBE_REAL_DRIVE_SIZE:
+ if (ValidateIOBufferSize (Irp, sizeof (ProbeRealDriveSizeRequest), ValidateInputOutput))
+ {
+ ProbeRealDriveSizeRequest *request = (ProbeRealDriveSizeRequest *) Irp->AssociatedIrp.SystemBuffer;
+ NTSTATUS status;
+ UNICODE_STRING name;
+ PFILE_OBJECT fileObject;
+ PDEVICE_OBJECT deviceObject;
+
+ EnsureNullTerminatedString (request->DeviceName, sizeof (request->DeviceName));
+
+ RtlInitUnicodeString (&name, request->DeviceName);
+ status = IoGetDeviceObjectPointer (&name, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject);
+ if (!NT_SUCCESS (status))
+ {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = status;
+ break;
+ }
+
+ status = ProbeRealDriveSize (deviceObject, &request->RealDriveSize);
+ ObDereferenceObject (fileObject);
+
+ if (status == STATUS_TIMEOUT)
+ {
+ request->TimeOut = TRUE;
+ Irp->IoStatus.Information = sizeof (ProbeRealDriveSizeRequest);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ else if (!NT_SUCCESS (status))
+ {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = status;
+ }
+ else
+ {
+ request->TimeOut = FALSE;
+ Irp->IoStatus.Information = sizeof (ProbeRealDriveSizeRequest);
+ Irp->IoStatus.Status = status;
+ }
+ }
+ break;
+
+ case TC_IOCTL_MOUNT_VOLUME:
+ if (ValidateIOBufferSize (Irp, sizeof (MOUNT_STRUCT), ValidateInputOutput))
+ {
+ MOUNT_STRUCT *mount = (MOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
+
+ if (mount->VolumePassword.Length > MAX_PASSWORD || mount->ProtectedHidVolPassword.Length > MAX_PASSWORD
+ || mount->pkcs5_prf < 0 || mount->pkcs5_prf > LAST_PRF_ID
+ || mount->VolumePim < -1 || mount->VolumePim == INT_MAX
+ || mount->ProtectedHidVolPkcs5Prf < 0 || mount->ProtectedHidVolPkcs5Prf > LAST_PRF_ID
+ || (mount->bTrueCryptMode != FALSE && mount->bTrueCryptMode != TRUE)
+ )
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+ break;
+ }
+
+ EnsureNullTerminatedString (mount->wszVolume, sizeof (mount->wszVolume));
+ EnsureNullTerminatedString (mount->wszLabel, sizeof (mount->wszLabel));
+
+ Irp->IoStatus.Information = sizeof (MOUNT_STRUCT);
+ Irp->IoStatus.Status = MountDevice (DeviceObject, mount);
+
+ burn (&mount->VolumePassword, sizeof (mount->VolumePassword));
+ burn (&mount->ProtectedHidVolPassword, sizeof (mount->ProtectedHidVolPassword));
+ burn (&mount->pkcs5_prf, sizeof (mount->pkcs5_prf));
+ burn (&mount->VolumePim, sizeof (mount->VolumePim));
+ burn (&mount->bTrueCryptMode, sizeof (mount->bTrueCryptMode));
+ burn (&mount->ProtectedHidVolPkcs5Prf, sizeof (mount->ProtectedHidVolPkcs5Prf));
+ burn (&mount->ProtectedHidVolPim, sizeof (mount->ProtectedHidVolPim));
+ }
+ break;
+
+ case TC_IOCTL_DISMOUNT_VOLUME:
+ if (ValidateIOBufferSize (Irp, sizeof (UNMOUNT_STRUCT), ValidateInputOutput))
+ {
+ UNMOUNT_STRUCT *unmount = (UNMOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
+ PDEVICE_OBJECT ListDevice = GetVirtualVolumeDeviceObject (unmount->nDosDriveNo);
+
+ unmount->nReturnCode = ERR_DRIVE_NOT_FOUND;
+
+ if (ListDevice)
+ {
+ PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension;
+
+ if (IsVolumeAccessibleByCurrentUser (ListExtension))
+ unmount->nReturnCode = UnmountDevice (unmount, ListDevice, unmount->ignoreOpenFiles);
+ }
+
+ Irp->IoStatus.Information = sizeof (UNMOUNT_STRUCT);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ break;
+
+ case TC_IOCTL_DISMOUNT_ALL_VOLUMES:
+ if (ValidateIOBufferSize (Irp, sizeof (UNMOUNT_STRUCT), ValidateInputOutput))
+ {
+ UNMOUNT_STRUCT *unmount = (UNMOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
+
+ unmount->nReturnCode = UnmountAllDevices (unmount, unmount->ignoreOpenFiles);
+
+ Irp->IoStatus.Information = sizeof (UNMOUNT_STRUCT);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ break;
+
+ case TC_IOCTL_BOOT_ENCRYPTION_SETUP:
+ Irp->IoStatus.Status = StartBootEncryptionSetup (DeviceObject, Irp, irpSp);
+ Irp->IoStatus.Information = 0;
+ break;
+
+ case TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP:
+ Irp->IoStatus.Status = AbortBootEncryptionSetup();
+ Irp->IoStatus.Information = 0;
+ break;
+
+ case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS:
+ GetBootEncryptionStatus (Irp, irpSp);
+ break;
+
+ case TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT:
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = GetSetupResult();
+ break;
+
+ case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES:
+ GetBootDriveVolumeProperties (Irp, irpSp);
+ break;
+
+ case TC_IOCTL_GET_BOOT_LOADER_VERSION:
+ GetBootLoaderVersion (Irp, irpSp);
+ break;
+
+ case TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER:
+ ReopenBootVolumeHeader (Irp, irpSp);
+ break;
+
+ case VC_IOCTL_GET_BOOT_LOADER_FINGERPRINT:
+ GetBootLoaderFingerprint (Irp, irpSp);
+ break;
+
+ case TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME:
+ GetBootEncryptionAlgorithmName (Irp, irpSp);
+ break;
+
+ case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING:
+ if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput))
+ {
+ *(int *) Irp->AssociatedIrp.SystemBuffer = IsHiddenSystemRunning() ? 1 : 0;
+ Irp->IoStatus.Information = sizeof (int);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ break;
+
+ case TC_IOCTL_START_DECOY_SYSTEM_WIPE:
+ Irp->IoStatus.Status = StartDecoySystemWipe (DeviceObject, Irp, irpSp);
+ Irp->IoStatus.Information = 0;
+ break;
+
+ case TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE:
+ Irp->IoStatus.Status = AbortDecoySystemWipe();
+ Irp->IoStatus.Information = 0;
+ break;
+
+ case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT:
+ Irp->IoStatus.Status = GetDecoySystemWipeResult();
+ Irp->IoStatus.Information = 0;
+ break;
+
+ case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS:
+ GetDecoySystemWipeStatus (Irp, irpSp);
+ break;
+
+ case TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR:
+ Irp->IoStatus.Status = WriteBootDriveSector (Irp, irpSp);
+ Irp->IoStatus.Information = 0;
+ break;
+
+ case TC_IOCTL_GET_WARNING_FLAGS:
+ if (ValidateIOBufferSize (Irp, sizeof (GetWarningFlagsRequest), ValidateOutput))
+ {
+ GetWarningFlagsRequest *flags = (GetWarningFlagsRequest *) Irp->AssociatedIrp.SystemBuffer;
+
+ flags->PagingFileCreationPrevented = PagingFileCreationPrevented;
+ PagingFileCreationPrevented = FALSE;
+ flags->SystemFavoriteVolumeDirty = SystemFavoriteVolumeDirty;
+ SystemFavoriteVolumeDirty = FALSE;
+
+ Irp->IoStatus.Information = sizeof (GetWarningFlagsRequest);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ break;
+
+ case TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY:
+ if (UserCanAccessDriveDevice())
+ {
+ SystemFavoriteVolumeDirty = TRUE;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ else
+ Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
+
+ Irp->IoStatus.Information = 0;
+ break;
+
+ case TC_IOCTL_REREAD_DRIVER_CONFIG:
+ Irp->IoStatus.Status = ReadRegistryConfigFlags (FALSE);
+ Irp->IoStatus.Information = 0;
+ break;
+
+ case TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG:
+ if ( (ValidateIOBufferSize (Irp, sizeof (GetSystemDriveDumpConfigRequest), ValidateOutput))
+ && (Irp->RequestorMode == KernelMode)
+ )
+ {
+ GetSystemDriveDumpConfigRequest *request = (GetSystemDriveDumpConfigRequest *) Irp->AssociatedIrp.SystemBuffer;
+
+ request->BootDriveFilterExtension = GetBootDriveFilterExtension();
+ if (IsBootDriveMounted() && request->BootDriveFilterExtension)
+ {
+ request->HwEncryptionEnabled = IsHwEncryptionEnabled();
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof (*request);
+ }
+ else
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+ }
+ }
+ break;
+
+ default:
+ return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
+ }
+
+
+#ifdef DEBUG
+ if (!NT_SUCCESS (Irp->IoStatus.Status))
+ {
+ switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case TC_IOCTL_GET_MOUNTED_VOLUMES:
+ case TC_IOCTL_GET_PASSWORD_CACHE_STATUS:
+ case TC_IOCTL_GET_PORTABLE_MODE_STATUS:
+ case TC_IOCTL_SET_PORTABLE_MODE_STATUS:
+ case TC_IOCTL_OPEN_TEST:
+ case TC_IOCTL_GET_RESOLVED_SYMLINK:
+ case TC_IOCTL_GET_DRIVE_PARTITION_INFO:
+ case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES:
+ case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS:
+ case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING:
+ break;
+
+ default:
+ Dump ("IOCTL error 0x%08x\n", Irp->IoStatus.Status);
+ }
+ }
+#endif
+
+ return TCCompleteIrp (Irp, Irp->IoStatus.Status, Irp->IoStatus.Information);
+}
+
+
+NTSTATUS TCStartThread (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread)
+{
+ return TCStartThreadInProcess (threadProc, threadArg, kThread, NULL);
+}
+
+
+NTSTATUS TCStartThreadInProcess (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread, PEPROCESS process)
+{
+ NTSTATUS status;
+ HANDLE threadHandle;
+ HANDLE processHandle = NULL;
+ OBJECT_ATTRIBUTES threadObjAttributes;
+
+ if (process)
+ {
+ status = ObOpenObjectByPointer (process, OBJ_KERNEL_HANDLE, NULL, 0, NULL, KernelMode, &processHandle);
+ if (!NT_SUCCESS (status))
+ return status;
+ }
+
+ InitializeObjectAttributes (&threadObjAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ status = PsCreateSystemThread (&threadHandle, THREAD_ALL_ACCESS, &threadObjAttributes, processHandle, NULL, threadProc, threadArg);
+ if (!NT_SUCCESS (status))
+ return status;
+
+ status = ObReferenceObjectByHandle (threadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID *) kThread, NULL);
+ if (!NT_SUCCESS (status))
+ {
+ ZwClose (threadHandle);
+ *kThread = NULL;
+ return status;
+ }
+
+ if (processHandle)
+ ZwClose (processHandle);
+
+ ZwClose (threadHandle);
+ return STATUS_SUCCESS;
+}
+
+
+void TCStopThread (PKTHREAD kThread, PKEVENT wakeUpEvent)
+{
+ if (wakeUpEvent)
+ KeSetEvent (wakeUpEvent, 0, FALSE);
+
+ KeWaitForSingleObject (kThread, Executive, KernelMode, FALSE, NULL);
+ ObDereferenceObject (kThread);
+}
+
+
+NTSTATUS TCStartVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, MOUNT_STRUCT * mount)
+{
+ PTHREAD_BLOCK pThreadBlock = TCalloc (sizeof (THREAD_BLOCK));
+ HANDLE hThread;
+ NTSTATUS ntStatus;
+ OBJECT_ATTRIBUTES threadObjAttributes;
+ SECURITY_QUALITY_OF_SERVICE qos;
+
+ Dump ("Starting thread...\n");
+
+ if (pThreadBlock == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ pThreadBlock->DeviceObject = DeviceObject;
+ pThreadBlock->mount = mount;
+ }
+
+ qos.Length = sizeof (qos);
+ qos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
+ qos.EffectiveOnly = TRUE;
+ qos.ImpersonationLevel = SecurityImpersonation;
+
+ ntStatus = SeCreateClientSecurity (PsGetCurrentThread(), &qos, FALSE, &Extension->SecurityClientContext);
+ if (!NT_SUCCESS (ntStatus))
+ goto ret;
+
+ Extension->SecurityClientContextValid = TRUE;
+
+ Extension->bThreadShouldQuit = FALSE;
+
+ InitializeObjectAttributes (&threadObjAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ ntStatus = PsCreateSystemThread (&hThread,
+ THREAD_ALL_ACCESS,
+ &threadObjAttributes,
+ NULL,
+ NULL,
+ VolumeThreadProc,
+ pThreadBlock);
+
+ if (!NT_SUCCESS (ntStatus))
+ {
+ Dump ("PsCreateSystemThread Failed END\n");
+ goto ret;
+ }
+
+ ntStatus = ObReferenceObjectByHandle (hThread,
+ THREAD_ALL_ACCESS,
+ NULL,
+ KernelMode,
+ &Extension->peThread,
+ NULL);
+
+ ZwClose (hThread);
+
+ if (!NT_SUCCESS (ntStatus))
+ goto ret;
+
+ Dump ("Waiting for thread to initialize...\n");
+
+ KeWaitForSingleObject (&Extension->keCreateEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ Dump ("Waiting completed! Thread returns 0x%08x\n", pThreadBlock->ntCreateStatus);
+ ntStatus = pThreadBlock->ntCreateStatus;
+
+ret:
+ TCfree (pThreadBlock);
+ return ntStatus;
+}
+
+void TCStopVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
+{
+ NTSTATUS ntStatus;
+
+ UNREFERENCED_PARAMETER (DeviceObject); /* Remove compiler warning */
+
+ Dump ("Signalling thread to quit...\n");
+
+ Extension->bThreadShouldQuit = TRUE;
+
+ KeReleaseSemaphore (&Extension->RequestSemaphore,
+ 0,
+ 1,
+ TRUE);
+
+ ntStatus = KeWaitForSingleObject (Extension->peThread,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ ASSERT (NT_SUCCESS (ntStatus));
+
+ ObDereferenceObject (Extension->peThread);
+ Extension->peThread = NULL;
+
+ Dump ("Thread exited\n");
+}
+
+
+// Suspend current thread for a number of milliseconds
+void TCSleep (int milliSeconds)
+{
+ PKTIMER timer = (PKTIMER) TCalloc (sizeof (KTIMER));
+ LARGE_INTEGER duetime;
+
+ if (!timer)
+ return;
+
+ duetime.QuadPart = (__int64) milliSeconds * -10000;
+ KeInitializeTimerEx(timer, NotificationTimer);
+ KeSetTimerEx(timer, duetime, 0, NULL);
+
+ KeWaitForSingleObject (timer, Executive, KernelMode, FALSE, NULL);
+
+ TCfree (timer);
+}
+
+BOOL IsDeviceName(wchar_t wszVolume[TC_MAX_PATH])
+{
+ if ( (wszVolume[0] == '\\')
+ && (wszVolume[1] == 'D' || wszVolume[1] == 'd')
+ && (wszVolume[2] == 'E' || wszVolume[2] == 'e')
+ && (wszVolume[3] == 'V' || wszVolume[3] == 'v')
+ && (wszVolume[4] == 'I' || wszVolume[4] == 'i')
+ && (wszVolume[5] == 'C' || wszVolume[5] == 'c')
+ && (wszVolume[6] == 'E' || wszVolume[6] == 'e')
+ )
+ {
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+/* VolumeThreadProc does all the work of processing IRP's, and dispatching them
+ to either the ReadWrite function or the DeviceControl function */
+VOID VolumeThreadProc (PVOID Context)
+{
+ PTHREAD_BLOCK pThreadBlock = (PTHREAD_BLOCK) Context;
+ PDEVICE_OBJECT DeviceObject = pThreadBlock->DeviceObject;
+ PEXTENSION Extension = (PEXTENSION) DeviceObject->DeviceExtension;
+ BOOL bDevice;
+
+ /* Set thread priority to lowest realtime level. */
+ KeSetPriorityThread (KeGetCurrentThread (), LOW_REALTIME_PRIORITY);
+
+ Dump ("Mount THREAD OPENING VOLUME BEGIN\n");
+
+ if ( !IsDeviceName (pThreadBlock->mount->wszVolume))
+ {
+ RtlStringCbCopyW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),WIDE ("\\??\\"));
+ RtlStringCbCatW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),pThreadBlock->mount->wszVolume);
+ bDevice = FALSE;
+ }
+ else
+ {
+ pThreadBlock->wszMountVolume[0] = 0;
+ RtlStringCbCatW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),pThreadBlock->mount->wszVolume);
+ bDevice = TRUE;
+ }
+
+ Dump ("Mount THREAD request for File %ls DriveNumber %d Device = %d\n",
+ pThreadBlock->wszMountVolume, pThreadBlock->mount->nDosDriveNo, bDevice);
+
+ pThreadBlock->ntCreateStatus = TCOpenVolume (DeviceObject,
+ Extension,
+ pThreadBlock->mount,
+ pThreadBlock->wszMountVolume,
+ bDevice);
+
+ if (!NT_SUCCESS (pThreadBlock->ntCreateStatus) || pThreadBlock->mount->nReturnCode != 0)
+ {
+ KeSetEvent (&Extension->keCreateEvent, 0, FALSE);
+ PsTerminateSystemThread (STATUS_SUCCESS);
+ }
+
+ // Start IO queue
+ Extension->Queue.IsFilterDevice = FALSE;
+ Extension->Queue.DeviceObject = DeviceObject;
+ Extension->Queue.CryptoInfo = Extension->cryptoInfo;
+ Extension->Queue.HostFileHandle = Extension->hDeviceFile;
+ Extension->Queue.VirtualDeviceLength = Extension->DiskLength;
+ Extension->Queue.MaxReadAheadOffset.QuadPart = Extension->HostLength;
+
+ if (Extension->SecurityClientContextValid)
+ Extension->Queue.SecurityClientContext = &Extension->SecurityClientContext;
+ else
+ Extension->Queue.SecurityClientContext = NULL;
+
+ pThreadBlock->ntCreateStatus = EncryptedIoQueueStart (&Extension->Queue);
+
+ if (!NT_SUCCESS (pThreadBlock->ntCreateStatus))
+ {
+ TCCloseVolume (DeviceObject, Extension);
+
+ pThreadBlock->mount->nReturnCode = ERR_OS_ERROR;
+ KeSetEvent (&Extension->keCreateEvent, 0, FALSE);
+ PsTerminateSystemThread (STATUS_SUCCESS);
+ }
+
+ KeSetEvent (&Extension->keCreateEvent, 0, FALSE);
+ /* From this point on pThreadBlock cannot be used as it will have been released! */
+ pThreadBlock = NULL;
+
+ for (;;)
+ {
+ /* Wait for a request from the dispatch routines. */
+ KeWaitForSingleObject ((PVOID) & Extension->RequestSemaphore, Executive, KernelMode, FALSE, NULL);
+
+ for (;;)
+ {
+ PIO_STACK_LOCATION irpSp;
+ PLIST_ENTRY request;
+ PIRP irp;
+
+ request = ExInterlockedRemoveHeadList (&Extension->ListEntry, &Extension->ListSpinLock);
+ if (request == NULL)
+ break;
+
+ irp = CONTAINING_RECORD (request, IRP, Tail.Overlay.ListEntry);
+ irpSp = IoGetCurrentIrpStackLocation (irp);
+
+ ASSERT (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
+
+ ProcessVolumeDeviceControlIrp (DeviceObject, Extension, irp);
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, irp);
+ }
+
+ if (Extension->bThreadShouldQuit)
+ {
+ Dump ("Closing volume\n");
+ EncryptedIoQueueStop (&Extension->Queue);
+
+ TCCloseVolume (DeviceObject, Extension);
+ PsTerminateSystemThread (STATUS_SUCCESS);
+ }
+ }
+}
+
+void TCGetNTNameFromNumber (LPWSTR ntname, int cbNtName, int nDriveNo)
+{
+ WCHAR tmp[2] =
+ {0, 0};
+ int j = nDriveNo + (WCHAR) 'A';
+
+ tmp[0] = (short) j;
+ RtlStringCbCopyW (ntname, cbNtName,(LPWSTR) NT_MOUNT_PREFIX);
+ RtlStringCbCatW (ntname, cbNtName, tmp);
+}
+
+void TCGetDosNameFromNumber (LPWSTR dosname,int cbDosName, int nDriveNo, DeviceNamespaceType namespaceType)
+{
+ WCHAR tmp[3] =
+ {0, ':', 0};
+ int j = nDriveNo + (WCHAR) 'A';
+
+ tmp[0] = (short) j;
+
+ if (DeviceNamespaceGlobal == namespaceType)
+ {
+ RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX_GLOBAL);
+ }
+ else
+ {
+ RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX_DEFAULT);
+ }
+
+ RtlStringCbCatW (dosname, cbDosName, tmp);
+}
+
+#ifdef _DEBUG
+LPWSTR TCTranslateCode (ULONG ulCode)
+{
+ switch (ulCode)
+ {
+#define TC_CASE_RET_NAME(CODE) case CODE : return L###CODE
+
+ TC_CASE_RET_NAME (TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP);
+ TC_CASE_RET_NAME (TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE);
+ TC_CASE_RET_NAME (TC_IOCTL_BOOT_ENCRYPTION_SETUP);
+ TC_CASE_RET_NAME (TC_IOCTL_DISMOUNT_ALL_VOLUMES);
+ TC_CASE_RET_NAME (TC_IOCTL_DISMOUNT_VOLUME);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_LOADER_VERSION);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_DEVICE_REFCOUNT);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVE_GEOMETRY);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVE_PARTITION_INFO);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVER_VERSION);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_MOUNTED_VOLUMES);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_PASSWORD_CACHE_STATUS);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_PORTABLE_MODE_STATUS);
+ TC_CASE_RET_NAME (TC_IOCTL_SET_PORTABLE_MODE_STATUS);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_RESOLVED_SYMLINK);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_VOLUME_PROPERTIES);
+ TC_CASE_RET_NAME (TC_IOCTL_GET_WARNING_FLAGS);
+ TC_CASE_RET_NAME (TC_IOCTL_DISK_IS_WRITABLE);
+ TC_CASE_RET_NAME (TC_IOCTL_IS_ANY_VOLUME_MOUNTED);
+ TC_CASE_RET_NAME (TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED);
+ TC_CASE_RET_NAME (TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING);
+ TC_CASE_RET_NAME (TC_IOCTL_MOUNT_VOLUME);
+ TC_CASE_RET_NAME (TC_IOCTL_OPEN_TEST);
+ TC_CASE_RET_NAME (TC_IOCTL_PROBE_REAL_DRIVE_SIZE);
+ TC_CASE_RET_NAME (TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER);
+ TC_CASE_RET_NAME (TC_IOCTL_REREAD_DRIVER_CONFIG);
+ TC_CASE_RET_NAME (TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY);
+ TC_CASE_RET_NAME (TC_IOCTL_START_DECOY_SYSTEM_WIPE);
+ TC_CASE_RET_NAME (TC_IOCTL_WIPE_PASSWORD_CACHE);
+ TC_CASE_RET_NAME (TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR);
+
+ TC_CASE_RET_NAME (IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS);
+
+#undef TC_CASE_RET_NAME
+ }
+
+ if (ulCode == IOCTL_DISK_GET_DRIVE_GEOMETRY)
+ return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_GEOMETRY");
+ else if (ulCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX)
+ return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX");
+ else if (ulCode == IOCTL_MOUNTDEV_QUERY_DEVICE_NAME)
+ return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME");
+ else if (ulCode == IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME)
+ return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME");
+ else if (ulCode == IOCTL_MOUNTDEV_QUERY_UNIQUE_ID)
+ return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_UNIQUE_ID");
+ else if (ulCode == IOCTL_VOLUME_ONLINE)
+ return (LPWSTR) _T ("IOCTL_VOLUME_ONLINE");
+ else if (ulCode == IOCTL_MOUNTDEV_LINK_CREATED)
+ return (LPWSTR) _T ("IOCTL_MOUNTDEV_LINK_CREATED");
+ else if (ulCode == IOCTL_MOUNTDEV_LINK_DELETED)
+ return (LPWSTR) _T ("IOCTL_MOUNTDEV_LINK_DELETED");
+ else if (ulCode == IOCTL_MOUNTMGR_QUERY_POINTS)
+ return (LPWSTR) _T ("IOCTL_MOUNTMGR_QUERY_POINTS");
+ else if (ulCode == IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED)
+ return (LPWSTR) _T ("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED");
+ else if (ulCode == IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED)
+ return (LPWSTR) _T ("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED");
+ else if (ulCode == IOCTL_DISK_GET_LENGTH_INFO)
+ return (LPWSTR) _T ("IOCTL_DISK_GET_LENGTH_INFO");
+ else if (ulCode == IOCTL_STORAGE_GET_DEVICE_NUMBER)
+ return (LPWSTR) _T ("IOCTL_STORAGE_GET_DEVICE_NUMBER");
+ else if (ulCode == IOCTL_DISK_GET_PARTITION_INFO)
+ return (LPWSTR) _T ("IOCTL_DISK_GET_PARTITION_INFO");
+ else if (ulCode == IOCTL_DISK_GET_PARTITION_INFO_EX)
+ return (LPWSTR) _T ("IOCTL_DISK_GET_PARTITION_INFO_EX");
+ else if (ulCode == IOCTL_DISK_SET_PARTITION_INFO)
+ return (LPWSTR) _T ("IOCTL_DISK_SET_PARTITION_INFO");
+ else if (ulCode == IOCTL_DISK_GET_DRIVE_LAYOUT)
+ return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_LAYOUT");
+ else if (ulCode == IOCTL_DISK_SET_DRIVE_LAYOUT_EX)
+ return (LPWSTR) _T ("IOCTL_DISK_SET_DRIVE_LAYOUT_EX");
+ else if (ulCode == IOCTL_DISK_VERIFY)
+ return (LPWSTR) _T ("IOCTL_DISK_VERIFY");
+ else if (ulCode == IOCTL_DISK_FORMAT_TRACKS)
+ return (LPWSTR) _T ("IOCTL_DISK_FORMAT_TRACKS");
+ else if (ulCode == IOCTL_DISK_REASSIGN_BLOCKS)
+ return (LPWSTR) _T ("IOCTL_DISK_REASSIGN_BLOCKS");
+ else if (ulCode == IOCTL_DISK_PERFORMANCE)
+ return (LPWSTR) _T ("IOCTL_DISK_PERFORMANCE");
+ else if (ulCode == IOCTL_DISK_IS_WRITABLE)
+ return (LPWSTR) _T ("IOCTL_DISK_IS_WRITABLE");
+ else if (ulCode == IOCTL_DISK_LOGGING)
+ return (LPWSTR) _T ("IOCTL_DISK_LOGGING");
+ else if (ulCode == IOCTL_DISK_FORMAT_TRACKS_EX)
+ return (LPWSTR) _T ("IOCTL_DISK_FORMAT_TRACKS_EX");
+ else if (ulCode == IOCTL_DISK_HISTOGRAM_STRUCTURE)
+ return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_STRUCTURE");
+ else if (ulCode == IOCTL_DISK_HISTOGRAM_DATA)
+ return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_DATA");
+ else if (ulCode == IOCTL_DISK_HISTOGRAM_RESET)
+ return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_RESET");
+ else if (ulCode == IOCTL_DISK_REQUEST_STRUCTURE)
+ return (LPWSTR) _T ("IOCTL_DISK_REQUEST_STRUCTURE");
+ else if (ulCode == IOCTL_DISK_REQUEST_DATA)
+ return (LPWSTR) _T ("IOCTL_DISK_REQUEST_DATA");
+ else if (ulCode == IOCTL_DISK_CONTROLLER_NUMBER)
+ return (LPWSTR) _T ("IOCTL_DISK_CONTROLLER_NUMBER");
+ else if (ulCode == SMART_GET_VERSION)
+ return (LPWSTR) _T ("SMART_GET_VERSION");
+ else if (ulCode == SMART_SEND_DRIVE_COMMAND)
+ return (LPWSTR) _T ("SMART_SEND_DRIVE_COMMAND");
+ else if (ulCode == SMART_RCV_DRIVE_DATA)
+ return (LPWSTR) _T ("SMART_RCV_DRIVE_DATA");
+ else if (ulCode == IOCTL_DISK_INTERNAL_SET_VERIFY)
+ return (LPWSTR) _T ("IOCTL_DISK_INTERNAL_SET_VERIFY");
+ else if (ulCode == IOCTL_DISK_INTERNAL_CLEAR_VERIFY)
+ return (LPWSTR) _T ("IOCTL_DISK_INTERNAL_CLEAR_VERIFY");
+ else if (ulCode == IOCTL_DISK_CHECK_VERIFY)
+ return (LPWSTR) _T ("IOCTL_DISK_CHECK_VERIFY");
+ else if (ulCode == IOCTL_DISK_MEDIA_REMOVAL)
+ return (LPWSTR) _T ("IOCTL_DISK_MEDIA_REMOVAL");
+ else if (ulCode == IOCTL_DISK_EJECT_MEDIA)
+ return (LPWSTR) _T ("IOCTL_DISK_EJECT_MEDIA");
+ else if (ulCode == IOCTL_DISK_LOAD_MEDIA)
+ return (LPWSTR) _T ("IOCTL_DISK_LOAD_MEDIA");
+ else if (ulCode == IOCTL_DISK_RESERVE)
+ return (LPWSTR) _T ("IOCTL_DISK_RESERVE");
+ else if (ulCode == IOCTL_DISK_RELEASE)
+ return (LPWSTR) _T ("IOCTL_DISK_RELEASE");
+ else if (ulCode == IOCTL_DISK_FIND_NEW_DEVICES)
+ return (LPWSTR) _T ("IOCTL_DISK_FIND_NEW_DEVICES");
+ else if (ulCode == IOCTL_DISK_GET_MEDIA_TYPES)
+ return (LPWSTR) _T ("IOCTL_DISK_GET_MEDIA_TYPES");
+ else if (ulCode == IOCTL_STORAGE_SET_HOTPLUG_INFO)
+ return (LPWSTR) _T ("IOCTL_STORAGE_SET_HOTPLUG_INFO");
+ else if (ulCode == IRP_MJ_READ)
+ return (LPWSTR) _T ("IRP_MJ_READ");
+ else if (ulCode == IRP_MJ_WRITE)
+ return (LPWSTR) _T ("IRP_MJ_WRITE");
+ else if (ulCode == IRP_MJ_CREATE)
+ return (LPWSTR) _T ("IRP_MJ_CREATE");
+ else if (ulCode == IRP_MJ_CLOSE)
+ return (LPWSTR) _T ("IRP_MJ_CLOSE");
+ else if (ulCode == IRP_MJ_CLEANUP)
+ return (LPWSTR) _T ("IRP_MJ_CLEANUP");
+ else if (ulCode == IRP_MJ_FLUSH_BUFFERS)
+ return (LPWSTR) _T ("IRP_MJ_FLUSH_BUFFERS");
+ else if (ulCode == IRP_MJ_SHUTDOWN)
+ return (LPWSTR) _T ("IRP_MJ_SHUTDOWN");
+ else if (ulCode == IRP_MJ_DEVICE_CONTROL)
+ return (LPWSTR) _T ("IRP_MJ_DEVICE_CONTROL");
+ else
+ {
+ return (LPWSTR) _T ("IOCTL");
+ }
+}
+
+#endif
+
+void TCDeleteDeviceObject (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
+{
+ UNICODE_STRING Win32NameString;
+ NTSTATUS ntStatus;
+
+ Dump ("TCDeleteDeviceObject BEGIN\n");
+
+ if (Extension->bRootDevice)
+ {
+ RtlInitUnicodeString (&Win32NameString, (LPWSTR) DOS_ROOT_PREFIX);
+ ntStatus = IoDeleteSymbolicLink (&Win32NameString);
+ if (!NT_SUCCESS (ntStatus))
+ Dump ("IoDeleteSymbolicLink failed ntStatus = 0x%08x\n", ntStatus);
+
+ RootDeviceObject = NULL;
+ }
+ else
+ {
+ if (Extension->peThread != NULL)
+ TCStopVolumeThread (DeviceObject, Extension);
+
+ if (Extension->UserSid)
+ TCfree (Extension->UserSid);
+
+ if (Extension->SecurityClientContextValid)
+ {
+ if (OsMajorVersion == 5 && OsMinorVersion == 0)
+ {
+ ObDereferenceObject (Extension->SecurityClientContext.ClientToken);
+ }
+ else
+ {
+ // Windows 2000 does not support PsDereferenceImpersonationToken() used by SeDeleteClientSecurity().
+ // TODO: Use only SeDeleteClientSecurity() once support for Windows 2000 is dropped.
+
+ VOID (*PsDereferenceImpersonationTokenD) (PACCESS_TOKEN ImpersonationToken);
+ UNICODE_STRING name;
+ RtlInitUnicodeString (&name, L"PsDereferenceImpersonationToken");
+
+ PsDereferenceImpersonationTokenD = MmGetSystemRoutineAddress (&name);
+ if (!PsDereferenceImpersonationTokenD)
+ TC_BUG_CHECK (STATUS_NOT_IMPLEMENTED);
+
+# define PsDereferencePrimaryToken
+# define PsDereferenceImpersonationToken PsDereferenceImpersonationTokenD
+
+ SeDeleteClientSecurity (&Extension->SecurityClientContext);
+
+# undef PsDereferencePrimaryToken
+# undef PsDereferenceImpersonationToken
+ }
+ }
+
+ VirtualVolumeDeviceObjects[Extension->nDosDriveNo] = NULL;
+ }
+
+ IoDeleteDevice (DeviceObject);
+
+ Dump ("TCDeleteDeviceObject END\n");
+}
+
+
+VOID TCUnloadDriver (PDRIVER_OBJECT DriverObject)
+{
+ Dump ("TCUnloadDriver BEGIN\n");
+
+ OnShutdownPending();
+
+ if (IsBootDriveMounted())
+ TC_BUG_CHECK (STATUS_INVALID_DEVICE_STATE);
+
+ EncryptionThreadPoolStop();
+ TCDeleteDeviceObject (RootDeviceObject, (PEXTENSION) RootDeviceObject->DeviceExtension);
+
+ Dump ("TCUnloadDriver END\n");
+}
+
+
+void OnShutdownPending ()
+{
+ UNMOUNT_STRUCT unmount;
+ memset (&unmount, 0, sizeof (unmount));
+ unmount.ignoreOpenFiles = TRUE;
+
+ while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_DISMOUNT_ALL_VOLUMES, &unmount, sizeof (unmount), &unmount, sizeof (unmount)) == STATUS_INSUFFICIENT_RESOURCES || unmount.HiddenVolumeProtectionTriggered)
+ unmount.HiddenVolumeProtectionTriggered = FALSE;
+
+ while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_WIPE_PASSWORD_CACHE, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES);
+}
+
+
+NTSTATUS TCDeviceIoControl (PWSTR deviceName, ULONG IoControlCode, void *InputBuffer, ULONG InputBufferSize, void *OutputBuffer, ULONG OutputBufferSize)
+{
+ IO_STATUS_BLOCK ioStatusBlock;
+ NTSTATUS ntStatus;
+ PIRP irp;
+ PFILE_OBJECT fileObject;
+ PDEVICE_OBJECT deviceObject;
+ KEVENT event;
+ UNICODE_STRING name;
+
+ RtlInitUnicodeString(&name, deviceName);
+ ntStatus = IoGetDeviceObjectPointer (&name, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject);
+
+ if (!NT_SUCCESS (ntStatus))
+ return ntStatus;
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+ irp = IoBuildDeviceIoControlRequest (IoControlCode,
+ deviceObject,
+ InputBuffer, InputBufferSize,
+ OutputBuffer, OutputBufferSize,
+ FALSE,
+ &event,
+ &ioStatusBlock);
+
+ if (irp == NULL)
+ {
+ Dump ("IRP allocation failed\n");
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto ret;
+ }
+
+ IoGetNextIrpStackLocation (irp)->FileObject = fileObject;
+
+ ntStatus = IoCallDriver (deviceObject, irp);
+ if (ntStatus == STATUS_PENDING)
+ {
+ KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
+ ntStatus = ioStatusBlock.Status;
+ }
+
+ret:
+ ObDereferenceObject (fileObject);
+ return ntStatus;
+}
+
+
+typedef struct
+{
+ PDEVICE_OBJECT deviceObject; ULONG ioControlCode; void *inputBuffer; int inputBufferSize; void *outputBuffer; int outputBufferSize;
+ NTSTATUS Status;
+ KEVENT WorkItemCompletedEvent;
+} SendDeviceIoControlRequestWorkItemArgs;
+
+
+static VOID SendDeviceIoControlRequestWorkItemRoutine (PDEVICE_OBJECT rootDeviceObject, SendDeviceIoControlRequestWorkItemArgs *arg)
+{
+ arg->Status = SendDeviceIoControlRequest (arg->deviceObject, arg->ioControlCode, arg->inputBuffer, arg->inputBufferSize, arg->outputBuffer, arg->outputBufferSize);
+ KeSetEvent (&arg->WorkItemCompletedEvent, IO_NO_INCREMENT, FALSE);
+}
+
+
+NTSTATUS SendDeviceIoControlRequest (PDEVICE_OBJECT deviceObject, ULONG ioControlCode, void *inputBuffer, int inputBufferSize, void *outputBuffer, int outputBufferSize)
+{
+ IO_STATUS_BLOCK ioStatusBlock;
+ NTSTATUS status;
+ PIRP irp;
+ KEVENT event;
+
+ if (KeGetCurrentIrql() > APC_LEVEL)
+ {
+ SendDeviceIoControlRequestWorkItemArgs args;
+
+ PIO_WORKITEM workItem = IoAllocateWorkItem (RootDeviceObject);
+ if (!workItem)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ args.deviceObject = deviceObject;
+ args.ioControlCode = ioControlCode;
+ args.inputBuffer = inputBuffer;
+ args.inputBufferSize = inputBufferSize;
+ args.outputBuffer = outputBuffer;
+ args.outputBufferSize = outputBufferSize;
+
+ KeInitializeEvent (&args.WorkItemCompletedEvent, SynchronizationEvent, FALSE);
+ IoQueueWorkItem (workItem, SendDeviceIoControlRequestWorkItemRoutine, DelayedWorkQueue, &args);
+
+ KeWaitForSingleObject (&args.WorkItemCompletedEvent, Executive, KernelMode, FALSE, NULL);
+ IoFreeWorkItem (workItem);
+
+ return args.Status;
+ }
+
+ KeInitializeEvent (&event, NotificationEvent, FALSE);
+
+ irp = IoBuildDeviceIoControlRequest (ioControlCode, deviceObject, inputBuffer, inputBufferSize,
+ outputBuffer, outputBufferSize, FALSE, &event, &ioStatusBlock);
+
+ if (!irp)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ ObReferenceObject (deviceObject);
+
+ status = IoCallDriver (deviceObject, irp);
+ if (status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
+ status = ioStatusBlock.Status;
+ }
+
+ ObDereferenceObject (deviceObject);
+ return status;
+}
+
+
+NTSTATUS ProbeRealDriveSize (PDEVICE_OBJECT driveDeviceObject, LARGE_INTEGER *driveSize)
+{
+ NTSTATUS status;
+ LARGE_INTEGER sysLength;
+ LARGE_INTEGER offset;
+ byte *sectorBuffer;
+ ULONGLONG startTime;
+
+ if (!UserCanAccessDriveDevice())
+ return STATUS_ACCESS_DENIED;
+
+ sectorBuffer = TCalloc (TC_SECTOR_SIZE_BIOS);
+ if (!sectorBuffer)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ status = SendDeviceIoControlRequest (driveDeviceObject, IOCTL_DISK_GET_LENGTH_INFO,
+ NULL, 0, &sysLength, sizeof (sysLength));
+
+ if (!NT_SUCCESS (status))
+ {
+ Dump ("Failed to get drive size - error %x\n", status);
+ TCfree (sectorBuffer);
+ return status;
+ }
+
+ startTime = KeQueryInterruptTime ();
+ for (offset.QuadPart = sysLength.QuadPart; ; offset.QuadPart += TC_SECTOR_SIZE_BIOS)
+ {
+ status = TCReadDevice (driveDeviceObject, sectorBuffer, offset, TC_SECTOR_SIZE_BIOS);
+
+ if (NT_SUCCESS (status))
+ status = TCWriteDevice (driveDeviceObject, sectorBuffer, offset, TC_SECTOR_SIZE_BIOS);
+
+ if (!NT_SUCCESS (status))
+ {
+ driveSize->QuadPart = offset.QuadPart;
+ Dump ("Real drive size = %I64d bytes (%I64d hidden)\n", driveSize->QuadPart, driveSize->QuadPart - sysLength.QuadPart);
+ TCfree (sectorBuffer);
+ return STATUS_SUCCESS;
+ }
+
+ if (KeQueryInterruptTime() - startTime > 3ULL * 60 * 1000 * 1000 * 10)
+ {
+ // Abort if probing for more than 3 minutes
+ driveSize->QuadPart = sysLength.QuadPart;
+ TCfree (sectorBuffer);
+ return STATUS_TIMEOUT;
+ }
+ }
+}
+
+
+NTSTATUS TCOpenFsVolume (PEXTENSION Extension, PHANDLE volumeHandle, PFILE_OBJECT * fileObject)
+{
+ NTSTATUS ntStatus;
+ OBJECT_ATTRIBUTES objectAttributes;
+ UNICODE_STRING fullFileName;
+ IO_STATUS_BLOCK ioStatus;
+ WCHAR volumeName[TC_MAX_PATH];
+
+ TCGetNTNameFromNumber (volumeName, sizeof(volumeName),Extension->nDosDriveNo);
+ RtlInitUnicodeString (&fullFileName, volumeName);
+ InitializeObjectAttributes (&objectAttributes, &fullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ ntStatus = ZwCreateFile (volumeHandle,
+ SYNCHRONIZE | GENERIC_READ,
+ &objectAttributes,
+ &ioStatus,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0);
+
+ Dump ("Volume %ls open NTSTATUS 0x%08x\n", volumeName, ntStatus);
+
+ if (!NT_SUCCESS (ntStatus))
+ return ntStatus;
+
+ ntStatus = ObReferenceObjectByHandle (*volumeHandle,
+ FILE_READ_DATA,
+ NULL,
+ KernelMode,
+ fileObject,
+ NULL);
+
+ if (!NT_SUCCESS (ntStatus))
+ ZwClose (*volumeHandle);
+
+ return ntStatus;
+}
+
+
+void TCCloseFsVolume (HANDLE volumeHandle, PFILE_OBJECT fileObject)
+{
+ ObDereferenceObject (fileObject);
+ ZwClose (volumeHandle);
+}
+
+
+static NTSTATUS TCReadWriteDevice (BOOL write, PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length)
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP irp;
+ KEVENT completionEvent;
+
+ ASSERT (KeGetCurrentIrql() <= APC_LEVEL);
+
+ KeInitializeEvent (&completionEvent, NotificationEvent, FALSE);
+ irp = IoBuildSynchronousFsdRequest (write ? IRP_MJ_WRITE : IRP_MJ_READ, deviceObject, buffer, length, &offset, &completionEvent, &ioStatusBlock);
+ if (!irp)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ ObReferenceObject (deviceObject);
+ status = IoCallDriver (deviceObject, irp);
+
+ if (status == STATUS_PENDING)
+ {
+ status = KeWaitForSingleObject (&completionEvent, Executive, KernelMode, FALSE, NULL);
+ if (NT_SUCCESS (status))
+ status = ioStatusBlock.Status;
+ }
+
+ ObDereferenceObject (deviceObject);
+ return status;
+}
+
+
+NTSTATUS TCReadDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length)
+{
+ return TCReadWriteDevice (FALSE, deviceObject, buffer, offset, length);
+}
+
+
+NTSTATUS TCWriteDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length)
+{
+ return TCReadWriteDevice (TRUE, deviceObject, buffer, offset, length);
+}
+
+
+NTSTATUS TCFsctlCall (PFILE_OBJECT fileObject, LONG IoControlCode,
+ void *InputBuffer, int InputBufferSize, void *OutputBuffer, int OutputBufferSize)
+{
+ IO_STATUS_BLOCK ioStatusBlock;
+ NTSTATUS ntStatus;
+ PIRP irp;
+ KEVENT event;
+ PIO_STACK_LOCATION stack;
+ PDEVICE_OBJECT deviceObject = IoGetRelatedDeviceObject (fileObject);
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+ irp = IoBuildDeviceIoControlRequest (IoControlCode,
+ deviceObject,
+ InputBuffer, InputBufferSize,
+ OutputBuffer, OutputBufferSize,
+ FALSE,
+ &event,
+ &ioStatusBlock);
+
+ if (irp == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ stack = IoGetNextIrpStackLocation(irp);
+
+ stack->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
+ stack->MinorFunction = IRP_MN_USER_FS_REQUEST;
+ stack->FileObject = fileObject;
+
+ ntStatus = IoCallDriver (deviceObject, irp);
+ if (ntStatus == STATUS_PENDING)
+ {
+ KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
+ ntStatus = ioStatusBlock.Status;
+ }
+
+ return ntStatus;
+}
+
+
+NTSTATUS CreateDriveLink (int nDosDriveNo)
+{
+ WCHAR dev[128], link[128];
+ UNICODE_STRING deviceName, symLink;
+ NTSTATUS ntStatus;
+
+ TCGetNTNameFromNumber (dev, sizeof(dev),nDosDriveNo);
+ TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault);
+
+ RtlInitUnicodeString (&deviceName, dev);
+ RtlInitUnicodeString (&symLink, link);
+
+ ntStatus = IoCreateSymbolicLink (&symLink, &deviceName);
+ Dump ("IoCreateSymbolicLink returned %X\n", ntStatus);
+ return ntStatus;
+}
+
+
+NTSTATUS RemoveDriveLink (int nDosDriveNo)
+{
+ WCHAR link[256];
+ UNICODE_STRING symLink;
+ NTSTATUS ntStatus;
+
+ TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault);
+ RtlInitUnicodeString (&symLink, link);
+
+ ntStatus = IoDeleteSymbolicLink (&symLink);
+ Dump ("IoDeleteSymbolicLink returned %X\n", ntStatus);
+ return ntStatus;
+}
+
+
+NTSTATUS MountManagerMount (MOUNT_STRUCT *mount)
+{
+ NTSTATUS ntStatus;
+ WCHAR arrVolume[256];
+ char buf[200];
+ PMOUNTMGR_TARGET_NAME in = (PMOUNTMGR_TARGET_NAME) buf;
+ PMOUNTMGR_CREATE_POINT_INPUT point = (PMOUNTMGR_CREATE_POINT_INPUT) buf;
+
+ TCGetNTNameFromNumber (arrVolume, sizeof(arrVolume),mount->nDosDriveNo);
+ in->DeviceNameLength = (USHORT) wcslen (arrVolume) * 2;
+ RtlStringCbCopyW(in->DeviceName, sizeof(buf) - sizeof(in->DeviceNameLength),arrVolume);
+
+ ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
+ in, (ULONG) (sizeof (in->DeviceNameLength) + wcslen (arrVolume) * 2), 0, 0);
+
+ memset (buf, 0, sizeof buf);
+ TCGetDosNameFromNumber ((PWSTR) &point[1], sizeof(buf) - sizeof(MOUNTMGR_CREATE_POINT_INPUT),mount->nDosDriveNo, DeviceNamespaceDefault);
+
+ point->SymbolicLinkNameOffset = sizeof (MOUNTMGR_CREATE_POINT_INPUT);
+ point->SymbolicLinkNameLength = (USHORT) wcslen ((PWSTR) &point[1]) * 2;
+
+ point->DeviceNameOffset = point->SymbolicLinkNameOffset + point->SymbolicLinkNameLength;
+ TCGetNTNameFromNumber ((PWSTR) (buf + point->DeviceNameOffset), sizeof(buf) - point->DeviceNameOffset,mount->nDosDriveNo);
+ point->DeviceNameLength = (USHORT) wcslen ((PWSTR) (buf + point->DeviceNameOffset)) * 2;
+
+ ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_CREATE_POINT, point,
+ point->DeviceNameOffset + point->DeviceNameLength, 0, 0);
+
+ return ntStatus;
+}
+
+
+NTSTATUS MountManagerUnmount (int nDosDriveNo)
+{
+ NTSTATUS ntStatus;
+ char buf[256], out[300];
+ PMOUNTMGR_MOUNT_POINT in = (PMOUNTMGR_MOUNT_POINT) buf;
+
+ memset (buf, 0, sizeof buf);
+
+ TCGetDosNameFromNumber ((PWSTR) &in[1], sizeof(buf) - sizeof(MOUNTMGR_MOUNT_POINT),nDosDriveNo, DeviceNamespaceDefault);
+
+ // Only symbolic link can be deleted with IOCTL_MOUNTMGR_DELETE_POINTS. If any other entry is specified, the mount manager will ignore subsequent IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION for the same volume ID.
+ in->SymbolicLinkNameOffset = sizeof (MOUNTMGR_MOUNT_POINT);
+ in->SymbolicLinkNameLength = (USHORT) wcslen ((PWCHAR) &in[1]) * 2;
+
+ ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_DELETE_POINTS,
+ in, sizeof(MOUNTMGR_MOUNT_POINT) + in->SymbolicLinkNameLength, out, sizeof out);
+
+ Dump ("IOCTL_MOUNTMGR_DELETE_POINTS returned 0x%08x\n", ntStatus);
+
+ return ntStatus;
+}
+
+
+NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount)
+{
+ PDEVICE_OBJECT NewDeviceObject;
+ NTSTATUS ntStatus;
+
+ // Make sure the user is asking for a reasonable nDosDriveNo
+ if (mount->nDosDriveNo >= 0 && mount->nDosDriveNo <= 25
+ && IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceDefault) // drive letter must not exist both locally and globally
+ && IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceGlobal)
+ )
+ {
+ Dump ("Mount request looks valid\n");
+ }
+ else
+ {
+ Dump ("WARNING: MOUNT DRIVE LETTER INVALID\n");
+ mount->nReturnCode = ERR_DRIVE_NOT_FOUND;
+ return ERR_DRIVE_NOT_FOUND;
+ }
+
+ if (!SelfTestsPassed)
+ {
+ mount->nReturnCode = ERR_SELF_TESTS_FAILED;
+ return ERR_SELF_TESTS_FAILED;
+ }
+
+ ntStatus = TCCreateDeviceObject (DeviceObject->DriverObject, &NewDeviceObject, mount);
+
+ if (!NT_SUCCESS (ntStatus))
+ {
+ Dump ("Mount CREATE DEVICE ERROR, ntStatus = 0x%08x\n", ntStatus);
+ return ntStatus;
+ }
+ else
+ {
+ PEXTENSION NewExtension = (PEXTENSION) NewDeviceObject->DeviceExtension;
+ SECURITY_SUBJECT_CONTEXT subContext;
+ PACCESS_TOKEN accessToken;
+
+ SeCaptureSubjectContext (&subContext);
+ SeLockSubjectContext(&subContext);
+ if (subContext.ClientToken && subContext.ImpersonationLevel >= SecurityImpersonation)
+ accessToken = subContext.ClientToken;
+ else
+ accessToken = subContext.PrimaryToken;
+
+ if (!accessToken)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ PTOKEN_USER tokenUser;
+
+ ntStatus = SeQueryInformationToken (accessToken, TokenUser, &tokenUser);
+ if (NT_SUCCESS (ntStatus))
+ {
+ ULONG sidLength = RtlLengthSid (tokenUser->User.Sid);
+
+ NewExtension->UserSid = TCalloc (sidLength);
+ if (!NewExtension->UserSid)
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ else
+ ntStatus = RtlCopySid (sidLength, NewExtension->UserSid, tokenUser->User.Sid);
+
+ ExFreePool (tokenUser); // Documented in newer versions of WDK
+ }
+ }
+
+ SeUnlockSubjectContext(&subContext);
+ SeReleaseSubjectContext (&subContext);
+
+ if (NT_SUCCESS (ntStatus))
+ ntStatus = TCStartVolumeThread (NewDeviceObject, NewExtension, mount);
+
+ if (!NT_SUCCESS (ntStatus))
+ {
+ Dump ("Mount FAILURE NT ERROR, ntStatus = 0x%08x\n", ntStatus);
+ TCDeleteDeviceObject (NewDeviceObject, NewExtension);
+ return ntStatus;
+ }
+ else
+ {
+ if (mount->nReturnCode == 0)
+ {
+ HANDLE volumeHandle;
+ PFILE_OBJECT volumeFileObject;
+ ULONG labelLen = (ULONG) wcslen (mount->wszLabel);
+ BOOL bIsNTFS = FALSE;
+ ULONG labelMaxLen, labelEffectiveLen;
+
+ Dump ("Mount SUCCESS TC code = 0x%08x READ-ONLY = %d\n", mount->nReturnCode, NewExtension->bReadOnly);
+
+ if (NewExtension->bReadOnly)
+ NewDeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
+
+ NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ NewExtension->UniqueVolumeId = LastUniqueVolumeId++;
+
+ // check again that the drive letter is available globally and locally
+ if ( !IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceDefault)
+ || !IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceGlobal)
+ )
+ {
+ TCDeleteDeviceObject (NewDeviceObject, NewExtension);
+ mount->nReturnCode = ERR_DRIVE_NOT_FOUND;
+ return ERR_DRIVE_NOT_FOUND;
+ }
+
+ if (mount->bMountManager)
+ MountManagerMount (mount);
+
+ NewExtension->bMountManager = mount->bMountManager;
+
+ // We create symbolic link even if mount manager is notified of
+ // arriving volume as it apparently sometimes fails to create the link
+ CreateDriveLink (mount->nDosDriveNo);
+
+ mount->FilesystemDirty = FALSE;
+
+ if (NT_SUCCESS (TCOpenFsVolume (NewExtension, &volumeHandle, &volumeFileObject)))
+ {
+ __try
+ {
+ ULONG fsStatus;
+
+ if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_IS_VOLUME_DIRTY, NULL, 0, &fsStatus, sizeof (fsStatus)))
+ && (fsStatus & VOLUME_IS_DIRTY))
+ {
+ mount->FilesystemDirty = TRUE;
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ mount->FilesystemDirty = TRUE;
+ }
+
+ // detect if the filesystem is NTFS or FAT
+ __try
+ {
+ NTFS_VOLUME_DATA_BUFFER ntfsData;
+ if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &ntfsData, sizeof (ntfsData))))
+ {
+ bIsNTFS = TRUE;
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ bIsNTFS = FALSE;
+ }
+
+ NewExtension->bIsNTFS = bIsNTFS;
+ mount->bIsNTFS = bIsNTFS;
+
+ if (labelLen > 0)
+ {
+ if (bIsNTFS)
+ labelMaxLen = 32; // NTFS maximum label length
+ else
+ labelMaxLen = 11; // FAT maximum label length
+
+ // calculate label effective length
+ labelEffectiveLen = labelLen > labelMaxLen? labelMaxLen : labelLen;
+
+ // correct the label in the device
+ memset (&NewExtension->wszLabel[labelEffectiveLen], 0, 33 - labelEffectiveLen);
+ memcpy (mount->wszLabel, NewExtension->wszLabel, 33);
+
+ // set the volume label
+ __try
+ {
+ IO_STATUS_BLOCK ioblock;
+ ULONG labelInfoSize = sizeof(FILE_FS_LABEL_INFORMATION) + (labelEffectiveLen * sizeof(WCHAR));
+ FILE_FS_LABEL_INFORMATION* labelInfo = (FILE_FS_LABEL_INFORMATION*) TCalloc (labelInfoSize);
+ labelInfo->VolumeLabelLength = labelEffectiveLen * sizeof(WCHAR);
+ memcpy (labelInfo->VolumeLabel, mount->wszLabel, labelInfo->VolumeLabelLength);
+
+ if (STATUS_SUCCESS == ZwSetVolumeInformationFile (volumeHandle, &ioblock, labelInfo, labelInfoSize, FileFsLabelInformation))
+ {
+ mount->bDriverSetLabel = TRUE;
+ NewExtension->bDriverSetLabel = TRUE;
+ }
+
+ TCfree(labelInfo);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+
+ }
+ }
+
+ TCCloseFsVolume (volumeHandle, volumeFileObject);
+ }
+ }
+ else
+ {
+ Dump ("Mount FAILURE TC code = 0x%08x\n", mount->nReturnCode);
+ TCDeleteDeviceObject (NewDeviceObject, NewExtension);
+ }
+
+ return STATUS_SUCCESS;
+ }
+ }
+}
+
+NTSTATUS UnmountDevice (UNMOUNT_STRUCT *unmountRequest, PDEVICE_OBJECT deviceObject, BOOL ignoreOpenFiles)
+{
+ PEXTENSION extension = deviceObject->DeviceExtension;
+ NTSTATUS ntStatus;
+ HANDLE volumeHandle;
+ PFILE_OBJECT volumeFileObject;
+
+ Dump ("UnmountDevice %d\n", extension->nDosDriveNo);
+
+ ntStatus = TCOpenFsVolume (extension, &volumeHandle, &volumeFileObject);
+
+ if (NT_SUCCESS (ntStatus))
+ {
+ int dismountRetry;
+
+ // Dismounting a writable NTFS filesystem prevents the driver from being unloaded on Windows 7
+ if (IsOSAtLeast (WIN_7) && !extension->bReadOnly)
+ {
+ NTFS_VOLUME_DATA_BUFFER ntfsData;
+
+ if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &ntfsData, sizeof (ntfsData))))
+ DriverUnloadDisabled = TRUE;
+ }
+
+ // Lock volume
+ ntStatus = TCFsctlCall (volumeFileObject, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0);
+ Dump ("FSCTL_LOCK_VOLUME returned %X\n", ntStatus);
+
+ if (!NT_SUCCESS (ntStatus) && !ignoreOpenFiles)
+ {
+ TCCloseFsVolume (volumeHandle, volumeFileObject);
+ return ERR_FILES_OPEN;
+ }
+
+ // Dismount volume
+ for (dismountRetry = 0; dismountRetry < 200; ++dismountRetry)
+ {
+ ntStatus = TCFsctlCall (volumeFileObject, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0);
+ Dump ("FSCTL_DISMOUNT_VOLUME returned %X\n", ntStatus);
+
+ if (NT_SUCCESS (ntStatus) || ntStatus == STATUS_VOLUME_DISMOUNTED)
+ break;
+
+ if (!ignoreOpenFiles)
+ {
+ TCCloseFsVolume (volumeHandle, volumeFileObject);
+ return ERR_FILES_OPEN;
+ }
+
+ TCSleep (100);
+ }
+ }
+ else
+ {
+ // Volume cannot be opened => force dismount if allowed
+ if (!ignoreOpenFiles)
+ return ERR_FILES_OPEN;
+ else
+ volumeHandle = NULL;
+ }
+
+ if (extension->bMountManager)
+ MountManagerUnmount (extension->nDosDriveNo);
+
+ // We always remove symbolic link as mount manager might fail to do so
+ RemoveDriveLink (extension->nDosDriveNo);
+
+ extension->bShuttingDown = TRUE;
+
+ ntStatus = IoAcquireRemoveLock (&extension->Queue.RemoveLock, NULL);
+ ASSERT (NT_SUCCESS (ntStatus));
+ IoReleaseRemoveLockAndWait (&extension->Queue.RemoveLock, NULL);
+
+ if (volumeHandle != NULL)
+ TCCloseFsVolume (volumeHandle, volumeFileObject);
+
+ if (unmountRequest)
+ {
+ PCRYPTO_INFO cryptoInfo = ((PEXTENSION) deviceObject->DeviceExtension)->cryptoInfo;
+ unmountRequest->HiddenVolumeProtectionTriggered = (cryptoInfo->bProtectHiddenVolume && cryptoInfo->bHiddenVolProtectionAction);
+ }
+
+ TCDeleteDeviceObject (deviceObject, (PEXTENSION) deviceObject->DeviceExtension);
+ return 0;
+}
+
+
+static PDEVICE_OBJECT FindVolumeWithHighestUniqueId (int maxUniqueId)
+{
+ PDEVICE_OBJECT highestIdDevice = NULL;
+ int highestId = -1;
+ int drive;
+
+ for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive)
+ {
+ PDEVICE_OBJECT device = GetVirtualVolumeDeviceObject (drive);
+ if (device)
+ {
+ PEXTENSION extension = (PEXTENSION) device->DeviceExtension;
+ if (extension->UniqueVolumeId > highestId && extension->UniqueVolumeId <= maxUniqueId)
+ {
+ highestId = extension->UniqueVolumeId;
+ highestIdDevice = device;
+ }
+ }
+ }
+
+ return highestIdDevice;
+}
+
+
+NTSTATUS UnmountAllDevices (UNMOUNT_STRUCT *unmountRequest, BOOL ignoreOpenFiles)
+{
+ NTSTATUS status = 0;
+ PDEVICE_OBJECT ListDevice;
+ int maxUniqueId = LastUniqueVolumeId;
+
+ Dump ("Unmounting all volumes\n");
+
+ if (unmountRequest)
+ unmountRequest->HiddenVolumeProtectionTriggered = FALSE;
+
+ // Dismount volumes in the reverse order they were mounted to properly dismount nested volumes
+ while ((ListDevice = FindVolumeWithHighestUniqueId (maxUniqueId)) != NULL)
+ {
+ PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension;
+ maxUniqueId = ListExtension->UniqueVolumeId - 1;
+
+ if (IsVolumeAccessibleByCurrentUser (ListExtension))
+ {
+ NTSTATUS ntStatus;
+
+ if (unmountRequest)
+ unmountRequest->nDosDriveNo = ListExtension->nDosDriveNo;
+
+ ntStatus = UnmountDevice (unmountRequest, ListDevice, ignoreOpenFiles);
+ status = ntStatus == 0 ? status : ntStatus;
+
+ if (unmountRequest && unmountRequest->HiddenVolumeProtectionTriggered)
+ break;
+ }
+ }
+
+ return status;
+}
+
+// Resolves symbolic link name to its target name
+NTSTATUS SymbolicLinkToTarget (PWSTR symlinkName, PWSTR targetName, USHORT maxTargetNameLength)
+{
+ NTSTATUS ntStatus;
+ OBJECT_ATTRIBUTES objectAttributes;
+ UNICODE_STRING fullFileName;
+ HANDLE handle;
+
+ RtlInitUnicodeString (&fullFileName, symlinkName);
+ InitializeObjectAttributes (&objectAttributes, &fullFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ ntStatus = ZwOpenSymbolicLinkObject (&handle, GENERIC_READ, &objectAttributes);
+
+ if (NT_SUCCESS (ntStatus))
+ {
+ UNICODE_STRING target;
+ target.Buffer = targetName;
+ target.Length = 0;
+ target.MaximumLength = maxTargetNameLength;
+ memset (targetName, 0, maxTargetNameLength);
+
+ ntStatus = ZwQuerySymbolicLinkObject (handle, &target, NULL);
+
+ ZwClose (handle);
+ }
+
+ return ntStatus;
+}
+
+
+// Checks if two regions overlap (borders are parts of regions)
+BOOL RegionsOverlap (unsigned __int64 start1, unsigned __int64 end1, unsigned __int64 start2, unsigned __int64 end2)
+{
+ return (start1 < start2) ? (end1 >= start2) : (start1 <= end2);
+}
+
+
+void GetIntersection (uint64 start1, uint32 length1, uint64 start2, uint64 end2, uint64 *intersectStart, uint32 *intersectLength)
+{
+ uint64 end1 = start1 + length1 - 1;
+ uint64 intersectEnd = (end1 <= end2) ? end1 : end2;
+
+ *intersectStart = (start1 >= start2) ? start1 : start2;
+ *intersectLength = (uint32) ((*intersectStart > intersectEnd) ? 0 : intersectEnd + 1 - *intersectStart);
+
+ if (*intersectLength == 0)
+ *intersectStart = start1;
+}
+
+
+BOOL IsAccessibleByUser (PUNICODE_STRING objectFileName, BOOL readOnly)
+{
+ OBJECT_ATTRIBUTES fileObjAttributes;
+ IO_STATUS_BLOCK ioStatusBlock;
+ HANDLE fileHandle;
+ NTSTATUS status;
+
+ ASSERT (!IoIsSystemThread (PsGetCurrentThread()));
+
+ InitializeObjectAttributes (&fileObjAttributes, objectFileName, OBJ_CASE_INSENSITIVE | OBJ_FORCE_ACCESS_CHECK | OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ status = ZwCreateFile (&fileHandle,
+ readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
+ &fileObjAttributes,
+ &ioStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0);
+
+ if (NT_SUCCESS (status))
+ {
+ ZwClose (fileHandle);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+BOOL UserCanAccessDriveDevice ()
+{
+ UNICODE_STRING name;
+ RtlInitUnicodeString (&name, L"\\Device\\MountPointManager");
+
+ return IsAccessibleByUser (&name, FALSE);
+}
+
+BOOL IsDriveLetterAvailable (int nDosDriveNo, DeviceNamespaceType namespaceType)
+{
+ OBJECT_ATTRIBUTES objectAttributes;
+ UNICODE_STRING objectName;
+ WCHAR link[128];
+ HANDLE handle;
+ NTSTATUS ntStatus;
+
+ TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, namespaceType);
+ RtlInitUnicodeString (&objectName, link);
+ InitializeObjectAttributes (&objectAttributes, &objectName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ if (NT_SUCCESS (ntStatus = ZwOpenSymbolicLinkObject (&handle, GENERIC_READ, &objectAttributes)))
+ {
+ ZwClose (handle);
+ return FALSE;
+ }
+
+ return (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND)? TRUE : FALSE;
+}
+
+
+NTSTATUS TCCompleteIrp (PIRP irp, NTSTATUS status, ULONG_PTR information)
+{
+ irp->IoStatus.Status = status;
+ irp->IoStatus.Information = information;
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+ return status;
+}
+
+
+NTSTATUS TCCompleteDiskIrp (PIRP irp, NTSTATUS status, ULONG_PTR information)
+{
+ irp->IoStatus.Status = status;
+ irp->IoStatus.Information = information;
+ IoCompleteRequest (irp, NT_SUCCESS (status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
+ return status;
+}
+
+
+size_t GetCpuCount ()
+{
+ KAFFINITY activeCpuMap = KeQueryActiveProcessors();
+ size_t mapSize = sizeof (activeCpuMap) * 8;
+ size_t cpuCount = 0;
+
+ while (mapSize--)
+ {
+ if (activeCpuMap & 1)
+ ++cpuCount;
+
+ activeCpuMap >>= 1;
+ }
+
+ if (cpuCount == 0)
+ return 1;
+
+ return cpuCount;
+}
+
+
+void EnsureNullTerminatedString (wchar_t *str, size_t maxSizeInBytes)
+{
+ ASSERT ((maxSizeInBytes & 1) == 0);
+ str[maxSizeInBytes / sizeof (wchar_t) - 1] = 0;
+}
+
+
+void *AllocateMemoryWithTimeout (size_t size, int retryDelay, int timeout)
+{
+ LARGE_INTEGER waitInterval;
+ waitInterval.QuadPart = retryDelay * -10000;
+
+ ASSERT (KeGetCurrentIrql() <= APC_LEVEL);
+ ASSERT (retryDelay > 0 && retryDelay <= timeout);
+
+ while (TRUE)
+ {
+ void *memory = TCalloc (size);
+ if (memory)
+ return memory;
+
+ timeout -= retryDelay;
+ if (timeout <= 0)
+ break;
+
+ KeDelayExecutionThread (KernelMode, FALSE, &waitInterval);
+ }
+
+ return NULL;
+}
+
+
+NTSTATUS TCReadRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, PKEY_VALUE_PARTIAL_INFORMATION *keyData)
+{
+ OBJECT_ATTRIBUTES regObjAttribs;
+ HANDLE regKeyHandle;
+ NTSTATUS status;
+ UNICODE_STRING valName;
+ ULONG size = 0;
+ ULONG resultSize;
+
+ InitializeObjectAttributes (&regObjAttribs, keyPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
+ status = ZwOpenKey (&regKeyHandle, KEY_READ, &regObjAttribs);
+ if (!NT_SUCCESS (status))
+ return status;
+
+ RtlInitUnicodeString (&valName, keyValueName);
+ status = ZwQueryValueKey (regKeyHandle, &valName, KeyValuePartialInformation, NULL, 0, &size);
+
+ if (!NT_SUCCESS (status) && status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL)
+ {
+ ZwClose (regKeyHandle);
+ return status;
+ }
+
+ if (size == 0)
+ {
+ ZwClose (regKeyHandle);
+ return STATUS_NO_DATA_DETECTED;
+ }
+
+ *keyData = (PKEY_VALUE_PARTIAL_INFORMATION) TCalloc (size);
+ if (!*keyData)
+ {
+ ZwClose (regKeyHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ status = ZwQueryValueKey (regKeyHandle, &valName, KeyValuePartialInformation, *keyData, size, &resultSize);
+
+ ZwClose (regKeyHandle);
+ return status;
+}
+
+
+NTSTATUS TCWriteRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, ULONG keyValueType, void *valueData, ULONG valueSize)
+{
+ OBJECT_ATTRIBUTES regObjAttribs;
+ HANDLE regKeyHandle;
+ NTSTATUS status;
+ UNICODE_STRING valName;
+
+ InitializeObjectAttributes (&regObjAttribs, keyPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
+ status = ZwOpenKey (&regKeyHandle, KEY_READ | KEY_WRITE, &regObjAttribs);
+ if (!NT_SUCCESS (status))
+ return status;
+
+ RtlInitUnicodeString (&valName, keyValueName);
+
+ status = ZwSetValueKey (regKeyHandle, &valName, 0, keyValueType, valueData, valueSize);
+
+ ZwClose (regKeyHandle);
+ return status;
+}
+
+
+BOOL IsVolumeClassFilterRegistered ()
+{
+ UNICODE_STRING name;
+ NTSTATUS status;
+ BOOL registered = FALSE;
+
+ PKEY_VALUE_PARTIAL_INFORMATION data;
+
+ RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class\\{71A27CDD-812A-11D0-BEC7-08002BE2092F}");
+ status = TCReadRegistryKey (&name, L"UpperFilters", &data);
+
+ if (NT_SUCCESS (status))
+ {
+ if (data->Type == REG_MULTI_SZ && data->DataLength >= 9 * sizeof (wchar_t))
+ {
+ // Search for the string "veracrypt"
+ ULONG i;
+ for (i = 0; i <= data->DataLength - 9 * sizeof (wchar_t); ++i)
+ {
+ if (memcmp (data->Data + i, L"veracrypt", 9 * sizeof (wchar_t)) == 0)
+ {
+ Dump ("Volume class filter active\n");
+ registered = TRUE;
+ break;
+ }
+ }
+ }
+
+ TCfree (data);
+ }
+
+ return registered;
+}
+
+
+NTSTATUS ReadRegistryConfigFlags (BOOL driverEntry)
+{
+ PKEY_VALUE_PARTIAL_INFORMATION data;
+ UNICODE_STRING name;
+ NTSTATUS status;
+ uint32 flags = 0;
+
+ RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\veracrypt");
+ status = TCReadRegistryKey (&name, TC_DRIVER_CONFIG_REG_VALUE_NAME, &data);
+
+ if (NT_SUCCESS (status))
+ {
+ if (data->Type == REG_DWORD)
+ {
+ flags = *(uint32 *) data->Data;
+ Dump ("Configuration flags = 0x%x\n", flags);
+
+ if (driverEntry)
+ {
+ if (flags & (TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD | TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES))
+ CacheBootPassword = TRUE;
+
+ if (flags & TC_DRIVER_CONFIG_DISABLE_NONADMIN_SYS_FAVORITES_ACCESS)
+ NonAdminSystemFavoritesAccessDisabled = TRUE;
+
+ if (flags & TC_DRIVER_CONFIG_CACHE_BOOT_PIM)
+ CacheBootPim = TRUE;
+ }
+
+ EnableHwEncryption ((flags & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION) ? FALSE : TRUE);
+
+ EnableExtendedIoctlSupport = (flags & TC_DRIVER_CONFIG_ENABLE_EXTENDED_IOCTL)? TRUE : FALSE;
+ }
+ else
+ status = STATUS_INVALID_PARAMETER;
+
+ TCfree (data);
+ }
+
+ if (driverEntry && NT_SUCCESS (TCReadRegistryKey (&name, TC_ENCRYPTION_FREE_CPU_COUNT_REG_VALUE_NAME, &data)))
+ {
+ if (data->Type == REG_DWORD)
+ EncryptionThreadPoolFreeCpuCountLimit = *(uint32 *) data->Data;
+
+ TCfree (data);
+ }
+
+ return status;
+}
+
+
+NTSTATUS WriteRegistryConfigFlags (uint32 flags)
+{
+ UNICODE_STRING name;
+ RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\veracrypt");
+
+ return TCWriteRegistryKey (&name, TC_DRIVER_CONFIG_REG_VALUE_NAME, REG_DWORD, &flags, sizeof (flags));
+}
+
+
+NTSTATUS GetDeviceSectorSize (PDEVICE_OBJECT deviceObject, ULONG *bytesPerSector)
+{
+ NTSTATUS status;
+ DISK_GEOMETRY geometry;
+
+ status = SendDeviceIoControlRequest (deviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry));
+
+ if (!NT_SUCCESS (status))
+ return status;
+
+ *bytesPerSector = geometry.BytesPerSector;
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS ZeroUnreadableSectors (PDEVICE_OBJECT deviceObject, LARGE_INTEGER startOffset, ULONG size, uint64 *zeroedSectorCount)
+{
+ NTSTATUS status;
+ ULONG sectorSize;
+ ULONG sectorCount;
+ byte *sectorBuffer = NULL;
+
+ *zeroedSectorCount = 0;
+
+ status = GetDeviceSectorSize (deviceObject, &sectorSize);
+ if (!NT_SUCCESS (status))
+ return status;
+
+ sectorBuffer = TCalloc (sectorSize);
+ if (!sectorBuffer)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount, startOffset.QuadPart += sectorSize)
+ {
+ status = TCReadDevice (deviceObject, sectorBuffer, startOffset, sectorSize);
+ if (!NT_SUCCESS (status))
+ {
+ Dump ("Zeroing sector at %I64d\n", startOffset.QuadPart);
+ memset (sectorBuffer, 0, sectorSize);
+
+ status = TCWriteDevice (deviceObject, sectorBuffer, startOffset, sectorSize);
+ if (!NT_SUCCESS (status))
+ goto err;
+
+ ++(*zeroedSectorCount);
+ }
+ }
+
+ status = STATUS_SUCCESS;
+
+err:
+ if (sectorBuffer)
+ TCfree (sectorBuffer);
+
+ return status;
+}
+
+
+NTSTATUS ReadDeviceSkipUnreadableSectors (PDEVICE_OBJECT deviceObject, byte *buffer, LARGE_INTEGER startOffset, ULONG size, uint64 *badSectorCount)
+{
+ NTSTATUS status;
+ ULONG sectorSize;
+ ULONG sectorCount;
+
+ *badSectorCount = 0;
+
+ status = GetDeviceSectorSize (deviceObject, &sectorSize);
+ if (!NT_SUCCESS (status))
+ return status;
+
+ for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount, startOffset.QuadPart += sectorSize, buffer += sectorSize)
+ {
+ status = TCReadDevice (deviceObject, buffer, startOffset, sectorSize);
+ if (!NT_SUCCESS (status))
+ {
+ Dump ("Skipping bad sector at %I64d\n", startOffset.QuadPart);
+ memset (buffer, 0, sectorSize);
+ ++(*badSectorCount);
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+BOOL IsVolumeAccessibleByCurrentUser (PEXTENSION volumeDeviceExtension)
+{
+ SECURITY_SUBJECT_CONTEXT subContext;
+ PACCESS_TOKEN accessToken;
+ PTOKEN_USER tokenUser;
+ BOOL result = FALSE;
+
+ if (IoIsSystemThread (PsGetCurrentThread())
+ || UserCanAccessDriveDevice()
+ || !volumeDeviceExtension->UserSid
+ || (volumeDeviceExtension->SystemFavorite && !NonAdminSystemFavoritesAccessDisabled))
+ {
+ return TRUE;
+ }
+
+ SeCaptureSubjectContext (&subContext);
+ SeLockSubjectContext(&subContext);
+ if (subContext.ClientToken && subContext.ImpersonationLevel >= SecurityImpersonation)
+ accessToken = subContext.ClientToken;
+ else
+ accessToken = subContext.PrimaryToken;
+
+ if (!accessToken)
+ goto ret;
+
+ if (SeTokenIsAdmin (accessToken))
+ {
+ result = TRUE;
+ goto ret;
+ }
+
+ if (!NT_SUCCESS (SeQueryInformationToken (accessToken, TokenUser, &tokenUser)))
+ goto ret;
+
+ result = RtlEqualSid (volumeDeviceExtension->UserSid, tokenUser->User.Sid);
+ ExFreePool (tokenUser); // Documented in newer versions of WDK
+
+ret:
+ SeUnlockSubjectContext(&subContext);
+ SeReleaseSubjectContext (&subContext);
+ return result;
+}
+
+
+void GetElapsedTimeInit (LARGE_INTEGER *lastPerfCounter)
+{
+ *lastPerfCounter = KeQueryPerformanceCounter (NULL);
+}
+
+
+// Returns elapsed time in microseconds since last call
+int64 GetElapsedTime (LARGE_INTEGER *lastPerfCounter)
+{
+ LARGE_INTEGER freq;
+ LARGE_INTEGER counter = KeQueryPerformanceCounter (&freq);
+
+ int64 elapsed = (counter.QuadPart - lastPerfCounter->QuadPart) * 1000000LL / freq.QuadPart;
+ *lastPerfCounter = counter;
+
+ return elapsed;
+}
+
+
+BOOL IsOSAtLeast (OSVersionEnum reqMinOS)
+{
+ /* When updating this function, update IsOSVersionAtLeast() in Dlgcode.c too. */
+
+ ULONG major = 0, minor = 0;
+
+ ASSERT (OsMajorVersion != 0);
+
+ switch (reqMinOS)
+ {
+ case WIN_2000: major = 5; minor = 0; break;
+ case WIN_XP: major = 5; minor = 1; break;
+ case WIN_SERVER_2003: major = 5; minor = 2; break;
+ case WIN_VISTA: major = 6; minor = 0; break;
+ case WIN_7: major = 6; minor = 1; break;
+ case WIN_8: major = 6; minor = 2; break;
+ case WIN_8_1: major = 6; minor = 3; break;
+ case WIN_10: major = 10; minor = 0; break;
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ break;
+ }
+
+ return ((OsMajorVersion << 16 | OsMinorVersion << 8)
+ >= (major << 16 | minor << 8));
+}
diff --git a/src/Driver/Ntdriver.h b/src/Driver/Ntdriver.h
index 59634760..d5d548e8 100644
--- a/src/Driver/Ntdriver.h
+++ b/src/Driver/Ntdriver.h
@@ -1,189 +1,189 @@
-/*
- Legal Notice: Some portions of the source code contained in this file were
- derived from the source code of TrueCrypt 7.1a, which is
- Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
- governed by the TrueCrypt License 3.0, also from the source code of
- Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
- and which is governed by the 'License Agreement for Encryption for the Masses'
- 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. */
-
-#ifndef TC_HEADER_NTDRIVER
-#define TC_HEADER_NTDRIVER
-
-#include "Common.h"
-#include "EncryptedIoQueue.h"
-
-/* This structure is used to start new threads */
-typedef struct _THREAD_BLOCK_
-{
- PDEVICE_OBJECT DeviceObject;
- NTSTATUS ntCreateStatus;
- WCHAR wszMountVolume[TC_MAX_PATH + 8];
- MOUNT_STRUCT *mount;
-} THREAD_BLOCK, *PTHREAD_BLOCK;
-
-
-/* This structure is allocated for non-root devices! WARNING: bRootDevice
- must be the first member of the structure! */
-typedef struct EXTENSION
-{
- BOOL bRootDevice; /* Is this the root device ? which the user-mode apps talk to */
- BOOL IsVolumeDevice;
- BOOL IsDriveFilterDevice;
- BOOL IsVolumeFilterDevice;
-
- int UniqueVolumeId;
- int nDosDriveNo; /* Drive number this extension is mounted against */
-
- BOOL bShuttingDown; /* Is the driver shutting down ? */
- BOOL bThreadShouldQuit; /* Instruct per device worker thread to quit */
- PETHREAD peThread; /* Thread handle */
- KEVENT keCreateEvent; /* Device creation event */
- KSPIN_LOCK ListSpinLock; /* IRP spinlock */
- LIST_ENTRY ListEntry; /* IRP listentry */
- KSEMAPHORE RequestSemaphore; /* IRP list request Semaphore */
-
- HANDLE hDeviceFile; /* Device handle for this device */
- PFILE_OBJECT pfoDeviceFile; /* Device fileobject for this device */
- PDEVICE_OBJECT pFsdDevice; /* lower level device handle */
-
- CRYPTO_INFO *cryptoInfo; /* Cryptographic and other information for this device */
-
- __int64 HostLength;
- __int64 DiskLength; /* The length of the disk referred to by this device */
- __int64 NumberOfCylinders; /* Partition info */
- ULONG TracksPerCylinder; /* Partition info */
- ULONG SectorsPerTrack; /* Partition info */
- ULONG BytesPerSector; /* Partition info */
- UCHAR PartitionType; /* Partition info */
-
- uint32 HostBytesPerSector;
- uint32 HostBytesPerPhysicalSector;
- ULONG BytesOffsetForSectorAlignment;
-
- KEVENT keVolumeEvent; /* Event structure used when setting up a device */
-
- EncryptedIoQueue Queue;
-
- BOOL bReadOnly; /* Is this device read-only ? */
- BOOL bRemovable; /* Is this device removable media ? */
- BOOL PartitionInInactiveSysEncScope;
- BOOL bRawDevice; /* Is this a raw-partition or raw-floppy device ? */
- BOOL bMountManager; /* Mount manager knows about volume */
- BOOL SystemFavorite;
-
- WCHAR wszVolume[TC_MAX_PATH]; /* DONT change this size without also changing MOUNT_LIST_STRUCT! */
- WCHAR wszLabel[33];
- BOOL bIsNTFS;
- BOOL bDriverSetLabel;
-
- unsigned char volumeID[VOLUME_ID_SIZE];
-
- LARGE_INTEGER fileCreationTime;
- LARGE_INTEGER fileLastAccessTime;
- LARGE_INTEGER fileLastWriteTime;
- LARGE_INTEGER fileLastChangeTime;
- BOOL bTimeStampValid;
-
- PSID UserSid;
- BOOL SecurityClientContextValid;
- SECURITY_CLIENT_CONTEXT SecurityClientContext;
-
-} EXTENSION, *PEXTENSION;
-
-
-typedef enum
-{
- ValidateInput,
- ValidateOutput,
- ValidateInputOutput
-} ValidateIOBufferSizeType;
-
-typedef enum
-{
- DeviceNamespaceDefault,
- DeviceNamespaceGlobal,
-} DeviceNamespaceType;
-
-extern PDRIVER_OBJECT TCDriverObject;
-extern PDEVICE_OBJECT RootDeviceObject;
-extern BOOL DriverShuttingDown;
-extern ULONG OsMajorVersion;
-extern ULONG OsMinorVersion;
-extern BOOL VolumeClassFilterRegistered;
-extern BOOL CacheBootPassword;
-extern BOOL CacheBootPim;
-
-/* Helper macro returning x seconds in units of 100 nanoseconds */
-#define WAIT_SECONDS(x) ((x)*10000000)
-
-NTSTATUS DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
-NTSTATUS DriverAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo);
-void DumpMemory (void *memory, int size);
-BOOL IsAccessibleByUser (PUNICODE_STRING objectFileName, BOOL readOnly);
-NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp);
-NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp);
-NTSTATUS SendDeviceIoControlRequest (PDEVICE_OBJECT deviceObject, ULONG ioControlCode, void *inputBuffer, int inputBufferSize, void *outputBuffer, int outputBufferSize);
-NTSTATUS TCDispatchQueueIRP (PDEVICE_OBJECT DeviceObject, PIRP Irp);
-NTSTATUS TCCreateRootDeviceObject (PDRIVER_OBJECT DriverObject);
-NTSTATUS TCCreateDeviceObject (PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT * ppDeviceObject, MOUNT_STRUCT * mount);
-NTSTATUS TCReadDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length);
-NTSTATUS TCWriteDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length);
-NTSTATUS TCStartThread (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread);
-NTSTATUS TCStartThreadInProcess (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread, PEPROCESS process);
-NTSTATUS TCStartVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, MOUNT_STRUCT * mount);
-void TCStopThread (PKTHREAD kThread, PKEVENT wakeUpEvent);
-void TCStopVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension);
-VOID VolumeThreadProc (PVOID Context);
-void TCSleep (int milliSeconds);
-void TCGetNTNameFromNumber (LPWSTR ntname, int cbNtName, int nDriveNo);
-void TCGetDosNameFromNumber (LPWSTR dosname, int cbDosName, int nDriveNo, DeviceNamespaceType namespaceType);
-LPWSTR TCTranslateCode (ULONG ulCode);
-void TCDeleteDeviceObject (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension);
-VOID TCUnloadDriver (PDRIVER_OBJECT DriverObject);
-void OnShutdownPending ();
-NTSTATUS TCDeviceIoControl (PWSTR deviceName, ULONG IoControlCode, void *InputBuffer, ULONG InputBufferSize, void *OutputBuffer, ULONG OutputBufferSize);
-NTSTATUS TCOpenFsVolume (PEXTENSION Extension, PHANDLE volumeHandle, PFILE_OBJECT * fileObject);
-void TCCloseFsVolume (HANDLE volumeHandle, PFILE_OBJECT fileObject);
-NTSTATUS TCFsctlCall (PFILE_OBJECT fileObject, LONG IoControlCode, void *InputBuffer, int InputBufferSize, void *OutputBuffer, int OutputBufferSize);
-NTSTATUS CreateDriveLink (int nDosDriveNo);
-NTSTATUS RemoveDriveLink (int nDosDriveNo);
-NTSTATUS MountManagerMount (MOUNT_STRUCT *mount);
-NTSTATUS MountManagerUnmount (int nDosDriveNo);
-NTSTATUS MountDevice (PDEVICE_OBJECT deviceObject, MOUNT_STRUCT *mount);
-NTSTATUS UnmountDevice (UNMOUNT_STRUCT *unmountRequest, PDEVICE_OBJECT deviceObject, BOOL ignoreOpenFiles);
-NTSTATUS UnmountAllDevices (UNMOUNT_STRUCT *unmountRequest, BOOL ignoreOpenFiles);
-NTSTATUS SymbolicLinkToTarget (PWSTR symlinkName, PWSTR targetName, USHORT maxTargetNameLength);
-BOOL RootDeviceControlMutexAcquireNoWait ();
-void RootDeviceControlMutexRelease ();
-BOOL RegionsOverlap (unsigned __int64 start1, unsigned __int64 end1, unsigned __int64 start2, unsigned __int64 end2);
-void GetIntersection (uint64 start1, uint32 length1, uint64 start2, uint64 end2, uint64 *intersectStart, uint32 *intersectLength);
-NTSTATUS TCCompleteIrp (PIRP irp, NTSTATUS status, ULONG_PTR information);
-NTSTATUS TCCompleteDiskIrp (PIRP irp, NTSTATUS status, ULONG_PTR information);
-NTSTATUS ProbeRealDriveSize (PDEVICE_OBJECT driveDeviceObject, LARGE_INTEGER *driveSize);
-BOOL UserCanAccessDriveDevice ();
-size_t GetCpuCount ();
-void EnsureNullTerminatedString (wchar_t *str, size_t maxSizeInBytes);
-void *AllocateMemoryWithTimeout (size_t size, int retryDelay, int timeout);
-BOOL IsDriveLetterAvailable (int nDosDriveNo, DeviceNamespaceType namespaceType);
-NTSTATUS TCReadRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, PKEY_VALUE_PARTIAL_INFORMATION *keyData);
-NTSTATUS TCWriteRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, ULONG keyValueType, void *valueData, ULONG valueSize);
-BOOL IsVolumeClassFilterRegistered ();
-NTSTATUS ReadRegistryConfigFlags (BOOL driverEntry);
-NTSTATUS WriteRegistryConfigFlags (uint32 flags);
-BOOL ValidateIOBufferSize (PIRP irp, size_t requiredBufferSize, ValidateIOBufferSizeType type);
-NTSTATUS GetDeviceSectorSize (PDEVICE_OBJECT deviceObject, ULONG *bytesPerSector);
-NTSTATUS ZeroUnreadableSectors (PDEVICE_OBJECT deviceObject, LARGE_INTEGER startOffset, ULONG size, uint64 *zeroedSectorCount);
-NTSTATUS ReadDeviceSkipUnreadableSectors (PDEVICE_OBJECT deviceObject, byte *buffer, LARGE_INTEGER startOffset, ULONG size, uint64 *badSectorCount);
-BOOL IsVolumeAccessibleByCurrentUser (PEXTENSION volumeDeviceExtension);
-void GetElapsedTimeInit (LARGE_INTEGER *lastPerfCounter);
-int64 GetElapsedTime (LARGE_INTEGER *lastPerfCounter);
-BOOL IsOSAtLeast (OSVersionEnum reqMinOS);
-
-#define TC_BUG_CHECK(status) KeBugCheckEx (SECURITY_SYSTEM, __LINE__, (ULONG_PTR) status, 0, 'VC')
-
-#endif // TC_HEADER_NTDRIVER
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of TrueCrypt 7.1a, which is
+ Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
+ governed by the TrueCrypt License 3.0, also from the source code of
+ Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
+ and which is governed by the 'License Agreement for Encryption for the Masses'
+ 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. */
+
+#ifndef TC_HEADER_NTDRIVER
+#define TC_HEADER_NTDRIVER
+
+#include "Common.h"
+#include "EncryptedIoQueue.h"
+
+/* This structure is used to start new threads */
+typedef struct _THREAD_BLOCK_
+{
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS ntCreateStatus;
+ WCHAR wszMountVolume[TC_MAX_PATH + 8];
+ MOUNT_STRUCT *mount;
+} THREAD_BLOCK, *PTHREAD_BLOCK;
+
+
+/* This structure is allocated for non-root devices! WARNING: bRootDevice
+ must be the first member of the structure! */
+typedef struct EXTENSION
+{
+ BOOL bRootDevice; /* Is this the root device ? which the user-mode apps talk to */
+ BOOL IsVolumeDevice;
+ BOOL IsDriveFilterDevice;
+ BOOL IsVolumeFilterDevice;
+
+ int UniqueVolumeId;
+ int nDosDriveNo; /* Drive number this extension is mounted against */
+
+ BOOL bShuttingDown; /* Is the driver shutting down ? */
+ BOOL bThreadShouldQuit; /* Instruct per device worker thread to quit */
+ PETHREAD peThread; /* Thread handle */
+ KEVENT keCreateEvent; /* Device creation event */
+ KSPIN_LOCK ListSpinLock; /* IRP spinlock */
+ LIST_ENTRY ListEntry; /* IRP listentry */
+ KSEMAPHORE RequestSemaphore; /* IRP list request Semaphore */
+
+ HANDLE hDeviceFile; /* Device handle for this device */
+ PFILE_OBJECT pfoDeviceFile; /* Device fileobject for this device */
+ PDEVICE_OBJECT pFsdDevice; /* lower level device handle */
+
+ CRYPTO_INFO *cryptoInfo; /* Cryptographic and other information for this device */
+
+ __int64 HostLength;
+ __int64 DiskLength; /* The length of the disk referred to by this device */
+ __int64 NumberOfCylinders; /* Partition info */
+ ULONG TracksPerCylinder; /* Partition info */
+ ULONG SectorsPerTrack; /* Partition info */
+ ULONG BytesPerSector; /* Partition info */
+ UCHAR PartitionType; /* Partition info */
+
+ uint32 HostBytesPerSector;
+ uint32 HostBytesPerPhysicalSector;
+ ULONG BytesOffsetForSectorAlignment;
+
+ KEVENT keVolumeEvent; /* Event structure used when setting up a device */
+
+ EncryptedIoQueue Queue;
+
+ BOOL bReadOnly; /* Is this device read-only ? */
+ BOOL bRemovable; /* Is this device removable media ? */
+ BOOL PartitionInInactiveSysEncScope;
+ BOOL bRawDevice; /* Is this a raw-partition or raw-floppy device ? */
+ BOOL bMountManager; /* Mount manager knows about volume */
+ BOOL SystemFavorite;
+
+ WCHAR wszVolume[TC_MAX_PATH]; /* DONT change this size without also changing MOUNT_LIST_STRUCT! */
+ WCHAR wszLabel[33];
+ BOOL bIsNTFS;
+ BOOL bDriverSetLabel;
+
+ unsigned char volumeID[VOLUME_ID_SIZE];
+
+ LARGE_INTEGER fileCreationTime;
+ LARGE_INTEGER fileLastAccessTime;
+ LARGE_INTEGER fileLastWriteTime;
+ LARGE_INTEGER fileLastChangeTime;
+ BOOL bTimeStampValid;
+
+ PSID UserSid;
+ BOOL SecurityClientContextValid;
+ SECURITY_CLIENT_CONTEXT SecurityClientContext;
+
+} EXTENSION, *PEXTENSION;
+
+
+typedef enum
+{
+ ValidateInput,
+ ValidateOutput,
+ ValidateInputOutput
+} ValidateIOBufferSizeType;
+
+typedef enum
+{
+ DeviceNamespaceDefault,
+ DeviceNamespaceGlobal,
+} DeviceNamespaceType;
+
+extern PDRIVER_OBJECT TCDriverObject;
+extern PDEVICE_OBJECT RootDeviceObject;
+extern BOOL DriverShuttingDown;
+extern ULONG OsMajorVersion;
+extern ULONG OsMinorVersion;
+extern BOOL VolumeClassFilterRegistered;
+extern BOOL CacheBootPassword;
+extern BOOL CacheBootPim;
+
+/* Helper macro returning x seconds in units of 100 nanoseconds */
+#define WAIT_SECONDS(x) ((x)*10000000)
+
+NTSTATUS DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
+NTSTATUS DriverAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo);
+void DumpMemory (void *memory, int size);
+BOOL IsAccessibleByUser (PUNICODE_STRING objectFileName, BOOL readOnly);
+NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp);
+NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp);
+NTSTATUS SendDeviceIoControlRequest (PDEVICE_OBJECT deviceObject, ULONG ioControlCode, void *inputBuffer, int inputBufferSize, void *outputBuffer, int outputBufferSize);
+NTSTATUS TCDispatchQueueIRP (PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS TCCreateRootDeviceObject (PDRIVER_OBJECT DriverObject);
+NTSTATUS TCCreateDeviceObject (PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT * ppDeviceObject, MOUNT_STRUCT * mount);
+NTSTATUS TCReadDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length);
+NTSTATUS TCWriteDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length);
+NTSTATUS TCStartThread (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread);
+NTSTATUS TCStartThreadInProcess (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread, PEPROCESS process);
+NTSTATUS TCStartVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, MOUNT_STRUCT * mount);
+void TCStopThread (PKTHREAD kThread, PKEVENT wakeUpEvent);
+void TCStopVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension);
+VOID VolumeThreadProc (PVOID Context);
+void TCSleep (int milliSeconds);
+void TCGetNTNameFromNumber (LPWSTR ntname, int cbNtName, int nDriveNo);
+void TCGetDosNameFromNumber (LPWSTR dosname, int cbDosName, int nDriveNo, DeviceNamespaceType namespaceType);
+LPWSTR TCTranslateCode (ULONG ulCode);
+void TCDeleteDeviceObject (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension);
+VOID TCUnloadDriver (PDRIVER_OBJECT DriverObject);
+void OnShutdownPending ();
+NTSTATUS TCDeviceIoControl (PWSTR deviceName, ULONG IoControlCode, void *InputBuffer, ULONG InputBufferSize, void *OutputBuffer, ULONG OutputBufferSize);
+NTSTATUS TCOpenFsVolume (PEXTENSION Extension, PHANDLE volumeHandle, PFILE_OBJECT * fileObject);
+void TCCloseFsVolume (HANDLE volumeHandle, PFILE_OBJECT fileObject);
+NTSTATUS TCFsctlCall (PFILE_OBJECT fileObject, LONG IoControlCode, void *InputBuffer, int InputBufferSize, void *OutputBuffer, int OutputBufferSize);
+NTSTATUS CreateDriveLink (int nDosDriveNo);
+NTSTATUS RemoveDriveLink (int nDosDriveNo);
+NTSTATUS MountManagerMount (MOUNT_STRUCT *mount);
+NTSTATUS MountManagerUnmount (int nDosDriveNo);
+NTSTATUS MountDevice (PDEVICE_OBJECT deviceObject, MOUNT_STRUCT *mount);
+NTSTATUS UnmountDevice (UNMOUNT_STRUCT *unmountRequest, PDEVICE_OBJECT deviceObject, BOOL ignoreOpenFiles);
+NTSTATUS UnmountAllDevices (UNMOUNT_STRUCT *unmountRequest, BOOL ignoreOpenFiles);
+NTSTATUS SymbolicLinkToTarget (PWSTR symlinkName, PWSTR targetName, USHORT maxTargetNameLength);
+BOOL RootDeviceControlMutexAcquireNoWait ();
+void RootDeviceControlMutexRelease ();
+BOOL RegionsOverlap (unsigned __int64 start1, unsigned __int64 end1, unsigned __int64 start2, unsigned __int64 end2);
+void GetIntersection (uint64 start1, uint32 length1, uint64 start2, uint64 end2, uint64 *intersectStart, uint32 *intersectLength);
+NTSTATUS TCCompleteIrp (PIRP irp, NTSTATUS status, ULONG_PTR information);
+NTSTATUS TCCompleteDiskIrp (PIRP irp, NTSTATUS status, ULONG_PTR information);
+NTSTATUS ProbeRealDriveSize (PDEVICE_OBJECT driveDeviceObject, LARGE_INTEGER *driveSize);
+BOOL UserCanAccessDriveDevice ();
+size_t GetCpuCount ();
+void EnsureNullTerminatedString (wchar_t *str, size_t maxSizeInBytes);
+void *AllocateMemoryWithTimeout (size_t size, int retryDelay, int timeout);
+BOOL IsDriveLetterAvailable (int nDosDriveNo, DeviceNamespaceType namespaceType);
+NTSTATUS TCReadRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, PKEY_VALUE_PARTIAL_INFORMATION *keyData);
+NTSTATUS TCWriteRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, ULONG keyValueType, void *valueData, ULONG valueSize);
+BOOL IsVolumeClassFilterRegistered ();
+NTSTATUS ReadRegistryConfigFlags (BOOL driverEntry);
+NTSTATUS WriteRegistryConfigFlags (uint32 flags);
+BOOL ValidateIOBufferSize (PIRP irp, size_t requiredBufferSize, ValidateIOBufferSizeType type);
+NTSTATUS GetDeviceSectorSize (PDEVICE_OBJECT deviceObject, ULONG *bytesPerSector);
+NTSTATUS ZeroUnreadableSectors (PDEVICE_OBJECT deviceObject, LARGE_INTEGER startOffset, ULONG size, uint64 *zeroedSectorCount);
+NTSTATUS ReadDeviceSkipUnreadableSectors (PDEVICE_OBJECT deviceObject, byte *buffer, LARGE_INTEGER startOffset, ULONG size, uint64 *badSectorCount);
+BOOL IsVolumeAccessibleByCurrentUser (PEXTENSION volumeDeviceExtension);
+void GetElapsedTimeInit (LARGE_INTEGER *lastPerfCounter);
+int64 GetElapsedTime (LARGE_INTEGER *lastPerfCounter);
+BOOL IsOSAtLeast (OSVersionEnum reqMinOS);
+
+#define TC_BUG_CHECK(status) KeBugCheckEx (SECURITY_SYSTEM, __LINE__, (ULONG_PTR) status, 0, 'VC')
+
+#endif // TC_HEADER_NTDRIVER
diff --git a/src/Driver/Ntvol.c b/src/Driver/Ntvol.c
index 4f35323b..34ee2dbb 100644
--- a/src/Driver/Ntvol.c
+++ b/src/Driver/Ntvol.c
@@ -1,900 +1,900 @@
-/*
- Legal Notice: Some portions of the source code contained in this file were
- derived from the source code of TrueCrypt 7.1a, which is
- Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
- governed by the TrueCrypt License 3.0, also from the source code of
- Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
- and which is governed by the 'License Agreement for Encryption for the Masses'
- 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 <wchar.h>
-#include "Crypto.h"
-#include "Volumes.h"
-
-#include "Apidrvr.h"
-#include "DriveFilter.h"
-#include "Ntdriver.h"
-#include "Ntvol.h"
-#include "VolumeFilter.h"
-
-#include "Boot/Windows/BootCommon.h"
-
-#include "Cache.h"
-
-#if 0 && _DEBUG
-#define EXTRA_INFO 1
-#endif
-
-#pragma warning( disable : 4127 )
-
-#include <Ntstrsafe.h>
-
-volatile BOOL ProbingHostDeviceForWrite = FALSE;
-
-
-NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
- PEXTENSION Extension,
- MOUNT_STRUCT *mount,
- PWSTR pwszMountVolume,
- BOOL bRawDevice)
-{
- FILE_STANDARD_INFORMATION FileStandardInfo;
- FILE_BASIC_INFORMATION FileBasicInfo;
- OBJECT_ATTRIBUTES oaFileAttributes;
- UNICODE_STRING FullFileName;
- IO_STATUS_BLOCK IoStatusBlock;
- PCRYPTO_INFO cryptoInfoPtr = NULL;
- PCRYPTO_INFO tmpCryptoInfo = NULL;
- LARGE_INTEGER lDiskLength;
- __int64 partitionStartingOffset = 0;
- int volumeType;
- char *readBuffer = 0;
- NTSTATUS ntStatus = 0;
- BOOL forceAccessCheck = (!bRawDevice && !(OsMajorVersion == 5 &&OsMinorVersion == 0)); // Windows 2000 does not support OBJ_FORCE_ACCESS_CHECK attribute
- BOOL disableBuffering = TRUE;
- BOOL exclusiveAccess = mount->bExclusiveAccess;
-
- Extension->pfoDeviceFile = NULL;
- Extension->hDeviceFile = NULL;
- Extension->bTimeStampValid = FALSE;
-
- RtlInitUnicodeString (&FullFileName, pwszMountVolume);
- InitializeObjectAttributes (&oaFileAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | (forceAccessCheck ? OBJ_FORCE_ACCESS_CHECK : 0) | OBJ_KERNEL_HANDLE, NULL, NULL);
- KeInitializeEvent (&Extension->keVolumeEvent, NotificationEvent, FALSE);
-
- if (Extension->SecurityClientContextValid)
- {
- ntStatus = SeImpersonateClientEx (&Extension->SecurityClientContext, NULL);
- if (!NT_SUCCESS (ntStatus))
- goto error;
- }
-
- mount->VolumeMountedReadOnlyAfterDeviceWriteProtected = FALSE;
-
- // If we are opening a device, query its size first
- if (bRawDevice)
- {
- PARTITION_INFORMATION pi;
- PARTITION_INFORMATION_EX pix;
- LARGE_INTEGER diskLengthInfo;
- DISK_GEOMETRY dg;
- STORAGE_PROPERTY_QUERY storagePropertyQuery = {0};
- STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR storageDescriptor = {0};
-
- ntStatus = IoGetDeviceObjectPointer (&FullFileName,
- FILE_READ_DATA | FILE_READ_ATTRIBUTES,
- &Extension->pfoDeviceFile,
- &Extension->pFsdDevice);
-
- if (!NT_SUCCESS (ntStatus))
- goto error;
-
- ntStatus = TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_DRIVE_GEOMETRY, (char *) &dg, sizeof (dg));
- if (!NT_SUCCESS (ntStatus))
- goto error;
-
- lDiskLength.QuadPart = dg.Cylinders.QuadPart * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.BytesPerSector;
- Extension->HostBytesPerSector = dg.BytesPerSector;
-
- storagePropertyQuery.PropertyId = StorageAccessAlignmentProperty;
- storagePropertyQuery.QueryType = PropertyStandardQuery;
-
- /* IOCTL_STORAGE_QUERY_PROPERTY supported only on Vista and above */
- if (NT_SUCCESS (TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IOCTL_STORAGE_QUERY_PROPERTY,
- (char*) &storagePropertyQuery, sizeof(storagePropertyQuery),
- (char *) &storageDescriptor, sizeof (storageDescriptor))))
- {
- Extension->HostBytesPerPhysicalSector = storageDescriptor.BytesPerPhysicalSector;
- }
- else
- {
- Extension->HostBytesPerPhysicalSector = dg.BytesPerSector;
- }
-
- // Drive geometry is used only when IOCTL_DISK_GET_PARTITION_INFO fails
- if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO_EX, (char *) &pix, sizeof (pix))))
- {
- lDiskLength.QuadPart = pix.PartitionLength.QuadPart;
- partitionStartingOffset = pix.StartingOffset.QuadPart;
- }
- // Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX
- else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO, (char *) &pi, sizeof (pi))))
- {
- lDiskLength.QuadPart = pi.PartitionLength.QuadPart;
- partitionStartingOffset = pi.StartingOffset.QuadPart;
- }
- else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_LENGTH_INFO, &diskLengthInfo, sizeof (diskLengthInfo))))
- {
- lDiskLength = diskLengthInfo;
- }
-
- ProbingHostDeviceForWrite = TRUE;
-
- if (!mount->bMountReadOnly
- && TCSendHostDeviceIoControlRequest (DeviceObject, Extension,
- IsHiddenSystemRunning() ? TC_IOCTL_DISK_IS_WRITABLE : IOCTL_DISK_IS_WRITABLE, NULL, 0) == STATUS_MEDIA_WRITE_PROTECTED)
- {
- mount->bMountReadOnly = TRUE;
- DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
- mount->VolumeMountedReadOnlyAfterDeviceWriteProtected = TRUE;
- }
-
- ProbingHostDeviceForWrite = FALSE;
-
- // Some Windows tools (e.g. diskmgmt, diskpart, vssadmin) fail or experience timeouts when there is a raw device
- // open for exclusive access. Therefore, exclusive access is used only for file-hosted volumes.
- // Applications requiring a consistent device image need to acquire exclusive write access first. This is prevented
- // when a device-hosted volume is mounted.
-
- exclusiveAccess = FALSE;
- }
- else
- {
- // Limit the maximum required buffer size
- if (mount->BytesPerSector > 128 * BYTES_PER_KB)
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- goto error;
- }
-
- Extension->HostBytesPerSector = mount->BytesPerSector;
- Extension->HostBytesPerPhysicalSector = mount->BytesPerPhysicalSector;
-
- if (Extension->HostBytesPerSector != TC_SECTOR_SIZE_FILE_HOSTED_VOLUME)
- disableBuffering = FALSE;
- }
-
- // Open the volume hosting file/device
- if (!mount->bMountReadOnly)
- {
- ntStatus = ZwCreateFile (&Extension->hDeviceFile,
- GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
- &oaFileAttributes,
- &IoStatusBlock,
- NULL,
- FILE_ATTRIBUTE_NORMAL |
- FILE_ATTRIBUTE_SYSTEM,
- exclusiveAccess ? 0 : FILE_SHARE_READ | FILE_SHARE_WRITE,
- FILE_OPEN,
- FILE_RANDOM_ACCESS |
- FILE_WRITE_THROUGH |
- (disableBuffering ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
- FILE_SYNCHRONOUS_IO_NONALERT,
- NULL,
- 0);
- }
-
- /* 26-4-99 NT for some partitions returns this code, it is really a access denied */
- if (ntStatus == 0xc000001b)
- ntStatus = STATUS_ACCESS_DENIED;
-
- mount->VolumeMountedReadOnlyAfterAccessDenied = FALSE;
-
- if (mount->bMountReadOnly || ntStatus == STATUS_ACCESS_DENIED)
- {
- ntStatus = ZwCreateFile (&Extension->hDeviceFile,
- GENERIC_READ | SYNCHRONIZE,
- &oaFileAttributes,
- &IoStatusBlock,
- NULL,
- FILE_ATTRIBUTE_NORMAL |
- FILE_ATTRIBUTE_SYSTEM,
- exclusiveAccess ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE,
- FILE_OPEN,
- FILE_RANDOM_ACCESS |
- FILE_WRITE_THROUGH |
- (disableBuffering ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
- FILE_SYNCHRONOUS_IO_NONALERT,
- NULL,
- 0);
-
- if (NT_SUCCESS (ntStatus) && !mount->bMountReadOnly)
- mount->VolumeMountedReadOnlyAfterAccessDenied = TRUE;
-
- Extension->bReadOnly = TRUE;
- DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
- }
- else
- Extension->bReadOnly = FALSE;
-
- /* 26-4-99 NT for some partitions returns this code, it is really a
- access denied */
- if (ntStatus == 0xc000001b)
- {
- /* Partitions which return this code can still be opened with
- FILE_SHARE_READ but this causes NT problems elsewhere in
- particular if you do FILE_SHARE_READ NT will die later if
- anyone even tries to open the partition (or file for that
- matter...) */
- ntStatus = STATUS_SHARING_VIOLATION;
- }
-
- if (!NT_SUCCESS (ntStatus))
- {
- goto error;
- }
-
- // If we have opened a file, query its size now
- if (bRawDevice == FALSE)
- {
- ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
- &IoStatusBlock,
- &FileBasicInfo,
- sizeof (FileBasicInfo),
- FileBasicInformation);
-
- if (NT_SUCCESS (ntStatus))
- {
- if (mount->bPreserveTimestamp)
- {
- Extension->fileCreationTime = FileBasicInfo.CreationTime;
- Extension->fileLastAccessTime = FileBasicInfo.LastAccessTime;
- Extension->fileLastWriteTime = FileBasicInfo.LastWriteTime;
- Extension->fileLastChangeTime = FileBasicInfo.ChangeTime;
- Extension->bTimeStampValid = TRUE;
- }
-
- ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
- &IoStatusBlock,
- &FileStandardInfo,
- sizeof (FileStandardInfo),
- FileStandardInformation);
- }
-
- if (!NT_SUCCESS (ntStatus))
- {
- Dump ("ZwQueryInformationFile failed while opening file: NTSTATUS 0x%08x\n",
- ntStatus);
- goto error;
- }
-
- lDiskLength.QuadPart = FileStandardInfo.EndOfFile.QuadPart;
-
- if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED)
- {
- Dump ("File \"%ls\" is marked as compressed - not supported!\n", pwszMountVolume);
- mount->nReturnCode = ERR_COMPRESSION_NOT_SUPPORTED;
- ntStatus = STATUS_SUCCESS;
- goto error;
- }
-
- ntStatus = ObReferenceObjectByHandle (Extension->hDeviceFile,
- FILE_ALL_ACCESS,
- *IoFileObjectType,
- KernelMode,
- &Extension->pfoDeviceFile,
- 0);
-
- if (!NT_SUCCESS (ntStatus))
- {
- goto error;
- }
-
- /* Get the FSD device for the file (probably either NTFS or FAT) */
- Extension->pFsdDevice = IoGetRelatedDeviceObject (Extension->pfoDeviceFile);
- }
- else
- {
- // Try to gain "raw" access to the partition in case there is a live filesystem on it (otherwise,
- // the NTFS driver guards hidden sectors and prevents mounting using a backup header e.g. after the user
- // accidentally quick-formats a dismounted partition-hosted TrueCrypt volume as NTFS).
-
- PFILE_OBJECT pfoTmpDeviceFile = NULL;
-
- if (NT_SUCCESS (ObReferenceObjectByHandle (Extension->hDeviceFile, FILE_ALL_ACCESS, *IoFileObjectType, KernelMode, &pfoTmpDeviceFile, NULL))
- && pfoTmpDeviceFile != NULL)
- {
- TCFsctlCall (pfoTmpDeviceFile, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0);
- ObDereferenceObject (pfoTmpDeviceFile);
- }
- }
-
- // Check volume size
- if (lDiskLength.QuadPart < TC_MIN_VOLUME_SIZE_LEGACY || lDiskLength.QuadPart > TC_MAX_VOLUME_SIZE)
- {
- mount->nReturnCode = ERR_VOL_SIZE_WRONG;
- ntStatus = STATUS_SUCCESS;
- goto error;
- }
-
- Extension->DiskLength = lDiskLength.QuadPart;
- Extension->HostLength = lDiskLength.QuadPart;
-
- readBuffer = TCalloc (max (max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, PAGE_SIZE), Extension->HostBytesPerSector));
- if (readBuffer == NULL)
- {
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- goto error;
- }
-
- // Go through all volume types (e.g., normal, hidden)
- for (volumeType = TC_VOLUME_TYPE_NORMAL;
- volumeType < TC_VOLUME_TYPE_COUNT;
- volumeType++)
- {
- Dump ("Trying to open volume type %d\n", volumeType);
-
- /* Read the volume header */
-
- if (!mount->bPartitionInInactiveSysEncScope
- || (mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_HIDDEN))
- {
- // Header of a volume that is not within the scope of system encryption, or
- // header of a system hidden volume (containing a hidden OS)
-
- LARGE_INTEGER headerOffset;
-
- if (mount->UseBackupHeader && lDiskLength.QuadPart <= TC_TOTAL_VOLUME_HEADERS_SIZE)
- continue;
-
- switch (volumeType)
- {
- case TC_VOLUME_TYPE_NORMAL:
- headerOffset.QuadPart = mount->UseBackupHeader ? lDiskLength.QuadPart - TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET;
- break;
-
- case TC_VOLUME_TYPE_HIDDEN:
- if (lDiskLength.QuadPart <= TC_VOLUME_HEADER_GROUP_SIZE)
- continue;
-
- headerOffset.QuadPart = mount->UseBackupHeader ? lDiskLength.QuadPart - TC_HIDDEN_VOLUME_HEADER_OFFSET : TC_HIDDEN_VOLUME_HEADER_OFFSET;
- break;
- }
-
- Dump ("Reading volume header at %I64d\n", headerOffset.QuadPart);
-
- ntStatus = ZwReadFile (Extension->hDeviceFile,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- readBuffer,
- bRawDevice ? max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, Extension->HostBytesPerSector) : TC_VOLUME_HEADER_EFFECTIVE_SIZE,
- &headerOffset,
- NULL);
- }
- else
- {
- // Header of a partition that is within the scope of system encryption
-
- WCHAR parentDrivePath [47+1] = {0};
- HANDLE hParentDeviceFile = NULL;
- UNICODE_STRING FullParentPath;
- OBJECT_ATTRIBUTES oaParentFileAttributes;
- LARGE_INTEGER parentKeyDataOffset;
-
- RtlStringCbPrintfW (parentDrivePath,
- sizeof (parentDrivePath),
- WIDE ("\\Device\\Harddisk%d\\Partition0"),
- mount->nPartitionInInactiveSysEncScopeDriveNo);
-
- Dump ("Mounting partition within scope of system encryption (reading key data from: %ls)\n", parentDrivePath);
-
- RtlInitUnicodeString (&FullParentPath, parentDrivePath);
- InitializeObjectAttributes (&oaParentFileAttributes, &FullParentPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
-
- ntStatus = ZwCreateFile (&hParentDeviceFile,
- GENERIC_READ | SYNCHRONIZE,
- &oaParentFileAttributes,
- &IoStatusBlock,
- NULL,
- FILE_ATTRIBUTE_NORMAL |
- FILE_ATTRIBUTE_SYSTEM,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- FILE_OPEN,
- FILE_RANDOM_ACCESS |
- FILE_WRITE_THROUGH |
- FILE_NO_INTERMEDIATE_BUFFERING |
- FILE_SYNCHRONOUS_IO_NONALERT,
- NULL,
- 0);
-
- if (!NT_SUCCESS (ntStatus))
- {
- if (hParentDeviceFile != NULL)
- ZwClose (hParentDeviceFile);
-
- Dump ("Cannot open %ls\n", parentDrivePath);
-
- goto error;
- }
-
- parentKeyDataOffset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
-
- ntStatus = ZwReadFile (hParentDeviceFile,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- readBuffer,
- max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, Extension->HostBytesPerSector),
- &parentKeyDataOffset,
- NULL);
-
- if (hParentDeviceFile != NULL)
- ZwClose (hParentDeviceFile);
- }
-
- if (!NT_SUCCESS (ntStatus) && ntStatus != STATUS_END_OF_FILE)
- {
- Dump ("Read failed: NTSTATUS 0x%08x\n", ntStatus);
- goto error;
- }
-
- if (ntStatus == STATUS_END_OF_FILE || IoStatusBlock.Information < TC_VOLUME_HEADER_EFFECTIVE_SIZE)
- {
- Dump ("Read didn't read enough data\n");
-
- // If FSCTL_ALLOW_EXTENDED_DASD_IO failed and there is a live filesystem on the partition, then the
- // filesystem driver may report EOF when we are reading hidden sectors (when the filesystem is
- // shorter than the partition). This can happen for example after the user quick-formats a dismounted
- // partition-hosted TrueCrypt volume and then tries to mount the volume using the embedded backup header.
- memset (readBuffer, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
- }
-
- /* Attempt to recognize the volume (decrypt the header) */
-
- ReadVolumeHeaderRecoveryMode = mount->RecoveryMode;
-
- if ((volumeType == TC_VOLUME_TYPE_HIDDEN) && mount->bProtectHiddenVolume)
- {
- mount->nReturnCode = ReadVolumeHeaderWCache (
- FALSE,
- mount->bCache,
- mount->bCachePim,
- readBuffer,
- &mount->ProtectedHidVolPassword,
- mount->ProtectedHidVolPkcs5Prf,
- mount->ProtectedHidVolPim,
- mount->bTrueCryptMode,
- &tmpCryptoInfo);
- }
- else
- {
- mount->nReturnCode = ReadVolumeHeaderWCache (
- mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_NORMAL,
- mount->bCache,
- mount->bCachePim,
- readBuffer,
- &mount->VolumePassword,
- mount->pkcs5_prf,
- mount->VolumePim,
- mount->bTrueCryptMode,
- &Extension->cryptoInfo);
- }
-
- ReadVolumeHeaderRecoveryMode = FALSE;
-
- if (mount->nReturnCode == 0 || mount->nReturnCode == ERR_CIPHER_INIT_WEAK_KEY)
- {
- /* Volume header successfully decrypted */
-
- if (!Extension->cryptoInfo)
- {
- /* should never happen */
- mount->nReturnCode = ERR_OUTOFMEMORY;
- ntStatus = STATUS_SUCCESS;
- goto error;
- }
-
- Dump ("Volume header decrypted\n");
- Dump ("Required program version = %x\n", (int) Extension->cryptoInfo->RequiredProgramVersion);
- Dump ("Legacy volume = %d\n", (int) Extension->cryptoInfo->LegacyVolume);
-
- if (IsHiddenSystemRunning() && !Extension->cryptoInfo->hiddenVolume)
- {
- Extension->bReadOnly = mount->bMountReadOnly = TRUE;
- HiddenSysLeakProtectionCount++;
- }
-
- Extension->cryptoInfo->bProtectHiddenVolume = FALSE;
- Extension->cryptoInfo->bHiddenVolProtectionAction = FALSE;
-
- Extension->cryptoInfo->bPartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope;
-
- /* compute the ID of this volume: SHA-512 of the effective header */
- sha256 (Extension->volumeID, readBuffer, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
-
- if (volumeType == TC_VOLUME_TYPE_NORMAL)
- {
- if (mount->bPartitionInInactiveSysEncScope)
- {
- if (Extension->cryptoInfo->EncryptedAreaStart.Value > (unsigned __int64) partitionStartingOffset
- || Extension->cryptoInfo->EncryptedAreaStart.Value + Extension->cryptoInfo->VolumeSize.Value <= (unsigned __int64) partitionStartingOffset)
- {
- // The partition is not within the key scope of system encryption
- mount->nReturnCode = ERR_PASSWORD_WRONG;
- ntStatus = STATUS_SUCCESS;
- goto error;
- }
-
- if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
- {
- // Partial encryption is not supported for volumes mounted as regular
- mount->nReturnCode = ERR_ENCRYPTION_NOT_COMPLETED;
- ntStatus = STATUS_SUCCESS;
- goto error;
- }
- }
- else if (Extension->cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC)
- {
- if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
- {
- // Non-system in-place encryption process has not been completed on this volume
- mount->nReturnCode = ERR_NONSYS_INPLACE_ENC_INCOMPLETE;
- ntStatus = STATUS_SUCCESS;
- goto error;
- }
- }
- }
-
- Extension->cryptoInfo->FirstDataUnitNo.Value = 0;
-
- if (Extension->cryptoInfo->hiddenVolume && IsHiddenSystemRunning())
- {
- // Prevent mount of a hidden system partition if the system hosted on it is currently running
- if (memcmp (Extension->cryptoInfo->master_keydata, GetSystemDriveCryptoInfo()->master_keydata, EAGetKeySize (Extension->cryptoInfo->ea)) == 0)
- {
- mount->nReturnCode = ERR_VOL_ALREADY_MOUNTED;
- ntStatus = STATUS_SUCCESS;
- goto error;
- }
- }
-
- switch (volumeType)
- {
- case TC_VOLUME_TYPE_NORMAL:
-
- Extension->cryptoInfo->hiddenVolume = FALSE;
-
- if (mount->bPartitionInInactiveSysEncScope)
- {
- Extension->cryptoInfo->volDataAreaOffset = 0;
- Extension->DiskLength = lDiskLength.QuadPart;
- Extension->cryptoInfo->FirstDataUnitNo.Value = partitionStartingOffset / ENCRYPTION_DATA_UNIT_SIZE;
- }
- else if (Extension->cryptoInfo->LegacyVolume)
- {
- Extension->cryptoInfo->volDataAreaOffset = TC_VOLUME_HEADER_SIZE_LEGACY;
- Extension->DiskLength = lDiskLength.QuadPart - TC_VOLUME_HEADER_SIZE_LEGACY;
- }
- else
- {
- Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->EncryptedAreaStart.Value;
- Extension->DiskLength = Extension->cryptoInfo->VolumeSize.Value;
- }
-
- break;
-
- case TC_VOLUME_TYPE_HIDDEN:
-
- cryptoInfoPtr = mount->bProtectHiddenVolume ? tmpCryptoInfo : Extension->cryptoInfo;
-
- Extension->cryptoInfo->hiddenVolumeOffset = cryptoInfoPtr->EncryptedAreaStart.Value;
-
- Dump ("Hidden volume offset = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset);
- Dump ("Hidden volume size = %I64d\n", cryptoInfoPtr->hiddenVolumeSize);
- Dump ("Hidden volume end = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset + cryptoInfoPtr->hiddenVolumeSize - 1);
-
- // Validate the offset
- if (Extension->cryptoInfo->hiddenVolumeOffset % ENCRYPTION_DATA_UNIT_SIZE != 0)
- {
- mount->nReturnCode = ERR_VOL_SIZE_WRONG;
- ntStatus = STATUS_SUCCESS;
- goto error;
- }
-
- // If we are supposed to actually mount the hidden volume (not just to protect it)
- if (!mount->bProtectHiddenVolume)
- {
- Extension->DiskLength = cryptoInfoPtr->hiddenVolumeSize;
- Extension->cryptoInfo->hiddenVolume = TRUE;
- Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->hiddenVolumeOffset;
- }
- else
- {
- // Hidden volume protection
- Extension->cryptoInfo->hiddenVolume = FALSE;
- Extension->cryptoInfo->bProtectHiddenVolume = TRUE;
-
- Extension->cryptoInfo->hiddenVolumeProtectedSize = tmpCryptoInfo->hiddenVolumeSize;
-
- Dump ("Hidden volume protection active: %I64d-%I64d (%I64d)\n", Extension->cryptoInfo->hiddenVolumeOffset, Extension->cryptoInfo->hiddenVolumeProtectedSize + Extension->cryptoInfo->hiddenVolumeOffset - 1, Extension->cryptoInfo->hiddenVolumeProtectedSize);
- }
-
- break;
- }
-
- Dump ("Volume data offset = %I64d\n", Extension->cryptoInfo->volDataAreaOffset);
- Dump ("Volume data size = %I64d\n", Extension->DiskLength);
- Dump ("Volume data end = %I64d\n", Extension->cryptoInfo->volDataAreaOffset + Extension->DiskLength - 1);
-
- if (Extension->DiskLength == 0)
- {
- Dump ("Incorrect volume size\n");
- continue;
- }
-
- // If this is a hidden volume, make sure we are supposed to actually
- // mount it (i.e. not just to protect it)
- if (volumeType == TC_VOLUME_TYPE_NORMAL || !mount->bProtectHiddenVolume)
- {
- // Validate sector size
- if (bRawDevice && Extension->cryptoInfo->SectorSize != Extension->HostBytesPerSector)
- {
- mount->nReturnCode = ERR_PARAMETER_INCORRECT;
- ntStatus = STATUS_SUCCESS;
- goto error;
- }
-
- // Calculate virtual volume geometry
- Extension->TracksPerCylinder = 1;
- Extension->SectorsPerTrack = 1;
- Extension->BytesPerSector = Extension->cryptoInfo->SectorSize;
- Extension->NumberOfCylinders = Extension->DiskLength / Extension->BytesPerSector;
- Extension->PartitionType = 0;
-
- Extension->bRawDevice = bRawDevice;
-
- memset (Extension->wszVolume, 0, sizeof (Extension->wszVolume));
- if (wcsstr (pwszMountVolume, WIDE ("\\??\\UNC\\")) == pwszMountVolume)
- {
- /* UNC path */
- RtlStringCbPrintfW (Extension->wszVolume,
- sizeof (Extension->wszVolume),
- WIDE ("\\??\\\\%s"),
- pwszMountVolume + 7);
- }
- else
- {
- RtlStringCbCopyW (Extension->wszVolume, sizeof(Extension->wszVolume),pwszMountVolume);
- }
-
- memset (Extension->wszLabel, 0, sizeof (Extension->wszLabel));
- RtlStringCbCopyW (Extension->wszLabel, sizeof(Extension->wszLabel), mount->wszLabel);
- }
-
- // If we are to protect a hidden volume we cannot exit yet, for we must also
- // decrypt the hidden volume header.
- if (!(volumeType == TC_VOLUME_TYPE_NORMAL && mount->bProtectHiddenVolume))
- {
- TCfree (readBuffer);
-
- if (tmpCryptoInfo != NULL)
- {
- crypto_close (tmpCryptoInfo);
- tmpCryptoInfo = NULL;
- }
-
- return STATUS_SUCCESS;
- }
- }
- else if ((mount->bProtectHiddenVolume && volumeType == TC_VOLUME_TYPE_NORMAL)
- || mount->nReturnCode != ERR_PASSWORD_WRONG)
- {
- /* If we are not supposed to protect a hidden volume, the only error that is
- tolerated is ERR_PASSWORD_WRONG (to allow mounting a possible hidden volume).
-
- If we _are_ supposed to protect a hidden volume, we do not tolerate any error
- (both volume headers must be successfully decrypted). */
-
- break;
- }
- }
-
- /* Failed due to some non-OS reason so we drop through and return NT
- SUCCESS then nReturnCode is checked later in user-mode */
-
- if (mount->nReturnCode == ERR_OUTOFMEMORY)
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- else
- ntStatus = STATUS_SUCCESS;
-
-error:
- if (mount->nReturnCode == ERR_SUCCESS)
- mount->nReturnCode = ERR_PASSWORD_WRONG;
-
- if (tmpCryptoInfo != NULL)
- {
- crypto_close (tmpCryptoInfo);
- tmpCryptoInfo = NULL;
- }
-
- if (Extension->cryptoInfo)
- {
- crypto_close (Extension->cryptoInfo);
- Extension->cryptoInfo = NULL;
- }
-
- if (Extension->bTimeStampValid)
- {
- RestoreTimeStamp (Extension);
- }
-
- /* Close the hDeviceFile */
- if (Extension->hDeviceFile != NULL)
- ZwClose (Extension->hDeviceFile);
-
- /* The cryptoInfo pointer is deallocated if the readheader routines
- fail so there is no need to deallocate here */
-
- /* Dereference the user-mode file object */
- if (Extension->pfoDeviceFile != NULL)
- ObDereferenceObject (Extension->pfoDeviceFile);
-
- /* Free the tmp IO buffers */
- if (readBuffer != NULL)
- TCfree (readBuffer);
-
- return ntStatus;
-}
-
-void TCCloseVolume (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
-{
- UNREFERENCED_PARAMETER (DeviceObject); /* Remove compiler warning */
-
- if (Extension->hDeviceFile != NULL)
- {
- if (Extension->bRawDevice == FALSE
- && Extension->bTimeStampValid)
- {
- RestoreTimeStamp (Extension);
- }
- ZwClose (Extension->hDeviceFile);
- }
- ObDereferenceObject (Extension->pfoDeviceFile);
- if (Extension->cryptoInfo)
- {
- crypto_close (Extension->cryptoInfo);
- Extension->cryptoInfo = NULL;
- }
-}
-
-
-NTSTATUS TCSendHostDeviceIoControlRequestEx (PDEVICE_OBJECT DeviceObject,
- PEXTENSION Extension,
- ULONG IoControlCode,
- void *InputBuffer,
- ULONG InputBufferSize,
- void *OutputBuffer,
- ULONG OutputBufferSize)
-{
- IO_STATUS_BLOCK IoStatusBlock;
- NTSTATUS ntStatus;
- PIRP Irp;
-
- UNREFERENCED_PARAMETER(DeviceObject); /* Remove compiler warning */
-
- KeClearEvent (&Extension->keVolumeEvent);
-
- Irp = IoBuildDeviceIoControlRequest (IoControlCode,
- Extension->pFsdDevice,
- InputBuffer, InputBufferSize,
- OutputBuffer, OutputBufferSize,
- FALSE,
- &Extension->keVolumeEvent,
- &IoStatusBlock);
-
- if (Irp == NULL)
- {
- Dump ("IRP allocation failed\n");
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- // Disk device may be used by filesystem driver which needs file object
- IoGetNextIrpStackLocation (Irp) -> FileObject = Extension->pfoDeviceFile;
-
- ntStatus = IoCallDriver (Extension->pFsdDevice, Irp);
- if (ntStatus == STATUS_PENDING)
- {
- KeWaitForSingleObject (&Extension->keVolumeEvent, Executive, KernelMode, FALSE, NULL);
- ntStatus = IoStatusBlock.Status;
- }
-
- return ntStatus;
-}
-
-NTSTATUS TCSendHostDeviceIoControlRequest (PDEVICE_OBJECT DeviceObject,
- PEXTENSION Extension,
- ULONG IoControlCode,
- void *OutputBuffer,
- ULONG OutputBufferSize)
-{
- return TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IoControlCode, NULL, 0, OutputBuffer, OutputBufferSize);
-}
-
-NTSTATUS COMPLETE_IRP (PDEVICE_OBJECT DeviceObject,
- PIRP Irp,
- NTSTATUS IrpStatus,
- ULONG_PTR IrpInformation)
-{
- Irp->IoStatus.Status = IrpStatus;
- Irp->IoStatus.Information = IrpInformation;
-
- UNREFERENCED_PARAMETER (DeviceObject); /* Remove compiler warning */
-
-#if EXTRA_INFO
- if (!NT_SUCCESS (IrpStatus))
- {
- PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
- Dump ("COMPLETE_IRP FAILING IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
- (ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
- }
- else
- {
- PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
- Dump ("COMPLETE_IRP SUCCESS IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
- (ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
- }
-#endif
- IoCompleteRequest (Irp, IO_NO_INCREMENT);
- return IrpStatus;
-}
-
-
-static void RestoreTimeStamp (PEXTENSION Extension)
-{
- NTSTATUS ntStatus;
- FILE_BASIC_INFORMATION FileBasicInfo;
- IO_STATUS_BLOCK IoStatusBlock;
-
- if (Extension->hDeviceFile != NULL
- && Extension->bRawDevice == FALSE
- && Extension->bReadOnly == FALSE
- && Extension->bTimeStampValid)
- {
- ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
- &IoStatusBlock,
- &FileBasicInfo,
- sizeof (FileBasicInfo),
- FileBasicInformation);
-
- if (!NT_SUCCESS (ntStatus))
- {
- Dump ("ZwQueryInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",
- ntStatus);
- }
- else
- {
- FileBasicInfo.CreationTime = Extension->fileCreationTime;
- FileBasicInfo.LastAccessTime = Extension->fileLastAccessTime;
- FileBasicInfo.LastWriteTime = Extension->fileLastWriteTime;
- FileBasicInfo.ChangeTime = Extension->fileLastChangeTime;
-
- ntStatus = ZwSetInformationFile(
- Extension->hDeviceFile,
- &IoStatusBlock,
- &FileBasicInfo,
- sizeof (FileBasicInfo),
- FileBasicInformation);
-
- if (!NT_SUCCESS (ntStatus))
- Dump ("ZwSetInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",ntStatus);
- }
- }
-}
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of TrueCrypt 7.1a, which is
+ Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
+ governed by the TrueCrypt License 3.0, also from the source code of
+ Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
+ and which is governed by the 'License Agreement for Encryption for the Masses'
+ 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 <wchar.h>
+#include "Crypto.h"
+#include "Volumes.h"
+
+#include "Apidrvr.h"
+#include "DriveFilter.h"
+#include "Ntdriver.h"
+#include "Ntvol.h"
+#include "VolumeFilter.h"
+
+#include "Boot/Windows/BootCommon.h"
+
+#include "Cache.h"
+
+#if 0 && _DEBUG
+#define EXTRA_INFO 1
+#endif
+
+#pragma warning( disable : 4127 )
+
+#include <Ntstrsafe.h>
+
+volatile BOOL ProbingHostDeviceForWrite = FALSE;
+
+
+NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
+ PEXTENSION Extension,
+ MOUNT_STRUCT *mount,
+ PWSTR pwszMountVolume,
+ BOOL bRawDevice)
+{
+ FILE_STANDARD_INFORMATION FileStandardInfo;
+ FILE_BASIC_INFORMATION FileBasicInfo;
+ OBJECT_ATTRIBUTES oaFileAttributes;
+ UNICODE_STRING FullFileName;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PCRYPTO_INFO cryptoInfoPtr = NULL;
+ PCRYPTO_INFO tmpCryptoInfo = NULL;
+ LARGE_INTEGER lDiskLength;
+ __int64 partitionStartingOffset = 0;
+ int volumeType;
+ char *readBuffer = 0;
+ NTSTATUS ntStatus = 0;
+ BOOL forceAccessCheck = (!bRawDevice && !(OsMajorVersion == 5 &&OsMinorVersion == 0)); // Windows 2000 does not support OBJ_FORCE_ACCESS_CHECK attribute
+ BOOL disableBuffering = TRUE;
+ BOOL exclusiveAccess = mount->bExclusiveAccess;
+
+ Extension->pfoDeviceFile = NULL;
+ Extension->hDeviceFile = NULL;
+ Extension->bTimeStampValid = FALSE;
+
+ RtlInitUnicodeString (&FullFileName, pwszMountVolume);
+ InitializeObjectAttributes (&oaFileAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | (forceAccessCheck ? OBJ_FORCE_ACCESS_CHECK : 0) | OBJ_KERNEL_HANDLE, NULL, NULL);
+ KeInitializeEvent (&Extension->keVolumeEvent, NotificationEvent, FALSE);
+
+ if (Extension->SecurityClientContextValid)
+ {
+ ntStatus = SeImpersonateClientEx (&Extension->SecurityClientContext, NULL);
+ if (!NT_SUCCESS (ntStatus))
+ goto error;
+ }
+
+ mount->VolumeMountedReadOnlyAfterDeviceWriteProtected = FALSE;
+
+ // If we are opening a device, query its size first
+ if (bRawDevice)
+ {
+ PARTITION_INFORMATION pi;
+ PARTITION_INFORMATION_EX pix;
+ LARGE_INTEGER diskLengthInfo;
+ DISK_GEOMETRY dg;
+ STORAGE_PROPERTY_QUERY storagePropertyQuery = {0};
+ STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR storageDescriptor = {0};
+
+ ntStatus = IoGetDeviceObjectPointer (&FullFileName,
+ FILE_READ_DATA | FILE_READ_ATTRIBUTES,
+ &Extension->pfoDeviceFile,
+ &Extension->pFsdDevice);
+
+ if (!NT_SUCCESS (ntStatus))
+ goto error;
+
+ ntStatus = TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_DRIVE_GEOMETRY, (char *) &dg, sizeof (dg));
+ if (!NT_SUCCESS (ntStatus))
+ goto error;
+
+ lDiskLength.QuadPart = dg.Cylinders.QuadPart * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.BytesPerSector;
+ Extension->HostBytesPerSector = dg.BytesPerSector;
+
+ storagePropertyQuery.PropertyId = StorageAccessAlignmentProperty;
+ storagePropertyQuery.QueryType = PropertyStandardQuery;
+
+ /* IOCTL_STORAGE_QUERY_PROPERTY supported only on Vista and above */
+ if (NT_SUCCESS (TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IOCTL_STORAGE_QUERY_PROPERTY,
+ (char*) &storagePropertyQuery, sizeof(storagePropertyQuery),
+ (char *) &storageDescriptor, sizeof (storageDescriptor))))
+ {
+ Extension->HostBytesPerPhysicalSector = storageDescriptor.BytesPerPhysicalSector;
+ }
+ else
+ {
+ Extension->HostBytesPerPhysicalSector = dg.BytesPerSector;
+ }
+
+ // Drive geometry is used only when IOCTL_DISK_GET_PARTITION_INFO fails
+ if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO_EX, (char *) &pix, sizeof (pix))))
+ {
+ lDiskLength.QuadPart = pix.PartitionLength.QuadPart;
+ partitionStartingOffset = pix.StartingOffset.QuadPart;
+ }
+ // Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX
+ else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO, (char *) &pi, sizeof (pi))))
+ {
+ lDiskLength.QuadPart = pi.PartitionLength.QuadPart;
+ partitionStartingOffset = pi.StartingOffset.QuadPart;
+ }
+ else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_LENGTH_INFO, &diskLengthInfo, sizeof (diskLengthInfo))))
+ {
+ lDiskLength = diskLengthInfo;
+ }
+
+ ProbingHostDeviceForWrite = TRUE;
+
+ if (!mount->bMountReadOnly
+ && TCSendHostDeviceIoControlRequest (DeviceObject, Extension,
+ IsHiddenSystemRunning() ? TC_IOCTL_DISK_IS_WRITABLE : IOCTL_DISK_IS_WRITABLE, NULL, 0) == STATUS_MEDIA_WRITE_PROTECTED)
+ {
+ mount->bMountReadOnly = TRUE;
+ DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
+ mount->VolumeMountedReadOnlyAfterDeviceWriteProtected = TRUE;
+ }
+
+ ProbingHostDeviceForWrite = FALSE;
+
+ // Some Windows tools (e.g. diskmgmt, diskpart, vssadmin) fail or experience timeouts when there is a raw device
+ // open for exclusive access. Therefore, exclusive access is used only for file-hosted volumes.
+ // Applications requiring a consistent device image need to acquire exclusive write access first. This is prevented
+ // when a device-hosted volume is mounted.
+
+ exclusiveAccess = FALSE;
+ }
+ else
+ {
+ // Limit the maximum required buffer size
+ if (mount->BytesPerSector > 128 * BYTES_PER_KB)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ goto error;
+ }
+
+ Extension->HostBytesPerSector = mount->BytesPerSector;
+ Extension->HostBytesPerPhysicalSector = mount->BytesPerPhysicalSector;
+
+ if (Extension->HostBytesPerSector != TC_SECTOR_SIZE_FILE_HOSTED_VOLUME)
+ disableBuffering = FALSE;
+ }
+
+ // Open the volume hosting file/device
+ if (!mount->bMountReadOnly)
+ {
+ ntStatus = ZwCreateFile (&Extension->hDeviceFile,
+ GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
+ &oaFileAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL |
+ FILE_ATTRIBUTE_SYSTEM,
+ exclusiveAccess ? 0 : FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_RANDOM_ACCESS |
+ FILE_WRITE_THROUGH |
+ (disableBuffering ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0);
+ }
+
+ /* 26-4-99 NT for some partitions returns this code, it is really a access denied */
+ if (ntStatus == 0xc000001b)
+ ntStatus = STATUS_ACCESS_DENIED;
+
+ mount->VolumeMountedReadOnlyAfterAccessDenied = FALSE;
+
+ if (mount->bMountReadOnly || ntStatus == STATUS_ACCESS_DENIED)
+ {
+ ntStatus = ZwCreateFile (&Extension->hDeviceFile,
+ GENERIC_READ | SYNCHRONIZE,
+ &oaFileAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL |
+ FILE_ATTRIBUTE_SYSTEM,
+ exclusiveAccess ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_RANDOM_ACCESS |
+ FILE_WRITE_THROUGH |
+ (disableBuffering ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0);
+
+ if (NT_SUCCESS (ntStatus) && !mount->bMountReadOnly)
+ mount->VolumeMountedReadOnlyAfterAccessDenied = TRUE;
+
+ Extension->bReadOnly = TRUE;
+ DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
+ }
+ else
+ Extension->bReadOnly = FALSE;
+
+ /* 26-4-99 NT for some partitions returns this code, it is really a
+ access denied */
+ if (ntStatus == 0xc000001b)
+ {
+ /* Partitions which return this code can still be opened with
+ FILE_SHARE_READ but this causes NT problems elsewhere in
+ particular if you do FILE_SHARE_READ NT will die later if
+ anyone even tries to open the partition (or file for that
+ matter...) */
+ ntStatus = STATUS_SHARING_VIOLATION;
+ }
+
+ if (!NT_SUCCESS (ntStatus))
+ {
+ goto error;
+ }
+
+ // If we have opened a file, query its size now
+ if (bRawDevice == FALSE)
+ {
+ ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
+ &IoStatusBlock,
+ &FileBasicInfo,
+ sizeof (FileBasicInfo),
+ FileBasicInformation);
+
+ if (NT_SUCCESS (ntStatus))
+ {
+ if (mount->bPreserveTimestamp)
+ {
+ Extension->fileCreationTime = FileBasicInfo.CreationTime;
+ Extension->fileLastAccessTime = FileBasicInfo.LastAccessTime;
+ Extension->fileLastWriteTime = FileBasicInfo.LastWriteTime;
+ Extension->fileLastChangeTime = FileBasicInfo.ChangeTime;
+ Extension->bTimeStampValid = TRUE;
+ }
+
+ ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
+ &IoStatusBlock,
+ &FileStandardInfo,
+ sizeof (FileStandardInfo),
+ FileStandardInformation);
+ }
+
+ if (!NT_SUCCESS (ntStatus))
+ {
+ Dump ("ZwQueryInformationFile failed while opening file: NTSTATUS 0x%08x\n",
+ ntStatus);
+ goto error;
+ }
+
+ lDiskLength.QuadPart = FileStandardInfo.EndOfFile.QuadPart;
+
+ if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED)
+ {
+ Dump ("File \"%ls\" is marked as compressed - not supported!\n", pwszMountVolume);
+ mount->nReturnCode = ERR_COMPRESSION_NOT_SUPPORTED;
+ ntStatus = STATUS_SUCCESS;
+ goto error;
+ }
+
+ ntStatus = ObReferenceObjectByHandle (Extension->hDeviceFile,
+ FILE_ALL_ACCESS,
+ *IoFileObjectType,
+ KernelMode,
+ &Extension->pfoDeviceFile,
+ 0);
+
+ if (!NT_SUCCESS (ntStatus))
+ {
+ goto error;
+ }
+
+ /* Get the FSD device for the file (probably either NTFS or FAT) */
+ Extension->pFsdDevice = IoGetRelatedDeviceObject (Extension->pfoDeviceFile);
+ }
+ else
+ {
+ // Try to gain "raw" access to the partition in case there is a live filesystem on it (otherwise,
+ // the NTFS driver guards hidden sectors and prevents mounting using a backup header e.g. after the user
+ // accidentally quick-formats a dismounted partition-hosted TrueCrypt volume as NTFS).
+
+ PFILE_OBJECT pfoTmpDeviceFile = NULL;
+
+ if (NT_SUCCESS (ObReferenceObjectByHandle (Extension->hDeviceFile, FILE_ALL_ACCESS, *IoFileObjectType, KernelMode, &pfoTmpDeviceFile, NULL))
+ && pfoTmpDeviceFile != NULL)
+ {
+ TCFsctlCall (pfoTmpDeviceFile, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0);
+ ObDereferenceObject (pfoTmpDeviceFile);
+ }
+ }
+
+ // Check volume size
+ if (lDiskLength.QuadPart < TC_MIN_VOLUME_SIZE_LEGACY || lDiskLength.QuadPart > TC_MAX_VOLUME_SIZE)
+ {
+ mount->nReturnCode = ERR_VOL_SIZE_WRONG;
+ ntStatus = STATUS_SUCCESS;
+ goto error;
+ }
+
+ Extension->DiskLength = lDiskLength.QuadPart;
+ Extension->HostLength = lDiskLength.QuadPart;
+
+ readBuffer = TCalloc (max (max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, PAGE_SIZE), Extension->HostBytesPerSector));
+ if (readBuffer == NULL)
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto error;
+ }
+
+ // Go through all volume types (e.g., normal, hidden)
+ for (volumeType = TC_VOLUME_TYPE_NORMAL;
+ volumeType < TC_VOLUME_TYPE_COUNT;
+ volumeType++)
+ {
+ Dump ("Trying to open volume type %d\n", volumeType);
+
+ /* Read the volume header */
+
+ if (!mount->bPartitionInInactiveSysEncScope
+ || (mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_HIDDEN))
+ {
+ // Header of a volume that is not within the scope of system encryption, or
+ // header of a system hidden volume (containing a hidden OS)
+
+ LARGE_INTEGER headerOffset;
+
+ if (mount->UseBackupHeader && lDiskLength.QuadPart <= TC_TOTAL_VOLUME_HEADERS_SIZE)
+ continue;
+
+ switch (volumeType)
+ {
+ case TC_VOLUME_TYPE_NORMAL:
+ headerOffset.QuadPart = mount->UseBackupHeader ? lDiskLength.QuadPart - TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET;
+ break;
+
+ case TC_VOLUME_TYPE_HIDDEN:
+ if (lDiskLength.QuadPart <= TC_VOLUME_HEADER_GROUP_SIZE)
+ continue;
+
+ headerOffset.QuadPart = mount->UseBackupHeader ? lDiskLength.QuadPart - TC_HIDDEN_VOLUME_HEADER_OFFSET : TC_HIDDEN_VOLUME_HEADER_OFFSET;
+ break;
+ }
+
+ Dump ("Reading volume header at %I64d\n", headerOffset.QuadPart);
+
+ ntStatus = ZwReadFile (Extension->hDeviceFile,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ readBuffer,
+ bRawDevice ? max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, Extension->HostBytesPerSector) : TC_VOLUME_HEADER_EFFECTIVE_SIZE,
+ &headerOffset,
+ NULL);
+ }
+ else
+ {
+ // Header of a partition that is within the scope of system encryption
+
+ WCHAR parentDrivePath [47+1] = {0};
+ HANDLE hParentDeviceFile = NULL;
+ UNICODE_STRING FullParentPath;
+ OBJECT_ATTRIBUTES oaParentFileAttributes;
+ LARGE_INTEGER parentKeyDataOffset;
+
+ RtlStringCbPrintfW (parentDrivePath,
+ sizeof (parentDrivePath),
+ WIDE ("\\Device\\Harddisk%d\\Partition0"),
+ mount->nPartitionInInactiveSysEncScopeDriveNo);
+
+ Dump ("Mounting partition within scope of system encryption (reading key data from: %ls)\n", parentDrivePath);
+
+ RtlInitUnicodeString (&FullParentPath, parentDrivePath);
+ InitializeObjectAttributes (&oaParentFileAttributes, &FullParentPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ ntStatus = ZwCreateFile (&hParentDeviceFile,
+ GENERIC_READ | SYNCHRONIZE,
+ &oaParentFileAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL |
+ FILE_ATTRIBUTE_SYSTEM,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_RANDOM_ACCESS |
+ FILE_WRITE_THROUGH |
+ FILE_NO_INTERMEDIATE_BUFFERING |
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0);
+
+ if (!NT_SUCCESS (ntStatus))
+ {
+ if (hParentDeviceFile != NULL)
+ ZwClose (hParentDeviceFile);
+
+ Dump ("Cannot open %ls\n", parentDrivePath);
+
+ goto error;
+ }
+
+ parentKeyDataOffset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
+
+ ntStatus = ZwReadFile (hParentDeviceFile,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ readBuffer,
+ max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, Extension->HostBytesPerSector),
+ &parentKeyDataOffset,
+ NULL);
+
+ if (hParentDeviceFile != NULL)
+ ZwClose (hParentDeviceFile);
+ }
+
+ if (!NT_SUCCESS (ntStatus) && ntStatus != STATUS_END_OF_FILE)
+ {
+ Dump ("Read failed: NTSTATUS 0x%08x\n", ntStatus);
+ goto error;
+ }
+
+ if (ntStatus == STATUS_END_OF_FILE || IoStatusBlock.Information < TC_VOLUME_HEADER_EFFECTIVE_SIZE)
+ {
+ Dump ("Read didn't read enough data\n");
+
+ // If FSCTL_ALLOW_EXTENDED_DASD_IO failed and there is a live filesystem on the partition, then the
+ // filesystem driver may report EOF when we are reading hidden sectors (when the filesystem is
+ // shorter than the partition). This can happen for example after the user quick-formats a dismounted
+ // partition-hosted TrueCrypt volume and then tries to mount the volume using the embedded backup header.
+ memset (readBuffer, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
+ }
+
+ /* Attempt to recognize the volume (decrypt the header) */
+
+ ReadVolumeHeaderRecoveryMode = mount->RecoveryMode;
+
+ if ((volumeType == TC_VOLUME_TYPE_HIDDEN) && mount->bProtectHiddenVolume)
+ {
+ mount->nReturnCode = ReadVolumeHeaderWCache (
+ FALSE,
+ mount->bCache,
+ mount->bCachePim,
+ readBuffer,
+ &mount->ProtectedHidVolPassword,
+ mount->ProtectedHidVolPkcs5Prf,
+ mount->ProtectedHidVolPim,
+ mount->bTrueCryptMode,
+ &tmpCryptoInfo);
+ }
+ else
+ {
+ mount->nReturnCode = ReadVolumeHeaderWCache (
+ mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_NORMAL,
+ mount->bCache,
+ mount->bCachePim,
+ readBuffer,
+ &mount->VolumePassword,
+ mount->pkcs5_prf,
+ mount->VolumePim,
+ mount->bTrueCryptMode,
+ &Extension->cryptoInfo);
+ }
+
+ ReadVolumeHeaderRecoveryMode = FALSE;
+
+ if (mount->nReturnCode == 0 || mount->nReturnCode == ERR_CIPHER_INIT_WEAK_KEY)
+ {
+ /* Volume header successfully decrypted */
+
+ if (!Extension->cryptoInfo)
+ {
+ /* should never happen */
+ mount->nReturnCode = ERR_OUTOFMEMORY;
+ ntStatus = STATUS_SUCCESS;
+ goto error;
+ }
+
+ Dump ("Volume header decrypted\n");
+ Dump ("Required program version = %x\n", (int) Extension->cryptoInfo->RequiredProgramVersion);
+ Dump ("Legacy volume = %d\n", (int) Extension->cryptoInfo->LegacyVolume);
+
+ if (IsHiddenSystemRunning() && !Extension->cryptoInfo->hiddenVolume)
+ {
+ Extension->bReadOnly = mount->bMountReadOnly = TRUE;
+ HiddenSysLeakProtectionCount++;
+ }
+
+ Extension->cryptoInfo->bProtectHiddenVolume = FALSE;
+ Extension->cryptoInfo->bHiddenVolProtectionAction = FALSE;
+
+ Extension->cryptoInfo->bPartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope;
+
+ /* compute the ID of this volume: SHA-512 of the effective header */
+ sha256 (Extension->volumeID, readBuffer, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
+
+ if (volumeType == TC_VOLUME_TYPE_NORMAL)
+ {
+ if (mount->bPartitionInInactiveSysEncScope)
+ {
+ if (Extension->cryptoInfo->EncryptedAreaStart.Value > (unsigned __int64) partitionStartingOffset
+ || Extension->cryptoInfo->EncryptedAreaStart.Value + Extension->cryptoInfo->VolumeSize.Value <= (unsigned __int64) partitionStartingOffset)
+ {
+ // The partition is not within the key scope of system encryption
+ mount->nReturnCode = ERR_PASSWORD_WRONG;
+ ntStatus = STATUS_SUCCESS;
+ goto error;
+ }
+
+ if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
+ {
+ // Partial encryption is not supported for volumes mounted as regular
+ mount->nReturnCode = ERR_ENCRYPTION_NOT_COMPLETED;
+ ntStatus = STATUS_SUCCESS;
+ goto error;
+ }
+ }
+ else if (Extension->cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC)
+ {
+ if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
+ {
+ // Non-system in-place encryption process has not been completed on this volume
+ mount->nReturnCode = ERR_NONSYS_INPLACE_ENC_INCOMPLETE;
+ ntStatus = STATUS_SUCCESS;
+ goto error;
+ }
+ }
+ }
+
+ Extension->cryptoInfo->FirstDataUnitNo.Value = 0;
+
+ if (Extension->cryptoInfo->hiddenVolume && IsHiddenSystemRunning())
+ {
+ // Prevent mount of a hidden system partition if the system hosted on it is currently running
+ if (memcmp (Extension->cryptoInfo->master_keydata, GetSystemDriveCryptoInfo()->master_keydata, EAGetKeySize (Extension->cryptoInfo->ea)) == 0)
+ {
+ mount->nReturnCode = ERR_VOL_ALREADY_MOUNTED;
+ ntStatus = STATUS_SUCCESS;
+ goto error;
+ }
+ }
+
+ switch (volumeType)
+ {
+ case TC_VOLUME_TYPE_NORMAL:
+
+ Extension->cryptoInfo->hiddenVolume = FALSE;
+
+ if (mount->bPartitionInInactiveSysEncScope)
+ {
+ Extension->cryptoInfo->volDataAreaOffset = 0;
+ Extension->DiskLength = lDiskLength.QuadPart;
+ Extension->cryptoInfo->FirstDataUnitNo.Value = partitionStartingOffset / ENCRYPTION_DATA_UNIT_SIZE;
+ }
+ else if (Extension->cryptoInfo->LegacyVolume)
+ {
+ Extension->cryptoInfo->volDataAreaOffset = TC_VOLUME_HEADER_SIZE_LEGACY;
+ Extension->DiskLength = lDiskLength.QuadPart - TC_VOLUME_HEADER_SIZE_LEGACY;
+ }
+ else
+ {
+ Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->EncryptedAreaStart.Value;
+ Extension->DiskLength = Extension->cryptoInfo->VolumeSize.Value;
+ }
+
+ break;
+
+ case TC_VOLUME_TYPE_HIDDEN:
+
+ cryptoInfoPtr = mount->bProtectHiddenVolume ? tmpCryptoInfo : Extension->cryptoInfo;
+
+ Extension->cryptoInfo->hiddenVolumeOffset = cryptoInfoPtr->EncryptedAreaStart.Value;
+
+ Dump ("Hidden volume offset = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset);
+ Dump ("Hidden volume size = %I64d\n", cryptoInfoPtr->hiddenVolumeSize);
+ Dump ("Hidden volume end = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset + cryptoInfoPtr->hiddenVolumeSize - 1);
+
+ // Validate the offset
+ if (Extension->cryptoInfo->hiddenVolumeOffset % ENCRYPTION_DATA_UNIT_SIZE != 0)
+ {
+ mount->nReturnCode = ERR_VOL_SIZE_WRONG;
+ ntStatus = STATUS_SUCCESS;
+ goto error;
+ }
+
+ // If we are supposed to actually mount the hidden volume (not just to protect it)
+ if (!mount->bProtectHiddenVolume)
+ {
+ Extension->DiskLength = cryptoInfoPtr->hiddenVolumeSize;
+ Extension->cryptoInfo->hiddenVolume = TRUE;
+ Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->hiddenVolumeOffset;
+ }
+ else
+ {
+ // Hidden volume protection
+ Extension->cryptoInfo->hiddenVolume = FALSE;
+ Extension->cryptoInfo->bProtectHiddenVolume = TRUE;
+
+ Extension->cryptoInfo->hiddenVolumeProtectedSize = tmpCryptoInfo->hiddenVolumeSize;
+
+ Dump ("Hidden volume protection active: %I64d-%I64d (%I64d)\n", Extension->cryptoInfo->hiddenVolumeOffset, Extension->cryptoInfo->hiddenVolumeProtectedSize + Extension->cryptoInfo->hiddenVolumeOffset - 1, Extension->cryptoInfo->hiddenVolumeProtectedSize);
+ }
+
+ break;
+ }
+
+ Dump ("Volume data offset = %I64d\n", Extension->cryptoInfo->volDataAreaOffset);
+ Dump ("Volume data size = %I64d\n", Extension->DiskLength);
+ Dump ("Volume data end = %I64d\n", Extension->cryptoInfo->volDataAreaOffset + Extension->DiskLength - 1);
+
+ if (Extension->DiskLength == 0)
+ {
+ Dump ("Incorrect volume size\n");
+ continue;
+ }
+
+ // If this is a hidden volume, make sure we are supposed to actually
+ // mount it (i.e. not just to protect it)
+ if (volumeType == TC_VOLUME_TYPE_NORMAL || !mount->bProtectHiddenVolume)
+ {
+ // Validate sector size
+ if (bRawDevice && Extension->cryptoInfo->SectorSize != Extension->HostBytesPerSector)
+ {
+ mount->nReturnCode = ERR_PARAMETER_INCORRECT;
+ ntStatus = STATUS_SUCCESS;
+ goto error;
+ }
+
+ // Calculate virtual volume geometry
+ Extension->TracksPerCylinder = 1;
+ Extension->SectorsPerTrack = 1;
+ Extension->BytesPerSector = Extension->cryptoInfo->SectorSize;
+ Extension->NumberOfCylinders = Extension->DiskLength / Extension->BytesPerSector;
+ Extension->PartitionType = 0;
+
+ Extension->bRawDevice = bRawDevice;
+
+ memset (Extension->wszVolume, 0, sizeof (Extension->wszVolume));
+ if (wcsstr (pwszMountVolume, WIDE ("\\??\\UNC\\")) == pwszMountVolume)
+ {
+ /* UNC path */
+ RtlStringCbPrintfW (Extension->wszVolume,
+ sizeof (Extension->wszVolume),
+ WIDE ("\\??\\\\%s"),
+ pwszMountVolume + 7);
+ }
+ else
+ {
+ RtlStringCbCopyW (Extension->wszVolume, sizeof(Extension->wszVolume),pwszMountVolume);
+ }
+
+ memset (Extension->wszLabel, 0, sizeof (Extension->wszLabel));
+ RtlStringCbCopyW (Extension->wszLabel, sizeof(Extension->wszLabel), mount->wszLabel);
+ }
+
+ // If we are to protect a hidden volume we cannot exit yet, for we must also
+ // decrypt the hidden volume header.
+ if (!(volumeType == TC_VOLUME_TYPE_NORMAL && mount->bProtectHiddenVolume))
+ {
+ TCfree (readBuffer);
+
+ if (tmpCryptoInfo != NULL)
+ {
+ crypto_close (tmpCryptoInfo);
+ tmpCryptoInfo = NULL;
+ }
+
+ return STATUS_SUCCESS;
+ }
+ }
+ else if ((mount->bProtectHiddenVolume && volumeType == TC_VOLUME_TYPE_NORMAL)
+ || mount->nReturnCode != ERR_PASSWORD_WRONG)
+ {
+ /* If we are not supposed to protect a hidden volume, the only error that is
+ tolerated is ERR_PASSWORD_WRONG (to allow mounting a possible hidden volume).
+
+ If we _are_ supposed to protect a hidden volume, we do not tolerate any error
+ (both volume headers must be successfully decrypted). */
+
+ break;
+ }
+ }
+
+ /* Failed due to some non-OS reason so we drop through and return NT
+ SUCCESS then nReturnCode is checked later in user-mode */
+
+ if (mount->nReturnCode == ERR_OUTOFMEMORY)
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ else
+ ntStatus = STATUS_SUCCESS;
+
+error:
+ if (mount->nReturnCode == ERR_SUCCESS)
+ mount->nReturnCode = ERR_PASSWORD_WRONG;
+
+ if (tmpCryptoInfo != NULL)
+ {
+ crypto_close (tmpCryptoInfo);
+ tmpCryptoInfo = NULL;
+ }
+
+ if (Extension->cryptoInfo)
+ {
+ crypto_close (Extension->cryptoInfo);
+ Extension->cryptoInfo = NULL;
+ }
+
+ if (Extension->bTimeStampValid)
+ {
+ RestoreTimeStamp (Extension);
+ }
+
+ /* Close the hDeviceFile */
+ if (Extension->hDeviceFile != NULL)
+ ZwClose (Extension->hDeviceFile);
+
+ /* The cryptoInfo pointer is deallocated if the readheader routines
+ fail so there is no need to deallocate here */
+
+ /* Dereference the user-mode file object */
+ if (Extension->pfoDeviceFile != NULL)
+ ObDereferenceObject (Extension->pfoDeviceFile);
+
+ /* Free the tmp IO buffers */
+ if (readBuffer != NULL)
+ TCfree (readBuffer);
+
+ return ntStatus;
+}
+
+void TCCloseVolume (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
+{
+ UNREFERENCED_PARAMETER (DeviceObject); /* Remove compiler warning */
+
+ if (Extension->hDeviceFile != NULL)
+ {
+ if (Extension->bRawDevice == FALSE
+ && Extension->bTimeStampValid)
+ {
+ RestoreTimeStamp (Extension);
+ }
+ ZwClose (Extension->hDeviceFile);
+ }
+ ObDereferenceObject (Extension->pfoDeviceFile);
+ if (Extension->cryptoInfo)
+ {
+ crypto_close (Extension->cryptoInfo);
+ Extension->cryptoInfo = NULL;
+ }
+}
+
+
+NTSTATUS TCSendHostDeviceIoControlRequestEx (PDEVICE_OBJECT DeviceObject,
+ PEXTENSION Extension,
+ ULONG IoControlCode,
+ void *InputBuffer,
+ ULONG InputBufferSize,
+ void *OutputBuffer,
+ ULONG OutputBufferSize)
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS ntStatus;
+ PIRP Irp;
+
+ UNREFERENCED_PARAMETER(DeviceObject); /* Remove compiler warning */
+
+ KeClearEvent (&Extension->keVolumeEvent);
+
+ Irp = IoBuildDeviceIoControlRequest (IoControlCode,
+ Extension->pFsdDevice,
+ InputBuffer, InputBufferSize,
+ OutputBuffer, OutputBufferSize,
+ FALSE,
+ &Extension->keVolumeEvent,
+ &IoStatusBlock);
+
+ if (Irp == NULL)
+ {
+ Dump ("IRP allocation failed\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Disk device may be used by filesystem driver which needs file object
+ IoGetNextIrpStackLocation (Irp) -> FileObject = Extension->pfoDeviceFile;
+
+ ntStatus = IoCallDriver (Extension->pFsdDevice, Irp);
+ if (ntStatus == STATUS_PENDING)
+ {
+ KeWaitForSingleObject (&Extension->keVolumeEvent, Executive, KernelMode, FALSE, NULL);
+ ntStatus = IoStatusBlock.Status;
+ }
+
+ return ntStatus;
+}
+
+NTSTATUS TCSendHostDeviceIoControlRequest (PDEVICE_OBJECT DeviceObject,
+ PEXTENSION Extension,
+ ULONG IoControlCode,
+ void *OutputBuffer,
+ ULONG OutputBufferSize)
+{
+ return TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IoControlCode, NULL, 0, OutputBuffer, OutputBufferSize);
+}
+
+NTSTATUS COMPLETE_IRP (PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ NTSTATUS IrpStatus,
+ ULONG_PTR IrpInformation)
+{
+ Irp->IoStatus.Status = IrpStatus;
+ Irp->IoStatus.Information = IrpInformation;
+
+ UNREFERENCED_PARAMETER (DeviceObject); /* Remove compiler warning */
+
+#if EXTRA_INFO
+ if (!NT_SUCCESS (IrpStatus))
+ {
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
+ Dump ("COMPLETE_IRP FAILING IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
+ (ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
+ }
+ else
+ {
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
+ Dump ("COMPLETE_IRP SUCCESS IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
+ (ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
+ }
+#endif
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+ return IrpStatus;
+}
+
+
+static void RestoreTimeStamp (PEXTENSION Extension)
+{
+ NTSTATUS ntStatus;
+ FILE_BASIC_INFORMATION FileBasicInfo;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ if (Extension->hDeviceFile != NULL
+ && Extension->bRawDevice == FALSE
+ && Extension->bReadOnly == FALSE
+ && Extension->bTimeStampValid)
+ {
+ ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
+ &IoStatusBlock,
+ &FileBasicInfo,
+ sizeof (FileBasicInfo),
+ FileBasicInformation);
+
+ if (!NT_SUCCESS (ntStatus))
+ {
+ Dump ("ZwQueryInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",
+ ntStatus);
+ }
+ else
+ {
+ FileBasicInfo.CreationTime = Extension->fileCreationTime;
+ FileBasicInfo.LastAccessTime = Extension->fileLastAccessTime;
+ FileBasicInfo.LastWriteTime = Extension->fileLastWriteTime;
+ FileBasicInfo.ChangeTime = Extension->fileLastChangeTime;
+
+ ntStatus = ZwSetInformationFile(
+ Extension->hDeviceFile,
+ &IoStatusBlock,
+ &FileBasicInfo,
+ sizeof (FileBasicInfo),
+ FileBasicInformation);
+
+ if (!NT_SUCCESS (ntStatus))
+ Dump ("ZwSetInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",ntStatus);
+ }
+ }
+}
diff --git a/src/Driver/Ntvol.h b/src/Driver/Ntvol.h
index 4a496a73..912c02b0 100644
--- a/src/Driver/Ntvol.h
+++ b/src/Driver/Ntvol.h
@@ -1,22 +1,22 @@
-/*
- Legal Notice: Some portions of the source code contained in this file were
- derived from the source code of TrueCrypt 7.1a, which is
- Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
- governed by the TrueCrypt License 3.0, also from the source code of
- Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
- and which is governed by the 'License Agreement for Encryption for the Masses'
- 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. */
-
-extern volatile BOOL ProbingHostDeviceForWrite;
-
-NTSTATUS TCOpenVolume ( PDEVICE_OBJECT DeviceObject , PEXTENSION Extension , MOUNT_STRUCT *mount , PWSTR pwszMountVolume , BOOL bRawDevice );
-void TCCloseVolume ( PDEVICE_OBJECT DeviceObject , PEXTENSION Extension );
-NTSTATUS TCCompletion ( PDEVICE_OBJECT DeviceObject , PIRP Irp , PVOID pUserBuffer );
-static NTSTATUS TCSendHostDeviceIoControlRequest ( PDEVICE_OBJECT DeviceObject , PEXTENSION Extension , ULONG IoControlCode , void *OutputBuffer , ULONG OutputBufferSize );
-static NTSTATUS TCSendHostDeviceIoControlRequestEx ( PDEVICE_OBJECT DeviceObject , PEXTENSION Extension , ULONG IoControlCode , void *InputBuffer , ULONG InputBufferSize , void *OutputBuffer , ULONG OutputBufferSize );
-NTSTATUS COMPLETE_IRP ( PDEVICE_OBJECT DeviceObject , PIRP Irp , NTSTATUS IrpStatus , ULONG_PTR IrpInformation );
-static void RestoreTimeStamp ( PEXTENSION Extension );
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of TrueCrypt 7.1a, which is
+ Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
+ governed by the TrueCrypt License 3.0, also from the source code of
+ Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
+ and which is governed by the 'License Agreement for Encryption for the Masses'
+ 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. */
+
+extern volatile BOOL ProbingHostDeviceForWrite;
+
+NTSTATUS TCOpenVolume ( PDEVICE_OBJECT DeviceObject , PEXTENSION Extension , MOUNT_STRUCT *mount , PWSTR pwszMountVolume , BOOL bRawDevice );
+void TCCloseVolume ( PDEVICE_OBJECT DeviceObject , PEXTENSION Extension );
+NTSTATUS TCCompletion ( PDEVICE_OBJECT DeviceObject , PIRP Irp , PVOID pUserBuffer );
+static NTSTATUS TCSendHostDeviceIoControlRequest ( PDEVICE_OBJECT DeviceObject , PEXTENSION Extension , ULONG IoControlCode , void *OutputBuffer , ULONG OutputBufferSize );
+static NTSTATUS TCSendHostDeviceIoControlRequestEx ( PDEVICE_OBJECT DeviceObject , PEXTENSION Extension , ULONG IoControlCode , void *InputBuffer , ULONG InputBufferSize , void *OutputBuffer , ULONG OutputBufferSize );
+NTSTATUS COMPLETE_IRP ( PDEVICE_OBJECT DeviceObject , PIRP Irp , NTSTATUS IrpStatus , ULONG_PTR IrpInformation );
+static void RestoreTimeStamp ( PEXTENSION Extension );
diff --git a/src/Driver/Resource.h b/src/Driver/Resource.h
index effd8044..a3e73646 100644
--- a/src/Driver/Resource.h
+++ b/src/Driver/Resource.h
@@ -1,16 +1,16 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by Driver.rc
-//
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NO_MFC 1
-#define _APS_NEXT_RESOURCE_VALUE 101
-#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1001
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Driver.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/Driver/Sources b/src/Driver/Sources
index 592c2dc6..8e8aef2d 100644
--- a/src/Driver/Sources
+++ b/src/Driver/Sources
@@ -1,21 +1,21 @@
-TARGETNAME=veracrypt
-TARGETTYPE=DRIVER
-
-USER_C_FLAGS=$(USER_C_FLAGS) -D_UNICODE
-LINKER_FLAGS=$(LINKER_FLAGS) -map
-
-INCLUDES = ../Common;../Crypto
-
-SOURCES = \
- DriveFilter.c \
- DumpFilter.c \
- EncryptedIoQueue.c \
- Ntdriver.c \
- Ntvol.c \
- VolumeFilter.c \
- Driver.rc
-
-TARGETLIBS = \
- $(SDK_LIB_PATH)/uuid.lib \
- ../Common/obj$(BUILD_ALT_DIR)/*/Common.lib \
- ../Crypto/obj$(BUILD_ALT_DIR)/*/Crypto.lib
+TARGETNAME=veracrypt
+TARGETTYPE=DRIVER
+
+USER_C_FLAGS=$(USER_C_FLAGS) -D_UNICODE
+LINKER_FLAGS=$(LINKER_FLAGS) -map
+
+INCLUDES = ../Common;../Crypto
+
+SOURCES = \
+ DriveFilter.c \
+ DumpFilter.c \
+ EncryptedIoQueue.c \
+ Ntdriver.c \
+ Ntvol.c \
+ VolumeFilter.c \
+ Driver.rc
+
+TARGETLIBS = \
+ $(SDK_LIB_PATH)/uuid.lib \
+ ../Common/obj$(BUILD_ALT_DIR)/*/Common.lib \
+ ../Crypto/obj$(BUILD_ALT_DIR)/*/Crypto.lib
diff --git a/src/Driver/VolumeFilter.c b/src/Driver/VolumeFilter.c
index 78b2d7b9..8cb675f6 100644
--- a/src/Driver/VolumeFilter.c
+++ b/src/Driver/VolumeFilter.c
@@ -1,299 +1,299 @@
-/*
- 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 "Ntdriver.h"
-#include "Ntvol.h"
-#include "DriveFilter.h"
-#include "VolumeFilter.h"
-
-typedef DriveFilterExtension VolumeFilterExtension;
-
-// Number of times the filter driver answered that an unencrypted volume
-// is read-only (or mounted an outer/normal TrueCrypt volume as read only)
-uint32 HiddenSysLeakProtectionCount = 0;
-
-
-NTSTATUS VolumeFilterAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo)
-{
- VolumeFilterExtension *Extension;
- NTSTATUS status;
- PDEVICE_OBJECT filterDeviceObject = NULL;
- PDEVICE_OBJECT attachedDeviceObject;
-
- Dump ("VolumeFilterAddDevice pdo=%p\n", pdo);
-
- attachedDeviceObject = IoGetAttachedDeviceReference (pdo);
- status = IoCreateDevice (driverObject, sizeof (VolumeFilterExtension), NULL, attachedDeviceObject->DeviceType, 0, FALSE, &filterDeviceObject);
-
- ObDereferenceObject (attachedDeviceObject);
-
- if (!NT_SUCCESS (status))
- {
- filterDeviceObject = NULL;
- goto err;
- }
-
- Extension = (VolumeFilterExtension *) filterDeviceObject->DeviceExtension;
- memset (Extension, 0, sizeof (VolumeFilterExtension));
-
- status = IoAttachDeviceToDeviceStackSafe (filterDeviceObject, pdo, &(Extension->LowerDeviceObject));
- if (status != STATUS_SUCCESS)
- {
- goto err;
- }
-
- if (!Extension->LowerDeviceObject)
- {
- status = STATUS_DEVICE_REMOVED;
- goto err;
- }
-
- Extension->IsVolumeFilterDevice = TRUE;
- Extension->DeviceObject = filterDeviceObject;
- Extension->Pdo = pdo;
-
- IoInitializeRemoveLock (&Extension->Queue.RemoveLock, 'LRCV', 0, 0);
-
- filterDeviceObject->Flags |= Extension->LowerDeviceObject->Flags & (DO_DIRECT_IO | DO_BUFFERED_IO | DO_POWER_PAGABLE);
- filterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
-
- return status;
-
-err:
- if (filterDeviceObject)
- {
- if (Extension->LowerDeviceObject)
- IoDetachDevice (Extension->LowerDeviceObject);
-
- IoDeleteDevice (filterDeviceObject);
- }
-
- 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, VolumeFilterExtension *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 NTSTATUS OnStartDeviceCompleted (PDEVICE_OBJECT filterDeviceObject, PIRP Irp, VolumeFilterExtension *Extension)
-{
- if (Irp->PendingReturned)
- IoMarkIrpPending (Irp);
-
- if (Extension->LowerDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
- filterDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
-
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
- return STATUS_CONTINUE_COMPLETION;
-}
-
-
-static NTSTATUS DispatchControl (PDEVICE_OBJECT DeviceObject, PIRP Irp, VolumeFilterExtension *Extension, PIO_STACK_LOCATION irpSp)
-{
- NTSTATUS status = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp);
- if (!NT_SUCCESS (status))
- return TCCompleteIrp (Irp, status, 0);
-
- if (IsHiddenSystemRunning())
- {
- switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
- {
- case IOCTL_DISK_IS_WRITABLE:
- {
- // All volumes except the system volume must be read-only
-
- DriveFilterExtension *bootDriveExtension = GetBootDriveFilterExtension();
- STORAGE_DEVICE_NUMBER storageDeviceNumber;
-
- if (!bootDriveExtension->SystemStorageDeviceNumberValid)
- TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
-
- status = SendDeviceIoControlRequest (Extension->LowerDeviceObject, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &storageDeviceNumber, sizeof (storageDeviceNumber));
-
- if (NT_SUCCESS (status) && bootDriveExtension->SystemStorageDeviceNumber == storageDeviceNumber.DeviceNumber)
- {
- PARTITION_INFORMATION_EX partition;
- status = SendDeviceIoControlRequest (Extension->LowerDeviceObject, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &partition, sizeof (partition));
-
- if (NT_SUCCESS (status) && partition.StartingOffset.QuadPart == bootDriveExtension->ConfiguredEncryptedAreaStart)
- {
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
- return TCCompleteDiskIrp (Irp, STATUS_SUCCESS, 0);
- }
- }
-
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
-
- ++HiddenSysLeakProtectionCount;
- return TCCompleteDiskIrp (Irp, STATUS_MEDIA_WRITE_PROTECTED, 0);
- }
-
- case TC_IOCTL_DISK_IS_WRITABLE:
- Dump ("TC_IOCTL_DISK_IS_WRITABLE pdo=%p\n", Extension->Pdo);
-
- if (!ProbingHostDeviceForWrite)
- break;
-
- // Probe the real state of the device as the user is mounting a TrueCrypt volume.
-
- // Volume filter may be attached to a merged drive+volume PDO. First test if TC_IOCTL_DISK_IS_WRITABLE works for the underlying device.
- status = SendDeviceIoControlRequest (Extension->LowerDeviceObject, TC_IOCTL_DISK_IS_WRITABLE, NULL, 0, NULL, 0);
-
- if (NT_SUCCESS (status) || status == STATUS_MEDIA_WRITE_PROTECTED)
- {
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
- return TCCompleteDiskIrp (Irp, status, 0);
- }
-
- status = SendDeviceIoControlRequest (Extension->LowerDeviceObject, IOCTL_DISK_IS_WRITABLE, NULL, 0, NULL, 0);
-
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
- return TCCompleteDiskIrp (Irp, status, 0);
-
- case IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES:
-
- // Filter IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES to enable potential future use of hidden systems on drives that use the trim operation but not wear-leveling (if any appear in future). The documentation forbids users to create hidden volumes/systems on drives that use wear-leveling and consequently also on drives that use trim (as trim is used only by drives that use wear-leveling, as of 2010).
-
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
- return TCCompleteDiskIrp (Irp, STATUS_SUCCESS, 0);
- }
- }
-
- status = PassIrp (Extension->LowerDeviceObject, Irp);
- IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
- return status;
-}
-
-
-static NTSTATUS DispatchPnp (PDEVICE_OBJECT DeviceObject, PIRP Irp, VolumeFilterExtension *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 volume pdo=%p\n", Extension->Pdo);
- return PassFilteredIrp (Extension->LowerDeviceObject, Irp, OnStartDeviceCompleted, Extension);
-
- case IRP_MN_DEVICE_USAGE_NOTIFICATION:
- {
- PDEVICE_OBJECT attachedDevice = IoGetAttachedDeviceReference (DeviceObject);
-
- if (attachedDevice == DeviceObject || (attachedDevice->Flags & DO_POWER_PAGABLE))
- DeviceObject->Flags |= DO_POWER_PAGABLE;
-
- ObDereferenceObject (attachedDevice);
- }
-
- return PassFilteredIrp (Extension->LowerDeviceObject, Irp, OnDeviceUsageNotificationCompleted, Extension);
-
-
- case IRP_MN_REMOVE_DEVICE:
- Dump ("IRP_MN_REMOVE_DEVICE volume pdo=%p\n", Extension->Pdo);
-
- IoReleaseRemoveLockAndWait (&Extension->Queue.RemoveLock, Irp);
- status = PassIrp (Extension->LowerDeviceObject, Irp);
-
- IoDetachDevice (Extension->LowerDeviceObject);
-
- 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, VolumeFilterExtension *Extension, PIO_STACK_LOCATION irpSp)
-{
- NTSTATUS status;
- 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 VolumeFilterDispatchIrp (PDEVICE_OBJECT DeviceObject, PIRP Irp)
-{
- VolumeFilterExtension *Extension = (VolumeFilterExtension *) DeviceObject->DeviceExtension;
- PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
- NTSTATUS status;
-
- ASSERT (!Extension->bRootDevice && Extension->IsVolumeFilterDevice);
-
- switch (irpSp->MajorFunction)
- {
- case IRP_MJ_DEVICE_CONTROL:
- return DispatchControl (DeviceObject, Irp, Extension, irpSp);
-
- case IRP_MJ_PNP:
- return DispatchPnp (DeviceObject, Irp, Extension, irpSp);
-
- case IRP_MJ_POWER:
- return DispatchPower (DeviceObject, Irp, Extension, irpSp);
-
- default:
- 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;
- }
-}
+/*
+ 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 "Ntdriver.h"
+#include "Ntvol.h"
+#include "DriveFilter.h"
+#include "VolumeFilter.h"
+
+typedef DriveFilterExtension VolumeFilterExtension;
+
+// Number of times the filter driver answered that an unencrypted volume
+// is read-only (or mounted an outer/normal TrueCrypt volume as read only)
+uint32 HiddenSysLeakProtectionCount = 0;
+
+
+NTSTATUS VolumeFilterAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo)
+{
+ VolumeFilterExtension *Extension;
+ NTSTATUS status;
+ PDEVICE_OBJECT filterDeviceObject = NULL;
+ PDEVICE_OBJECT attachedDeviceObject;
+
+ Dump ("VolumeFilterAddDevice pdo=%p\n", pdo);
+
+ attachedDeviceObject = IoGetAttachedDeviceReference (pdo);
+ status = IoCreateDevice (driverObject, sizeof (VolumeFilterExtension), NULL, attachedDeviceObject->DeviceType, 0, FALSE, &filterDeviceObject);
+
+ ObDereferenceObject (attachedDeviceObject);
+
+ if (!NT_SUCCESS (status))
+ {
+ filterDeviceObject = NULL;
+ goto err;
+ }
+
+ Extension = (VolumeFilterExtension *) filterDeviceObject->DeviceExtension;
+ memset (Extension, 0, sizeof (VolumeFilterExtension));
+
+ status = IoAttachDeviceToDeviceStackSafe (filterDeviceObject, pdo, &(Extension->LowerDeviceObject));
+ if (status != STATUS_SUCCESS)
+ {
+ goto err;
+ }
+
+ if (!Extension->LowerDeviceObject)
+ {
+ status = STATUS_DEVICE_REMOVED;
+ goto err;
+ }
+
+ Extension->IsVolumeFilterDevice = TRUE;
+ Extension->DeviceObject = filterDeviceObject;
+ Extension->Pdo = pdo;
+
+ IoInitializeRemoveLock (&Extension->Queue.RemoveLock, 'LRCV', 0, 0);
+
+ filterDeviceObject->Flags |= Extension->LowerDeviceObject->Flags & (DO_DIRECT_IO | DO_BUFFERED_IO | DO_POWER_PAGABLE);
+ filterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ return status;
+
+err:
+ if (filterDeviceObject)
+ {
+ if (Extension->LowerDeviceObject)
+ IoDetachDevice (Extension->LowerDeviceObject);
+
+ IoDeleteDevice (filterDeviceObject);
+ }
+
+ 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, VolumeFilterExtension *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 NTSTATUS OnStartDeviceCompleted (PDEVICE_OBJECT filterDeviceObject, PIRP Irp, VolumeFilterExtension *Extension)
+{
+ if (Irp->PendingReturned)
+ IoMarkIrpPending (Irp);
+
+ if (Extension->LowerDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
+ filterDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
+
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ return STATUS_CONTINUE_COMPLETION;
+}
+
+
+static NTSTATUS DispatchControl (PDEVICE_OBJECT DeviceObject, PIRP Irp, VolumeFilterExtension *Extension, PIO_STACK_LOCATION irpSp)
+{
+ NTSTATUS status = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ if (!NT_SUCCESS (status))
+ return TCCompleteIrp (Irp, status, 0);
+
+ if (IsHiddenSystemRunning())
+ {
+ switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_DISK_IS_WRITABLE:
+ {
+ // All volumes except the system volume must be read-only
+
+ DriveFilterExtension *bootDriveExtension = GetBootDriveFilterExtension();
+ STORAGE_DEVICE_NUMBER storageDeviceNumber;
+
+ if (!bootDriveExtension->SystemStorageDeviceNumberValid)
+ TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
+
+ status = SendDeviceIoControlRequest (Extension->LowerDeviceObject, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &storageDeviceNumber, sizeof (storageDeviceNumber));
+
+ if (NT_SUCCESS (status) && bootDriveExtension->SystemStorageDeviceNumber == storageDeviceNumber.DeviceNumber)
+ {
+ PARTITION_INFORMATION_EX partition;
+ status = SendDeviceIoControlRequest (Extension->LowerDeviceObject, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &partition, sizeof (partition));
+
+ if (NT_SUCCESS (status) && partition.StartingOffset.QuadPart == bootDriveExtension->ConfiguredEncryptedAreaStart)
+ {
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ return TCCompleteDiskIrp (Irp, STATUS_SUCCESS, 0);
+ }
+ }
+
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+
+ ++HiddenSysLeakProtectionCount;
+ return TCCompleteDiskIrp (Irp, STATUS_MEDIA_WRITE_PROTECTED, 0);
+ }
+
+ case TC_IOCTL_DISK_IS_WRITABLE:
+ Dump ("TC_IOCTL_DISK_IS_WRITABLE pdo=%p\n", Extension->Pdo);
+
+ if (!ProbingHostDeviceForWrite)
+ break;
+
+ // Probe the real state of the device as the user is mounting a TrueCrypt volume.
+
+ // Volume filter may be attached to a merged drive+volume PDO. First test if TC_IOCTL_DISK_IS_WRITABLE works for the underlying device.
+ status = SendDeviceIoControlRequest (Extension->LowerDeviceObject, TC_IOCTL_DISK_IS_WRITABLE, NULL, 0, NULL, 0);
+
+ if (NT_SUCCESS (status) || status == STATUS_MEDIA_WRITE_PROTECTED)
+ {
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ return TCCompleteDiskIrp (Irp, status, 0);
+ }
+
+ status = SendDeviceIoControlRequest (Extension->LowerDeviceObject, IOCTL_DISK_IS_WRITABLE, NULL, 0, NULL, 0);
+
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ return TCCompleteDiskIrp (Irp, status, 0);
+
+ case IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES:
+
+ // Filter IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES to enable potential future use of hidden systems on drives that use the trim operation but not wear-leveling (if any appear in future). The documentation forbids users to create hidden volumes/systems on drives that use wear-leveling and consequently also on drives that use trim (as trim is used only by drives that use wear-leveling, as of 2010).
+
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ return TCCompleteDiskIrp (Irp, STATUS_SUCCESS, 0);
+ }
+ }
+
+ status = PassIrp (Extension->LowerDeviceObject, Irp);
+ IoReleaseRemoveLock (&Extension->Queue.RemoveLock, Irp);
+ return status;
+}
+
+
+static NTSTATUS DispatchPnp (PDEVICE_OBJECT DeviceObject, PIRP Irp, VolumeFilterExtension *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 volume pdo=%p\n", Extension->Pdo);
+ return PassFilteredIrp (Extension->LowerDeviceObject, Irp, OnStartDeviceCompleted, Extension);
+
+ case IRP_MN_DEVICE_USAGE_NOTIFICATION:
+ {
+ PDEVICE_OBJECT attachedDevice = IoGetAttachedDeviceReference (DeviceObject);
+
+ if (attachedDevice == DeviceObject || (attachedDevice->Flags & DO_POWER_PAGABLE))
+ DeviceObject->Flags |= DO_POWER_PAGABLE;
+
+ ObDereferenceObject (attachedDevice);
+ }
+
+ return PassFilteredIrp (Extension->LowerDeviceObject, Irp, OnDeviceUsageNotificationCompleted, Extension);
+
+
+ case IRP_MN_REMOVE_DEVICE:
+ Dump ("IRP_MN_REMOVE_DEVICE volume pdo=%p\n", Extension->Pdo);
+
+ IoReleaseRemoveLockAndWait (&Extension->Queue.RemoveLock, Irp);
+ status = PassIrp (Extension->LowerDeviceObject, Irp);
+
+ IoDetachDevice (Extension->LowerDeviceObject);
+
+ 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, VolumeFilterExtension *Extension, PIO_STACK_LOCATION irpSp)
+{
+ NTSTATUS status;
+ 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 VolumeFilterDispatchIrp (PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ VolumeFilterExtension *Extension = (VolumeFilterExtension *) DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
+ NTSTATUS status;
+
+ ASSERT (!Extension->bRootDevice && Extension->IsVolumeFilterDevice);
+
+ switch (irpSp->MajorFunction)
+ {
+ case IRP_MJ_DEVICE_CONTROL:
+ return DispatchControl (DeviceObject, Irp, Extension, irpSp);
+
+ case IRP_MJ_PNP:
+ return DispatchPnp (DeviceObject, Irp, Extension, irpSp);
+
+ case IRP_MJ_POWER:
+ return DispatchPower (DeviceObject, Irp, Extension, irpSp);
+
+ default:
+ 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;
+ }
+}
diff --git a/src/Driver/VolumeFilter.h b/src/Driver/VolumeFilter.h
index ace7627a..be0cbd0b 100644
--- a/src/Driver/VolumeFilter.h
+++ b/src/Driver/VolumeFilter.h
@@ -1,23 +1,23 @@
-/*
- 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.
-*/
-
-#ifndef TC_HEADER_DRIVER_VOLUME_FILTER
-#define TC_HEADER_DRIVER_VOLUME_FILTER
-
-#include "TCdefs.h"
-
-extern uint32 HiddenSysLeakProtectionCount;
-
-NTSTATUS VolumeFilterAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo);
-NTSTATUS VolumeFilterDispatchIrp (PDEVICE_OBJECT DeviceObject, PIRP Irp);
-
-#endif // TC_HEADER_DRIVER_VOLUME_FILTER
+/*
+ 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.
+*/
+
+#ifndef TC_HEADER_DRIVER_VOLUME_FILTER
+#define TC_HEADER_DRIVER_VOLUME_FILTER
+
+#include "TCdefs.h"
+
+extern uint32 HiddenSysLeakProtectionCount;
+
+NTSTATUS VolumeFilterAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo);
+NTSTATUS VolumeFilterDispatchIrp (PDEVICE_OBJECT DeviceObject, PIRP Irp);
+
+#endif // TC_HEADER_DRIVER_VOLUME_FILTER