1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Object Referencing test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 #define NDEBUG
10 #include <debug.h>
11 
12 #define CheckObject(Handle, Pointers, Handles) do                   \
13 {                                                                   \
14     PUBLIC_OBJECT_BASIC_INFORMATION ObjectInfo;                     \
15     Status = ZwQueryObject(Handle, ObjectBasicInformation,          \
16                             &ObjectInfo, sizeof ObjectInfo, NULL);  \
17     ok_eq_hex(Status, STATUS_SUCCESS);                              \
18     ok_eq_ulong(ObjectInfo.PointerCount, Pointers);                 \
19     ok_eq_ulong(ObjectInfo.HandleCount, Handles);                   \
20 } while (0)
21 
22 static POBJECT_TYPE ObDirectoryObjectType;
23 
24 static
25 VOID
26 TestReference(
27     IN HANDLE Handle,
28     IN PUNICODE_STRING Name OPTIONAL,
29     IN PUNICODE_STRING NameUpper OPTIONAL,
30     IN BOOLEAN CaseSensitive,
31     IN ULONG AdditionalReferences,
32     IN BOOLEAN Permanent)
33 {
34     NTSTATUS Status;
35     LONG_PTR Ret;
36     PVOID Object = NULL;
37     PVOID Object2 = NULL;
38     PVOID Object3 = NULL;
39     PVOID Object4 = NULL;
40 
41     CheckObject(Handle, 2LU + AdditionalReferences, 1LU);
42 
43     Status = ObReferenceObjectByHandle(Handle, DIRECTORY_ALL_ACCESS, NULL, KernelMode, &Object, NULL);
44     ok_eq_hex(Status, STATUS_SUCCESS);
45     ok(Object != NULL, "ObReferenceObjectByHandle returned NULL object\n");
46     CheckObject(Handle, 3LU + AdditionalReferences, 1LU);
47 
48     Status = ObReferenceObjectByHandle(Handle, DIRECTORY_ALL_ACCESS, NULL, KernelMode, &Object2, NULL);
49     ok_eq_hex(Status, STATUS_SUCCESS);
50     ok(Object != NULL, "ObReferenceObjectByHandle returned NULL object\n");
51     ok_eq_pointer(Object, Object2);
52     CheckObject(Handle, 4LU + AdditionalReferences, 1LU);
53 
54     if (!skip(Object != NULL, "No object to reference!\n"))
55     {
56         Ret = ObReferenceObject(Object);
57         ok_eq_longptr(Ret, (LONG_PTR)4 + AdditionalReferences);
58         CheckObject(Handle, 5LU + AdditionalReferences, 1LU);
59 
60         Ret = ObReferenceObject(Object);
61         ok_eq_longptr(Ret, (LONG_PTR)5 + AdditionalReferences);
62         CheckObject(Handle, 6LU + AdditionalReferences, 1LU);
63 
64         Status = ObReferenceObjectByPointer(Object, DIRECTORY_ALL_ACCESS, NULL, KernelMode);
65         ok_eq_hex(Status, STATUS_SUCCESS);
66         CheckObject(Handle, 7LU + AdditionalReferences, 1LU);
67 
68         Status = ObReferenceObjectByPointer(Object, DIRECTORY_ALL_ACCESS, NULL, KernelMode);
69         ok_eq_hex(Status, STATUS_SUCCESS);
70         CheckObject(Handle, 8LU + AdditionalReferences, 1LU);
71 
72         Ret = ObDereferenceObject(Object);
73         ok_eq_longptr(Ret, (LONG_PTR)6 + AdditionalReferences);
74         CheckObject(Handle, 7LU + AdditionalReferences, 1LU);
75 
76         Ret = ObDereferenceObject(Object);
77         ok_eq_longptr(Ret, (LONG_PTR)5 + AdditionalReferences);
78         CheckObject(Handle, 6LU + AdditionalReferences, 1LU);
79 
80         Ret = ObDereferenceObject(Object);
81         ok_eq_longptr(Ret, (LONG_PTR)4 + AdditionalReferences);
82         CheckObject(Handle, 5LU + AdditionalReferences, 1LU);
83 
84         Ret = ObDereferenceObject(Object);
85         ok_eq_longptr(Ret, (LONG_PTR)3 + AdditionalReferences);
86         CheckObject(Handle, 4LU + AdditionalReferences, 1LU);
87     }
88 
89     if (Name && !skip(ObDirectoryObjectType != NULL, "No directory object type\n"))
90     {
91         Status = ObReferenceObjectByName(Name, 0, NULL, DIRECTORY_ALL_ACCESS, ObDirectoryObjectType, KernelMode, NULL, &Object3);
92         ok_eq_hex(Status, STATUS_SUCCESS);
93         CheckObject(Handle, 5LU + AdditionalReferences, 1LU);
94     }
95 
96     if (NameUpper && !skip(ObDirectoryObjectType != NULL, "No directory object type\n"))
97     {
98         Status = ObReferenceObjectByName(NameUpper, 0, NULL, DIRECTORY_ALL_ACCESS, ObDirectoryObjectType, KernelMode, NULL, &Object4);
99         ok_eq_hex(Status, CaseSensitive ? STATUS_OBJECT_NAME_NOT_FOUND : STATUS_SUCCESS);
100         CheckObject(Handle, 5LU + AdditionalReferences + !CaseSensitive, 1LU);
101     }
102 
103     if (NameUpper && !skip(Object4 != NULL, "No object to dereference\n"))
104     {
105         Ret = ObDereferenceObject(Object4);
106         ok_eq_longptr(Ret, (LONG_PTR)4 + AdditionalReferences);
107         CheckObject(Handle, 5LU + AdditionalReferences, 1LU);
108     }
109     if (Name && !skip(Object3 != NULL, "No object to dereference\n"))
110     {
111         Ret = ObDereferenceObject(Object3);
112         ok_eq_longptr(Ret, (LONG_PTR)3 + AdditionalReferences);
113         CheckObject(Handle, 4LU + AdditionalReferences, 1LU);
114     }
115     if (!skip(Object2 != NULL, "No object to dereference\n"))
116     {
117         Ret = ObDereferenceObject(Object2);
118         ok_eq_longptr(Ret, (LONG_PTR)2 + AdditionalReferences);
119         CheckObject(Handle, 3LU + AdditionalReferences, 1LU);
120     }
121     if (!skip(Object != NULL, "No object to dereference\n"))
122     {
123         Ret = ObDereferenceObject(Object);
124         ok_eq_longptr(Ret, (LONG_PTR)1 + AdditionalReferences);
125         CheckObject(Handle, 2LU + AdditionalReferences, 1LU);
126     }
127 
128     CheckObject(Handle, 2LU + AdditionalReferences, 1LU);
129 
130     if (Permanent)
131     {
132         Status = ZwMakeTemporaryObject(Handle);
133         ok_eq_hex(Status, STATUS_SUCCESS);
134         CheckObject(Handle, 2LU + AdditionalReferences, 1LU);
135 
136         Status = ZwMakeTemporaryObject(Handle);
137         ok_eq_hex(Status, STATUS_SUCCESS);
138         CheckObject(Handle, 2LU + AdditionalReferences, 1LU);
139     }
140 }
141 
142 START_TEST(ObReference)
143 {
144     NTSTATUS Status;
145     HANDLE DirectoryHandle = NULL;
146     OBJECT_ATTRIBUTES ObjectAttributes;
147     UNICODE_STRING Name, *pName;
148     UNICODE_STRING NameUpper, *pNameUpper;
149     ULONG i;
150     struct
151     {
152         PWSTR Name;
153         ULONG Flags;
154         ULONG AdditionalReferences;
155     } Tests[] =
156     {
157         { NULL,                 0,                                                          0 },
158         { NULL,                 OBJ_CASE_INSENSITIVE,                                       0 },
159         { NULL,                 OBJ_KERNEL_HANDLE,                                          0 },
160         { NULL,                 OBJ_PERMANENT,                                              0 },
161         { NULL,                 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,                       0 },
162         { NULL,                 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,                   0 },
163         { NULL,                 OBJ_KERNEL_HANDLE | OBJ_PERMANENT,                          0 },
164         { NULL,                 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_PERMANENT,   0 },
165         { L"\\YayDirectory0",   0,                                                          1 },
166         { L"\\YayDirectory1",   OBJ_CASE_INSENSITIVE,                                       1 },
167         { L"\\YayDirectory2",   OBJ_KERNEL_HANDLE,                                          1 },
168         { L"\\YayDirectory3",   OBJ_PERMANENT,                                              1 },
169         { L"\\YayDirectory4",   OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,                       1 },
170         { L"\\YayDirectory5",   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,                   1 },
171         { L"\\YayDirectory6",   OBJ_KERNEL_HANDLE | OBJ_PERMANENT,                          1 },
172         { L"\\YayDirectory7",   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_PERMANENT,   1 },
173     };
174     HANDLE ObjectTypeHandle;
175 
176     /* ObReferenceObjectByName needs the object type... so get it... */
177     RtlInitUnicodeString(&Name, L"\\ObjectTypes\\Directory");
178     InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_KERNEL_HANDLE, NULL, NULL);
179     Status = ObOpenObjectByName(&ObjectAttributes, NULL, KernelMode, NULL, 0, NULL, &ObjectTypeHandle);
180     ok_eq_hex(Status, STATUS_SUCCESS);
181     ok(ObjectTypeHandle != NULL, "ObjectTypeHandle = NULL\n");
182     if (!skip(Status == STATUS_SUCCESS && ObjectTypeHandle, "No handle\n"))
183     {
184         Status = ObReferenceObjectByHandle(ObjectTypeHandle, 0, NULL, KernelMode, (PVOID)&ObDirectoryObjectType, NULL);
185         ok_eq_hex(Status, STATUS_SUCCESS);
186         ok(ObDirectoryObjectType != NULL, "ObDirectoryObjectType = NULL\n");
187         Status = ZwClose(ObjectTypeHandle);
188         ok_eq_hex(Status, STATUS_SUCCESS);
189     }
190 
191     for (i = 0; i < sizeof Tests / sizeof Tests[0]; ++i)
192     {
193         DPRINT("Run %d\n", i);
194         if (Tests[i].Name)
195         {
196             RtlInitUnicodeString(&Name, Tests[i].Name);
197             pName = &Name;
198             Status = RtlUpcaseUnicodeString(&NameUpper, &Name, TRUE);
199             ok_eq_hex(Status, STATUS_SUCCESS);
200             if (skip(Status == STATUS_SUCCESS, "No upper case name\n"))
201                 pNameUpper = NULL;
202             else
203                 pNameUpper = &NameUpper;
204         }
205         else
206         {
207             pName = NULL;
208             pNameUpper = NULL;
209         }
210         InitializeObjectAttributes(&ObjectAttributes, pName, Tests[i].Flags, NULL, NULL);
211         Status = ZwCreateDirectoryObject(&DirectoryHandle, DIRECTORY_ALL_ACCESS, &ObjectAttributes);
212         ok_eq_hex(Status, STATUS_SUCCESS);
213         ok(DirectoryHandle != NULL, "DirectoryHandle = NULL\n");
214 
215         if (!skip(Status == STATUS_SUCCESS && DirectoryHandle, "Cannot proceed without an object\n"))
216         {
217             TestReference(DirectoryHandle, pName, pNameUpper, FALSE, Tests[i].AdditionalReferences, (Tests[i].Flags & OBJ_PERMANENT) != 0);
218             /* try again for good measure */
219             TestReference(DirectoryHandle, pName, pNameUpper, FALSE, Tests[i].AdditionalReferences, FALSE);
220 
221             Status = ZwClose(DirectoryHandle);
222             ok_eq_hex(Status, STATUS_SUCCESS);
223             DirectoryHandle = NULL;
224         }
225 
226         if (pNameUpper)
227             RtlFreeUnicodeString(pNameUpper);
228     }
229 
230     if (DirectoryHandle)
231     {
232         Status = ZwClose(DirectoryHandle);
233         ok_eq_hex(Status, STATUS_SUCCESS);
234     }
235 
236     /* parameter tests */
237     /* bugcheck at APC_LEVEL
238     Status = ObReferenceObject(NULL);
239     Status = ObReferenceObjectByPointer(NULL, 0, NULL, UserMode);
240     Status = ObReferenceObjectByPointer(NULL, 0, NULL, KernelMode);*/
241 
242     if (ObDirectoryObjectType)
243     {
244         ObDereferenceObject(ObDirectoryObjectType);
245         ObDirectoryObjectType = NULL;
246     }
247 }
248