https://git.reactos.org/?p=reactos.git;a=commitdiff;h=02a394ea578376bb069e2fda93ae4c242d53b245
commit 02a394ea578376bb069e2fda93ae4c242d53b245 Author: Hermès Bélusca-Maïto <hermes.belusca-ma...@reactos.org> AuthorDate: Mon Dec 30 21:28:01 2024 +0100 Commit: Hermès Bélusca-Maïto <hermes.belusca-ma...@reactos.org> CommitDate: Mon Jan 6 21:30:17 2025 +0100 [NTDLL_APITEST][KMTESTS] Add tests for NtQueryObject(ObjectNameInformation) (#7592) CORE-13525 --- modules/rostests/apitests/ntdll/CMakeLists.txt | 1 + modules/rostests/apitests/ntdll/NtQueryObject.c | 107 ++++++++++++++++++++++++ modules/rostests/apitests/ntdll/testlist.c | 2 + modules/rostests/kmtests/ntos_ob/ObQuery.c | 105 +++++++++++++++++++++++ 4 files changed, 215 insertions(+) diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt b/modules/rostests/apitests/ntdll/CMakeLists.txt index 6f956813680..29c1cf96ed9 100644 --- a/modules/rostests/apitests/ntdll/CMakeLists.txt +++ b/modules/rostests/apitests/ntdll/CMakeLists.txt @@ -41,6 +41,7 @@ list(APPEND SOURCE NtQueryInformationThread.c NtQueryInformationToken.c NtQueryKey.c + NtQueryObject.c NtQueryOpenSubKeys.c NtQuerySystemEnvironmentValue.c NtQuerySystemInformation.c diff --git a/modules/rostests/apitests/ntdll/NtQueryObject.c b/modules/rostests/apitests/ntdll/NtQueryObject.c new file mode 100644 index 00000000000..8ee7157cfcd --- /dev/null +++ b/modules/rostests/apitests/ntdll/NtQueryObject.c @@ -0,0 +1,107 @@ +/* + * PROJECT: ReactOS API Tests + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Test for NtQueryObject + * COPYRIGHT: Copyright 2024 Hermès Bélusca-Maïto <hermes.belusca-ma...@reactos.org> + */ + +#include "precomp.h" + +/* Flags combination allowing all the read, write and delete share modes. + * Currently similar to FILE_SHARE_VALID_FLAGS. */ +#define FILE_SHARE_ALL \ + (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) + +/* Adapted from kmtests/ntos_ob/ObQuery.c!ObjectNameInformationTests(). + * Please sync both tests in case you add or remove new features. */ +START_TEST(NtQueryObject) +{ + ULONG g_OsVersion = + SharedUserData->NtMajorVersion << 8 | SharedUserData->NtMinorVersion; + + NTSTATUS Status; + HANDLE DeviceHandle; + UNICODE_STRING DeviceName; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + + ULONG BufferSize1, BufferSize2, BufferSize3; + struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } ObjectNameBuffer; + PUNICODE_STRING ObjectName = &ObjectNameBuffer.Name; + + /* Test the drive containing SystemRoot */ + WCHAR NtDeviceName[] = L"\\DosDevices\\?:"; + NtDeviceName[sizeof("\\DosDevices\\")-1] = SharedUserData->NtSystemRoot[0]; + + /* Open a handle to the device */ + RtlInitUnicodeString(&DeviceName, NtDeviceName); + InitializeObjectAttributes(&ObjectAttributes, + &DeviceName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtOpenFile(&DeviceHandle, + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_ALL, + FILE_SYNCHRONOUS_IO_NONALERT); + ok_ntstatus(Status, STATUS_SUCCESS); + if (!NT_SUCCESS(Status)) + { + skip("Device '%S': Opening failed\n", NtDeviceName); + return; + } + + /* Invoke ObjectNameInformation that retrieves the canonical device name */ + Status = NtQueryObject(DeviceHandle, + ObjectNameInformation, + &ObjectNameBuffer, + 0, + &BufferSize1); + ok_ntstatus(Status, STATUS_INFO_LENGTH_MISMATCH); + + Status = NtQueryObject(DeviceHandle, + ObjectNameInformation, + &ObjectNameBuffer, + sizeof(OBJECT_NAME_INFORMATION), + &BufferSize2); + ok_ntstatus(Status, STATUS_BUFFER_OVERFLOW); + + Status = NtQueryObject(DeviceHandle, + ObjectNameInformation, + &ObjectNameBuffer, + sizeof(ObjectNameBuffer), + &BufferSize3); + ok_ntstatus(Status, STATUS_SUCCESS); + + NtClose(DeviceHandle); + + /* Compare the returned buffer sizes */ + + /* The returned size behaviour changed (when NtQueryObject()'s + * input Length is zero) between Windows <= 2003 and Vista+ */ + if (g_OsVersion < _WIN32_WINNT_VISTA) + ok_eq_ulong(BufferSize1, (ULONG)sizeof(OBJECT_NAME_INFORMATION)); + else + ok_eq_ulong(BufferSize1, (ULONG)sizeof(OBJECT_NAME_INFORMATION) + ObjectName->MaximumLength); + + ok_eq_ulong(BufferSize2, BufferSize3); + ok_eq_ulong(BufferSize3, (ULONG)sizeof(OBJECT_NAME_INFORMATION) + ObjectName->MaximumLength); + + /* Test the name buffer */ + ok(ObjectName->Length > 0, "ObjectName->Length == %hu, expected > 0\n", ObjectName->Length); + ok_eq_uint(ObjectName->MaximumLength, ObjectName->Length + sizeof(WCHAR)); + ok(ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] == UNICODE_NULL, + "UNICODE_NULL not found at end of ObjectName->Buffer\n"); + if (ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] != UNICODE_NULL) + { + skip("ObjectName->Buffer string length check skipped\n"); + return; + } + /* Verify that ObjectName->Length doesn't count extra NUL-terminators */ + { + SIZE_T strLen = wcslen(ObjectName->Buffer) * sizeof(WCHAR); + ok_eq_size(strLen, (SIZE_T)ObjectName->Length); + } +} diff --git a/modules/rostests/apitests/ntdll/testlist.c b/modules/rostests/apitests/ntdll/testlist.c index 10cc0d987da..86f653d5adf 100644 --- a/modules/rostests/apitests/ntdll/testlist.c +++ b/modules/rostests/apitests/ntdll/testlist.c @@ -37,6 +37,7 @@ extern void func_NtQueryInformationProcess(void); extern void func_NtQueryInformationThread(void); extern void func_NtQueryInformationToken(void); extern void func_NtQueryKey(void); +extern void func_NtQueryObject(void); extern void func_NtQueryOpenSubKeys(void); extern void func_NtQuerySystemEnvironmentValue(void); extern void func_NtQuerySystemInformation(void); @@ -140,6 +141,7 @@ const struct test winetest_testlist[] = { "NtQueryInformationThread", func_NtQueryInformationThread }, { "NtQueryInformationToken", func_NtQueryInformationToken }, { "NtQueryKey", func_NtQueryKey }, + { "NtQueryObject", func_NtQueryObject }, { "NtQueryOpenSubKeys", func_NtQueryOpenSubKeys }, { "NtQuerySystemEnvironmentValue", func_NtQuerySystemEnvironmentValue }, { "NtQuerySystemInformation", func_NtQuerySystemInformation }, diff --git a/modules/rostests/kmtests/ntos_ob/ObQuery.c b/modules/rostests/kmtests/ntos_ob/ObQuery.c index b58762067f7..be6000f1643 100644 --- a/modules/rostests/kmtests/ntos_ob/ObQuery.c +++ b/modules/rostests/kmtests/ntos_ob/ObQuery.c @@ -3,6 +3,7 @@ * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Kernel mode tests for object information querying * COPYRIGHT: Copyright 2023 George Bișoc <george.bi...@reactos.org> + * Copyright 2024 Hermès Bélusca-Maïto <hermes.belusca-ma...@reactos.org> */ #include <kmt_test.h> @@ -65,7 +66,111 @@ ObjectBasicInformationTests(VOID) ZwClose(WinStaDirHandle); } +/* Flags combination allowing all the read, write and delete share modes. + * Currently similar to FILE_SHARE_VALID_FLAGS. */ +#define FILE_SHARE_ALL \ + (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) + +#define ok_ntstatus ok_eq_hex + +/* Adapted from apitests/ntdll/NtQueryObject.c!START_TEST(NtQueryObject). + * Please sync both tests in case you add or remove new features. */ +static +VOID +ObjectNameInformationTests(VOID) +{ + ULONG g_OsVersion = + SharedUserData->NtMajorVersion << 8 | SharedUserData->NtMinorVersion; + + NTSTATUS Status; + HANDLE DeviceHandle; + UNICODE_STRING DeviceName; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + + ULONG BufferSize1, BufferSize2, BufferSize3; + struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } ObjectNameBuffer; + PUNICODE_STRING ObjectName = &ObjectNameBuffer.Name; + + /* Test the drive containing SystemRoot */ + WCHAR NtDeviceName[] = L"\\DosDevices\\?:"; + NtDeviceName[sizeof("\\DosDevices\\")-1] = SharedUserData->NtSystemRoot[0]; + + /* We must be in PASSIVE_LEVEL to do all of this stuff */ + ok_irql(PASSIVE_LEVEL); + + /* Open a handle to the device */ + RtlInitUnicodeString(&DeviceName, NtDeviceName); + InitializeObjectAttributes(&ObjectAttributes, + &DeviceName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL); + Status = ZwOpenFile(&DeviceHandle, + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_ALL, + FILE_SYNCHRONOUS_IO_NONALERT); + ok_ntstatus(Status, STATUS_SUCCESS); + if (skip(NT_SUCCESS(Status), "Device '%wZ': Opening failed\n", &DeviceName)) + return; + + /* Invoke ObjectNameInformation that retrieves the canonical device name */ + Status = ZwQueryObject(DeviceHandle, + ObjectNameInformation, + &ObjectNameBuffer, + 0, + &BufferSize1); + ok_ntstatus(Status, STATUS_INFO_LENGTH_MISMATCH); + + Status = ZwQueryObject(DeviceHandle, + ObjectNameInformation, + &ObjectNameBuffer, + sizeof(OBJECT_NAME_INFORMATION), + &BufferSize2); + ok_ntstatus(Status, STATUS_BUFFER_OVERFLOW); + + Status = ZwQueryObject(DeviceHandle, + ObjectNameInformation, + &ObjectNameBuffer, + sizeof(ObjectNameBuffer), + &BufferSize3); + ok_ntstatus(Status, STATUS_SUCCESS); + + ZwClose(DeviceHandle); + + /* Compare the returned buffer sizes */ + + /* The returned size behaviour changed (when ZwQueryObject()'s + * input Length is zero) between Windows <= 2003 and Vista+ */ + if (g_OsVersion < _WIN32_WINNT_VISTA) + ok_eq_ulong(BufferSize1, sizeof(OBJECT_NAME_INFORMATION)); + else + ok_eq_ulong(BufferSize1, sizeof(OBJECT_NAME_INFORMATION) + ObjectName->MaximumLength); + + ok_eq_ulong(BufferSize2, BufferSize3); + ok_eq_ulong(BufferSize3, sizeof(OBJECT_NAME_INFORMATION) + ObjectName->MaximumLength); + + /* Test the name buffer */ + ok(ObjectName->Length > 0, "ObjectName->Length == %hu, expected > 0\n", ObjectName->Length); + ok_eq_uint(ObjectName->MaximumLength, ObjectName->Length + sizeof(WCHAR)); + ok(ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] == UNICODE_NULL, + "UNICODE_NULL not found at end of ObjectName->Buffer\n"); + if (skip(ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] == UNICODE_NULL, + "ObjectName->Buffer string length check skipped\n")) + { + return; + } + /* Verify that ObjectName->Length doesn't count extra NUL-terminators */ + { + SIZE_T strLen = wcslen(ObjectName->Buffer) * sizeof(WCHAR); + ok_eq_size(strLen, (SIZE_T)ObjectName->Length); + } +} + START_TEST(ObQuery) { ObjectBasicInformationTests(); + ObjectNameInformationTests(); }