static void AcquireBufferPoolMutex (EncryptedIoQueue *queue) { NTSTATUS status; status = KeWaitForMutexObject (&queue->BufferPoolMutex, Executive, KernelMode, FALSE, NULL); if (!NT_SUCCESS (status)) TC_BUG_CHECK (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 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 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 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 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; }