diff options
Diffstat (limited to 'src/Driver/Ntvol.c')
-rw-r--r-- | src/Driver/Ntvol.c | 152 |
1 files changed, 135 insertions, 17 deletions
diff --git a/src/Driver/Ntvol.c b/src/Driver/Ntvol.c index 81549ba1..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; @@ -68,6 +70,12 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject, Extension->HostMaximumPhysicalPages = 17; Extension->HostAlignmentMask = 0; + /* default values for non-SSD drives */ + 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); @@ -80,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) @@ -90,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, @@ -143,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; @@ -152,6 +169,8 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject, { STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR alignmentDesc = {0}; STORAGE_ADAPTER_DESCRIPTOR adapterDesc = {0}; + DEVICE_SEEK_PENALTY_DESCRIPTOR penaltyDesc = {0}; + DEVICE_TRIM_DESCRIPTOR trimDesc = {0}; storagePropertyQuery.PropertyId = StorageAccessAlignmentProperty; storagePropertyQuery.QueryType = PropertyStandardQuery; @@ -178,6 +197,28 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject, Extension->HostMaximumPhysicalPages = adapterDesc.MaximumPhysicalPages; Extension->HostAlignmentMask = adapterDesc.AlignmentMask; } + + storagePropertyQuery.PropertyId = StorageDeviceSeekPenaltyProperty; + penaltyDesc.Version = sizeof (DEVICE_SEEK_PENALTY_DESCRIPTOR); + penaltyDesc.Size = sizeof (DEVICE_SEEK_PENALTY_DESCRIPTOR); + + if (NT_SUCCESS (TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IOCTL_STORAGE_QUERY_PROPERTY, + (char*) &storagePropertyQuery, sizeof(storagePropertyQuery), + (char *) &penaltyDesc, sizeof (penaltyDesc)))) + { + Extension->IncursSeekPenalty = penaltyDesc.IncursSeekPenalty; + } + + storagePropertyQuery.PropertyId = StorageDeviceTrimProperty; + trimDesc.Version = sizeof (DEVICE_TRIM_DESCRIPTOR); + trimDesc.Size = sizeof (DEVICE_TRIM_DESCRIPTOR); + + if (NT_SUCCESS (TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IOCTL_STORAGE_QUERY_PROPERTY, + (char*) &storagePropertyQuery, sizeof(storagePropertyQuery), + (char *) &trimDesc, sizeof (trimDesc)))) + { + Extension->TrimEnabled = trimDesc.TrimEnabled; + } } // Drive geometry is used only when IOCTL_DISK_GET_PARTITION_INFO fails @@ -186,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; @@ -265,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, @@ -280,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; @@ -324,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, @@ -414,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; @@ -532,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); } @@ -569,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); @@ -602,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) @@ -625,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; @@ -723,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; @@ -751,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) @@ -843,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, @@ -858,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, |