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