mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2026-06-09 22:36:59 -05:00
Windows: Harden Windows driver input validation
Validate SecRegion password cache offsets before use. Wipe decrypted SecRegion password-cache data even when cache validation fails. Clamp encrypted I/O work item counts and check allocation sizing. Reject invalid boot drive sector writes and initialize decoy wipe data unit. Validate hidden-system boot offsets and remap arithmetic before use.
This commit is contained in:
+131
-24
@@ -74,6 +74,82 @@ static NTSTATUS DecoySystemWipeResult;
|
|||||||
static uint64 BootArgsRegionsDefault[] = { EFI_BOOTARGS_REGIONS_DEFAULT };
|
static uint64 BootArgsRegionsDefault[] = { EFI_BOOTARGS_REGIONS_DEFAULT };
|
||||||
static uint64 BootArgsRegionsEFI[] = { EFI_BOOTARGS_REGIONS_EFI };
|
static uint64 BootArgsRegionsEFI[] = { EFI_BOOTARGS_REGIONS_EFI };
|
||||||
|
|
||||||
|
static BOOL GetHiddenSystemPartitionOffset (uint64 *hiddenPartitionOffset)
|
||||||
|
{
|
||||||
|
uint64 hiddenOffset = BootArgs.HiddenSystemPartitionStart;
|
||||||
|
|
||||||
|
if (hiddenOffset == 0
|
||||||
|
|| hiddenOffset > (uint64) _I64_MAX
|
||||||
|
|| (hiddenOffset % TC_SECTOR_SIZE_BIOS) != 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
*hiddenPartitionOffset = hiddenOffset;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL GetHiddenSystemPartitionOffsets (uint64 *hiddenPartitionOffset, uint64 *decoyPartitionOffset)
|
||||||
|
{
|
||||||
|
uint64 hiddenOffset;
|
||||||
|
uint64 decoyOffset = BootArgs.DecoySystemPartitionStart;
|
||||||
|
|
||||||
|
if (!GetHiddenSystemPartitionOffset (&hiddenOffset)
|
||||||
|
|| decoyOffset > (uint64) _I64_MAX
|
||||||
|
|| (decoyOffset % TC_SECTOR_SIZE_BIOS) != 0
|
||||||
|
|| decoyOffset >= hiddenOffset)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
*hiddenPartitionOffset = hiddenOffset;
|
||||||
|
*decoyPartitionOffset = decoyOffset;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL GetHiddenVolumeHeaderOffset (LARGE_INTEGER *offset)
|
||||||
|
{
|
||||||
|
uint64 hiddenPartitionOffset;
|
||||||
|
uint64 hiddenHeaderOffset;
|
||||||
|
|
||||||
|
if (!GetHiddenSystemPartitionOffset (&hiddenPartitionOffset)
|
||||||
|
|| hiddenPartitionOffset > ((uint64) _I64_MAX - TC_HIDDEN_VOLUME_HEADER_OFFSET))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
hiddenHeaderOffset = hiddenPartitionOffset + TC_HIDDEN_VOLUME_HEADER_OFFSET;
|
||||||
|
if (hiddenHeaderOffset > ((uint64) _I64_MAX - TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
offset->QuadPart = (LONGLONG) hiddenHeaderOffset;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL GetHiddenSystemRemapOffsets (PCRYPTO_INFO cryptoInfo, int64 *hiddenVolumeStartOffset, int64 *remappedAreaOffset, int64 *remappedAreaDataUnitOffset)
|
||||||
|
{
|
||||||
|
uint64 hiddenOffset;
|
||||||
|
uint64 decoyOffset;
|
||||||
|
uint64 encryptedAreaStart = cryptoInfo->EncryptedAreaStart.Value;
|
||||||
|
uint64 encryptedAreaLength = cryptoInfo->EncryptedAreaLength.Value;
|
||||||
|
uint64 hiddenToDecoyDistance;
|
||||||
|
uint64 hiddenVolumeStart;
|
||||||
|
|
||||||
|
if (!GetHiddenSystemPartitionOffsets (&hiddenOffset, &decoyOffset)
|
||||||
|
|| encryptedAreaStart > (uint64) _I64_MAX
|
||||||
|
|| encryptedAreaLength > (uint64) _I64_MAX
|
||||||
|
|| cryptoInfo->VolumeSize.Value > (uint64) _I64_MAX
|
||||||
|
|| (encryptedAreaStart % ENCRYPTION_DATA_UNIT_SIZE) != 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
hiddenToDecoyDistance = hiddenOffset - decoyOffset;
|
||||||
|
if (cryptoInfo->VolumeSize.Value > hiddenToDecoyDistance
|
||||||
|
|| encryptedAreaLength > hiddenToDecoyDistance
|
||||||
|
|| encryptedAreaStart > ((uint64) _I64_MAX - hiddenOffset))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
hiddenVolumeStart = hiddenOffset + encryptedAreaStart;
|
||||||
|
|
||||||
|
*hiddenVolumeStartOffset = (int64) hiddenVolumeStart;
|
||||||
|
*remappedAreaOffset = (int64) (hiddenVolumeStart - decoyOffset);
|
||||||
|
*remappedAreaDataUnitOffset = (int64) (encryptedAreaStart / ENCRYPTION_DATA_UNIT_SIZE) - (int64) (decoyOffset / ENCRYPTION_DATA_UNIT_SIZE);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS LoadBootArguments (BOOL bIsEfi)
|
NTSTATUS LoadBootArguments (BOOL bIsEfi)
|
||||||
{
|
{
|
||||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||||
@@ -410,7 +486,6 @@ static void ComputeBootLoaderFingerprint(PDEVICE_OBJECT LowerDeviceObject, uint8
|
|||||||
static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password, __unaligned uint32 *headerSaltCrc32)
|
static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password, __unaligned uint32 *headerSaltCrc32)
|
||||||
{
|
{
|
||||||
BOOL hiddenVolume = (BootArgs.HiddenSystemPartitionStart != 0);
|
BOOL hiddenVolume = (BootArgs.HiddenSystemPartitionStart != 0);
|
||||||
int64 hiddenHeaderOffset = BootArgs.HiddenSystemPartitionStart + TC_HIDDEN_VOLUME_HEADER_OFFSET;
|
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
LARGE_INTEGER offset;
|
LARGE_INTEGER offset;
|
||||||
unsigned char *header;
|
unsigned char *header;
|
||||||
@@ -462,7 +537,17 @@ static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password,
|
|||||||
if (!header)
|
if (!header)
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
offset.QuadPart = hiddenVolume ? hiddenHeaderOffset : TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
|
if (hiddenVolume)
|
||||||
|
{
|
||||||
|
if (!GetHiddenVolumeHeaderOffset (&offset))
|
||||||
|
{
|
||||||
|
status = STATUS_INVALID_PARAMETER;
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
offset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
|
||||||
|
|
||||||
Dump ("Reading volume header at %I64u\n", offset.QuadPart);
|
Dump ("Reading volume header at %I64u\n", offset.QuadPart);
|
||||||
|
|
||||||
status = TCReadDevice (Extension->LowerDeviceObject, header, offset, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
|
status = TCReadDevice (Extension->LowerDeviceObject, header, offset, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
|
||||||
@@ -527,22 +612,25 @@ static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password,
|
|||||||
|
|
||||||
if (Extension->Queue.CryptoInfo->hiddenVolume)
|
if (Extension->Queue.CryptoInfo->hiddenVolume)
|
||||||
{
|
{
|
||||||
int64 hiddenPartitionOffset = BootArgs.HiddenSystemPartitionStart;
|
int64 hiddenVolumeStartOffset;
|
||||||
Dump ("Hidden volume start offset = %I64d\n", Extension->Queue.CryptoInfo->EncryptedAreaStart.Value + hiddenPartitionOffset);
|
int64 remappedAreaOffset;
|
||||||
|
int64 remappedAreaDataUnitOffset;
|
||||||
|
|
||||||
|
if (!GetHiddenSystemRemapOffsets (Extension->Queue.CryptoInfo, &hiddenVolumeStartOffset, &remappedAreaOffset, &remappedAreaDataUnitOffset))
|
||||||
|
{
|
||||||
|
// We have already erased boot loader scheduled keys.
|
||||||
|
TC_THROW_FATAL_EXCEPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dump ("Hidden volume start offset = %I64d\n", hiddenVolumeStartOffset);
|
||||||
|
|
||||||
Extension->HiddenSystem = TRUE;
|
Extension->HiddenSystem = TRUE;
|
||||||
|
|
||||||
Extension->Queue.RemapEncryptedArea = TRUE;
|
Extension->Queue.RemapEncryptedArea = TRUE;
|
||||||
Extension->Queue.RemappedAreaOffset = hiddenPartitionOffset + Extension->Queue.CryptoInfo->EncryptedAreaStart.Value - BootArgs.DecoySystemPartitionStart;
|
Extension->Queue.RemappedAreaOffset = remappedAreaOffset;
|
||||||
Extension->Queue.RemappedAreaDataUnitOffset = Extension->Queue.CryptoInfo->EncryptedAreaStart.Value / ENCRYPTION_DATA_UNIT_SIZE - BootArgs.DecoySystemPartitionStart / ENCRYPTION_DATA_UNIT_SIZE;
|
Extension->Queue.RemappedAreaDataUnitOffset = remappedAreaDataUnitOffset;
|
||||||
|
|
||||||
Extension->Queue.CryptoInfo->EncryptedAreaStart.Value = BootArgs.DecoySystemPartitionStart;
|
Extension->Queue.CryptoInfo->EncryptedAreaStart.Value = BootArgs.DecoySystemPartitionStart;
|
||||||
|
|
||||||
if (Extension->Queue.CryptoInfo->VolumeSize.Value > hiddenPartitionOffset - BootArgs.DecoySystemPartitionStart)
|
|
||||||
{
|
|
||||||
// we have already erased boot loader scheduled keys
|
|
||||||
TC_THROW_FATAL_EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dump ("RemappedAreaOffset = %I64d\n", Extension->Queue.RemappedAreaOffset);
|
Dump ("RemappedAreaOffset = %I64d\n", Extension->Queue.RemappedAreaOffset);
|
||||||
Dump ("RemappedAreaDataUnitOffset = %I64d\n", Extension->Queue.RemappedAreaDataUnitOffset);
|
Dump ("RemappedAreaDataUnitOffset = %I64d\n", Extension->Queue.RemappedAreaDataUnitOffset);
|
||||||
@@ -585,17 +673,24 @@ static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password,
|
|||||||
if(crc == crcSaved){
|
if(crc == crcSaved){
|
||||||
if(DeList->DE[DE_IDX_PWDCACHE].Type == DE_PwdCache) {
|
if(DeList->DE[DE_IDX_PWDCACHE].Type == DE_PwdCache) {
|
||||||
uint64 sector = 0;
|
uint64 sector = 0;
|
||||||
DCS_DEP_PWD_CACHE* pwdCache = (DCS_DEP_PWD_CACHE*)(BootSecRegionData + DeList->DE[DE_IDX_PWDCACHE].Sectors.Offset);
|
uint32 pwdCacheOffset = DeList->DE[DE_IDX_PWDCACHE].Offset;
|
||||||
DecryptDataUnits((unsigned char*)pwdCache, (UINT64_STRUCT*)§or, 1, Extension->Queue.CryptoInfo);
|
if ((DeList->DE[DE_IDX_PWDCACHE].Length >= sizeof(DCS_DEP_PWD_CACHE))
|
||||||
crcSaved = pwdCache->CRC;
|
&& ((pwdCacheOffset % TC_SECTOR_SIZE_BIOS) == 0)
|
||||||
pwdCache->CRC = 0;
|
&& (pwdCacheOffset <= BootSecRegionSize)
|
||||||
crc = GetCrc32((unsigned char*)pwdCache, 512);
|
&& ((BootSecRegionSize - pwdCacheOffset) >= sizeof(DCS_DEP_PWD_CACHE)))
|
||||||
if(crcSaved == crc && pwdCache->Count < CACHE_SIZE){
|
{
|
||||||
uint32 i;
|
DCS_DEP_PWD_CACHE* pwdCache = (DCS_DEP_PWD_CACHE*)(BootSecRegionData + pwdCacheOffset);
|
||||||
for(i = 0; i<pwdCache->Count; ++i){
|
DecryptDataUnits((unsigned char*)pwdCache, (UINT64_STRUCT*)§or, 1, Extension->Queue.CryptoInfo);
|
||||||
if (CacheBootPassword && pwdCache->Pwd[i].Length > 0) {
|
crcSaved = pwdCache->CRC;
|
||||||
int cachedPim = CacheBootPim? (int) (pwdCache->Pim[i]) : 0;
|
pwdCache->CRC = 0;
|
||||||
AddLegacyPasswordToCache (&pwdCache->Pwd[i], cachedPim);
|
crc = GetCrc32((unsigned char*)pwdCache, 512);
|
||||||
|
if(crcSaved == crc && pwdCache->Count < CACHE_SIZE){
|
||||||
|
uint32 i;
|
||||||
|
for(i = 0; i<pwdCache->Count; ++i){
|
||||||
|
if (CacheBootPassword && pwdCache->Pwd[i].Length > 0) {
|
||||||
|
int cachedPim = CacheBootPim? (int) (pwdCache->Pim[i]) : 0;
|
||||||
|
AddLegacyPasswordToCache (&pwdCache->Pwd[i], cachedPim);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
burn(pwdCache, sizeof(*pwdCache));
|
burn(pwdCache, sizeof(*pwdCache));
|
||||||
@@ -1155,7 +1250,13 @@ void ReopenBootVolumeHeader (PIRP irp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (BootDriveFilterExtension->HiddenSystem)
|
if (BootDriveFilterExtension->HiddenSystem)
|
||||||
offset.QuadPart = BootArgs.HiddenSystemPartitionStart + TC_HIDDEN_VOLUME_HEADER_OFFSET;
|
{
|
||||||
|
if (!GetHiddenVolumeHeaderOffset (&offset))
|
||||||
|
{
|
||||||
|
irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
offset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
|
offset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
|
||||||
|
|
||||||
@@ -2378,5 +2479,11 @@ NTSTATUS WriteBootDriveSector (PIRP irp, PIO_STACK_LOCATION irpSp)
|
|||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
request = (WriteBootDriveSectorRequest *) irp->AssociatedIrp.SystemBuffer;
|
request = (WriteBootDriveSectorRequest *) irp->AssociatedIrp.SystemBuffer;
|
||||||
|
if (request->Offset.QuadPart < 0
|
||||||
|
|| (request->Offset.QuadPart % TC_SECTOR_SIZE_BIOS) != 0
|
||||||
|
|| BootDriveLength.QuadPart < (LONGLONG) sizeof (request->Data)
|
||||||
|
|| request->Offset.QuadPart > BootDriveLength.QuadPart - (LONGLONG) sizeof (request->Data))
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
return TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, request->Data, request->Offset, sizeof (request->Data));
|
return TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, request->Data, request->Offset, sizeof (request->Data));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1250,10 +1250,15 @@ NTSTATUS EncryptedIoQueueStart (EncryptedIoQueue *queue)
|
|||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
EncryptedIoQueueBuffer *buffer;
|
EncryptedIoQueueBuffer *buffer;
|
||||||
int i, j, preallocatedIoRequestCount, preallocatedItemCount, fragmentSize;
|
int i, j, preallocatedIoRequestCount, preallocatedItemCount, fragmentSize;
|
||||||
|
int maxWorkItems;
|
||||||
|
SIZE_T workItemPoolSize;
|
||||||
|
|
||||||
preallocatedIoRequestCount = EncryptionIoRequestCount;
|
preallocatedIoRequestCount = EncryptionIoRequestCount;
|
||||||
preallocatedItemCount = EncryptionItemCount;
|
preallocatedItemCount = EncryptionItemCount;
|
||||||
fragmentSize = EncryptionFragmentSize;
|
fragmentSize = EncryptionFragmentSize;
|
||||||
|
maxWorkItems = EncryptionMaxWorkItems;
|
||||||
|
if (maxWorkItems <= 0 || maxWorkItems > VC_MAX_WORK_ITEMS)
|
||||||
|
maxWorkItems = VC_MAX_WORK_ITEMS;
|
||||||
|
|
||||||
queue->StartPending = TRUE;
|
queue->StartPending = TRUE;
|
||||||
queue->ThreadExitRequested = FALSE;
|
queue->ThreadExitRequested = FALSE;
|
||||||
@@ -1355,11 +1360,16 @@ retry_preallocated:
|
|||||||
|
|
||||||
// Initialize the free work item list
|
// Initialize the free work item list
|
||||||
InitializeListHead(&queue->FreeWorkItemsList);
|
InitializeListHead(&queue->FreeWorkItemsList);
|
||||||
KeInitializeSemaphore(&queue->WorkItemSemaphore, EncryptionMaxWorkItems, EncryptionMaxWorkItems);
|
KeInitializeSemaphore(&queue->WorkItemSemaphore, maxWorkItems, maxWorkItems);
|
||||||
KeInitializeSpinLock(&queue->WorkItemLock);
|
KeInitializeSpinLock(&queue->WorkItemLock);
|
||||||
|
|
||||||
queue->MaxWorkItems = EncryptionMaxWorkItems;
|
queue->MaxWorkItems = maxWorkItems;
|
||||||
queue->WorkItemPool = (PCOMPLETE_IRP_WORK_ITEM)TCalloc(sizeof(COMPLETE_IRP_WORK_ITEM) * queue->MaxWorkItems);
|
if (FAILED(SizeTMult(sizeof(COMPLETE_IRP_WORK_ITEM), queue->MaxWorkItems, &workItemPoolSize)))
|
||||||
|
{
|
||||||
|
goto noMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
queue->WorkItemPool = (PCOMPLETE_IRP_WORK_ITEM)TCalloc(workItemPoolSize);
|
||||||
if (!queue->WorkItemPool)
|
if (!queue->WorkItemPool)
|
||||||
{
|
{
|
||||||
goto noMemory;
|
goto noMemory;
|
||||||
|
|||||||
@@ -4704,6 +4704,8 @@ NTSTATUS ReadRegistryConfigFlags (BOOL driverEntry)
|
|||||||
|
|
||||||
if (EncryptionMaxWorkItems == 0)
|
if (EncryptionMaxWorkItems == 0)
|
||||||
EncryptionMaxWorkItems = VC_MAX_WORK_ITEMS;
|
EncryptionMaxWorkItems = VC_MAX_WORK_ITEMS;
|
||||||
|
else if (EncryptionMaxWorkItems < 0 || EncryptionMaxWorkItems > VC_MAX_WORK_ITEMS)
|
||||||
|
EncryptionMaxWorkItems = VC_MAX_WORK_ITEMS;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user