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>
33 // I ment to make this test scalable, but for now
34 // we work with two object types only
37 typedef struct _MY_OBJECT1
40 } MY_OBJECT1
, *PMY_OBJECT1
;
42 typedef struct _MY_OBJECT2
46 } MY_OBJECT2
, *PMY_OBJECT2
;
48 POBJECT_TYPE ObTypes
[NUM_OBTYPES
];
49 UNICODE_STRING ObTypeName
[NUM_OBTYPES
];
50 UNICODE_STRING ObName
[NUM_OBTYPES
];
51 OBJECT_TYPE_INITIALIZER ObTypeInitializer
[NUM_OBTYPES
];
52 UNICODE_STRING ObDirectoryName
;
53 OBJECT_ATTRIBUTES ObDirectoryAttributes
;
54 OBJECT_ATTRIBUTES ObAttributes
[NUM_OBTYPES
];
55 PVOID ObBody
[NUM_OBTYPES
];
56 PMY_OBJECT1 ObObject1
;
57 PMY_OBJECT2 ObObject2
;
58 HANDLE ObHandle1
[NUM_OBTYPES
];
59 HANDLE ObHandle2
[NUM_OBTYPES
];
60 HANDLE DirectoryHandle
;
62 USHORT DumpCount
, OpenCount
, CloseCount
, DeleteCount
,
63 ParseCount
, OkayToCloseCount
, QueryNameCount
;
65 /* PRIVATE FUNCTIONS **********************************************************/
69 DumpProc(IN PVOID Object
,
70 IN POB_DUMP_CONTROL DumpControl
)
72 DbgPrint("DumpProc() called\n");
79 OpenProc(IN OB_OPEN_REASON OpenReason
,
82 IN ACCESS_MASK GrantedAccess
,
85 DbgPrint("OpenProc() 0x%p, OpenReason %d, HC %d, AM 0x%X\n",
86 Object
, OpenReason
, HandleCount
, GrantedAccess
);
93 CloseProc(IN PEPROCESS Process
,
95 IN ACCESS_MASK GrantedAccess
,
96 IN ULONG ProcessHandleCount
,
97 IN ULONG SystemHandleCount
)
99 DbgPrint("CloseProc() 0x%p, PHC %d, SHC %d, AM 0x%X\n", Object
,
100 ProcessHandleCount
, SystemHandleCount
, GrantedAccess
);
107 DeleteProc(IN PVOID Object
)
109 DbgPrint("DeleteProc() 0x%p\n", Object
);
115 ParseProc(IN PVOID ParseObject
,
117 IN OUT PACCESS_STATE AccessState
,
118 IN KPROCESSOR_MODE AccessMode
,
120 IN OUT PUNICODE_STRING CompleteName
,
121 IN OUT PUNICODE_STRING RemainingName
,
122 IN OUT PVOID Context OPTIONAL
,
123 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
126 DbgPrint("ParseProc() called\n");
130 return STATUS_OBJECT_NAME_NOT_FOUND
;//STATUS_SUCCESS;
136 OkayToCloseProc(IN PEPROCESS Process OPTIONAL
,
139 IN KPROCESSOR_MODE AccessMode
)
141 DbgPrint("OkayToCloseProc() 0x%p, H 0x%p, AM 0x%X\n", Object
, Handle
,
144 return STATUS_SUCCESS
;
149 QueryNameProc(IN PVOID Object
,
150 IN BOOLEAN HasObjectName
,
151 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
153 OUT PULONG ReturnLength
,
154 IN KPROCESSOR_MODE AccessMode
)
156 DbgPrint("QueryNameProc() 0x%p, HON %d, Len %d, AM 0x%X\n",
157 Object
, HasObjectName
, Length
, AccessMode
);
160 ObjectNameInfo
= NULL
;
162 return STATUS_OBJECT_NAME_NOT_FOUND
;
167 ObtCreateObjectTypes()
173 for (i
=0; i
<NUM_OBTYPES
; i
++)
175 // Prepare object type name
176 // TODO: Generate type names and don't use this unprofessional,
177 swprintf(Name
, L
"MyObjectType%lx", i
);
178 RtlInitUnicodeString(&ObTypeName
[i
], Name
);
180 // Prepare initializer
181 RtlZeroMemory(&ObTypeInitializer
[i
], sizeof(ObTypeInitializer
[i
]));
182 ObTypeInitializer
[i
].Length
= sizeof(ObTypeInitializer
[i
]);
183 ObTypeInitializer
[i
].PoolType
= NonPagedPool
;
184 ObTypeInitializer
[i
].MaintainHandleCount
= TRUE
;
185 ObTypeInitializer
[i
].ValidAccessMask
= OBJECT_TYPE_ALL_ACCESS
;
187 // Test for invalid parameter
188 // FIXME: Make it more exact, to see which params Win2k3 checks
190 Status
= ObCreateObjectType(&ObTypeName
[i
], &ObTypeInitializer
[i
],
191 (PSECURITY_DESCRIPTOR
)NULL
, &ObTypes
[i
]);
192 ok(Status
== STATUS_INVALID_PARAMETER
,
193 "ObCreateObjectType returned 0x%lX", Status
);
196 ObTypeInitializer
[i
].CloseProcedure
= (OB_CLOSE_METHOD
)CloseProc
;
197 ObTypeInitializer
[i
].DeleteProcedure
= (OB_DELETE_METHOD
)DeleteProc
;
198 ObTypeInitializer
[i
].DumpProcedure
= (OB_DUMP_METHOD
)DumpProc
;
199 ObTypeInitializer
[i
].OpenProcedure
= (OB_OPEN_METHOD
)OpenProc
;
200 ObTypeInitializer
[i
].ParseProcedure
= (OB_PARSE_METHOD
)ParseProc
;
201 //ObTypeInitializer[i].OkayToCloseProcedure =
202 // (OB_OKAYTOCLOSE_METHOD)OkayToCloseProc;
204 //ObTypeInitializer[i].QueryNameProcedure =
205 // (OB_QUERYNAME_METHOD)QueryNameProc;
207 //ObTypeInitializer[i].SecurityProcedure =
208 // (OB_SECURITY_METHOD)SecurityProc;
210 Status
= ObCreateObjectType(&ObTypeName
[i
], &ObTypeInitializer
[i
],
211 (PSECURITY_DESCRIPTOR
)NULL
, &ObTypes
[i
]);
212 ok(Status
== STATUS_SUCCESS
,
213 "Failed to create object type with status=0x%lX", Status
);
222 // Directory will have permanent and case insensitive flags
223 RtlInitUnicodeString(&ObDirectoryName
, L
"\\ObtDirectory");
224 InitializeObjectAttributes(&ObDirectoryAttributes
, &ObDirectoryName
,
225 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
227 Status
= ZwCreateDirectoryObject(&DirectoryHandle
, 0, &ObDirectoryAttributes
);
228 ok(Status
== STATUS_SUCCESS
,
229 "Failed to create directory object with status=0x%lX", Status
);
237 USHORT OpenSave
, CloseSave
, DeleteSave
, ParseSave
,
238 OkayToCloseSave
, QueryNameSave
;
240 // Create two objects
241 RtlInitUnicodeString(&ObName
[0], L
"\\ObtDirectory\\MyObject1");
242 InitializeObjectAttributes(&ObAttributes
[0], &ObName
[0],
243 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
245 RtlInitUnicodeString(&ObName
[1], L
"\\ObtDirectory\\MyObject2");
246 InitializeObjectAttributes(&ObAttributes
[1], &ObName
[1],
247 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
249 Status
= ObCreateObject(KernelMode
, ObTypes
[0], &ObAttributes
[0],
250 KernelMode
, NULL
, (ULONG
)sizeof(MY_OBJECT1
), 0L, 0L,
251 (PVOID
*)&ObBody
[0]);
252 ok(Status
== STATUS_SUCCESS
,
253 "Failed to create object with status=0x%lX", Status
);
255 Status
= ObCreateObject(KernelMode
, ObTypes
[1], &ObAttributes
[1],
256 KernelMode
, NULL
, (ULONG
)sizeof(MY_OBJECT2
), 0L, 0L,
257 (PVOID
*)&ObBody
[1]);
258 ok(Status
== STATUS_SUCCESS
,
259 "Failed to create object with status=0x%lX", Status
);
262 OpenSave
=OpenCount
; CloseSave
=CloseCount
; DeleteSave
=DeleteCount
;
263 ParseSave
=ParseCount
; OkayToCloseSave
=OkayToCloseCount
;
264 QueryNameSave
=QueryNameCount
;
267 Status
= ObInsertObject(ObBody
[0], NULL
, STANDARD_RIGHTS_ALL
, 0,
268 &ObBody
[0], &ObHandle1
[0]);
269 ok(Status
== STATUS_SUCCESS
,
270 "Failed to insert object 0 with status=0x%lX", Status
);
271 ok(ObBody
[0] != NULL
, "Object body = NULL");
272 ok(ObHandle1
[0] != NULL
, "Handle = NULL");
275 ok(OpenSave
+1 == OpenCount
, "Open method calls mismatch\n");
276 ok(CloseSave
== CloseCount
, "Excessive Close method call\n");
277 ok(DeleteSave
== DeleteCount
, "Excessive Delete method call\n");
278 ok(ParseSave
== ParseCount
, "Excessive Parse method call\n");
281 OpenSave
=OpenCount
; CloseSave
=CloseCount
; DeleteSave
=DeleteCount
;
282 ParseSave
=ParseCount
; OkayToCloseSave
=OkayToCloseCount
;
283 QueryNameSave
=QueryNameCount
;
285 Status
= ObInsertObject(ObBody
[1], NULL
, GENERIC_ALL
, 0,
286 &ObBody
[1], &ObHandle1
[1]);
287 ok(Status
== STATUS_SUCCESS
,
288 "Failed to insert object 1 with status=0x%lX", Status
);
289 ok(ObBody
[1] != NULL
, "Object body = NULL");
290 ok(ObHandle1
[1] != NULL
, "Handle = NULL");
293 ok(OpenSave
+1 == OpenCount
, "Open method calls mismatch\n");
294 ok(CloseSave
== CloseCount
, "Excessive Close method call\n");
295 ok(DeleteSave
== DeleteCount
, "Excessive Delete method call\n");
296 ok(ParseSave
== ParseCount
, "Excessive Parse method call\n");
299 OpenSave
=OpenCount
; CloseSave
=CloseCount
; DeleteSave
=DeleteCount
;
300 ParseSave
=ParseCount
; OkayToCloseSave
=OkayToCloseCount
;
301 QueryNameSave
=QueryNameCount
;
303 // Now create an object of type 0, of the same name and expect it to fail
304 // inserting, but success creation
305 RtlInitUnicodeString(&ObName
[0], L
"\\ObtDirectory\\MyObject1");
306 InitializeObjectAttributes(&ObAttributes
[0], &ObName
[0], OBJ_OPENIF
,
309 Status
= ObCreateObject(KernelMode
, ObTypes
[0], &ObAttributes
[0], KernelMode
,
310 NULL
, (ULONG
)sizeof(MY_OBJECT1
), 0L, 0L, (PVOID
*)&ObBody1
[0]);
311 ok(Status
== STATUS_SUCCESS
,
312 "Failed to create object with status=0x%lX", Status
);
315 ok(OpenSave
== OpenCount
, "Excessive Open method call\n");
316 ok(CloseSave
== CloseCount
, "Excessive Close method call\n");
317 ok(DeleteSave
== DeleteCount
, "Excessive Delete method call\n");
318 ok(ParseSave
== ParseCount
, "Excessive Parse method call\n");
320 Status
= ObInsertObject(ObBody1
[0], NULL
, GENERIC_ALL
, 0,
321 &ObBody1
[1], &ObHandle2
[0]);
322 ok(Status
== STATUS_OBJECT_NAME_EXISTS
,
323 "Object insertion should have failed, but got 0x%lX", Status
);
324 ok(ObBody
[0] == ObBody1
[1],
325 "Object bodies doesn't match, 0x%p != 0x%p", ObBody
[0], ObBody1
[1]);
326 ok(ObHandle2
[0] != NULL
, "Bad handle returned 0x%lX", (ULONG
)ObHandle2
[0]);
328 DPRINT1("%d %d %d %d %d %d %d\n", DumpCount
, OpenCount
, // deletecount+1
329 CloseCount
, DeleteCount
, ParseCount
, OkayToCloseCount
, QueryNameCount
);
331 // check counters and then save
332 ok(OpenSave
+1 == OpenCount
, "Excessive Open method call\n");
333 ok(CloseSave
== CloseCount
, "Excessive Close method call\n");
334 ok(DeleteSave
+1 == DeleteCount
, "Delete method call mismatch\n");
335 ok(ParseSave
== ParseCount
, "Excessive Parse method call\n");
336 OpenSave
=OpenCount
; CloseSave
=CloseCount
; DeleteSave
=DeleteCount
;
337 ParseSave
=ParseCount
; OkayToCloseSave
=OkayToCloseCount
;
338 QueryNameSave
=QueryNameCount
;
341 Status
= ZwClose(ObHandle2
[0]);
342 ok(Status
== STATUS_SUCCESS
,
343 "Failed to close handle status=0x%lX", Status
);
345 // check counters and then save
346 ok(OpenSave
== OpenCount
, "Excessive Open method call\n");
347 ok(CloseSave
+1 == CloseCount
, "Close method call mismatch\n");
348 ok(DeleteSave
== DeleteCount
, "Excessive Delete method call\n");
349 ok(ParseSave
== ParseCount
, "Excessive Parse method call\n");
350 OpenSave
=OpenCount
; CloseSave
=CloseCount
; DeleteSave
=DeleteCount
;
351 ParseSave
=ParseCount
; OkayToCloseSave
=OkayToCloseCount
;
352 QueryNameSave
=QueryNameCount
;
355 // Object referenced 2 times:
357 // 2) AdditionalReferences
358 ObDereferenceObject(ObBody1
[1]);
360 //DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, // no change
361 // CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
362 ok(OpenSave
== OpenCount
, "Open method call mismatch\n");
363 ok(CloseSave
== CloseCount
, "Close method call mismatch\n");
364 ok(DeleteSave
== DeleteCount
, "Delete method call mismatch\n");
365 ok(ParseSave
== ParseCount
, "Parse method call mismatch\n");
375 //UNICODE_STRING ObPathName[NUM_OBTYPES];
377 // Close what we have opened and free what we allocated
378 ZwClose(ObHandle1
[0]);
379 ZwClose(ObHandle1
[1]);
380 ZwClose(ObHandle2
[0]);
381 ZwClose(ObHandle2
[1]);
383 // Now we have to get rid of a directory object
384 // Since it is permanent, we have to firstly make it temporary
385 // and only then kill
386 // (this procedure is described in DDK)
387 Status
= ObReferenceObjectByHandle(DirectoryHandle
, 0L, NULL
,
388 KernelMode
, &DirObject
, NULL
);
389 ok(Status
== STATUS_SUCCESS
,
390 "Failed to reference object by handle with status=0x%lX", Status
);
392 // Dereference 2 times - first for just previous referencing
393 // and 2nd time for creation of permanent object itself
394 ObDereferenceObject(DirObject
);
395 ObDereferenceObject(DirObject
);
397 Status
= ZwMakeTemporaryObject(DirectoryHandle
);
398 ok(Status
== STATUS_SUCCESS
,
399 "Failed to make temp object with status=0x%lX", Status
);
401 // Close the handle now and we are done
402 Status
= ZwClose(DirectoryHandle
);
403 ok(Status
== STATUS_SUCCESS
,
404 "Failed to close handle with status=0x%lX", Status
);
406 // Now delete the last piece - object types
407 // In fact, it's weird to get rid of object types, especially the way,
408 // how it's done in the commented section below
409 for (i
=0; i
<NUM_OBTYPES
; i
++)
410 ObDereferenceObject(ObTypes
[i
]);
412 RtlInitUnicodeString(&ObPathName[0], L"\\ObjectTypes\\MyObjectType1");
413 RtlInitUnicodeString(&ObPathName[1], L"\\ObjectTypes\\MyObjectType2");
415 for (i=0; i<NUM_OBTYPES; i++)
417 Status = ObReferenceObjectByName(&ObPathName[i],
418 OBJ_CASE_INSENSITIVE, NULL, 0L, NULL, KernelMode, NULL,
421 ObDereferenceObject(TypeObject);
422 ObDereferenceObject(TypeObject);
423 DPRINT("Reference Name %S = %p, ObTypes[%d] = %p\n",
424 ObPathName[i], TypeObject, i, ObTypes[i]);
434 UNICODE_STRING ObPathName
[NUM_OBTYPES
];
436 // Reference them by handle
437 for (i
=0; i
<NUM_OBTYPES
; i
++)
439 Status
= ObReferenceObjectByHandle(ObHandle1
[i
], 0L, ObTypes
[i
],
440 KernelMode
, &ObBody
[i
], NULL
);
441 ok(Status
== STATUS_SUCCESS
,
442 "Failed to reference object by handle, status=0x%lX", Status
);
443 DPRINT("Ref by handle %lx = %p\n", ObHandle1
[i
], ObBody
[i
]);
446 // Reference them by pointer
447 for (i
=0; i
<NUM_OBTYPES
; i
++)
449 Status
= ObReferenceObjectByPointer(ObBody
[i
], 0L, ObTypes
[i
], KernelMode
);
450 ok(Status
== STATUS_SUCCESS
,
451 "Failed to reference object by pointer, status=0x%lX", Status
);
454 // Reference them by name
455 RtlInitUnicodeString(&ObPathName
[0], L
"\\ObtDirectory\\MyObject1");
456 RtlInitUnicodeString(&ObPathName
[1], L
"\\ObtDirectory\\MyObject2");
458 for (i
=0; i
<NUM_OBTYPES
; i
++)
460 Status
= ObReferenceObjectByName(&ObPathName
[i
],
461 OBJ_CASE_INSENSITIVE
, NULL
, 0L, ObTypes
[i
], KernelMode
, NULL
,
464 DPRINT("Ref by name %wZ = %p\n", &ObPathName
[i
], ObBody
[i
]);
467 // Dereference now all of them
469 // For ObInsertObject, AdditionalReference
470 ObDereferenceObject(ObBody
[0]);
471 ObDereferenceObject(ObBody
[1]);
474 ObDereferenceObject(ObBody
[0]);
475 ObDereferenceObject(ObBody
[1]);
478 ObDereferenceObject(ObBody
[0]);
479 ObDereferenceObject(ObBody
[1]);
482 ObDereferenceObject(ObBody
[0]);
483 ObDereferenceObject(ObBody
[1]);
486 /* PUBLIC FUNCTIONS ***********************************************************/
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("NTOSKRNL Ob Manager");