[PARTMGR] Reimplement IOCTL_MOUNTDEV_QUERY_UNIQUE_ID for MBR and GPT partitions (#6926)

CORE-15575

In addition, fix a PartitionId assignment copy-paste error in PartitionCreateDevice().

The returned standard UniqueId has the following format:

- Basic volume on MBR disk: disk Mbr.Signature + partition StartingOffset (length: 0x0C)
- Basic volume on GPT disk: "DMIO:ID:" + Gpt.PartitionGuid (length: 0x18)
- Volume on Basic disk (NT <= 4): 8-byte FTDisk identifier (length: 0x08)
- Volume on Dynamic disk (NT 5+): "DMIO:ID:" + dmio VolumeGuid (length: 0x18)
- Super-floppy (single-partition with StartingOffset == 0),
  or Removable media: DiskInterfaceName.
- As fallback, we use the VolumeInterfaceName.

References:
- https://winreg-kb.readthedocs.io/en/latest/sources/system-keys/Mounted-devices.html
- https://stackoverflow.com/a/72787681/21852502
- Manual testing on Windows.
This commit is contained in:
Hermès Bélusca-Maïto 2024-05-22 22:45:52 +02:00
parent 3d26d76a4c
commit e80cd6760c
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
2 changed files with 92 additions and 17 deletions

View file

@ -65,7 +65,7 @@ PartitionCreateDevice(
else else
{ {
partExt->Gpt.PartitionType = PartitionEntry->Gpt.PartitionType; partExt->Gpt.PartitionType = PartitionEntry->Gpt.PartitionType;
partExt->Gpt.PartitionId = PartitionEntry->Gpt.PartitionType; partExt->Gpt.PartitionId = PartitionEntry->Gpt.PartitionId;
partExt->Gpt.Attributes = PartitionEntry->Gpt.Attributes; partExt->Gpt.Attributes = PartitionEntry->Gpt.Attributes;
RtlCopyMemory(partExt->Gpt.Name, PartitionEntry->Gpt.Name, sizeof(partExt->Gpt.Name)); RtlCopyMemory(partExt->Gpt.Name, PartitionEntry->Gpt.Name, sizeof(partExt->Gpt.Name));
@ -756,7 +756,7 @@ PartitionHandleDeviceControl(
Irp->IoStatus.Information = sizeof(*gptAttrs); Irp->IoStatus.Information = sizeof(*gptAttrs);
break; break;
} }
// mountmgr stuff // mountmgr notifications (these should be in volmgr.sys once it is implemented)
case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
{ {
PMOUNTDEV_NAME name = Irp->AssociatedIrp.SystemBuffer; PMOUNTDEV_NAME name = Irp->AssociatedIrp.SystemBuffer;
@ -785,36 +785,88 @@ PartitionHandleDeviceControl(
} }
case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
{ {
const SIZE_T headerSize = FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId);
PMOUNTDEV_UNIQUE_ID uniqueId = Irp->AssociatedIrp.SystemBuffer; PMOUNTDEV_UNIQUE_ID uniqueId = Irp->AssociatedIrp.SystemBuffer;
PBASIC_VOLUME_UNIQUE_ID basicVolId = (PBASIC_VOLUME_UNIQUE_ID)&uniqueId->UniqueId;
PUNICODE_STRING InterfaceName;
if (!partExt->VolumeInterfaceName.Buffer) // Check whether the minimal header size was provided
{ if (!VerifyIrpOutBufferSize(Irp, headerSize))
status = STATUS_INVALID_PARAMETER;
break;
}
if (!VerifyIrpOutBufferSize(Irp, sizeof(USHORT)))
{ {
status = STATUS_BUFFER_TOO_SMALL; status = STATUS_BUFFER_TOO_SMALL;
break; break;
} }
uniqueId->UniqueIdLength = partExt->VolumeInterfaceName.Length; PartMgrAcquireLayoutLock(fdoExtension);
// return UniqueIdLength back InterfaceName = &partExt->VolumeInterfaceName;
if (!VerifyIrpOutBufferSize(Irp, sizeof(USHORT) + uniqueId->UniqueIdLength)) if (fdoExtension->IsSuperFloppy)
InterfaceName = &fdoExtension->DiskInterfaceName;
// Calculate and return the necessary data size
if ((fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR) &&
!fdoExtension->IsSuperFloppy)
{ {
Irp->IoStatus.Information = sizeof(USHORT); uniqueId->UniqueIdLength = sizeof(basicVolId->Mbr);
}
else if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_GPT)
{
uniqueId->UniqueIdLength = sizeof(basicVolId->Gpt);
}
else
{
if (!InterfaceName->Buffer || !InterfaceName->Length)
{
PartMgrReleaseLayoutLock(fdoExtension);
status = STATUS_INVALID_PARAMETER;
break;
}
uniqueId->UniqueIdLength = InterfaceName->Length;
}
// Return UniqueIdLength back
if (!VerifyIrpOutBufferSize(Irp, headerSize + uniqueId->UniqueIdLength))
{
PartMgrReleaseLayoutLock(fdoExtension);
Irp->IoStatus.Information = headerSize;
status = STATUS_BUFFER_OVERFLOW; status = STATUS_BUFFER_OVERFLOW;
break; break;
} }
//
// Write the UniqueId
//
// Format:
// - Basic volume on MBR disk: disk Mbr.Signature + partition StartingOffset (length: 0x0C)
// - Basic volume on GPT disk: "DMIO:ID:" + Gpt.PartitionGuid (length: 0x18)
// - Volume on Basic disk (NT <= 4): 8-byte FTDisk identifier (length: 0x08)
// - Volume on Dynamic disk (NT 5+): "DMIO:ID:" + dmio VolumeGuid (length: 0x18)
// - Super-floppy (single-partition with StartingOffset == 0),
// or Removable media: DiskInterfaceName.
// - As fallback, we use the VolumeInterfaceName.
//
if ((fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR) &&
!fdoExtension->IsSuperFloppy)
{
basicVolId->Mbr.Signature = fdoExtension->DiskData.Mbr.Signature;
basicVolId->Mbr.StartingOffset = partExt->StartingOffset;
}
else if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_GPT)
{
basicVolId->Gpt.Signature = DMIO_ID_SIGNATURE;
basicVolId->Gpt.PartitionGuid = partExt->Gpt.PartitionId;
}
else
{
RtlCopyMemory(uniqueId->UniqueId, RtlCopyMemory(uniqueId->UniqueId,
partExt->VolumeInterfaceName.Buffer, InterfaceName->Buffer,
uniqueId->UniqueIdLength); uniqueId->UniqueIdLength);
}
PartMgrReleaseLayoutLock(fdoExtension);
status = STATUS_SUCCESS; status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(USHORT) + uniqueId->UniqueIdLength; Irp->IoStatus.Information = headerSize + uniqueId->UniqueIdLength;
break; break;
} }
default: default:

View file

@ -31,6 +31,29 @@ typedef struct _DISK_GEOMETRY_EX_INTERNAL
DISK_DETECTION_INFO Detection; DISK_DETECTION_INFO Detection;
} DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL; } DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL;
// Unique ID data for basic (disk partition-based) volumes.
// It is stored in the MOUNTDEV_UNIQUE_ID::UniqueId member
// as an array of bytes.
#include <pshpack1.h>
typedef union _BASIC_VOLUME_UNIQUE_ID
{
struct
{
ULONG Signature;
ULONGLONG StartingOffset;
} Mbr;
struct
{
ULONGLONG Signature; // UCHAR[8] // "DMIO:ID:"
GUID PartitionGuid;
} Gpt;
} BASIC_VOLUME_UNIQUE_ID, *PBASIC_VOLUME_UNIQUE_ID;
#include <poppack.h>
C_ASSERT(RTL_FIELD_SIZE(BASIC_VOLUME_UNIQUE_ID, Mbr) == 0x0C);
C_ASSERT(RTL_FIELD_SIZE(BASIC_VOLUME_UNIQUE_ID, Gpt) == 0x18);
#define DMIO_ID_SIGNATURE (*(ULONGLONG*)"DMIO:ID:")
typedef struct _FDO_EXTENSION typedef struct _FDO_EXTENSION
{ {
BOOLEAN IsFDO; BOOLEAN IsFDO;