reactos/ntoskrnl/io/iomgr/arcname.c
Hermès Bélusca-Maïto 4b4ffa92f5
[NTOS:IO] Modify when 'PartitionBuffer' and how 'DriveLayout' are freed in IopCreateArcNamesDisk().
- Manage the lifetime of the temporary 'PartitionBuffer' buffer where
  it is locally used only, and free it as soon as possible, just after
  calculating the sector checksum. No need to then free it outside of
  the main for-loop.

- When the 'DriveLayout' buffer is freed, ensure the pointer is NULL-ed
  (and assert this at the top of the main for-loop), since it can also
  be freed at cleanup outside this for-loop, and in this case a NULL
  check is performed.
  This will avoid the scenario of possibly double-freeing a pointer,
  in the case the 'DriveLayout' was previously freed (when e.g. reading
  the sector for checksum calculation failed), then the for-loop goes to
  the next disk and stops early.
2021-06-11 02:21:48 +02:00

993 lines
36 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/io/iomgr/arcname.c
* PURPOSE: ARC Path Initialization Functions
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Eric Kohl
* Pierre Schweitzer (pierre.schweitzer@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
UNICODE_STRING IoArcHalDeviceName, IoArcBootDeviceName;
PCHAR IoLoaderArcBootDeviceName;
/* FUNCTIONS *****************************************************************/
CODE_SEG("INIT")
NTSTATUS
NTAPI
IopCreateArcNamesCd(IN PLOADER_PARAMETER_BLOCK LoaderBlock);
CODE_SEG("INIT")
NTSTATUS
NTAPI
IopCreateArcNamesDisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
IN BOOLEAN SingleDisk,
OUT PBOOLEAN FoundBoot);
CODE_SEG("INIT")
NTSTATUS
NTAPI
IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
SIZE_T Length;
NTSTATUS Status;
CHAR Buffer[128];
BOOLEAN SingleDisk;
BOOLEAN FoundBoot = FALSE;
UNICODE_STRING SystemDevice, LoaderPathNameW, BootDeviceName;
PARC_DISK_INFORMATION ArcDiskInfo = LoaderBlock->ArcDiskInformation;
ANSI_STRING ArcSystemString, ArcString, LanmanRedirector, LoaderPathNameA;
/* Check if we only have one disk on the machine */
SingleDisk = (ArcDiskInfo->DiskSignatureListHead.Flink->Flink ==
&ArcDiskInfo->DiskSignatureListHead);
/* Create the global HAL partition name */
sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcHalDeviceName);
RtlInitAnsiString(&ArcString, Buffer);
RtlAnsiStringToUnicodeString(&IoArcHalDeviceName, &ArcString, TRUE);
/* Create the global system partition name */
sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
RtlInitAnsiString(&ArcString, Buffer);
RtlAnsiStringToUnicodeString(&IoArcBootDeviceName, &ArcString, TRUE);
/* Allocate memory for the string */
Length = strlen(LoaderBlock->ArcBootDeviceName) + sizeof(ANSI_NULL);
IoLoaderArcBootDeviceName = ExAllocatePoolWithTag(PagedPool,
Length,
TAG_IO);
if (IoLoaderArcBootDeviceName)
{
/* Copy the name */
RtlCopyMemory(IoLoaderArcBootDeviceName,
LoaderBlock->ArcBootDeviceName,
Length);
}
/* Check if we only found a disk, but we're booting from CD-ROM */
if ((SingleDisk) && strstr(LoaderBlock->ArcBootDeviceName, "cdrom"))
{
/* Then disable single-disk mode, since there's a CD drive out there */
SingleDisk = FALSE;
}
/* Build the boot strings */
RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName);
/* If we are doing remote booting */
if (IoRemoteBootClient)
{
/* Yes, we have found boot device */
FoundBoot = TRUE;
/* Get NT device name */
RtlInitAnsiString(&LanmanRedirector, "\\Device\\LanmanRedirector");
Status = RtlAnsiStringToUnicodeString(&SystemDevice, &LanmanRedirector, TRUE);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Get ARC booting device name (in net(0) something) */
sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
RtlInitAnsiString(&ArcString, Buffer);
Status = RtlAnsiStringToUnicodeString(&BootDeviceName, &ArcString, TRUE);
if (NT_SUCCESS(Status))
{
/* Map ARC to NT name */
IoAssignArcName(&BootDeviceName, &SystemDevice);
RtlFreeUnicodeString(&BootDeviceName);
/* Now, get loader path name */
RtlInitAnsiString(&LoaderPathNameA, LoaderBlock->NtHalPathName);
Status = RtlAnsiStringToUnicodeString(&LoaderPathNameW, &LoaderPathNameA, TRUE);
if (!NT_SUCCESS(Status))
{
RtlFreeUnicodeString(&SystemDevice);
return Status;
}
/* And set it has system partition */
IopStoreSystemPartitionInformation(&SystemDevice, &LoaderPathNameW);
}
RtlFreeUnicodeString(&SystemDevice);
/* Don't quit here, even if everything went fine!
* We need IopCreateArcNamesDisk to properly map
* devices with symlinks.
* It will return success if the mapping process went fine
* even if it didn't find boot device.
* It won't reset boot device finding status as well.
*/
}
/* Loop every disk and try to find boot disk */
Status = IopCreateArcNamesDisk(LoaderBlock, SingleDisk, &FoundBoot);
/* If it succeeded but we didn't find boot device, try to browse Cds */
if (NT_SUCCESS(Status) && !FoundBoot)
{
Status = IopCreateArcNamesCd(LoaderBlock);
}
/* Return success */
return Status;
}
CODE_SEG("INIT")
NTSTATUS
NTAPI
IopCreateArcNamesCd(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
PIRP Irp;
KEVENT Event;
NTSTATUS Status;
PLIST_ENTRY NextEntry;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
LARGE_INTEGER StartingOffset;
IO_STATUS_BLOCK IoStatusBlock;
PULONG PartitionBuffer = NULL;
CHAR Buffer[128], ArcBuffer[128];
BOOLEAN NotEnabledPresent = FALSE;
STORAGE_DEVICE_NUMBER DeviceNumber;
ANSI_STRING DeviceStringA, ArcNameStringA;
PWSTR SymbolicLinkList, lSymbolicLinkList;
PARC_DISK_SIGNATURE ArcDiskSignature = NULL;
UNICODE_STRING DeviceStringW, ArcNameStringW;
ULONG DiskNumber, CdRomCount, CheckSum, i, EnabledDisks = 0;
PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation;
/* Get all the Cds present in the system */
CdRomCount = IoGetConfigurationInformation()->CdRomCount;
/* Get enabled Cds and check if result matches
* For the record, enabled Cds (or even disk) are Cds/disks
* that have been successfully handled by MountMgr driver
* and that already own their device name. This is the "new" way
* to handle them, that came with NT5.
* Currently, Windows 2003 provides an ARC names creation based
* on both enabled drives and not enabled drives (lack from
* the driver).
* Given the current ReactOS state, that's good for us.
* To sum up, this is NOT a hack or whatsoever.
*/
Status = IopFetchConfigurationInformation(&SymbolicLinkList,
GUID_DEVINTERFACE_CDROM,
CdRomCount,
&EnabledDisks);
if (!NT_SUCCESS(Status))
{
NotEnabledPresent = TRUE;
}
/* Save symbolic link list address in order to free it after */
lSymbolicLinkList = SymbolicLinkList;
/* For the moment, we won't fail */
Status = STATUS_SUCCESS;
/* Browse all the ARC devices trying to find the one matching boot device */
for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
NextEntry != &ArcDiskInformation->DiskSignatureListHead;
NextEntry = NextEntry->Flink)
{
ArcDiskSignature = CONTAINING_RECORD(NextEntry,
ARC_DISK_SIGNATURE,
ListEntry);
if (strcmp(LoaderBlock->ArcBootDeviceName, ArcDiskSignature->ArcName) == 0)
{
break;
}
ArcDiskSignature = NULL;
}
/* Not found... Not booting from a Cd */
if (!ArcDiskSignature)
{
DPRINT("Failed finding a cd that could match current boot device\n");
goto Cleanup;
}
/* Allocate needed space for reading Cd */
PartitionBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, 2048, TAG_IO);
if (!PartitionBuffer)
{
DPRINT("Failed allocating resources!\n");
/* Here, we fail, BUT we return success, some Microsoft joke */
goto Cleanup;
}
/* If we have more enabled Cds, take that into account */
if (EnabledDisks > CdRomCount)
{
CdRomCount = EnabledDisks;
}
/* If we'll have to browse for none enabled Cds, fix higher count */
if (NotEnabledPresent && !EnabledDisks)
{
CdRomCount += 5;
}
/* Finally, if in spite of all that work, we still don't have Cds, leave */
if (!CdRomCount)
{
goto Cleanup;
}
/* Start browsing Cds */
for (DiskNumber = 0, EnabledDisks = 0; DiskNumber < CdRomCount; DiskNumber++)
{
/* Check if we have an enabled disk */
if (lSymbolicLinkList && *lSymbolicLinkList != UNICODE_NULL)
{
/* Create its device name using first symbolic link */
RtlInitUnicodeString(&DeviceStringW, lSymbolicLinkList);
/* Then, update symbolic links list */
lSymbolicLinkList += wcslen(lSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR));
/* Get its associated device object and file object */
Status = IoGetDeviceObjectPointer(&DeviceStringW,
FILE_READ_ATTRIBUTES,
&FileObject,
&DeviceObject);
/* Failure? Good bye! */
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Now, we'll ask the device its device number */
Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
DeviceObject,
NULL,
0,
&DeviceNumber,
sizeof(DeviceNumber),
FALSE,
&Event,
&IoStatusBlock);
/* Failure? Good bye! */
if (!Irp)
{
/* Dereference file object before leaving */
ObDereferenceObject(FileObject);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
/* Call the driver, and wait for it if needed */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(FileObject);
goto Cleanup;
}
/* Finally, build proper device name */
sprintf(Buffer, "\\Device\\CdRom%lu", DeviceNumber.DeviceNumber);
RtlInitAnsiString(&DeviceStringA, Buffer);
Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(FileObject);
goto Cleanup;
}
}
else
{
/* Create device name for the cd */
sprintf(Buffer, "\\Device\\CdRom%lu", EnabledDisks++);
RtlInitAnsiString(&DeviceStringA, Buffer);
Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Get its device object */
Status = IoGetDeviceObjectPointer(&DeviceStringW,
FILE_READ_ATTRIBUTES,
&FileObject,
&DeviceObject);
if (!NT_SUCCESS(Status))
{
RtlFreeUnicodeString(&DeviceStringW);
goto Cleanup;
}
}
/* Initiate data for reading cd and compute checksum */
StartingOffset.QuadPart = 0x8000;
CheckSum = 0;
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
DeviceObject,
PartitionBuffer,
2048,
&StartingOffset,
&Event,
&IoStatusBlock);
if (Irp)
{
/* Call the driver, and wait for it if needed */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
/* If reading succeeded, compute checksum by adding data, 2048 bytes checksum */
if (NT_SUCCESS(Status))
{
for (i = 0; i < 2048 / sizeof(ULONG); i++)
{
CheckSum += PartitionBuffer[i];
}
}
}
/* Dereference file object */
ObDereferenceObject(FileObject);
/* If checksums are matching, we have the proper cd */
if (CheckSum + ArcDiskSignature->CheckSum == 0)
{
/* Create ARC name */
sprintf(ArcBuffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
if (NT_SUCCESS(Status))
{
/* Create symbolic link */
IoAssignArcName(&ArcNameStringW, &DeviceStringW);
RtlFreeUnicodeString(&ArcNameStringW);
DPRINT("Boot device found\n");
}
/* And quit, whatever happens */
RtlFreeUnicodeString(&DeviceStringW);
goto Cleanup;
}
/* Free string before trying another disk */
RtlFreeUnicodeString(&DeviceStringW);
}
Cleanup:
if (PartitionBuffer)
{
ExFreePoolWithTag(PartitionBuffer, TAG_IO);
}
if (SymbolicLinkList)
{
ExFreePool(SymbolicLinkList);
}
return Status;
}
CODE_SEG("INIT")
NTSTATUS
NTAPI
IopCreateArcNamesDisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
IN BOOLEAN SingleDisk,
OUT PBOOLEAN FoundBoot)
{
PIRP Irp;
PVOID Data;
KEVENT Event;
NTSTATUS Status;
PLIST_ENTRY NextEntry;
PFILE_OBJECT FileObject;
DISK_GEOMETRY DiskGeometry;
PDEVICE_OBJECT DeviceObject;
LARGE_INTEGER StartingOffset;
PULONG PartitionBuffer = NULL;
IO_STATUS_BLOCK IoStatusBlock;
CHAR Buffer[128], ArcBuffer[128];
BOOLEAN NotEnabledPresent = FALSE;
STORAGE_DEVICE_NUMBER DeviceNumber;
PARC_DISK_SIGNATURE ArcDiskSignature;
PWSTR SymbolicLinkList, lSymbolicLinkList;
PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = NULL;
UNICODE_STRING DeviceStringW, ArcNameStringW, HalPathStringW;
ULONG DiskNumber, DiskCount, CheckSum, i, Signature, EnabledDisks = 0;
PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation;
ANSI_STRING ArcBootString, ArcSystemString, DeviceStringA, ArcNameStringA, HalPathStringA;
/* Initialise device number */
DeviceNumber.DeviceNumber = ULONG_MAX;
/* Get all the disks present in the system */
DiskCount = IoGetConfigurationInformation()->DiskCount;
/* Get enabled disks and check if result matches */
Status = IopFetchConfigurationInformation(&SymbolicLinkList,
GUID_DEVINTERFACE_DISK,
DiskCount,
&EnabledDisks);
if (!NT_SUCCESS(Status))
{
NotEnabledPresent = TRUE;
}
/* Save symbolic link list address in order to free it after */
lSymbolicLinkList = SymbolicLinkList;
/* Build the boot strings */
RtlInitAnsiString(&ArcBootString, LoaderBlock->ArcBootDeviceName);
RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName);
/* If we have more enabled disks, take that into account */
if (EnabledDisks > DiskCount)
{
DiskCount = EnabledDisks;
}
/* If we'll have to browse for none enabled disks, fix higher count */
if (NotEnabledPresent && !EnabledDisks)
{
DiskCount += 20;
}
/* Finally, if in spite of all that work, we still don't have disks, leave */
if (!DiskCount)
{
goto Cleanup;
}
/* Start browsing disks */
for (DiskNumber = 0; DiskNumber < DiskCount; DiskNumber++)
{
ASSERT(DriveLayout == NULL);
/* Check if we have an enabled disk */
if (lSymbolicLinkList && *lSymbolicLinkList != UNICODE_NULL)
{
/* Create its device name using first symbolic link */
RtlInitUnicodeString(&DeviceStringW, lSymbolicLinkList);
/* Then, update symbolic links list */
lSymbolicLinkList += wcslen(lSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR));
/* Get its associated device object and file object */
Status = IoGetDeviceObjectPointer(&DeviceStringW,
FILE_READ_ATTRIBUTES,
&FileObject,
&DeviceObject);
if (NT_SUCCESS(Status))
{
/* Now, we'll ask the device its device number */
Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
DeviceObject,
NULL,
0,
&DeviceNumber,
sizeof(DeviceNumber),
FALSE,
&Event,
&IoStatusBlock);
/* Missing resources is a shame... No need to go farther */
if (!Irp)
{
ObDereferenceObject(FileObject);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
/* Call the driver, and wait for it if needed */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
/* If we didn't get the appriopriate data, just skip that disk */
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(FileObject);
continue;
}
}
/* End of enabled disks enumeration */
if (NotEnabledPresent && *lSymbolicLinkList == UNICODE_NULL)
{
/* No enabled disk worked, reset field */
if (DeviceNumber.DeviceNumber == ULONG_MAX)
{
DeviceNumber.DeviceNumber = 0;
}
/* Update disk number to enable the following not enabled disks */
if (DeviceNumber.DeviceNumber > DiskNumber)
{
DiskNumber = DeviceNumber.DeviceNumber;
}
/* Increase a bit more */
DiskCount = DiskNumber + 20;
}
}
else
{
/* Create device name for the disk */
sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", DiskNumber);
RtlInitAnsiString(&DeviceStringA, Buffer);
Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Get its device object */
Status = IoGetDeviceObjectPointer(&DeviceStringW,
FILE_READ_ATTRIBUTES,
&FileObject,
&DeviceObject);
RtlFreeUnicodeString(&DeviceStringW);
/* This is a security measure, to ensure DiskNumber will be used */
DeviceNumber.DeviceNumber = ULONG_MAX;
}
/* Something failed somewhere earlier, just skip the disk */
if (!NT_SUCCESS(Status))
{
continue;
}
/* Let's ask the disk for its geometry */
Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
DeviceObject,
NULL,
0,
&DiskGeometry,
sizeof(DiskGeometry),
FALSE,
&Event,
&IoStatusBlock);
/* Missing resources is a shame... No need to go farther */
if (!Irp)
{
ObDereferenceObject(FileObject);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
/* Call the driver, and wait for it if needed */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
/* Failure, skip disk */
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(FileObject);
continue;
}
/* Read the partition table */
Status = IoReadPartitionTableEx(DeviceObject,
&DriveLayout);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(FileObject);
continue;
}
/* Ensure we have at least 512 bytes per sector */
if (DiskGeometry.BytesPerSector < 512)
{
DiskGeometry.BytesPerSector = 512;
}
/* Check MBR type against EZ Drive type */
StartingOffset.QuadPart = 0;
HalExamineMBR(DeviceObject, DiskGeometry.BytesPerSector, 0x55, &Data);
if (Data)
{
/* If MBR is of the EZ Drive type, we'll read after it */
StartingOffset.QuadPart = DiskGeometry.BytesPerSector;
ExFreePool(Data);
}
/* Allocate for reading enough data for checksum */
PartitionBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, DiskGeometry.BytesPerSector, TAG_IO);
if (!PartitionBuffer)
{
ObDereferenceObject(FileObject);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
/* Read the first sector for computing checksum */
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
DeviceObject,
PartitionBuffer,
DiskGeometry.BytesPerSector,
&StartingOffset,
&Event,
&IoStatusBlock);
if (!Irp)
{
ExFreePoolWithTag(PartitionBuffer, TAG_IO);
ObDereferenceObject(FileObject);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
/* Call the driver to perform reading */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
/* If reading succeeded, calculate checksum by adding data */
if (NT_SUCCESS(Status))
{
for (i = 0, CheckSum = 0; i < 512 / sizeof(ULONG); i++)
{
CheckSum += PartitionBuffer[i];
}
}
/* Release now unnecessary resources */
ExFreePoolWithTag(PartitionBuffer, TAG_IO);
ObDereferenceObject(FileObject);
/* If we failed, release drive layout before going to next disk */
if (!NT_SUCCESS(Status))
{
ExFreePool(DriveLayout);
DriveLayout = NULL;
continue;
}
/* Browse each ARC disk */
for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
NextEntry != &ArcDiskInformation->DiskSignatureListHead;
NextEntry = NextEntry->Flink)
{
ArcDiskSignature = CONTAINING_RECORD(NextEntry,
ARC_DISK_SIGNATURE,
ListEntry);
/* If they match, i.e.
* - There's only one disk for both BIOS and detected/enabled
* - Signatures are matching
* - Checksums are matching
* - This is MBR
*/
if (((SingleDisk && DiskCount == 1) ||
(IopVerifyDiskSignature(DriveLayout, ArcDiskSignature, &Signature) &&
(ArcDiskSignature->CheckSum + CheckSum == 0))) &&
(DriveLayout->PartitionStyle == PARTITION_STYLE_MBR))
{
/* Create device name */
sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", (DeviceNumber.DeviceNumber != ULONG_MAX) ? DeviceNumber.DeviceNumber : DiskNumber);
RtlInitAnsiString(&DeviceStringA, Buffer);
Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Create ARC name */
sprintf(ArcBuffer, "\\ArcName\\%s", ArcDiskSignature->ArcName);
RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
if (!NT_SUCCESS(Status))
{
RtlFreeUnicodeString(&DeviceStringW);
goto Cleanup;
}
/* Link both */
IoAssignArcName(&ArcNameStringW, &DeviceStringW);
/* And release resources */
RtlFreeUnicodeString(&ArcNameStringW);
RtlFreeUnicodeString(&DeviceStringW);
/* Now, browse for every partition */
for (i = 1; i <= DriveLayout->PartitionCount; i++)
{
/* Create device name */
sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu", (DeviceNumber.DeviceNumber != ULONG_MAX) ? DeviceNumber.DeviceNumber : DiskNumber, i);
RtlInitAnsiString(&DeviceStringA, Buffer);
Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Create partial ARC name */
sprintf(ArcBuffer, "%spartition(%lu)", ArcDiskSignature->ArcName, i);
RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
/* Is that boot device? */
if (RtlEqualString(&ArcNameStringA, &ArcBootString, TRUE))
{
DPRINT("Found boot device\n");
*FoundBoot = TRUE;
}
/* Is that system partition? */
if (RtlEqualString(&ArcNameStringA, &ArcSystemString, TRUE))
{
/* Create HAL path name */
RtlInitAnsiString(&HalPathStringA, LoaderBlock->NtHalPathName);
Status = RtlAnsiStringToUnicodeString(&HalPathStringW, &HalPathStringA, TRUE);
if (!NT_SUCCESS(Status))
{
RtlFreeUnicodeString(&DeviceStringW);
goto Cleanup;
}
/* Then store those information to registry */
IopStoreSystemPartitionInformation(&DeviceStringW, &HalPathStringW);
RtlFreeUnicodeString(&HalPathStringW);
}
/* Create complete ARC name */
sprintf(ArcBuffer, "\\ArcName\\%spartition(%lu)", ArcDiskSignature->ArcName, i);
RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
if (!NT_SUCCESS(Status))
{
RtlFreeUnicodeString(&DeviceStringW);
goto Cleanup;
}
/* Link device name & ARC name */
IoAssignArcName(&ArcNameStringW, &DeviceStringW);
/* Release strings */
RtlFreeUnicodeString(&ArcNameStringW);
RtlFreeUnicodeString(&DeviceStringW);
}
}
else
{
/* Debugging feedback: Warn in case there's a valid partition,
* a matching signature, BUT a non-matching checksum: this can
* be the sign of a duplicate signature, or even worse a virus
* played with the partition table. */
if (ArcDiskSignature->ValidPartitionTable &&
(ArcDiskSignature->Signature == Signature) &&
(ArcDiskSignature->CheckSum + CheckSum != 0))
{
DPRINT("Be careful, you have a duplicate disk signature, or a virus altered your MBR!\n");
}
}
}
/* Finally, release drive layout */
ExFreePool(DriveLayout);
DriveLayout = NULL;
}
Status = STATUS_SUCCESS;
Cleanup:
if (DriveLayout)
{
ExFreePool(DriveLayout);
}
if (SymbolicLinkList)
{
ExFreePool(SymbolicLinkList);
}
return Status;
}
CODE_SEG("INIT")
NTSTATUS
NTAPI
IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
OUT PANSI_STRING NtBootPath)
{
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
CHAR Buffer[256], AnsiBuffer[256];
WCHAR ArcNameBuffer[64];
ANSI_STRING TargetString, ArcString, TempString;
UNICODE_STRING LinkName, TargetName, ArcName;
HANDLE LinkHandle;
/* Create the Unicode name for the current ARC boot device */
sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
RtlInitAnsiString(&TargetString, Buffer);
Status = RtlAnsiStringToUnicodeString(&TargetName, &TargetString, TRUE);
if (!NT_SUCCESS(Status)) return FALSE;
/* Initialize the attributes and open the link */
InitializeObjectAttributes(&ObjectAttributes,
&TargetName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenSymbolicLinkObject(&LinkHandle,
SYMBOLIC_LINK_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
/* We failed, free the string */
RtlFreeUnicodeString(&TargetName);
return FALSE;
}
/* Query the current \\SystemRoot */
ArcName.Buffer = ArcNameBuffer;
ArcName.Length = 0;
ArcName.MaximumLength = sizeof(ArcNameBuffer);
Status = NtQuerySymbolicLinkObject(LinkHandle, &ArcName, NULL);
if (!NT_SUCCESS(Status))
{
/* We failed, free the string */
RtlFreeUnicodeString(&TargetName);
return FALSE;
}
/* Convert it to Ansi */
ArcString.Buffer = AnsiBuffer;
ArcString.Length = 0;
ArcString.MaximumLength = sizeof(AnsiBuffer);
Status = RtlUnicodeStringToAnsiString(&ArcString, &ArcName, FALSE);
AnsiBuffer[ArcString.Length] = ANSI_NULL;
/* Close the link handle and free the name */
ObCloseHandle(LinkHandle, KernelMode);
RtlFreeUnicodeString(&TargetName);
/* Setup the system root name again */
RtlInitAnsiString(&TempString, "\\SystemRoot");
Status = RtlAnsiStringToUnicodeString(&LinkName, &TempString, TRUE);
if (!NT_SUCCESS(Status)) return FALSE;
/* Open the symbolic link for it */
InitializeObjectAttributes(&ObjectAttributes,
&LinkName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenSymbolicLinkObject(&LinkHandle,
SYMBOLIC_LINK_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status)) return FALSE;
/* Destroy it */
NtMakeTemporaryObject(LinkHandle);
ObCloseHandle(LinkHandle, KernelMode);
/* Now create the new name for it */
sprintf(Buffer, "%s%s", ArcString.Buffer, LoaderBlock->NtBootPathName);
/* Copy it into the passed parameter and null-terminate it */
RtlCopyString(NtBootPath, &ArcString);
Buffer[strlen(Buffer) - 1] = ANSI_NULL;
/* Setup the Unicode-name for the new symbolic link value */
RtlInitAnsiString(&TargetString, Buffer);
InitializeObjectAttributes(&ObjectAttributes,
&LinkName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL,
NULL);
Status = RtlAnsiStringToUnicodeString(&ArcName, &TargetString, TRUE);
if (!NT_SUCCESS(Status)) return FALSE;
/* Create it */
Status = NtCreateSymbolicLinkObject(&LinkHandle,
SYMBOLIC_LINK_ALL_ACCESS,
&ObjectAttributes,
&ArcName);
/* Free all the strings and close the handle and return success */
RtlFreeUnicodeString(&ArcName);
RtlFreeUnicodeString(&LinkName);
ObCloseHandle(LinkHandle, KernelMode);
return TRUE;
}
BOOLEAN
NTAPI
IopVerifyDiskSignature(IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout,
IN PARC_DISK_SIGNATURE ArcDiskSignature,
OUT PULONG Signature)
{
/* First condition: having a valid partition table */
if (!ArcDiskSignature->ValidPartitionTable)
{
return FALSE;
}
/* If that partition table is the MBR */
if (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR)
{
/* Then check MBR signature */
if (DriveLayout->Mbr.Signature == ArcDiskSignature->Signature)
{
/* And return it */
if (Signature)
{
*Signature = DriveLayout->Mbr.Signature;
}
return TRUE;
}
}
/* If that partition table is the GPT */
else if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT)
{
/* Check we are using GPT and compare GUID */
if (ArcDiskSignature->IsGpt &&
(((PULONG)ArcDiskSignature->GptSignature)[0] == DriveLayout->Gpt.DiskId.Data1 &&
((PUSHORT)ArcDiskSignature->GptSignature)[2] == DriveLayout->Gpt.DiskId.Data2 &&
((PUSHORT)ArcDiskSignature->GptSignature)[3] == DriveLayout->Gpt.DiskId.Data3 &&
((PULONGLONG)ArcDiskSignature->GptSignature)[1] == ((PULONGLONG)DriveLayout->Gpt.DiskId.Data4)[0]))
{
/* There's no signature to give, so we just zero output */
if (Signature)
{
*Signature = 0;
}
return TRUE;
}
}
/* If we fall here, it means that something went wrong, so return that */
return FALSE;
}
/* EOF */