mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2026-05-14 00:21:35 +00: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:
@@ -74,6 +74,82 @@ static NTSTATUS DecoySystemWipeResult;
|
||||
static uint64 BootArgsRegionsDefault[] = { EFI_BOOTARGS_REGIONS_DEFAULT };
|
||||
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 status = STATUS_UNSUCCESSFUL;
|
||||
@@ -410,7 +486,6 @@ static void ComputeBootLoaderFingerprint(PDEVICE_OBJECT LowerDeviceObject, uint8
|
||||
static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password, __unaligned uint32 *headerSaltCrc32)
|
||||
{
|
||||
BOOL hiddenVolume = (BootArgs.HiddenSystemPartitionStart != 0);
|
||||
int64 hiddenHeaderOffset = BootArgs.HiddenSystemPartitionStart + TC_HIDDEN_VOLUME_HEADER_OFFSET;
|
||||
NTSTATUS status;
|
||||
LARGE_INTEGER offset;
|
||||
unsigned char *header;
|
||||
@@ -462,7 +537,17 @@ static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password,
|
||||
if (!header)
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
int64 hiddenPartitionOffset = BootArgs.HiddenSystemPartitionStart;
|
||||
Dump ("Hidden volume start offset = %I64d\n", Extension->Queue.CryptoInfo->EncryptedAreaStart.Value + hiddenPartitionOffset);
|
||||
int64 hiddenVolumeStartOffset;
|
||||
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->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.RemappedAreaOffset = remappedAreaOffset;
|
||||
Extension->Queue.RemappedAreaDataUnitOffset = remappedAreaDataUnitOffset;
|
||||
|
||||
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 ("RemappedAreaDataUnitOffset = %I64d\n", Extension->Queue.RemappedAreaDataUnitOffset);
|
||||
@@ -585,17 +673,24 @@ static NTSTATUS MountDrive (DriveFilterExtension *Extension, Password *password,
|
||||
if(crc == crcSaved){
|
||||
if(DeList->DE[DE_IDX_PWDCACHE].Type == DE_PwdCache) {
|
||||
uint64 sector = 0;
|
||||
DCS_DEP_PWD_CACHE* pwdCache = (DCS_DEP_PWD_CACHE*)(BootSecRegionData + DeList->DE[DE_IDX_PWDCACHE].Sectors.Offset);
|
||||
DecryptDataUnits((unsigned char*)pwdCache, (UINT64_STRUCT*)§or, 1, Extension->Queue.CryptoInfo);
|
||||
crcSaved = pwdCache->CRC;
|
||||
pwdCache->CRC = 0;
|
||||
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);
|
||||
uint32 pwdCacheOffset = DeList->DE[DE_IDX_PWDCACHE].Offset;
|
||||
if ((DeList->DE[DE_IDX_PWDCACHE].Length >= sizeof(DCS_DEP_PWD_CACHE))
|
||||
&& ((pwdCacheOffset % TC_SECTOR_SIZE_BIOS) == 0)
|
||||
&& (pwdCacheOffset <= BootSecRegionSize)
|
||||
&& ((BootSecRegionSize - pwdCacheOffset) >= sizeof(DCS_DEP_PWD_CACHE)))
|
||||
{
|
||||
DCS_DEP_PWD_CACHE* pwdCache = (DCS_DEP_PWD_CACHE*)(BootSecRegionData + pwdCacheOffset);
|
||||
DecryptDataUnits((unsigned char*)pwdCache, (UINT64_STRUCT*)§or, 1, Extension->Queue.CryptoInfo);
|
||||
crcSaved = pwdCache->CRC;
|
||||
pwdCache->CRC = 0;
|
||||
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));
|
||||
@@ -1155,7 +1250,13 @@ void ReopenBootVolumeHeader (PIRP irp)
|
||||
}
|
||||
|
||||
if (BootDriveFilterExtension->HiddenSystem)
|
||||
offset.QuadPart = BootArgs.HiddenSystemPartitionStart + TC_HIDDEN_VOLUME_HEADER_OFFSET;
|
||||
{
|
||||
if (!GetHiddenVolumeHeaderOffset (&offset))
|
||||
{
|
||||
irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
||||
goto ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
offset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
|
||||
|
||||
@@ -2378,5 +2479,11 @@ NTSTATUS WriteBootDriveSector (PIRP irp, PIO_STACK_LOCATION irpSp)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -1250,10 +1250,15 @@ NTSTATUS EncryptedIoQueueStart (EncryptedIoQueue *queue)
|
||||
NTSTATUS status;
|
||||
EncryptedIoQueueBuffer *buffer;
|
||||
int i, j, preallocatedIoRequestCount, preallocatedItemCount, fragmentSize;
|
||||
int maxWorkItems;
|
||||
SIZE_T workItemPoolSize;
|
||||
|
||||
preallocatedIoRequestCount = EncryptionIoRequestCount;
|
||||
preallocatedItemCount = EncryptionItemCount;
|
||||
fragmentSize = EncryptionFragmentSize;
|
||||
maxWorkItems = EncryptionMaxWorkItems;
|
||||
if (maxWorkItems <= 0 || maxWorkItems > VC_MAX_WORK_ITEMS)
|
||||
maxWorkItems = VC_MAX_WORK_ITEMS;
|
||||
|
||||
queue->StartPending = TRUE;
|
||||
queue->ThreadExitRequested = FALSE;
|
||||
@@ -1355,11 +1360,16 @@ retry_preallocated:
|
||||
|
||||
// Initialize the free work item list
|
||||
InitializeListHead(&queue->FreeWorkItemsList);
|
||||
KeInitializeSemaphore(&queue->WorkItemSemaphore, EncryptionMaxWorkItems, EncryptionMaxWorkItems);
|
||||
KeInitializeSemaphore(&queue->WorkItemSemaphore, maxWorkItems, maxWorkItems);
|
||||
KeInitializeSpinLock(&queue->WorkItemLock);
|
||||
|
||||
queue->MaxWorkItems = EncryptionMaxWorkItems;
|
||||
queue->WorkItemPool = (PCOMPLETE_IRP_WORK_ITEM)TCalloc(sizeof(COMPLETE_IRP_WORK_ITEM) * queue->MaxWorkItems);
|
||||
queue->MaxWorkItems = 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)
|
||||
{
|
||||
goto noMemory;
|
||||
|
||||
@@ -4704,6 +4704,8 @@ NTSTATUS ReadRegistryConfigFlags (BOOL driverEntry)
|
||||
|
||||
if (EncryptionMaxWorkItems == 0)
|
||||
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