3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/object.c
6 * PURPOSE: Implements generic object managment functions
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 * Skywing (skywing@valhallalegends.com)
12 /* INCLUDES *****************************************************************/
16 #include <internal/debug.h>
18 #define UNICODE_PATH_SEP L'\\'
19 #define UNICODE_NO_PATH L"..."
20 #define OB_NAME_TAG TAG('O','b','N','m')
22 typedef struct _RETENTION_CHECK_PARAMS
24 WORK_QUEUE_ITEM WorkItem
;
25 POBJECT_HEADER ObjectHeader
;
26 } RETENTION_CHECK_PARAMS
, *PRETENTION_CHECK_PARAMS
;
28 /* FUNCTIONS ************************************************************/
32 ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName
,
33 IN PUNICODE_STRING ObjectName
,
34 IN KPROCESSOR_MODE AccessMode
)
36 NTSTATUS Status
= STATUS_SUCCESS
;
38 PWCHAR StringBuffer
= NULL
;
39 UNICODE_STRING LocalName
= {}; /* <= GCC 4.0 + Optimizer */
41 /* Initialize the Input String */
42 RtlInitUnicodeString(CapturedName
, NULL
);
44 /* Protect everything */
47 /* First Probe the String */
48 DPRINT("ObpCaptureObjectName: %wZ\n", ObjectName
);
49 if (AccessMode
!= KernelMode
)
51 ProbeForRead(ObjectName
,
52 sizeof(UNICODE_STRING
),
54 LocalName
= *ObjectName
;
56 ProbeForRead(LocalName
.Buffer
,
62 /* No probing needed */
63 LocalName
= *ObjectName
;
66 /* Make sure there really is a string */
67 DPRINT("Probing OK\n");
68 if ((StringLength
= LocalName
.Length
))
70 /* Check that the size is a valid WCHAR multiple */
71 if ((StringLength
& (sizeof(WCHAR
) - 1)) ||
72 /* Check that the NULL-termination below will work */
73 (StringLength
== (MAXUSHORT
- sizeof(WCHAR
) + 1)))
75 /* PS: Please keep the checks above expanded for clarity */
76 DPRINT1("Invalid String Length\n");
77 Status
= STATUS_OBJECT_NAME_INVALID
;
81 /* Allocate a non-paged buffer for this string */
82 DPRINT("Capturing String\n");
83 CapturedName
->Length
= StringLength
;
84 CapturedName
->MaximumLength
= StringLength
+ sizeof(WCHAR
);
85 if ((StringBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
86 StringLength
+ sizeof(WCHAR
),
89 /* Copy the string and null-terminate it */
90 RtlMoveMemory(StringBuffer
, LocalName
.Buffer
, StringLength
);
91 StringBuffer
[StringLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
92 CapturedName
->Buffer
= StringBuffer
;
93 DPRINT("String Captured: %wZ\n", CapturedName
);
98 DPRINT1("Out of Memory!\n");
99 Status
= STATUS_INSUFFICIENT_RESOURCES
;
104 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
106 Status
= _SEH_GetExceptionCode();
108 /* Remember to free the buffer in case of failure */
110 if (StringBuffer
) ExFreePool(StringBuffer
);
115 DPRINT("Returning: %lx\n", Status
);
121 ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes
,
122 IN KPROCESSOR_MODE AccessMode
,
123 IN POBJECT_TYPE ObjectType
,
124 IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
125 OUT PUNICODE_STRING ObjectName
)
127 NTSTATUS Status
= STATUS_SUCCESS
;
128 PSECURITY_DESCRIPTOR SecurityDescriptor
;
129 PSECURITY_QUALITY_OF_SERVICE SecurityQos
;
130 PUNICODE_STRING LocalObjectName
= NULL
;
132 /* Zero out the Capture Data */
133 DPRINT("ObpCaptureObjectAttributes\n");
134 RtlZeroMemory(ObjectCreateInfo
, sizeof(OBJECT_CREATE_INFORMATION
));
136 /* SEH everything here for protection */
139 /* Check if we got Oba */
140 if (ObjectAttributes
)
142 if (AccessMode
!= KernelMode
)
144 DPRINT("Probing OBA\n");
145 ProbeForRead(ObjectAttributes
,
146 sizeof(OBJECT_ATTRIBUTES
),
150 /* Validate the Size and Attributes */
151 DPRINT("Validating OBA\n");
152 if ((ObjectAttributes
->Length
!= sizeof(OBJECT_ATTRIBUTES
)) ||
153 (ObjectAttributes
->Attributes
& ~OBJ_VALID_ATTRIBUTES
))
155 Status
= STATUS_INVALID_PARAMETER
;
156 DPRINT1("Invalid Size: %lx or Attributes: %lx\n",
157 ObjectAttributes
->Length
, ObjectAttributes
->Attributes
);
161 /* Set some Create Info */
162 DPRINT("Creating OBCI\n");
163 ObjectCreateInfo
->RootDirectory
= ObjectAttributes
->RootDirectory
;
164 ObjectCreateInfo
->Attributes
= ObjectAttributes
->Attributes
;
165 LocalObjectName
= ObjectAttributes
->ObjectName
;
166 SecurityDescriptor
= ObjectAttributes
->SecurityDescriptor
;
167 SecurityQos
= ObjectAttributes
->SecurityQualityOfService
;
169 /* Validate the SD */
170 if (SecurityDescriptor
)
172 DPRINT("Probing SD: %x\n", SecurityDescriptor
);
173 Status
= SeCaptureSecurityDescriptor(SecurityDescriptor
,
177 &ObjectCreateInfo
->SecurityDescriptor
);
178 if(!NT_SUCCESS(Status
))
180 DPRINT1("Unable to capture the security descriptor!!!\n");
181 ObjectCreateInfo
->SecurityDescriptor
= NULL
;
185 DPRINT("Probe done\n");
186 ObjectCreateInfo
->SecurityDescriptorCharge
= 2048; /* FIXME */
187 ObjectCreateInfo
->ProbeMode
= AccessMode
;
190 /* Validate the QoS */
193 if (AccessMode
!= KernelMode
)
195 DPRINT("Probing QoS\n");
196 ProbeForRead(SecurityQos
,
197 sizeof(SECURITY_QUALITY_OF_SERVICE
),
202 ObjectCreateInfo
->SecurityQualityOfService
= *SecurityQos
;
203 ObjectCreateInfo
->SecurityQos
= &ObjectCreateInfo
->SecurityQualityOfService
;
208 LocalObjectName
= NULL
;
211 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
213 Status
= _SEH_GetExceptionCode();
219 /* Now check if the Object Attributes had an Object Name */
222 DPRINT("Name Buffer: %wZ\n", LocalObjectName
);
223 Status
= ObpCaptureObjectName(ObjectName
,
229 /* Clear the string */
230 RtlInitUnicodeString(ObjectName
, NULL
);
232 /* He can't have specified a Root Directory */
233 if (ObjectCreateInfo
->RootDirectory
)
235 DPRINT1("Invalid name\n");
236 Status
= STATUS_OBJECT_NAME_INVALID
;
241 if (!NT_SUCCESS(Status
))
243 DPRINT1("Failed to capture, cleaning up\n");
244 ObpReleaseCapturedAttributes(ObjectCreateInfo
);
247 DPRINT("Return to caller %x\n", Status
);
254 ObpReleaseCapturedAttributes(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
)
256 /* Release the SD, it's the only thing we allocated */
257 if (ObjectCreateInfo
->SecurityDescriptor
)
259 SeReleaseSecurityDescriptor(ObjectCreateInfo
->SecurityDescriptor
,
260 ObjectCreateInfo
->ProbeMode
,
262 ObjectCreateInfo
->SecurityDescriptor
= NULL
;
267 /**********************************************************************
279 * Pointer to a unicode string that will contain the
280 * remaining path if the function returns successfully.
281 * The caller must free the buffer after use by calling
282 * RtlFreeUnicodeString ().
285 * Optional pointer to an object type. This is used to
286 * descide if a symbolic link object will be parsed or not.
291 ObFindObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
292 PUNICODE_STRING ObjectName
,
293 PVOID
* ReturnedObject
,
294 PUNICODE_STRING RemainingPath
,
295 POBJECT_TYPE ObjectType
)
300 POBJECT_HEADER CurrentHeader
;
303 UNICODE_STRING PathString
;
308 DPRINT("ObFindObject(ObjectCreateInfo %x, ReturnedObject %x, "
309 "RemainingPath %x)\n",ObjectCreateInfo
,ReturnedObject
,RemainingPath
);
311 RtlInitUnicodeString (RemainingPath
, NULL
);
313 if (ObjectCreateInfo
->RootDirectory
== NULL
)
315 ObReferenceObjectByPointer(NameSpaceRoot
,
319 CurrentObject
= NameSpaceRoot
;
323 Status
= ObReferenceObjectByHandle(ObjectCreateInfo
->RootDirectory
,
329 if (!NT_SUCCESS(Status
))
335 if (ObjectName
->Length
== 0 ||
336 ObjectName
->Buffer
[0] == UNICODE_NULL
)
338 *ReturnedObject
= CurrentObject
;
339 return STATUS_SUCCESS
;
342 if (ObjectCreateInfo
->RootDirectory
== NULL
&&
343 ObjectName
->Buffer
[0] != L
'\\')
345 ObDereferenceObject (CurrentObject
);
347 return STATUS_UNSUCCESSFUL
;
350 /* Create a zero-terminated copy of the object name */
351 PathString
.Length
= ObjectName
->Length
;
352 PathString
.MaximumLength
= ObjectName
->Length
+ sizeof(WCHAR
);
353 PathString
.Buffer
= ExAllocatePool (NonPagedPool
,
354 PathString
.MaximumLength
);
355 if (PathString
.Buffer
== NULL
)
357 ObDereferenceObject (CurrentObject
);
358 return STATUS_INSUFFICIENT_RESOURCES
;
361 RtlCopyMemory (PathString
.Buffer
,
364 PathString
.Buffer
[PathString
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
366 current
= PathString
.Buffer
;
368 RootObject
= CurrentObject
;
369 Attributes
= ObjectCreateInfo
->Attributes
;
370 if (ObjectType
== ObSymbolicLinkType
)
371 Attributes
|= OBJ_OPENLINK
;
375 DPRINT("current %S\n",current
);
376 CurrentHeader
= BODY_TO_HEADER(CurrentObject
);
378 DPRINT("Current ObjectType %wZ\n",
379 &CurrentHeader
->Type
->Name
);
381 if (CurrentHeader
->Type
->TypeInfo
.ParseProcedure
== NULL
)
383 DPRINT("Current object can't parse\n");
386 Status
= CurrentHeader
->Type
->TypeInfo
.ParseProcedure(CurrentObject
,
391 if (Status
== STATUS_REPARSE
)
393 /* reparse the object path */
394 NextObject
= NameSpaceRoot
;
395 current
= PathString
.Buffer
;
397 ObReferenceObjectByPointer(NextObject
,
403 if (NextObject
== NULL
)
407 ObDereferenceObject(CurrentObject
);
408 CurrentObject
= NextObject
;
413 RtlpCreateUnicodeString (RemainingPath
, current
, NonPagedPool
);
416 RtlFreeUnicodeString (&PathString
);
417 *ReturnedObject
= CurrentObject
;
419 return STATUS_SUCCESS
;
423 /**********************************************************************
425 * ObQueryNameString@16
437 ObQueryNameString(IN PVOID Object
,
438 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
440 OUT PULONG ReturnLength
)
442 POBJECT_HEADER_NAME_INFO LocalInfo
;
443 POBJECT_HEADER ObjectHeader
;
444 PDIRECTORY_OBJECT ParentDirectory
;
449 DPRINT("ObQueryNameString: %x, %x\n", Object
, ObjectNameInfo
);
451 /* Get the Kernel Meta-Structures */
452 ObjectHeader
= BODY_TO_HEADER(Object
);
453 LocalInfo
= HEADER_TO_OBJECT_NAME(ObjectHeader
);
455 /* Check if a Query Name Procedure is available */
456 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
458 /* Call the procedure */
459 DPRINT("Calling Object's Procedure\n");
460 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
465 /* Return the status */
469 /* Check if the object doesn't even have a name */
470 if (!LocalInfo
|| !LocalInfo
->Name
.Buffer
)
472 /* We're returning the name structure */
473 DPRINT("Nameless Object\n");
474 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
476 /* Check if we were given enough space */
477 if (*ReturnLength
> Length
)
479 DPRINT1("Not enough buffer space\n");
480 return STATUS_INFO_LENGTH_MISMATCH
;
483 /* Return an empty buffer */
484 ObjectNameInfo
->Name
.Length
= 0;
485 ObjectNameInfo
->Name
.MaximumLength
= 0;
486 ObjectNameInfo
->Name
.Buffer
= NULL
;
488 return STATUS_SUCCESS
;
492 * Find the size needed for the name. We won't do
493 * this during the Name Creation loop because we want
494 * to let the caller know that the buffer isn't big
495 * enough right at the beginning, not work our way through
496 * and find out at the end
498 if (Object
== NameSpaceRoot
)
500 /* Size of the '\' string */
501 DPRINT("Object is Root\n");
502 NameSize
= sizeof(UNICODE_PATH_SEP
);
506 /* Get the Object Directory and add name of Object */
507 ParentDirectory
= LocalInfo
->Directory
;
508 NameSize
= sizeof(UNICODE_PATH_SEP
) + LocalInfo
->Name
.Length
;
510 /* Loop inside the directory to get the top-most one (meaning root) */
511 while ((ParentDirectory
!= NameSpaceRoot
) && (ParentDirectory
))
513 /* Get the Name Information */
514 LocalInfo
= HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory
));
516 /* Add the size of the Directory Name */
517 if (LocalInfo
&& LocalInfo
->Directory
)
519 /* Size of the '\' string + Directory Name */
520 NameSize
+= sizeof(UNICODE_PATH_SEP
) + LocalInfo
->Name
.Length
;
522 /* Move to next parent Directory */
523 ParentDirectory
= LocalInfo
->Directory
;
527 /* Directory with no name. We append "...\" */
528 DPRINT("Nameless Directory\n");
529 NameSize
+= sizeof(UNICODE_NO_PATH
) + sizeof(UNICODE_PATH_SEP
);
535 /* Finally, add the name of the structure and the null char */
536 *ReturnLength
= NameSize
+ sizeof(OBJECT_NAME_INFORMATION
) + sizeof(UNICODE_NULL
);
537 DPRINT("Final Length: %x\n", *ReturnLength
);
539 /* Check if we were given enough space */
540 if (*ReturnLength
> Length
)
542 DPRINT1("Not enough buffer space\n");
543 return STATUS_INFO_LENGTH_MISMATCH
;
547 * Now we will actually create the name. We work backwards because
548 * it's easier to start off from the Name we have and walk up the
549 * parent directories. We use the same logic as Name Length calculation.
551 LocalInfo
= HEADER_TO_OBJECT_NAME(ObjectHeader
);
552 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
553 *--ObjectName
= UNICODE_NULL
;
555 if (Object
== NameSpaceRoot
)
557 /* This is already the Root Directory, return "\\" */
558 DPRINT("Returning Root Dir\n");
559 *--ObjectName
= UNICODE_PATH_SEP
;
560 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
561 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
562 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
564 return STATUS_SUCCESS
;
568 /* Start by adding the Object's Name */
569 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
- LocalInfo
->Name
.Length
);
570 RtlMoveMemory(ObjectName
, LocalInfo
->Name
.Buffer
, LocalInfo
->Name
.Length
);
572 /* Now parse the Parent directories until we reach the top */
573 ParentDirectory
= LocalInfo
->Directory
;
574 while ((ParentDirectory
!= NameSpaceRoot
) && (ParentDirectory
))
576 /* Get the name information */
577 LocalInfo
= HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory
));
580 *(--ObjectName
) = UNICODE_PATH_SEP
;
582 /* Add the Parent Directory's Name */
583 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
586 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
- LocalInfo
->Name
.Length
);
587 RtlMoveMemory(ObjectName
, LocalInfo
->Name
.Buffer
, LocalInfo
->Name
.Length
);
589 /* Move to next parent */
590 ParentDirectory
= LocalInfo
->Directory
;
594 /* Directory without a name, we add "..." */
595 DPRINT("Nameless Directory\n");
596 ObjectName
-= sizeof(UNICODE_NO_PATH
);
597 ObjectName
= UNICODE_NO_PATH
;
602 /* Add Root Directory Name */
603 *(--ObjectName
) = UNICODE_PATH_SEP
;
604 DPRINT("Current Buffer: %S\n", ObjectName
);
605 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
606 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
607 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
608 DPRINT("Complete: %wZ\n", ObjectNameInfo
);
611 return STATUS_SUCCESS
;
616 ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
617 PUNICODE_STRING ObjectName
,
618 POBJECT_TYPE ObjectType
,
620 POBJECT_HEADER
*ObjectHeader
)
622 POBJECT_HEADER Header
;
623 BOOLEAN HasHandleInfo
= FALSE
;
624 BOOLEAN HasNameInfo
= FALSE
;
625 BOOLEAN HasCreatorInfo
= FALSE
;
626 POBJECT_HEADER_HANDLE_INFO HandleInfo
;
627 POBJECT_HEADER_NAME_INFO NameInfo
;
628 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
630 ULONG FinalSize
= ObjectSize
;
633 /* If we don't have an Object Type yet, force NonPaged */
634 DPRINT("ObpAllocateObject\n");
637 PoolType
= NonPagedPool
;
638 Tag
= TAG('O', 'b', 'j', 'T');
642 PoolType
= ObjectType
->TypeInfo
.PoolType
;
643 Tag
= ObjectType
->Key
;
646 DPRINT("Checking ObjectName: %x\n", ObjectName
);
647 /* Check if the Object has a name */
648 if (ObjectName
->Buffer
)
650 FinalSize
+= sizeof(OBJECT_HEADER_NAME_INFO
);
656 /* Check if the Object maintains handle counts */
657 DPRINT("Checking ObjectType->TypeInfo: %x\n", &ObjectType
->TypeInfo
);
658 if (ObjectType
->TypeInfo
.MaintainHandleCount
)
660 FinalSize
+= sizeof(OBJECT_HEADER_HANDLE_INFO
);
661 HasHandleInfo
= TRUE
;
664 /* Check if the Object maintains type lists */
665 if (ObjectType
->TypeInfo
.MaintainTypeList
)
667 FinalSize
+= sizeof(OBJECT_HEADER_CREATOR_INFO
);
668 HasCreatorInfo
= TRUE
;
672 /* Allocate memory for the Object and Header */
673 DPRINT("Allocating: %x %x\n", FinalSize
, Tag
);
674 Header
= ExAllocatePoolWithTag(PoolType
, FinalSize
, Tag
);
676 DPRINT1("Not enough memory!\n");
677 return STATUS_INSUFFICIENT_RESOURCES
;
680 /* Initialize Handle Info */
683 HandleInfo
= (POBJECT_HEADER_HANDLE_INFO
)Header
;
684 DPRINT("Info: %x\n", HandleInfo
);
685 HandleInfo
->SingleEntry
.HandleCount
= 0;
686 Header
= (POBJECT_HEADER
)(HandleInfo
+ 1);
689 /* Initialize the Object Name Info */
692 NameInfo
= (POBJECT_HEADER_NAME_INFO
)Header
;
693 DPRINT("Info: %x %wZ\n", NameInfo
, ObjectName
);
694 NameInfo
->Name
= *ObjectName
;
695 NameInfo
->Directory
= NULL
;
696 Header
= (POBJECT_HEADER
)(NameInfo
+ 1);
699 /* Initialize Creator Info */
702 CreatorInfo
= (POBJECT_HEADER_CREATOR_INFO
)Header
;
703 DPRINT("Info: %x\n", CreatorInfo
);
704 /* FIXME: Needs Alex's Init patch
705 * CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId();
707 InitializeListHead(&CreatorInfo
->TypeList
);
708 Header
= (POBJECT_HEADER
)(CreatorInfo
+ 1);
711 /* Initialize the object header */
712 RtlZeroMemory(Header
, ObjectSize
);
713 DPRINT("Initalized header %p\n", Header
);
714 Header
->HandleCount
= 0;
715 Header
->PointerCount
= 1;
716 Header
->Type
= ObjectType
;
717 Header
->Flags
= OB_FLAG_CREATE_INFO
;
719 /* Set the Offsets for the Info */
722 Header
->HandleInfoOffset
= HasNameInfo
* sizeof(OBJECT_HEADER_NAME_INFO
) +
723 sizeof(OBJECT_HEADER_HANDLE_INFO
) +
724 HasCreatorInfo
* sizeof(OBJECT_HEADER_CREATOR_INFO
);
725 Header
->Flags
|= OB_FLAG_SINGLE_PROCESS
;
729 Header
->NameInfoOffset
= sizeof(OBJECT_HEADER_NAME_INFO
) +
730 HasCreatorInfo
* sizeof(OBJECT_HEADER_CREATOR_INFO
);
732 if (HasCreatorInfo
) Header
->Flags
|= OB_FLAG_CREATOR_INFO
;
734 if (ObjectCreateInfo
&& ObjectCreateInfo
->Attributes
& OBJ_PERMANENT
)
736 Header
->Flags
|= OB_FLAG_PERMANENT
;
738 if (ObjectCreateInfo
&& ObjectCreateInfo
->Attributes
& OBJ_EXCLUSIVE
)
740 Header
->Flags
|= OB_FLAG_EXCLUSIVE
;
743 /* Link stuff to Object Header */
744 Header
->ObjectCreateInfo
= ObjectCreateInfo
;
747 *ObjectHeader
= Header
;
748 return STATUS_SUCCESS
;
751 /**********************************************************************
766 ObCreateObject(IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL
,
767 IN POBJECT_TYPE Type
,
768 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
769 IN KPROCESSOR_MODE AccessMode
,
770 IN OUT PVOID ParseContext OPTIONAL
,
772 IN ULONG PagedPoolCharge OPTIONAL
,
773 IN ULONG NonPagedPoolCharge OPTIONAL
,
777 POBJECT_CREATE_INFORMATION ObjectCreateInfo
;
778 UNICODE_STRING ObjectName
;
779 POBJECT_HEADER Header
;
781 DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n",
782 Type
, ObjectAttributes
, Object
);
784 /* Allocate a Buffer for the Object Create Info */
785 DPRINT("Allocating Create Buffer\n");
786 ObjectCreateInfo
= ExAllocatePoolWithTag(NonPagedPool
,
787 sizeof(*ObjectCreateInfo
),
788 TAG('O','b','C', 'I'));
790 /* Capture all the info */
791 DPRINT("Capturing Create Info\n");
792 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
793 ObjectAttributesAccessMode
,
798 if (NT_SUCCESS(Status
))
800 /* Allocate the Object */
801 DPRINT("Allocating: %wZ\n", &ObjectName
);
802 Status
= ObpAllocateObject(ObjectCreateInfo
,
805 OBJECT_ALLOC_SIZE(ObjectSize
),
808 if (NT_SUCCESS(Status
))
810 /* Return the Object */
811 DPRINT("Returning Object\n");
812 *Object
= &Header
->Body
;
814 /* Return to caller, leave the Capture Info Alive for ObInsert */
818 /* Release the Capture Info, we don't need it */
819 DPRINT1("Allocation failed\n");
820 ObpReleaseCapturedAttributes(ObjectCreateInfo
);
821 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
824 /* We failed, so release the Buffer */
825 DPRINT1("Capture failed\n");
826 ExFreePool(ObjectCreateInfo
);
831 * FUNCTION: Increments the pointer reference count for a given object
833 * ObjectBody = Object's body
834 * DesiredAccess = Desired access to the object
835 * ObjectType = Points to the object type structure
836 * AccessMode = Type of access check to perform
842 ObReferenceObjectByPointer(IN PVOID Object
,
843 IN ACCESS_MASK DesiredAccess
,
844 IN POBJECT_TYPE ObjectType
,
845 IN KPROCESSOR_MODE AccessMode
)
847 POBJECT_HEADER Header
;
849 /* NOTE: should be possible to reference an object above APC_LEVEL! */
851 DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
854 Header
= BODY_TO_HEADER(Object
);
856 if (ObjectType
!= NULL
&& Header
->Type
!= ObjectType
)
858 DPRINT("Failed %p (type was %x %wZ) should be %x %wZ\n",
861 &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Header
->Type
))->Name
,
863 &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ObjectType
))->Name
);
864 return(STATUS_UNSUCCESSFUL
);
866 if (Header
->Type
== PsProcessType
)
868 DPRINT("Ref p 0x%x PointerCount %d type %x ",
869 Object
, Header
->PointerCount
, PsProcessType
);
870 DPRINT("eip %x\n", ((PULONG
)&Object
)[-1]);
872 if (Header
->Type
== PsThreadType
)
874 DPRINT("Deref t 0x%x with PointerCount %d type %x ",
875 Object
, Header
->PointerCount
, PsThreadType
);
876 DPRINT("eip %x\n", ((PULONG
)&Object
)[-1]);
879 if (Header
->PointerCount
== 0 && !(Header
->Flags
& OB_FLAG_PERMANENT
))
881 if (Header
->Type
== PsProcessType
)
883 return STATUS_PROCESS_IS_TERMINATING
;
885 if (Header
->Type
== PsThreadType
)
887 return STATUS_THREAD_IS_TERMINATING
;
889 return(STATUS_UNSUCCESSFUL
);
892 if (1 == InterlockedIncrement(&Header
->PointerCount
) && !(Header
->Flags
& OB_FLAG_PERMANENT
))
897 return(STATUS_SUCCESS
);
905 ObOpenObjectByPointer(IN PVOID Object
,
906 IN ULONG HandleAttributes
,
907 IN PACCESS_STATE PassedAccessState
,
908 IN ACCESS_MASK DesiredAccess
,
909 IN POBJECT_TYPE ObjectType
,
910 IN KPROCESSOR_MODE AccessMode
,
917 DPRINT("ObOpenObjectByPointer()\n");
919 Status
= ObReferenceObjectByPointer(Object
,
923 if (!NT_SUCCESS(Status
))
928 Status
= ObpCreateHandle(PsGetCurrentProcess(),
931 (BOOLEAN
)(HandleAttributes
& OBJ_INHERIT
),
934 ObDereferenceObject(Object
);
936 return STATUS_SUCCESS
;
941 ObpDeleteObject(POBJECT_HEADER Header
)
943 PVOID HeaderLocation
= Header
;
944 POBJECT_HEADER_HANDLE_INFO HandleInfo
;
945 POBJECT_HEADER_NAME_INFO NameInfo
;
946 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
948 DPRINT("ObpDeleteObject(Header %p)\n", Header
);
949 if (KeGetCurrentIrql() != PASSIVE_LEVEL
)
951 DPRINT("ObpDeleteObject called at an unsupported IRQL. Use ObpDeleteObjectDpcLevel instead.\n");
955 if (Header
->Type
!= NULL
&&
956 Header
->Type
->TypeInfo
.DeleteProcedure
!= NULL
)
958 Header
->Type
->TypeInfo
.DeleteProcedure(&Header
->Body
);
961 if (Header
->SecurityDescriptor
!= NULL
)
963 ObpRemoveSecurityDescriptor(Header
->SecurityDescriptor
);
966 if (HEADER_TO_OBJECT_NAME(Header
))
968 if(HEADER_TO_OBJECT_NAME(Header
)->Name
.Buffer
)
970 ExFreePool(HEADER_TO_OBJECT_NAME(Header
)->Name
.Buffer
);
973 if (Header
->ObjectCreateInfo
)
975 ObpReleaseCapturedAttributes(Header
->ObjectCreateInfo
);
976 ExFreePool(Header
->ObjectCreateInfo
);
979 /* To find the header, walk backwards from how we allocated */
980 if ((CreatorInfo
= HEADER_TO_CREATOR_INFO(Header
)))
982 HeaderLocation
= CreatorInfo
;
984 if ((NameInfo
= HEADER_TO_OBJECT_NAME(Header
)))
986 HeaderLocation
= NameInfo
;
988 if ((HandleInfo
= HEADER_TO_HANDLE_INFO(Header
)))
990 HeaderLocation
= HandleInfo
;
993 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
994 ExFreePool(HeaderLocation
);
996 return(STATUS_SUCCESS
);
1001 ObpDeleteObjectWorkRoutine (IN PVOID Parameter
)
1003 PRETENTION_CHECK_PARAMS Params
= (PRETENTION_CHECK_PARAMS
)Parameter
;
1004 /* ULONG Tag; */ /* See below */
1007 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
); /* We need PAGED_CODE somewhere... */
1009 /* Turn this on when we have ExFreePoolWithTag
1010 Tag = Params->ObjectHeader->Type->Tag; */
1011 ObpDeleteObject(Params
->ObjectHeader
);
1013 /* ExFreePoolWithTag(Params, Tag); */
1018 ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader
,
1019 IN LONG OldPointerCount
)
1022 if (ObjectHeader
->PointerCount
< 0)
1024 CPRINT("Object %p/%p has invalid reference count (%d)\n",
1025 ObjectHeader
, HEADER_TO_BODY(ObjectHeader
),
1026 ObjectHeader
->PointerCount
);
1030 if (ObjectHeader
->HandleCount
< 0)
1032 CPRINT("Object %p/%p has invalid handle count (%d)\n",
1033 ObjectHeader
, HEADER_TO_BODY(ObjectHeader
),
1034 ObjectHeader
->HandleCount
);
1040 switch (KeGetCurrentIrql ())
1043 return ObpDeleteObject (ObjectHeader
);
1046 case DISPATCH_LEVEL
:
1048 PRETENTION_CHECK_PARAMS Params
;
1051 We use must succeed pool here because if the allocation fails
1052 then we leak memory.
1054 Params
= (PRETENTION_CHECK_PARAMS
)
1055 ExAllocatePoolWithTag(NonPagedPoolMustSucceed
,
1056 sizeof(RETENTION_CHECK_PARAMS
),
1057 ObjectHeader
->Type
->Key
);
1058 Params
->ObjectHeader
= ObjectHeader
;
1059 ExInitializeWorkItem(&Params
->WorkItem
,
1060 ObpDeleteObjectWorkRoutine
,
1062 ExQueueWorkItem(&Params
->WorkItem
,
1065 return STATUS_PENDING
;
1068 DPRINT("ObpDeleteObjectDpcLevel called at unsupported "
1069 "IRQL %u!\n", KeGetCurrentIrql());
1071 return STATUS_UNSUCCESSFUL
;
1074 return STATUS_SUCCESS
;
1078 /**********************************************************************
1080 * ObfReferenceObject@4
1083 * Increments a given object's reference count and performs
1087 * ObjectBody = Body of the object.
1095 ObfReferenceObject(IN PVOID Object
)
1097 POBJECT_HEADER Header
;
1101 Header
= BODY_TO_HEADER(Object
);
1103 /* No one should be referencing an object once we are deleting it. */
1104 if (InterlockedIncrement(&Header
->PointerCount
) == 1 && !(Header
->Flags
& OB_FLAG_PERMANENT
))
1111 /**********************************************************************
1113 * ObfDereferenceObject@4
1116 * Decrements a given object's reference count and performs
1120 * ObjectBody = Body of the object.
1128 ObfDereferenceObject(IN PVOID Object
)
1130 POBJECT_HEADER Header
;
1131 LONG NewPointerCount
;
1136 /* Extract the object header. */
1137 Header
= BODY_TO_HEADER(Object
);
1138 Permanent
= Header
->Flags
& OB_FLAG_PERMANENT
;
1141 Drop our reference and get the new count so we can tell if this was the
1144 NewPointerCount
= InterlockedDecrement(&Header
->PointerCount
);
1145 DPRINT("ObfDereferenceObject(0x%x)==%d\n", Object
, NewPointerCount
);
1146 ASSERT(NewPointerCount
>= 0);
1148 /* Check whether the object can now be deleted. */
1149 if (NewPointerCount
== 0 &&
1152 ObpDeleteObjectDpcLevel(Header
, NewPointerCount
);
1158 ObInitializeFastReference(IN PEX_FAST_REF FastRef
,
1161 /* FIXME: Fast Referencing is Unimplemented */
1162 FastRef
->Object
= Object
;
1168 ObFastReferenceObject(IN PEX_FAST_REF FastRef
)
1170 /* FIXME: Fast Referencing is Unimplemented */
1172 /* Do a normal Reference */
1173 ObReferenceObject(FastRef
->Object
);
1175 /* Return the Object */
1176 return FastRef
->Object
;
1181 ObFastDereferenceObject(IN PEX_FAST_REF FastRef
,
1184 /* FIXME: Fast Referencing is Unimplemented */
1186 /* Do a normal Dereference */
1187 ObDereferenceObject(FastRef
->Object
);
1192 ObFastReplaceObject(IN PEX_FAST_REF FastRef
,
1195 PVOID OldObject
= FastRef
->Object
;
1197 /* FIXME: Fast Referencing is Unimplemented */
1198 FastRef
->Object
= Object
;
1200 /* Do a normal Dereference */
1201 ObDereferenceObject(OldObject
);
1203 /* Return old Object*/
1207 /**********************************************************************
1209 * ObGetObjectPointerCount@4
1212 * Retrieves the pointer(reference) count of the given object.
1215 * ObjectBody = Body of the object.
1223 ObGetObjectPointerCount(PVOID Object
)
1225 POBJECT_HEADER Header
;
1230 Header
= BODY_TO_HEADER(Object
);
1232 return Header
->PointerCount
;
1236 /**********************************************************************
1238 * ObGetObjectHandleCount@4
1241 * Retrieves the handle count of the given object.
1244 * ObjectBody = Body of the object.
1250 ObGetObjectHandleCount(PVOID Object
)
1252 POBJECT_HEADER Header
;
1257 Header
= BODY_TO_HEADER(Object
);
1259 return Header
->HandleCount
;
1263 /**********************************************************************
1265 * ObDereferenceObject@4
1268 * Decrements a given object's reference count and performs
1272 * ObjectBody = Body of the object.
1280 #ifdef ObDereferenceObject
1281 #undef ObDereferenceObject
1285 ObDereferenceObject(IN PVOID Object
)
1287 ObfDereferenceObject(Object
);