Merge 25584, 25588.
[reactos.git] / reactos / drivers / test / kmtest / ntos_ob.c
1 /*
2 * NTOSKRNL Ob Regressions KM-Test
3 * ReactOS Kernel Mode Regression Testing framework
4 *
5 * Copyright 2006 Aleksey Bragin <aleksey@reactos.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; see the file COPYING.LIB.
19 * If not, write to the Free Software Foundation,
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23 /* INCLUDES *******************************************************************/
24
25 #include <ddk/ntddk.h>
26 #include "kmtest.h"
27
28 //#define NDEBUG
29 #include "debug.h"
30
31 #include "ndk/obtypes.h"
32 #include "ndk/obfuncs.h"
33
34 #include "ndk/ifssupp.h"
35 #include "ndk/setypes.h"
36 #include "ndk/sefuncs.h"
37
38 // I ment to make this test scalable, but for now
39 // we work with two object types only
40 #define NUM_OBTYPES 2
41
42 typedef struct _MY_OBJECT1
43 {
44 ULONG Something1;
45 } MY_OBJECT1, *PMY_OBJECT1;
46
47 typedef struct _MY_OBJECT2
48 {
49 ULONG Something1;
50 ULONG SomeLong[10];
51 } MY_OBJECT2, *PMY_OBJECT2;
52
53 POBJECT_TYPE ObTypes[NUM_OBTYPES];
54 UNICODE_STRING ObTypeName[NUM_OBTYPES];
55 UNICODE_STRING ObName[NUM_OBTYPES];
56 OBJECT_TYPE_INITIALIZER ObTypeInitializer[NUM_OBTYPES];
57 UNICODE_STRING ObDirectoryName;
58 OBJECT_ATTRIBUTES ObDirectoryAttributes;
59 OBJECT_ATTRIBUTES ObAttributes[NUM_OBTYPES];
60 PVOID ObBody[NUM_OBTYPES];
61 PMY_OBJECT1 ObObject1;
62 PMY_OBJECT2 ObObject2;
63 HANDLE ObHandle1[NUM_OBTYPES];
64 HANDLE ObHandle2[NUM_OBTYPES];
65 HANDLE DirectoryHandle;
66
67 USHORT DumpCount, OpenCount, CloseCount, DeleteCount,
68 ParseCount, OkayToCloseCount, QueryNameCount;
69
70 /* PRIVATE FUNCTIONS **********************************************************/
71
72 VOID
73 NTAPI
74 DumpProc(IN PVOID Object,
75 IN POB_DUMP_CONTROL DumpControl)
76 {
77 DbgPrint("DumpProc() called\n");
78 DumpCount++;
79 }
80
81 // Tested in Win2k3
82 VOID
83 NTAPI
84 OpenProc(IN OB_OPEN_REASON OpenReason,
85 IN PEPROCESS Process,
86 IN PVOID Object,
87 IN ACCESS_MASK GrantedAccess,
88 IN ULONG HandleCount)
89 {
90 DbgPrint("OpenProc() 0x%p, OpenReason %d, HC %d, AM 0x%X\n",
91 Object, OpenReason, HandleCount, GrantedAccess);
92 OpenCount++;
93 }
94
95 // Tested in Win2k3
96 VOID
97 NTAPI
98 CloseProc(IN PEPROCESS Process,
99 IN PVOID Object,
100 IN ACCESS_MASK GrantedAccess,
101 IN ULONG ProcessHandleCount,
102 IN ULONG SystemHandleCount)
103 {
104 DbgPrint("CloseProc() 0x%p, PHC %d, SHC %d, AM 0x%X\n", Object,
105 ProcessHandleCount, SystemHandleCount, GrantedAccess);
106 CloseCount++;
107 }
108
109 // Tested in Win2k3
110 VOID
111 NTAPI
112 DeleteProc(IN PVOID Object)
113 {
114 DbgPrint("DeleteProc() 0x%p\n", Object);
115 DeleteCount++;
116 }
117
118 NTSTATUS
119 NTAPI
120 ParseProc(IN PVOID ParseObject,
121 IN PVOID ObjectType,
122 IN OUT PACCESS_STATE AccessState,
123 IN KPROCESSOR_MODE AccessMode,
124 IN ULONG Attributes,
125 IN OUT PUNICODE_STRING CompleteName,
126 IN OUT PUNICODE_STRING RemainingName,
127 IN OUT PVOID Context OPTIONAL,
128 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
129 OUT PVOID *Object)
130 {
131 DbgPrint("ParseProc() called\n");
132 *Object = NULL;
133
134 ParseCount++;
135 return STATUS_OBJECT_NAME_NOT_FOUND;//STATUS_SUCCESS;
136 }
137
138 // Tested in Win2k3
139 NTSTATUS
140 NTAPI
141 OkayToCloseProc(IN PEPROCESS Process OPTIONAL,
142 IN PVOID Object,
143 IN HANDLE Handle,
144 IN KPROCESSOR_MODE AccessMode)
145 {
146 DbgPrint("OkayToCloseProc() 0x%p, H 0x%p, AM 0x%X\n", Object, Handle,
147 AccessMode);
148 OkayToCloseCount++;
149 return STATUS_SUCCESS;
150 }
151
152 NTSTATUS
153 NTAPI
154 QueryNameProc(IN PVOID Object,
155 IN BOOLEAN HasObjectName,
156 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
157 IN ULONG Length,
158 OUT PULONG ReturnLength,
159 IN KPROCESSOR_MODE AccessMode)
160 {
161 DbgPrint("QueryNameProc() 0x%p, HON %d, Len %d, AM 0x%X\n",
162 Object, HasObjectName, Length, AccessMode);
163 QueryNameCount++;
164
165 ObjectNameInfo = NULL;
166 ReturnLength = 0;
167 return STATUS_OBJECT_NAME_NOT_FOUND;
168 }
169
170
171 VOID
172 ObtCreateObjectTypes()
173 {
174 USHORT i;
175 NTSTATUS Status;
176 WCHAR Name[15];
177
178 for (i=0; i<NUM_OBTYPES; i++)
179 {
180 // Prepare object type name
181 // TODO: Generate type names and don't use this unprofessional,
182 swprintf(Name, L"MyObjectType%lx", i);
183 RtlInitUnicodeString(&ObTypeName[i], Name);
184
185 // Prepare initializer
186 RtlZeroMemory(&ObTypeInitializer[i], sizeof(ObTypeInitializer[i]));
187 ObTypeInitializer[i].Length = sizeof(ObTypeInitializer[i]);
188 ObTypeInitializer[i].PoolType = NonPagedPool;
189 ObTypeInitializer[i].MaintainHandleCount = TRUE;
190 ObTypeInitializer[i].ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
191
192 // Test for invalid parameter
193 // FIXME: Make it more exact, to see which params Win2k3 checks
194 // existence of
195 Status = ObCreateObjectType(&ObTypeName[i], &ObTypeInitializer[i],
196 (PSECURITY_DESCRIPTOR)NULL, &ObTypes[i]);
197 ok(Status == STATUS_INVALID_PARAMETER,
198 "ObCreateObjectType returned 0x%lX", Status);
199
200 // Object procedures
201 ObTypeInitializer[i].CloseProcedure = (OB_CLOSE_METHOD)CloseProc;
202 ObTypeInitializer[i].DeleteProcedure = (OB_DELETE_METHOD)DeleteProc;
203 ObTypeInitializer[i].DumpProcedure = (OB_DUMP_METHOD)DumpProc;
204 ObTypeInitializer[i].OpenProcedure = (OB_OPEN_METHOD)OpenProc;
205 ObTypeInitializer[i].ParseProcedure = (OB_PARSE_METHOD)ParseProc;
206 //ObTypeInitializer[i].OkayToCloseProcedure =
207 // (OB_OKAYTOCLOSE_METHOD)OkayToCloseProc;
208
209 //ObTypeInitializer[i].QueryNameProcedure =
210 // (OB_QUERYNAME_METHOD)QueryNameProc;
211
212 //ObTypeInitializer[i].SecurityProcedure =
213 // (OB_SECURITY_METHOD)SecurityProc;
214
215 Status = ObCreateObjectType(&ObTypeName[i], &ObTypeInitializer[i],
216 (PSECURITY_DESCRIPTOR)NULL, &ObTypes[i]);
217 ok(Status == STATUS_SUCCESS,
218 "Failed to create object type with status=0x%lX", Status);
219 }
220 }
221
222 VOID
223 ObtCreateDirectory()
224 {
225 NTSTATUS Status;
226
227 // Directory will have permanent and case insensitive flags
228 RtlInitUnicodeString(&ObDirectoryName, L"\\ObtDirectory");
229 InitializeObjectAttributes(&ObDirectoryAttributes, &ObDirectoryName,
230 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, NULL, NULL);
231
232 Status = ZwCreateDirectoryObject(&DirectoryHandle, 0, &ObDirectoryAttributes);
233 ok(Status == STATUS_SUCCESS,
234 "Failed to create directory object with status=0x%lX", Status);
235 }
236
237 VOID
238 ObtCreateObjects()
239 {
240 PVOID ObBody1[2];
241 NTSTATUS Status;
242 USHORT OpenSave, CloseSave, DeleteSave, ParseSave,
243 OkayToCloseSave, QueryNameSave;
244
245 // Create two objects
246 RtlInitUnicodeString(&ObName[0], L"\\ObtDirectory\\MyObject1");
247 InitializeObjectAttributes(&ObAttributes[0], &ObName[0],
248 OBJ_CASE_INSENSITIVE, NULL, NULL);
249
250 RtlInitUnicodeString(&ObName[1], L"\\ObtDirectory\\MyObject2");
251 InitializeObjectAttributes(&ObAttributes[1], &ObName[1],
252 OBJ_CASE_INSENSITIVE, NULL, NULL);
253
254 Status = ObCreateObject(KernelMode, ObTypes[0], &ObAttributes[0],
255 KernelMode, NULL, (ULONG)sizeof(MY_OBJECT1), 0L, 0L,
256 (PVOID *)&ObBody[0]);
257 ok(Status == STATUS_SUCCESS,
258 "Failed to create object with status=0x%lX", Status);
259
260 Status = ObCreateObject(KernelMode, ObTypes[1], &ObAttributes[1],
261 KernelMode, NULL, (ULONG)sizeof(MY_OBJECT2), 0L, 0L,
262 (PVOID *)&ObBody[1]);
263 ok(Status == STATUS_SUCCESS,
264 "Failed to create object with status=0x%lX", Status);
265
266 // save counters
267 OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
268 ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
269 QueryNameSave=QueryNameCount;
270
271 // Insert them
272 Status = ObInsertObject(ObBody[0], NULL, STANDARD_RIGHTS_ALL, 0,
273 &ObBody[0], &ObHandle1[0]);
274 ok(Status == STATUS_SUCCESS,
275 "Failed to insert object 0 with status=0x%lX", Status);
276 ok(ObBody[0] != NULL, "Object body = NULL");
277 ok(ObHandle1[0] != NULL, "Handle = NULL");
278
279 // check counters
280 ok(OpenSave+1 == OpenCount, "Open method calls mismatch\n");
281 ok(CloseSave == CloseCount, "Excessive Close method call\n");
282 ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
283 ok(ParseSave == ParseCount, "Excessive Parse method call\n");
284
285 // save counters
286 OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
287 ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
288 QueryNameSave=QueryNameCount;
289
290 Status = ObInsertObject(ObBody[1], NULL, GENERIC_ALL, 0,
291 &ObBody[1], &ObHandle1[1]);
292 ok(Status == STATUS_SUCCESS,
293 "Failed to insert object 1 with status=0x%lX", Status);
294 ok(ObBody[1] != NULL, "Object body = NULL");
295 ok(ObHandle1[1] != NULL, "Handle = NULL");
296
297 // check counters
298 ok(OpenSave+1 == OpenCount, "Open method calls mismatch\n");
299 ok(CloseSave == CloseCount, "Excessive Close method call\n");
300 ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
301 ok(ParseSave == ParseCount, "Excessive Parse method call\n");
302
303 // save counters
304 OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
305 ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
306 QueryNameSave=QueryNameCount;
307
308 // Now create an object of type 0, of the same name and expect it to fail
309 // inserting, but success creation
310 RtlInitUnicodeString(&ObName[0], L"\\ObtDirectory\\MyObject1");
311 InitializeObjectAttributes(&ObAttributes[0], &ObName[0], OBJ_OPENIF,
312 NULL, NULL);
313
314 Status = ObCreateObject(KernelMode, ObTypes[0], &ObAttributes[0], KernelMode,
315 NULL, (ULONG)sizeof(MY_OBJECT1), 0L, 0L, (PVOID *)&ObBody1[0]);
316 ok(Status == STATUS_SUCCESS,
317 "Failed to create object with status=0x%lX", Status);
318
319 // check counters
320 ok(OpenSave == OpenCount, "Excessive Open method call\n");
321 ok(CloseSave == CloseCount, "Excessive Close method call\n");
322 ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
323 ok(ParseSave == ParseCount, "Excessive Parse method call\n");
324
325 Status = ObInsertObject(ObBody1[0], NULL, GENERIC_ALL, 0,
326 &ObBody1[1], &ObHandle2[0]);
327 ok(Status == STATUS_OBJECT_NAME_EXISTS,
328 "Object insertion should have failed, but got 0x%lX", Status);
329 ok(ObBody[0] == ObBody1[1],
330 "Object bodies doesn't match, 0x%p != 0x%p", ObBody[0], ObBody1[1]);
331 ok(ObHandle2[0] != NULL, "Bad handle returned 0x%lX", (ULONG)ObHandle2[0]);
332
333 DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, // deletecount+1
334 CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
335
336 // check counters and then save
337 ok(OpenSave+1 == OpenCount, "Excessive Open method call\n");
338 ok(CloseSave == CloseCount, "Excessive Close method call\n");
339 ok(DeleteSave+1 == DeleteCount, "Delete method call mismatch\n");
340 ok(ParseSave == ParseCount, "Excessive Parse method call\n");
341 OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
342 ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
343 QueryNameSave=QueryNameCount;
344
345 // Close its handle
346 Status = ZwClose(ObHandle2[0]);
347 ok(Status == STATUS_SUCCESS,
348 "Failed to close handle status=0x%lX", Status);
349
350 // check counters and then save
351 ok(OpenSave == OpenCount, "Excessive Open method call\n");
352 ok(CloseSave+1 == CloseCount, "Close method call mismatch\n");
353 ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
354 ok(ParseSave == ParseCount, "Excessive Parse method call\n");
355 OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
356 ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
357 QueryNameSave=QueryNameCount;
358
359
360 // Object referenced 2 times:
361 // 1) ObInsertObject
362 // 2) AdditionalReferences
363 ObDereferenceObject(ObBody1[1]);
364
365 //DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, // no change
366 // CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
367 ok(OpenSave == OpenCount, "Open method call mismatch\n");
368 ok(CloseSave == CloseCount, "Close method call mismatch\n");
369 ok(DeleteSave == DeleteCount, "Delete method call mismatch\n");
370 ok(ParseSave == ParseCount, "Parse method call mismatch\n");
371 }
372
373 VOID
374 ObtClose()
375 {
376 PVOID DirObject;
377 NTSTATUS Status;
378 //PVOID TypeObject;
379 USHORT i;
380 //UNICODE_STRING ObPathName[NUM_OBTYPES];
381
382 // Close what we have opened and free what we allocated
383 ZwClose(ObHandle1[0]);
384 ZwClose(ObHandle1[1]);
385 ZwClose(ObHandle2[0]);
386 ZwClose(ObHandle2[1]);
387
388 // Now we have to get rid of a directory object
389 // Since it is permanent, we have to firstly make it temporary
390 // and only then kill
391 // (this procedure is described in DDK)
392 Status = ObReferenceObjectByHandle(DirectoryHandle, 0L, NULL,
393 KernelMode, &DirObject, NULL);
394 ok(Status == STATUS_SUCCESS,
395 "Failed to reference object by handle with status=0x%lX", Status);
396
397 // Dereference 2 times - first for just previous referencing
398 // and 2nd time for creation of permanent object itself
399 ObDereferenceObject(DirObject);
400 ObDereferenceObject(DirObject);
401
402 Status = ZwMakeTemporaryObject(DirectoryHandle);
403 ok(Status == STATUS_SUCCESS,
404 "Failed to make temp object with status=0x%lX", Status);
405
406 // Close the handle now and we are done
407 Status = ZwClose(DirectoryHandle);
408 ok(Status == STATUS_SUCCESS,
409 "Failed to close handle with status=0x%lX", Status);
410
411 // Now delete the last piece - object types
412 // In fact, it's weird to get rid of object types, especially the way,
413 // how it's done in the commented section below
414 for (i=0; i<NUM_OBTYPES; i++)
415 ObDereferenceObject(ObTypes[i]);
416 /*
417 RtlInitUnicodeString(&ObPathName[0], L"\\ObjectTypes\\MyObjectType1");
418 RtlInitUnicodeString(&ObPathName[1], L"\\ObjectTypes\\MyObjectType2");
419
420 for (i=0; i<NUM_OBTYPES; i++)
421 {
422 Status = ObReferenceObjectByName(&ObPathName[i],
423 OBJ_CASE_INSENSITIVE, NULL, 0L, NULL, KernelMode, NULL,
424 &TypeObject);
425
426 ObDereferenceObject(TypeObject);
427 ObDereferenceObject(TypeObject);
428 DPRINT("Reference Name %S = %p, ObTypes[%d] = %p\n",
429 ObPathName[i], TypeObject, i, ObTypes[i]);
430 }
431 */
432 }
433
434 VOID
435 ObtReferenceTests()
436 {
437 USHORT i;
438 NTSTATUS Status;
439 UNICODE_STRING ObPathName[NUM_OBTYPES];
440
441 // Reference them by handle
442 for (i=0; i<NUM_OBTYPES; i++)
443 {
444 Status = ObReferenceObjectByHandle(ObHandle1[i], 0L, ObTypes[i],
445 KernelMode, &ObBody[i], NULL);
446 ok(Status == STATUS_SUCCESS,
447 "Failed to reference object by handle, status=0x%lX", Status);
448 DPRINT("Ref by handle %lx = %p\n", ObHandle1[i], ObBody[i]);
449 }
450
451 // Reference them by pointer
452 for (i=0; i<NUM_OBTYPES; i++)
453 {
454 Status = ObReferenceObjectByPointer(ObBody[i], 0L, ObTypes[i], KernelMode);
455 ok(Status == STATUS_SUCCESS,
456 "Failed to reference object by pointer, status=0x%lX", Status);
457 }
458
459 // Reference them by name
460 RtlInitUnicodeString(&ObPathName[0], L"\\ObtDirectory\\MyObject1");
461 RtlInitUnicodeString(&ObPathName[1], L"\\ObtDirectory\\MyObject2");
462
463 for (i=0; i<NUM_OBTYPES; i++)
464 {
465 Status = ObReferenceObjectByName(&ObPathName[i],
466 OBJ_CASE_INSENSITIVE, NULL, 0L, ObTypes[i], KernelMode, NULL,
467 &ObBody[0]);
468
469 DPRINT("Ref by name %wZ = %p\n", &ObPathName[i], ObBody[i]);
470 }
471
472 // Dereference now all of them
473
474 // For ObInsertObject, AdditionalReference
475 ObDereferenceObject(ObBody[0]);
476 ObDereferenceObject(ObBody[1]);
477
478 // For ByHandle
479 ObDereferenceObject(ObBody[0]);
480 ObDereferenceObject(ObBody[1]);
481
482 // For ByPointer
483 ObDereferenceObject(ObBody[0]);
484 ObDereferenceObject(ObBody[1]);
485
486 // For ByName
487 ObDereferenceObject(ObBody[0]);
488 ObDereferenceObject(ObBody[1]);
489 }
490
491 /* PUBLIC FUNCTIONS ***********************************************************/
492
493 VOID
494 FASTCALL
495 NtoskrnlObTest()
496 {
497 StartTest();
498
499 DumpCount = 0; OpenCount = 0; CloseCount = 0;
500 DeleteCount = 0; ParseCount = 0;
501
502 // Create object-types to use in tests
503 ObtCreateObjectTypes();
504 DPRINT("ObtCreateObjectTypes() done\n");
505
506 // Create Directory
507 ObtCreateDirectory();
508 DPRINT("ObtCreateDirectory() done\n");
509
510 // Create and insert objects
511 ObtCreateObjects();
512 DPRINT("ObtCreateObjects() done\n");
513
514 // Reference them in a variety of ways
515 //ObtReferenceTests();
516
517 // Clean up
518 // FIXME: Disable to see results of creating objects in usermode.
519 // Also it has problems with object types removal
520 ObtClose();
521 DPRINT("Cleanup done\n");
522
523 FinishTest("NTOSKRNL Ob Manager");
524 }