2 * NTOSKRNL Ob Regressions KM-Test
3 * ReactOS Kernel Mode Regression Testing framework
5 * Copyright 2006 Aleksey Bragin <aleksey@reactos.org>
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.
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.
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.
23 /* INCLUDES *******************************************************************/
25 #include <ddk/ntddk.h>
26 #include <ddk/ntifs.h>
34 // I ment to make this test scalable, but for now
35 // we work with two object types only
38 typedef struct _MY_OBJECT1
41 } MY_OBJECT1
, *PMY_OBJECT1
;
43 typedef struct _MY_OBJECT2
47 } MY_OBJECT2
, *PMY_OBJECT2
;
49 POBJECT_TYPE ObTypes
[NUM_OBTYPES
];
50 UNICODE_STRING ObTypeName
[NUM_OBTYPES
];
51 UNICODE_STRING ObName
[NUM_OBTYPES
];
52 OBJECT_TYPE_INITIALIZER ObTypeInitializer
[NUM_OBTYPES
];
53 UNICODE_STRING ObDirectoryName
;
54 OBJECT_ATTRIBUTES ObDirectoryAttributes
;
55 OBJECT_ATTRIBUTES ObAttributes
[NUM_OBTYPES
];
56 PVOID ObBody
[NUM_OBTYPES
];
57 PMY_OBJECT1 ObObject1
;
58 PMY_OBJECT2 ObObject2
;
59 HANDLE ObHandle1
[NUM_OBTYPES
];
60 HANDLE ObHandle2
[NUM_OBTYPES
];
61 HANDLE DirectoryHandle
;
63 USHORT DumpCount
, OpenCount
, CloseCount
, DeleteCount
,
64 ParseCount
, OkayToCloseCount
, QueryNameCount
;
66 /* PRIVATE FUNCTIONS **********************************************************/
70 DumpProc(IN PVOID Object
,
71 IN POB_DUMP_CONTROL DumpControl
)
73 DbgPrint("DumpProc() called\n");
80 OpenProc(IN OB_OPEN_REASON OpenReason
,
83 IN ACCESS_MASK GrantedAccess
,
86 DbgPrint("OpenProc() 0x%p, OpenReason %d, HC %d, AM 0x%X\n",
87 Object
, OpenReason
, HandleCount
, GrantedAccess
);
94 CloseProc(IN PEPROCESS Process
,
96 IN ACCESS_MASK GrantedAccess
,
97 IN ULONG ProcessHandleCount
,
98 IN ULONG SystemHandleCount
)
100 DbgPrint("CloseProc() 0x%p, PHC %d, SHC %d, AM 0x%X\n", Object
,
101 ProcessHandleCount
, SystemHandleCount
, GrantedAccess
);
108 DeleteProc(IN PVOID Object
)
110 DbgPrint("DeleteProc() 0x%p\n", Object
);
116 ParseProc(IN PVOID ParseObject
,
118 IN OUT PACCESS_STATE AccessState
,
119 IN KPROCESSOR_MODE AccessMode
,
121 IN OUT PUNICODE_STRING CompleteName
,
122 IN OUT PUNICODE_STRING RemainingName
,
123 IN OUT PVOID Context OPTIONAL
,
124 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
127 DbgPrint("ParseProc() called\n");
131 return STATUS_OBJECT_NAME_NOT_FOUND
;//STATUS_SUCCESS;
137 OkayToCloseProc(IN PEPROCESS Process OPTIONAL
,
140 IN KPROCESSOR_MODE AccessMode
)
142 DbgPrint("OkayToCloseProc() 0x%p, H 0x%p, AM 0x%X\n", Object
, Handle
,
145 return STATUS_SUCCESS
;
150 QueryNameProc(IN PVOID Object
,
151 IN BOOLEAN HasObjectName
,
152 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
154 OUT PULONG ReturnLength
,
155 IN KPROCESSOR_MODE AccessMode
)
157 DbgPrint("QueryNameProc() 0x%p, HON %d, Len %d, AM 0x%X\n",
158 Object
, HasObjectName
, Length
, AccessMode
);
161 ObjectNameInfo
= NULL
;
163 return STATUS_OBJECT_NAME_NOT_FOUND
;
168 ObtCreateObjectTypes()
174 for (i
=0; i
<NUM_OBTYPES
; i
++)
176 // Prepare object type name
177 // TODO: Generate type names and don't use this unprofessional,
178 swprintf(Name
, L
"MyObjectType%lx", i
);
179 RtlInitUnicodeString(&ObTypeName
[i
], Name
);
181 // Prepare initializer
182 RtlZeroMemory(&ObTypeInitializer
[i
], sizeof(ObTypeInitializer
[i
]));
183 ObTypeInitializer
[i
].Length
= sizeof(ObTypeInitializer
[i
]);
184 ObTypeInitializer
[i
].PoolType
= NonPagedPool
;
185 ObTypeInitializer
[i
].MaintainHandleCount
= TRUE
;
186 ObTypeInitializer
[i
].ValidAccessMask
= OBJECT_TYPE_ALL_ACCESS
;
188 // Test for invalid parameter
189 // FIXME: Make it more exact, to see which params Win2k3 checks
191 Status
= ObCreateObjectType(&ObTypeName
[i
], &ObTypeInitializer
[i
],
192 (PSECURITY_DESCRIPTOR
)NULL
, &ObTypes
[i
]);
193 ok(Status
== STATUS_INVALID_PARAMETER
,
194 "ObCreateObjectType returned 0x%lX", Status
);
197 ObTypeInitializer
[i
].CloseProcedure
= (OB_CLOSE_METHOD
)CloseProc
;
198 ObTypeInitializer
[i
].DeleteProcedure
= (OB_DELETE_METHOD
)DeleteProc
;
199 ObTypeInitializer
[i
].DumpProcedure
= (OB_DUMP_METHOD
)DumpProc
;
200 ObTypeInitializer
[i
].OpenProcedure
= (OB_OPEN_METHOD
)OpenProc
;
201 ObTypeInitializer
[i
].ParseProcedure
= (OB_PARSE_METHOD
)ParseProc
;
202 //ObTypeInitializer[i].OkayToCloseProcedure =
203 // (OB_OKAYTOCLOSE_METHOD)OkayToCloseProc;
205 //ObTypeInitializer[i].QueryNameProcedure =
206 // (OB_QUERYNAME_METHOD)QueryNameProc;
208 //ObTypeInitializer[i].SecurityProcedure =
209 // (OB_SECURITY_METHOD)SecurityProc;
211 Status
= ObCreateObjectType(&ObTypeName
[i
], &ObTypeInitializer
[i
],
212 (PSECURITY_DESCRIPTOR
)NULL
, &ObTypes
[i
]);
213 ok(Status
== STATUS_SUCCESS
,
214 "Failed to create object type with status=0x%lX", Status
);
223 // Directory will have permanent and case insensitive flags
224 RtlInitUnicodeString(&ObDirectoryName
, L
"\\ObtDirectory");
225 InitializeObjectAttributes(&ObDirectoryAttributes
, &ObDirectoryName
,
226 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
228 Status
= ZwCreateDirectoryObject(&DirectoryHandle
, 0, &ObDirectoryAttributes
);
229 ok(Status
== STATUS_SUCCESS
,
230 "Failed to create directory object with status=0x%lX", Status
);
238 USHORT OpenSave
, CloseSave
, DeleteSave
, ParseSave
,
239 OkayToCloseSave
, QueryNameSave
;
241 // Create two objects
242 RtlInitUnicodeString(&ObName
[0], L
"\\ObtDirectory\\MyObject1");
243 InitializeObjectAttributes(&ObAttributes
[0], &ObName
[0],
244 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
246 RtlInitUnicodeString(&ObName
[1], L
"\\ObtDirectory\\MyObject2");
247 InitializeObjectAttributes(&ObAttributes
[1], &ObName
[1],
248 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
250 Status
= ObCreateObject(KernelMode
, ObTypes
[0], &ObAttributes
[0],
251 KernelMode
, NULL
, (ULONG
)sizeof(MY_OBJECT1
), 0L, 0L,
252 (PVOID
*)&ObBody
[0]);
253 ok(Status
== STATUS_SUCCESS
,
254 "Failed to create object with status=0x%lX", Status
);
256 Status
= ObCreateObject(KernelMode
, ObTypes
[1], &ObAttributes
[1],
257 KernelMode
, NULL
, (ULONG
)sizeof(MY_OBJECT2
), 0L, 0L,
258 (PVOID
*)&ObBody
[1]);
259 ok(Status
== STATUS_SUCCESS
,
260 "Failed to create object with status=0x%lX", Status
);
263 OpenSave
=OpenCount
; CloseSave
=CloseCount
; DeleteSave
=DeleteCount
;
264 ParseSave
=ParseCount
; OkayToCloseSave
=OkayToCloseCount
;
265 QueryNameSave
=QueryNameCount
;
268 Status
= ObInsertObject(ObBody
[0], NULL
, STANDARD_RIGHTS_ALL
, 0,
269 &ObBody
[0], &ObHandle1
[0]);
270 ok(Status
== STATUS_SUCCESS
,
271 "Failed to insert object 0 with status=0x%lX", Status
);
272 ok(ObBody
[0] != NULL
, "Object body = NULL");
273 ok(ObHandle1
[0] != NULL
, "Handle = NULL");
276 ok(OpenSave
+1 == OpenCount
, "Open method calls mismatch\n");
277 ok(CloseSave
== CloseCount
, "Excessive Close method call\n");
278 ok(DeleteSave
== DeleteCount
, "Excessive Delete method call\n");
279 ok(ParseSave
== ParseCount
, "Excessive Parse method call\n");
282 OpenSave
=OpenCount
; CloseSave
=CloseCount
; DeleteSave
=DeleteCount
;
283 ParseSave
=ParseCount
; OkayToCloseSave
=OkayToCloseCount
;
284 QueryNameSave
=QueryNameCount
;
286 Status
= ObInsertObject(ObBody
[1], NULL
, GENERIC_ALL
, 0,
287 &ObBody
[1], &ObHandle1
[1]);
288 ok(Status
== STATUS_SUCCESS
,
289 "Failed to insert object 1 with status=0x%lX", Status
);
290 ok(ObBody
[1] != NULL
, "Object body = NULL");
291 ok(ObHandle1
[1] != NULL
, "Handle = NULL");
294 ok(OpenSave
+1 == OpenCount
, "Open method calls mismatch\n");
295 ok(CloseSave
== CloseCount
, "Excessive Close method call\n");
296 ok(DeleteSave
== DeleteCount
, "Excessive Delete method call\n");
297 ok(ParseSave
== ParseCount
, "Excessive Parse method call\n");
300 OpenSave
=OpenCount
; CloseSave
=CloseCount
; DeleteSave
=DeleteCount
;
301 ParseSave
=ParseCount
; OkayToCloseSave
=OkayToCloseCount
;
302 QueryNameSave
=QueryNameCount
;
304 // Now create an object of type 0, of the same name and expect it to fail
305 // inserting, but success creation
306 RtlInitUnicodeString(&ObName
[0], L
"\\ObtDirectory\\MyObject1");
307 InitializeObjectAttributes(&ObAttributes
[0], &ObName
[0], OBJ_OPENIF
,
310 Status
= ObCreateObject(KernelMode
, ObTypes
[0], &ObAttributes
[0], KernelMode
,
311 NULL
, (ULONG
)sizeof(MY_OBJECT1
), 0L, 0L, (PVOID
*)&ObBody1
[0]);
312 ok(Status
== STATUS_SUCCESS
,
313 "Failed to create object with status=0x%lX", Status
);
316 ok(OpenSave
== OpenCount
, "Excessive Open method call\n");
317 ok(CloseSave
== CloseCount
, "Excessive Close method call\n");
318 ok(DeleteSave
== DeleteCount
, "Excessive Delete method call\n");
319 ok(ParseSave
== ParseCount
, "Excessive Parse method call\n");
321 Status
= ObInsertObject(ObBody1
[0], NULL
, GENERIC_ALL
, 0,
322 &ObBody1
[1], &ObHandle2
[0]);
323 ok(Status
== STATUS_OBJECT_NAME_EXISTS
,
324 "Object insertion should have failed, but got 0x%lX", Status
);
325 ok(ObBody
[0] == ObBody1
[1],
326 "Object bodies doesn't match, 0x%p != 0x%p", ObBody
[0], ObBody1
[1]);
327 ok(ObHandle2
[0] != NULL
, "Bad handle returned 0x%lX", (ULONG_PTR
)ObHandle2
[0]);
329 DPRINT1("%d %d %d %d %d %d %d\n", DumpCount
, OpenCount
, // deletecount+1
330 CloseCount
, DeleteCount
, ParseCount
, OkayToCloseCount
, QueryNameCount
);
332 // check counters and then save
333 ok(OpenSave
+1 == OpenCount
, "Excessive Open method call\n");
334 ok(CloseSave
== CloseCount
, "Excessive Close method call\n");
335 ok(DeleteSave
+1 == DeleteCount
, "Delete method call mismatch\n");
336 ok(ParseSave
== ParseCount
, "Excessive Parse method call\n");
337 OpenSave
=OpenCount
; CloseSave
=CloseCount
; DeleteSave
=DeleteCount
;
338 ParseSave
=ParseCount
; OkayToCloseSave
=OkayToCloseCount
;
339 QueryNameSave
=QueryNameCount
;
342 Status
= ZwClose(ObHandle2
[0]);
343 ok(Status
== STATUS_SUCCESS
,
344 "Failed to close handle status=0x%lX", Status
);
346 // check counters and then save
347 ok(OpenSave
== OpenCount
, "Excessive Open method call\n");
348 ok(CloseSave
+1 == CloseCount
, "Close method call mismatch\n");
349 ok(DeleteSave
== DeleteCount
, "Excessive Delete method call\n");
350 ok(ParseSave
== ParseCount
, "Excessive Parse method call\n");
351 OpenSave
=OpenCount
; CloseSave
=CloseCount
; DeleteSave
=DeleteCount
;
352 ParseSave
=ParseCount
; OkayToCloseSave
=OkayToCloseCount
;
353 QueryNameSave
=QueryNameCount
;
356 // Object referenced 2 times:
358 // 2) AdditionalReferences
359 ObDereferenceObject(ObBody1
[1]);
361 //DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, // no change
362 // CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
363 ok(OpenSave
== OpenCount
, "Open method call mismatch\n");
364 ok(CloseSave
== CloseCount
, "Close method call mismatch\n");
365 ok(DeleteSave
== DeleteCount
, "Delete method call mismatch\n");
366 ok(ParseSave
== ParseCount
, "Parse method call mismatch\n");
376 //UNICODE_STRING ObPathName[NUM_OBTYPES];
378 // Close what we have opened and free what we allocated
379 ZwClose(ObHandle1
[0]);
380 ZwClose(ObHandle1
[1]);
381 ZwClose(ObHandle2
[0]);
382 ZwClose(ObHandle2
[1]);
384 // Now we have to get rid of a directory object
385 // Since it is permanent, we have to firstly make it temporary
386 // and only then kill
387 // (this procedure is described in DDK)
388 Status
= ObReferenceObjectByHandle(DirectoryHandle
, 0L, NULL
,
389 KernelMode
, &DirObject
, NULL
);
390 ok(Status
== STATUS_SUCCESS
,
391 "Failed to reference object by handle with status=0x%lX", Status
);
393 // Dereference 2 times - first for just previous referencing
394 // and 2nd time for creation of permanent object itself
395 ObDereferenceObject(DirObject
);
396 ObDereferenceObject(DirObject
);
398 Status
= ZwMakeTemporaryObject(DirectoryHandle
);
399 ok(Status
== STATUS_SUCCESS
,
400 "Failed to make temp object with status=0x%lX", Status
);
402 // Close the handle now and we are done
403 Status
= ZwClose(DirectoryHandle
);
404 ok(Status
== STATUS_SUCCESS
,
405 "Failed to close handle with status=0x%lX", Status
);
407 // Now delete the last piece - object types
408 // In fact, it's weird to get rid of object types, especially the way,
409 // how it's done in the commented section below
410 for (i
=0; i
<NUM_OBTYPES
; i
++)
411 ObDereferenceObject(ObTypes
[i
]);
413 RtlInitUnicodeString(&ObPathName[0], L"\\ObjectTypes\\MyObjectType1");
414 RtlInitUnicodeString(&ObPathName[1], L"\\ObjectTypes\\MyObjectType2");
416 for (i=0; i<NUM_OBTYPES; i++)
418 Status = ObReferenceObjectByName(&ObPathName[i],
419 OBJ_CASE_INSENSITIVE, NULL, 0L, NULL, KernelMode, NULL,
422 ObDereferenceObject(TypeObject);
423 ObDereferenceObject(TypeObject);
424 DPRINT("Reference Name %S = %p, ObTypes[%d] = %p\n",
425 ObPathName[i], TypeObject, i, ObTypes[i]);
435 UNICODE_STRING ObPathName
[NUM_OBTYPES
];
437 // Reference them by handle
438 for (i
=0; i
<NUM_OBTYPES
; i
++)
440 Status
= ObReferenceObjectByHandle(ObHandle1
[i
], 0L, ObTypes
[i
],
441 KernelMode
, &ObBody
[i
], NULL
);
442 ok(Status
== STATUS_SUCCESS
,
443 "Failed to reference object by handle, status=0x%lX", Status
);
444 DPRINT("Ref by handle %lx = %p\n", ObHandle1
[i
], ObBody
[i
]);
447 // Reference them by pointer
448 for (i
=0; i
<NUM_OBTYPES
; i
++)
450 Status
= ObReferenceObjectByPointer(ObBody
[i
], 0L, ObTypes
[i
], KernelMode
);
451 ok(Status
== STATUS_SUCCESS
,
452 "Failed to reference object by pointer, status=0x%lX", Status
);
455 // Reference them by name
456 RtlInitUnicodeString(&ObPathName
[0], L
"\\ObtDirectory\\MyObject1");
457 RtlInitUnicodeString(&ObPathName
[1], L
"\\ObtDirectory\\MyObject2");
459 for (i
=0; i
<NUM_OBTYPES
; i
++)
461 Status
= ObReferenceObjectByName(&ObPathName
[i
],
462 OBJ_CASE_INSENSITIVE
, NULL
, 0L, ObTypes
[i
], KernelMode
, NULL
,
465 DPRINT("Ref by name %wZ = %p\n", &ObPathName
[i
], ObBody
[i
]);
468 // Dereference now all of them
470 // For ObInsertObject, AdditionalReference
471 ObDereferenceObject(ObBody
[0]);
472 ObDereferenceObject(ObBody
[1]);
475 ObDereferenceObject(ObBody
[0]);
476 ObDereferenceObject(ObBody
[1]);
479 ObDereferenceObject(ObBody
[0]);
480 ObDereferenceObject(ObBody
[1]);
483 ObDereferenceObject(ObBody
[0]);
484 ObDereferenceObject(ObBody
[1]);
487 /* PUBLIC FUNCTIONS ***********************************************************/
490 NtoskrnlObTest(HANDLE KeyHandle
)
494 DumpCount
= 0; OpenCount
= 0; CloseCount
= 0;
495 DeleteCount
= 0; ParseCount
= 0;
497 // Create object-types to use in tests
498 ObtCreateObjectTypes();
499 DPRINT("ObtCreateObjectTypes() done\n");
502 ObtCreateDirectory();
503 DPRINT("ObtCreateDirectory() done\n");
505 // Create and insert objects
507 DPRINT("ObtCreateObjects() done\n");
509 // Reference them in a variety of ways
510 //ObtReferenceTests();
513 // FIXME: Disable to see results of creating objects in usermode.
514 // Also it has problems with object types removal
516 DPRINT("Cleanup done\n");
518 FinishTest(KeyHandle
, L
"ObMgrTest");