1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ex/handle.c
5 * PURPOSE: Generic Executive Handle Tables
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller <w3seek@reactos.com>
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 LIST_ENTRY HandleTableListHead;
19 EX_PUSH_LOCK HandleTableListLock;
20 #define SizeOfHandle(x) (sizeof(HANDLE) * (x))
21 #define INDEX_TO_HANDLE_VALUE(x) ((x) << HANDLE_TAG_BITS)
22
23 /* PRIVATE FUNCTIONS *********************************************************/
24
25 #ifdef _WIN64
26 #define strtoulptr strtoull
27 #else
28 #define strtoulptr strtoul
29 #endif
30
31 CODE_SEG("INIT")
32 VOID
33 NTAPI
ExpInitializeHandleTables(VOID)34 ExpInitializeHandleTables(VOID)
35 {
36 /* Initialize the list of handle tables and the lock */
37 InitializeListHead(&HandleTableListHead);
38 ExInitializePushLock(&HandleTableListLock);
39 }
40
41 PHANDLE_TABLE_ENTRY
42 NTAPI
ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable,IN EXHANDLE Handle)43 ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable,
44 IN EXHANDLE Handle)
45 {
46 ULONG TableLevel;
47 ULONG_PTR TableBase;
48 PHANDLE_TABLE_ENTRY HandleArray, Entry;
49 PVOID *PointerArray;
50
51 /* Clear the tag bits */
52 Handle.TagBits = 0;
53
54 /* Check if the handle is in the allocated range */
55 if (Handle.Value >= HandleTable->NextHandleNeedingPool)
56 {
57 return NULL;
58 }
59
60 /* Get the table code */
61 TableBase = HandleTable->TableCode;
62
63 /* Extract the table level and actual table base */
64 TableLevel = (ULONG)(TableBase & 3);
65 TableBase &= ~3;
66
67 PointerArray = (PVOID*)TableBase;
68 HandleArray = (PHANDLE_TABLE_ENTRY)TableBase;
69
70 /* Check what level we're running at */
71 switch (TableLevel)
72 {
73 case 2:
74
75 /* Get the mid level pointer array */
76 PointerArray = PointerArray[Handle.HighIndex];
77 ASSERT(PointerArray != NULL);
78
79 /* Fall through */
80 case 1:
81
82 /* Get the handle array */
83 HandleArray = PointerArray[Handle.MidIndex];
84 ASSERT(HandleArray != NULL);
85
86 /* Fall through */
87 case 0:
88
89 /* Get the entry using the low index */
90 Entry = &HandleArray[Handle.LowIndex];
91
92 /* All done */
93 break;
94
95 default:
96
97 ASSERT(FALSE);
98 Entry = NULL;
99 }
100
101 /* Return the handle entry */
102 return Entry;
103 }
104
105 PVOID
106 NTAPI
ExpAllocateTablePagedPool(IN PEPROCESS Process OPTIONAL,IN SIZE_T Size)107 ExpAllocateTablePagedPool(IN PEPROCESS Process OPTIONAL,
108 IN SIZE_T Size)
109 {
110 PVOID Buffer;
111 NTSTATUS Status;
112
113 /* Do the allocation */
114 Buffer = ExAllocatePoolWithTag(PagedPool, Size, TAG_OBJECT_TABLE);
115 if (Buffer)
116 {
117 /* Clear the memory */
118 RtlZeroMemory(Buffer, Size);
119
120 /* Check if we have a process to charge quota */
121 if (Process)
122 {
123 /* Charge quota */
124 Status = PsChargeProcessPagedPoolQuota(Process, Size);
125 if (!NT_SUCCESS(Status))
126 {
127 ExFreePoolWithTag(Buffer, TAG_OBJECT_TABLE);
128 return NULL;
129 }
130 }
131 }
132
133 /* Return the allocated memory */
134 return Buffer;
135 }
136
137 PVOID
138 NTAPI
ExpAllocateTablePagedPoolNoZero(IN PEPROCESS Process OPTIONAL,IN SIZE_T Size)139 ExpAllocateTablePagedPoolNoZero(IN PEPROCESS Process OPTIONAL,
140 IN SIZE_T Size)
141 {
142 PVOID Buffer;
143 NTSTATUS Status;
144
145 /* Do the allocation */
146 Buffer = ExAllocatePoolWithTag(PagedPool, Size, TAG_OBJECT_TABLE);
147 if (Buffer)
148 {
149 /* Check if we have a process to charge quota */
150 if (Process)
151 {
152 /* Charge quota */
153 Status = PsChargeProcessPagedPoolQuota(Process, Size);
154 if (!NT_SUCCESS(Status))
155 {
156 ExFreePoolWithTag(Buffer, TAG_OBJECT_TABLE);
157 return NULL;
158 }
159 }
160 }
161
162 /* Return the allocated memory */
163 return Buffer;
164 }
165
166 VOID
167 NTAPI
ExpFreeTablePagedPool(IN PEPROCESS Process OPTIONAL,IN PVOID Buffer,IN SIZE_T Size)168 ExpFreeTablePagedPool(IN PEPROCESS Process OPTIONAL,
169 IN PVOID Buffer,
170 IN SIZE_T Size)
171 {
172 /* Free the buffer */
173 ExFreePoolWithTag(Buffer, TAG_OBJECT_TABLE);
174 if (Process)
175 {
176 /* Release quota */
177 PsReturnProcessPagedPoolQuota(Process, Size);
178 }
179 }
180
181 VOID
182 NTAPI
ExpFreeLowLevelTable(IN PEPROCESS Process,IN PHANDLE_TABLE_ENTRY TableEntry)183 ExpFreeLowLevelTable(IN PEPROCESS Process,
184 IN PHANDLE_TABLE_ENTRY TableEntry)
185 {
186 /* Check if we have an entry */
187 if (TableEntry[0].Object)
188 {
189 /* Free the entry */
190 ExpFreeTablePagedPool(Process,
191 TableEntry[0].Object,
192 LOW_LEVEL_ENTRIES *
193 sizeof(HANDLE_TABLE_ENTRY_INFO));
194 }
195
196 /* Free the table */
197 ExpFreeTablePagedPool(Process, TableEntry, PAGE_SIZE);
198 }
199
200 VOID
201 NTAPI
ExpFreeHandleTable(IN PHANDLE_TABLE HandleTable)202 ExpFreeHandleTable(IN PHANDLE_TABLE HandleTable)
203 {
204 PEPROCESS Process = HandleTable->QuotaProcess;
205 ULONG i, j;
206 ULONG_PTR TableCode = HandleTable->TableCode;
207 ULONG_PTR TableBase = TableCode & ~3;
208 ULONG TableLevel = (ULONG)(TableCode & 3);
209 PHANDLE_TABLE_ENTRY Level1, *Level2, **Level3;
210 PAGED_CODE();
211
212 /* Check which level we're at */
213 if (TableLevel == 0)
214 {
215 /* Select the first level table base and just free it */
216 Level1 = (PVOID)TableBase;
217 ExpFreeLowLevelTable(Process, Level1);
218 }
219 else if (TableLevel == 1)
220 {
221 /* Select the second level table base */
222 Level2 = (PVOID)TableBase;
223
224 /* Loop each mid level entry */
225 for (i = 0; i < MID_LEVEL_ENTRIES; i++)
226 {
227 /* Leave if we've reached the last entry */
228 if (!Level2[i]) break;
229
230 /* Free the second level table */
231 ExpFreeLowLevelTable(Process, Level2[i]);
232 }
233
234 /* Free the second level table */
235 ExpFreeTablePagedPool(Process, Level2, PAGE_SIZE);
236 }
237 else
238 {
239 /* Select the third level table base */
240 Level3 = (PVOID)TableBase;
241
242 /* Loop each high level entry */
243 for (i = 0; i < HIGH_LEVEL_ENTRIES; i++)
244 {
245 /* Leave if we've reached the last entry */
246 if (!Level3[i]) break;
247
248 /* Loop each mid level entry */
249 for (j = 0; j < MID_LEVEL_ENTRIES; j++)
250 {
251 /* Leave if we've reached the last entry */
252 if (!Level3[i][j]) break;
253
254 /* Free the second level table */
255 ExpFreeLowLevelTable(Process, Level3[i][j]);
256 }
257
258 /* Free the third level table entry */
259 ExpFreeTablePagedPool(Process, Level3[i], PAGE_SIZE);
260 }
261
262 /* Free the third level table */
263 ExpFreeTablePagedPool(Process,
264 Level3,
265 SizeOfHandle(HIGH_LEVEL_ENTRIES));
266 }
267
268 /* Free the actual table and check if we need to release quota */
269 ExFreePoolWithTag(HandleTable, TAG_OBJECT_TABLE);
270 if (Process)
271 {
272 /* Release the quota it was taking up */
273 PsReturnProcessPagedPoolQuota(Process, sizeof(HANDLE_TABLE));
274 }
275 }
276
277 VOID
278 NTAPI
ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable,IN EXHANDLE Handle,IN PHANDLE_TABLE_ENTRY HandleTableEntry)279 ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable,
280 IN EXHANDLE Handle,
281 IN PHANDLE_TABLE_ENTRY HandleTableEntry)
282 {
283 ULONG OldValue, *Free;
284 ULONG LockIndex;
285 PAGED_CODE();
286
287 /* Sanity checks */
288 ASSERT(HandleTableEntry->Object == NULL);
289 ASSERT(HandleTableEntry == ExpLookupHandleTableEntry(HandleTable, Handle));
290
291 /* Decrement the handle count */
292 InterlockedDecrement(&HandleTable->HandleCount);
293
294 /* Mark the handle as free */
295 Handle.TagBits = 0;
296
297 /* Check if we're FIFO */
298 if (!HandleTable->StrictFIFO)
299 {
300 /* Select a lock index */
301 LockIndex = Handle.Index % 4;
302
303 /* Select which entry to use */
304 Free = (HandleTable->HandleTableLock[LockIndex].Locked) ?
305 &HandleTable->FirstFree : &HandleTable->LastFree;
306 }
307 else
308 {
309 /* No need to worry about locking, take the last entry */
310 Free = &HandleTable->LastFree;
311 }
312
313 /* Start value change loop */
314 for (;;)
315 {
316 /* Get the current value and write */
317 OldValue = *Free;
318 HandleTableEntry->NextFreeTableEntry = OldValue;
319 if (InterlockedCompareExchange((PLONG)Free, Handle.AsULONG, OldValue) == OldValue)
320 {
321 /* Break out, we're done. Make sure the handle value makes sense */
322 ASSERT((OldValue & FREE_HANDLE_MASK) <
323 HandleTable->NextHandleNeedingPool);
324 break;
325 }
326 }
327 }
328
329 PHANDLE_TABLE
330 NTAPI
ExpAllocateHandleTable(IN PEPROCESS Process OPTIONAL,IN BOOLEAN NewTable)331 ExpAllocateHandleTable(IN PEPROCESS Process OPTIONAL,
332 IN BOOLEAN NewTable)
333 {
334 PHANDLE_TABLE HandleTable;
335 PHANDLE_TABLE_ENTRY HandleTableTable, HandleEntry;
336 ULONG i;
337 NTSTATUS Status;
338 PAGED_CODE();
339
340 /* Allocate the table */
341 HandleTable = ExAllocatePoolWithTag(PagedPool,
342 sizeof(HANDLE_TABLE),
343 TAG_OBJECT_TABLE);
344 if (!HandleTable) return NULL;
345
346 /* Check if we have a process */
347 if (Process)
348 {
349 /* Charge quota */
350 Status = PsChargeProcessPagedPoolQuota(Process, sizeof(HANDLE_TABLE));
351 if (!NT_SUCCESS(Status))
352 {
353 ExFreePoolWithTag(HandleTable, TAG_OBJECT_TABLE);
354 return NULL;
355 }
356 }
357
358 /* Clear the table */
359 RtlZeroMemory(HandleTable, sizeof(HANDLE_TABLE));
360
361 /* Now allocate the first level structures */
362 HandleTableTable = ExpAllocateTablePagedPoolNoZero(Process, PAGE_SIZE);
363 if (!HandleTableTable)
364 {
365 /* Failed, free the table */
366 ExFreePoolWithTag(HandleTable, TAG_OBJECT_TABLE);
367
368 /* Return the quota it was taking up */
369 if (Process)
370 {
371 PsReturnProcessPagedPoolQuota(Process, sizeof(HANDLE_TABLE));
372 }
373
374 return NULL;
375 }
376
377 /* Write the pointer to our first level structures */
378 HandleTable->TableCode = (ULONG_PTR)HandleTableTable;
379
380 /* Initialize the first entry */
381 HandleEntry = &HandleTableTable[0];
382 HandleEntry->NextFreeTableEntry = -2;
383 HandleEntry->Value = 0;
384
385 /* Check if this is a new table */
386 if (NewTable)
387 {
388 /* Go past the root entry */
389 HandleEntry++;
390
391 /* Loop every low level entry */
392 for (i = 1; i < (LOW_LEVEL_ENTRIES - 1); i++)
393 {
394 /* Set up the free data */
395 HandleEntry->Value = 0;
396 HandleEntry->NextFreeTableEntry = INDEX_TO_HANDLE_VALUE(i + 1);
397
398 /* Move to the next entry */
399 HandleEntry++;
400 }
401
402 /* Terminate the last entry */
403 HandleEntry->Value = 0;
404 HandleEntry->NextFreeTableEntry = 0;
405 HandleTable->FirstFree = INDEX_TO_HANDLE_VALUE(1);
406 }
407
408 /* Set the next handle needing pool after our allocated page from above */
409 HandleTable->NextHandleNeedingPool = INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES);
410
411 /* Setup the rest of the handle table data */
412 HandleTable->QuotaProcess = Process;
413 HandleTable->UniqueProcessId = PsGetCurrentProcess()->UniqueProcessId;
414 HandleTable->Flags = 0;
415
416 /* Loop all the handle table locks */
417 for (i = 0; i < 4; i++)
418 {
419 /* Initialize the handle table lock */
420 ExInitializePushLock(&HandleTable->HandleTableLock[i]);
421 }
422
423 /* Initialize the contention event lock and return the lock */
424 ExInitializePushLock(&HandleTable->HandleContentionEvent);
425 return HandleTable;
426 }
427
428 PHANDLE_TABLE_ENTRY
429 NTAPI
ExpAllocateLowLevelTable(IN PHANDLE_TABLE HandleTable,IN BOOLEAN DoInit)430 ExpAllocateLowLevelTable(IN PHANDLE_TABLE HandleTable,
431 IN BOOLEAN DoInit)
432 {
433 ULONG i, Base;
434 PHANDLE_TABLE_ENTRY Low, HandleEntry;
435
436 /* Allocate the low level table */
437 Low = ExpAllocateTablePagedPoolNoZero(HandleTable->QuotaProcess,
438 PAGE_SIZE);
439 if (!Low) return NULL;
440
441 /* Setup the initial entry */
442 HandleEntry = &Low[0];
443 HandleEntry->NextFreeTableEntry = -2;
444 HandleEntry->Value = 0;
445
446 /* Check if we're initializing */
447 if (DoInit)
448 {
449 /* Go to the next entry and the base entry */
450 HandleEntry++;
451 Base = HandleTable->NextHandleNeedingPool + INDEX_TO_HANDLE_VALUE(2);
452
453 /* Loop each entry */
454 for (i = Base;
455 i < Base + INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES - 2);
456 i += INDEX_TO_HANDLE_VALUE(1))
457 {
458 /* Free this entry and move on to the next one */
459 HandleEntry->NextFreeTableEntry = i;
460 HandleEntry->Value = 0;
461 HandleEntry++;
462 }
463
464 /* Terminate the last entry */
465 HandleEntry->NextFreeTableEntry = 0;
466 HandleEntry->Value = 0;
467 }
468
469 /* Return the low level table */
470 return Low;
471 }
472
473 PHANDLE_TABLE_ENTRY*
474 NTAPI
ExpAllocateMidLevelTable(IN PHANDLE_TABLE HandleTable,IN BOOLEAN DoInit,OUT PHANDLE_TABLE_ENTRY * LowTableEntry)475 ExpAllocateMidLevelTable(IN PHANDLE_TABLE HandleTable,
476 IN BOOLEAN DoInit,
477 OUT PHANDLE_TABLE_ENTRY *LowTableEntry)
478 {
479 PHANDLE_TABLE_ENTRY *Mid, Low;
480
481 /* Allocate the mid level table */
482 Mid = ExpAllocateTablePagedPool(HandleTable->QuotaProcess, PAGE_SIZE);
483 if (!Mid) return NULL;
484
485 /* Allocate a new low level for it */
486 Low = ExpAllocateLowLevelTable(HandleTable, DoInit);
487 if (!Low)
488 {
489 /* We failed, free the mid table */
490 ExpFreeTablePagedPool(HandleTable->QuotaProcess, Mid, PAGE_SIZE);
491 return NULL;
492 }
493
494 /* Link the tables and return the pointer */
495 Mid[0] = Low;
496 *LowTableEntry = Low;
497 return Mid;
498 }
499
500 BOOLEAN
501 NTAPI
ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable,IN BOOLEAN DoInit)502 ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable,
503 IN BOOLEAN DoInit)
504 {
505 ULONG i, j, Index;
506 PHANDLE_TABLE_ENTRY Low = NULL, *Mid, **High, *SecondLevel, **ThirdLevel;
507 ULONG NewFree, FirstFree;
508 PVOID Value;
509 ULONG_PTR TableCode = HandleTable->TableCode;
510 ULONG_PTR TableBase = TableCode & ~3;
511 ULONG TableLevel = (ULONG)(TableCode & 3);
512 PAGED_CODE();
513
514 /* Check how many levels we already have */
515 if (TableLevel == 0)
516 {
517 /* Allocate a mid level, since we only have a low level */
518 Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low);
519 if (!Mid) return FALSE;
520
521 /* Link up the tables */
522 Mid[1] = Mid[0];
523 Mid[0] = (PVOID)TableBase;
524
525 /* Write the new level and attempt to change the table code */
526 TableBase = ((ULONG_PTR)Mid) | 1;
527 Value = InterlockedExchangePointer((PVOID*)&HandleTable->TableCode, (PVOID)TableBase);
528 }
529 else if (TableLevel == 1)
530 {
531 /* Setup the 2nd level table */
532 SecondLevel = (PVOID)TableBase;
533
534 /* Get if the next index can fit in the table */
535 i = HandleTable->NextHandleNeedingPool /
536 INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES);
537 if (i < MID_LEVEL_ENTRIES)
538 {
539 /* We need to allocate a new table */
540 Low = ExpAllocateLowLevelTable(HandleTable, DoInit);
541 if (!Low) return FALSE;
542
543 /* Update the table */
544 Value = InterlockedExchangePointer((PVOID*)&SecondLevel[i], Low);
545 ASSERT(Value == NULL);
546 }
547 else
548 {
549 /* We need a new high level table */
550 High = ExpAllocateTablePagedPool(HandleTable->QuotaProcess,
551 SizeOfHandle(HIGH_LEVEL_ENTRIES));
552 if (!High) return FALSE;
553
554 /* Allocate a new mid level table as well */
555 Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low);
556 if (!Mid)
557 {
558 /* We failed, free the high level table as well */
559 ExpFreeTablePagedPool(HandleTable->QuotaProcess,
560 High,
561 SizeOfHandle(HIGH_LEVEL_ENTRIES));
562 return FALSE;
563 }
564
565 /* Link up the tables */
566 High[0] = (PVOID)TableBase;
567 High[1] = Mid;
568
569 /* Write the new table and change the table code */
570 TableBase = ((ULONG_PTR)High) | 2;
571 Value = InterlockedExchangePointer((PVOID*)&HandleTable->TableCode,
572 (PVOID)TableBase);
573 }
574 }
575 else if (TableLevel == 2)
576 {
577 /* Setup the 3rd level table */
578 ThirdLevel = (PVOID)TableBase;
579
580 /* Get the index and check if it can fit */
581 i = HandleTable->NextHandleNeedingPool / INDEX_TO_HANDLE_VALUE(MAX_MID_INDEX);
582 if (i >= HIGH_LEVEL_ENTRIES) return FALSE;
583
584 /* Check if there's no mid-level table */
585 if (!ThirdLevel[i])
586 {
587 /* Allocate a new mid level table */
588 Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low);
589 if (!Mid) return FALSE;
590
591 /* Update the table pointer */
592 Value = InterlockedExchangePointer((PVOID*)&ThirdLevel[i], Mid);
593 ASSERT(Value == NULL);
594 }
595 else
596 {
597 /* We have one, check at which index we should insert our entry */
598 Index = (HandleTable->NextHandleNeedingPool / INDEX_TO_HANDLE_VALUE(1)) -
599 i * MAX_MID_INDEX;
600 j = Index / LOW_LEVEL_ENTRIES;
601
602 /* Allocate a new low level */
603 Low = ExpAllocateLowLevelTable(HandleTable, DoInit);
604 if (!Low) return FALSE;
605
606 /* Update the table pointer */
607 Value = InterlockedExchangePointer((PVOID*)&ThirdLevel[i][j], Low);
608 ASSERT(Value == NULL);
609 }
610 }
611 else
612 {
613 /* Something is really broken */
614 ASSERT(FALSE);
615 }
616
617 /* Update the index of the next handle */
618 Index = InterlockedExchangeAdd((PLONG) &HandleTable->NextHandleNeedingPool,
619 INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES));
620
621 /* Check if need to initialize the table */
622 if (DoInit)
623 {
624 /* Create a new index number */
625 Index += INDEX_TO_HANDLE_VALUE(1);
626
627 /* Start free index change loop */
628 for (;;)
629 {
630 /* Setup the first free index */
631 FirstFree = HandleTable->FirstFree;
632 Low[LOW_LEVEL_ENTRIES - 1].NextFreeTableEntry = FirstFree;
633
634 /* Change the index */
635 NewFree = InterlockedCompareExchange((PLONG) &HandleTable->FirstFree,
636 Index,
637 FirstFree);
638 if (NewFree == FirstFree) break;
639 }
640 }
641
642 /* All done */
643 return TRUE;
644 }
645
646 ULONG
647 NTAPI
ExpMoveFreeHandles(IN PHANDLE_TABLE HandleTable)648 ExpMoveFreeHandles(IN PHANDLE_TABLE HandleTable)
649 {
650 ULONG LastFree, i;
651
652 /* Clear the last free index */
653 LastFree = InterlockedExchange((PLONG) &HandleTable->LastFree, 0);
654
655 /* Check if we had no index */
656 if (!LastFree) return LastFree;
657
658 /* Acquire the locks we need */
659 for (i = 1; i < 4; i++)
660 {
661 /* Acquire this lock exclusively */
662 ExWaitOnPushLock(&HandleTable->HandleTableLock[i]);
663 }
664
665 /* Check if we're not strict FIFO */
666 if (!HandleTable->StrictFIFO)
667 {
668 /* Update the first free index */
669 if (!InterlockedCompareExchange((PLONG) &HandleTable->FirstFree, LastFree, 0))
670 {
671 /* We're done, exit */
672 return LastFree;
673 }
674 }
675
676 /* We are strict FIFO, we need to reverse the entries */
677 ASSERT(FALSE);
678 return LastFree;
679 }
680
681 PHANDLE_TABLE_ENTRY
682 NTAPI
ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable,OUT PEXHANDLE NewHandle)683 ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable,
684 OUT PEXHANDLE NewHandle)
685 {
686 ULONG OldValue, NewValue, NewValue1;
687 PHANDLE_TABLE_ENTRY Entry;
688 EXHANDLE Handle, OldHandle;
689 BOOLEAN Result;
690 ULONG i;
691
692 /* Start allocation loop */
693 for (;;)
694 {
695 /* Get the current link */
696 OldValue = HandleTable->FirstFree;
697 while (!OldValue)
698 {
699 /* No free entries remain, lock the handle table */
700 KeEnterCriticalRegion();
701 ExAcquirePushLockExclusive(&HandleTable->HandleTableLock[0]);
702
703 /* Check the value again */
704 OldValue = HandleTable->FirstFree;
705 if (OldValue)
706 {
707 /* Another thread has already created a new level, bail out */
708 ExReleasePushLockExclusive(&HandleTable->HandleTableLock[0]);
709 KeLeaveCriticalRegion();
710 break;
711 }
712
713 /* Now move any free handles */
714 OldValue = ExpMoveFreeHandles(HandleTable);
715 if (OldValue)
716 {
717 /* Another thread has already moved them, bail out */
718 ExReleasePushLockExclusive(&HandleTable->HandleTableLock[0]);
719 KeLeaveCriticalRegion();
720 break;
721 }
722
723 /* We're the first one through, so do the actual allocation */
724 Result = ExpAllocateHandleTableEntrySlow(HandleTable, TRUE);
725
726 /* Unlock the table and get the value now */
727 ExReleasePushLockExclusive(&HandleTable->HandleTableLock[0]);
728 KeLeaveCriticalRegion();
729 OldValue = HandleTable->FirstFree;
730
731 /* Check if allocation failed */
732 if (!Result)
733 {
734 /* Check if nobody else went through here */
735 if (!OldValue)
736 {
737 /* We're still the only thread around, so fail */
738 NewHandle->GenericHandleOverlay = NULL;
739 return NULL;
740 }
741 }
742 }
743
744 /* We made it, write the current value */
745 Handle.Value = (OldValue & FREE_HANDLE_MASK);
746
747 /* Lookup the entry for this handle */
748 Entry = ExpLookupHandleTableEntry(HandleTable, Handle);
749
750 /* Get an available lock and acquire it */
751 OldHandle.Value = OldValue;
752 i = OldHandle.Index % 4;
753 KeEnterCriticalRegion();
754 ExAcquirePushLockShared(&HandleTable->HandleTableLock[i]);
755
756 /* Check if the value changed after acquiring the lock */
757 if (OldValue != *(volatile ULONG*)&HandleTable->FirstFree)
758 {
759 /* It did, so try again */
760 ExReleasePushLockShared(&HandleTable->HandleTableLock[i]);
761 KeLeaveCriticalRegion();
762 continue;
763 }
764
765 /* Now get the next value and do the compare */
766 NewValue = *(volatile ULONG*)&Entry->NextFreeTableEntry;
767 NewValue1 = InterlockedCompareExchange((PLONG) &HandleTable->FirstFree,
768 NewValue,
769 OldValue);
770
771 /* The change was done, so release the lock */
772 ExReleasePushLockShared(&HandleTable->HandleTableLock[i]);
773 KeLeaveCriticalRegion();
774
775 /* Check if the compare was successful */
776 if (NewValue1 == OldValue)
777 {
778 /* Make sure that the new handle is in range, and break out */
779 ASSERT((NewValue & FREE_HANDLE_MASK) <
780 HandleTable->NextHandleNeedingPool);
781 break;
782 }
783 else
784 {
785 /* The compare failed, make sure we expected it */
786 ASSERT((NewValue1 & FREE_HANDLE_MASK) !=
787 (OldValue & FREE_HANDLE_MASK));
788 }
789 }
790
791 /* Increase the number of handles */
792 InterlockedIncrement(&HandleTable->HandleCount);
793
794 /* Return the handle and the entry */
795 *NewHandle = Handle;
796 return Entry;
797 }
798
799 PHANDLE_TABLE
800 NTAPI
ExCreateHandleTable(IN PEPROCESS Process OPTIONAL)801 ExCreateHandleTable(IN PEPROCESS Process OPTIONAL)
802 {
803 PHANDLE_TABLE HandleTable;
804 PAGED_CODE();
805
806 /* Allocate the handle table */
807 HandleTable = ExpAllocateHandleTable(Process, TRUE);
808 if (!HandleTable) return NULL;
809
810 /* Acquire the handle table lock */
811 KeEnterCriticalRegion();
812 ExAcquirePushLockExclusive(&HandleTableListLock);
813
814 /* Insert it into the list */
815 InsertTailList(&HandleTableListHead, &HandleTable->HandleTableList);
816
817 /* Release the lock */
818 ExReleasePushLockExclusive(&HandleTableListLock);
819 KeLeaveCriticalRegion();
820
821 /* Return the handle table */
822 return HandleTable;
823 }
824
825 HANDLE
826 NTAPI
ExCreateHandle(IN PHANDLE_TABLE HandleTable,IN PHANDLE_TABLE_ENTRY HandleTableEntry)827 ExCreateHandle(IN PHANDLE_TABLE HandleTable,
828 IN PHANDLE_TABLE_ENTRY HandleTableEntry)
829 {
830 EXHANDLE Handle;
831 PHANDLE_TABLE_ENTRY NewEntry;
832 PAGED_CODE();
833
834 /* Start with a clean handle */
835 Handle.GenericHandleOverlay = NULL;
836
837 /* Allocate a new entry */
838 NewEntry = ExpAllocateHandleTableEntry(HandleTable, &Handle);
839 if (NewEntry)
840 {
841 /* Enter a critical region */
842 KeEnterCriticalRegion();
843
844 /* Write the entry */
845 *NewEntry = *HandleTableEntry;
846
847 /* Unlock it and leave the critical region */
848 ExUnlockHandleTableEntry(HandleTable, NewEntry);
849 KeLeaveCriticalRegion();
850 }
851
852 /* Return the handle value */
853 return Handle.GenericHandleOverlay;
854 }
855
856 VOID
857 NTAPI
ExpBlockOnLockedHandleEntry(IN PHANDLE_TABLE HandleTable,IN PHANDLE_TABLE_ENTRY HandleTableEntry)858 ExpBlockOnLockedHandleEntry(IN PHANDLE_TABLE HandleTable,
859 IN PHANDLE_TABLE_ENTRY HandleTableEntry)
860 {
861 LONG_PTR OldValue;
862 EX_PUSH_LOCK_WAIT_BLOCK WaitBlock;
863
864 /* Block on the pushlock */
865 ExBlockPushLock(&HandleTable->HandleContentionEvent, &WaitBlock);
866
867 /* Get the current value and check if it's been unlocked */
868 OldValue = HandleTableEntry->Value;
869 if (!(OldValue) || (OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT))
870 {
871 /* Unblock the pushlock and return */
872 ExfUnblockPushLock(&HandleTable->HandleContentionEvent, &WaitBlock);
873 }
874 else
875 {
876 /* Wait for it to be unblocked */
877 ExWaitForUnblockPushLock(&HandleTable->HandleContentionEvent,
878 &WaitBlock);
879 }
880 }
881
882 BOOLEAN
883 NTAPI
ExpLockHandleTableEntry(IN PHANDLE_TABLE HandleTable,IN PHANDLE_TABLE_ENTRY HandleTableEntry)884 ExpLockHandleTableEntry(IN PHANDLE_TABLE HandleTable,
885 IN PHANDLE_TABLE_ENTRY HandleTableEntry)
886 {
887 LONG_PTR NewValue, OldValue;
888
889 /* Sanity check */
890 ASSERT((KeGetCurrentThread()->CombinedApcDisable != 0) ||
891 (KeGetCurrentIrql() == APC_LEVEL));
892
893 /* Start lock loop */
894 for (;;)
895 {
896 /* Get the current value and check if it's locked */
897 OldValue = *(volatile LONG_PTR *)&HandleTableEntry->Object;
898 if (OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT)
899 {
900 /* It's not locked, remove the lock bit to lock it */
901 NewValue = OldValue & ~EXHANDLE_TABLE_ENTRY_LOCK_BIT;
902 if (InterlockedCompareExchangePointer(&HandleTableEntry->Object,
903 (PVOID)NewValue,
904 (PVOID)OldValue) == (PVOID)OldValue)
905 {
906 /* We locked it, get out */
907 return TRUE;
908 }
909 }
910 else
911 {
912 /* We couldn't lock it, bail out if it's been freed */
913 if (!OldValue) return FALSE;
914 }
915
916 /* It's locked, wait for it to be unlocked */
917 ExpBlockOnLockedHandleEntry(HandleTable, HandleTableEntry);
918 }
919 }
920
921 VOID
922 NTAPI
ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable,IN PHANDLE_TABLE_ENTRY HandleTableEntry)923 ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable,
924 IN PHANDLE_TABLE_ENTRY HandleTableEntry)
925 {
926 LONG_PTR OldValue;
927 PAGED_CODE();
928
929 /* Sanity check */
930 ASSERT((KeGetCurrentThread()->CombinedApcDisable != 0) ||
931 (KeGetCurrentIrql() == APC_LEVEL));
932
933 /* Set the lock bit and make sure it wasn't earlier */
934 OldValue = InterlockedOr((PLONG) &HandleTableEntry->Value,
935 EXHANDLE_TABLE_ENTRY_LOCK_BIT);
936 ASSERT((OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT) == 0);
937
938 /* Unblock any waiters */
939 ExfUnblockPushLock(&HandleTable->HandleContentionEvent, NULL);
940 }
941
942 VOID
943 NTAPI
ExRemoveHandleTable(IN PHANDLE_TABLE HandleTable)944 ExRemoveHandleTable(IN PHANDLE_TABLE HandleTable)
945 {
946 PAGED_CODE();
947
948 /* Acquire the table lock */
949 KeEnterCriticalRegion();
950 ExAcquirePushLockExclusive(&HandleTableListLock);
951
952 /* Remove the table and reset the list */
953 RemoveEntryList(&HandleTable->HandleTableList);
954 InitializeListHead(&HandleTable->HandleTableList);
955
956 /* Release the lock */
957 ExReleasePushLockExclusive(&HandleTableListLock);
958 KeLeaveCriticalRegion();
959 }
960
961 VOID
962 NTAPI
ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable,IN PVOID DestroyHandleProcedure OPTIONAL)963 ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable,
964 IN PVOID DestroyHandleProcedure OPTIONAL)
965 {
966 PAGED_CODE();
967
968 /* Remove the handle from the list */
969 ExRemoveHandleTable(HandleTable);
970
971 /* Check if we have a destroy callback */
972 if (DestroyHandleProcedure)
973 {
974 /* FIXME: */
975 ASSERT(FALSE);
976 }
977
978 /* Free the handle table */
979 ExpFreeHandleTable(HandleTable);
980 }
981
982 BOOLEAN
983 NTAPI
ExDestroyHandle(IN PHANDLE_TABLE HandleTable,IN HANDLE Handle,IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL)984 ExDestroyHandle(IN PHANDLE_TABLE HandleTable,
985 IN HANDLE Handle,
986 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL)
987 {
988 EXHANDLE ExHandle;
989 PVOID Object;
990 PAGED_CODE();
991
992 /* Setup the actual handle value */
993 ExHandle.GenericHandleOverlay = Handle;
994
995 /* Enter a critical region and check if we have to lookup the handle */
996 KeEnterCriticalRegion();
997 if (!HandleTableEntry)
998 {
999 /* Lookup the entry */
1000 HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle);
1001
1002 /* Make sure that we found an entry, and that it's valid */
1003 if (!(HandleTableEntry) ||
1004 !(HandleTableEntry->Object) ||
1005 (HandleTableEntry->NextFreeTableEntry == -2))
1006 {
1007 /* Invalid handle, fail */
1008 KeLeaveCriticalRegion();
1009 return FALSE;
1010 }
1011
1012 /* Lock the entry */
1013 if (!ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
1014 {
1015 /* Couldn't lock, fail */
1016 KeLeaveCriticalRegion();
1017 return FALSE;
1018 }
1019 }
1020 else
1021 {
1022 /* Make sure the handle is locked */
1023 ASSERT((HandleTableEntry->Value & EXHANDLE_TABLE_ENTRY_LOCK_BIT) == 0);
1024 }
1025
1026 /* Clear the handle */
1027 Object = InterlockedExchangePointer((PVOID*)&HandleTableEntry->Object, NULL);
1028
1029 /* Sanity checks */
1030 ASSERT(Object != NULL);
1031 ASSERT((((ULONG_PTR)Object) & EXHANDLE_TABLE_ENTRY_LOCK_BIT) == 0);
1032
1033 /* Unblock the pushlock */
1034 ExfUnblockPushLock(&HandleTable->HandleContentionEvent, NULL);
1035
1036 /* Free the actual entry */
1037 ExpFreeHandleTableEntry(HandleTable, ExHandle, HandleTableEntry);
1038
1039 /* If we got here, return success */
1040 KeLeaveCriticalRegion();
1041 return TRUE;
1042 }
1043
1044 PHANDLE_TABLE_ENTRY
1045 NTAPI
ExMapHandleToPointer(IN PHANDLE_TABLE HandleTable,IN HANDLE Handle)1046 ExMapHandleToPointer(IN PHANDLE_TABLE HandleTable,
1047 IN HANDLE Handle)
1048 {
1049 EXHANDLE ExHandle;
1050 PHANDLE_TABLE_ENTRY HandleTableEntry;
1051 PAGED_CODE();
1052
1053 /* Set the handle value */
1054 ExHandle.GenericHandleOverlay = Handle;
1055
1056 /* Fail if we got an invalid index */
1057 if (!(ExHandle.Index & (LOW_LEVEL_ENTRIES - 1))) return NULL;
1058
1059 /* Do the lookup */
1060 HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle);
1061 if (!HandleTableEntry) return NULL;
1062
1063 /* Lock it */
1064 if (!ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) return NULL;
1065
1066 /* Return the entry */
1067 return HandleTableEntry;
1068 }
1069
1070 PHANDLE_TABLE
1071 NTAPI
ExDupHandleTable(IN PEPROCESS Process,IN PHANDLE_TABLE HandleTable,IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure,IN ULONG_PTR Mask)1072 ExDupHandleTable(IN PEPROCESS Process,
1073 IN PHANDLE_TABLE HandleTable,
1074 IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure,
1075 IN ULONG_PTR Mask)
1076 {
1077 PHANDLE_TABLE NewTable;
1078 EXHANDLE Handle;
1079 PHANDLE_TABLE_ENTRY HandleTableEntry, NewEntry;
1080 BOOLEAN Failed = FALSE;
1081 PAGED_CODE();
1082
1083 /* Allocate the duplicated copy */
1084 NewTable = ExpAllocateHandleTable(Process, FALSE);
1085 if (!NewTable) return NULL;
1086
1087 /* Loop each entry */
1088 while (NewTable->NextHandleNeedingPool <
1089 HandleTable->NextHandleNeedingPool)
1090 {
1091 /* Insert it into the duplicated copy */
1092 if (!ExpAllocateHandleTableEntrySlow(NewTable, FALSE))
1093 {
1094 /* Insert failed, free the new copy and return */
1095 ExpFreeHandleTable(NewTable);
1096 return NULL;
1097 }
1098 }
1099
1100 /* Setup the initial handle table data */
1101 NewTable->HandleCount = 0;
1102 NewTable->ExtraInfoPages = 0;
1103 NewTable->FirstFree = 0;
1104
1105 /* Setup the first handle value */
1106 Handle.Value = INDEX_TO_HANDLE_VALUE(1);
1107
1108 /* Enter a critical region and lookup the new entry */
1109 KeEnterCriticalRegion();
1110 while ((NewEntry = ExpLookupHandleTableEntry(NewTable, Handle)))
1111 {
1112 /* Lookup the old entry */
1113 HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle);
1114
1115 /* Loop each entry */
1116 do
1117 {
1118 /* Check if it doesn't match the audit mask */
1119 if (!(HandleTableEntry->Value & Mask))
1120 {
1121 /* Free it since we won't use it */
1122 Failed = TRUE;
1123 }
1124 else
1125 {
1126 /* Lock the entry */
1127 if (!ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
1128 {
1129 /* Free it since we can't lock it, so we won't use it */
1130 Failed = TRUE;
1131 }
1132 else
1133 {
1134 /* Copy the handle value */
1135 *NewEntry = *HandleTableEntry;
1136
1137 /* Call the duplicate callback */
1138 if (DupHandleProcedure(Process,
1139 HandleTable,
1140 HandleTableEntry,
1141 NewEntry))
1142 {
1143 /* Clear failure flag */
1144 Failed = FALSE;
1145
1146 /* Lock the entry, increase the handle count */
1147 NewEntry->Value |= EXHANDLE_TABLE_ENTRY_LOCK_BIT;
1148 NewTable->HandleCount++;
1149 }
1150 else
1151 {
1152 /* Duplication callback refused, fail */
1153 Failed = TRUE;
1154 }
1155 }
1156 }
1157
1158 /* Check if we failed earlier and need to free */
1159 if (Failed)
1160 {
1161 /* Free this entry */
1162 NewEntry->Object = NULL;
1163 NewEntry->NextFreeTableEntry = NewTable->FirstFree;
1164 NewTable->FirstFree = (ULONG)Handle.Value;
1165 }
1166
1167 /* Increase the handle value and move to the next entry */
1168 Handle.Value += INDEX_TO_HANDLE_VALUE(1);
1169 NewEntry++;
1170 HandleTableEntry++;
1171 } while (Handle.Value % INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES));
1172
1173 /* We're done, skip the last entry */
1174 Handle.Value += INDEX_TO_HANDLE_VALUE(1);
1175 }
1176
1177 /* Acquire the table lock and insert this new table into the list */
1178 ExAcquirePushLockExclusive(&HandleTableListLock);
1179 InsertTailList(&HandleTableListHead, &NewTable->HandleTableList);
1180 ExReleasePushLockExclusive(&HandleTableListLock);
1181
1182 /* Leave the critical region we entered previously and return the table */
1183 KeLeaveCriticalRegion();
1184 return NewTable;
1185 }
1186
1187 BOOLEAN
1188 NTAPI
ExChangeHandle(IN PHANDLE_TABLE HandleTable,IN HANDLE Handle,IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine,IN ULONG_PTR Context)1189 ExChangeHandle(IN PHANDLE_TABLE HandleTable,
1190 IN HANDLE Handle,
1191 IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine,
1192 IN ULONG_PTR Context)
1193 {
1194 EXHANDLE ExHandle;
1195 PHANDLE_TABLE_ENTRY HandleTableEntry;
1196 BOOLEAN Result = FALSE;
1197 PAGED_CODE();
1198
1199 /* Set the handle value */
1200 ExHandle.GenericHandleOverlay = Handle;
1201
1202 /* Find the entry for this handle */
1203 HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle);
1204
1205 /* Make sure that we found an entry, and that it's valid */
1206 if (!(HandleTableEntry) ||
1207 !(HandleTableEntry->Object) ||
1208 (HandleTableEntry->NextFreeTableEntry == -2))
1209 {
1210 /* It isn't, fail */
1211 return FALSE;
1212 }
1213
1214 /* Enter a critical region */
1215 KeEnterCriticalRegion();
1216
1217 /* Try locking the handle entry */
1218 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
1219 {
1220 /* Call the change routine and unlock the entry */
1221 Result = ChangeRoutine(HandleTableEntry, Context);
1222 ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
1223 }
1224
1225 /* Leave the critical region and return the callback result */
1226 KeLeaveCriticalRegion();
1227 return Result;
1228 }
1229
1230 VOID
1231 NTAPI
ExSweepHandleTable(IN PHANDLE_TABLE HandleTable,IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure,IN PVOID Context)1232 ExSweepHandleTable(IN PHANDLE_TABLE HandleTable,
1233 IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure,
1234 IN PVOID Context)
1235 {
1236 EXHANDLE Handle;
1237 PHANDLE_TABLE_ENTRY HandleTableEntry;
1238 PAGED_CODE();
1239
1240 /* Set the initial value and loop the entries */
1241 Handle.Value = INDEX_TO_HANDLE_VALUE(1);
1242 while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
1243 {
1244 /* Loop each handle */
1245 do
1246 {
1247 /* Lock the entry */
1248 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
1249 {
1250 /* Notify the callback routine */
1251 EnumHandleProcedure(HandleTableEntry,
1252 Handle.GenericHandleOverlay,
1253 Context);
1254 }
1255
1256 /* Go to the next handle and entry */
1257 Handle.Value += INDEX_TO_HANDLE_VALUE(1);
1258 HandleTableEntry++;
1259 } while (Handle.Value % INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES));
1260
1261 /* Skip past the last entry */
1262 Handle.Value += INDEX_TO_HANDLE_VALUE(1);
1263 }
1264 }
1265
1266 /*
1267 * @implemented
1268 */
1269 BOOLEAN
1270 NTAPI
ExEnumHandleTable(IN PHANDLE_TABLE HandleTable,IN PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure,IN OUT PVOID Context,OUT PHANDLE EnumHandle OPTIONAL)1271 ExEnumHandleTable(IN PHANDLE_TABLE HandleTable,
1272 IN PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure,
1273 IN OUT PVOID Context,
1274 OUT PHANDLE EnumHandle OPTIONAL)
1275 {
1276 EXHANDLE Handle;
1277 PHANDLE_TABLE_ENTRY HandleTableEntry;
1278 BOOLEAN Result = FALSE;
1279 PAGED_CODE();
1280
1281 /* Enter a critical region */
1282 KeEnterCriticalRegion();
1283
1284 /* Set the initial value and loop the entries */
1285 Handle.Value = 0;
1286 while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
1287 {
1288 /* Validate the entry */
1289 if ((HandleTableEntry->Object) &&
1290 (HandleTableEntry->NextFreeTableEntry != -2))
1291 {
1292 /* Lock the entry */
1293 if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
1294 {
1295 /* Notify the callback routine */
1296 Result = EnumHandleProcedure(HandleTableEntry,
1297 Handle.GenericHandleOverlay,
1298 Context);
1299
1300 /* Unlock it */
1301 ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
1302
1303 /* Was this the one looked for? */
1304 if (Result)
1305 {
1306 /* If so, return it if requested */
1307 if (EnumHandle) *EnumHandle = Handle.GenericHandleOverlay;
1308 break;
1309 }
1310 }
1311 }
1312
1313 /* Go to the next entry */
1314 Handle.Value += INDEX_TO_HANDLE_VALUE(1);
1315 }
1316
1317 /* Leave the critical region and return callback result */
1318 KeLeaveCriticalRegion();
1319 return Result;
1320 }
1321
1322 #if DBG && defined(KDBG)
1323
1324 #include <kdbg/kdb.h>
1325
ExpKdbgExtHandle(ULONG Argc,PCHAR Argv[])1326 BOOLEAN ExpKdbgExtHandle(ULONG Argc, PCHAR Argv[])
1327 {
1328 USHORT i;
1329 char *endptr;
1330 HANDLE ProcessId;
1331 EXHANDLE ExHandle;
1332 PLIST_ENTRY Entry;
1333 PEPROCESS Process;
1334 WCHAR KeyPath[256];
1335 PFILE_OBJECT FileObject;
1336 PHANDLE_TABLE HandleTable;
1337 POBJECT_HEADER ObjectHeader;
1338 PHANDLE_TABLE_ENTRY TableEntry;
1339 ULONG NeededLength = 0;
1340 ULONG NameLength;
1341 PCM_KEY_CONTROL_BLOCK Kcb, CurrentKcb;
1342 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
1343
1344 if (Argc > 1)
1345 {
1346 /* Get EPROCESS address or PID */
1347 i = 0;
1348 while (Argv[1][i])
1349 {
1350 if (!isdigit(Argv[1][i]))
1351 {
1352 i = 0;
1353 break;
1354 }
1355
1356 ++i;
1357 }
1358
1359 if (i == 0)
1360 {
1361 if (!KdbpGetHexNumber(Argv[1], (PVOID)&Process))
1362 {
1363 KdbpPrint("Invalid parameter: %s\n", Argv[1]);
1364 return TRUE;
1365 }
1366
1367 /* In the end, we always want a PID */
1368 ProcessId = PsGetProcessId(Process);
1369 }
1370 else
1371 {
1372 ProcessId = (HANDLE)strtoulptr(Argv[1], &endptr, 10);
1373 if (*endptr != '\0')
1374 {
1375 KdbpPrint("Invalid parameter: %s\n", Argv[1]);
1376 return TRUE;
1377 }
1378 }
1379 }
1380 else
1381 {
1382 ProcessId = PsGetCurrentProcessId();
1383 }
1384
1385 for (Entry = HandleTableListHead.Flink;
1386 Entry != &HandleTableListHead;
1387 Entry = Entry->Flink)
1388 {
1389 /* Only return matching PID
1390 * 0 matches everything
1391 */
1392 HandleTable = CONTAINING_RECORD(Entry, HANDLE_TABLE, HandleTableList);
1393 if (ProcessId != 0 && HandleTable->UniqueProcessId != ProcessId)
1394 {
1395 continue;
1396 }
1397
1398 KdbpPrint("\n");
1399
1400 KdbpPrint("Handle table at %p with %d entries in use\n", HandleTable, HandleTable->HandleCount);
1401
1402 ExHandle.Value = 0;
1403 while ((TableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle)))
1404 {
1405 if ((TableEntry->Object) &&
1406 (TableEntry->NextFreeTableEntry != -2))
1407 {
1408 ObjectHeader = ObpGetHandleObject(TableEntry);
1409
1410 KdbpPrint("%p: Object: %p GrantedAccess: %x Entry: %p\n", ExHandle.Value, &ObjectHeader->Body, TableEntry->GrantedAccess, TableEntry);
1411 KdbpPrint("Object: %p Type: (%x) %wZ\n", &ObjectHeader->Body, ObjectHeader->Type, &ObjectHeader->Type->Name);
1412 KdbpPrint("\tObjectHeader: %p\n", ObjectHeader);
1413 KdbpPrint("\t\tHandleCount: %u PointerCount: %u\n", ObjectHeader->HandleCount, ObjectHeader->PointerCount);
1414
1415 /* Specific objects debug prints */
1416
1417 /* For file, display path */
1418 if (ObjectHeader->Type == IoFileObjectType)
1419 {
1420 FileObject = (PFILE_OBJECT)&ObjectHeader->Body;
1421
1422 KdbpPrint("\t\t\tName: %wZ\n", &FileObject->FileName);
1423 }
1424
1425 /* For directory, and win32k objects, display object name */
1426 else if (ObjectHeader->Type == ObpDirectoryObjectType ||
1427 ObjectHeader->Type == ExWindowStationObjectType ||
1428 ObjectHeader->Type == ExDesktopObjectType ||
1429 ObjectHeader->Type == MmSectionObjectType)
1430 {
1431 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
1432 if (ObjectNameInfo != NULL && ObjectNameInfo->Name.Buffer != NULL)
1433 {
1434 KdbpPrint("\t\t\tName: %wZ\n", &ObjectNameInfo->Name);
1435 }
1436 }
1437
1438 /* For registry keys, display full path */
1439 else if (ObjectHeader->Type == CmpKeyObjectType)
1440 {
1441 Kcb = ((PCM_KEY_BODY)&ObjectHeader->Body)->KeyControlBlock;
1442 if (!Kcb->Delete)
1443 {
1444 CurrentKcb = Kcb;
1445
1446 /* See: CmpQueryNameInformation() */
1447
1448 while (CurrentKcb != NULL)
1449 {
1450 if (CurrentKcb->NameBlock->Compressed)
1451 NeededLength += CmpCompressedNameSize(CurrentKcb->NameBlock->Name, CurrentKcb->NameBlock->NameLength);
1452 else
1453 NeededLength += CurrentKcb->NameBlock->NameLength;
1454
1455 NeededLength += sizeof(OBJ_NAME_PATH_SEPARATOR);
1456
1457 CurrentKcb = CurrentKcb->ParentKcb;
1458 }
1459
1460 if (NeededLength < sizeof(KeyPath))
1461 {
1462 CurrentKcb = Kcb;
1463
1464 while (CurrentKcb != NULL)
1465 {
1466 if (CurrentKcb->NameBlock->Compressed)
1467 {
1468 NameLength = CmpCompressedNameSize(CurrentKcb->NameBlock->Name, CurrentKcb->NameBlock->NameLength);
1469 CmpCopyCompressedName(&KeyPath[(NeededLength - NameLength)/sizeof(WCHAR)],
1470 NameLength,
1471 CurrentKcb->NameBlock->Name,
1472 CurrentKcb->NameBlock->NameLength);
1473 }
1474 else
1475 {
1476 NameLength = CurrentKcb->NameBlock->NameLength;
1477 RtlCopyMemory(&KeyPath[(NeededLength - NameLength)/sizeof(WCHAR)],
1478 CurrentKcb->NameBlock->Name,
1479 NameLength);
1480 }
1481
1482 NeededLength -= NameLength;
1483 NeededLength -= sizeof(OBJ_NAME_PATH_SEPARATOR);
1484 KeyPath[NeededLength/sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
1485
1486 CurrentKcb = CurrentKcb->ParentKcb;
1487 }
1488 }
1489
1490 KdbpPrint("\t\t\tName: %S\n", KeyPath);
1491 }
1492 }
1493 }
1494
1495 ExHandle.Value += INDEX_TO_HANDLE_VALUE(1);
1496 }
1497 }
1498
1499 return TRUE;
1500 }
1501
1502 #endif // DBG && defined(KDBG)
1503