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();
 }

Reply via email to