https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a8669e023ad50b4afb714…
commit a8669e023ad50b4afb714bf12002f2d5d22080ad
Author: Oleg Dubinskiy <oleg.dubinskij2013(a)yandex.ua>
AuthorDate: Fri Jan 21 21:05:03 2022 +0200
Commit: Oleg Dubinskiy <oleg.dubinskij30(a)gmail.com>
CommitDate: Sun Feb 2 23:30:38 2025 +0100
[NTOS:IO] Rewrite OpenRegistryHandlesFromSymbolicLink
Also add a new IopOpenOrCreateSymbolicLinkSubKeys routine, which does some work for
it.
CORE-17361
---
ntoskrnl/io/iomgr/deviface.c | 347 +++++++++++++++++++++++++++----------------
1 file changed, 221 insertions(+), 126 deletions(-)
diff --git a/ntoskrnl/io/iomgr/deviface.c b/ntoskrnl/io/iomgr/deviface.c
index a5f20efb50a..5c3391f929b 100644
--- a/ntoskrnl/io/iomgr/deviface.c
+++ b/ntoskrnl/io/iomgr/deviface.c
@@ -287,187 +287,282 @@ IopSeparateSymbolicLink(
return Status;
}
+/**
+ * @brief
+ * Retrieves a handles to the device and instance registry keys
+ * for the previously opened registry key handle of the specified symbolic link.
+ **/
static
NTSTATUS
-OpenRegistryHandlesFromSymbolicLink(IN PUNICODE_STRING SymbolicLinkName,
- IN ACCESS_MASK DesiredAccess,
- IN OPTIONAL PHANDLE GuidKey,
- IN OPTIONAL PHANDLE DeviceKey,
- IN OPTIONAL PHANDLE InstanceKey)
+IopOpenOrCreateSymbolicLinkSubKeys(
+ _Out_opt_ PHANDLE DeviceHandle,
+ _Out_opt_ PULONG DeviceDisposition,
+ _Out_opt_ PHANDLE InstanceHandle,
+ _Out_opt_ PULONG InstanceDisposition,
+ _In_ HANDLE ClassHandle,
+ _In_ PCUNICODE_STRING SymbolicLinkName,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ BOOLEAN Create)
{
- OBJECT_ATTRIBUTES ObjectAttributes;
- UNICODE_STRING BaseKeyU;
- UNICODE_STRING GuidString, SubKeyName, ReferenceString;
- PWCHAR StartPosition, EndPosition;
- HANDLE ClassesKey;
- PHANDLE GuidKeyRealP, DeviceKeyRealP, InstanceKeyRealP;
- HANDLE GuidKeyReal, DeviceKeyReal, InstanceKeyReal;
+ UNICODE_STRING ReferenceString = {0};
+ UNICODE_STRING SymbolicLink = {0};
+ HANDLE DeviceKeyHandle, InstanceKeyHandle;
+ ULONG DeviceKeyDisposition, InstanceKeyDisposition;
+ BOOLEAN ReferenceStringPresent = FALSE; /* Assuming no ref string by default */
NTSTATUS Status;
+ USHORT i;
- SubKeyName.Buffer = NULL;
+ DeviceKeyHandle = InstanceKeyHandle = NULL;
- if (GuidKey != NULL)
- GuidKeyRealP = GuidKey;
- else
- GuidKeyRealP = &GuidKeyReal;
+ /* Duplicate the symbolic link (we'll modify it later) */
+ Status = RtlDuplicateUnicodeString(0, SymbolicLinkName, &SymbolicLink);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlDuplicateUnicodeString() failed, Status 0x%08lx\n",
Status);
+ goto Quit;
+ }
- if (DeviceKey != NULL)
- DeviceKeyRealP = DeviceKey;
- else
- DeviceKeyRealP = &DeviceKeyReal;
+ /* Separate it into its constituents */
+ Status = IopSeparateSymbolicLink(&SymbolicLink,
+ NULL,
+ NULL,
+ NULL,
+ &ReferenceString,
+ &ReferenceStringPresent,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to separate symbolic link %wZ, Status 0x%08lx\n",
&SymbolicLink, Status);
+ goto Quit;
+ }
- if (InstanceKey != NULL)
- InstanceKeyRealP = InstanceKey;
+ /* Did we got a ref string? */
+ if (ReferenceStringPresent)
+ {
+ /* Remove it from our symbolic link */
+ SymbolicLink.MaximumLength = SymbolicLink.Length -= ReferenceString.Length;
+
+ /* Replace the 1st backslash `\` character by '#' pound */
+ ReferenceString.Buffer[0] = L'#';
+ }
else
- InstanceKeyRealP = &InstanceKeyReal;
+ {
+ /* No ref string, initialize it with a single pound character '#' */
+ RtlInitUnicodeString(&ReferenceString, L"#");
+ }
- *GuidKeyRealP = NULL;
- *DeviceKeyRealP = NULL;
- *InstanceKeyRealP = NULL;
+ /* Replace all '\' by '#' in symbolic link */
+ for (i = 0; i < SymbolicLink.Length / sizeof(WCHAR); i++)
+ {
+ if (SymbolicLink.Buffer[i] == L'\\')
+ SymbolicLink.Buffer[i] = L'#';
+ }
- RtlInitUnicodeString(&BaseKeyU, BaseKeyString);
+ /* Fix prefix: '#??#' -> '##?#' */
+ SymbolicLink.Buffer[1] = L'#';
+
+ DPRINT("Munged symbolic link is %wZ\n", &SymbolicLink);
+
+ /* Try to open or create device interface keys */
+ if (Create)
+ {
+ Status = IopCreateRegistryKeyEx(&DeviceKeyHandle,
+ ClassHandle,
+ &SymbolicLink,
+ DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
+ REG_OPTION_NON_VOLATILE,
+ &DeviceKeyDisposition);
+ }
+ else
+ {
+ Status = IopOpenRegistryKeyEx(&DeviceKeyHandle,
+ ClassHandle,
+ &SymbolicLink,
+ DesiredAccess | KEY_ENUMERATE_SUB_KEYS);
+ }
- /* Open the DeviceClasses key */
- InitializeObjectAttributes(&ObjectAttributes,
- &BaseKeyU,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- NULL,
- NULL);
- Status = ZwOpenKey(&ClassesKey,
- DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
- &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
- DPRINT1("Failed to open %wZ\n", &BaseKeyU);
- goto cleanup;
+ DPRINT1("Failed to create or open %wZ, Status 0x%08lx\n",
&SymbolicLink, Status);
+ goto Quit;
}
- StartPosition = wcschr(SymbolicLinkName->Buffer, L'{');
- EndPosition = wcschr(SymbolicLinkName->Buffer, L'}');
- if (!StartPosition || !EndPosition || StartPosition > EndPosition)
+ DPRINT("Munged reference string is %wZ\n", &ReferenceString);
+
+ /* Try to open or create instance subkeys */
+ if (Create)
{
- DPRINT1("Bad symbolic link: %wZ\n", SymbolicLinkName);
- return STATUS_INVALID_PARAMETER_1;
+ Status = IopCreateRegistryKeyEx(&InstanceKeyHandle,
+ DeviceKeyHandle,
+ &ReferenceString,
+ DesiredAccess,
+ REG_OPTION_NON_VOLATILE,
+ &InstanceKeyDisposition);
+ }
+ else
+ {
+ Status = IopOpenRegistryKeyEx(&InstanceKeyHandle,
+ DeviceKeyHandle,
+ &ReferenceString,
+ DesiredAccess);
}
- GuidString.Buffer = StartPosition;
- GuidString.MaximumLength = GuidString.Length = (USHORT)((ULONG_PTR)(EndPosition + 1)
- (ULONG_PTR)StartPosition);
- InitializeObjectAttributes(&ObjectAttributes,
- &GuidString,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- ClassesKey,
- NULL);
- Status = ZwCreateKey(GuidKeyRealP,
- DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
- &ObjectAttributes,
- 0,
- NULL,
- REG_OPTION_NON_VOLATILE,
- NULL);
- ZwClose(ClassesKey);
if (!NT_SUCCESS(Status))
{
- DPRINT1("Failed to open %wZ%wZ (%x)\n", &BaseKeyU, &GuidString,
Status);
- goto cleanup;
+ DPRINT1("Failed to create or open %wZ, Status 0x%08lx\n",
&ReferenceString, Status);
+ goto Quit;
}
- SubKeyName.MaximumLength = SymbolicLinkName->Length + sizeof(WCHAR);
- SubKeyName.Length = 0;
- SubKeyName.Buffer = ExAllocatePool(PagedPool, SubKeyName.MaximumLength);
- if (!SubKeyName.Buffer)
+ Status = STATUS_SUCCESS;
+
+Quit:
+ if (NT_SUCCESS(Status))
{
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto cleanup;
+ if (DeviceHandle)
+ *DeviceHandle = DeviceKeyHandle;
+ else
+ ZwClose(DeviceKeyHandle);
+
+ if (DeviceDisposition)
+ *DeviceDisposition = DeviceKeyDisposition;
+
+ if (InstanceHandle)
+ *InstanceHandle = InstanceKeyHandle;
+ else
+ ZwClose(InstanceKeyHandle);
+
+ if (InstanceDisposition)
+ *InstanceDisposition = InstanceKeyDisposition;
}
+ else
+ {
+ if (InstanceKeyHandle)
+ ZwClose(InstanceKeyHandle);
- RtlAppendUnicodeStringToString(&SubKeyName,
- SymbolicLinkName);
+ if (Create)
+ ZwDeleteKey(DeviceKeyHandle);
- SubKeyName.Buffer[SubKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;
+ if (DeviceKeyHandle)
+ ZwClose(DeviceKeyHandle);
+ }
- SubKeyName.Buffer[0] = L'#';
- SubKeyName.Buffer[1] = L'#';
- SubKeyName.Buffer[2] = L'?';
- SubKeyName.Buffer[3] = L'#';
+ if (SymbolicLink.Buffer)
+ RtlFreeUnicodeString(&SymbolicLink);
- ReferenceString.Buffer = wcsrchr(SubKeyName.Buffer, '\\');
- if (ReferenceString.Buffer != NULL)
- {
- ReferenceString.Buffer[0] = L'#';
+ return Status;
+}
- SubKeyName.Length = (USHORT)((ULONG_PTR)(ReferenceString.Buffer) -
(ULONG_PTR)SubKeyName.Buffer);
- ReferenceString.Length = SymbolicLinkName->Length - SubKeyName.Length;
+/**
+ * @brief
+ * Retrieves a handles to the GUID, device and instance registry keys
+ * for the specified symbolic link.
+ **/
+static
+NTSTATUS
+OpenRegistryHandlesFromSymbolicLink(
+ _In_ PCUNICODE_STRING SymbolicLinkName,
+ _In_ ACCESS_MASK DesiredAccess,
+ _Out_opt_ PHANDLE GuidKey,
+ _Out_opt_ PHANDLE DeviceKey,
+ _Out_opt_ PHANDLE InstanceKey)
+{
+ UNICODE_STRING BaseKeyU;
+ UNICODE_STRING GuidString;
+ HANDLE ClassesKey;
+ HANDLE GuidKeyReal, DeviceKeyReal, InstanceKeyReal;
+ NTSTATUS Status;
+
+ ClassesKey = GuidKeyReal = DeviceKeyReal = InstanceKeyReal = NULL;
+
+ RtlInitUnicodeString(&BaseKeyU, BaseKeyString);
+
+ /* Separate symbolic link onto the parts */
+ Status = IopSeparateSymbolicLink(SymbolicLinkName,
+ NULL,
+ NULL,
+ &GuidString,
+ NULL,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to parse symbolic link %wZ, Status 0x%08lx\n",
+ SymbolicLinkName, Status);
+ goto Quit;
}
- else
+
+ /* Open the DeviceClasses key */
+ Status = IopOpenRegistryKeyEx(&ClassesKey,
+ NULL,
+ &BaseKeyU,
+ DesiredAccess | KEY_ENUMERATE_SUB_KEYS);
+ if (!NT_SUCCESS(Status))
{
- RtlInitUnicodeString(&ReferenceString, L"#");
+ DPRINT1("Failed to open %wZ, Status 0x%08lx\n", &BaseKeyU,
Status);
+ goto Quit;
}
- InitializeObjectAttributes(&ObjectAttributes,
- &SubKeyName,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- *GuidKeyRealP,
- NULL);
- Status = ZwCreateKey(DeviceKeyRealP,
- DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
- &ObjectAttributes,
- 0,
- NULL,
- REG_OPTION_NON_VOLATILE,
- NULL);
+ /* Open the GUID subkey */
+ Status = IopOpenRegistryKeyEx(&GuidKeyReal,
+ ClassesKey,
+ &GuidString,
+ DesiredAccess | KEY_ENUMERATE_SUB_KEYS);
if (!NT_SUCCESS(Status))
{
- DPRINT1("Failed to open %wZ%wZ\\%wZ Status %x\n", &BaseKeyU,
&GuidString, &SubKeyName, Status);
- goto cleanup;
+ DPRINT1("Failed to open %wZ%wZ, Status 0x%08lx\n", &BaseKeyU,
&GuidString, Status);
+ goto Quit;
}
- InitializeObjectAttributes(&ObjectAttributes,
- &ReferenceString,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- *DeviceKeyRealP,
- NULL);
- Status = ZwCreateKey(InstanceKeyRealP,
- DesiredAccess,
- &ObjectAttributes,
- 0,
- NULL,
- REG_OPTION_NON_VOLATILE,
- NULL);
+ /* Open the device and instance subkeys */
+ Status = IopOpenOrCreateSymbolicLinkSubKeys(&DeviceKeyReal,
+ NULL,
+ &InstanceKeyReal,
+ NULL,
+ GuidKeyReal,
+ SymbolicLinkName,
+ DesiredAccess,
+ FALSE);
if (!NT_SUCCESS(Status))
{
- DPRINT1("Failed to open %wZ%wZ\\%wZ%\\%wZ (%x)\n", &BaseKeyU,
&GuidString, &SubKeyName, &ReferenceString, Status);
- goto cleanup;
+ DPRINT1("Failed to open %wZ%wZ, Status 0x%08lx\n", &BaseKeyU,
&GuidString, Status);
+ goto Quit;
}
Status = STATUS_SUCCESS;
-cleanup:
- if (SubKeyName.Buffer != NULL)
- ExFreePool(SubKeyName.Buffer);
-
+Quit:
if (NT_SUCCESS(Status))
{
- if (!GuidKey)
- ZwClose(*GuidKeyRealP);
+ if (GuidKey)
+ *GuidKey = GuidKeyReal;
+ else
+ ZwClose(GuidKeyReal);
- if (!DeviceKey)
- ZwClose(*DeviceKeyRealP);
+ if (DeviceKey)
+ *DeviceKey = DeviceKeyReal;
+ else
+ ZwClose(DeviceKeyReal);
- if (!InstanceKey)
- ZwClose(*InstanceKeyRealP);
+ if (InstanceKey)
+ *InstanceKey = InstanceKeyReal;
+ else
+ ZwClose(InstanceKeyReal);
}
else
{
- if (*GuidKeyRealP != NULL)
- ZwClose(*GuidKeyRealP);
+ if (GuidKeyReal)
+ ZwClose(GuidKeyReal);
- if (*DeviceKeyRealP != NULL)
- ZwClose(*DeviceKeyRealP);
+ if (DeviceKeyReal)
+ ZwClose(DeviceKeyReal);
- if (*InstanceKeyRealP != NULL)
- ZwClose(*InstanceKeyRealP);
+ if (InstanceKeyReal)
+ ZwClose(InstanceKeyReal);
}
+ if (ClassesKey)
+ ZwClose(ClassesKey);
+
return Status;
}