VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Driver/Ntdriver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Driver/Ntdriver.c')
-rw-r--r--src/Driver/Ntdriver.c399
1 files changed, 305 insertions, 94 deletions
diff --git a/src/Driver/Ntdriver.c b/src/Driver/Ntdriver.c
index 7293de2..2ae17f5 100644
--- a/src/Driver/Ntdriver.c
+++ b/src/Driver/Ntdriver.c
@@ -142,6 +142,10 @@ static BOOL RamEncryptionActivated = FALSE;
static KeSaveExtendedProcessorStateFn KeSaveExtendedProcessorStatePtr = NULL;
static KeRestoreExtendedProcessorStateFn KeRestoreExtendedProcessorStatePtr = NULL;
static ExGetFirmwareEnvironmentVariableFn ExGetFirmwareEnvironmentVariablePtr = NULL;
+static KeAreAllApcsDisabledFn KeAreAllApcsDisabledPtr = NULL;
+static KeSetSystemGroupAffinityThreadFn KeSetSystemGroupAffinityThreadPtr = NULL;
+static KeQueryActiveGroupCountFn KeQueryActiveGroupCountPtr = NULL;
+static KeQueryActiveProcessorCountExFn KeQueryActiveProcessorCountExPtr = NULL;
POOL_TYPE ExDefaultNonPagedPoolType = NonPagedPool;
ULONG ExDefaultMdlProtection = 0;
@@ -272,14 +276,30 @@ NTSTATUS DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
ExDefaultMdlProtection = MdlMappingNoExecute;
}
+ // KeAreAllApcsDisabled is available starting from Windows Server 2003
+ if ((OsMajorVersion > 5) || (OsMajorVersion == 5 && OsMinorVersion >= 2))
+ {
+ UNICODE_STRING KeAreAllApcsDisabledFuncName;
+ RtlInitUnicodeString(&KeAreAllApcsDisabledFuncName, L"KeAreAllApcsDisabled");
+
+ KeAreAllApcsDisabledPtr = (KeAreAllApcsDisabledFn) MmGetSystemRoutineAddress(&KeAreAllApcsDisabledFuncName);
+ }
+
// KeSaveExtendedProcessorState/KeRestoreExtendedProcessorState are available starting from Windows 7
+ // KeQueryActiveGroupCount/KeQueryActiveProcessorCountEx/KeSetSystemGroupAffinityThread are available starting from Windows 7
if ((OsMajorVersion > 6) || (OsMajorVersion == 6 && OsMinorVersion >= 1))
{
- UNICODE_STRING saveFuncName, restoreFuncName;
+ UNICODE_STRING saveFuncName, restoreFuncName, groupCountFuncName, procCountFuncName, setAffinityFuncName;
RtlInitUnicodeString(&saveFuncName, L"KeSaveExtendedProcessorState");
RtlInitUnicodeString(&restoreFuncName, L"KeRestoreExtendedProcessorState");
+ RtlInitUnicodeString(&groupCountFuncName, L"KeQueryActiveGroupCount");
+ RtlInitUnicodeString(&procCountFuncName, L"KeQueryActiveProcessorCountEx");
+ RtlInitUnicodeString(&setAffinityFuncName, L"KeSetSystemGroupAffinityThread");
KeSaveExtendedProcessorStatePtr = (KeSaveExtendedProcessorStateFn) MmGetSystemRoutineAddress(&saveFuncName);
KeRestoreExtendedProcessorStatePtr = (KeRestoreExtendedProcessorStateFn) MmGetSystemRoutineAddress(&restoreFuncName);
+ KeSetSystemGroupAffinityThreadPtr = (KeSetSystemGroupAffinityThreadFn) MmGetSystemRoutineAddress(&setAffinityFuncName);
+ KeQueryActiveGroupCountPtr = (KeQueryActiveGroupCountFn) MmGetSystemRoutineAddress(&groupCountFuncName);
+ KeQueryActiveProcessorCountExPtr = (KeQueryActiveProcessorCountExFn) MmGetSystemRoutineAddress(&procCountFuncName);
}
// ExGetFirmwareEnvironmentVariable is available starting from Windows 8
@@ -1374,7 +1394,8 @@ NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION
else
{
IO_STATUS_BLOCK ioStatus;
- PVOID buffer = TCalloc (max (pVerifyInformation->Length, PAGE_SIZE));
+ DWORD dwBuffersize = min (pVerifyInformation->Length, 16 * PAGE_SIZE);
+ PVOID buffer = TCalloc (dwBuffersize);
if (!buffer)
{
@@ -1382,14 +1403,29 @@ NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION
}
else
{
- LARGE_INTEGER offset = pVerifyInformation->StartingOffset;
+ LARGE_INTEGER offset;
+ DWORD dwRemainingBytes = pVerifyInformation->Length, dwReadCount;
offset.QuadPart = ullNewOffset;
- Irp->IoStatus.Status = ZwReadFile (Extension->hDeviceFile, NULL, NULL, NULL, &ioStatus, buffer, pVerifyInformation->Length, &offset, NULL);
- TCfree (buffer);
+ while (dwRemainingBytes)
+ {
+ dwReadCount = min (dwBuffersize, dwRemainingBytes);
+ Irp->IoStatus.Status = ZwReadFile (Extension->hDeviceFile, NULL, NULL, NULL, &ioStatus, buffer, dwReadCount, &offset, NULL);
- if (NT_SUCCESS (Irp->IoStatus.Status) && ioStatus.Information != pVerifyInformation->Length)
- Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ if (NT_SUCCESS (Irp->IoStatus.Status) && ioStatus.Information != dwReadCount)
+ {
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ else if (!NT_SUCCESS (Irp->IoStatus.Status))
+ break;
+
+ dwRemainingBytes -= dwReadCount;
+ offset.QuadPart += (ULONGLONG) dwReadCount;
+ }
+
+ burn (buffer, dwBuffersize);
+ TCfree (buffer);
}
}
@@ -3457,6 +3493,18 @@ void OnShutdownPending ()
while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_WIPE_PASSWORD_CACHE, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES);
}
+typedef struct
+{
+ PWSTR deviceName; ULONG IoControlCode; void *InputBuffer; ULONG InputBufferSize; void *OutputBuffer; ULONG OutputBufferSize;
+ NTSTATUS Status;
+ KEVENT WorkItemCompletedEvent;
+} TCDeviceIoControlWorkItemArgs;
+
+static VOID TCDeviceIoControlWorkItemRoutine (PDEVICE_OBJECT rootDeviceObject, TCDeviceIoControlWorkItemArgs *arg)
+{
+ arg->Status = TCDeviceIoControl (arg->deviceName, arg->IoControlCode, arg->InputBuffer, arg->InputBufferSize, arg->OutputBuffer, arg->OutputBufferSize);
+ KeSetEvent (&arg->WorkItemCompletedEvent, IO_NO_INCREMENT, FALSE);
+}
NTSTATUS TCDeviceIoControl (PWSTR deviceName, ULONG IoControlCode, void *InputBuffer, ULONG InputBufferSize, void *OutputBuffer, ULONG OutputBufferSize)
{
@@ -3468,6 +3516,30 @@ NTSTATUS TCDeviceIoControl (PWSTR deviceName, ULONG IoControlCode, void *InputBu
KEVENT event;
UNICODE_STRING name;
+ if ((KeGetCurrentIrql() >= APC_LEVEL) || VC_KeAreAllApcsDisabled())
+ {
+ TCDeviceIoControlWorkItemArgs args;
+
+ PIO_WORKITEM workItem = IoAllocateWorkItem (RootDeviceObject);
+ if (!workItem)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ args.deviceName = deviceName;
+ args.IoControlCode = IoControlCode;
+ args.InputBuffer = InputBuffer;
+ args.InputBufferSize = InputBufferSize;
+ args.OutputBuffer = OutputBuffer;
+ args.OutputBufferSize = OutputBufferSize;
+
+ KeInitializeEvent (&args.WorkItemCompletedEvent, SynchronizationEvent, FALSE);
+ IoQueueWorkItem (workItem, TCDeviceIoControlWorkItemRoutine, DelayedWorkQueue, &args);
+
+ KeWaitForSingleObject (&args.WorkItemCompletedEvent, Executive, KernelMode, FALSE, NULL);
+ IoFreeWorkItem (workItem);
+
+ return args.Status;
+ }
+
RtlInitUnicodeString(&name, deviceName);
ntStatus = IoGetDeviceObjectPointer (&name, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject);
@@ -3528,7 +3600,7 @@ NTSTATUS SendDeviceIoControlRequest (PDEVICE_OBJECT deviceObject, ULONG ioContro
PIRP irp;
KEVENT event;
- if (KeGetCurrentIrql() > APC_LEVEL)
+ if ((KeGetCurrentIrql() >= APC_LEVEL) || VC_KeAreAllApcsDisabled())
{
SendDeviceIoControlRequestWorkItemArgs args;
@@ -3844,6 +3916,136 @@ NTSTATUS MountManagerUnmount (int nDosDriveNo)
return ntStatus;
}
+typedef struct
+{
+ MOUNT_STRUCT* mount; PEXTENSION NewExtension;
+ NTSTATUS Status;
+ KEVENT WorkItemCompletedEvent;
+} UpdateFsVolumeInformationWorkItemArgs;
+
+static NTSTATUS UpdateFsVolumeInformation (MOUNT_STRUCT* mount, PEXTENSION NewExtension);
+
+static VOID UpdateFsVolumeInformationWorkItemRoutine (PDEVICE_OBJECT rootDeviceObject, UpdateFsVolumeInformationWorkItemArgs *arg)
+{
+ arg->Status = UpdateFsVolumeInformation (arg->mount, arg->NewExtension);
+ KeSetEvent (&arg->WorkItemCompletedEvent, IO_NO_INCREMENT, FALSE);
+}
+
+static NTSTATUS UpdateFsVolumeInformation (MOUNT_STRUCT* mount, PEXTENSION NewExtension)
+{
+ HANDLE volumeHandle;
+ PFILE_OBJECT volumeFileObject;
+ ULONG labelLen = (ULONG) wcslen (mount->wszLabel);
+ BOOL bIsNTFS = FALSE;
+ ULONG labelMaxLen, labelEffectiveLen;
+
+ if ((KeGetCurrentIrql() >= APC_LEVEL) || VC_KeAreAllApcsDisabled())
+ {
+ UpdateFsVolumeInformationWorkItemArgs args;
+
+ PIO_WORKITEM workItem = IoAllocateWorkItem (RootDeviceObject);
+ if (!workItem)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ args.mount = mount;
+ args.NewExtension = NewExtension;
+
+ KeInitializeEvent (&args.WorkItemCompletedEvent, SynchronizationEvent, FALSE);
+ IoQueueWorkItem (workItem, UpdateFsVolumeInformationWorkItemRoutine, DelayedWorkQueue, &args);
+
+ KeWaitForSingleObject (&args.WorkItemCompletedEvent, Executive, KernelMode, FALSE, NULL);
+ IoFreeWorkItem (workItem);
+
+ return args.Status;
+ }
+
+ __try
+ {
+ 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);
+ if (labelInfo)
+ {
+ 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);
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+
+ }
+
+ return STATUS_SUCCESS;
+}
+
NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount)
{
@@ -3931,12 +4133,6 @@ NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount)
{
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)
@@ -3968,81 +4164,13 @@ NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount)
mount->FilesystemDirty = FALSE;
- if (mount->bMountManager && NT_SUCCESS (TCOpenFsVolume (NewExtension, &volumeHandle, &volumeFileObject)))
+ if (mount->bMountManager)
{
- __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)
+ NTSTATUS updateStatus = UpdateFsVolumeInformation (mount, NewExtension);
+ if (!NT_SUCCESS (updateStatus))
{
- 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);
- if (labelInfo)
- {
- 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)
- {
-
- }
+ Dump ("MountDevice: UpdateFsVolumeInformation failed with status 0x%08x\n", updateStatus);
}
-
- TCCloseFsVolume (volumeHandle, volumeFileObject);
}
}
else
@@ -4056,6 +4184,20 @@ NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount)
}
}
+typedef struct
+{
+ UNMOUNT_STRUCT *unmountRequest; PDEVICE_OBJECT deviceObject; BOOL ignoreOpenFiles;
+ NTSTATUS Status;
+ KEVENT WorkItemCompletedEvent;
+} UnmountDeviceWorkItemArgs;
+
+
+static VOID UnmountDeviceWorkItemRoutine (PDEVICE_OBJECT rootDeviceObject, UnmountDeviceWorkItemArgs *arg)
+{
+ arg->Status = UnmountDevice (arg->unmountRequest, arg->deviceObject, arg->ignoreOpenFiles);
+ KeSetEvent (&arg->WorkItemCompletedEvent, IO_NO_INCREMENT, FALSE);
+}
+
NTSTATUS UnmountDevice (UNMOUNT_STRUCT *unmountRequest, PDEVICE_OBJECT deviceObject, BOOL ignoreOpenFiles)
{
PEXTENSION extension = deviceObject->DeviceExtension;
@@ -4063,6 +4205,27 @@ NTSTATUS UnmountDevice (UNMOUNT_STRUCT *unmountRequest, PDEVICE_OBJECT deviceObj
HANDLE volumeHandle;
PFILE_OBJECT volumeFileObject;
+ if ((KeGetCurrentIrql() >= APC_LEVEL) || VC_KeAreAllApcsDisabled())
+ {
+ UnmountDeviceWorkItemArgs args;
+
+ PIO_WORKITEM workItem = IoAllocateWorkItem (RootDeviceObject);
+ if (!workItem)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ args.deviceObject = deviceObject;
+ args.unmountRequest = unmountRequest;
+ args.ignoreOpenFiles = ignoreOpenFiles;
+
+ KeInitializeEvent (&args.WorkItemCompletedEvent, SynchronizationEvent, FALSE);
+ IoQueueWorkItem (workItem, UnmountDeviceWorkItemRoutine, DelayedWorkQueue, &args);
+
+ KeWaitForSingleObject (&args.WorkItemCompletedEvent, Executive, KernelMode, FALSE, NULL);
+ IoFreeWorkItem (workItem);
+
+ return args.Status;
+ }
+
Dump ("UnmountDevice %d\n", extension->nDosDriveNo);
ntStatus = TCOpenFsVolume (extension, &volumeHandle, &volumeFileObject);
@@ -4335,16 +4498,27 @@ NTSTATUS TCCompleteDiskIrp (PIRP irp, NTSTATUS status, ULONG_PTR information)
size_t GetCpuCount ()
{
- KAFFINITY activeCpuMap = KeQueryActiveProcessors();
- size_t mapSize = sizeof (activeCpuMap) * 8;
size_t cpuCount = 0;
-
- while (mapSize--)
+ if (KeQueryActiveGroupCountPtr && KeQueryActiveProcessorCountExPtr)
+ {
+ USHORT i, groupCount = KeQueryActiveGroupCountPtr ();
+ for (i = 0; i < groupCount; i++)
+ {
+ cpuCount += (size_t) KeQueryActiveProcessorCountExPtr (i);
+ }
+ }
+ else
{
- if (activeCpuMap & 1)
- ++cpuCount;
+ KAFFINITY activeCpuMap = KeQueryActiveProcessors();
+ size_t mapSize = sizeof (activeCpuMap) * 8;
+
+ while (mapSize--)
+ {
+ if (activeCpuMap & 1)
+ ++cpuCount;
- activeCpuMap >>= 1;
+ activeCpuMap >>= 1;
+ }
}
if (cpuCount == 0)
@@ -4353,6 +4527,35 @@ size_t GetCpuCount ()
return cpuCount;
}
+USHORT GetCpuGroup (size_t index)
+{
+ if (KeQueryActiveGroupCountPtr && KeQueryActiveProcessorCountExPtr)
+ {
+ USHORT i, groupCount = KeQueryActiveGroupCountPtr ();
+ size_t cpuCount = 0;
+ for (i = 0; i < groupCount; i++)
+ {
+ cpuCount += (size_t) KeQueryActiveProcessorCountExPtr (i);
+ if (cpuCount >= index)
+ {
+ return i;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void SetThreadCpuGroupAffinity (USHORT index)
+{
+ if (KeSetSystemGroupAffinityThreadPtr)
+ {
+ GROUP_AFFINITY groupAffinity = {0};
+ groupAffinity.Mask = ~0ULL;
+ groupAffinity.Group = index;
+ KeSetSystemGroupAffinityThreadPtr (&groupAffinity, NULL);
+ }
+}
void EnsureNullTerminatedString (wchar_t *str, size_t maxSizeInBytes)
{
@@ -4759,4 +4962,12 @@ VOID NTAPI KeRestoreExtendedProcessorState (
{
(KeRestoreExtendedProcessorStatePtr) (XStateSave);
}
-} \ No newline at end of file
+}
+
+BOOLEAN VC_KeAreAllApcsDisabled (VOID)
+{
+ if (KeAreAllApcsDisabledPtr)
+ return (KeAreAllApcsDisabledPtr) ();
+ else
+ return FALSE;
+}