https://git.reactos.org/?p=reactos.git;a=commitdiff;h=02a394ea578376bb069e2…
commit 02a394ea578376bb069e2fda93ae4c242d53b245
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Mon Dec 30 21:28:01 2024 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)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-maito(a)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.bisoc(a)reactos.org>
+ * Copyright 2024 Hermès Bélusca-Maïto
<hermes.belusca-maito(a)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();
}