VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Driver/Ntvol.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Driver/Ntvol.c')
-rw-r--r--src/Driver/Ntvol.c124
1 files changed, 107 insertions, 17 deletions
diff --git a/src/Driver/Ntvol.c b/src/Driver/Ntvol.c
index c8552ab3..444468c5 100644
--- a/src/Driver/Ntvol.c
+++ b/src/Driver/Ntvol.c
@@ -43,21 +43,23 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
PWSTR pwszMountVolume,
BOOL bRawDevice)
{
- FILE_STANDARD_INFORMATION FileStandardInfo;
+ FILE_STANDARD_INFORMATION FileStandardInfo = { 0 };
FILE_BASIC_INFORMATION FileBasicInfo;
OBJECT_ATTRIBUTES oaFileAttributes;
UNICODE_STRING FullFileName;
IO_STATUS_BLOCK IoStatusBlock;
PCRYPTO_INFO cryptoInfoPtr = NULL;
PCRYPTO_INFO tmpCryptoInfo = NULL;
- LARGE_INTEGER lDiskLength;
+ LARGE_INTEGER lDiskLength = { 0 };
__int64 partitionStartingOffset = 0;
int volumeType;
char *readBuffer = 0;
NTSTATUS ntStatus = 0;
- BOOL forceAccessCheck = (!bRawDevice && !(OsMajorVersion == 5 &&OsMinorVersion == 0)); // Windows 2000 does not support OBJ_FORCE_ACCESS_CHECK attribute
+ BOOL forceAccessCheck = !bRawDevice;
BOOL disableBuffering = TRUE;
BOOL exclusiveAccess = mount->bExclusiveAccess;
+ /* when mounting with hidden volume protection, we cache the passwords after both outer and hidden volumes are mounted successfully*/
+ BOOL bAutoCachePassword = mount->bProtectHiddenVolume? FALSE : mount->bCache;
Extension->pfoDeviceFile = NULL;
Extension->hDeviceFile = NULL;
@@ -72,6 +74,8 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
Extension->IncursSeekPenalty = TRUE;
Extension->TrimEnabled = FALSE;
+ Extension->DeviceNumber = (ULONG) -1;
+
RtlInitUnicodeString (&FullFileName, pwszMountVolume);
InitializeObjectAttributes (&oaFileAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | (forceAccessCheck ? OBJ_FORCE_ACCESS_CHECK : 0) | OBJ_KERNEL_HANDLE, NULL, NULL);
KeInitializeEvent (&Extension->keVolumeEvent, NotificationEvent, FALSE);
@@ -84,6 +88,7 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
}
mount->VolumeMountedReadOnlyAfterDeviceWriteProtected = FALSE;
+ mount->VolumeMountedReadOnlyAfterPartialSysEnc = FALSE;
// If we are opening a device, query its size first
if (bRawDevice)
@@ -94,6 +99,7 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
DISK_GEOMETRY_EX dg;
STORAGE_PROPERTY_QUERY storagePropertyQuery = {0};
byte* dgBuffer;
+ STORAGE_DEVICE_NUMBER storageDeviceNumber;
ntStatus = IoGetDeviceObjectPointer (&FullFileName,
FILE_READ_DATA | FILE_READ_ATTRIBUTES,
@@ -147,6 +153,13 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
TCfree (dgBuffer);
+ if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension,
+ IOCTL_STORAGE_GET_DEVICE_NUMBER,
+ (char*) &storageDeviceNumber, sizeof (storageDeviceNumber))))
+ {
+ Extension->DeviceNumber = storageDeviceNumber.DeviceNumber;
+ }
+
lDiskLength.QuadPart = dg.DiskSize.QuadPart;
Extension->HostBytesPerSector = dg.Geometry.BytesPerSector;
Extension->HostBytesPerPhysicalSector = dg.Geometry.BytesPerSector;
@@ -214,7 +227,7 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
lDiskLength.QuadPart = pix.PartitionLength.QuadPart;
partitionStartingOffset = pix.StartingOffset.QuadPart;
}
- // Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX
+ // If IOCTL_DISK_GET_PARTITION_INFO_EX fails, switch to IOCTL_DISK_GET_PARTITION_INFO
else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO, (char *) &pi, sizeof (pi))))
{
lDiskLength.QuadPart = pi.PartitionLength.QuadPart;
@@ -293,7 +306,7 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
if (mount->bMountReadOnly || ntStatus == STATUS_ACCESS_DENIED)
{
ntStatus = ZwCreateFile (&Extension->hDeviceFile,
- GENERIC_READ | SYNCHRONIZE,
+ GENERIC_READ | (!bRawDevice && mount->bPreserveTimestamp? FILE_WRITE_ATTRIBUTES : 0) | SYNCHRONIZE,
&oaFileAttributes,
&IoStatusBlock,
NULL,
@@ -308,6 +321,26 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
NULL,
0);
+ if (!NT_SUCCESS (ntStatus) && !bRawDevice && mount->bPreserveTimestamp)
+ {
+ /* try again without FILE_WRITE_ATTRIBUTES */
+ ntStatus = ZwCreateFile (&Extension->hDeviceFile,
+ GENERIC_READ | SYNCHRONIZE,
+ &oaFileAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL |
+ FILE_ATTRIBUTE_SYSTEM,
+ exclusiveAccess ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_RANDOM_ACCESS |
+ FILE_WRITE_THROUGH |
+ (disableBuffering ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0);
+ }
+
if (NT_SUCCESS (ntStatus) && !mount->bMountReadOnly)
mount->VolumeMountedReadOnlyAfterAccessDenied = TRUE;
@@ -352,6 +385,18 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
Extension->fileLastWriteTime = FileBasicInfo.LastWriteTime;
Extension->fileLastChangeTime = FileBasicInfo.ChangeTime;
Extension->bTimeStampValid = TRUE;
+
+ // we tell the system not to update LastAccessTime, LastWriteTime, and ChangeTime
+ FileBasicInfo.CreationTime.QuadPart = 0;
+ FileBasicInfo.LastAccessTime.QuadPart = -1;
+ FileBasicInfo.LastWriteTime.QuadPart = -1;
+ FileBasicInfo.ChangeTime.QuadPart = -1;
+
+ ZwSetInformationFile (Extension->hDeviceFile,
+ &IoStatusBlock,
+ &FileBasicInfo,
+ sizeof (FileBasicInfo),
+ FileBasicInformation);
}
ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
@@ -442,7 +487,7 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
// Header of a volume that is not within the scope of system encryption, or
// header of a system hidden volume (containing a hidden OS)
- LARGE_INTEGER headerOffset;
+ LARGE_INTEGER headerOffset = {0};
if (mount->UseBackupHeader && lDiskLength.QuadPart <= TC_TOTAL_VOLUME_HEADERS_SIZE)
continue;
@@ -560,26 +605,24 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
{
mount->nReturnCode = ReadVolumeHeaderWCache (
FALSE,
- mount->bCache,
+ bAutoCachePassword,
mount->bCachePim,
readBuffer,
&mount->ProtectedHidVolPassword,
mount->ProtectedHidVolPkcs5Prf,
mount->ProtectedHidVolPim,
- mount->bTrueCryptMode,
&tmpCryptoInfo);
}
else
{
mount->nReturnCode = ReadVolumeHeaderWCache (
mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_NORMAL,
- mount->bCache,
+ bAutoCachePassword,
mount->bCachePim,
readBuffer,
&mount->VolumePassword,
mount->pkcs5_prf,
mount->VolumePim,
- mount->bTrueCryptMode,
&Extension->cryptoInfo);
}
@@ -597,6 +640,11 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
goto error;
}
+#ifdef _WIN64
+ if (IsRamEncryptionEnabled() && (volumeType == TC_VOLUME_TYPE_NORMAL || !mount->bProtectHiddenVolume))
+ VcProtectKeys (Extension->cryptoInfo, VcGetEncryptionID (Extension->cryptoInfo));
+#endif
+
Dump ("Volume header decrypted\n");
Dump ("Required program version = %x\n", (int) Extension->cryptoInfo->RequiredProgramVersion);
Dump ("Legacy volume = %d\n", (int) Extension->cryptoInfo->LegacyVolume);
@@ -630,10 +678,9 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
{
- // Partial encryption is not supported for volumes mounted as regular
- mount->nReturnCode = ERR_ENCRYPTION_NOT_COMPLETED;
- ntStatus = STATUS_SUCCESS;
- goto error;
+ // mount as readonly in case of partial system encryption
+ Extension->bReadOnly = mount->bMountReadOnly = TRUE;
+ mount->VolumeMountedReadOnlyAfterPartialSysEnc = TRUE;
}
}
else if (Extension->cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC)
@@ -653,7 +700,7 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
if (Extension->cryptoInfo->hiddenVolume && IsHiddenSystemRunning())
{
// Prevent mount of a hidden system partition if the system hosted on it is currently running
- if (memcmp (Extension->cryptoInfo->master_keydata, GetSystemDriveCryptoInfo()->master_keydata, EAGetKeySize (Extension->cryptoInfo->ea)) == 0)
+ if (memcmp (Extension->cryptoInfo->master_keydata_hash, GetSystemDriveCryptoInfo()->master_keydata_hash, sizeof(Extension->cryptoInfo->master_keydata_hash)) == 0)
{
mount->nReturnCode = ERR_VOL_ALREADY_MOUNTED;
ntStatus = STATUS_SUCCESS;
@@ -751,8 +798,7 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
Extension->TracksPerCylinder = 1;
Extension->SectorsPerTrack = 1;
Extension->BytesPerSector = Extension->cryptoInfo->SectorSize;
- // Add extra sector since our virtual partition starts at Extension->BytesPerSector and not 0
- Extension->NumberOfCylinders = (Extension->DiskLength / Extension->BytesPerSector) + 1;
+ Extension->NumberOfCylinders = Extension->DiskLength / Extension->BytesPerSector;
Extension->PartitionType = 0;
Extension->bRawDevice = bRawDevice;
@@ -779,6 +825,13 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
// decrypt the hidden volume header.
if (!(volumeType == TC_VOLUME_TYPE_NORMAL && mount->bProtectHiddenVolume))
{
+ /* in case of mounting with hidden volume protection, we cache both passwords manually after bother outer and hidden volumes are mounted*/
+ if (mount->bProtectHiddenVolume && mount->bCache)
+ {
+ AddPasswordToCache(&mount->VolumePassword, mount->VolumePim, mount->bCachePim);
+ AddPasswordToCache(&mount->ProtectedHidVolPassword, mount->ProtectedHidVolPim, mount->bCachePim);
+ }
+
TCfree (readBuffer);
if (tmpCryptoInfo != NULL)
@@ -871,6 +924,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,
@@ -886,6 +951,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,