2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/oblife.c
5 * PURPOSE: Manages the lifetime of an Object, including its creation,
6 * and deletion, as well as setting or querying any of its
7 * information while it is active. Since Object Types are also
8 * Objects, those are also managed here.
9 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
11 * Thomas Weidenmueller (w3seek@reactos.org)
14 /* INCLUDES ******************************************************************/
20 extern ULONG NtGlobalFlag
;
22 POBJECT_TYPE ObpTypeObjectType
= NULL
;
23 KEVENT ObpDefaultObject
;
25 GENERAL_LOOKASIDE ObpNameBufferLookasideList
, ObpCreateInfoLookasideList
;
27 WORK_QUEUE_ITEM ObpReaperWorkItem
;
28 volatile PVOID ObpReaperList
;
30 ULONG ObpObjectsCreated
, ObpObjectsWithName
, ObpObjectsWithPoolQuota
;
31 ULONG ObpObjectsWithHandleDB
, ObpObjectsWithCreatorInfo
;
32 POBJECT_TYPE ObpObjectTypes
[32];
34 /* PRIVATE FUNCTIONS *********************************************************/
38 ObpDeallocateObject(IN PVOID Object
)
41 POBJECT_HEADER Header
;
42 POBJECT_TYPE ObjectType
;
43 POBJECT_HEADER_HANDLE_INFO HandleInfo
;
44 POBJECT_HEADER_NAME_INFO NameInfo
;
45 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
46 POBJECT_HEADER_QUOTA_INFO QuotaInfo
;
47 ULONG PagedPoolCharge
, NonPagedPoolCharge
;
50 /* Get the header and assume this is what we'll free */
51 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
52 ObjectType
= Header
->Type
;
53 HeaderLocation
= Header
;
55 /* To find the header, walk backwards from how we allocated */
56 if ((CreatorInfo
= OBJECT_HEADER_TO_CREATOR_INFO(Header
)))
58 HeaderLocation
= CreatorInfo
;
60 if ((NameInfo
= OBJECT_HEADER_TO_NAME_INFO(Header
)))
62 HeaderLocation
= NameInfo
;
64 if ((HandleInfo
= OBJECT_HEADER_TO_HANDLE_INFO(Header
)))
66 HeaderLocation
= HandleInfo
;
68 if ((QuotaInfo
= OBJECT_HEADER_TO_QUOTA_INFO(Header
)))
70 HeaderLocation
= QuotaInfo
;
73 /* Decrease the total */
74 InterlockedDecrement((PLONG
)&ObjectType
->TotalNumberOfObjects
);
76 /* Check if we have create info */
77 if (Header
->Flags
& OB_FLAG_CREATE_INFO
)
79 /* Double-check that it exists */
80 if (Header
->ObjectCreateInfo
)
83 ObpFreeObjectCreateInformation(Header
->ObjectCreateInfo
);
84 Header
->ObjectCreateInfo
= NULL
;
89 /* Check if it has a quota block */
90 if (Header
->QuotaBlockCharged
)
92 /* Check if we have quota information */
95 /* Get charges from quota information */
96 PagedPoolCharge
= QuotaInfo
->PagedPoolCharge
+
97 QuotaInfo
->SecurityDescriptorCharge
;
98 NonPagedPoolCharge
= QuotaInfo
->NonPagedPoolCharge
;
102 /* Get charges from object type */
103 PagedPoolCharge
= ObjectType
->TypeInfo
.DefaultPagedPoolCharge
;
104 NonPagedPoolCharge
= ObjectType
->
105 TypeInfo
.DefaultNonPagedPoolCharge
;
107 /* Add the SD charge too */
108 if (Header
->Flags
& OB_FLAG_SECURITY
) PagedPoolCharge
+= 2048;
113 /* Check if a handle database was active */
114 if ((HandleInfo
) && !(Header
->Flags
& OB_FLAG_SINGLE_PROCESS
))
117 ExFreePool(HandleInfo
->HandleCountDatabase
);
118 HandleInfo
->HandleCountDatabase
= NULL
;
121 /* Check if we have a name */
122 if ((NameInfo
) && (NameInfo
->Name
.Buffer
))
125 ExFreePool(NameInfo
->Name
.Buffer
);
126 NameInfo
->Name
.Buffer
= NULL
;
129 /* Catch invalid access */
130 Header
->Type
= (POBJECT_TYPE
)0xBAADB0B0;
132 /* Free the object using the same allocation tag */
133 ExFreePoolWithTag(HeaderLocation
, ObjectType
->Key
);
138 ObpDeleteObject(IN PVOID Object
,
139 IN BOOLEAN CalledFromWorkerThread
)
141 POBJECT_HEADER Header
;
142 POBJECT_TYPE ObjectType
;
143 POBJECT_HEADER_NAME_INFO NameInfo
;
144 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
148 /* Get the header and type */
149 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
150 ObjectType
= Header
->Type
;
152 /* Get creator and name information */
153 NameInfo
= OBJECT_HEADER_TO_NAME_INFO(Header
);
154 CreatorInfo
= OBJECT_HEADER_TO_CREATOR_INFO(Header
);
156 /* Check if the object is on a type list */
157 if ((CreatorInfo
) && !(IsListEmpty(&CreatorInfo
->TypeList
)))
159 /* Lock the object type */
160 ObpEnterObjectTypeMutex(ObjectType
);
162 /* Remove the object from the type list */
163 RemoveEntryList(&CreatorInfo
->TypeList
);
165 /* Release the lock */
166 ObpLeaveObjectTypeMutex(ObjectType
);
169 /* Check if we have a name */
170 if ((NameInfo
) && (NameInfo
->Name
.Buffer
))
173 ExFreePool(NameInfo
->Name
.Buffer
);
174 RtlInitEmptyUnicodeString(&NameInfo
->Name
, NULL
, 0);
177 /* Check if we have a security descriptor */
178 if (Header
->SecurityDescriptor
)
180 /* Call the security procedure to delete it */
181 ObpCalloutStart(&CalloutIrql
);
182 ObjectType
->TypeInfo
.SecurityProcedure(Object
,
183 DeleteSecurityDescriptor
,
187 &Header
->SecurityDescriptor
,
190 ObpCalloutEnd(CalloutIrql
, "Security", ObjectType
, Object
);
193 /* Check if we have a delete procedure */
194 if (ObjectType
->TypeInfo
.DeleteProcedure
)
196 /* Save whether we were deleted from worker thread or not */
197 if (!CalledFromWorkerThread
) Header
->Flags
|= OB_FLAG_DEFER_DELETE
;
200 ObpCalloutStart(&CalloutIrql
);
201 ObjectType
->TypeInfo
.DeleteProcedure(Object
);
202 ObpCalloutEnd(CalloutIrql
, "Delete", ObjectType
, Object
);
205 /* Now de-allocate all object members */
206 ObpDeallocateObject(Object
);
211 ObpReapObject(IN PVOID Parameter
)
213 POBJECT_HEADER ReapObject
, NextObject
;
218 /* Get the reap object */
219 ReapObject
= InterlockedExchangePointer(&ObpReaperList
, (PVOID
)1);
221 /* Start deletion loop */
224 /* Get the next object */
225 NextObject
= ReapObject
->NextToFree
;
227 /* Delete the object */
228 ObpDeleteObject(&ReapObject
->Body
, TRUE
);
230 /* Move to the next one */
231 ReapObject
= NextObject
;
232 } while ((ReapObject
) && (ReapObject
!= (PVOID
)1));
233 } while ((ObpReaperList
!= (PVOID
)1) ||
234 (InterlockedCompareExchange((PLONG
)&ObpReaperList
, 0, 1) != 1));
238 * @name ObpSetPermanentObject
240 * The ObpSetPermanentObject routine makes an sets or clears the permanent
241 * flag of an object, thus making it either permanent or temporary.
244 * Pointer to the object to make permanent or temporary.
247 * Flag specifying which operation to perform.
251 * @remarks If the object is being made temporary, then it will be checked
252 * as a candidate for immediate removal from the namespace.
257 ObpSetPermanentObject(IN PVOID ObjectBody
,
258 IN BOOLEAN Permanent
)
260 POBJECT_HEADER ObjectHeader
;
263 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(ObjectBody
);
265 /* Acquire object lock */
266 ObpAcquireObjectLock(ObjectHeader
);
268 /* Check what we're doing to it */
271 /* Set it to permanent */
272 ObjectHeader
->Flags
|= OB_FLAG_PERMANENT
;
274 /* Release the lock */
275 ObpReleaseObjectLock(ObjectHeader
);
279 /* Remove the flag */
280 ObjectHeader
->Flags
&= ~OB_FLAG_PERMANENT
;
282 /* Release the lock */
283 ObpReleaseObjectLock(ObjectHeader
);
285 /* Check if we should delete the object now */
286 ObpDeleteNameCheck(ObjectBody
);
292 ObpAllocateObjectNameBuffer(IN ULONG Length
,
293 IN BOOLEAN UseLookaside
,
294 IN OUT PUNICODE_STRING ObjectName
)
299 /* Set the maximum length to the length plus the terminator */
300 MaximumLength
= Length
+ sizeof(UNICODE_NULL
);
302 /* Check if we should use the lookaside buffer */
303 if (!(UseLookaside
) || (MaximumLength
> OBP_NAME_LOOKASIDE_MAX_SIZE
))
305 /* Nope, allocate directly from pool */
306 /* Since we later use MaximumLength to detect that we're not allocating
307 * from a list, we need at least MaximumLength + sizeof(UNICODE_NULL)
310 * People do call this with UseLookasideList FALSE so the distinction
313 if (MaximumLength
<= OBP_NAME_LOOKASIDE_MAX_SIZE
)
315 MaximumLength
= OBP_NAME_LOOKASIDE_MAX_SIZE
+ sizeof(UNICODE_NULL
);
317 Buffer
= ExAllocatePoolWithTag(PagedPool
,
323 /* Allocate from the lookaside */
324 MaximumLength
= OBP_NAME_LOOKASIDE_MAX_SIZE
;
325 Buffer
= ObpAllocateObjectCreateInfoBuffer(LookasideNameBufferList
);
328 /* Setup the string */
329 ObjectName
->MaximumLength
= (USHORT
)MaximumLength
;
330 ObjectName
->Length
= (USHORT
)Length
;
331 ObjectName
->Buffer
= Buffer
;
337 ObpFreeObjectNameBuffer(IN PUNICODE_STRING Name
)
339 PVOID Buffer
= Name
->Buffer
;
341 /* We know this is a pool-allocation if the size doesn't match */
342 if (Name
->MaximumLength
!= OBP_NAME_LOOKASIDE_MAX_SIZE
)
344 /* Free it from the pool */
349 /* Otherwise, free from the lookaside */
350 ObpFreeCapturedAttributes(Buffer
, LookasideNameBufferList
);
356 ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName
,
357 IN PUNICODE_STRING ObjectName
,
358 IN KPROCESSOR_MODE AccessMode
,
359 IN BOOLEAN UseLookaside
)
361 NTSTATUS Status
= STATUS_SUCCESS
;
363 PWCHAR StringBuffer
= NULL
;
364 UNICODE_STRING LocalName
;
367 /* Initialize the Input String */
368 RtlInitEmptyUnicodeString(CapturedName
, NULL
, 0);
370 /* Protect everything */
373 /* Check if we came from user mode */
374 if (AccessMode
!= KernelMode
)
376 /* First Probe the String */
377 LocalName
= ProbeForReadUnicodeString(ObjectName
);
378 ProbeForRead(LocalName
.Buffer
, LocalName
.Length
, sizeof(WCHAR
));
382 /* No probing needed */
383 LocalName
= *ObjectName
;
386 /* Make sure there really is a string */
387 if ((StringLength
= LocalName
.Length
))
389 /* Check that the size is a valid WCHAR multiple */
390 if ((StringLength
& (sizeof(WCHAR
) - 1)) ||
391 /* Check that the NULL-termination below will work */
392 (StringLength
== (MAXUSHORT
- sizeof(UNICODE_NULL
) + 1)))
394 /* PS: Please keep the checks above expanded for clarity */
395 Status
= STATUS_OBJECT_NAME_INVALID
;
399 /* Allocate the string buffer */
400 StringBuffer
= ObpAllocateObjectNameBuffer(StringLength
,
405 /* Set failure code */
406 Status
= STATUS_INSUFFICIENT_RESOURCES
;
411 RtlCopyMemory(StringBuffer
, LocalName
.Buffer
, StringLength
);
412 StringBuffer
[StringLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
417 _SEH2_EXCEPT(ExSystemExceptionFilter())
419 /* Handle exception and free the string buffer */
420 Status
= _SEH2_GetExceptionCode();
423 ObpFreeObjectNameBuffer(CapturedName
);
434 ObpCaptureObjectCreateInformation(IN POBJECT_ATTRIBUTES ObjectAttributes
,
435 IN KPROCESSOR_MODE AccessMode
,
436 IN BOOLEAN AllocateFromLookaside
,
437 IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
438 OUT PUNICODE_STRING ObjectName
)
440 NTSTATUS Status
= STATUS_SUCCESS
;
441 PSECURITY_DESCRIPTOR SecurityDescriptor
;
442 PSECURITY_QUALITY_OF_SERVICE SecurityQos
;
443 PUNICODE_STRING LocalObjectName
= NULL
;
446 /* Zero out the Capture Data */
447 RtlZeroMemory(ObjectCreateInfo
, sizeof(OBJECT_CREATE_INFORMATION
));
449 /* SEH everything here for protection */
452 /* Check if we got attributes */
453 if (ObjectAttributes
)
455 /* Check if we're in user mode */
456 if (AccessMode
!= KernelMode
)
458 /* Probe the attributes */
459 ProbeForRead(ObjectAttributes
,
460 sizeof(OBJECT_ATTRIBUTES
),
464 /* Validate the Size and Attributes */
465 if ((ObjectAttributes
->Length
!= sizeof(OBJECT_ATTRIBUTES
)) ||
466 (ObjectAttributes
->Attributes
& ~OBJ_VALID_ATTRIBUTES
))
468 /* Invalid combination, fail */
469 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
472 /* Set some Create Info */
473 ObjectCreateInfo
->RootDirectory
= ObjectAttributes
->RootDirectory
;
474 ObjectCreateInfo
->Attributes
= ObjectAttributes
->Attributes
;
475 LocalObjectName
= ObjectAttributes
->ObjectName
;
476 SecurityDescriptor
= ObjectAttributes
->SecurityDescriptor
;
477 SecurityQos
= ObjectAttributes
->SecurityQualityOfService
;
479 /* Check if we have a security descriptor */
480 if (SecurityDescriptor
)
483 Status
= SeCaptureSecurityDescriptor(SecurityDescriptor
,
489 if (!NT_SUCCESS(Status
))
491 /* Capture failed, quit */
492 ObjectCreateInfo
->SecurityDescriptor
= NULL
;
493 _SEH2_YIELD(return Status
);
496 /* Save the probe mode and security descriptor size */
497 ObjectCreateInfo
->SecurityDescriptorCharge
= 2048; /* FIXME */
498 ObjectCreateInfo
->ProbeMode
= AccessMode
;
501 /* Check if we have QoS */
504 /* Check if we came from user mode */
505 if (AccessMode
!= KernelMode
)
507 /* Validate the QoS */
508 ProbeForRead(SecurityQos
,
509 sizeof(SECURITY_QUALITY_OF_SERVICE
),
514 ObjectCreateInfo
->SecurityQualityOfService
= *SecurityQos
;
515 ObjectCreateInfo
->SecurityQos
=
516 &ObjectCreateInfo
->SecurityQualityOfService
;
521 /* We don't have a name */
522 LocalObjectName
= NULL
;
525 _SEH2_EXCEPT(ExSystemExceptionFilter())
527 /* Cleanup and return the exception code */
528 ObpReleaseObjectCreateInformation(ObjectCreateInfo
);
529 _SEH2_YIELD(return _SEH2_GetExceptionCode());
533 /* Now check if the Object Attributes had an Object Name */
536 Status
= ObpCaptureObjectName(ObjectName
,
539 AllocateFromLookaside
);
543 /* Clear the string */
544 RtlInitEmptyUnicodeString(ObjectName
, NULL
, 0);
546 /* He can't have specified a Root Directory */
547 if (ObjectCreateInfo
->RootDirectory
)
549 Status
= STATUS_OBJECT_NAME_INVALID
;
553 /* Cleanup if we failed */
554 if (!NT_SUCCESS(Status
))
556 ObpReleaseObjectCreateInformation(ObjectCreateInfo
);
559 /* Return status to caller */
565 ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
)
567 /* Call the macro. We use this function to isolate Ob internals from Io */
568 ObpFreeCapturedAttributes(ObjectCreateInfo
, LookasideCreateInfoList
);
573 ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
574 IN PUNICODE_STRING ObjectName
,
575 IN POBJECT_TYPE ObjectType
,
577 IN KPROCESSOR_MODE PreviousMode
,
578 IN POBJECT_HEADER
*ObjectHeader
)
580 POBJECT_HEADER Header
;
581 ULONG QuotaSize
, HandleSize
, NameSize
, CreatorSize
;
582 POBJECT_HEADER_HANDLE_INFO HandleInfo
;
583 POBJECT_HEADER_NAME_INFO NameInfo
;
584 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
585 POBJECT_HEADER_QUOTA_INFO QuotaInfo
;
594 /* Check if we don't have an Object Type yet */
597 /* Use default tag and non-paged pool */
598 PoolType
= NonPagedPool
;
603 /* Use the pool and tag given */
604 PoolType
= ObjectType
->TypeInfo
.PoolType
;
605 Tag
= ObjectType
->Key
;
608 /* Check if we have no create information (ie: we're an object type) */
609 if (!ObjectCreateInfo
)
612 QuotaSize
= HandleSize
= 0;
613 NameSize
= sizeof(OBJECT_HEADER_NAME_INFO
);
614 CreatorSize
= sizeof(OBJECT_HEADER_CREATOR_INFO
);
618 /* Check if we have quota */
619 if ((((ObjectCreateInfo
->PagedPoolCharge
!=
620 ObjectType
->TypeInfo
.DefaultPagedPoolCharge
) ||
621 (ObjectCreateInfo
->NonPagedPoolCharge
!=
622 ObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
) ||
623 (ObjectCreateInfo
->SecurityDescriptorCharge
> 2048)) &&
624 (PsGetCurrentProcess() != PsInitialSystemProcess
)) ||
625 (ObjectCreateInfo
->Attributes
& OBJ_EXCLUSIVE
))
628 QuotaSize
= sizeof(OBJECT_HEADER_QUOTA_INFO
);
629 ObpObjectsWithPoolQuota
++;
637 /* Check if we have a handle database */
638 if (ObjectType
->TypeInfo
.MaintainHandleCount
)
640 /* Set handle database size */
641 HandleSize
= sizeof(OBJECT_HEADER_HANDLE_INFO
);
642 ObpObjectsWithHandleDB
++;
650 /* Check if the Object has a name */
651 if (ObjectName
->Buffer
)
654 NameSize
= sizeof(OBJECT_HEADER_NAME_INFO
);
655 ObpObjectsWithName
++;
663 /* Check if the Object maintains type lists */
664 if (ObjectType
->TypeInfo
.MaintainTypeList
)
666 /* Set owner/creator size */
667 CreatorSize
= sizeof(OBJECT_HEADER_CREATOR_INFO
);
668 ObpObjectsWithCreatorInfo
++;
677 /* Set final header size */
678 FinalSize
= QuotaSize
+
682 FIELD_OFFSET(OBJECT_HEADER
, Body
);
684 /* Allocate memory for the Object and Header */
685 Header
= ExAllocatePoolWithTag(PoolType
, FinalSize
+ ObjectSize
, Tag
);
686 if (!Header
) return STATUS_INSUFFICIENT_RESOURCES
;
688 /* Check if we have a quota header */
691 /* Initialize quota info */
692 QuotaInfo
= (POBJECT_HEADER_QUOTA_INFO
)Header
;
693 QuotaInfo
->PagedPoolCharge
= ObjectCreateInfo
->PagedPoolCharge
;
694 QuotaInfo
->NonPagedPoolCharge
= ObjectCreateInfo
->NonPagedPoolCharge
;
695 QuotaInfo
->SecurityDescriptorCharge
= ObjectCreateInfo
->SecurityDescriptorCharge
;
696 QuotaInfo
->ExclusiveProcess
= NULL
;
697 Header
= (POBJECT_HEADER
)(QuotaInfo
+ 1);
700 /* Check if we have a handle database header */
703 /* Initialize Handle Info */
704 HandleInfo
= (POBJECT_HEADER_HANDLE_INFO
)Header
;
705 HandleInfo
->SingleEntry
.HandleCount
= 0;
706 Header
= (POBJECT_HEADER
)(HandleInfo
+ 1);
709 /* Check if we have a name header */
712 /* Initialize the Object Name Info */
713 NameInfo
= (POBJECT_HEADER_NAME_INFO
)Header
;
714 NameInfo
->Name
= *ObjectName
;
715 NameInfo
->Directory
= NULL
;
716 NameInfo
->QueryReferences
= 1;
718 /* Check if this is a call with the special protection flag */
719 if ((PreviousMode
== KernelMode
) &&
720 (ObjectCreateInfo
) &&
721 (ObjectCreateInfo
->Attributes
& 0x10000))
723 /* Set flag which will make the object protected from user-mode */
724 NameInfo
->QueryReferences
|= 0x40000000;
727 /* Set the header pointer */
728 Header
= (POBJECT_HEADER
)(NameInfo
+ 1);
731 /* Check if we have a creator header */
734 /* Initialize Creator Info */
735 CreatorInfo
= (POBJECT_HEADER_CREATOR_INFO
)Header
;
736 CreatorInfo
->CreatorBackTraceIndex
= 0;
737 CreatorInfo
->CreatorUniqueProcess
= PsGetCurrentProcessId();
738 InitializeListHead(&CreatorInfo
->TypeList
);
739 Header
= (POBJECT_HEADER
)(CreatorInfo
+ 1);
742 /* Check for quota information */
746 Header
->QuotaInfoOffset
= (UCHAR
)(QuotaSize
+
754 Header
->QuotaInfoOffset
= 0;
757 /* Check for handle information */
761 Header
->HandleInfoOffset
= (UCHAR
)(HandleSize
+
768 Header
->HandleInfoOffset
= 0;
771 /* Check for name information */
775 Header
->NameInfoOffset
= (UCHAR
)(NameSize
+ CreatorSize
);
780 Header
->NameInfoOffset
= 0;
783 /* Set the new object flag */
784 Header
->Flags
= OB_FLAG_CREATE_INFO
;
786 /* Remember if we have creator info */
787 if (CreatorSize
) Header
->Flags
|= OB_FLAG_CREATOR_INFO
;
789 /* Remember if we have handle info */
790 if (HandleSize
) Header
->Flags
|= OB_FLAG_SINGLE_PROCESS
;
792 /* Initialize the object header */
793 Header
->PointerCount
= 1;
794 Header
->HandleCount
= 0;
795 Header
->Type
= ObjectType
;
796 Header
->ObjectCreateInfo
= ObjectCreateInfo
;
797 Header
->SecurityDescriptor
= NULL
;
799 /* Check if this is a permanent object */
800 if ((ObjectCreateInfo
) && (ObjectCreateInfo
->Attributes
& OBJ_PERMANENT
))
802 /* Set the needed flag so we can check */
803 Header
->Flags
|= OB_FLAG_PERMANENT
;
806 /* Check if this is an exclusive object */
807 if ((ObjectCreateInfo
) && (ObjectCreateInfo
->Attributes
& OBJ_EXCLUSIVE
))
809 /* Set the needed flag so we can check */
810 Header
->Flags
|= OB_FLAG_EXCLUSIVE
;
813 /* Set kernel-mode flag */
814 if (PreviousMode
== KernelMode
) Header
->Flags
|= OB_FLAG_KERNEL_MODE
;
816 /* Check if we have a type */
819 /* Increase the number of objects of this type */
820 InterlockedIncrement((PLONG
)&ObjectType
->TotalNumberOfObjects
);
822 /* Update the high water */
823 ObjectType
->HighWaterNumberOfObjects
= max(ObjectType
->
824 TotalNumberOfObjects
,
826 HighWaterNumberOfObjects
);
830 *ObjectHeader
= Header
;
831 return STATUS_SUCCESS
;
836 ObQueryTypeInfo(IN POBJECT_TYPE ObjectType
,
837 OUT POBJECT_TYPE_INFORMATION ObjectTypeInfo
,
839 OUT PULONG ReturnLength
)
841 NTSTATUS Status
= STATUS_SUCCESS
;
847 /* Set return length aligned to 4-byte boundary */
848 *ReturnLength
+= sizeof(*ObjectTypeInfo
) +
849 ALIGN_UP(ObjectType
->Name
.MaximumLength
, ULONG
);
851 /* Check if thats too much though. */
852 if (Length
< *ReturnLength
)
854 _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
858 ObjectTypeInfo
->TotalNumberOfHandles
=
859 ObjectType
->TotalNumberOfHandles
;
860 ObjectTypeInfo
->TotalNumberOfObjects
=
861 ObjectType
->TotalNumberOfObjects
;
862 ObjectTypeInfo
->HighWaterNumberOfHandles
=
863 ObjectType
->HighWaterNumberOfHandles
;
864 ObjectTypeInfo
->HighWaterNumberOfObjects
=
865 ObjectType
->HighWaterNumberOfObjects
;
866 ObjectTypeInfo
->PoolType
=
867 ObjectType
->TypeInfo
.PoolType
;
868 ObjectTypeInfo
->DefaultNonPagedPoolCharge
=
869 ObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
;
870 ObjectTypeInfo
->DefaultPagedPoolCharge
=
871 ObjectType
->TypeInfo
.DefaultPagedPoolCharge
;
872 ObjectTypeInfo
->ValidAccessMask
=
873 ObjectType
->TypeInfo
.ValidAccessMask
;
874 ObjectTypeInfo
->SecurityRequired
=
875 ObjectType
->TypeInfo
.SecurityRequired
;
876 ObjectTypeInfo
->InvalidAttributes
=
877 ObjectType
->TypeInfo
.InvalidAttributes
;
878 ObjectTypeInfo
->GenericMapping
=
879 ObjectType
->TypeInfo
.GenericMapping
;
880 ObjectTypeInfo
->MaintainHandleCount
=
881 ObjectType
->TypeInfo
.MaintainHandleCount
;
883 /* Setup the name buffer */
884 InfoBuffer
= (PWSTR
)(ObjectTypeInfo
+ 1);
885 ObjectTypeInfo
->TypeName
.Buffer
= InfoBuffer
;
886 ObjectTypeInfo
->TypeName
.MaximumLength
= ObjectType
->Name
.MaximumLength
;
887 ObjectTypeInfo
->TypeName
.Length
= ObjectType
->Name
.Length
;
890 RtlCopyMemory(InfoBuffer
,
891 ObjectType
->Name
.Buffer
,
892 ObjectType
->Name
.Length
);
894 /* Null-terminate it */
895 (InfoBuffer
)[ObjectType
->Name
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
897 _SEH2_EXCEPT(ExSystemExceptionFilter())
899 /* Otherwise, get the exception code */
900 Status
= _SEH2_GetExceptionCode();
904 /* Return status to caller */
909 /* PUBLIC FUNCTIONS **********************************************************/
913 ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL
,
914 IN POBJECT_TYPE Type
,
915 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
916 IN KPROCESSOR_MODE AccessMode
,
917 IN OUT PVOID ParseContext OPTIONAL
,
919 IN ULONG PagedPoolCharge OPTIONAL
,
920 IN ULONG NonPagedPoolCharge OPTIONAL
,
924 POBJECT_CREATE_INFORMATION ObjectCreateInfo
;
925 UNICODE_STRING ObjectName
;
926 POBJECT_HEADER Header
;
928 /* Allocate a capture buffer */
929 ObjectCreateInfo
= ObpAllocateObjectCreateInfoBuffer(LookasideCreateInfoList
);
930 if (!ObjectCreateInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
932 /* Capture all the info */
933 Status
= ObpCaptureObjectCreateInformation(ObjectAttributes
,
938 if (NT_SUCCESS(Status
))
940 /* Validate attributes */
941 if (Type
->TypeInfo
.InvalidAttributes
& ObjectCreateInfo
->Attributes
)
944 Status
= STATUS_INVALID_PARAMETER
;
948 /* Check if we have a paged charge */
949 if (!PagedPoolCharge
)
952 PagedPoolCharge
= Type
->TypeInfo
.DefaultPagedPoolCharge
;
955 /* Check for nonpaged charge */
956 if (!NonPagedPoolCharge
)
959 NonPagedPoolCharge
= Type
->TypeInfo
.DefaultNonPagedPoolCharge
;
962 /* Write the pool charges */
963 ObjectCreateInfo
->PagedPoolCharge
= PagedPoolCharge
;
964 ObjectCreateInfo
->NonPagedPoolCharge
= NonPagedPoolCharge
;
966 /* Allocate the Object */
967 Status
= ObpAllocateObject(ObjectCreateInfo
,
973 if (NT_SUCCESS(Status
))
975 /* Return the Object */
976 *Object
= &Header
->Body
;
978 /* Check if this is a permanent object */
979 if (Header
->Flags
& OB_FLAG_PERMANENT
)
981 /* Do the privilege check */
982 if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege
,
986 ObpDeallocateObject(*Object
);
987 Status
= STATUS_PRIVILEGE_NOT_HELD
;
996 /* Release the Capture Info, we don't need it */
997 ObpFreeObjectCreateInformation(ObjectCreateInfo
);
998 if (ObjectName
.Buffer
) ObpFreeObjectNameBuffer(&ObjectName
);
1001 /* We failed, so release the Buffer */
1002 ObpFreeCapturedAttributes(ObjectCreateInfo
, LookasideCreateInfoList
);
1008 ObCreateObjectType(IN PUNICODE_STRING TypeName
,
1009 IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer
,
1011 OUT POBJECT_TYPE
*ObjectType
)
1013 POBJECT_HEADER Header
;
1014 POBJECT_TYPE LocalObjectType
;
1018 OBP_LOOKUP_CONTEXT Context
;
1021 UNICODE_STRING ObjectName
;
1022 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
1024 /* Verify parameters */
1026 !(TypeName
->Length
) ||
1027 (TypeName
->Length
% sizeof(WCHAR
)) ||
1028 !(ObjectTypeInitializer
) ||
1029 (ObjectTypeInitializer
->Length
!= sizeof(*ObjectTypeInitializer
)) ||
1030 (ObjectTypeInitializer
->InvalidAttributes
& ~OBJ_VALID_ATTRIBUTES
) ||
1031 (ObjectTypeInitializer
->MaintainHandleCount
&&
1032 (!(ObjectTypeInitializer
->OpenProcedure
) &&
1033 !ObjectTypeInitializer
->CloseProcedure
)) ||
1034 ((!ObjectTypeInitializer
->UseDefaultObject
) &&
1035 (ObjectTypeInitializer
->PoolType
!= NonPagedPool
)))
1038 return STATUS_INVALID_PARAMETER
;
1041 /* Make sure the name doesn't have a separator */
1042 p
= TypeName
->Buffer
;
1043 i
= TypeName
->Length
/ sizeof(WCHAR
);
1046 /* Check for one and fail */
1047 if (*p
++ == OBJ_NAME_PATH_SEPARATOR
) return STATUS_OBJECT_NAME_INVALID
;
1050 /* Setup a lookup context */
1051 ObpInitializeLookupContext(&Context
);
1053 /* Check if we've already created the directory of types */
1054 if (ObpTypeDirectoryObject
)
1056 /* Acquire the directory lock */
1057 ObpAcquireDirectoryLockExclusive(ObpTypeDirectoryObject
, &Context
);
1060 if (ObpLookupEntryDirectory(ObpTypeDirectoryObject
,
1062 OBJ_CASE_INSENSITIVE
,
1066 /* We have already created it, so fail */
1067 ObpReleaseLookupContext(&Context
);
1068 return STATUS_OBJECT_NAME_COLLISION
;
1072 /* Now make a copy of the object name */
1073 ObjectName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1074 TypeName
->MaximumLength
,
1076 if (!ObjectName
.Buffer
)
1078 /* Out of memory, fail */
1079 ObpReleaseLookupContext(&Context
);
1080 return STATUS_INSUFFICIENT_RESOURCES
;
1083 /* Set the length and copy the name */
1084 ObjectName
.MaximumLength
= TypeName
->MaximumLength
;
1085 RtlCopyUnicodeString(&ObjectName
, TypeName
);
1087 /* Allocate the Object */
1088 Status
= ObpAllocateObject(NULL
,
1091 sizeof(OBJECT_TYPE
),
1093 (POBJECT_HEADER
*)&Header
);
1094 if (!NT_SUCCESS(Status
))
1096 /* Free the name and fail */
1097 ObpReleaseLookupContext(&Context
);
1098 ExFreePool(ObjectName
.Buffer
);
1102 /* Setup the flags and name */
1103 LocalObjectType
= (POBJECT_TYPE
)&Header
->Body
;
1104 LocalObjectType
->Name
= ObjectName
;
1105 Header
->Flags
|= OB_FLAG_KERNEL_MODE
| OB_FLAG_PERMANENT
;
1107 /* Clear accounting data */
1108 LocalObjectType
->TotalNumberOfObjects
=
1109 LocalObjectType
->TotalNumberOfHandles
=
1110 LocalObjectType
->HighWaterNumberOfObjects
=
1111 LocalObjectType
->HighWaterNumberOfHandles
= 0;
1113 /* Check if this is the first Object Type */
1114 if (!ObpTypeObjectType
)
1116 /* It is, so set this as the type object */
1117 ObpTypeObjectType
= LocalObjectType
;
1118 Header
->Type
= ObpTypeObjectType
;
1120 /* Set the hard-coded key and object count */
1121 LocalObjectType
->TotalNumberOfObjects
= 1;
1122 LocalObjectType
->Key
= 'TjbO';
1127 Tag
[0] = (CHAR
)TypeName
->Buffer
[0];
1128 Tag
[1] = (CHAR
)TypeName
->Buffer
[1];
1129 Tag
[2] = (CHAR
)TypeName
->Buffer
[2];
1130 Tag
[3] = (CHAR
)TypeName
->Buffer
[3];
1131 LocalObjectType
->Key
= *(PULONG
)Tag
;
1134 /* Set up the type information */
1135 LocalObjectType
->TypeInfo
= *ObjectTypeInitializer
;
1136 LocalObjectType
->TypeInfo
.PoolType
= ObjectTypeInitializer
->PoolType
;
1138 /* Check if we have to maintain a type list */
1139 if (NtGlobalFlag
& FLG_MAINTAIN_OBJECT_TYPELIST
)
1141 /* Enable support */
1142 LocalObjectType
->TypeInfo
.MaintainTypeList
= TRUE
;
1145 /* Calculate how much space our header'll take up */
1146 HeaderSize
= sizeof(OBJECT_HEADER
) +
1147 sizeof(OBJECT_HEADER_NAME_INFO
) +
1148 (ObjectTypeInitializer
->MaintainHandleCount
?
1149 sizeof(OBJECT_HEADER_HANDLE_INFO
) : 0);
1151 /* Check the pool type */
1152 if (ObjectTypeInitializer
->PoolType
== NonPagedPool
)
1154 /* Update the NonPaged Pool charge */
1155 LocalObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
+= HeaderSize
;
1159 /* Update the Paged Pool charge */
1160 LocalObjectType
->TypeInfo
.DefaultPagedPoolCharge
+= HeaderSize
;
1163 /* All objects types need a security procedure */
1164 if (!ObjectTypeInitializer
->SecurityProcedure
)
1166 LocalObjectType
->TypeInfo
.SecurityProcedure
= SeDefaultObjectMethod
;
1169 /* Select the Wait Object */
1170 if (LocalObjectType
->TypeInfo
.UseDefaultObject
)
1172 /* Add the SYNCHRONIZE access mask since it's waitable */
1173 LocalObjectType
->TypeInfo
.ValidAccessMask
|= SYNCHRONIZE
;
1175 /* Use the "Default Object", a simple event */
1176 LocalObjectType
->DefaultObject
= &ObpDefaultObject
;
1178 /* The File Object gets an optimized hack so it can be waited on */
1179 else if ((TypeName
->Length
== 8) && !(wcscmp(TypeName
->Buffer
, L
"File")))
1181 /* Wait on the File Object's event directly */
1182 LocalObjectType
->DefaultObject
= (PVOID
)FIELD_OFFSET(FILE_OBJECT
,
1185 else if ((TypeName
->Length
== 24) && !(wcscmp(TypeName
->Buffer
, L
"WaitablePort")))
1187 /* Wait on the LPC Port's object directly */
1188 LocalObjectType
->DefaultObject
= (PVOID
)FIELD_OFFSET(LPCP_PORT_OBJECT
,
1193 /* No default Object */
1194 LocalObjectType
->DefaultObject
= NULL
;
1197 /* Initialize Object Type components */
1198 ExInitializeResourceLite(&LocalObjectType
->Mutex
);
1199 for (i
= 0; i
< 4; i
++)
1201 /* Initialize the object locks */
1202 ExInitializeResourceLite(&LocalObjectType
->ObjectLocks
[i
]);
1204 InitializeListHead(&LocalObjectType
->TypeList
);
1206 /* Lock the object type */
1207 ObpEnterObjectTypeMutex(LocalObjectType
);
1209 /* Get creator info and insert it into the type list */
1210 CreatorInfo
= OBJECT_HEADER_TO_CREATOR_INFO(Header
);
1211 if (CreatorInfo
) InsertTailList(&ObpTypeObjectType
->TypeList
,
1212 &CreatorInfo
->TypeList
);
1214 /* Set the index and the entry into the object type array */
1215 LocalObjectType
->Index
= ObpTypeObjectType
->TotalNumberOfObjects
;
1216 if (LocalObjectType
->Index
< 32)
1218 /* It fits, insert it */
1219 ObpObjectTypes
[LocalObjectType
->Index
- 1] = LocalObjectType
;
1222 /* Release the object type */
1223 ObpLeaveObjectTypeMutex(LocalObjectType
);
1225 /* Check if we're actually creating the directory object itself */
1226 if (!(ObpTypeDirectoryObject
) ||
1227 (ObpInsertEntryDirectory(ObpTypeDirectoryObject
, &Context
, Header
)))
1229 /* Check if the type directory exists */
1230 if (ObpTypeDirectoryObject
)
1233 ObReferenceObject(ObpTypeDirectoryObject
);
1236 /* Cleanup the lookup context */
1237 ObpReleaseLookupContext(&Context
);
1239 /* Return the object type and success */
1240 *ObjectType
= LocalObjectType
;
1241 return STATUS_SUCCESS
;
1244 /* If we got here, then we failed */
1245 ObpReleaseLookupContext(&Context
);
1246 return STATUS_INSUFFICIENT_RESOURCES
;
1251 ObpDeleteObjectType(IN PVOID Object
)
1254 POBJECT_TYPE ObjectType
= (PVOID
)Object
;
1256 /* Loop our locks */
1257 for (i
= 0; i
< 4; i
++)
1259 /* Delete each one */
1260 ExDeleteResourceLite(&ObjectType
->ObjectLocks
[i
]);
1263 /* Delete our main mutex */
1264 ExDeleteResourceLite(&ObjectType
->Mutex
);
1268 * @name ObMakeTemporaryObject
1271 * The ObMakeTemporaryObject routine <FILLMEIN>
1283 ObMakeTemporaryObject(IN PVOID ObjectBody
)
1287 /* Call the internal API */
1288 ObpSetPermanentObject(ObjectBody
, FALSE
);
1292 * @name NtMakeTemporaryObject
1295 * The NtMakeTemporaryObject routine <FILLMEIN>
1297 * @param ObjectHandle
1300 * @return STATUS_SUCCESS or appropriate error value.
1307 NtMakeTemporaryObject(IN HANDLE ObjectHandle
)
1313 /* Reference the object for DELETE access */
1314 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1317 KeGetPreviousMode(),
1320 if (Status
!= STATUS_SUCCESS
) return Status
;
1322 /* Set it as temporary and dereference it */
1323 ObpSetPermanentObject(ObjectBody
, FALSE
);
1324 ObDereferenceObject(ObjectBody
);
1325 return STATUS_SUCCESS
;
1329 * @name NtMakePermanentObject
1332 * The NtMakePermanentObject routine <FILLMEIN>
1334 * @param ObjectHandle
1337 * @return STATUS_SUCCESS or appropriate error value.
1344 NtMakePermanentObject(IN HANDLE ObjectHandle
)
1348 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1351 /* Make sure that the caller has SeCreatePermanentPrivilege */
1352 Status
= SeSinglePrivilegeCheck(SeCreatePermanentPrivilege
,
1354 if (!NT_SUCCESS(Status
)) return STATUS_PRIVILEGE_NOT_HELD
;
1356 /* Reference the object */
1357 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1363 if (Status
!= STATUS_SUCCESS
) return Status
;
1365 /* Set it as permanent and dereference it */
1366 ObpSetPermanentObject(ObjectBody
, TRUE
);
1367 ObDereferenceObject(ObjectBody
);
1368 return STATUS_SUCCESS
;
1372 * @name NtQueryObject
1375 * The NtQueryObject routine <FILLMEIN>
1377 * @param ObjectHandle
1380 * @param ObjectInformationClass
1383 * @param ObjectInformation
1389 * @param ResultLength
1392 * @return STATUS_SUCCESS or appropriate error value.
1399 NtQueryObject(IN HANDLE ObjectHandle
,
1400 IN OBJECT_INFORMATION_CLASS ObjectInformationClass
,
1401 OUT PVOID ObjectInformation
,
1403 OUT PULONG ResultLength OPTIONAL
)
1405 OBJECT_HANDLE_INFORMATION HandleInfo
;
1406 POBJECT_HEADER ObjectHeader
= NULL
;
1407 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags
;
1408 POBJECT_BASIC_INFORMATION BasicInfo
;
1410 PVOID Object
= NULL
;
1412 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1415 /* Check if the caller is from user mode */
1416 if (PreviousMode
!= KernelMode
)
1418 /* Protect validation with SEH */
1421 /* Probe the input structure */
1422 ProbeForWrite(ObjectInformation
, Length
, sizeof(UCHAR
));
1424 /* If we have a result length, probe it too */
1425 if (ResultLength
) ProbeForWriteUlong(ResultLength
);
1427 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1429 /* Return the exception code */
1430 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1436 * Make sure this isn't a generic type query, since the caller doesn't
1437 * have to give a handle for it
1439 if (ObjectInformationClass
!= ObjectTypesInformation
)
1441 /* Reference the object */
1442 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1445 KeGetPreviousMode(),
1448 if (!NT_SUCCESS (Status
)) return Status
;
1450 /* Get the object header */
1451 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1456 /* Check the information class */
1457 switch (ObjectInformationClass
)
1460 case ObjectBasicInformation
:
1462 /* Validate length */
1463 InfoLength
= sizeof(OBJECT_BASIC_INFORMATION
);
1464 if (Length
!= sizeof(OBJECT_BASIC_INFORMATION
))
1467 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1471 /* Fill out the basic information */
1472 BasicInfo
= (POBJECT_BASIC_INFORMATION
)ObjectInformation
;
1473 BasicInfo
->Attributes
= HandleInfo
.HandleAttributes
;
1474 BasicInfo
->GrantedAccess
= HandleInfo
.GrantedAccess
;
1475 BasicInfo
->HandleCount
= ObjectHeader
->HandleCount
;
1476 BasicInfo
->PointerCount
= ObjectHeader
->PointerCount
;
1478 /* Permanent/Exclusive Flags are NOT in Handle attributes! */
1479 if (ObjectHeader
->Flags
& OB_FLAG_EXCLUSIVE
)
1482 BasicInfo
->Attributes
|= OBJ_EXCLUSIVE
;
1484 if (ObjectHeader
->Flags
& OB_FLAG_PERMANENT
)
1487 BasicInfo
->Attributes
|= OBJ_PERMANENT
;
1490 /* Copy quota information */
1491 BasicInfo
->PagedPoolCharge
= 0; /* FIXME*/
1492 BasicInfo
->NonPagedPoolCharge
= 0; /* FIXME*/
1494 /* Copy name information */
1495 BasicInfo
->NameInfoSize
= 0; /* FIXME*/
1496 BasicInfo
->TypeInfoSize
= 0; /* FIXME*/
1498 /* Copy security information */
1499 BasicInfo
->SecurityDescriptorSize
= 0; /* FIXME*/
1501 /* Check if this is a symlink */
1502 if (ObjectHeader
->Type
== ObSymbolicLinkType
)
1504 /* Return the creation time */
1505 BasicInfo
->CreationTime
.QuadPart
=
1506 ((POBJECT_SYMBOLIC_LINK
)Object
)->CreationTime
.QuadPart
;
1510 /* Otherwise return 0 */
1511 BasicInfo
->CreationTime
.QuadPart
= (ULONGLONG
)0;
1514 /* Break out with success */
1515 Status
= STATUS_SUCCESS
;
1518 /* Name information */
1519 case ObjectNameInformation
:
1521 /* Call the helper and break out */
1522 Status
= ObQueryNameString(Object
,
1523 (POBJECT_NAME_INFORMATION
)
1529 /* Information about this type */
1530 case ObjectTypeInformation
:
1532 /* Call the helper and break out */
1533 Status
= ObQueryTypeInfo(ObjectHeader
->Type
,
1534 (POBJECT_TYPE_INFORMATION
)
1540 /* Information about all types */
1541 case ObjectTypesInformation
:
1542 DPRINT1("NOT IMPLEMENTED!\n");
1543 Status
= STATUS_NOT_IMPLEMENTED
;
1546 /* Information about the handle flags */
1547 case ObjectHandleFlagInformation
:
1549 /* Validate length */
1550 InfoLength
= sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION
);
1551 if (Length
!= sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION
))
1553 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1557 /* Get the structure */
1558 HandleFlags
= (POBJECT_HANDLE_ATTRIBUTE_INFORMATION
)
1562 HandleFlags
->Inherit
= HandleInfo
.HandleAttributes
& OBJ_INHERIT
;
1563 HandleFlags
->ProtectFromClose
= (HandleInfo
.HandleAttributes
&
1564 OBJ_PROTECT_CLOSE
) != 0;
1566 /* Break out with success */
1567 Status
= STATUS_SUCCESS
;
1574 Status
= STATUS_INVALID_INFO_CLASS
;
1578 /* Check if the caller wanted the return length */
1581 /* Write the length */
1582 *ResultLength
= Length
;
1585 _SEH2_EXCEPT(ExSystemExceptionFilter())
1587 /* Otherwise, get the exception code */
1588 Status
= _SEH2_GetExceptionCode();
1592 /* Dereference the object if we had referenced it */
1593 if (Object
) ObDereferenceObject (Object
);
1600 * @name NtSetInformationObject
1603 * The NtSetInformationObject routine <FILLMEIN>
1605 * @param ObjectHandle
1608 * @param ObjectInformationClass
1611 * @param ObjectInformation
1617 * @return STATUS_SUCCESS or appropriate error value.
1624 NtSetInformationObject(IN HANDLE ObjectHandle
,
1625 IN OBJECT_INFORMATION_CLASS ObjectInformationClass
,
1626 IN PVOID ObjectInformation
,
1630 OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context
;
1632 KAPC_STATE ApcState
;
1633 BOOLEAN AttachedToProcess
= FALSE
;
1636 /* Validate the information class */
1637 if (ObjectInformationClass
!= ObjectHandleFlagInformation
)
1640 return STATUS_INVALID_INFO_CLASS
;
1643 /* Validate the length */
1644 if (Length
!= sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION
))
1646 /* Invalid length */
1647 return STATUS_INFO_LENGTH_MISMATCH
;
1650 /* Save the previous mode */
1651 Context
.PreviousMode
= ExGetPreviousMode();
1653 /* Check if we were called from user mode */
1654 if (Context
.PreviousMode
!= KernelMode
)
1659 /* Probe and capture the attribute buffer */
1660 ProbeForRead(ObjectInformation
,
1661 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION
),
1663 Context
.Information
= *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION
)
1666 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1668 /* Return the exception code */
1669 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1675 /* Just copy the buffer directly */
1676 Context
.Information
= *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION
)
1680 /* Check if this is a kernel handle */
1681 if (ObIsKernelHandle(ObjectHandle
, Context
.PreviousMode
))
1683 /* Get the actual handle */
1684 ObjectHandle
= ObKernelHandleToHandle(ObjectHandle
);
1685 ObjectTable
= ObpKernelHandleTable
;
1687 /* Check if we're not in the system process */
1688 if (PsGetCurrentProcess() != PsInitialSystemProcess
)
1691 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1692 AttachedToProcess
= TRUE
;
1697 /* Use the current table */
1698 ObjectTable
= PsGetCurrentProcess()->ObjectTable
;
1701 /* Change the handle attributes */
1702 if (!ExChangeHandle(ObjectTable
,
1704 ObpSetHandleAttributes
,
1705 (ULONG_PTR
)&Context
))
1708 Status
= STATUS_ACCESS_DENIED
;
1713 Status
= STATUS_SUCCESS
;
1716 /* De-attach if we were attached, and return status */
1717 if (AttachedToProcess
) KeUnstackDetachProcess(&ApcState
);