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();
218 if (NT_SUCCESS(Status
))
220 /* Now check if the Object Attributes had an Object Name */
223 DPRINT("Name Buffer: %wZ\n", LocalObjectName
);
224 Status
= ObpCaptureObjectName(ObjectName
,
230 /* Clear the string */
231 RtlInitUnicodeString(ObjectName
, NULL
);
233 /* He can't have specified a Root Directory */
234 if (ObjectCreateInfo
->RootDirectory
)
236 DPRINT1("Invalid name\n");
237 Status
= STATUS_OBJECT_NAME_INVALID
;
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.
292 ObFindObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
293 PUNICODE_STRING ObjectName
,
294 PVOID
* ReturnedObject
,
295 PUNICODE_STRING RemainingPath
,
296 POBJECT_TYPE ObjectType
)
301 POBJECT_HEADER CurrentHeader
;
304 UNICODE_STRING PathString
;
309 DPRINT("ObFindObject(ObjectCreateInfo %x, ReturnedObject %x, "
310 "RemainingPath %x)\n",ObjectCreateInfo
,ReturnedObject
,RemainingPath
);
312 RtlInitUnicodeString (RemainingPath
, NULL
);
314 if (ObjectCreateInfo
->RootDirectory
== NULL
)
316 ObReferenceObjectByPointer(NameSpaceRoot
,
320 CurrentObject
= NameSpaceRoot
;
324 Status
= ObReferenceObjectByHandle(ObjectCreateInfo
->RootDirectory
,
330 if (!NT_SUCCESS(Status
))
336 if (ObjectName
->Length
== 0 ||
337 ObjectName
->Buffer
[0] == UNICODE_NULL
)
339 *ReturnedObject
= CurrentObject
;
340 return STATUS_SUCCESS
;
343 if (ObjectCreateInfo
->RootDirectory
== NULL
&&
344 ObjectName
->Buffer
[0] != L
'\\')
346 ObDereferenceObject (CurrentObject
);
348 return STATUS_UNSUCCESSFUL
;
351 /* Create a zero-terminated copy of the object name */
352 PathString
.Length
= ObjectName
->Length
;
353 PathString
.MaximumLength
= ObjectName
->Length
+ sizeof(WCHAR
);
354 PathString
.Buffer
= ExAllocatePool (NonPagedPool
,
355 PathString
.MaximumLength
);
356 if (PathString
.Buffer
== NULL
)
358 ObDereferenceObject (CurrentObject
);
359 return STATUS_INSUFFICIENT_RESOURCES
;
362 RtlCopyMemory (PathString
.Buffer
,
365 PathString
.Buffer
[PathString
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
367 current
= PathString
.Buffer
;
369 RootObject
= CurrentObject
;
370 Attributes
= ObjectCreateInfo
->Attributes
;
371 if (ObjectType
== ObSymbolicLinkType
)
372 Attributes
|= OBJ_OPENLINK
;
376 DPRINT("current %S\n",current
);
377 CurrentHeader
= BODY_TO_HEADER(CurrentObject
);
379 DPRINT("Current ObjectType %wZ\n",
380 &CurrentHeader
->Type
->Name
);
382 if (CurrentHeader
->Type
->TypeInfo
.ParseProcedure
== NULL
)
384 DPRINT("Current object can't parse\n");
387 Status
= CurrentHeader
->Type
->TypeInfo
.ParseProcedure(CurrentObject
,
392 if (Status
== STATUS_REPARSE
)
394 /* reparse the object path */
395 NextObject
= NameSpaceRoot
;
396 current
= PathString
.Buffer
;
398 ObReferenceObjectByPointer(NextObject
,
404 if (NextObject
== NULL
)
408 ObDereferenceObject(CurrentObject
);
409 CurrentObject
= NextObject
;
414 RtlpCreateUnicodeString (RemainingPath
, current
, NonPagedPool
);
417 RtlFreeUnicodeString (&PathString
);
418 *ReturnedObject
= CurrentObject
;
420 return STATUS_SUCCESS
;
424 /**********************************************************************
426 * ObQueryNameString@16
438 ObQueryNameString(IN PVOID Object
,
439 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
441 OUT PULONG ReturnLength
)
443 POBJECT_HEADER_NAME_INFO LocalInfo
;
444 POBJECT_HEADER ObjectHeader
;
445 PDIRECTORY_OBJECT ParentDirectory
;
450 DPRINT("ObQueryNameString: %x, %x\n", Object
, ObjectNameInfo
);
452 /* Get the Kernel Meta-Structures */
453 ObjectHeader
= BODY_TO_HEADER(Object
);
454 LocalInfo
= HEADER_TO_OBJECT_NAME(ObjectHeader
);
456 /* Check if a Query Name Procedure is available */
457 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
459 /* Call the procedure */
460 DPRINT("Calling Object's Procedure\n");
461 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
466 /* Return the status */
470 /* Check if the object doesn't even have a name */
471 if (!LocalInfo
|| !LocalInfo
->Name
.Buffer
)
473 /* We're returning the name structure */
474 DPRINT("Nameless Object\n");
475 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
477 /* Check if we were given enough space */
478 if (*ReturnLength
> Length
)
480 DPRINT1("Not enough buffer space\n");
481 return STATUS_INFO_LENGTH_MISMATCH
;
484 /* Return an empty buffer */
485 ObjectNameInfo
->Name
.Length
= 0;
486 ObjectNameInfo
->Name
.MaximumLength
= 0;
487 ObjectNameInfo
->Name
.Buffer
= NULL
;
489 return STATUS_SUCCESS
;
493 * Find the size needed for the name. We won't do
494 * this during the Name Creation loop because we want
495 * to let the caller know that the buffer isn't big
496 * enough right at the beginning, not work our way through
497 * and find out at the end
499 if (Object
== NameSpaceRoot
)
501 /* Size of the '\' string */
502 DPRINT("Object is Root\n");
503 NameSize
= sizeof(UNICODE_PATH_SEP
);
507 /* Get the Object Directory and add name of Object */
508 ParentDirectory
= LocalInfo
->Directory
;
509 NameSize
= sizeof(UNICODE_PATH_SEP
) + LocalInfo
->Name
.Length
;
511 /* Loop inside the directory to get the top-most one (meaning root) */
512 while ((ParentDirectory
!= NameSpaceRoot
) && (ParentDirectory
))
514 /* Get the Name Information */
515 LocalInfo
= HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory
));
517 /* Add the size of the Directory Name */
518 if (LocalInfo
&& LocalInfo
->Directory
)
520 /* Size of the '\' string + Directory Name */
521 NameSize
+= sizeof(UNICODE_PATH_SEP
) + LocalInfo
->Name
.Length
;
523 /* Move to next parent Directory */
524 ParentDirectory
= LocalInfo
->Directory
;
528 /* Directory with no name. We append "...\" */
529 DPRINT("Nameless Directory\n");
530 NameSize
+= sizeof(UNICODE_NO_PATH
) + sizeof(UNICODE_PATH_SEP
);
536 /* Finally, add the name of the structure and the null char */
537 *ReturnLength
= NameSize
+ sizeof(OBJECT_NAME_INFORMATION
) + sizeof(UNICODE_NULL
);
538 DPRINT("Final Length: %x\n", *ReturnLength
);
540 /* Check if we were given enough space */
541 if (*ReturnLength
> Length
)
543 DPRINT1("Not enough buffer space\n");
544 return STATUS_INFO_LENGTH_MISMATCH
;
548 * Now we will actually create the name. We work backwards because
549 * it's easier to start off from the Name we have and walk up the
550 * parent directories. We use the same logic as Name Length calculation.
552 LocalInfo
= HEADER_TO_OBJECT_NAME(ObjectHeader
);
553 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
554 *--ObjectName
= UNICODE_NULL
;
556 if (Object
== NameSpaceRoot
)
558 /* This is already the Root Directory, return "\\" */
559 DPRINT("Returning Root Dir\n");
560 *--ObjectName
= UNICODE_PATH_SEP
;
561 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
562 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
563 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
565 return STATUS_SUCCESS
;
569 /* Start by adding the Object's Name */
570 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
- LocalInfo
->Name
.Length
);
571 RtlMoveMemory(ObjectName
, LocalInfo
->Name
.Buffer
, LocalInfo
->Name
.Length
);
573 /* Now parse the Parent directories until we reach the top */
574 ParentDirectory
= LocalInfo
->Directory
;
575 while ((ParentDirectory
!= NameSpaceRoot
) && (ParentDirectory
))
577 /* Get the name information */
578 LocalInfo
= HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory
));
581 *(--ObjectName
) = UNICODE_PATH_SEP
;
583 /* Add the Parent Directory's Name */
584 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
587 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
- LocalInfo
->Name
.Length
);
588 RtlMoveMemory(ObjectName
, LocalInfo
->Name
.Buffer
, LocalInfo
->Name
.Length
);
590 /* Move to next parent */
591 ParentDirectory
= LocalInfo
->Directory
;
595 /* Directory without a name, we add "..." */
596 DPRINT("Nameless Directory\n");
597 ObjectName
-= sizeof(UNICODE_NO_PATH
);
598 ObjectName
= UNICODE_NO_PATH
;
603 /* Add Root Directory Name */
604 *(--ObjectName
) = UNICODE_PATH_SEP
;
605 DPRINT("Current Buffer: %S\n", ObjectName
);
606 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
607 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
608 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
609 DPRINT("Complete: %wZ\n", ObjectNameInfo
);
612 return STATUS_SUCCESS
;
617 ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
618 PUNICODE_STRING ObjectName
,
619 POBJECT_TYPE ObjectType
,
621 POBJECT_HEADER
*ObjectHeader
)
623 POBJECT_HEADER Header
;
624 BOOLEAN HasHandleInfo
= FALSE
;
625 BOOLEAN HasNameInfo
= FALSE
;
626 BOOLEAN HasCreatorInfo
= FALSE
;
627 POBJECT_HEADER_HANDLE_INFO HandleInfo
;
628 POBJECT_HEADER_NAME_INFO NameInfo
;
629 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
631 ULONG FinalSize
= ObjectSize
;
634 /* If we don't have an Object Type yet, force NonPaged */
635 DPRINT("ObpAllocateObject\n");
638 PoolType
= NonPagedPool
;
639 Tag
= TAG('O', 'b', 'j', 'T');
643 PoolType
= ObjectType
->TypeInfo
.PoolType
;
644 Tag
= ObjectType
->Key
;
647 DPRINT("Checking ObjectName: %x\n", ObjectName
);
648 /* Check if the Object has a name */
649 if (ObjectName
->Buffer
)
651 FinalSize
+= sizeof(OBJECT_HEADER_NAME_INFO
);
657 /* Check if the Object maintains handle counts */
658 DPRINT("Checking ObjectType->TypeInfo: %x\n", &ObjectType
->TypeInfo
);
659 if (ObjectType
->TypeInfo
.MaintainHandleCount
)
661 FinalSize
+= sizeof(OBJECT_HEADER_HANDLE_INFO
);
662 HasHandleInfo
= TRUE
;
665 /* Check if the Object maintains type lists */
666 if (ObjectType
->TypeInfo
.MaintainTypeList
)
668 FinalSize
+= sizeof(OBJECT_HEADER_CREATOR_INFO
);
669 HasCreatorInfo
= TRUE
;
673 /* Allocate memory for the Object and Header */
674 DPRINT("Allocating: %x %x\n", FinalSize
, Tag
);
675 Header
= ExAllocatePoolWithTag(PoolType
, FinalSize
, Tag
);
677 DPRINT1("Not enough memory!\n");
678 return STATUS_INSUFFICIENT_RESOURCES
;
681 /* Initialize Handle Info */
684 HandleInfo
= (POBJECT_HEADER_HANDLE_INFO
)Header
;
685 DPRINT("Info: %x\n", HandleInfo
);
686 HandleInfo
->SingleEntry
.HandleCount
= 0;
687 Header
= (POBJECT_HEADER
)(HandleInfo
+ 1);
690 /* Initialize the Object Name Info */
693 NameInfo
= (POBJECT_HEADER_NAME_INFO
)Header
;
694 DPRINT("Info: %x %wZ\n", NameInfo
, ObjectName
);
695 NameInfo
->Name
= *ObjectName
;
696 NameInfo
->Directory
= NULL
;
697 Header
= (POBJECT_HEADER
)(NameInfo
+ 1);
700 /* Initialize Creator Info */
703 CreatorInfo
= (POBJECT_HEADER_CREATOR_INFO
)Header
;
704 DPRINT("Info: %x\n", CreatorInfo
);
705 /* FIXME: Needs Alex's Init patch
706 * CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId();
708 InitializeListHead(&CreatorInfo
->TypeList
);
709 Header
= (POBJECT_HEADER
)(CreatorInfo
+ 1);
712 /* Initialize the object header */
713 RtlZeroMemory(Header
, ObjectSize
);
714 DPRINT("Initalized header %p\n", Header
);
715 Header
->HandleCount
= 0;
716 Header
->PointerCount
= 1;
717 Header
->Type
= ObjectType
;
718 Header
->Flags
= OB_FLAG_CREATE_INFO
;
720 /* Set the Offsets for the Info */
723 Header
->HandleInfoOffset
= HasNameInfo
* sizeof(OBJECT_HEADER_NAME_INFO
) +
724 sizeof(OBJECT_HEADER_HANDLE_INFO
) +
725 HasCreatorInfo
* sizeof(OBJECT_HEADER_CREATOR_INFO
);
726 Header
->Flags
|= OB_FLAG_SINGLE_PROCESS
;
730 Header
->NameInfoOffset
= sizeof(OBJECT_HEADER_NAME_INFO
) +
731 HasCreatorInfo
* sizeof(OBJECT_HEADER_CREATOR_INFO
);
733 if (HasCreatorInfo
) Header
->Flags
|= OB_FLAG_CREATOR_INFO
;
735 if (ObjectCreateInfo
&& ObjectCreateInfo
->Attributes
& OBJ_PERMANENT
)
737 Header
->Flags
|= OB_FLAG_PERMANENT
;
739 if (ObjectCreateInfo
&& ObjectCreateInfo
->Attributes
& OBJ_EXCLUSIVE
)
741 Header
->Flags
|= OB_FLAG_EXCLUSIVE
;
744 /* Link stuff to Object Header */
745 Header
->ObjectCreateInfo
= ObjectCreateInfo
;
748 *ObjectHeader
= Header
;
749 return STATUS_SUCCESS
;
752 /**********************************************************************
767 ObCreateObject(IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL
,
768 IN POBJECT_TYPE Type
,
769 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
770 IN KPROCESSOR_MODE AccessMode
,
771 IN OUT PVOID ParseContext OPTIONAL
,
773 IN ULONG PagedPoolCharge OPTIONAL
,
774 IN ULONG NonPagedPoolCharge OPTIONAL
,
778 POBJECT_CREATE_INFORMATION ObjectCreateInfo
;
779 UNICODE_STRING ObjectName
;
780 POBJECT_HEADER Header
;
782 DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n",
783 Type
, ObjectAttributes
, Object
);
785 /* Allocate a Buffer for the Object Create Info */
786 DPRINT("Allocating Create Buffer\n");
787 ObjectCreateInfo
= ExAllocatePoolWithTag(NonPagedPool
,
788 sizeof(*ObjectCreateInfo
),
789 TAG('O','b','C', 'I'));
791 /* Capture all the info */
792 DPRINT("Capturing Create Info\n");
793 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
794 ObjectAttributesAccessMode
,
799 if (NT_SUCCESS(Status
))
801 /* Allocate the Object */
802 DPRINT("Allocating: %wZ\n", &ObjectName
);
803 Status
= ObpAllocateObject(ObjectCreateInfo
,
806 OBJECT_ALLOC_SIZE(ObjectSize
),
809 if (NT_SUCCESS(Status
))
811 /* Return the Object */
812 DPRINT("Returning Object\n");
813 *Object
= &Header
->Body
;
815 /* Return to caller, leave the Capture Info Alive for ObInsert */
819 /* Release the Capture Info, we don't need it */
820 DPRINT1("Allocation failed\n");
821 ObpReleaseCapturedAttributes(ObjectCreateInfo
);
822 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
825 /* We failed, so release the Buffer */
826 DPRINT1("Capture failed\n");
827 ExFreePool(ObjectCreateInfo
);
832 * FUNCTION: Increments the pointer reference count for a given object
834 * ObjectBody = Object's body
835 * DesiredAccess = Desired access to the object
836 * ObjectType = Points to the object type structure
837 * AccessMode = Type of access check to perform
843 ObReferenceObjectByPointer(IN PVOID Object
,
844 IN ACCESS_MASK DesiredAccess
,
845 IN POBJECT_TYPE ObjectType
,
846 IN KPROCESSOR_MODE AccessMode
)
848 POBJECT_HEADER Header
;
850 /* NOTE: should be possible to reference an object above APC_LEVEL! */
852 DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
855 Header
= BODY_TO_HEADER(Object
);
857 if (ObjectType
!= NULL
&& Header
->Type
!= ObjectType
)
859 DPRINT("Failed %p (type was %x %wZ) should be %x %wZ\n",
862 &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Header
->Type
))->Name
,
864 &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ObjectType
))->Name
);
865 return(STATUS_UNSUCCESSFUL
);
867 if (Header
->Type
== PsProcessType
)
869 DPRINT("Ref p 0x%x PointerCount %d type %x ",
870 Object
, Header
->PointerCount
, PsProcessType
);
871 DPRINT("eip %x\n", ((PULONG
)&Object
)[-1]);
873 if (Header
->Type
== PsThreadType
)
875 DPRINT("Deref t 0x%x with PointerCount %d type %x ",
876 Object
, Header
->PointerCount
, PsThreadType
);
877 DPRINT("eip %x\n", ((PULONG
)&Object
)[-1]);
880 if (Header
->PointerCount
== 0 && !(Header
->Flags
& OB_FLAG_PERMANENT
))
882 if (Header
->Type
== PsProcessType
)
884 return STATUS_PROCESS_IS_TERMINATING
;
886 if (Header
->Type
== PsThreadType
)
888 return STATUS_THREAD_IS_TERMINATING
;
890 return(STATUS_UNSUCCESSFUL
);
893 if (1 == InterlockedIncrement(&Header
->PointerCount
) && !(Header
->Flags
& OB_FLAG_PERMANENT
))
898 return(STATUS_SUCCESS
);
906 ObOpenObjectByPointer(IN PVOID Object
,
907 IN ULONG HandleAttributes
,
908 IN PACCESS_STATE PassedAccessState
,
909 IN ACCESS_MASK DesiredAccess
,
910 IN POBJECT_TYPE ObjectType
,
911 IN KPROCESSOR_MODE AccessMode
,
918 DPRINT("ObOpenObjectByPointer()\n");
920 Status
= ObReferenceObjectByPointer(Object
,
924 if (!NT_SUCCESS(Status
))
929 Status
= ObpCreateHandle(PsGetCurrentProcess(),
932 (BOOLEAN
)(HandleAttributes
& OBJ_INHERIT
),
935 ObDereferenceObject(Object
);
937 return STATUS_SUCCESS
;
942 ObpDeleteObject(POBJECT_HEADER Header
)
944 PVOID HeaderLocation
= Header
;
945 POBJECT_HEADER_HANDLE_INFO HandleInfo
;
946 POBJECT_HEADER_NAME_INFO NameInfo
;
947 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
949 DPRINT("ObpDeleteObject(Header %p)\n", Header
);
950 if (KeGetCurrentIrql() != PASSIVE_LEVEL
)
952 DPRINT("ObpDeleteObject called at an unsupported IRQL. Use ObpDeleteObjectDpcLevel instead.\n");
956 if (Header
->Type
!= NULL
&&
957 Header
->Type
->TypeInfo
.DeleteProcedure
!= NULL
)
959 Header
->Type
->TypeInfo
.DeleteProcedure(&Header
->Body
);
962 if (Header
->SecurityDescriptor
!= NULL
)
964 ObpRemoveSecurityDescriptor(Header
->SecurityDescriptor
);
967 if (HEADER_TO_OBJECT_NAME(Header
))
969 if(HEADER_TO_OBJECT_NAME(Header
)->Name
.Buffer
)
971 ExFreePool(HEADER_TO_OBJECT_NAME(Header
)->Name
.Buffer
);
974 if (Header
->ObjectCreateInfo
)
976 ObpReleaseCapturedAttributes(Header
->ObjectCreateInfo
);
977 ExFreePool(Header
->ObjectCreateInfo
);
980 /* To find the header, walk backwards from how we allocated */
981 if ((CreatorInfo
= HEADER_TO_CREATOR_INFO(Header
)))
983 HeaderLocation
= CreatorInfo
;
985 if ((NameInfo
= HEADER_TO_OBJECT_NAME(Header
)))
987 HeaderLocation
= NameInfo
;
989 if ((HandleInfo
= HEADER_TO_HANDLE_INFO(Header
)))
991 HeaderLocation
= HandleInfo
;
994 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
995 ExFreePool(HeaderLocation
);
997 return(STATUS_SUCCESS
);
1002 ObpDeleteObjectWorkRoutine (IN PVOID Parameter
)
1004 PRETENTION_CHECK_PARAMS Params
= (PRETENTION_CHECK_PARAMS
)Parameter
;
1005 /* ULONG Tag; */ /* See below */
1008 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
); /* We need PAGED_CODE somewhere... */
1010 /* Turn this on when we have ExFreePoolWithTag
1011 Tag = Params->ObjectHeader->Type->Tag; */
1012 ObpDeleteObject(Params
->ObjectHeader
);
1014 /* ExFreePoolWithTag(Params, Tag); */
1019 ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader
,
1020 IN LONG OldPointerCount
)
1023 if (ObjectHeader
->PointerCount
< 0)
1025 CPRINT("Object %p/%p has invalid reference count (%d)\n",
1026 ObjectHeader
, HEADER_TO_BODY(ObjectHeader
),
1027 ObjectHeader
->PointerCount
);
1031 if (ObjectHeader
->HandleCount
< 0)
1033 CPRINT("Object %p/%p has invalid handle count (%d)\n",
1034 ObjectHeader
, HEADER_TO_BODY(ObjectHeader
),
1035 ObjectHeader
->HandleCount
);
1041 switch (KeGetCurrentIrql ())
1044 return ObpDeleteObject (ObjectHeader
);
1047 case DISPATCH_LEVEL
:
1049 PRETENTION_CHECK_PARAMS Params
;
1052 We use must succeed pool here because if the allocation fails
1053 then we leak memory.
1055 Params
= (PRETENTION_CHECK_PARAMS
)
1056 ExAllocatePoolWithTag(NonPagedPoolMustSucceed
,
1057 sizeof(RETENTION_CHECK_PARAMS
),
1058 ObjectHeader
->Type
->Key
);
1059 Params
->ObjectHeader
= ObjectHeader
;
1060 ExInitializeWorkItem(&Params
->WorkItem
,
1061 ObpDeleteObjectWorkRoutine
,
1063 ExQueueWorkItem(&Params
->WorkItem
,
1066 return STATUS_PENDING
;
1069 DPRINT("ObpDeleteObjectDpcLevel called at unsupported "
1070 "IRQL %u!\n", KeGetCurrentIrql());
1072 return STATUS_UNSUCCESSFUL
;
1075 return STATUS_SUCCESS
;
1079 /**********************************************************************
1081 * ObfReferenceObject@4
1084 * Increments a given object's reference count and performs
1088 * ObjectBody = Body of the object.
1096 ObfReferenceObject(IN PVOID Object
)
1098 POBJECT_HEADER Header
;
1102 Header
= BODY_TO_HEADER(Object
);
1104 /* No one should be referencing an object once we are deleting it. */
1105 if (InterlockedIncrement(&Header
->PointerCount
) == 1 && !(Header
->Flags
& OB_FLAG_PERMANENT
))
1112 /**********************************************************************
1114 * ObfDereferenceObject@4
1117 * Decrements a given object's reference count and performs
1121 * ObjectBody = Body of the object.
1129 ObfDereferenceObject(IN PVOID Object
)
1131 POBJECT_HEADER Header
;
1132 LONG NewPointerCount
;
1137 /* Extract the object header. */
1138 Header
= BODY_TO_HEADER(Object
);
1139 Permanent
= Header
->Flags
& OB_FLAG_PERMANENT
;
1142 Drop our reference and get the new count so we can tell if this was the
1145 NewPointerCount
= InterlockedDecrement(&Header
->PointerCount
);
1146 DPRINT("ObfDereferenceObject(0x%x)==%d\n", Object
, NewPointerCount
);
1147 ASSERT(NewPointerCount
>= 0);
1149 /* Check whether the object can now be deleted. */
1150 if (NewPointerCount
== 0 &&
1153 ObpDeleteObjectDpcLevel(Header
, NewPointerCount
);
1159 ObInitializeFastReference(IN PEX_FAST_REF FastRef
,
1162 /* FIXME: Fast Referencing is Unimplemented */
1163 FastRef
->Object
= Object
;
1169 ObFastReferenceObject(IN PEX_FAST_REF FastRef
)
1171 /* FIXME: Fast Referencing is Unimplemented */
1173 /* Do a normal Reference */
1174 ObReferenceObject(FastRef
->Object
);
1176 /* Return the Object */
1177 return FastRef
->Object
;
1182 ObFastDereferenceObject(IN PEX_FAST_REF FastRef
,
1185 /* FIXME: Fast Referencing is Unimplemented */
1187 /* Do a normal Dereference */
1188 ObDereferenceObject(FastRef
->Object
);
1193 ObFastReplaceObject(IN PEX_FAST_REF FastRef
,
1196 PVOID OldObject
= FastRef
->Object
;
1198 /* FIXME: Fast Referencing is Unimplemented */
1199 FastRef
->Object
= Object
;
1201 /* Do a normal Dereference */
1202 ObDereferenceObject(OldObject
);
1204 /* Return old Object*/
1208 /**********************************************************************
1210 * ObGetObjectPointerCount@4
1213 * Retrieves the pointer(reference) count of the given object.
1216 * ObjectBody = Body of the object.
1224 ObGetObjectPointerCount(PVOID Object
)
1226 POBJECT_HEADER Header
;
1231 Header
= BODY_TO_HEADER(Object
);
1233 return Header
->PointerCount
;
1237 /**********************************************************************
1239 * ObGetObjectHandleCount@4
1242 * Retrieves the handle count of the given object.
1245 * ObjectBody = Body of the object.
1252 ObGetObjectHandleCount(PVOID Object
)
1254 POBJECT_HEADER Header
;
1259 Header
= BODY_TO_HEADER(Object
);
1261 return Header
->HandleCount
;
1265 /**********************************************************************
1267 * ObDereferenceObject@4
1270 * Decrements a given object's reference count and performs
1274 * ObjectBody = Body of the object.
1282 #ifdef ObDereferenceObject
1283 #undef ObDereferenceObject
1287 ObDereferenceObject(IN PVOID Object
)
1289 ObfDereferenceObject(Object
);