Merge from branch ReactX to Trunk,
[reactos.git] / rostests / drivers / 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 <ddk/ntifs.h>
27 #include "kmtest.h"
28
29 //#define NDEBUG
30 #include "debug.h"
31
32 #include "ntndk.h"
33
34 // I ment to make this test scalable, but for now
35 // we work with two object types only
36 #define NUM_OBTYPES 2
37
38 typedef struct _MY_OBJECT1
39 {
40 ULONG Something1;
41 } MY_OBJECT1, *PMY_OBJECT1;
42
43 typedef struct _MY_OBJECT2
44 {
45 ULONG Something1;
46 ULONG SomeLong[10];
47 } MY_OBJECT2, *PMY_OBJECT2;
48
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;
62
63 USHORT DumpCount, OpenCount, CloseCount, DeleteCount,
64 ParseCount, OkayToCloseCount, QueryNameCount;
65
66 /* PRIVATE FUNCTIONS **********************************************************/
67
68 VOID
69 NTAPI
70 DumpProc(IN PVOID Object,
71 IN POB_DUMP_CONTROL DumpControl)
72 {
73 DbgPrint("DumpProc() called\n");
74 DumpCount++;
75 }
76
77 // Tested in Win2k3
78 VOID
79 NTAPI
80 OpenProc(IN OB_OPEN_REASON OpenReason,
81 IN PEPROCESS Process,
82 IN PVOID Object,
83 IN ACCESS_MASK GrantedAccess,
84 IN ULONG HandleCount)
85 {
86 DbgPrint("OpenProc() 0x%p, OpenReason %d, HC %d, AM 0x%X\n",
87 Object, OpenReason, HandleCount, GrantedAccess);
88 OpenCount++;
89 }
90
91 // Tested in Win2k3
92 VOID
93 NTAPI
94 CloseProc(IN PEPROCESS Process,
95 IN PVOID Object,
96 IN ACCESS_MASK GrantedAccess,
97 IN ULONG ProcessHandleCount,
98 IN ULONG SystemHandleCount)
99 {
100 DbgPrint("CloseProc() 0x%p, PHC %d, SHC %d, AM 0x%X\n", Object,
101 ProcessHandleCount, SystemHandleCount, GrantedAccess);
102 CloseCount++;
103 }
104
105 // Tested in Win2k3
106 VOID
107 NTAPI
108 DeleteProc(IN PVOID Object)
109 {
110 DbgPrint("DeleteProc() 0x%p\n", Object);
111 DeleteCount++;
112 }
113
114 NTSTATUS
115 NTAPI
116 ParseProc(IN PVOID ParseObject,
117 IN PVOID ObjectType,
118 IN OUT PACCESS_STATE AccessState,
119 IN KPROCESSOR_MODE AccessMode,
120 IN ULONG Attributes,
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,
125 OUT PVOID *Object)
126 {
127 DbgPrint("ParseProc() called\n");
128 *Object = NULL;
129
130 ParseCount++;
131 return STATUS_OBJECT_NAME_NOT_FOUND;//STATUS_SUCCESS;
132 }
133
134 // Tested in Win2k3
135 NTSTATUS
136 NTAPI
137 OkayToCloseProc(IN PEPROCESS Process OPTIONAL,
138 IN PVOID Object,
139 IN HANDLE Handle,
140 IN KPROCESSOR_MODE AccessMode)
141 {
142 DbgPrint("OkayToCloseProc() 0x%p, H 0x%p, AM 0x%X\n", Object, Handle,
143 AccessMode);
144 OkayToCloseCount++;
145 return STATUS_SUCCESS;
146 }
147
148 NTSTATUS
149 NTAPI
150 QueryNameProc(IN PVOID Object,
151 IN BOOLEAN HasObjectName,
152 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
153 IN ULONG Length,
154 OUT PULONG ReturnLength,
155 IN KPROCESSOR_MODE AccessMode)
156 {
157 DbgPrint("QueryNameProc() 0x%p, HON %d, Len %d, AM 0x%X\n",
158 Object, HasObjectName, Length, AccessMode);
159 QueryNameCount++;
160
161 ObjectNameInfo = NULL;
162 ReturnLength = 0;
163 return STATUS_OBJECT_NAME_NOT_FOUND;
164 }
165
166
167 VOID
168 ObtCreateObjectTypes()
169 {
170 USHORT i;
171 NTSTATUS Status;
172 WCHAR Name[15];
173
174 for (i=0; i<NUM_OBTYPES; i++)
175 {
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);
180
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;
187
188 // Test for invalid parameter
189 // FIXME: Make it more exact, to see which params Win2k3 checks
190 // existence of
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);
195
196 // Object procedures
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;
204
205 //ObTypeInitializer[i].QueryNameProcedure =
206 // (OB_QUERYNAME_METHOD)QueryNameProc;
207
208 //ObTypeInitializer[i].SecurityProcedure =
209 // (OB_SECURITY_METHOD)SecurityProc;
210
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);
215 }
216 }
217
218 VOID
219 ObtCreateDirectory()
220 {
221 NTSTATUS Status;
222
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);
227
228 Status = ZwCreateDirectoryObject(&DirectoryHandle, 0, &ObDirectoryAttributes);
229 ok(Status == STATUS_SUCCESS,
230 "Failed to create directory object with status=0x%lX", Status);
231 }
232
233 VOID
234 ObtCreateObjects()
235 {
236 PVOID ObBody1[2];
237 NTSTATUS Status;
238 USHORT OpenSave, CloseSave, DeleteSave, ParseSave,
239 OkayToCloseSave, QueryNameSave;
240
241 // Create two objects
242 RtlInitUnicodeString(&ObName[0], L"\\ObtDirectory\\MyObject1");
243 InitializeObjectAttributes(&ObAttributes[0], &ObName[0],
244 OBJ_CASE_INSENSITIVE, NULL, NULL);
245
246 RtlInitUnicodeString(&ObName[1], L"\\ObtDirectory\\MyObject2");
247 InitializeObjectAttributes(&ObAttributes[1], &ObName[1],
248 OBJ_CASE_INSENSITIVE, NULL, NULL);
249
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);
255
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);
261
262 // save counters
263 OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
264 ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
265 QueryNameSave=QueryNameCount;
266
267 // Insert them
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");
274
275 // check counters
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");
280
281 // save counters
282 OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
283 ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
284 QueryNameSave=QueryNameCount;
285
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");
292
293 // check counters
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");
298
299 // save counters
300 OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
301 ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
302 QueryNameSave=QueryNameCount;
303
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,
308 NULL, NULL);
309
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);
314
315 // check counters
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");
320
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)ObHandle2[0]);
328
329 DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, // deletecount+1
330 CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
331
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;
340
341 // Close its handle
342 Status = ZwClose(ObHandle2[0]);
343 ok(Status == STATUS_SUCCESS,
344 "Failed to close handle status=0x%lX", Status);
345
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;
354
355
356 // Object referenced 2 times:
357 // 1) ObInsertObject
358 // 2) AdditionalReferences
359 ObDereferenceObject(ObBody1[1]);
360
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");
367 }
368
369 VOID
370 ObtClose()
371 {
372 PVOID DirObject;
373 NTSTATUS Status;
374 //PVOID TypeObject;
375 USHORT i;
376 //UNICODE_STRING ObPathName[NUM_OBTYPES];
377
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]);
383
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);
392
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);
397
398 Status = ZwMakeTemporaryObject(DirectoryHandle);
399 ok(Status == STATUS_SUCCESS,
400 "Failed to make temp object with status=0x%lX", Status);
401
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);
406
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]);
412 /*
413 RtlInitUnicodeString(&ObPathName[0], L"\\ObjectTypes\\MyObjectType1");
414 RtlInitUnicodeString(&ObPathName[1], L"\\ObjectTypes\\MyObjectType2");
415
416 for (i=0; i<NUM_OBTYPES; i++)
417 {
418 Status = ObReferenceObjectByName(&ObPathName[i],
419 OBJ_CASE_INSENSITIVE, NULL, 0L, NULL, KernelMode, NULL,
420 &TypeObject);
421
422 ObDereferenceObject(TypeObject);
423 ObDereferenceObject(TypeObject);
424 DPRINT("Reference Name %S = %p, ObTypes[%d] = %p\n",
425 ObPathName[i], TypeObject, i, ObTypes[i]);
426 }
427 */
428 }
429
430 VOID
431 ObtReferenceTests()
432 {
433 USHORT i;
434 NTSTATUS Status;
435 UNICODE_STRING ObPathName[NUM_OBTYPES];
436
437 // Reference them by handle
438 for (i=0; i<NUM_OBTYPES; i++)
439 {
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]);
445 }
446
447 // Reference them by pointer
448 for (i=0; i<NUM_OBTYPES; i++)
449 {
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);
453 }
454
455 // Reference them by name
456 RtlInitUnicodeString(&ObPathName[0], L"\\ObtDirectory\\MyObject1");
457 RtlInitUnicodeString(&ObPathName[1], L"\\ObtDirectory\\MyObject2");
458
459 for (i=0; i<NUM_OBTYPES; i++)
460 {
461 Status = ObReferenceObjectByName(&ObPathName[i],
462 OBJ_CASE_INSENSITIVE, NULL, 0L, ObTypes[i], KernelMode, NULL,
463 &ObBody[0]);
464
465 DPRINT("Ref by name %wZ = %p\n", &ObPathName[i], ObBody[i]);
466 }
467
468 // Dereference now all of them
469
470 // For ObInsertObject, AdditionalReference
471 ObDereferenceObject(ObBody[0]);
472 ObDereferenceObject(ObBody[1]);
473
474 // For ByHandle
475 ObDereferenceObject(ObBody[0]);
476 ObDereferenceObject(ObBody[1]);
477
478 // For ByPointer
479 ObDereferenceObject(ObBody[0]);
480 ObDereferenceObject(ObBody[1]);
481
482 // For ByName
483 ObDereferenceObject(ObBody[0]);
484 ObDereferenceObject(ObBody[1]);
485 }
486
487 /* PUBLIC FUNCTIONS ***********************************************************/
488
489 VOID
490 FASTCALL
491 NtoskrnlObTest()
492 {
493 StartTest();
494
495 DumpCount = 0; OpenCount = 0; CloseCount = 0;
496 DeleteCount = 0; ParseCount = 0;
497
498 // Create object-types to use in tests
499 ObtCreateObjectTypes();
500 DPRINT("ObtCreateObjectTypes() done\n");
501
502 // Create Directory
503 ObtCreateDirectory();
504 DPRINT("ObtCreateDirectory() done\n");
505
506 // Create and insert objects
507 ObtCreateObjects();
508 DPRINT("ObtCreateObjects() done\n");
509
510 // Reference them in a variety of ways
511 //ObtReferenceTests();
512
513 // Clean up
514 // FIXME: Disable to see results of creating objects in usermode.
515 // Also it has problems with object types removal
516 ObtClose();
517 DPRINT("Cleanup done\n");
518
519 FinishTest("NTOSKRNL Ob Manager");
520 }