2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/create.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 ******************************************************************/
18 #include <internal/debug.h>
20 extern ULONG NtGlobalFlag
;
22 POBJECT_TYPE ObTypeObjectType
= NULL
;
23 KEVENT ObpDefaultObject
;
25 NPAGED_LOOKASIDE_LIST ObpNmLookasideList
, ObpCiLookasideList
;
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 ObpFreeAndReleaseCapturedAttributes(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 type lock */
266 ObpEnterObjectTypeMutex(ObjectHeader
->Type
);
268 /* Check what we're doing to it */
271 /* Set it to permanent */
272 ObjectHeader
->Flags
|= OB_FLAG_PERMANENT
;
274 /* Release the lock */
275 ObpLeaveObjectTypeMutex(ObjectHeader
->Type
);
279 /* Remove the flag */
280 ObjectHeader
->Flags
&= ~OB_FLAG_PERMANENT
;
282 /* Release the lock */
283 ObpLeaveObjectTypeMutex(ObjectHeader
->Type
);
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
> 248))
305 /* Nope, allocate directly from pool */
306 Buffer
= ExAllocatePoolWithTag(PagedPool
,
312 /* Allocate from the lookaside */
313 //MaximumLength = 248; <= hack, we should actually set this...!
314 Buffer
= ObpAllocateCapturedAttributes(LookasideNameBufferList
);
317 /* Setup the string */
318 ObjectName
->Length
= (USHORT
)Length
;
319 ObjectName
->MaximumLength
= (USHORT
)MaximumLength
;
320 ObjectName
->Buffer
= Buffer
;
326 ObpFreeObjectNameBuffer(IN PUNICODE_STRING Name
)
328 PVOID Buffer
= Name
->Buffer
;
330 /* We know this is a pool-allocation if the size doesn't match */
331 if (Name
->MaximumLength
!= 248)
333 /* Free it from the pool */
338 /* Otherwise, free from the lookaside */
339 ObpFreeCapturedAttributes(Buffer
, LookasideNameBufferList
);
345 ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName
,
346 IN PUNICODE_STRING ObjectName
,
347 IN KPROCESSOR_MODE AccessMode
,
348 IN BOOLEAN UseLookaside
)
350 NTSTATUS Status
= STATUS_SUCCESS
;
352 PWCHAR StringBuffer
= NULL
;
353 UNICODE_STRING LocalName
;
356 /* Initialize the Input String */
357 RtlInitEmptyUnicodeString(CapturedName
, NULL
, 0);
359 /* Protect everything */
362 /* Check if we came from user mode */
363 if (AccessMode
!= KernelMode
)
365 /* First Probe the String */
366 ProbeForReadUnicodeString(ObjectName
);
367 LocalName
= *ObjectName
;
368 ProbeForRead(LocalName
.Buffer
, LocalName
.Length
, sizeof(WCHAR
));
372 /* No probing needed */
373 LocalName
= *ObjectName
;
376 /* Make sure there really is a string */
377 if ((StringLength
= LocalName
.Length
))
379 /* Check that the size is a valid WCHAR multiple */
380 if ((StringLength
& (sizeof(WCHAR
) - 1)) ||
381 /* Check that the NULL-termination below will work */
382 (StringLength
== (MAXUSHORT
- sizeof(UNICODE_NULL
) + 1)))
384 /* PS: Please keep the checks above expanded for clarity */
385 Status
= STATUS_OBJECT_NAME_INVALID
;
389 /* Allocate the string buffer */
390 StringBuffer
= ObpAllocateObjectNameBuffer(StringLength
,
395 /* Set failure code */
396 Status
= STATUS_INSUFFICIENT_RESOURCES
;
401 RtlCopyMemory(StringBuffer
, LocalName
.Buffer
, StringLength
);
402 StringBuffer
[StringLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
407 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
409 /* Handle exception and free the string buffer */
410 Status
= _SEH_GetExceptionCode();
411 if (StringBuffer
) ExFreePool(StringBuffer
);
421 ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes
,
422 IN KPROCESSOR_MODE AccessMode
,
423 IN BOOLEAN AllocateFromLookaside
,
424 IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
425 OUT PUNICODE_STRING ObjectName
)
427 NTSTATUS Status
= STATUS_SUCCESS
;
428 PSECURITY_DESCRIPTOR SecurityDescriptor
;
429 PSECURITY_QUALITY_OF_SERVICE SecurityQos
;
430 PUNICODE_STRING LocalObjectName
= NULL
;
433 /* Zero out the Capture Data */
434 RtlZeroMemory(ObjectCreateInfo
, sizeof(OBJECT_CREATE_INFORMATION
));
436 /* SEH everything here for protection */
439 /* Check if we got attributes */
440 if (ObjectAttributes
)
442 /* Check if we're in user mode */
443 if (AccessMode
!= KernelMode
)
445 /* Probe the attributes */
446 ProbeForRead(ObjectAttributes
,
447 sizeof(OBJECT_ATTRIBUTES
),
451 /* Validate the Size and Attributes */
452 if ((ObjectAttributes
->Length
!= sizeof(OBJECT_ATTRIBUTES
)) ||
453 (ObjectAttributes
->Attributes
& ~OBJ_VALID_ATTRIBUTES
))
455 /* Invalid combination, fail */
456 Status
= STATUS_INVALID_PARAMETER
;
460 /* Set some Create Info */
461 ObjectCreateInfo
->RootDirectory
= ObjectAttributes
->RootDirectory
;
462 ObjectCreateInfo
->Attributes
= ObjectAttributes
->Attributes
;
463 LocalObjectName
= ObjectAttributes
->ObjectName
;
464 SecurityDescriptor
= ObjectAttributes
->SecurityDescriptor
;
465 SecurityQos
= ObjectAttributes
->SecurityQualityOfService
;
467 /* Check if we have a security descriptor */
468 if (SecurityDescriptor
)
471 Status
= SeCaptureSecurityDescriptor(SecurityDescriptor
,
477 if(!NT_SUCCESS(Status
))
479 /* Capture failed, quit */
480 ObjectCreateInfo
->SecurityDescriptor
= NULL
;
484 /* Save the probe mode and security descriptor size */
485 ObjectCreateInfo
->SecurityDescriptorCharge
= 2048; /* FIXME */
486 ObjectCreateInfo
->ProbeMode
= AccessMode
;
489 /* Check if we have QoS */
492 /* Check if we came from user mode */
493 if (AccessMode
!= KernelMode
)
495 /* Validate the QoS */
496 ProbeForRead(SecurityQos
,
497 sizeof(SECURITY_QUALITY_OF_SERVICE
),
502 ObjectCreateInfo
->SecurityQualityOfService
= *SecurityQos
;
503 ObjectCreateInfo
->SecurityQos
=
504 &ObjectCreateInfo
->SecurityQualityOfService
;
509 /* We don't have a name */
510 LocalObjectName
= NULL
;
513 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
515 /* Get the exception */
516 Status
= _SEH_GetExceptionCode();
520 if (NT_SUCCESS(Status
))
522 /* Now check if the Object Attributes had an Object Name */
525 Status
= ObpCaptureObjectName(ObjectName
,
528 AllocateFromLookaside
);
532 /* Clear the string */
533 RtlInitEmptyUnicodeString(ObjectName
, NULL
, 0);
535 /* He can't have specified a Root Directory */
536 if (ObjectCreateInfo
->RootDirectory
)
538 Status
= STATUS_OBJECT_NAME_INVALID
;
543 /* Cleanup if we failed */
544 if (!NT_SUCCESS(Status
)) ObpReleaseCapturedAttributes(ObjectCreateInfo
);
546 /* Return status to caller */
552 ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
)
554 /* Call the macro. We use this function to isolate Ob internals from Io */
555 ObpFreeCapturedAttributes(ObjectCreateInfo
, LookasideCreateInfoList
);
560 ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
561 IN PUNICODE_STRING ObjectName
,
562 IN POBJECT_TYPE ObjectType
,
564 IN KPROCESSOR_MODE PreviousMode
,
565 IN POBJECT_HEADER
*ObjectHeader
)
567 POBJECT_HEADER Header
;
568 ULONG QuotaSize
, HandleSize
, NameSize
, CreatorSize
;
569 POBJECT_HEADER_HANDLE_INFO HandleInfo
;
570 POBJECT_HEADER_NAME_INFO NameInfo
;
571 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
572 POBJECT_HEADER_QUOTA_INFO QuotaInfo
;
581 /* Check if we don't have an Object Type yet */
584 /* Use default tag and non-paged pool */
585 PoolType
= NonPagedPool
;
586 Tag
= TAG('O', 'b', 'j', 'T');
590 /* Use the pool and tag given */
591 PoolType
= ObjectType
->TypeInfo
.PoolType
;
592 Tag
= ObjectType
->Key
;
595 /* Check if we have no create information (ie: we're an object type) */
596 if (!ObjectCreateInfo
)
599 QuotaSize
= HandleSize
= 0;
600 NameSize
= sizeof(OBJECT_HEADER_NAME_INFO
);
601 CreatorSize
= sizeof(OBJECT_HEADER_CREATOR_INFO
);
605 /* Check if we have quota */
606 if ((((ObjectCreateInfo
->PagedPoolCharge
!=
607 ObjectType
->TypeInfo
.DefaultPagedPoolCharge
) ||
608 (ObjectCreateInfo
->NonPagedPoolCharge
!=
609 ObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
) ||
610 (ObjectCreateInfo
->SecurityDescriptorCharge
> 2048)) &&
611 (PsGetCurrentProcess() != PsInitialSystemProcess
)) ||
612 (ObjectCreateInfo
->Attributes
& OBJ_EXCLUSIVE
))
615 QuotaSize
= sizeof(OBJECT_HEADER_QUOTA_INFO
);
616 ObpObjectsWithPoolQuota
++;
624 /* Check if we have a handle database */
625 if (ObjectType
->TypeInfo
.MaintainHandleCount
)
627 /* Set handle database size */
628 HandleSize
= sizeof(OBJECT_HEADER_HANDLE_INFO
);
629 ObpObjectsWithHandleDB
++;
637 /* Check if the Object has a name */
638 if (ObjectName
->Buffer
)
641 NameSize
= sizeof(OBJECT_HEADER_NAME_INFO
);
642 ObpObjectsWithName
++;
650 /* Check if the Object maintains type lists */
651 if (ObjectType
->TypeInfo
.MaintainTypeList
)
653 /* Set owner/creator size */
654 CreatorSize
= sizeof(OBJECT_HEADER_CREATOR_INFO
);
655 ObpObjectsWithCreatorInfo
++;
664 /* Set final header size */
665 FinalSize
= QuotaSize
+
669 FIELD_OFFSET(OBJECT_HEADER
, Body
);
671 /* Allocate memory for the Object and Header */
672 Header
= ExAllocatePoolWithTag(PoolType
, FinalSize
+ ObjectSize
, Tag
);
673 if (!Header
) return STATUS_INSUFFICIENT_RESOURCES
;
675 /* Check if we have a quota header */
678 /* Initialize quota info */
679 QuotaInfo
= (POBJECT_HEADER_QUOTA_INFO
)Header
;
680 QuotaInfo
->PagedPoolCharge
= ObjectCreateInfo
->PagedPoolCharge
;
681 QuotaInfo
->NonPagedPoolCharge
= ObjectCreateInfo
->NonPagedPoolCharge
;
682 QuotaInfo
->SecurityDescriptorCharge
= ObjectCreateInfo
->SecurityDescriptorCharge
;
683 QuotaInfo
->ExclusiveProcess
= NULL
;
684 Header
= (POBJECT_HEADER
)(QuotaInfo
+ 1);
687 /* Check if we have a handle database header */
690 /* Initialize Handle Info */
691 HandleInfo
= (POBJECT_HEADER_HANDLE_INFO
)Header
;
692 HandleInfo
->SingleEntry
.HandleCount
= 0;
693 Header
= (POBJECT_HEADER
)(HandleInfo
+ 1);
696 /* Check if we have a name header */
699 /* Initialize the Object Name Info */
700 NameInfo
= (POBJECT_HEADER_NAME_INFO
)Header
;
701 NameInfo
->Name
= *ObjectName
;
702 NameInfo
->Directory
= NULL
;
703 NameInfo
->QueryReferences
= 1;
705 /* Check if this is a call with the special protection flag */
706 if ((PreviousMode
== KernelMode
) &&
707 (ObjectCreateInfo
) &&
708 (ObjectCreateInfo
->Attributes
& 0x10000))
710 /* Set flag which will make the object protected from user-mode */
711 NameInfo
->QueryReferences
|= 0x40000000;
714 /* Set the header pointer */
715 Header
= (POBJECT_HEADER
)(NameInfo
+ 1);
718 /* Check if we have a creator header */
721 /* Initialize Creator Info */
722 CreatorInfo
= (POBJECT_HEADER_CREATOR_INFO
)Header
;
723 CreatorInfo
->CreatorBackTraceIndex
= 0;
724 CreatorInfo
->CreatorUniqueProcess
= PsGetCurrentProcessId();
725 InitializeListHead(&CreatorInfo
->TypeList
);
726 Header
= (POBJECT_HEADER
)(CreatorInfo
+ 1);
729 /* Check for quota information */
733 Header
->QuotaInfoOffset
= (UCHAR
)(QuotaSize
+
741 Header
->QuotaInfoOffset
= 0;
744 /* Check for handle information */
748 Header
->HandleInfoOffset
= (UCHAR
)(HandleSize
+
755 Header
->HandleInfoOffset
= 0;
758 /* Check for name information */
762 Header
->NameInfoOffset
= (UCHAR
)(NameSize
+ CreatorSize
);
767 Header
->NameInfoOffset
= 0;
770 /* Set the new object flag */
771 Header
->Flags
= OB_FLAG_CREATE_INFO
;
773 /* Remember if we have creator info */
774 if (CreatorSize
) Header
->Flags
|= OB_FLAG_CREATOR_INFO
;
776 /* Remember if we have handle info */
777 if (HandleSize
) Header
->Flags
|= OB_FLAG_SINGLE_PROCESS
;
779 /* Initialize the object header */
780 Header
->PointerCount
= 1;
781 Header
->HandleCount
= 0;
782 Header
->Type
= ObjectType
;
783 Header
->ObjectCreateInfo
= ObjectCreateInfo
;
784 Header
->SecurityDescriptor
= NULL
;
786 /* Check if this is a permanent object */
787 if ((ObjectCreateInfo
) && (ObjectCreateInfo
->Attributes
& OBJ_PERMANENT
))
789 /* Set the needed flag so we can check */
790 Header
->Flags
|= OB_FLAG_PERMANENT
;
793 /* Check if this is an exclusive object */
794 if ((ObjectCreateInfo
) && (ObjectCreateInfo
->Attributes
& OBJ_EXCLUSIVE
))
796 /* Set the needed flag so we can check */
797 Header
->Flags
|= OB_FLAG_EXCLUSIVE
;
800 /* Set kernel-mode flag */
801 if (PreviousMode
== KernelMode
) Header
->Flags
|= OB_FLAG_KERNEL_MODE
;
803 /* Check if we have a type */
806 /* Increase the number of objects of this type */
807 InterlockedIncrement((PLONG
)&ObjectType
->TotalNumberOfObjects
);
809 /* Update the high water */
810 ObjectType
->HighWaterNumberOfObjects
= max(ObjectType
->
811 TotalNumberOfObjects
,
813 HighWaterNumberOfObjects
);
816 /* OMG-Hack-Of-Doom */
817 RtlZeroMemory(&Header
->Body
, ObjectSize
);
820 *ObjectHeader
= Header
;
821 return STATUS_SUCCESS
;
826 ObQueryTypeInfo(IN POBJECT_TYPE ObjectType
,
827 OUT POBJECT_TYPE_INFORMATION ObjectTypeInfo
,
829 OUT PULONG ReturnLength
)
831 NTSTATUS Status
= STATUS_SUCCESS
;
837 /* Set return length aligned to 4-byte boundary */
838 *ReturnLength
+= sizeof(*ObjectTypeInfo
) +
839 ALIGN_UP(ObjectType
->Name
.MaximumLength
, ULONG
);
841 /* Check if thats too much though. */
842 if (Length
< *ReturnLength
) return STATUS_INFO_LENGTH_MISMATCH
;
845 ObjectTypeInfo
->TotalNumberOfHandles
=
846 ObjectType
->TotalNumberOfHandles
;
847 ObjectTypeInfo
->TotalNumberOfObjects
=
848 ObjectType
->TotalNumberOfObjects
;
849 ObjectTypeInfo
->HighWaterNumberOfHandles
=
850 ObjectType
->HighWaterNumberOfHandles
;
851 ObjectTypeInfo
->HighWaterNumberOfObjects
=
852 ObjectType
->HighWaterNumberOfObjects
;
853 ObjectTypeInfo
->PoolType
=
854 ObjectType
->TypeInfo
.PoolType
;
855 ObjectTypeInfo
->DefaultNonPagedPoolCharge
=
856 ObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
;
857 ObjectTypeInfo
->DefaultPagedPoolCharge
=
858 ObjectType
->TypeInfo
.DefaultPagedPoolCharge
;
859 ObjectTypeInfo
->ValidAccessMask
=
860 ObjectType
->TypeInfo
.ValidAccessMask
;
861 ObjectTypeInfo
->SecurityRequired
=
862 ObjectType
->TypeInfo
.SecurityRequired
;
863 ObjectTypeInfo
->InvalidAttributes
=
864 ObjectType
->TypeInfo
.InvalidAttributes
;
865 ObjectTypeInfo
->GenericMapping
=
866 ObjectType
->TypeInfo
.GenericMapping
;
867 ObjectTypeInfo
->MaintainHandleCount
=
868 ObjectType
->TypeInfo
.MaintainHandleCount
;
870 /* Setup the name buffer */
871 InfoBuffer
= (PWSTR
)(ObjectTypeInfo
+ 1);
872 ObjectTypeInfo
->TypeName
.Buffer
= InfoBuffer
;
873 ObjectTypeInfo
->TypeName
.MaximumLength
= ObjectType
->Name
.MaximumLength
;
874 ObjectTypeInfo
->TypeName
.Length
= ObjectType
->Name
.Length
;
877 RtlCopyMemory(InfoBuffer
,
878 ObjectType
->Name
.Buffer
,
879 ObjectType
->Name
.Length
);
881 /* Null-terminate it */
882 (InfoBuffer
)[ObjectType
->Name
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
884 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
886 /* Otherwise, get the exception code */
887 Status
= _SEH_GetExceptionCode();
891 /* Return status to caller */
896 /* PUBLIC FUNCTIONS **********************************************************/
900 ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL
,
901 IN POBJECT_TYPE Type
,
902 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
903 IN KPROCESSOR_MODE AccessMode
,
904 IN OUT PVOID ParseContext OPTIONAL
,
906 IN ULONG PagedPoolCharge OPTIONAL
,
907 IN ULONG NonPagedPoolCharge OPTIONAL
,
911 POBJECT_CREATE_INFORMATION ObjectCreateInfo
;
912 UNICODE_STRING ObjectName
;
913 POBJECT_HEADER Header
;
915 /* Allocate a capture buffer */
916 ObjectCreateInfo
= ObpAllocateCapturedAttributes(LookasideCreateInfoList
);
917 if (!ObjectCreateInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
919 /* Capture all the info */
920 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
925 if (NT_SUCCESS(Status
))
927 /* Validate attributes */
928 if (Type
->TypeInfo
.InvalidAttributes
& ObjectCreateInfo
->Attributes
)
931 Status
= STATUS_INVALID_PARAMETER
;
935 /* Check if we have a paged charge */
936 if (!PagedPoolCharge
)
939 PagedPoolCharge
= Type
->TypeInfo
.DefaultPagedPoolCharge
;
942 /* Check for nonpaged charge */
943 if (!NonPagedPoolCharge
)
946 NonPagedPoolCharge
= Type
->TypeInfo
.DefaultNonPagedPoolCharge
;
949 /* Write the pool charges */
950 ObjectCreateInfo
->PagedPoolCharge
= PagedPoolCharge
;
951 ObjectCreateInfo
->NonPagedPoolCharge
= NonPagedPoolCharge
;
953 /* Allocate the Object */
954 Status
= ObpAllocateObject(ObjectCreateInfo
,
960 if (NT_SUCCESS(Status
))
962 /* Return the Object */
963 *Object
= &Header
->Body
;
965 /* Check if this is a permanent object */
966 if (Header
->Flags
& OB_FLAG_PERMANENT
)
968 /* Do the privilege check */
969 if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege
,
973 ObpDeallocateObject(*Object
);
974 Status
= STATUS_PRIVILEGE_NOT_HELD
;
983 /* Release the Capture Info, we don't need it */
984 ObpReleaseCapturedAttributes(ObjectCreateInfo
);
985 if (ObjectName
.Buffer
) ObpFreeObjectNameBuffer(&ObjectName
);
988 /* We failed, so release the Buffer */
989 ObpFreeCapturedAttributes(ObjectCreateInfo
, LookasideCreateInfoList
);
995 ObCreateObjectType(IN PUNICODE_STRING TypeName
,
996 IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer
,
998 OUT POBJECT_TYPE
*ObjectType
)
1000 POBJECT_HEADER Header
;
1001 POBJECT_TYPE LocalObjectType
;
1005 OBP_LOOKUP_CONTEXT Context
;
1008 UNICODE_STRING ObjectName
;
1009 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
1011 /* Verify parameters */
1013 !(TypeName
->Length
) ||
1014 (TypeName
->Length
% sizeof(WCHAR
)) ||
1015 !(ObjectTypeInitializer
) ||
1016 (ObjectTypeInitializer
->Length
!= sizeof(*ObjectTypeInitializer
)) ||
1017 (ObjectTypeInitializer
->InvalidAttributes
& ~OBJ_VALID_ATTRIBUTES
) ||
1018 (ObjectTypeInitializer
->MaintainHandleCount
&&
1019 (!(ObjectTypeInitializer
->OpenProcedure
) &&
1020 !ObjectTypeInitializer
->CloseProcedure
)) ||
1021 ((!ObjectTypeInitializer
->UseDefaultObject
) &&
1022 (ObjectTypeInitializer
->PoolType
!= NonPagedPool
)))
1025 return STATUS_INVALID_PARAMETER
;
1028 /* Make sure the name doesn't have a separator */
1029 p
= TypeName
->Buffer
;
1030 i
= TypeName
->Length
/ sizeof(WCHAR
);
1033 /* Check for one and fail */
1034 if (*p
++ == OBJ_NAME_PATH_SEPARATOR
) return STATUS_OBJECT_NAME_INVALID
;
1037 /* Setup a lookup context */
1038 ObpInitializeDirectoryLookup(&Context
);
1040 /* Check if we've already created the directory of types */
1041 if (ObpTypeDirectoryObject
)
1043 /* Acquire the directory lock */
1044 ObpAcquireDirectoryLockExclusive(ObpTypeDirectoryObject
, &Context
);
1047 if (ObpLookupEntryDirectory(ObpTypeDirectoryObject
,
1049 OBJ_CASE_INSENSITIVE
,
1053 /* We have already created it, so fail */
1054 ObpCleanupDirectoryLookup(&Context
);
1055 return STATUS_OBJECT_NAME_COLLISION
;
1059 /* Now make a copy of the object name */
1060 ObjectName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1061 TypeName
->MaximumLength
,
1063 if (!ObjectName
.Buffer
)
1065 /* Out of memory, fail */
1066 ObpCleanupDirectoryLookup(&Context
);
1067 return STATUS_INSUFFICIENT_RESOURCES
;
1070 /* Set the length and copy the name */
1071 ObjectName
.MaximumLength
= TypeName
->MaximumLength
;
1072 RtlCopyUnicodeString(&ObjectName
, TypeName
);
1074 /* Allocate the Object */
1075 Status
= ObpAllocateObject(NULL
,
1078 sizeof(OBJECT_TYPE
),
1080 (POBJECT_HEADER
*)&Header
);
1081 if (!NT_SUCCESS(Status
))
1083 /* Free the name and fail */
1084 ObpCleanupDirectoryLookup(&Context
);
1085 ExFreePool(ObjectName
.Buffer
);
1089 /* Setup the flags and name */
1090 LocalObjectType
= (POBJECT_TYPE
)&Header
->Body
;
1091 LocalObjectType
->Name
= ObjectName
;
1092 Header
->Flags
|= OB_FLAG_KERNEL_MODE
| OB_FLAG_PERMANENT
;
1094 /* Clear accounting data */
1095 LocalObjectType
->TotalNumberOfObjects
=
1096 LocalObjectType
->TotalNumberOfHandles
=
1097 LocalObjectType
->HighWaterNumberOfObjects
=
1098 LocalObjectType
->HighWaterNumberOfHandles
= 0;
1100 /* Check if this is the first Object Type */
1101 if (!ObTypeObjectType
)
1103 /* It is, so set this as the type object */
1104 ObTypeObjectType
= LocalObjectType
;
1105 Header
->Type
= ObTypeObjectType
;
1107 /* Set the hard-coded key and object count */
1108 LocalObjectType
->TotalNumberOfObjects
= 1;
1109 LocalObjectType
->Key
= TAG('O', 'b', 'j', 'T');
1114 Tag
[0] = (CHAR
)TypeName
->Buffer
[0];
1115 Tag
[1] = (CHAR
)TypeName
->Buffer
[1];
1116 Tag
[2] = (CHAR
)TypeName
->Buffer
[2];
1117 Tag
[3] = (CHAR
)TypeName
->Buffer
[3];
1118 LocalObjectType
->Key
= *(PULONG
)Tag
;
1121 /* Set up the type information */
1122 LocalObjectType
->TypeInfo
= *ObjectTypeInitializer
;
1123 LocalObjectType
->TypeInfo
.PoolType
= ObjectTypeInitializer
->PoolType
;
1125 /* Check if we have to maintain a type list */
1126 if (NtGlobalFlag
& FLG_MAINTAIN_OBJECT_TYPELIST
)
1128 /* Enable support */
1129 LocalObjectType
->TypeInfo
.MaintainTypeList
= TRUE
;
1132 /* Calculate how much space our header'll take up */
1133 HeaderSize
= sizeof(OBJECT_HEADER
) +
1134 sizeof(OBJECT_HEADER_NAME_INFO
) +
1135 (ObjectTypeInitializer
->MaintainHandleCount
?
1136 sizeof(OBJECT_HEADER_HANDLE_INFO
) : 0);
1138 /* Check the pool type */
1139 if (ObjectTypeInitializer
->PoolType
== NonPagedPool
)
1141 /* Update the NonPaged Pool charge */
1142 LocalObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
+= HeaderSize
;
1146 /* Update the Paged Pool charge */
1147 LocalObjectType
->TypeInfo
.DefaultPagedPoolCharge
+= HeaderSize
;
1150 /* All objects types need a security procedure */
1151 if (!ObjectTypeInitializer
->SecurityProcedure
)
1153 LocalObjectType
->TypeInfo
.SecurityProcedure
= SeDefaultObjectMethod
;
1156 /* Select the Wait Object */
1157 if (LocalObjectType
->TypeInfo
.UseDefaultObject
)
1159 /* Add the SYNCHRONIZE access mask since it's waitable */
1160 LocalObjectType
->TypeInfo
.ValidAccessMask
|= SYNCHRONIZE
;
1162 /* Use the "Default Object", a simple event */
1163 LocalObjectType
->DefaultObject
= &ObpDefaultObject
;
1165 /* The File Object gets an optimized hack so it can be waited on */
1166 else if ((TypeName
->Length
== 8) && !(wcscmp(TypeName
->Buffer
, L
"File")))
1168 /* Wait on the File Object's event directly */
1169 LocalObjectType
->DefaultObject
= (PVOID
)FIELD_OFFSET(FILE_OBJECT
,
1172 else if ((TypeName
->Length
== 24) && !(wcscmp(TypeName
->Buffer
, L
"WaitablePort")))
1174 /* Wait on the LPC Port's object directly */
1175 LocalObjectType
->DefaultObject
= (PVOID
)FIELD_OFFSET(LPCP_PORT_OBJECT
,
1180 /* No default Object */
1181 LocalObjectType
->DefaultObject
= NULL
;
1184 /* Initialize Object Type components */
1185 ExInitializeResourceLite(&LocalObjectType
->Mutex
);
1186 for (i
= 0; i
< 4; i
++)
1188 /* Initialize the object locks */
1189 ExInitializeResourceLite(&LocalObjectType
->ObjectLocks
[i
]);
1191 InitializeListHead(&LocalObjectType
->TypeList
);
1193 /* Lock the object type */
1194 ObpEnterObjectTypeMutex(LocalObjectType
);
1196 /* Get creator info and insert it into the type list */
1197 CreatorInfo
= OBJECT_HEADER_TO_CREATOR_INFO(Header
);
1198 if (CreatorInfo
) InsertTailList(&ObTypeObjectType
->TypeList
,
1199 &CreatorInfo
->TypeList
);
1201 /* Set the index and the entry into the object type array */
1202 LocalObjectType
->Index
= ObTypeObjectType
->TotalNumberOfObjects
;
1203 if (LocalObjectType
->Index
< 32)
1205 /* It fits, insert it */
1206 ObpObjectTypes
[LocalObjectType
->Index
- 1] = LocalObjectType
;
1209 /* Release the object type */
1210 ObpLeaveObjectTypeMutex(LocalObjectType
);
1212 /* Check if we're actually creating the directory object itself */
1213 if (!(ObpTypeDirectoryObject
) ||
1214 (ObpInsertEntryDirectory(ObpTypeDirectoryObject
, &Context
, Header
)))
1216 /* Check if the type directory exists */
1217 if (ObpTypeDirectoryObject
)
1220 ObReferenceObject(ObpTypeDirectoryObject
);
1223 /* Cleanup the lookup context */
1224 ObpCleanupDirectoryLookup(&Context
);
1226 /* Return the object type and success */
1227 *ObjectType
= LocalObjectType
;
1228 return STATUS_SUCCESS
;
1231 /* If we got here, then we failed */
1232 ObpCleanupDirectoryLookup(&Context
);
1233 return STATUS_INSUFFICIENT_RESOURCES
;
1237 * @name ObMakeTemporaryObject
1240 * The ObMakeTemporaryObject routine <FILLMEIN>
1252 ObMakeTemporaryObject(IN PVOID ObjectBody
)
1256 /* Call the internal API */
1257 ObpSetPermanentObject(ObjectBody
, FALSE
);
1261 * @name NtMakeTemporaryObject
1264 * The NtMakeTemporaryObject routine <FILLMEIN>
1266 * @param ObjectHandle
1269 * @return STATUS_SUCCESS or appropriate error value.
1276 NtMakeTemporaryObject(IN HANDLE ObjectHandle
)
1282 /* Reference the object for DELETE access */
1283 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1286 KeGetPreviousMode(),
1289 if (Status
!= STATUS_SUCCESS
) return Status
;
1291 /* Set it as temporary and dereference it */
1292 ObpSetPermanentObject(ObjectBody
, FALSE
);
1293 ObDereferenceObject(ObjectBody
);
1294 return STATUS_SUCCESS
;
1298 * @name NtMakePermanentObject
1301 * The NtMakePermanentObject routine <FILLMEIN>
1303 * @param ObjectHandle
1306 * @return STATUS_SUCCESS or appropriate error value.
1313 NtMakePermanentObject(IN HANDLE ObjectHandle
)
1317 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1320 /* Make sure that the caller has SeCreatePermanentPrivilege */
1321 Status
= SeSinglePrivilegeCheck(SeCreatePermanentPrivilege
,
1323 if (!NT_SUCCESS(Status
)) return STATUS_PRIVILEGE_NOT_HELD
;
1325 /* Reference the object */
1326 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1332 if (Status
!= STATUS_SUCCESS
) return Status
;
1334 /* Set it as permanent and dereference it */
1335 ObpSetPermanentObject(ObjectBody
, TRUE
);
1336 ObDereferenceObject(ObjectBody
);
1337 return STATUS_SUCCESS
;
1341 * @name NtQueryObject
1344 * The NtQueryObject routine <FILLMEIN>
1346 * @param ObjectHandle
1349 * @param ObjectInformationClass
1352 * @param ObjectInformation
1358 * @param ResultLength
1361 * @return STATUS_SUCCESS or appropriate error value.
1368 NtQueryObject(IN HANDLE ObjectHandle
,
1369 IN OBJECT_INFORMATION_CLASS ObjectInformationClass
,
1370 OUT PVOID ObjectInformation
,
1372 OUT PULONG ResultLength OPTIONAL
)
1374 OBJECT_HANDLE_INFORMATION HandleInfo
;
1375 POBJECT_HEADER ObjectHeader
= NULL
;
1376 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags
;
1377 POBJECT_BASIC_INFORMATION BasicInfo
;
1379 PVOID Object
= NULL
;
1380 NTSTATUS Status
= STATUS_SUCCESS
;
1381 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1384 /* Check if the caller is from user mode */
1385 if (PreviousMode
!= KernelMode
)
1387 /* Protect validation with SEH */
1390 /* Probe the input structure */
1391 ProbeForWrite(ObjectInformation
, Length
, sizeof(UCHAR
));
1393 /* If we have a result length, probe it too */
1394 if (ResultLength
) ProbeForWriteUlong(ResultLength
);
1398 /* Get the exception code */
1399 Status
= _SEH_GetExceptionCode();
1403 /* Fail if we raised an exception */
1404 if (!NT_SUCCESS(Status
)) return Status
;
1408 * Make sure this isn't a generic type query, since the caller doesn't
1409 * have to give a handle for it
1411 if (ObjectInformationClass
!= ObjectAllTypesInformation
)
1413 /* Reference the object */
1414 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1417 KeGetPreviousMode(),
1420 if (!NT_SUCCESS (Status
)) return Status
;
1422 /* Get the object header */
1423 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1428 /* Check the information class */
1429 switch (ObjectInformationClass
)
1432 case ObjectBasicInformation
:
1434 /* Validate length */
1435 InfoLength
= sizeof(OBJECT_BASIC_INFORMATION
);
1436 if (Length
!= sizeof(OBJECT_BASIC_INFORMATION
))
1439 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1443 /* Fill out the basic information */
1444 BasicInfo
= (POBJECT_BASIC_INFORMATION
)ObjectInformation
;
1445 BasicInfo
->Attributes
= HandleInfo
.HandleAttributes
;
1446 BasicInfo
->GrantedAccess
= HandleInfo
.GrantedAccess
;
1447 BasicInfo
->HandleCount
= ObjectHeader
->HandleCount
;
1448 BasicInfo
->PointerCount
= ObjectHeader
->PointerCount
;
1450 /* Permanent/Exclusive Flags are NOT in Handle attributes! */
1451 if (ObjectHeader
->Flags
& OB_FLAG_EXCLUSIVE
)
1454 BasicInfo
->Attributes
|= OBJ_EXCLUSIVE
;
1456 if (ObjectHeader
->Flags
& OB_FLAG_PERMANENT
)
1459 BasicInfo
->Attributes
|= OBJ_PERMANENT
;
1462 /* Copy quota information */
1463 BasicInfo
->PagedPoolUsage
= 0; /* FIXME*/
1464 BasicInfo
->NonPagedPoolUsage
= 0; /* FIXME*/
1466 /* Copy name information */
1467 BasicInfo
->NameInformationLength
= 0; /* FIXME*/
1468 BasicInfo
->TypeInformationLength
= 0; /* FIXME*/
1470 /* Copy security information */
1471 BasicInfo
->SecurityDescriptorLength
= 0; /* FIXME*/
1473 /* Check if this is a symlink */
1474 if (ObjectHeader
->Type
== ObSymbolicLinkType
)
1476 /* Return the creation time */
1477 BasicInfo
->CreateTime
.QuadPart
=
1478 ((POBJECT_SYMBOLIC_LINK
)Object
)->CreationTime
.QuadPart
;
1482 /* Otherwise return 0 */
1483 BasicInfo
->CreateTime
.QuadPart
= (ULONGLONG
)0;
1486 /* Break out with success */
1487 Status
= STATUS_SUCCESS
;
1490 /* Name information */
1491 case ObjectNameInformation
:
1493 /* Call the helper and break out */
1494 Status
= ObQueryNameString(Object
,
1495 (POBJECT_NAME_INFORMATION
)
1501 /* Information about this type */
1502 case ObjectTypeInformation
:
1504 /* Call the helper and break out */
1505 Status
= ObQueryTypeInfo(ObjectHeader
->Type
,
1506 (POBJECT_TYPE_INFORMATION
)
1512 /* Information about all types */
1513 case ObjectAllTypesInformation
:
1514 DPRINT1("NOT IMPLEMENTED!\n");
1515 Status
= STATUS_NOT_IMPLEMENTED
;
1518 /* Information about the handle flags */
1519 case ObjectHandleInformation
:
1521 /* Validate length */
1522 InfoLength
= sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION
);
1523 if (Length
!= sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION
))
1525 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1529 /* Get the structure */
1530 HandleFlags
= (POBJECT_HANDLE_ATTRIBUTE_INFORMATION
)
1534 HandleFlags
->Inherit
= HandleInfo
.HandleAttributes
& OBJ_INHERIT
;
1535 HandleFlags
->ProtectFromClose
= (HandleInfo
.HandleAttributes
&
1536 OBJ_PROTECT_CLOSE
) != 0;
1538 /* Break out with success */
1539 Status
= STATUS_SUCCESS
;
1546 Status
= STATUS_INVALID_INFO_CLASS
;
1550 /* Check if the caller wanted the return length */
1553 /* Write the length */
1554 *ResultLength
= Length
;
1557 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
)
1559 /* Otherwise, get the exception code */
1560 Status
= _SEH_GetExceptionCode();
1564 /* Dereference the object if we had referenced it */
1565 if (Object
) ObDereferenceObject (Object
);
1572 * @name NtSetInformationObject
1575 * The NtSetInformationObject routine <FILLMEIN>
1577 * @param ObjectHandle
1580 * @param ObjectInformationClass
1583 * @param ObjectInformation
1589 * @return STATUS_SUCCESS or appropriate error value.
1596 NtSetInformationObject(IN HANDLE ObjectHandle
,
1597 IN OBJECT_INFORMATION_CLASS ObjectInformationClass
,
1598 IN PVOID ObjectInformation
,
1601 NTSTATUS Status
= STATUS_SUCCESS
;
1602 OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context
;
1604 KAPC_STATE ApcState
;
1605 BOOLEAN AttachedToProcess
= FALSE
;
1608 /* Validate the information class */
1609 if (ObjectInformationClass
!= ObjectHandleInformation
)
1612 return STATUS_INVALID_INFO_CLASS
;
1615 /* Validate the length */
1616 if (Length
!= sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION
))
1618 /* Invalid length */
1619 return STATUS_INFO_LENGTH_MISMATCH
;
1622 /* Save the previous mode and actual information */
1623 Context
.PreviousMode
= ExGetPreviousMode();
1625 if (Context
.PreviousMode
!= KernelMode
)
1629 ProbeForRead(ObjectInformation
,
1630 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION
),
1632 Context
.Information
= *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION
)
1637 Status
= _SEH_GetExceptionCode();
1641 if (!NT_SUCCESS(Status
)) return Status
;
1644 Context
.Information
= *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION
)
1647 /* Check if this is a kernel handle */
1648 if (ObIsKernelHandle(ObjectHandle
, Context
.PreviousMode
))
1650 /* Get the actual handle */
1651 ObjectHandle
= ObKernelHandleToHandle(ObjectHandle
);
1652 ObjectTable
= ObpKernelHandleTable
;
1654 /* Check if we're not in the system process */
1655 if (PsGetCurrentProcess() != PsInitialSystemProcess
)
1658 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1659 AttachedToProcess
= TRUE
;
1664 /* Use the current table */
1665 ObjectTable
= PsGetCurrentProcess()->ObjectTable
;
1668 /* Change the handle attributes */
1669 if (!ExChangeHandle(ObjectTable
,
1671 ObpSetHandleAttributes
,
1672 (ULONG_PTR
)&Context
))
1675 Status
= STATUS_ACCESS_DENIED
;
1678 /* De-attach if we were attached, and return status */
1679 if (AttachedToProcess
) KeUnstackDetachProcess(&ApcState
);