From c29ee8331afa52f72df5fb21daa02457243650fe Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Wed, 26 Jul 2017 23:54:00 +0200 Subject: Windows driver: correctly handle IOCTL_DISK_GET_DRIVE_GEOMETRY_EX to fix issues with some disks. Implement IOCTL_STORAGE_GET_MEDIA_TYPES_EX. --- src/Common/Volumes.c | 25 +++---- src/Driver/Ntdriver.c | 180 ++++++++++++++++++++++++++++++++++++++++++-------- src/Driver/Ntvol.c | 47 ++++++++++++- 3 files changed, 208 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/Common/Volumes.c b/src/Common/Volumes.c index 32da282d..e49ce250 100644 --- a/src/Common/Volumes.c +++ b/src/Common/Volumes.c @@ -1155,21 +1155,21 @@ BOOL ReadEffectiveVolumeHeader (BOOL device, HANDLE fileHandle, byte *header, DW #endif byte sectorBuffer[TC_MAX_VOLUME_SECTOR_SIZE]; - DISK_GEOMETRY_EX geometry; + DISK_GEOMETRY geometry; if (!device) return ReadFile (fileHandle, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, bytesRead, NULL); - if (!DeviceIoControl (fileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &geometry, sizeof (geometry), bytesRead, NULL)) + if (!DeviceIoControl (fileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry), bytesRead, NULL)) return FALSE; - if (geometry.Geometry.BytesPerSector > sizeof (sectorBuffer) || geometry.Geometry.BytesPerSector < TC_MIN_VOLUME_SECTOR_SIZE) + if (geometry.BytesPerSector > sizeof (sectorBuffer) || geometry.BytesPerSector < TC_MIN_VOLUME_SECTOR_SIZE) { SetLastError (ERROR_INVALID_PARAMETER); return FALSE; } - if (!ReadFile (fileHandle, sectorBuffer, max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, geometry.Geometry.BytesPerSector), bytesRead, NULL)) + if (!ReadFile (fileHandle, sectorBuffer, max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, geometry.BytesPerSector), bytesRead, NULL)) return FALSE; memcpy (header, sectorBuffer, min (*bytesRead, TC_VOLUME_HEADER_EFFECTIVE_SIZE)); @@ -1189,7 +1189,7 @@ BOOL WriteEffectiveVolumeHeader (BOOL device, HANDLE fileHandle, byte *header) byte sectorBuffer[TC_MAX_VOLUME_SECTOR_SIZE]; DWORD bytesDone; - DISK_GEOMETRY_EX geometry; + DISK_GEOMETRY geometry; if (!device) { @@ -1205,23 +1205,24 @@ BOOL WriteEffectiveVolumeHeader (BOOL device, HANDLE fileHandle, byte *header) return TRUE; } - if (!DeviceIoControl (fileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &geometry, sizeof (geometry), &bytesDone, NULL)) + + if (!DeviceIoControl (fileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry), &bytesDone, NULL)) return FALSE; - if (geometry.Geometry.BytesPerSector > sizeof (sectorBuffer) || geometry.Geometry.BytesPerSector < TC_MIN_VOLUME_SECTOR_SIZE) + if (geometry.BytesPerSector > sizeof (sectorBuffer) || geometry.BytesPerSector < TC_MIN_VOLUME_SECTOR_SIZE) { SetLastError (ERROR_INVALID_PARAMETER); return FALSE; } - if (geometry.Geometry.BytesPerSector != TC_VOLUME_HEADER_EFFECTIVE_SIZE) + if (geometry.BytesPerSector != TC_VOLUME_HEADER_EFFECTIVE_SIZE) { LARGE_INTEGER seekOffset; - if (!ReadFile (fileHandle, sectorBuffer, geometry.Geometry.BytesPerSector, &bytesDone, NULL)) + if (!ReadFile (fileHandle, sectorBuffer, geometry.BytesPerSector, &bytesDone, NULL)) return FALSE; - if (bytesDone != geometry.Geometry.BytesPerSector) + if (bytesDone != geometry.BytesPerSector) { SetLastError (ERROR_INVALID_PARAMETER); return FALSE; @@ -1234,10 +1235,10 @@ BOOL WriteEffectiveVolumeHeader (BOOL device, HANDLE fileHandle, byte *header) memcpy (sectorBuffer, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); - if (!WriteFile (fileHandle, sectorBuffer, geometry.Geometry.BytesPerSector, &bytesDone, NULL)) + if (!WriteFile (fileHandle, sectorBuffer, geometry.BytesPerSector, &bytesDone, NULL)) return FALSE; - if (bytesDone != geometry.Geometry.BytesPerSector) + if (bytesDone != geometry.BytesPerSector) { SetLastError (ERROR_INVALID_PARAMETER); return FALSE; diff --git a/src/Driver/Ntdriver.c b/src/Driver/Ntdriver.c index 247af64e..73930404 100644 --- a/src/Driver/Ntdriver.c +++ b/src/Driver/Ntdriver.c @@ -709,7 +709,6 @@ NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION break; case IOCTL_DISK_GET_MEDIA_TYPES: - case IOCTL_STORAGE_GET_MEDIA_TYPES: case IOCTL_DISK_GET_DRIVE_GEOMETRY: Dump ("ProcessVolumeDeviceControlIrp (IOCTL_DISK_GET_DRIVE_GEOMETRY)\n"); /* Return the drive geometry for the disk. Note that we @@ -731,28 +730,111 @@ NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: Dump ("ProcessVolumeDeviceControlIrp (IOCTL_DISK_GET_DRIVE_GEOMETRY_EX)\n"); - Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; - Irp->IoStatus.Information = 0; - if (EnableExtendedIoctlSupport) { - /* Return the drive geometry for the disk and its size.*/ - if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY_EX), ValidateOutput)) + ULONG minOutputSize = IsOSAtLeast (WIN_SERVER_2003)? sizeof (DISK_GEOMETRY_EX) : sizeof (DISK_GEOMETRY) + sizeof (LARGE_INTEGER); + ULONG fullOutputSize = sizeof (DISK_GEOMETRY) + sizeof (LARGE_INTEGER) + sizeof (DISK_PARTITION_INFO) + sizeof (DISK_DETECTION_INFO); + + if (ValidateIOBufferSize (Irp, minOutputSize, ValidateOutput)) { - PDISK_GEOMETRY_EX outputBuffer = (PDISK_GEOMETRY_EX) - Irp->AssociatedIrp.SystemBuffer; + PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp); + BOOL bFullBuffer = (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= fullOutputSize)? TRUE : FALSE; + PDISK_GEOMETRY_EX outputBuffer = (PDISK_GEOMETRY_EX) Irp->AssociatedIrp.SystemBuffer; outputBuffer->Geometry.MediaType = Extension->bRemovable ? RemovableMedia : FixedMedia; outputBuffer->Geometry.Cylinders.QuadPart = Extension->NumberOfCylinders; outputBuffer->Geometry.TracksPerCylinder = Extension->TracksPerCylinder; outputBuffer->Geometry.SectorsPerTrack = Extension->SectorsPerTrack; outputBuffer->Geometry.BytesPerSector = Extension->BytesPerSector; - outputBuffer->DiskSize.QuadPart = Extension->DiskLength; + /* add one sector to DiskLength since our partition size is DiskLength and its offset if BytesPerSector */ + outputBuffer->DiskSize.QuadPart = Extension->DiskLength + Extension->BytesPerSector; + + if (bFullBuffer) + { + PDISK_PARTITION_INFO pPartInfo = (PDISK_PARTITION_INFO)(((ULONG_PTR) outputBuffer) + sizeof (DISK_GEOMETRY) + sizeof (LARGE_INTEGER)); + PDISK_DETECTION_INFO pDetectInfo = ((PDISK_DETECTION_INFO)((((ULONG_PTR) pPartInfo) + sizeof (DISK_PARTITION_INFO)))); + + pPartInfo->SizeOfPartitionInfo = sizeof (DISK_PARTITION_INFO); + pPartInfo->PartitionStyle = PARTITION_STYLE_MBR; + pPartInfo->Mbr.Signature = GetCrc32((unsigned char*) &(Extension->UniqueVolumeId), 4); + + pDetectInfo->SizeOfDetectInfo = sizeof (DISK_DETECTION_INFO); + + Irp->IoStatus.Information = fullOutputSize; + } + else + { + if (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof (DISK_GEOMETRY_EX)) + Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_EX); + else + Irp->IoStatus.Information = minOutputSize; + } + Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_EX); } } break; + case IOCTL_STORAGE_GET_MEDIA_TYPES: + Dump ("ProcessVolumeDeviceControlIrp (IOCTL_STORAGE_GET_MEDIA_TYPES)\n"); + /* Return the drive geometry for the disk. Note that we + return values which were made up to suit the disk size. */ + if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY), ValidateOutput)) + { + PDISK_GEOMETRY outputBuffer = (PDISK_GEOMETRY) + Irp->AssociatedIrp.SystemBuffer; + + outputBuffer->MediaType = Extension->bRemovable ? RemovableMedia : FixedMedia; + outputBuffer->Cylinders.QuadPart = Extension->NumberOfCylinders; + outputBuffer->TracksPerCylinder = Extension->TracksPerCylinder; + outputBuffer->SectorsPerTrack = Extension->SectorsPerTrack; + outputBuffer->BytesPerSector = Extension->BytesPerSector; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (DISK_GEOMETRY); + } + break; + + case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: + Dump ("ProcessVolumeDeviceControlIrp (IOCTL_STORAGE_GET_MEDIA_TYPES_EX)\n"); + if (ValidateIOBufferSize (Irp, sizeof (GET_MEDIA_TYPES), ValidateOutput)) + { + PGET_MEDIA_TYPES outputBuffer = (PGET_MEDIA_TYPES) + Irp->AssociatedIrp.SystemBuffer; + PDEVICE_MEDIA_INFO mediaInfo = &outputBuffer->MediaInfo[0]; + + outputBuffer->DeviceType = FILE_DEVICE_DISK; + outputBuffer->MediaInfoCount = 1; + + if (Extension->bRemovable) + { + mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1; + if (Extension->bReadOnly) + mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_ONLY | MEDIA_WRITE_PROTECTED); + else + mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE); + mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = (STORAGE_MEDIA_TYPE) RemovableMedia; + mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = Extension->NumberOfCylinders; + mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = Extension->TracksPerCylinder; + mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = Extension->SectorsPerTrack; + mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = Extension->BytesPerSector; + } + else + { + mediaInfo->DeviceSpecific.DiskInfo.NumberMediaSides = 1; + if (Extension->bReadOnly) + mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_ONLY | MEDIA_WRITE_PROTECTED); + else + mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE); + mediaInfo->DeviceSpecific.DiskInfo.MediaType = (STORAGE_MEDIA_TYPE) FixedMedia; + mediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart = Extension->NumberOfCylinders; + mediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder = Extension->TracksPerCylinder; + mediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack = Extension->SectorsPerTrack; + mediaInfo->DeviceSpecific.DiskInfo.BytesPerSector = Extension->BytesPerSector; + } + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (GET_MEDIA_TYPES); + } + break; + case IOCTL_STORAGE_QUERY_PROPERTY: Dump ("ProcessVolumeDeviceControlIrp (IOCTL_STORAGE_QUERY_PROPERTY)\n"); Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; @@ -1019,7 +1101,6 @@ NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION if (bFullBuffer) { Irp->IoStatus.Information += 3*sizeof(PARTITION_INFORMATION_EX); - memset (((BYTE*) Irp->AssociatedIrp.SystemBuffer) + sizeof (DRIVE_LAYOUT_INFORMATION_EX), 0, 3*sizeof(PARTITION_INFORMATION_EX)); } } } @@ -1166,8 +1247,8 @@ NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION capacity->Version = sizeof (STORAGE_READ_CAPACITY); capacity->Size = sizeof (STORAGE_READ_CAPACITY); capacity->BlockLength = Extension->BytesPerSector; - capacity->NumberOfBlocks.QuadPart = Extension->DiskLength / Extension->BytesPerSector; - capacity->DiskLength.QuadPart = Extension->DiskLength; + capacity->NumberOfBlocks.QuadPart = (Extension->DiskLength / Extension->BytesPerSector) + 1; + capacity->DiskLength.QuadPart = Extension->DiskLength + Extension->BytesPerSector; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof (STORAGE_READ_CAPACITY); @@ -1888,23 +1969,64 @@ NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Ex DISK_GEOMETRY_EX_STRUCT *g = (DISK_GEOMETRY_EX_STRUCT *) Irp->AssociatedIrp.SystemBuffer; { NTSTATUS ntStatus; - DISK_GEOMETRY_EX geo = {0}; + PVOID buffer = TCalloc (256); // enough for DISK_GEOMETRY_EX and padded data + if (buffer) + { + EnsureNullTerminatedString (g->deviceName, sizeof (g->deviceName)); + Dump ("Calling IOCTL_DISK_GET_DRIVE_GEOMETRY_EX on %ls\n", g->deviceName); - EnsureNullTerminatedString (g->deviceName, sizeof (g->deviceName)); - Dump ("Calling IOCTL_DISK_GET_DRIVE_GEOMETRY_EX on %ls\n", g->deviceName); + ntStatus = TCDeviceIoControl (g->deviceName, + IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, + NULL, 0, buffer, 256); - ntStatus = TCDeviceIoControl (g->deviceName, - IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, - NULL, 0, &geo, sizeof (geo)); + if (NT_SUCCESS(ntStatus)) + { + PDISK_GEOMETRY_EX pGeo = (PDISK_GEOMETRY_EX) buffer; + memcpy (&g->diskGeometry, &pGeo->Geometry, sizeof (DISK_GEOMETRY)); + g->DiskSize.QuadPart = pGeo->DiskSize.QuadPart; + } + else + { + DISK_GEOMETRY dg = {0}; + Dump ("Failed. Calling IOCTL_DISK_GET_DRIVE_GEOMETRY on %ls\n", g->deviceName); + ntStatus = TCDeviceIoControl (g->deviceName, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, 0, &dg, sizeof (dg)); - if (NT_SUCCESS(ntStatus)) + if (NT_SUCCESS(ntStatus)) + { + memcpy (&g->diskGeometry, &dg, sizeof (DISK_GEOMETRY)); + g->DiskSize.QuadPart = dg.Cylinders.QuadPart * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.BytesPerSector; + + if (OsMajorVersion >= 6) + { + STORAGE_READ_CAPACITY storage = {0}; + NTSTATUS lStatus; + storage.Version = sizeof (STORAGE_READ_CAPACITY); + Dump ("Calling IOCTL_STORAGE_READ_CAPACITY on %ls\n", g->deviceName); + lStatus = TCDeviceIoControl (g->deviceName, + IOCTL_STORAGE_READ_CAPACITY, + NULL, 0, &storage, sizeof (STORAGE_READ_CAPACITY)); + if ( NT_SUCCESS(lStatus) + && (storage.Size == sizeof (STORAGE_READ_CAPACITY)) + ) + { + g->DiskSize.QuadPart = storage.DiskLength.QuadPart; + } + } + } + } + + TCfree (buffer); + + Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_EX_STRUCT); + Irp->IoStatus.Status = ntStatus; + } + else { - memcpy (&g->diskGeometry, &geo.Geometry, sizeof (DISK_GEOMETRY)); - g->DiskSize.QuadPart = geo.DiskSize.QuadPart; + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Information = 0; } - - Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_EX_STRUCT); - Irp->IoStatus.Status = ntStatus; } } break; @@ -3877,14 +3999,14 @@ NTSTATUS WriteRegistryConfigFlags (uint32 flags) NTSTATUS GetDeviceSectorSize (PDEVICE_OBJECT deviceObject, ULONG *bytesPerSector) { NTSTATUS status; - DISK_GEOMETRY_EX geometry; - - status = SendDeviceIoControlRequest (deviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &geometry, sizeof (geometry)); + DISK_GEOMETRY geometry; + status = SendDeviceIoControlRequest (deviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry)); if (!NT_SUCCESS (status)) return status; - *bytesPerSector = geometry.Geometry.BytesPerSector; + *bytesPerSector = geometry.BytesPerSector; + return STATUS_SUCCESS; } diff --git a/src/Driver/Ntvol.c b/src/Driver/Ntvol.c index b9117571..99e06bdf 100644 --- a/src/Driver/Ntvol.c +++ b/src/Driver/Ntvol.c @@ -90,6 +90,7 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject, DISK_GEOMETRY_EX dg; STORAGE_PROPERTY_QUERY storagePropertyQuery = {0}; STORAGE_DESCRIPTOR_HEADER storageHeader = {0}; + byte* dgBuffer; ntStatus = IoGetDeviceObjectPointer (&FullFileName, FILE_READ_DATA | FILE_READ_ATTRIBUTES, @@ -99,9 +100,48 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject, if (!NT_SUCCESS (ntStatus)) goto error; - ntStatus = TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, (char *) &dg, sizeof (dg)); - if (!NT_SUCCESS (ntStatus)) + dgBuffer = TCalloc (256); + if (!dgBuffer) + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; goto error; + } + + ntStatus = TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, (char *) dgBuffer, 256); + if (!NT_SUCCESS (ntStatus)) + { + DISK_GEOMETRY geo; + ntStatus = TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_DRIVE_GEOMETRY, (char *) &geo, sizeof (geo)); + if (!NT_SUCCESS (ntStatus)) + { + TCfree (dgBuffer); + goto error; + } + memset (&dg, 0, sizeof (dg)); + memcpy (&dg.Geometry, &geo, sizeof (geo)); + dg.DiskSize.QuadPart = geo.Cylinders.QuadPart * geo.SectorsPerTrack * geo.TracksPerCylinder * geo.BytesPerSector; + + if (OsMajorVersion >= 6) + { + STORAGE_READ_CAPACITY storage = {0}; + NTSTATUS lStatus; + + storage.Version = sizeof (STORAGE_READ_CAPACITY); + lStatus = TCSendHostDeviceIoControlRequest (DeviceObject, Extension, + IOCTL_STORAGE_READ_CAPACITY, + (char*) &storage, sizeof (STORAGE_READ_CAPACITY)); + if ( NT_SUCCESS(lStatus) + && (storage.Size == sizeof (STORAGE_READ_CAPACITY)) + ) + { + dg.DiskSize.QuadPart = storage.DiskLength.QuadPart; + } + } + } + else + memcpy (&dg, dgBuffer, sizeof (DISK_GEOMETRY_EX)); + + TCfree (dgBuffer); lDiskLength.QuadPart = dg.DiskSize.QuadPart; Extension->HostBytesPerSector = dg.Geometry.BytesPerSector; @@ -704,7 +744,8 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject, Extension->TracksPerCylinder = 1; Extension->SectorsPerTrack = 1; Extension->BytesPerSector = Extension->cryptoInfo->SectorSize; - Extension->NumberOfCylinders = Extension->DiskLength / Extension->BytesPerSector; + // Add extra sector since our virtual partition starts at Extension->BytesPerSector and not 0 + Extension->NumberOfCylinders = (Extension->DiskLength / Extension->BytesPerSector) + 1; Extension->PartitionType = 0; Extension->bRawDevice = bRawDevice; -- cgit v1.2.3