Reactos

[NTDLL_APITEST][KMTESTS] Add tests for NtQueryObject(ObjectNameInformation) (#7592)

CORE-13525

+215
+1
modules/rostests/apitests/ntdll/CMakeLists.txt
··· 41 41 NtQueryInformationThread.c 42 42 NtQueryInformationToken.c 43 43 NtQueryKey.c 44 + NtQueryObject.c 44 45 NtQueryOpenSubKeys.c 45 46 NtQuerySystemEnvironmentValue.c 46 47 NtQuerySystemInformation.c
+107
modules/rostests/apitests/ntdll/NtQueryObject.c
··· 1 + /* 2 + * PROJECT: ReactOS API Tests 3 + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 + * PURPOSE: Test for NtQueryObject 5 + * COPYRIGHT: Copyright 2024 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org> 6 + */ 7 + 8 + #include "precomp.h" 9 + 10 + /* Flags combination allowing all the read, write and delete share modes. 11 + * Currently similar to FILE_SHARE_VALID_FLAGS. */ 12 + #define FILE_SHARE_ALL \ 13 + (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) 14 + 15 + /* Adapted from kmtests/ntos_ob/ObQuery.c!ObjectNameInformationTests(). 16 + * Please sync both tests in case you add or remove new features. */ 17 + START_TEST(NtQueryObject) 18 + { 19 + ULONG g_OsVersion = 20 + SharedUserData->NtMajorVersion << 8 | SharedUserData->NtMinorVersion; 21 + 22 + NTSTATUS Status; 23 + HANDLE DeviceHandle; 24 + UNICODE_STRING DeviceName; 25 + OBJECT_ATTRIBUTES ObjectAttributes; 26 + IO_STATUS_BLOCK IoStatusBlock; 27 + 28 + ULONG BufferSize1, BufferSize2, BufferSize3; 29 + struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } ObjectNameBuffer; 30 + PUNICODE_STRING ObjectName = &ObjectNameBuffer.Name; 31 + 32 + /* Test the drive containing SystemRoot */ 33 + WCHAR NtDeviceName[] = L"\\DosDevices\\?:"; 34 + NtDeviceName[sizeof("\\DosDevices\\")-1] = SharedUserData->NtSystemRoot[0]; 35 + 36 + /* Open a handle to the device */ 37 + RtlInitUnicodeString(&DeviceName, NtDeviceName); 38 + InitializeObjectAttributes(&ObjectAttributes, 39 + &DeviceName, 40 + OBJ_CASE_INSENSITIVE, 41 + NULL, 42 + NULL); 43 + Status = NtOpenFile(&DeviceHandle, 44 + FILE_READ_ATTRIBUTES | SYNCHRONIZE, 45 + &ObjectAttributes, 46 + &IoStatusBlock, 47 + FILE_SHARE_ALL, 48 + FILE_SYNCHRONOUS_IO_NONALERT); 49 + ok_ntstatus(Status, STATUS_SUCCESS); 50 + if (!NT_SUCCESS(Status)) 51 + { 52 + skip("Device '%S': Opening failed\n", NtDeviceName); 53 + return; 54 + } 55 + 56 + /* Invoke ObjectNameInformation that retrieves the canonical device name */ 57 + Status = NtQueryObject(DeviceHandle, 58 + ObjectNameInformation, 59 + &ObjectNameBuffer, 60 + 0, 61 + &BufferSize1); 62 + ok_ntstatus(Status, STATUS_INFO_LENGTH_MISMATCH); 63 + 64 + Status = NtQueryObject(DeviceHandle, 65 + ObjectNameInformation, 66 + &ObjectNameBuffer, 67 + sizeof(OBJECT_NAME_INFORMATION), 68 + &BufferSize2); 69 + ok_ntstatus(Status, STATUS_BUFFER_OVERFLOW); 70 + 71 + Status = NtQueryObject(DeviceHandle, 72 + ObjectNameInformation, 73 + &ObjectNameBuffer, 74 + sizeof(ObjectNameBuffer), 75 + &BufferSize3); 76 + ok_ntstatus(Status, STATUS_SUCCESS); 77 + 78 + NtClose(DeviceHandle); 79 + 80 + /* Compare the returned buffer sizes */ 81 + 82 + /* The returned size behaviour changed (when NtQueryObject()'s 83 + * input Length is zero) between Windows <= 2003 and Vista+ */ 84 + if (g_OsVersion < _WIN32_WINNT_VISTA) 85 + ok_eq_ulong(BufferSize1, (ULONG)sizeof(OBJECT_NAME_INFORMATION)); 86 + else 87 + ok_eq_ulong(BufferSize1, (ULONG)sizeof(OBJECT_NAME_INFORMATION) + ObjectName->MaximumLength); 88 + 89 + ok_eq_ulong(BufferSize2, BufferSize3); 90 + ok_eq_ulong(BufferSize3, (ULONG)sizeof(OBJECT_NAME_INFORMATION) + ObjectName->MaximumLength); 91 + 92 + /* Test the name buffer */ 93 + ok(ObjectName->Length > 0, "ObjectName->Length == %hu, expected > 0\n", ObjectName->Length); 94 + ok_eq_uint(ObjectName->MaximumLength, ObjectName->Length + sizeof(WCHAR)); 95 + ok(ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] == UNICODE_NULL, 96 + "UNICODE_NULL not found at end of ObjectName->Buffer\n"); 97 + if (ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] != UNICODE_NULL) 98 + { 99 + skip("ObjectName->Buffer string length check skipped\n"); 100 + return; 101 + } 102 + /* Verify that ObjectName->Length doesn't count extra NUL-terminators */ 103 + { 104 + SIZE_T strLen = wcslen(ObjectName->Buffer) * sizeof(WCHAR); 105 + ok_eq_size(strLen, (SIZE_T)ObjectName->Length); 106 + } 107 + }
+2
modules/rostests/apitests/ntdll/testlist.c
··· 37 37 extern void func_NtQueryInformationThread(void); 38 38 extern void func_NtQueryInformationToken(void); 39 39 extern void func_NtQueryKey(void); 40 + extern void func_NtQueryObject(void); 40 41 extern void func_NtQueryOpenSubKeys(void); 41 42 extern void func_NtQuerySystemEnvironmentValue(void); 42 43 extern void func_NtQuerySystemInformation(void); ··· 140 141 { "NtQueryInformationThread", func_NtQueryInformationThread }, 141 142 { "NtQueryInformationToken", func_NtQueryInformationToken }, 142 143 { "NtQueryKey", func_NtQueryKey }, 144 + { "NtQueryObject", func_NtQueryObject }, 143 145 { "NtQueryOpenSubKeys", func_NtQueryOpenSubKeys }, 144 146 { "NtQuerySystemEnvironmentValue", func_NtQuerySystemEnvironmentValue }, 145 147 { "NtQuerySystemInformation", func_NtQuerySystemInformation },
+105
modules/rostests/kmtests/ntos_ob/ObQuery.c
··· 3 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 4 * PURPOSE: Kernel mode tests for object information querying 5 5 * COPYRIGHT: Copyright 2023 George Bișoc <george.bisoc@reactos.org> 6 + * Copyright 2024 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org> 6 7 */ 7 8 8 9 #include <kmt_test.h> ··· 65 66 ZwClose(WinStaDirHandle); 66 67 } 67 68 69 + /* Flags combination allowing all the read, write and delete share modes. 70 + * Currently similar to FILE_SHARE_VALID_FLAGS. */ 71 + #define FILE_SHARE_ALL \ 72 + (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) 73 + 74 + #define ok_ntstatus ok_eq_hex 75 + 76 + /* Adapted from apitests/ntdll/NtQueryObject.c!START_TEST(NtQueryObject). 77 + * Please sync both tests in case you add or remove new features. */ 78 + static 79 + VOID 80 + ObjectNameInformationTests(VOID) 81 + { 82 + ULONG g_OsVersion = 83 + SharedUserData->NtMajorVersion << 8 | SharedUserData->NtMinorVersion; 84 + 85 + NTSTATUS Status; 86 + HANDLE DeviceHandle; 87 + UNICODE_STRING DeviceName; 88 + OBJECT_ATTRIBUTES ObjectAttributes; 89 + IO_STATUS_BLOCK IoStatusBlock; 90 + 91 + ULONG BufferSize1, BufferSize2, BufferSize3; 92 + struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } ObjectNameBuffer; 93 + PUNICODE_STRING ObjectName = &ObjectNameBuffer.Name; 94 + 95 + /* Test the drive containing SystemRoot */ 96 + WCHAR NtDeviceName[] = L"\\DosDevices\\?:"; 97 + NtDeviceName[sizeof("\\DosDevices\\")-1] = SharedUserData->NtSystemRoot[0]; 98 + 99 + /* We must be in PASSIVE_LEVEL to do all of this stuff */ 100 + ok_irql(PASSIVE_LEVEL); 101 + 102 + /* Open a handle to the device */ 103 + RtlInitUnicodeString(&DeviceName, NtDeviceName); 104 + InitializeObjectAttributes(&ObjectAttributes, 105 + &DeviceName, 106 + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 107 + NULL, 108 + NULL); 109 + Status = ZwOpenFile(&DeviceHandle, 110 + FILE_READ_ATTRIBUTES | SYNCHRONIZE, 111 + &ObjectAttributes, 112 + &IoStatusBlock, 113 + FILE_SHARE_ALL, 114 + FILE_SYNCHRONOUS_IO_NONALERT); 115 + ok_ntstatus(Status, STATUS_SUCCESS); 116 + if (skip(NT_SUCCESS(Status), "Device '%wZ': Opening failed\n", &DeviceName)) 117 + return; 118 + 119 + /* Invoke ObjectNameInformation that retrieves the canonical device name */ 120 + Status = ZwQueryObject(DeviceHandle, 121 + ObjectNameInformation, 122 + &ObjectNameBuffer, 123 + 0, 124 + &BufferSize1); 125 + ok_ntstatus(Status, STATUS_INFO_LENGTH_MISMATCH); 126 + 127 + Status = ZwQueryObject(DeviceHandle, 128 + ObjectNameInformation, 129 + &ObjectNameBuffer, 130 + sizeof(OBJECT_NAME_INFORMATION), 131 + &BufferSize2); 132 + ok_ntstatus(Status, STATUS_BUFFER_OVERFLOW); 133 + 134 + Status = ZwQueryObject(DeviceHandle, 135 + ObjectNameInformation, 136 + &ObjectNameBuffer, 137 + sizeof(ObjectNameBuffer), 138 + &BufferSize3); 139 + ok_ntstatus(Status, STATUS_SUCCESS); 140 + 141 + ZwClose(DeviceHandle); 142 + 143 + /* Compare the returned buffer sizes */ 144 + 145 + /* The returned size behaviour changed (when ZwQueryObject()'s 146 + * input Length is zero) between Windows <= 2003 and Vista+ */ 147 + if (g_OsVersion < _WIN32_WINNT_VISTA) 148 + ok_eq_ulong(BufferSize1, sizeof(OBJECT_NAME_INFORMATION)); 149 + else 150 + ok_eq_ulong(BufferSize1, sizeof(OBJECT_NAME_INFORMATION) + ObjectName->MaximumLength); 151 + 152 + ok_eq_ulong(BufferSize2, BufferSize3); 153 + ok_eq_ulong(BufferSize3, sizeof(OBJECT_NAME_INFORMATION) + ObjectName->MaximumLength); 154 + 155 + /* Test the name buffer */ 156 + ok(ObjectName->Length > 0, "ObjectName->Length == %hu, expected > 0\n", ObjectName->Length); 157 + ok_eq_uint(ObjectName->MaximumLength, ObjectName->Length + sizeof(WCHAR)); 158 + ok(ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] == UNICODE_NULL, 159 + "UNICODE_NULL not found at end of ObjectName->Buffer\n"); 160 + if (skip(ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] == UNICODE_NULL, 161 + "ObjectName->Buffer string length check skipped\n")) 162 + { 163 + return; 164 + } 165 + /* Verify that ObjectName->Length doesn't count extra NUL-terminators */ 166 + { 167 + SIZE_T strLen = wcslen(ObjectName->Buffer) * sizeof(WCHAR); 168 + ok_eq_size(strLen, (SIZE_T)ObjectName->Length); 169 + } 170 + } 171 + 68 172 START_TEST(ObQuery) 69 173 { 70 174 ObjectBasicInformationTests(); 175 + ObjectNameInformationTests(); 71 176 }