VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMounir IDRASSI <mounir.idrassi@idrix.fr>2019-11-06 00:22:01 +0100
committerMounir IDRASSI <mounir.idrassi@idrix.fr>2019-11-07 00:48:09 +0100
commitb7a21b8a76afd7855832f1cf11bff14a3e076e97 (patch)
tree98a4f0b20f6ea2c7223f0d929a9517536dbae0f9 /src
parent4587472e8787daf936e63cda35145cd1a363721a (diff)
downloadVeraCrypt-b7a21b8a76afd7855832f1cf11bff14a3e076e97.tar.gz
VeraCrypt-b7a21b8a76afd7855832f1cf11bff14a3e076e97.zip
Windows Driver: Fix strange crashes caused by probably by APC queue issues from calls to IoBuildDeviceIoControlRequest and ZwCreate (cf https://www.osr.com/blog/2018/02/14/beware-iobuilddeviceiocontrolrequest/)
Diffstat (limited to 'src')
-rw-r--r--src/Driver/Ntdriver.c305
-rw-r--r--src/Driver/Ntvol.c37
2 files changed, 262 insertions, 80 deletions
diff --git a/src/Driver/Ntdriver.c b/src/Driver/Ntdriver.c
index 7293de2d..1327c12a 100644
--- a/src/Driver/Ntdriver.c
+++ b/src/Driver/Ntdriver.c
@@ -142,6 +142,7 @@ static BOOL RamEncryptionActivated = FALSE;
static KeSaveExtendedProcessorStateFn KeSaveExtendedProcessorStatePtr = NULL;
static KeRestoreExtendedProcessorStateFn KeRestoreExtendedProcessorStatePtr = NULL;
static ExGetFirmwareEnvironmentVariableFn ExGetFirmwareEnvironmentVariablePtr = NULL;
+static KeAreAllApcsDisabledFn KeAreAllApcsDisabledPtr = NULL;
POOL_TYPE ExDefaultNonPagedPoolType = NonPagedPool;
ULONG ExDefaultMdlProtection = 0;
@@ -272,6 +273,15 @@ 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
if ((OsMajorVersion > 6) || (OsMajorVersion == 6 && OsMinorVersion >= 1))
{
@@ -3457,6 +3467,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 +3490,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 +3574,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 +3890,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 +4107,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 +4138,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)
+ NTSTATUS updateStatus = UpdateFsVolumeInformation (mount, NewExtension);
+ if (!NT_SUCCESS (updateStatus))
{
- 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)
- {
-
- }
+ Dump ("MountDevice: UpdateFsVolumeInformation failed with status 0x%08x\n", updateStatus);
}
-
- TCCloseFsVolume (volumeHandle, volumeFileObject);
}
}
else
@@ -4056,6 +4158,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 +4179,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);
@@ -4759,4 +4896,12 @@ VOID NTAPI KeRestoreExtendedProcessorState (
{
(KeRestoreExtendedProcessorStatePtr) (XStateSave);
}
-} \ No newline at end of file
+}
+
+BOOLEAN VC_KeAreAllApcsDisabled (VOID)
+{
+ if (KeAreAllApcsDisabledPtr)
+ return (KeAreAllApcsDisabledPtr) ();
+ else
+ return FALSE;
+}
diff --git a/src/Driver/Ntvol.c b/src/Driver/Ntvol.c
index afd3a964..c3344fd0 100644
--- a/src/Driver/Ntvol.c
+++ b/src/Driver/Ntvol.c
@@ -886,6 +886,18 @@ void TCCloseVolume (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
}
}
+typedef struct
+{
+ PDEVICE_OBJECT deviceObject; PEXTENSION Extension; ULONG ioControlCode; void *inputBuffer; int inputBufferSize; void *outputBuffer; int outputBufferSize;
+ NTSTATUS Status;
+ KEVENT WorkItemCompletedEvent;
+} TCSendHostDeviceIoControlRequestExWorkItemArgs;
+
+static VOID TCSendHostDeviceIoControlRequestExWorkItemRoutine (PDEVICE_OBJECT rootDeviceObject, TCSendHostDeviceIoControlRequestExWorkItemArgs *arg)
+{
+ arg->Status = TCSendHostDeviceIoControlRequestEx (arg->deviceObject, arg->Extension, arg->ioControlCode, arg->inputBuffer, arg->inputBufferSize, arg->outputBuffer, arg->outputBufferSize);
+ KeSetEvent (&arg->WorkItemCompletedEvent, IO_NO_INCREMENT, FALSE);
+}
NTSTATUS TCSendHostDeviceIoControlRequestEx (PDEVICE_OBJECT DeviceObject,
PEXTENSION Extension,
@@ -901,6 +913,31 @@ NTSTATUS TCSendHostDeviceIoControlRequestEx (PDEVICE_OBJECT DeviceObject,
UNREFERENCED_PARAMETER(DeviceObject); /* Remove compiler warning */
+ if ((KeGetCurrentIrql() >= APC_LEVEL) || VC_KeAreAllApcsDisabled())
+ {
+ TCSendHostDeviceIoControlRequestExWorkItemArgs args;
+
+ PIO_WORKITEM workItem = IoAllocateWorkItem (RootDeviceObject);
+ if (!workItem)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ args.deviceObject = DeviceObject;
+ args.Extension = Extension;
+ args.ioControlCode = IoControlCode;
+ args.inputBuffer = InputBuffer;
+ args.inputBufferSize = InputBufferSize;
+ args.outputBuffer = OutputBuffer;
+ args.outputBufferSize = OutputBufferSize;
+
+ KeInitializeEvent (&args.WorkItemCompletedEvent, SynchronizationEvent, FALSE);
+ IoQueueWorkItem (workItem, TCSendHostDeviceIoControlRequestExWorkItemRoutine, DelayedWorkQueue, &args);
+
+ KeWaitForSingleObject (&args.WorkItemCompletedEvent, Executive, KernelMode, FALSE, NULL);
+ IoFreeWorkItem (workItem);
+
+ return args.Status;
+ }
+
KeClearEvent (&Extension->keVolumeEvent);
Irp = IoBuildDeviceIoControlRequest (IoControlCode,