1
0
mirror of https://github.com/veracrypt/VeraCrypt.git synced 2026-06-19 02:56:07 -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:
Mounir IDRASSI
2026-04-26 18:42:26 +09:00
parent d841ac63e4
commit a9b1d5ce57
3 changed files with 146 additions and 27 deletions
+131 -24
View File
@@ -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*)&sector, 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*)&sector, 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));
}