2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/obref.c
5 * PURPOSE: Manages the referencing and de-referencing of all Objects,
6 * as well as the Object Fast Reference implementation.
7 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 * Thomas Weidenmueller (w3seek@reactos.org)
12 /* INCLUDES ******************************************************************/
18 extern ULONG ObpAccessProtectCloseBit
;
20 /* PRIVATE FUNCTIONS *********************************************************/
24 ObReferenceObjectSafe(IN PVOID Object
)
26 POBJECT_HEADER ObjectHeader
;
27 LONG_PTR OldValue
, NewValue
;
29 /* Get the object header */
30 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
32 /* Get the current reference count and fail if it's zero */
33 OldValue
= ObjectHeader
->PointerCount
;
34 if (!OldValue
) return FALSE
;
36 /* Start reference loop */
39 /* Increase the reference count */
40 NewValue
= InterlockedCompareExchangeSizeT(&ObjectHeader
->PointerCount
,
43 if (OldValue
== NewValue
) return TRUE
;
49 /* If we got here, then the reference count is now 0 */
55 ObpDeferObjectDeletion(IN POBJECT_HEADER Header
)
59 /* Loop while trying to update the list */
62 /* Get the current entry */
63 Entry
= ObpReaperList
;
65 /* Link our object to the list */
66 Header
->NextToFree
= Entry
;
69 } while (InterlockedCompareExchangePointer(&ObpReaperList
,
73 /* Queue the work item if needed */
74 if (!Entry
) ExQueueWorkItem(&ObpReaperWorkItem
, CriticalWorkQueue
);
79 ObReferenceObjectEx(IN PVOID Object
,
82 /* Increment the reference count and return the count now */
83 return InterlockedExchangeAddSizeT(&OBJECT_TO_OBJECT_HEADER(Object
)->
90 ObDereferenceObjectEx(IN PVOID Object
,
93 POBJECT_HEADER Header
;
96 /* Extract the object header */
97 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
99 /* Check whether the object can now be deleted. */
100 NewCount
= InterlockedExchangeAddSizeT(&Header
->PointerCount
, -Count
) - Count
;
101 if (!NewCount
) ObpDeferObjectDeletion(Header
);
103 /* Return the current count */
109 ObInitializeFastReference(IN PEX_FAST_REF FastRef
,
110 IN PVOID Object OPTIONAL
)
112 /* Check if we were given an object and reference it 7 times */
113 if (Object
) ObReferenceObjectEx(Object
, MAX_FAST_REFS
);
115 /* Setup the fast reference */
116 ExInitializeFastReference(FastRef
, Object
);
121 ObFastReferenceObjectLocked(IN PEX_FAST_REF FastRef
)
124 EX_FAST_REF OldValue
= *FastRef
;
126 /* Get the object and reference it slowly */
127 Object
= ExGetObjectFastReference(OldValue
);
128 if (Object
) ObReferenceObject(Object
);
134 ObFastReferenceObject(IN PEX_FAST_REF FastRef
)
136 EX_FAST_REF OldValue
;
140 /* Reference the object and get it pointer */
141 OldValue
= ExAcquireFastReference(FastRef
);
142 Object
= ExGetObjectFastReference(OldValue
);
144 /* Check how many references are left */
145 Count
= ExGetCountFastReference(OldValue
);
147 /* Check if the reference count is over 1 */
148 if (Count
> 1) return Object
;
150 /* Check if the reference count has reached 0 */
151 if (!Count
) return NULL
;
153 /* Otherwise, reference the object 7 times */
154 ObReferenceObjectEx(Object
, MAX_FAST_REFS
);
156 /* Now update the reference count */
157 if (!ExInsertFastReference(FastRef
, Object
))
159 /* We failed: completely dereference the object */
160 ObDereferenceObjectEx(Object
, MAX_FAST_REFS
);
163 /* Return the Object */
169 ObFastDereferenceObject(IN PEX_FAST_REF FastRef
,
172 /* Release a fast reference. If this failed, use the slow path */
173 if (!ExReleaseFastReference(FastRef
, Object
)) ObDereferenceObject(Object
);
178 ObFastReplaceObject(IN PEX_FAST_REF FastRef
,
181 EX_FAST_REF OldValue
;
185 /* Check if we were given an object and reference it 7 times */
186 if (Object
) ObReferenceObjectEx(Object
, MAX_FAST_REFS
);
189 OldValue
= ExSwapFastReference(FastRef
, Object
);
190 OldObject
= ExGetObjectFastReference(OldValue
);
192 /* Check if we had an active object and dereference it */
193 Count
= ExGetCountFastReference(OldValue
);
194 if ((OldObject
) && (Count
)) ObDereferenceObjectEx(OldObject
, Count
);
196 /* Return the old object */
202 ObReferenceFileObjectForWrite(IN HANDLE Handle
,
203 IN KPROCESSOR_MODE AccessMode
,
204 OUT PFILE_OBJECT
*FileObject
,
205 OUT POBJECT_HANDLE_INFORMATION HandleInformation
)
208 PHANDLE_TABLE HandleTable
;
209 POBJECT_HEADER ObjectHeader
;
210 PHANDLE_TABLE_ENTRY HandleEntry
;
211 ACCESS_MASK GrantedAccess
, DesiredAccess
;
216 /* Check if this is a special handle */
217 if (HandleToLong(Handle
) < 0)
219 /* Make sure we have a valid kernel handle */
220 if (AccessMode
!= KernelMode
|| Handle
== NtCurrentProcess() || Handle
== NtCurrentThread())
222 return STATUS_INVALID_HANDLE
;
225 /* Use the kernel handle table and get the actual handle value */
226 Handle
= ObKernelHandleToHandle(Handle
);
227 HandleTable
= ObpKernelHandleTable
;
231 /* Otherwise use this process's handle table */
232 HandleTable
= PsGetCurrentProcess()->ObjectTable
;
235 ASSERT(HandleTable
!= NULL
);
236 KeEnterCriticalRegion();
238 /* Get the handle entry */
239 HandleEntry
= ExMapHandleToPointer(HandleTable
, Handle
);
242 /* Get the object header and validate the type*/
243 ObjectHeader
= ObpGetHandleObject(HandleEntry
);
245 /* Get the desired access from the file object */
246 if (!NT_SUCCESS(IoComputeDesiredAccessFileObject((PFILE_OBJECT
)&ObjectHeader
->Body
,
249 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
253 /* Extract the granted access from the handle entry */
254 if (BooleanFlagOn(NtGlobalFlag
, FLG_KERNEL_STACK_TRACE_DB
))
256 /* FIXME: Translate granted access */
257 GrantedAccess
= HandleEntry
->GrantedAccess
;
261 GrantedAccess
= HandleEntry
->GrantedAccess
& ~ObpAccessProtectCloseBit
;
264 /* FIXME: Get handle information for audit */
266 HandleInformation
->GrantedAccess
= GrantedAccess
;
268 /* FIXME: Get handle attributes */
269 HandleInformation
->HandleAttributes
= 0;
271 /* Do granted and desired access match? */
272 if (GrantedAccess
& DesiredAccess
)
274 /* FIXME: Audit access if required */
276 /* Reference the object directly since we have its header */
277 InterlockedIncrementSizeT(&ObjectHeader
->PointerCount
);
279 /* Unlock the handle */
280 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
281 KeLeaveCriticalRegion();
283 *FileObject
= (PFILE_OBJECT
)&ObjectHeader
->Body
;
286 ASSERT(*FileObject
!= NULL
);
287 return STATUS_SUCCESS
;
290 /* No match, deny write access */
291 Status
= STATUS_ACCESS_DENIED
;
293 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
298 Status
= STATUS_INVALID_HANDLE
;
301 /* Return failure status */
302 KeLeaveCriticalRegion();
306 /* PUBLIC FUNCTIONS *********************************************************/
310 ObfReferenceObject(IN PVOID Object
)
314 /* Get the header and increment the reference count */
315 return InterlockedIncrementSizeT(&OBJECT_TO_OBJECT_HEADER(Object
)->PointerCount
);
320 ObfDereferenceObject(IN PVOID Object
)
322 POBJECT_HEADER Header
;
325 /* Extract the object header */
326 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
328 if (Header
->PointerCount
< Header
->HandleCount
)
330 DPRINT1("Misbehaving object: %wZ\n", &Header
->Type
->Name
);
331 return Header
->PointerCount
;
334 /* Check whether the object can now be deleted. */
335 OldCount
= InterlockedDecrementSizeT(&Header
->PointerCount
);
339 ASSERT(Header
->HandleCount
== 0);
341 /* Check if APCs are still active */
342 if (!KeAreAllApcsDisabled())
344 /* Remove the object */
345 ObpDeleteObject(Object
, FALSE
);
349 /* Add us to the deferred deletion list */
350 ObpDeferObjectDeletion(Header
);
354 /* Return the old count */
360 ObDereferenceObjectDeferDelete(IN PVOID Object
)
362 POBJECT_HEADER Header
= OBJECT_TO_OBJECT_HEADER(Object
);
364 /* Check whether the object can now be deleted. */
365 if (!InterlockedDecrementSizeT(&Header
->PointerCount
))
367 /* Add us to the deferred deletion list */
368 ObpDeferObjectDeletion(Header
);
372 #undef ObDereferenceObject
375 ObDereferenceObject(IN PVOID Object
)
377 /* Call the fastcall function */
378 ObfDereferenceObject(Object
);
383 ObReferenceObjectByPointer(IN PVOID Object
,
384 IN ACCESS_MASK DesiredAccess
,
385 IN POBJECT_TYPE ObjectType
,
386 IN KPROCESSOR_MODE AccessMode
)
388 POBJECT_HEADER Header
;
391 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
394 * Validate object type if the call is for UserMode.
395 * NOTE: Unless it's a symbolic link (Caz Yokoyama [MSFT])
397 if ((Header
->Type
!= ObjectType
) && ((AccessMode
!= KernelMode
) ||
398 (ObjectType
== ObpSymbolicLinkObjectType
)))
401 return STATUS_OBJECT_TYPE_MISMATCH
;
404 /* Increment the reference count and return success */
405 InterlockedIncrementSizeT(&Header
->PointerCount
);
406 return STATUS_SUCCESS
;
411 ObReferenceObjectByName(IN PUNICODE_STRING ObjectPath
,
413 IN PACCESS_STATE PassedAccessState
,
414 IN ACCESS_MASK DesiredAccess
,
415 IN POBJECT_TYPE ObjectType
,
416 IN KPROCESSOR_MODE AccessMode
,
417 IN OUT PVOID ParseContext
,
418 OUT PVOID
* ObjectPtr
)
421 UNICODE_STRING ObjectName
;
423 OBP_LOOKUP_CONTEXT Context
;
424 AUX_ACCESS_DATA AuxData
;
425 ACCESS_STATE AccessState
;
429 if (!ObjectPath
) return STATUS_OBJECT_NAME_INVALID
;
431 /* Capture the name */
432 Status
= ObpCaptureObjectName(&ObjectName
, ObjectPath
, AccessMode
, TRUE
);
433 if (!NT_SUCCESS(Status
)) return Status
;
435 /* We also need a valid name after capture */
436 if (!ObjectName
.Length
) return STATUS_OBJECT_NAME_INVALID
;
438 /* Check if we didn't get an access state */
439 if (!PassedAccessState
)
441 /* Use our built-in access state */
442 PassedAccessState
= &AccessState
;
443 Status
= SeCreateAccessState(&AccessState
,
446 &ObjectType
->TypeInfo
.GenericMapping
);
447 if (!NT_SUCCESS(Status
)) goto Quickie
;
450 /* Find the object */
452 Status
= ObpLookupObjectName(NULL
,
464 /* Cleanup after lookup */
465 ObpReleaseLookupContext(&Context
);
467 /* Check if the lookup succeeded */
468 if (NT_SUCCESS(Status
))
470 /* Check if access is allowed */
471 if (ObpCheckObjectReference(Object
,
477 /* Return the object */
482 /* Free the access state */
483 if (PassedAccessState
== &AccessState
)
485 SeDeleteAccessState(PassedAccessState
);
489 /* Free the captured name if we had one, and return status */
490 ObpFreeObjectNameBuffer(&ObjectName
);
496 ObReferenceObjectByHandle(IN HANDLE Handle
,
497 IN ACCESS_MASK DesiredAccess
,
498 IN POBJECT_TYPE ObjectType
,
499 IN KPROCESSOR_MODE AccessMode
,
501 OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL
)
503 PHANDLE_TABLE_ENTRY HandleEntry
;
504 POBJECT_HEADER ObjectHeader
;
505 ACCESS_MASK GrantedAccess
;
507 PEPROCESS CurrentProcess
;
509 PETHREAD CurrentThread
;
516 /* Check if this is a special handle */
517 if (HandleToLong(Handle
) < 0)
519 /* Check if this is the current process */
520 if (Handle
== NtCurrentProcess())
522 /* Check if this is the right object type */
523 if ((ObjectType
== PsProcessType
) || !(ObjectType
))
525 /* Get the current process and granted access */
526 CurrentProcess
= PsGetCurrentProcess();
527 GrantedAccess
= CurrentProcess
->GrantedAccess
;
529 /* Validate access */
530 /* ~GrantedAccess = RefusedAccess.*/
531 /* ~GrantedAccess & DesiredAccess = list of refused bits. */
532 /* !(~GrantedAccess & DesiredAccess) == TRUE means ALL requested rights are granted */
533 if ((AccessMode
== KernelMode
) ||
534 !(~GrantedAccess
& DesiredAccess
))
536 /* Check if the caller wanted handle information */
537 if (HandleInformation
)
540 HandleInformation
->HandleAttributes
= 0;
541 HandleInformation
->GrantedAccess
= GrantedAccess
;
544 /* Reference ourselves */
545 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(CurrentProcess
);
546 InterlockedExchangeAddSizeT(&ObjectHeader
->PointerCount
, 1);
548 /* Return the pointer */
549 *Object
= CurrentProcess
;
550 ASSERT(*Object
!= NULL
);
551 Status
= STATUS_SUCCESS
;
556 Status
= STATUS_ACCESS_DENIED
;
561 /* The caller used this special handle value with a non-process type */
562 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
565 /* Return the status */
568 else if (Handle
== NtCurrentThread())
570 /* Check if this is the right object type */
571 if ((ObjectType
== PsThreadType
) || !(ObjectType
))
573 /* Get the current process and granted access */
574 CurrentThread
= PsGetCurrentThread();
575 GrantedAccess
= CurrentThread
->GrantedAccess
;
577 /* Validate access */
578 /* ~GrantedAccess = RefusedAccess.*/
579 /* ~GrantedAccess & DesiredAccess = list of refused bits. */
580 /* !(~GrantedAccess & DesiredAccess) == TRUE means ALL requested rights are granted */
581 if ((AccessMode
== KernelMode
) ||
582 !(~GrantedAccess
& DesiredAccess
))
584 /* Check if the caller wanted handle information */
585 if (HandleInformation
)
588 HandleInformation
->HandleAttributes
= 0;
589 HandleInformation
->GrantedAccess
= GrantedAccess
;
592 /* Reference ourselves */
593 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(CurrentThread
);
594 InterlockedExchangeAddSizeT(&ObjectHeader
->PointerCount
, 1);
596 /* Return the pointer */
597 *Object
= CurrentThread
;
598 ASSERT(*Object
!= NULL
);
599 Status
= STATUS_SUCCESS
;
604 Status
= STATUS_ACCESS_DENIED
;
609 /* The caller used this special handle value with a non-process type */
610 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
613 /* Return the status */
616 else if (AccessMode
== KernelMode
)
618 /* Use the kernel handle table and get the actual handle value */
619 Handle
= ObKernelHandleToHandle(Handle
);
620 HandleTable
= ObpKernelHandleTable
;
624 /* Invalid access, fail */
625 return STATUS_INVALID_HANDLE
;
630 /* Otherwise use this process's handle table */
631 HandleTable
= PsGetCurrentProcess()->ObjectTable
;
634 /* Enter a critical region while we touch the handle table */
635 ASSERT(HandleTable
!= NULL
);
636 KeEnterCriticalRegion();
638 /* Get the handle entry */
639 HandleEntry
= ExMapHandleToPointer(HandleTable
, Handle
);
642 /* Get the object header and validate the type*/
643 ObjectHeader
= ObpGetHandleObject(HandleEntry
);
644 if (!(ObjectType
) || (ObjectType
== ObjectHeader
->Type
))
646 /* Get the granted access and validate it */
647 GrantedAccess
= HandleEntry
->GrantedAccess
;
649 /* Validate access */
650 /* ~GrantedAccess = RefusedAccess.*/
651 /* ~GrantedAccess & DesiredAccess = list of refused bits. */
652 /* !(~GrantedAccess & DesiredAccess) == TRUE means ALL requested rights are granted */
653 if ((AccessMode
== KernelMode
) ||
654 !(~GrantedAccess
& DesiredAccess
))
656 /* Reference the object directly since we have its header */
657 InterlockedIncrementSizeT(&ObjectHeader
->PointerCount
);
659 /* Mask out the internal attributes */
660 Attributes
= HandleEntry
->ObAttributes
& OBJ_HANDLE_ATTRIBUTES
;
662 /* Check if the caller wants handle information */
663 if (HandleInformation
)
665 /* Fill out the information */
666 HandleInformation
->HandleAttributes
= Attributes
;
667 HandleInformation
->GrantedAccess
= GrantedAccess
;
670 /* Return the pointer */
671 *Object
= &ObjectHeader
->Body
;
673 /* Unlock the handle */
674 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
675 KeLeaveCriticalRegion();
678 ASSERT(*Object
!= NULL
);
679 return STATUS_SUCCESS
;
683 /* Requested access failed */
684 DPRINT("Rights not granted: %x\n", ~GrantedAccess
& DesiredAccess
);
685 Status
= STATUS_ACCESS_DENIED
;
690 /* Invalid object type */
691 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
694 /* Unlock the entry */
695 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
700 Status
= STATUS_INVALID_HANDLE
;
703 /* Return failure status */
704 KeLeaveCriticalRegion();