https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a8669e023ad50b4afb714bf12002f2d5d22080ad
commit a8669e023ad50b4afb714bf12002f2d5d22080ad Author: Oleg Dubinskiy <oleg.dubinskij2...@yandex.ua> AuthorDate: Fri Jan 21 21:05:03 2022 +0200 Commit: Oleg Dubinskiy <oleg.dubinski...@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; }