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;
111 /* Return the quota */
112 DPRINT("FIXME: Should return quotas: %lx %lx\n", PagedPoolCharge
, NonPagedPoolCharge
);
114 PsReturnSharedPoolQuota(ObjectHeader
->QuotaBlockCharged
,
122 /* Check if a handle database was active */
123 if ((HandleInfo
) && !(Header
->Flags
& OB_FLAG_SINGLE_PROCESS
))
126 ExFreePool(HandleInfo
->HandleCountDatabase
);
127 HandleInfo
->HandleCountDatabase
= NULL
;
130 /* Check if we have a name */
131 if ((NameInfo
) && (NameInfo
->Name
.Buffer
))
134 ExFreePool(NameInfo
->Name
.Buffer
);
135 NameInfo
->Name
.Buffer
= NULL
;
138 /* Catch invalid access */
139 Header
->Type
= (POBJECT_TYPE
)0xBAADB0B0;
141 /* Free the object using the same allocation tag */
142 ExFreePoolWithTag(HeaderLocation
, ObjectType
->Key
);
147 ObpDeleteObject(IN PVOID Object
,
148 IN BOOLEAN CalledFromWorkerThread
)
150 POBJECT_HEADER Header
;
151 POBJECT_TYPE ObjectType
;
152 POBJECT_HEADER_NAME_INFO NameInfo
;
153 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
157 /* Get the header and type */
158 Header
= OBJECT_TO_OBJECT_HEADER(Object
);
159 ObjectType
= Header
->Type
;
161 /* Get creator and name information */
162 NameInfo
= OBJECT_HEADER_TO_NAME_INFO(Header
);
163 CreatorInfo
= OBJECT_HEADER_TO_CREATOR_INFO(Header
);
165 /* Check if the object is on a type list */
166 if ((CreatorInfo
) && !(IsListEmpty(&CreatorInfo
->TypeList
)))
168 /* Lock the object type */
169 ObpEnterObjectTypeMutex(ObjectType
);
171 /* Remove the object from the type list */
172 RemoveEntryList(&CreatorInfo
->TypeList
);
174 /* Release the lock */
175 ObpLeaveObjectTypeMutex(ObjectType
);
178 /* Check if we have a name */
179 if ((NameInfo
) && (NameInfo
->Name
.Buffer
))
182 ExFreePool(NameInfo
->Name
.Buffer
);
183 RtlInitEmptyUnicodeString(&NameInfo
->Name
, NULL
, 0);
186 /* Check if we have a security descriptor */
187 if (Header
->SecurityDescriptor
)
189 /* Call the security procedure to delete it */
190 ObpCalloutStart(&CalloutIrql
);
191 ObjectType
->TypeInfo
.SecurityProcedure(Object
,
192 DeleteSecurityDescriptor
,
196 &Header
->SecurityDescriptor
,
199 ObpCalloutEnd(CalloutIrql
, "Security", ObjectType
, Object
);
202 /* Check if we have a delete procedure */
203 if (ObjectType
->TypeInfo
.DeleteProcedure
)
205 /* Save whether we were deleted from worker thread or not */
206 if (!CalledFromWorkerThread
) Header
->Flags
|= OB_FLAG_DEFER_DELETE
;
209 ObpCalloutStart(&CalloutIrql
);
210 ObjectType
->TypeInfo
.DeleteProcedure(Object
);
211 ObpCalloutEnd(CalloutIrql
, "Delete", ObjectType
, Object
);
214 /* Now de-allocate all object members */
215 ObpDeallocateObject(Object
);
220 ObpReapObject(IN PVOID Parameter
)
222 POBJECT_HEADER ReapObject
, NextObject
;
227 /* Get the reap object */
228 ReapObject
= InterlockedExchangePointer(&ObpReaperList
, (PVOID
)1);
230 /* Start deletion loop */
233 /* Get the next object */
234 NextObject
= ReapObject
->NextToFree
;
236 /* Delete the object */
237 ObpDeleteObject(&ReapObject
->Body
, TRUE
);
239 /* Move to the next one */
240 ReapObject
= NextObject
;
241 } while ((ReapObject
) && (ReapObject
!= (PVOID
)1));
242 } while ((ObpReaperList
!= (PVOID
)1) ||
243 (InterlockedCompareExchange((PLONG
)&ObpReaperList
, 0, 1) != 1));
247 * @name ObpSetPermanentObject
249 * The ObpSetPermanentObject routine makes an sets or clears the permanent
250 * flag of an object, thus making it either permanent or temporary.
253 * Pointer to the object to make permanent or temporary.
256 * Flag specifying which operation to perform.
260 * @remarks If the object is being made temporary, then it will be checked
261 * as a candidate for immediate removal from the namespace.
266 ObpSetPermanentObject(IN PVOID ObjectBody
,
267 IN BOOLEAN Permanent
)
269 POBJECT_HEADER ObjectHeader
;
272 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(ObjectBody
);
274 /* Acquire object lock */
275 ObpAcquireObjectLock(ObjectHeader
);
277 /* Check what we're doing to it */
280 /* Set it to permanent */
281 ObjectHeader
->Flags
|= OB_FLAG_PERMANENT
;
283 /* Release the lock */
284 ObpReleaseObjectLock(ObjectHeader
);
288 /* Remove the flag */
289 ObjectHeader
->Flags
&= ~OB_FLAG_PERMANENT
;
291 /* Release the lock */
292 ObpReleaseObjectLock(ObjectHeader
);
294 /* Check if we should delete the object now */
295 ObpDeleteNameCheck(ObjectBody
);
301 ObpAllocateObjectNameBuffer(IN ULONG Length
,
302 IN BOOLEAN UseLookaside
,
303 IN OUT PUNICODE_STRING ObjectName
)
308 /* Set the maximum length to the length plus the terminator */
309 MaximumLength
= Length
+ sizeof(UNICODE_NULL
);
311 /* Check if we should use the lookaside buffer */
312 if (!(UseLookaside
) || (MaximumLength
> OBP_NAME_LOOKASIDE_MAX_SIZE
))
314 /* Nope, allocate directly from pool */
315 /* Since we later use MaximumLength to detect that we're not allocating
316 * from a list, we need at least MaximumLength + sizeof(UNICODE_NULL)
319 * People do call this with UseLookasideList FALSE so the distinction
322 if (MaximumLength
<= OBP_NAME_LOOKASIDE_MAX_SIZE
)
324 MaximumLength
= OBP_NAME_LOOKASIDE_MAX_SIZE
+ sizeof(UNICODE_NULL
);
326 Buffer
= ExAllocatePoolWithTag(PagedPool
,
332 /* Allocate from the lookaside */
333 MaximumLength
= OBP_NAME_LOOKASIDE_MAX_SIZE
;
334 Buffer
= ObpAllocateObjectCreateInfoBuffer(LookasideNameBufferList
);
337 /* Setup the string */
338 ObjectName
->MaximumLength
= (USHORT
)MaximumLength
;
339 ObjectName
->Length
= (USHORT
)Length
;
340 ObjectName
->Buffer
= Buffer
;
346 ObpFreeObjectNameBuffer(IN PUNICODE_STRING Name
)
348 PVOID Buffer
= Name
->Buffer
;
350 /* We know this is a pool-allocation if the size doesn't match */
351 if (Name
->MaximumLength
!= OBP_NAME_LOOKASIDE_MAX_SIZE
)
353 /* Free it from the pool */
358 /* Otherwise, free from the lookaside */
359 ObpFreeCapturedAttributes(Buffer
, LookasideNameBufferList
);
365 ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName
,
366 IN PUNICODE_STRING ObjectName
,
367 IN KPROCESSOR_MODE AccessMode
,
368 IN BOOLEAN UseLookaside
)
370 NTSTATUS Status
= STATUS_SUCCESS
;
372 PWCHAR StringBuffer
= NULL
;
373 UNICODE_STRING LocalName
;
376 /* Initialize the Input String */
377 RtlInitEmptyUnicodeString(CapturedName
, NULL
, 0);
379 /* Protect everything */
382 /* Check if we came from user mode */
383 if (AccessMode
!= KernelMode
)
385 /* First Probe the String */
386 LocalName
= ProbeForReadUnicodeString(ObjectName
);
387 ProbeForRead(LocalName
.Buffer
, LocalName
.Length
, sizeof(WCHAR
));
391 /* No probing needed */
392 LocalName
= *ObjectName
;
395 /* Make sure there really is a string */
396 if ((StringLength
= LocalName
.Length
))
398 /* Check that the size is a valid WCHAR multiple */
399 if ((StringLength
& (sizeof(WCHAR
) - 1)) ||
400 /* Check that the NULL-termination below will work */
401 (StringLength
== (MAXUSHORT
- sizeof(UNICODE_NULL
) + 1)))
403 /* PS: Please keep the checks above expanded for clarity */
404 Status
= STATUS_OBJECT_NAME_INVALID
;
408 /* Allocate the string buffer */
409 StringBuffer
= ObpAllocateObjectNameBuffer(StringLength
,
414 /* Set failure code */
415 Status
= STATUS_INSUFFICIENT_RESOURCES
;
420 RtlCopyMemory(StringBuffer
, LocalName
.Buffer
, StringLength
);
421 StringBuffer
[StringLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
426 _SEH2_EXCEPT(ExSystemExceptionFilter())
428 /* Handle exception and free the string buffer */
429 Status
= _SEH2_GetExceptionCode();
432 ObpFreeObjectNameBuffer(CapturedName
);
443 ObpCaptureObjectCreateInformation(IN POBJECT_ATTRIBUTES ObjectAttributes
,
444 IN KPROCESSOR_MODE AccessMode
,
445 IN BOOLEAN AllocateFromLookaside
,
446 IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
447 OUT PUNICODE_STRING ObjectName
)
449 NTSTATUS Status
= STATUS_SUCCESS
;
450 PSECURITY_DESCRIPTOR SecurityDescriptor
;
451 PSECURITY_QUALITY_OF_SERVICE SecurityQos
;
452 PUNICODE_STRING LocalObjectName
= NULL
;
455 /* Zero out the Capture Data */
456 RtlZeroMemory(ObjectCreateInfo
, sizeof(OBJECT_CREATE_INFORMATION
));
458 /* SEH everything here for protection */
461 /* Check if we got attributes */
462 if (ObjectAttributes
)
464 /* Check if we're in user mode */
465 if (AccessMode
!= KernelMode
)
467 /* Probe the attributes */
468 ProbeForRead(ObjectAttributes
,
469 sizeof(OBJECT_ATTRIBUTES
),
473 /* Validate the Size and Attributes */
474 if ((ObjectAttributes
->Length
!= sizeof(OBJECT_ATTRIBUTES
)) ||
475 (ObjectAttributes
->Attributes
& ~OBJ_VALID_ATTRIBUTES
))
477 /* Invalid combination, fail */
478 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
481 /* Set some Create Info */
482 ObjectCreateInfo
->RootDirectory
= ObjectAttributes
->RootDirectory
;
483 ObjectCreateInfo
->Attributes
= ObjectAttributes
->Attributes
;
484 LocalObjectName
= ObjectAttributes
->ObjectName
;
485 SecurityDescriptor
= ObjectAttributes
->SecurityDescriptor
;
486 SecurityQos
= ObjectAttributes
->SecurityQualityOfService
;
488 /* Check if we have a security descriptor */
489 if (SecurityDescriptor
)
492 Status
= SeCaptureSecurityDescriptor(SecurityDescriptor
,
498 if (!NT_SUCCESS(Status
))
500 /* Capture failed, quit */
501 ObjectCreateInfo
->SecurityDescriptor
= NULL
;
502 _SEH2_YIELD(return Status
);
505 /* Save the probe mode and security descriptor size */
506 ObjectCreateInfo
->SecurityDescriptorCharge
= 2048; /* FIXME */
507 ObjectCreateInfo
->ProbeMode
= AccessMode
;
510 /* Check if we have QoS */
513 /* Check if we came from user mode */
514 if (AccessMode
!= KernelMode
)
516 /* Validate the QoS */
517 ProbeForRead(SecurityQos
,
518 sizeof(SECURITY_QUALITY_OF_SERVICE
),
523 ObjectCreateInfo
->SecurityQualityOfService
= *SecurityQos
;
524 ObjectCreateInfo
->SecurityQos
=
525 &ObjectCreateInfo
->SecurityQualityOfService
;
530 /* We don't have a name */
531 LocalObjectName
= NULL
;
534 _SEH2_EXCEPT(ExSystemExceptionFilter())
536 /* Cleanup and return the exception code */
537 ObpReleaseObjectCreateInformation(ObjectCreateInfo
);
538 _SEH2_YIELD(return _SEH2_GetExceptionCode());
542 /* Now check if the Object Attributes had an Object Name */
545 Status
= ObpCaptureObjectName(ObjectName
,
548 AllocateFromLookaside
);
552 /* Clear the string */
553 RtlInitEmptyUnicodeString(ObjectName
, NULL
, 0);
555 /* He can't have specified a Root Directory */
556 if (ObjectCreateInfo
->RootDirectory
)
558 Status
= STATUS_OBJECT_NAME_INVALID
;
562 /* Cleanup if we failed */
563 if (!NT_SUCCESS(Status
))
565 ObpReleaseObjectCreateInformation(ObjectCreateInfo
);
568 /* Return status to caller */
574 ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
)
576 /* Call the macro. We use this function to isolate Ob internals from Io */
577 ObpFreeCapturedAttributes(ObjectCreateInfo
, LookasideCreateInfoList
);
582 ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
583 IN PUNICODE_STRING ObjectName
,
584 IN POBJECT_TYPE ObjectType
,
586 IN KPROCESSOR_MODE PreviousMode
,
587 IN POBJECT_HEADER
*ObjectHeader
)
589 POBJECT_HEADER Header
;
590 ULONG QuotaSize
, HandleSize
, NameSize
, CreatorSize
;
591 POBJECT_HEADER_HANDLE_INFO HandleInfo
;
592 POBJECT_HEADER_NAME_INFO NameInfo
;
593 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
594 POBJECT_HEADER_QUOTA_INFO QuotaInfo
;
603 /* Check if we don't have an Object Type yet */
606 /* Use default tag and non-paged pool */
607 PoolType
= NonPagedPool
;
612 /* Use the pool and tag given */
613 PoolType
= ObjectType
->TypeInfo
.PoolType
;
614 Tag
= ObjectType
->Key
;
617 /* Check if we have no create information (ie: we're an object type) */
618 if (!ObjectCreateInfo
)
621 QuotaSize
= HandleSize
= 0;
622 NameSize
= sizeof(OBJECT_HEADER_NAME_INFO
);
623 CreatorSize
= sizeof(OBJECT_HEADER_CREATOR_INFO
);
627 /* Check if we have quota */
628 if ((((ObjectCreateInfo
->PagedPoolCharge
!=
629 ObjectType
->TypeInfo
.DefaultPagedPoolCharge
) ||
630 (ObjectCreateInfo
->NonPagedPoolCharge
!=
631 ObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
) ||
632 (ObjectCreateInfo
->SecurityDescriptorCharge
> 2048)) &&
633 (PsGetCurrentProcess() != PsInitialSystemProcess
)) ||
634 (ObjectCreateInfo
->Attributes
& OBJ_EXCLUSIVE
))
637 QuotaSize
= sizeof(OBJECT_HEADER_QUOTA_INFO
);
638 ObpObjectsWithPoolQuota
++;
646 /* Check if we have a handle database */
647 if (ObjectType
->TypeInfo
.MaintainHandleCount
)
649 /* Set handle database size */
650 HandleSize
= sizeof(OBJECT_HEADER_HANDLE_INFO
);
651 ObpObjectsWithHandleDB
++;
659 /* Check if the Object has a name */
660 if (ObjectName
->Buffer
)
663 NameSize
= sizeof(OBJECT_HEADER_NAME_INFO
);
664 ObpObjectsWithName
++;
672 /* Check if the Object maintains type lists */
673 if (ObjectType
->TypeInfo
.MaintainTypeList
)
675 /* Set owner/creator size */
676 CreatorSize
= sizeof(OBJECT_HEADER_CREATOR_INFO
);
677 ObpObjectsWithCreatorInfo
++;
686 /* Set final header size */
687 FinalSize
= QuotaSize
+
691 FIELD_OFFSET(OBJECT_HEADER
, Body
);
693 /* Allocate memory for the Object and Header */
694 Header
= ExAllocatePoolWithTag(PoolType
, FinalSize
+ ObjectSize
, Tag
);
695 if (!Header
) return STATUS_INSUFFICIENT_RESOURCES
;
697 /* Check if we have a quota header */
700 /* Initialize quota info */
701 QuotaInfo
= (POBJECT_HEADER_QUOTA_INFO
)Header
;
702 QuotaInfo
->PagedPoolCharge
= ObjectCreateInfo
->PagedPoolCharge
;
703 QuotaInfo
->NonPagedPoolCharge
= ObjectCreateInfo
->NonPagedPoolCharge
;
704 QuotaInfo
->SecurityDescriptorCharge
= ObjectCreateInfo
->SecurityDescriptorCharge
;
705 QuotaInfo
->ExclusiveProcess
= NULL
;
706 Header
= (POBJECT_HEADER
)(QuotaInfo
+ 1);
709 /* Check if we have a handle database header */
712 /* Initialize Handle Info */
713 HandleInfo
= (POBJECT_HEADER_HANDLE_INFO
)Header
;
714 HandleInfo
->SingleEntry
.HandleCount
= 0;
715 Header
= (POBJECT_HEADER
)(HandleInfo
+ 1);
718 /* Check if we have a name header */
721 /* Initialize the Object Name Info */
722 NameInfo
= (POBJECT_HEADER_NAME_INFO
)Header
;
723 NameInfo
->Name
= *ObjectName
;
724 NameInfo
->Directory
= NULL
;
725 NameInfo
->QueryReferences
= 1;
727 /* Check if this is a call with the special protection flag */
728 if ((PreviousMode
== KernelMode
) &&
729 (ObjectCreateInfo
) &&
730 (ObjectCreateInfo
->Attributes
& 0x10000))
732 /* Set flag which will make the object protected from user-mode */
733 NameInfo
->QueryReferences
|= 0x40000000;
736 /* Set the header pointer */
737 Header
= (POBJECT_HEADER
)(NameInfo
+ 1);
740 /* Check if we have a creator header */
743 /* Initialize Creator Info */
744 CreatorInfo
= (POBJECT_HEADER_CREATOR_INFO
)Header
;
745 CreatorInfo
->CreatorBackTraceIndex
= 0;
746 CreatorInfo
->CreatorUniqueProcess
= PsGetCurrentProcessId();
747 InitializeListHead(&CreatorInfo
->TypeList
);
748 Header
= (POBJECT_HEADER
)(CreatorInfo
+ 1);
751 /* Check for quota information */
755 Header
->QuotaInfoOffset
= (UCHAR
)(QuotaSize
+
763 Header
->QuotaInfoOffset
= 0;
766 /* Check for handle information */
770 Header
->HandleInfoOffset
= (UCHAR
)(HandleSize
+
777 Header
->HandleInfoOffset
= 0;
780 /* Check for name information */
784 Header
->NameInfoOffset
= (UCHAR
)(NameSize
+ CreatorSize
);
789 Header
->NameInfoOffset
= 0;
792 /* Set the new object flag */
793 Header
->Flags
= OB_FLAG_CREATE_INFO
;
795 /* Remember if we have creator info */
796 if (CreatorSize
) Header
->Flags
|= OB_FLAG_CREATOR_INFO
;
798 /* Remember if we have handle info */
799 if (HandleSize
) Header
->Flags
|= OB_FLAG_SINGLE_PROCESS
;
801 /* Initialize the object header */
802 Header
->PointerCount
= 1;
803 Header
->HandleCount
= 0;
804 Header
->Type
= ObjectType
;
805 Header
->ObjectCreateInfo
= ObjectCreateInfo
;
806 Header
->SecurityDescriptor
= NULL
;
808 /* Check if this is a permanent object */
809 if ((ObjectCreateInfo
) && (ObjectCreateInfo
->Attributes
& OBJ_PERMANENT
))
811 /* Set the needed flag so we can check */
812 Header
->Flags
|= OB_FLAG_PERMANENT
;
815 /* Check if this is an exclusive object */
816 if ((ObjectCreateInfo
) && (ObjectCreateInfo
->Attributes
& OBJ_EXCLUSIVE
))
818 /* Set the needed flag so we can check */
819 Header
->Flags
|= OB_FLAG_EXCLUSIVE
;
822 /* Set kernel-mode flag */
823 if (PreviousMode
== KernelMode
) Header
->Flags
|= OB_FLAG_KERNEL_MODE
;
825 /* Check if we have a type */
828 /* Increase the number of objects of this type */
829 InterlockedIncrement((PLONG
)&ObjectType
->TotalNumberOfObjects
);
831 /* Update the high water */
832 ObjectType
->HighWaterNumberOfObjects
= max(ObjectType
->
833 TotalNumberOfObjects
,
835 HighWaterNumberOfObjects
);
839 *ObjectHeader
= Header
;
840 return STATUS_SUCCESS
;
845 ObQueryTypeInfo(IN POBJECT_TYPE ObjectType
,
846 OUT POBJECT_TYPE_INFORMATION ObjectTypeInfo
,
848 OUT PULONG ReturnLength
)
850 NTSTATUS Status
= STATUS_SUCCESS
;
856 /* Set return length aligned to 4-byte boundary */
857 *ReturnLength
+= sizeof(*ObjectTypeInfo
) +
858 ALIGN_UP(ObjectType
->Name
.MaximumLength
, ULONG
);
860 /* Check if thats too much though. */
861 if (Length
< *ReturnLength
)
863 _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
867 ObjectTypeInfo
->TotalNumberOfHandles
=
868 ObjectType
->TotalNumberOfHandles
;
869 ObjectTypeInfo
->TotalNumberOfObjects
=
870 ObjectType
->TotalNumberOfObjects
;
871 ObjectTypeInfo
->HighWaterNumberOfHandles
=
872 ObjectType
->HighWaterNumberOfHandles
;
873 ObjectTypeInfo
->HighWaterNumberOfObjects
=
874 ObjectType
->HighWaterNumberOfObjects
;
875 ObjectTypeInfo
->PoolType
=
876 ObjectType
->TypeInfo
.PoolType
;
877 ObjectTypeInfo
->DefaultNonPagedPoolCharge
=
878 ObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
;
879 ObjectTypeInfo
->DefaultPagedPoolCharge
=
880 ObjectType
->TypeInfo
.DefaultPagedPoolCharge
;
881 ObjectTypeInfo
->ValidAccessMask
=
882 ObjectType
->TypeInfo
.ValidAccessMask
;
883 ObjectTypeInfo
->SecurityRequired
=
884 ObjectType
->TypeInfo
.SecurityRequired
;
885 ObjectTypeInfo
->InvalidAttributes
=
886 ObjectType
->TypeInfo
.InvalidAttributes
;
887 ObjectTypeInfo
->GenericMapping
=
888 ObjectType
->TypeInfo
.GenericMapping
;
889 ObjectTypeInfo
->MaintainHandleCount
=
890 ObjectType
->TypeInfo
.MaintainHandleCount
;
892 /* Setup the name buffer */
893 InfoBuffer
= (PWSTR
)(ObjectTypeInfo
+ 1);
894 ObjectTypeInfo
->TypeName
.Buffer
= InfoBuffer
;
895 ObjectTypeInfo
->TypeName
.MaximumLength
= ObjectType
->Name
.MaximumLength
;
896 ObjectTypeInfo
->TypeName
.Length
= ObjectType
->Name
.Length
;
899 RtlCopyMemory(InfoBuffer
,
900 ObjectType
->Name
.Buffer
,
901 ObjectType
->Name
.Length
);
903 /* Null-terminate it */
904 (InfoBuffer
)[ObjectType
->Name
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
906 _SEH2_EXCEPT(ExSystemExceptionFilter())
908 /* Otherwise, get the exception code */
909 Status
= _SEH2_GetExceptionCode();
913 /* Return status to caller */
918 /* PUBLIC FUNCTIONS **********************************************************/
922 ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL
,
923 IN POBJECT_TYPE Type
,
924 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
925 IN KPROCESSOR_MODE AccessMode
,
926 IN OUT PVOID ParseContext OPTIONAL
,
928 IN ULONG PagedPoolCharge OPTIONAL
,
929 IN ULONG NonPagedPoolCharge OPTIONAL
,
933 POBJECT_CREATE_INFORMATION ObjectCreateInfo
;
934 UNICODE_STRING ObjectName
;
935 POBJECT_HEADER Header
;
937 /* Allocate a capture buffer */
938 ObjectCreateInfo
= ObpAllocateObjectCreateInfoBuffer(LookasideCreateInfoList
);
939 if (!ObjectCreateInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
941 /* Capture all the info */
942 Status
= ObpCaptureObjectCreateInformation(ObjectAttributes
,
947 if (NT_SUCCESS(Status
))
949 /* Validate attributes */
950 if (Type
->TypeInfo
.InvalidAttributes
& ObjectCreateInfo
->Attributes
)
953 Status
= STATUS_INVALID_PARAMETER
;
957 /* Check if we have a paged charge */
958 if (!PagedPoolCharge
)
961 PagedPoolCharge
= Type
->TypeInfo
.DefaultPagedPoolCharge
;
964 /* Check for nonpaged charge */
965 if (!NonPagedPoolCharge
)
968 NonPagedPoolCharge
= Type
->TypeInfo
.DefaultNonPagedPoolCharge
;
971 /* Write the pool charges */
972 ObjectCreateInfo
->PagedPoolCharge
= PagedPoolCharge
;
973 ObjectCreateInfo
->NonPagedPoolCharge
= NonPagedPoolCharge
;
975 /* Allocate the Object */
976 Status
= ObpAllocateObject(ObjectCreateInfo
,
982 if (NT_SUCCESS(Status
))
984 /* Return the Object */
985 *Object
= &Header
->Body
;
987 /* Check if this is a permanent object */
988 if (Header
->Flags
& OB_FLAG_PERMANENT
)
990 /* Do the privilege check */
991 if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege
,
995 ObpDeallocateObject(*Object
);
996 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1005 /* Release the Capture Info, we don't need it */
1006 ObpFreeObjectCreateInformation(ObjectCreateInfo
);
1007 if (ObjectName
.Buffer
) ObpFreeObjectNameBuffer(&ObjectName
);
1010 /* We failed, so release the Buffer */
1011 ObpFreeCapturedAttributes(ObjectCreateInfo
, LookasideCreateInfoList
);
1017 ObCreateObjectType(IN PUNICODE_STRING TypeName
,
1018 IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer
,
1020 OUT POBJECT_TYPE
*ObjectType
)
1022 POBJECT_HEADER Header
;
1023 POBJECT_TYPE LocalObjectType
;
1027 OBP_LOOKUP_CONTEXT Context
;
1030 UNICODE_STRING ObjectName
;
1031 POBJECT_HEADER_CREATOR_INFO CreatorInfo
;
1033 /* Verify parameters */
1035 !(TypeName
->Length
) ||
1036 (TypeName
->Length
% sizeof(WCHAR
)) ||
1037 !(ObjectTypeInitializer
) ||
1038 (ObjectTypeInitializer
->Length
!= sizeof(*ObjectTypeInitializer
)) ||
1039 (ObjectTypeInitializer
->InvalidAttributes
& ~OBJ_VALID_ATTRIBUTES
) ||
1040 (ObjectTypeInitializer
->MaintainHandleCount
&&
1041 (!(ObjectTypeInitializer
->OpenProcedure
) &&
1042 !ObjectTypeInitializer
->CloseProcedure
)) ||
1043 ((!ObjectTypeInitializer
->UseDefaultObject
) &&
1044 (ObjectTypeInitializer
->PoolType
!= NonPagedPool
)))
1047 return STATUS_INVALID_PARAMETER
;
1050 /* Make sure the name doesn't have a separator */
1051 p
= TypeName
->Buffer
;
1052 i
= TypeName
->Length
/ sizeof(WCHAR
);
1055 /* Check for one and fail */
1056 if (*p
++ == OBJ_NAME_PATH_SEPARATOR
) return STATUS_OBJECT_NAME_INVALID
;
1059 /* Setup a lookup context */
1060 ObpInitializeLookupContext(&Context
);
1062 /* Check if we've already created the directory of types */
1063 if (ObpTypeDirectoryObject
)
1065 /* Acquire the directory lock */
1066 ObpAcquireDirectoryLockExclusive(ObpTypeDirectoryObject
, &Context
);
1069 if (ObpLookupEntryDirectory(ObpTypeDirectoryObject
,
1071 OBJ_CASE_INSENSITIVE
,
1075 /* We have already created it, so fail */
1076 ObpReleaseLookupContext(&Context
);
1077 return STATUS_OBJECT_NAME_COLLISION
;
1081 /* Now make a copy of the object name */
1082 ObjectName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1083 TypeName
->MaximumLength
,
1085 if (!ObjectName
.Buffer
)
1087 /* Out of memory, fail */
1088 ObpReleaseLookupContext(&Context
);
1089 return STATUS_INSUFFICIENT_RESOURCES
;
1092 /* Set the length and copy the name */
1093 ObjectName
.MaximumLength
= TypeName
->MaximumLength
;
1094 RtlCopyUnicodeString(&ObjectName
, TypeName
);
1096 /* Allocate the Object */
1097 Status
= ObpAllocateObject(NULL
,
1100 sizeof(OBJECT_TYPE
),
1102 (POBJECT_HEADER
*)&Header
);
1103 if (!NT_SUCCESS(Status
))
1105 /* Free the name and fail */
1106 ObpReleaseLookupContext(&Context
);
1107 ExFreePool(ObjectName
.Buffer
);
1111 /* Setup the flags and name */
1112 LocalObjectType
= (POBJECT_TYPE
)&Header
->Body
;
1113 LocalObjectType
->Name
= ObjectName
;
1114 Header
->Flags
|= OB_FLAG_KERNEL_MODE
| OB_FLAG_PERMANENT
;
1116 /* Clear accounting data */
1117 LocalObjectType
->TotalNumberOfObjects
=
1118 LocalObjectType
->TotalNumberOfHandles
=
1119 LocalObjectType
->HighWaterNumberOfObjects
=
1120 LocalObjectType
->HighWaterNumberOfHandles
= 0;
1122 /* Check if this is the first Object Type */
1123 if (!ObpTypeObjectType
)
1125 /* It is, so set this as the type object */
1126 ObpTypeObjectType
= LocalObjectType
;
1127 Header
->Type
= ObpTypeObjectType
;
1129 /* Set the hard-coded key and object count */
1130 LocalObjectType
->TotalNumberOfObjects
= 1;
1131 LocalObjectType
->Key
= 'TjbO';
1136 Tag
[0] = (CHAR
)TypeName
->Buffer
[0];
1137 Tag
[1] = (CHAR
)TypeName
->Buffer
[1];
1138 Tag
[2] = (CHAR
)TypeName
->Buffer
[2];
1139 Tag
[3] = (CHAR
)TypeName
->Buffer
[3];
1140 LocalObjectType
->Key
= *(PULONG
)Tag
;
1143 /* Set up the type information */
1144 LocalObjectType
->TypeInfo
= *ObjectTypeInitializer
;
1145 LocalObjectType
->TypeInfo
.PoolType
= ObjectTypeInitializer
->PoolType
;
1147 /* Check if we have to maintain a type list */
1148 if (NtGlobalFlag
& FLG_MAINTAIN_OBJECT_TYPELIST
)
1150 /* Enable support */
1151 LocalObjectType
->TypeInfo
.MaintainTypeList
= TRUE
;
1154 /* Calculate how much space our header'll take up */
1155 HeaderSize
= sizeof(OBJECT_HEADER
) +
1156 sizeof(OBJECT_HEADER_NAME_INFO
) +
1157 (ObjectTypeInitializer
->MaintainHandleCount
?
1158 sizeof(OBJECT_HEADER_HANDLE_INFO
) : 0);
1160 /* Check the pool type */
1161 if (ObjectTypeInitializer
->PoolType
== NonPagedPool
)
1163 /* Update the NonPaged Pool charge */
1164 LocalObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
+= HeaderSize
;
1168 /* Update the Paged Pool charge */
1169 LocalObjectType
->TypeInfo
.DefaultPagedPoolCharge
+= HeaderSize
;
1172 /* All objects types need a security procedure */
1173 if (!ObjectTypeInitializer
->SecurityProcedure
)
1175 LocalObjectType
->TypeInfo
.SecurityProcedure
= SeDefaultObjectMethod
;
1178 /* Select the Wait Object */
1179 if (LocalObjectType
->TypeInfo
.UseDefaultObject
)
1181 /* Add the SYNCHRONIZE access mask since it's waitable */
1182 LocalObjectType
->TypeInfo
.ValidAccessMask
|= SYNCHRONIZE
;
1184 /* Use the "Default Object", a simple event */
1185 LocalObjectType
->DefaultObject
= &ObpDefaultObject
;
1187 /* The File Object gets an optimized hack so it can be waited on */
1188 else if ((TypeName
->Length
== 8) && !(wcscmp(TypeName
->Buffer
, L
"File")))
1190 /* Wait on the File Object's event directly */
1191 LocalObjectType
->DefaultObject
= (PVOID
)FIELD_OFFSET(FILE_OBJECT
,
1194 else if ((TypeName
->Length
== 24) && !(wcscmp(TypeName
->Buffer
, L
"WaitablePort")))
1196 /* Wait on the LPC Port's object directly */
1197 LocalObjectType
->DefaultObject
= (PVOID
)FIELD_OFFSET(LPCP_PORT_OBJECT
,
1202 /* No default Object */
1203 LocalObjectType
->DefaultObject
= NULL
;
1206 /* Initialize Object Type components */
1207 ExInitializeResourceLite(&LocalObjectType
->Mutex
);
1208 for (i
= 0; i
< 4; i
++)
1210 /* Initialize the object locks */
1211 ExInitializeResourceLite(&LocalObjectType
->ObjectLocks
[i
]);
1213 InitializeListHead(&LocalObjectType
->TypeList
);
1215 /* Lock the object type */
1216 ObpEnterObjectTypeMutex(LocalObjectType
);
1218 /* Get creator info and insert it into the type list */
1219 CreatorInfo
= OBJECT_HEADER_TO_CREATOR_INFO(Header
);
1220 if (CreatorInfo
) InsertTailList(&ObpTypeObjectType
->TypeList
,
1221 &CreatorInfo
->TypeList
);
1223 /* Set the index and the entry into the object type array */
1224 LocalObjectType
->Index
= ObpTypeObjectType
->TotalNumberOfObjects
;
1225 if (LocalObjectType
->Index
< 32)
1227 /* It fits, insert it */
1228 ObpObjectTypes
[LocalObjectType
->Index
- 1] = LocalObjectType
;
1231 /* Release the object type */
1232 ObpLeaveObjectTypeMutex(LocalObjectType
);
1234 /* Check if we're actually creating the directory object itself */
1235 if (!(ObpTypeDirectoryObject
) ||
1236 (ObpInsertEntryDirectory(ObpTypeDirectoryObject
, &Context
, Header
)))
1238 /* Check if the type directory exists */
1239 if (ObpTypeDirectoryObject
)
1242 ObReferenceObject(ObpTypeDirectoryObject
);
1245 /* Cleanup the lookup context */
1246 ObpReleaseLookupContext(&Context
);
1248 /* Return the object type and success */
1249 *ObjectType
= LocalObjectType
;
1250 return STATUS_SUCCESS
;
1253 /* If we got here, then we failed */
1254 ObpReleaseLookupContext(&Context
);
1255 return STATUS_INSUFFICIENT_RESOURCES
;
1260 ObpDeleteObjectType(IN PVOID Object
)
1263 POBJECT_TYPE ObjectType
= (PVOID
)Object
;
1265 /* Loop our locks */
1266 for (i
= 0; i
< 4; i
++)
1268 /* Delete each one */
1269 ExDeleteResourceLite(&ObjectType
->ObjectLocks
[i
]);
1272 /* Delete our main mutex */
1273 ExDeleteResourceLite(&ObjectType
->Mutex
);
1277 * @name ObMakeTemporaryObject
1280 * The ObMakeTemporaryObject routine <FILLMEIN>
1292 ObMakeTemporaryObject(IN PVOID ObjectBody
)
1296 /* Call the internal API */
1297 ObpSetPermanentObject(ObjectBody
, FALSE
);
1301 * @name NtMakeTemporaryObject
1304 * The NtMakeTemporaryObject routine <FILLMEIN>
1306 * @param ObjectHandle
1309 * @return STATUS_SUCCESS or appropriate error value.
1316 NtMakeTemporaryObject(IN HANDLE ObjectHandle
)
1322 /* Reference the object for DELETE access */
1323 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1326 KeGetPreviousMode(),
1329 if (Status
!= STATUS_SUCCESS
) return Status
;
1331 /* Set it as temporary and dereference it */
1332 ObpSetPermanentObject(ObjectBody
, FALSE
);
1333 ObDereferenceObject(ObjectBody
);
1334 return STATUS_SUCCESS
;
1338 * @name NtMakePermanentObject
1341 * The NtMakePermanentObject routine <FILLMEIN>
1343 * @param ObjectHandle
1346 * @return STATUS_SUCCESS or appropriate error value.
1353 NtMakePermanentObject(IN HANDLE ObjectHandle
)
1357 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1360 /* Make sure that the caller has SeCreatePermanentPrivilege */
1361 Status
= SeSinglePrivilegeCheck(SeCreatePermanentPrivilege
,
1363 if (!NT_SUCCESS(Status
)) return STATUS_PRIVILEGE_NOT_HELD
;
1365 /* Reference the object */
1366 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1372 if (Status
!= STATUS_SUCCESS
) return Status
;
1374 /* Set it as permanent and dereference it */
1375 ObpSetPermanentObject(ObjectBody
, TRUE
);
1376 ObDereferenceObject(ObjectBody
);
1377 return STATUS_SUCCESS
;
1381 * @name NtQueryObject
1384 * The NtQueryObject routine <FILLMEIN>
1386 * @param ObjectHandle
1389 * @param ObjectInformationClass
1392 * @param ObjectInformation
1398 * @param ResultLength
1401 * @return STATUS_SUCCESS or appropriate error value.
1408 NtQueryObject(IN HANDLE ObjectHandle
,
1409 IN OBJECT_INFORMATION_CLASS ObjectInformationClass
,
1410 OUT PVOID ObjectInformation
,
1412 OUT PULONG ResultLength OPTIONAL
)
1414 OBJECT_HANDLE_INFORMATION HandleInfo
;
1415 POBJECT_HEADER ObjectHeader
= NULL
;
1416 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags
;
1417 POBJECT_BASIC_INFORMATION BasicInfo
;
1419 PVOID Object
= NULL
;
1421 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1424 /* Check if the caller is from user mode */
1425 if (PreviousMode
!= KernelMode
)
1427 /* Protect validation with SEH */
1430 /* Probe the input structure */
1431 ProbeForWrite(ObjectInformation
, Length
, sizeof(UCHAR
));
1433 /* If we have a result length, probe it too */
1434 if (ResultLength
) ProbeForWriteUlong(ResultLength
);
1436 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1438 /* Return the exception code */
1439 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1445 * Make sure this isn't a generic type query, since the caller doesn't
1446 * have to give a handle for it
1448 if (ObjectInformationClass
!= ObjectTypesInformation
)
1450 /* Reference the object */
1451 Status
= ObReferenceObjectByHandle(ObjectHandle
,
1454 KeGetPreviousMode(),
1457 if (!NT_SUCCESS (Status
)) return Status
;
1459 /* Get the object header */
1460 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1465 /* Check the information class */
1466 switch (ObjectInformationClass
)
1469 case ObjectBasicInformation
:
1471 /* Validate length */
1472 InfoLength
= sizeof(OBJECT_BASIC_INFORMATION
);
1473 if (Length
!= sizeof(OBJECT_BASIC_INFORMATION
))
1476 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1480 /* Fill out the basic information */
1481 BasicInfo
= (POBJECT_BASIC_INFORMATION
)ObjectInformation
;
1482 BasicInfo
->Attributes
= HandleInfo
.HandleAttributes
;
1483 BasicInfo
->GrantedAccess
= HandleInfo
.GrantedAccess
;
1484 BasicInfo
->HandleCount
= ObjectHeader
->HandleCount
;
1485 BasicInfo
->PointerCount
= ObjectHeader
->PointerCount
;
1487 /* Permanent/Exclusive Flags are NOT in Handle attributes! */
1488 if (ObjectHeader
->Flags
& OB_FLAG_EXCLUSIVE
)
1491 BasicInfo
->Attributes
|= OBJ_EXCLUSIVE
;
1493 if (ObjectHeader
->Flags
& OB_FLAG_PERMANENT
)
1496 BasicInfo
->Attributes
|= OBJ_PERMANENT
;
1499 /* Copy quota information */
1500 BasicInfo
->PagedPoolCharge
= 0; /* FIXME*/
1501 BasicInfo
->NonPagedPoolCharge
= 0; /* FIXME*/
1503 /* Copy name information */
1504 BasicInfo
->NameInfoSize
= 0; /* FIXME*/
1505 BasicInfo
->TypeInfoSize
= 0; /* FIXME*/
1507 /* Copy security information */
1508 BasicInfo
->SecurityDescriptorSize
= 0; /* FIXME*/
1510 /* Check if this is a symlink */
1511 if (ObjectHeader
->Type
== ObSymbolicLinkType
)
1513 /* Return the creation time */
1514 BasicInfo
->CreationTime
.QuadPart
=
1515 ((POBJECT_SYMBOLIC_LINK
)Object
)->CreationTime
.QuadPart
;
1519 /* Otherwise return 0 */
1520 BasicInfo
->CreationTime
.QuadPart
= (ULONGLONG
)0;
1523 /* Break out with success */
1524 Status
= STATUS_SUCCESS
;
1527 /* Name information */
1528 case ObjectNameInformation
:
1530 /* Call the helper and break out */
1531 Status
= ObQueryNameString(Object
,
1532 (POBJECT_NAME_INFORMATION
)
1538 /* Information about this type */
1539 case ObjectTypeInformation
:
1541 /* Call the helper and break out */
1542 Status
= ObQueryTypeInfo(ObjectHeader
->Type
,
1543 (POBJECT_TYPE_INFORMATION
)
1549 /* Information about all types */
1550 case ObjectTypesInformation
:
1551 DPRINT1("NOT IMPLEMENTED!\n");
1552 Status
= STATUS_NOT_IMPLEMENTED
;
1555 /* Information about the handle flags */
1556 case ObjectHandleFlagInformation
:
1558 /* Validate length */
1559 InfoLength
= sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION
);
1560 if (Length
!= sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION
))
1562 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1566 /* Get the structure */
1567 HandleFlags
= (POBJECT_HANDLE_ATTRIBUTE_INFORMATION
)
1571 HandleFlags
->Inherit
= HandleInfo
.HandleAttributes
& OBJ_INHERIT
;
1572 HandleFlags
->ProtectFromClose
= (HandleInfo
.HandleAttributes
&
1573 OBJ_PROTECT_CLOSE
) != 0;
1575 /* Break out with success */
1576 Status
= STATUS_SUCCESS
;
1583 Status
= STATUS_INVALID_INFO_CLASS
;
1587 /* Check if the caller wanted the return length */
1590 /* Write the length */
1591 *ResultLength
= Length
;
1594 _SEH2_EXCEPT(ExSystemExceptionFilter())
1596 /* Otherwise, get the exception code */
1597 Status
= _SEH2_GetExceptionCode();
1601 /* Dereference the object if we had referenced it */
1602 if (Object
) ObDereferenceObject (Object
);
1609 * @name NtSetInformationObject
1612 * The NtSetInformationObject routine <FILLMEIN>
1614 * @param ObjectHandle
1617 * @param ObjectInformationClass
1620 * @param ObjectInformation
1626 * @return STATUS_SUCCESS or appropriate error value.
1633 NtSetInformationObject(IN HANDLE ObjectHandle
,
1634 IN OBJECT_INFORMATION_CLASS ObjectInformationClass
,
1635 IN PVOID ObjectInformation
,
1639 OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context
;
1641 KAPC_STATE ApcState
;
1642 BOOLEAN AttachedToProcess
= FALSE
;
1645 /* Validate the information class */
1646 if (ObjectInformationClass
!= ObjectHandleFlagInformation
)
1649 return STATUS_INVALID_INFO_CLASS
;
1652 /* Validate the length */
1653 if (Length
!= sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION
))
1655 /* Invalid length */
1656 return STATUS_INFO_LENGTH_MISMATCH
;
1659 /* Save the previous mode */
1660 Context
.PreviousMode
= ExGetPreviousMode();
1662 /* Check if we were called from user mode */
1663 if (Context
.PreviousMode
!= KernelMode
)
1668 /* Probe and capture the attribute buffer */
1669 ProbeForRead(ObjectInformation
,
1670 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION
),
1672 Context
.Information
= *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION
)
1675 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1677 /* Return the exception code */
1678 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1684 /* Just copy the buffer directly */
1685 Context
.Information
= *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION
)
1689 /* Check if this is a kernel handle */
1690 if (ObIsKernelHandle(ObjectHandle
, Context
.PreviousMode
))
1692 /* Get the actual handle */
1693 ObjectHandle
= ObKernelHandleToHandle(ObjectHandle
);
1694 ObjectTable
= ObpKernelHandleTable
;
1696 /* Check if we're not in the system process */
1697 if (PsGetCurrentProcess() != PsInitialSystemProcess
)
1700 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1701 AttachedToProcess
= TRUE
;
1706 /* Use the current table */
1707 ObjectTable
= PsGetCurrentProcess()->ObjectTable
;
1710 /* Change the handle attributes */
1711 if (!ExChangeHandle(ObjectTable
,
1713 ObpSetHandleAttributes
,
1714 (ULONG_PTR
)&Context
))
1717 Status
= STATUS_ACCESS_DENIED
;
1722 Status
= STATUS_SUCCESS
;
1725 /* De-attach if we were attached, and return status */
1726 if (AttachedToProcess
) KeUnstackDetachProcess(&ApcState
);