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 /* PRIVATE FUNCTIONS *********************************************************/
22 ObReferenceObjectSafe(IN PVOID Object
)
24 POBJECT_HEADER ObjectHeader
;
25 LONG OldValue
, NewValue
;
27 /* Get the object header */
28 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
30 /* Get the current reference count and fail if it's zero */
31 OldValue
= ObjectHeader
->PointerCount
;
32 if (!OldValue
) return FALSE
;
34 /* Start reference loop */
37 /* Increase the reference count */
38 NewValue
= InterlockedCompareExchange(&ObjectHeader
->PointerCount
,
41 if (OldValue
== NewValue
) return TRUE
;
47 /* If we got here, then the reference count is now 0 */
53 ObpDeferObjectDeletion(IN POBJECT_HEADER Header
)
57 /* Loop while trying to update the list */
60 /* Get the current entry */
61 Entry
= ObpReaperList
;
63 /* Link our object to the list */
64 Header
->NextToFree
= Entry
;
67 } while (InterlockedCompareExchangePointer(&ObpReaperList
,
71 /* Queue the work item if needed */
72 if (!Entry
) ExQueueWorkItem(&ObpReaperWorkItem
, CriticalWorkQueue
);
77 ObReferenceObjectEx(IN PVOID Object
,
80 /* Increment the reference count and return the count now */
81 return InterlockedExchangeAdd(&OBJECT_TO_OBJECT_HEADER(Object
)->
88 ObDereferenceObjectEx(IN PVOID Object
,
91 POBJECT_HEADER Header
;
94 /* Extract the object header */
95 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
97 /* Check whether the object can now be deleted. */
98 NewCount
= InterlockedExchangeAdd(&Header
->PointerCount
, -Count
) - Count
;
99 if (!NewCount
) ObpDeferObjectDeletion(Header
);
101 /* Return the current count */
107 ObInitializeFastReference(IN PEX_FAST_REF FastRef
,
108 IN PVOID Object OPTIONAL
)
110 /* Check if we were given an object and reference it 7 times */
111 if (Object
) ObReferenceObjectEx(Object
, MAX_FAST_REFS
);
113 /* Setup the fast reference */
114 ExInitializeFastReference(FastRef
, Object
);
119 ObFastReferenceObjectLocked(IN PEX_FAST_REF FastRef
)
122 EX_FAST_REF OldValue
= *FastRef
;
124 /* Get the object and reference it slowly */
125 Object
= ExGetObjectFastReference(OldValue
);
126 if (Object
) ObReferenceObject(Object
);
132 ObFastReferenceObject(IN PEX_FAST_REF FastRef
)
134 EX_FAST_REF OldValue
;
138 /* Reference the object and get it pointer */
139 OldValue
= ExAcquireFastReference(FastRef
);
140 Object
= ExGetObjectFastReference(OldValue
);
142 /* Check how many references are left */
143 Count
= ExGetCountFastReference(OldValue
);
145 /* Check if the reference count is over 1 */
146 if (Count
> 1) return Object
;
148 /* Check if the reference count has reached 0 */
149 if (!Count
) return NULL
;
151 /* Otherwise, reference the object 7 times */
152 ObReferenceObjectEx(Object
, MAX_FAST_REFS
);
154 /* Now update the reference count */
155 if (!ExInsertFastReference(FastRef
, Object
))
157 /* We failed: completely dereference the object */
158 ObDereferenceObjectEx(Object
, MAX_FAST_REFS
);
161 /* Return the Object */
167 ObFastDereferenceObject(IN PEX_FAST_REF FastRef
,
170 /* Release a fast reference. If this failed, use the slow path */
171 if (!ExReleaseFastReference(FastRef
, Object
)) ObDereferenceObject(Object
);
176 ObFastReplaceObject(IN PEX_FAST_REF FastRef
,
179 EX_FAST_REF OldValue
;
183 /* Check if we were given an object and reference it 7 times */
184 if (Object
) ObReferenceObjectEx(Object
, MAX_FAST_REFS
);
187 OldValue
= ExSwapFastReference(FastRef
, Object
);
188 OldObject
= ExGetObjectFastReference(OldValue
);
190 /* Check if we had an active object and dereference it */
191 Count
= ExGetCountFastReference(OldValue
);
192 if ((OldObject
) && (Count
)) ObDereferenceObjectEx(OldObject
, Count
);
194 /* Return the old object */
198 /* PUBLIC FUNCTIONS *********************************************************/
202 ObfReferenceObject(IN PVOID Object
)
206 /* Get the header and increment the reference count */
207 return InterlockedIncrement(&OBJECT_TO_OBJECT_HEADER(Object
)->PointerCount
);
212 ObfDereferenceObject(IN PVOID Object
)
214 POBJECT_HEADER Header
;
217 /* Extract the object header */
218 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
220 if (Header
->PointerCount
< Header
->HandleCount
)
222 DPRINT1("Misbehaving object: %wZ\n", &Header
->Type
->Name
);
223 return Header
->PointerCount
;
226 /* Check whether the object can now be deleted. */
227 OldCount
= InterlockedDecrement(&Header
->PointerCount
);
231 ASSERT(Header
->HandleCount
== 0);
233 /* Check if APCs are still active */
234 if (!KeAreAllApcsDisabled())
236 /* Remove the object */
237 ObpDeleteObject(Object
, FALSE
);
241 /* Add us to the deferred deletion list */
242 ObpDeferObjectDeletion(Header
);
246 /* Return the old count */
252 ObDereferenceObjectDeferDelete(IN PVOID Object
)
254 POBJECT_HEADER Header
= OBJECT_TO_OBJECT_HEADER(Object
);
256 /* Check whether the object can now be deleted. */
257 if (!InterlockedDecrement(&Header
->PointerCount
))
259 /* Add us to the deferred deletion list */
260 ObpDeferObjectDeletion(Header
);
264 #undef ObDereferenceObject
267 ObDereferenceObject(IN PVOID Object
)
269 /* Call the fastcall function */
270 ObfDereferenceObject(Object
);
275 ObReferenceObjectByPointer(IN PVOID Object
,
276 IN ACCESS_MASK DesiredAccess
,
277 IN POBJECT_TYPE ObjectType
,
278 IN KPROCESSOR_MODE AccessMode
)
280 POBJECT_HEADER Header
;
283 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
286 * Validate object type if the call is for UserMode.
287 * NOTE: Unless it's a symbolic link (Caz Yokoyama [MSFT])
289 if ((Header
->Type
!= ObjectType
) && ((AccessMode
!= KernelMode
) ||
290 (ObjectType
== ObSymbolicLinkType
)))
293 return STATUS_OBJECT_TYPE_MISMATCH
;
296 /* Increment the reference count and return success */
297 InterlockedIncrement(&Header
->PointerCount
);
298 return STATUS_SUCCESS
;
303 ObReferenceObjectByName(IN PUNICODE_STRING ObjectPath
,
305 IN PACCESS_STATE PassedAccessState
,
306 IN ACCESS_MASK DesiredAccess
,
307 IN POBJECT_TYPE ObjectType
,
308 IN KPROCESSOR_MODE AccessMode
,
309 IN OUT PVOID ParseContext
,
310 OUT PVOID
* ObjectPtr
)
313 UNICODE_STRING ObjectName
;
315 OBP_LOOKUP_CONTEXT Context
;
316 AUX_ACCESS_DATA AuxData
;
317 ACCESS_STATE AccessState
;
321 if (!ObjectPath
) return STATUS_OBJECT_NAME_INVALID
;
323 /* Capture the name */
324 Status
= ObpCaptureObjectName(&ObjectName
, ObjectPath
, AccessMode
, TRUE
);
325 if (!NT_SUCCESS(Status
)) return Status
;
327 /* We also need a valid name after capture */
328 if (!ObjectName
.Length
) return STATUS_OBJECT_NAME_INVALID
;
330 /* Check if we didn't get an access state */
331 if (!PassedAccessState
)
333 /* Use our built-in access state */
334 PassedAccessState
= &AccessState
;
335 Status
= SeCreateAccessState(&AccessState
,
338 &ObjectType
->TypeInfo
.GenericMapping
);
339 if (!NT_SUCCESS(Status
)) goto Quickie
;
342 /* Find the object */
344 Status
= ObpLookupObjectName(NULL
,
356 /* Cleanup after lookup */
357 ObpReleaseLookupContext(&Context
);
359 /* Check if the lookup succeeded */
360 if (NT_SUCCESS(Status
))
362 /* Check if access is allowed */
363 if (ObpCheckObjectReference(Object
,
369 /* Return the object */
374 /* Free the access state */
375 if (PassedAccessState
== &AccessState
)
377 SeDeleteAccessState(PassedAccessState
);
381 /* Free the captured name if we had one, and return status */
382 ObpFreeObjectNameBuffer(&ObjectName
);
388 ObReferenceObjectByHandle(IN HANDLE Handle
,
389 IN ACCESS_MASK DesiredAccess
,
390 IN POBJECT_TYPE ObjectType
,
391 IN KPROCESSOR_MODE AccessMode
,
393 OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL
)
395 PHANDLE_TABLE_ENTRY HandleEntry
;
396 POBJECT_HEADER ObjectHeader
;
397 ACCESS_MASK GrantedAccess
;
399 PEPROCESS CurrentProcess
;
401 PETHREAD CurrentThread
;
408 /* Check if this is a special handle */
409 if (HandleToLong(Handle
) < 0)
411 /* Check if this is the current process */
412 if (Handle
== NtCurrentProcess())
414 /* Check if this is the right object type */
415 if ((ObjectType
== PsProcessType
) || !(ObjectType
))
417 /* Get the current process and granted access */
418 CurrentProcess
= PsGetCurrentProcess();
419 GrantedAccess
= CurrentProcess
->GrantedAccess
;
421 /* Validate access */
422 /* ~GrantedAccess = RefusedAccess.*/
423 /* ~GrantedAccess & DesiredAccess = list of refused bits. */
424 /* !(~GrantedAccess & DesiredAccess) == TRUE means ALL requested rights are granted */
425 if ((AccessMode
== KernelMode
) ||
426 !(~GrantedAccess
& DesiredAccess
))
428 /* Check if the caller wanted handle information */
429 if (HandleInformation
)
432 HandleInformation
->HandleAttributes
= 0;
433 HandleInformation
->GrantedAccess
= GrantedAccess
;
436 /* Reference ourselves */
437 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(CurrentProcess
);
438 InterlockedExchangeAdd(&ObjectHeader
->PointerCount
, 1);
440 /* Return the pointer */
441 *Object
= CurrentProcess
;
442 ASSERT(*Object
!= NULL
);
443 Status
= STATUS_SUCCESS
;
448 Status
= STATUS_ACCESS_DENIED
;
453 /* The caller used this special handle value with a non-process type */
454 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
457 /* Return the status */
460 else if (Handle
== NtCurrentThread())
462 /* Check if this is the right object type */
463 if ((ObjectType
== PsThreadType
) || !(ObjectType
))
465 /* Get the current process and granted access */
466 CurrentThread
= PsGetCurrentThread();
467 GrantedAccess
= CurrentThread
->GrantedAccess
;
469 /* Validate access */
470 /* ~GrantedAccess = RefusedAccess.*/
471 /* ~GrantedAccess & DesiredAccess = list of refused bits. */
472 /* !(~GrantedAccess & DesiredAccess) == TRUE means ALL requested rights are granted */
473 if ((AccessMode
== KernelMode
) ||
474 !(~GrantedAccess
& DesiredAccess
))
476 /* Check if the caller wanted handle information */
477 if (HandleInformation
)
480 HandleInformation
->HandleAttributes
= 0;
481 HandleInformation
->GrantedAccess
= GrantedAccess
;
484 /* Reference ourselves */
485 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(CurrentThread
);
486 InterlockedExchangeAdd(&ObjectHeader
->PointerCount
, 1);
488 /* Return the pointer */
489 *Object
= CurrentThread
;
490 ASSERT(*Object
!= NULL
);
491 Status
= STATUS_SUCCESS
;
496 Status
= STATUS_ACCESS_DENIED
;
501 /* The caller used this special handle value with a non-process type */
502 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
505 /* Return the status */
508 else if (AccessMode
== KernelMode
)
510 /* Use the kernel handle table and get the actual handle value */
511 Handle
= ObKernelHandleToHandle(Handle
);
512 HandleTable
= ObpKernelHandleTable
;
516 /* Invalid access, fail */
517 return STATUS_INVALID_HANDLE
;
522 /* Otherwise use this process's handle table */
523 HandleTable
= PsGetCurrentProcess()->ObjectTable
;
526 /* Enter a critical region while we touch the handle table */
527 ASSERT(HandleTable
!= NULL
);
528 KeEnterCriticalRegion();
530 /* Get the handle entry */
531 HandleEntry
= ExMapHandleToPointer(HandleTable
, Handle
);
534 /* Get the object header and validate the type*/
535 ObjectHeader
= ObpGetHandleObject(HandleEntry
);
536 if (!(ObjectType
) || (ObjectType
== ObjectHeader
->Type
))
538 /* Get the granted access and validate it */
539 GrantedAccess
= HandleEntry
->GrantedAccess
;
541 /* Validate access */
542 /* ~GrantedAccess = RefusedAccess.*/
543 /* ~GrantedAccess & DesiredAccess = list of refused bits. */
544 /* !(~GrantedAccess & DesiredAccess) == TRUE means ALL requested rights are granted */
545 if ((AccessMode
== KernelMode
) ||
546 !(~GrantedAccess
& DesiredAccess
))
548 /* Reference the object directly since we have its header */
549 InterlockedIncrement(&ObjectHeader
->PointerCount
);
551 /* Mask out the internal attributes */
552 Attributes
= HandleEntry
->ObAttributes
& OBJ_HANDLE_ATTRIBUTES
;
554 /* Check if the caller wants handle information */
555 if (HandleInformation
)
557 /* Fill out the information */
558 HandleInformation
->HandleAttributes
= Attributes
;
559 HandleInformation
->GrantedAccess
= GrantedAccess
;
562 /* Return the pointer */
563 *Object
= &ObjectHeader
->Body
;
565 /* Unlock the handle */
566 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
567 KeLeaveCriticalRegion();
570 ASSERT(*Object
!= NULL
);
571 return STATUS_SUCCESS
;
575 /* Requested access failed */
576 DPRINT("Rights not granted: %x\n", ~GrantedAccess
& DesiredAccess
);
577 Status
= STATUS_ACCESS_DENIED
;
582 /* Invalid object type */
583 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
586 /* Unlock the entry */
587 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
592 Status
= STATUS_INVALID_HANDLE
;
595 /* Return failure status */
596 KeLeaveCriticalRegion();