xref: /reactos/ntoskrnl/ob/oblife.c (revision 8e7b22a6)
1 /*
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)
10  *                  Eric Kohl
11  *                  Thomas Weidenmueller (w3seek@reactos.org)
12  */
13 
14 /* INCLUDES ******************************************************************/
15 
16 #include <ntoskrnl.h>
17 #define NDEBUG
18 #include <debug.h>
19 
20 extern ULONG NtGlobalFlag;
21 
22 POBJECT_TYPE ObpTypeObjectType = NULL;
23 KEVENT ObpDefaultObject;
24 KGUARDED_MUTEX ObpDeviceMapLock;
25 
26 GENERAL_LOOKASIDE ObpNameBufferLookasideList, ObpCreateInfoLookasideList;
27 
28 WORK_QUEUE_ITEM ObpReaperWorkItem;
29 volatile PVOID ObpReaperList;
30 
31 ULONG ObpObjectsCreated, ObpObjectsWithName, ObpObjectsWithPoolQuota;
32 ULONG ObpObjectsWithHandleDB, ObpObjectsWithCreatorInfo;
33 POBJECT_TYPE ObpObjectTypes[32];
34 
35 /* PRIVATE FUNCTIONS *********************************************************/
36 
37 VOID
38 FASTCALL
ObpDeallocateObject(IN PVOID Object)39 ObpDeallocateObject(IN PVOID Object)
40 {
41     PVOID HeaderLocation;
42     POBJECT_HEADER Header;
43     POBJECT_TYPE ObjectType;
44     POBJECT_HEADER_HANDLE_INFO HandleInfo;
45     POBJECT_HEADER_NAME_INFO NameInfo;
46     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
47     POBJECT_HEADER_QUOTA_INFO QuotaInfo;
48     ULONG PagedPoolCharge, NonPagedPoolCharge;
49     PAGED_CODE();
50 
51     /* Get the header and assume this is what we'll free */
52     Header = OBJECT_TO_OBJECT_HEADER(Object);
53     ObjectType = Header->Type;
54     HeaderLocation = Header;
55 
56     /* To find the header, walk backwards from how we allocated */
57     if ((CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header)))
58     {
59         HeaderLocation = CreatorInfo;
60     }
61     if ((NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header)))
62     {
63         HeaderLocation = NameInfo;
64     }
65     if ((HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(Header)))
66     {
67         HeaderLocation = HandleInfo;
68     }
69     if ((QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO(Header)))
70     {
71         HeaderLocation = QuotaInfo;
72     }
73 
74     /* Decrease the total */
75     InterlockedDecrement((PLONG)&ObjectType->TotalNumberOfObjects);
76 
77     /* Check if we have create info */
78     if (Header->Flags & OB_FLAG_CREATE_INFO)
79     {
80         /* Double-check that it exists */
81         if (Header->ObjectCreateInfo)
82         {
83             /* Free it */
84             ObpFreeObjectCreateInformation(Header->ObjectCreateInfo);
85             Header->ObjectCreateInfo = NULL;
86         }
87     }
88     else
89     {
90         /* Check if it has a quota block */
91         if (Header->QuotaBlockCharged)
92         {
93             /* Check if we have quota information */
94             if (QuotaInfo)
95             {
96                 /* Get charges from quota information */
97                 PagedPoolCharge = QuotaInfo->PagedPoolCharge +
98                                   QuotaInfo->SecurityDescriptorCharge;
99                 NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge;
100             }
101             else
102             {
103                 /* Get charges from object type */
104                 PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
105                 NonPagedPoolCharge = ObjectType->
106                                      TypeInfo.DefaultNonPagedPoolCharge;
107 
108                 /* Add the SD charge too */
109                 if (Header->Flags & OB_FLAG_SECURITY) PagedPoolCharge += 2048;
110             }
111 
112             /* Return the quota */
113             if (Header->QuotaBlockCharged != OBP_SYSTEM_PROCESS_QUOTA)
114             {
115                 PsReturnSharedPoolQuota(Header->QuotaBlockCharged,
116                                         PagedPoolCharge,
117                                         NonPagedPoolCharge);
118             }
119         }
120     }
121 
122     /* Check if a handle database was active */
123     if ((HandleInfo) && !(Header->Flags & OB_FLAG_SINGLE_PROCESS))
124     {
125         /* Free it */
126         ExFreePool(HandleInfo->HandleCountDatabase);
127         HandleInfo->HandleCountDatabase = NULL;
128     }
129 
130     /* Check if we have a name */
131     if ((NameInfo) && (NameInfo->Name.Buffer))
132     {
133         /* Free it */
134         ExFreePool(NameInfo->Name.Buffer);
135         NameInfo->Name.Buffer = NULL;
136     }
137 
138     /* Catch invalid access */
139     Header->Type = (POBJECT_TYPE)(ULONG_PTR)0xBAADB0B0BAADB0B0ULL;
140 
141     /* Free the object using the same allocation tag */
142     ExFreePoolWithTag(HeaderLocation, ObjectType->Key);
143 }
144 
145 VOID
146 NTAPI
ObpDeleteObject(IN PVOID Object,IN BOOLEAN CalledFromWorkerThread)147 ObpDeleteObject(IN PVOID Object,
148                 IN BOOLEAN CalledFromWorkerThread)
149 {
150     POBJECT_HEADER Header;
151     POBJECT_TYPE ObjectType;
152     POBJECT_HEADER_NAME_INFO NameInfo;
153     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
154     KIRQL CalloutIrql;
155     PAGED_CODE();
156 
157     /* Get the header and type */
158     Header = OBJECT_TO_OBJECT_HEADER(Object);
159     ObjectType = Header->Type;
160 
161     /* Get creator and name information */
162     NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header);
163     CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
164 
165     /* Check if the object is on a type list */
166     if ((CreatorInfo) && !(IsListEmpty(&CreatorInfo->TypeList)))
167     {
168         /* Lock the object type */
169         ObpEnterObjectTypeMutex(ObjectType);
170 
171         /* Remove the object from the type list */
172         RemoveEntryList(&CreatorInfo->TypeList);
173 
174         /* Release the lock */
175         ObpLeaveObjectTypeMutex(ObjectType);
176     }
177 
178     /* Check if we have a name */
179     if ((NameInfo) && (NameInfo->Name.Buffer))
180     {
181         /* Free it */
182         ExFreePool(NameInfo->Name.Buffer);
183         RtlInitEmptyUnicodeString(&NameInfo->Name, NULL, 0);
184     }
185 
186     /* Check if we have a security descriptor */
187     if (Header->SecurityDescriptor)
188     {
189         /* Call the security procedure to delete it */
190         ObpCalloutStart(&CalloutIrql);
191         ObjectType->TypeInfo.SecurityProcedure(Object,
192                                                DeleteSecurityDescriptor,
193                                                0,
194                                                NULL,
195                                                NULL,
196                                                &Header->SecurityDescriptor,
197                                                0,
198                                                NULL);
199         ObpCalloutEnd(CalloutIrql, "Security", ObjectType, Object);
200     }
201 
202     /* Check if we have a delete procedure */
203     if (ObjectType->TypeInfo.DeleteProcedure)
204     {
205         /* Save whether we were deleted from worker thread or not */
206         if (!CalledFromWorkerThread) Header->Flags |= OB_FLAG_DEFER_DELETE;
207 
208         /* Call it */
209         ObpCalloutStart(&CalloutIrql);
210         ObjectType->TypeInfo.DeleteProcedure(Object);
211         ObpCalloutEnd(CalloutIrql, "Delete", ObjectType, Object);
212     }
213 
214     /* Now de-allocate all object members */
215     ObpDeallocateObject(Object);
216 }
217 
218 VOID
219 NTAPI
ObpReapObject(IN PVOID Parameter)220 ObpReapObject(IN PVOID Parameter)
221 {
222     POBJECT_HEADER ReapObject, NextObject;
223 
224     /* Start reaping */
225     do
226     {
227         /* Get the reap object */
228         ReapObject = InterlockedExchangePointer(&ObpReaperList, (PVOID)1);
229 
230         /* Start deletion loop */
231         do
232         {
233             /* Get the next object */
234             NextObject = ReapObject->NextToFree;
235 
236             /* Delete the object */
237             ObpDeleteObject(&ReapObject->Body, TRUE);
238 
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));
244 }
245 
246 /*++
247 * @name ObpSetPermanentObject
248 *
249 *     The ObpSetPermanentObject routine makes an sets or clears the permanent
250 *     flag of an object, thus making it either permanent or temporary.
251 *
252 * @param ObjectBody
253 *        Pointer to the object to make permanent or temporary.
254 *
255 * @param Permanent
256 *        Flag specifying which operation to perform.
257 *
258 * @return None.
259 *
260 * @remarks If the object is being made temporary, then it will be checked
261 *          as a candidate for immediate removal from the namespace.
262 *
263 *--*/
264 VOID
265 FASTCALL
ObpSetPermanentObject(IN PVOID ObjectBody,IN BOOLEAN Permanent)266 ObpSetPermanentObject(IN PVOID ObjectBody,
267                       IN BOOLEAN Permanent)
268 {
269     POBJECT_HEADER ObjectHeader;
270 
271     /* Get the header */
272     ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
273 
274     /* Acquire object lock */
275     ObpAcquireObjectLock(ObjectHeader);
276 
277     /* Check what we're doing to it */
278     if (Permanent)
279     {
280         /* Set it to permanent */
281         ObjectHeader->Flags |= OB_FLAG_PERMANENT;
282 
283         /* Release the lock */
284         ObpReleaseObjectLock(ObjectHeader);
285     }
286     else
287     {
288         /* Remove the flag */
289         ObjectHeader->Flags &= ~OB_FLAG_PERMANENT;
290 
291         /* Release the lock */
292         ObpReleaseObjectLock(ObjectHeader);
293 
294         /* Check if we should delete the object now */
295         ObpDeleteNameCheck(ObjectBody);
296     }
297 }
298 
299 PWCHAR
300 NTAPI
ObpAllocateObjectNameBuffer(IN ULONG Length,IN BOOLEAN UseLookaside,IN OUT PUNICODE_STRING ObjectName)301 ObpAllocateObjectNameBuffer(IN ULONG Length,
302                             IN BOOLEAN UseLookaside,
303                             IN OUT PUNICODE_STRING ObjectName)
304 {
305     ULONG MaximumLength;
306     PVOID Buffer;
307 
308     /* Set the maximum length to the length plus the terminator */
309     MaximumLength = Length + sizeof(UNICODE_NULL);
310 
311     /* Check if we should use the lookaside buffer */
312     if (!(UseLookaside) || (MaximumLength > OBP_NAME_LOOKASIDE_MAX_SIZE))
313     {
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)
317          * here.
318          *
319          * People do call this with UseLookasideList FALSE so the distinction
320          * is critical.
321          */
322         if (MaximumLength <= OBP_NAME_LOOKASIDE_MAX_SIZE)
323         {
324             MaximumLength = OBP_NAME_LOOKASIDE_MAX_SIZE + sizeof(UNICODE_NULL);
325         }
326         Buffer = ExAllocatePoolWithTag(PagedPool,
327                                        MaximumLength,
328                                        OB_NAME_TAG);
329     }
330     else
331     {
332         /* Allocate from the lookaside */
333         MaximumLength = OBP_NAME_LOOKASIDE_MAX_SIZE;
334         Buffer = ObpAllocateObjectCreateInfoBuffer(LookasideNameBufferList);
335     }
336 
337     /* Setup the string */
338     ObjectName->MaximumLength = (USHORT)MaximumLength;
339     ObjectName->Length = (USHORT)Length;
340     ObjectName->Buffer = Buffer;
341     return Buffer;
342 }
343 
344 VOID
345 NTAPI
ObpFreeObjectNameBuffer(IN PUNICODE_STRING Name)346 ObpFreeObjectNameBuffer(IN PUNICODE_STRING Name)
347 {
348     PVOID Buffer = Name->Buffer;
349 
350     /* We know this is a pool-allocation if the size doesn't match */
351     if (Name->MaximumLength != OBP_NAME_LOOKASIDE_MAX_SIZE)
352     {
353         /*
354          * Free it from the pool.
355          *
356          * We cannot use here ExFreePoolWithTag(..., OB_NAME_TAG); , because
357          * the object name may have been massaged during operation by different
358          * object parse routines. If the latter ones have to resolve a symbolic
359          * link (e.g. as is done by CmpParseKey() and CmpGetSymbolicLink()),
360          * the original object name is freed and re-allocated from the pool,
361          * possibly with a different pool tag. At the end of the day, the new
362          * object name can be reallocated and completely different, but we
363          * should still be able to free it!
364          */
365         ExFreePool(Buffer);
366     }
367     else
368     {
369         /* Otherwise, free from the lookaside */
370         ObpFreeCapturedAttributes(Buffer, LookasideNameBufferList);
371     }
372 }
373 
374 NTSTATUS
375 NTAPI
ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,IN PUNICODE_STRING ObjectName,IN KPROCESSOR_MODE AccessMode,IN BOOLEAN UseLookaside)376 ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,
377                      IN PUNICODE_STRING ObjectName,
378                      IN KPROCESSOR_MODE AccessMode,
379                      IN BOOLEAN UseLookaside)
380 {
381     NTSTATUS Status = STATUS_SUCCESS;
382     ULONG StringLength;
383     PWCHAR _SEH2_VOLATILE StringBuffer = NULL;
384     UNICODE_STRING LocalName;
385     PAGED_CODE();
386 
387     /* Initialize the Input String */
388     RtlInitEmptyUnicodeString(CapturedName, NULL, 0);
389 
390     /* Protect everything */
391     _SEH2_TRY
392     {
393         /* Check if we came from user mode */
394         if (AccessMode != KernelMode)
395         {
396             /* First Probe the String */
397             LocalName = ProbeForReadUnicodeString(ObjectName);
398             ProbeForRead(LocalName.Buffer, LocalName.Length, sizeof(WCHAR));
399         }
400         else
401         {
402             /* No probing needed */
403             LocalName = *ObjectName;
404         }
405 
406         /* Make sure there really is a string */
407         StringLength = LocalName.Length;
408         if (StringLength)
409         {
410             /* Check that the size is a valid WCHAR multiple */
411             if ((StringLength & (sizeof(WCHAR) - 1)) ||
412                 /* Check that the NULL-termination below will work */
413                 (StringLength == (MAXUSHORT - sizeof(UNICODE_NULL) + 1)))
414             {
415                 /* PS: Please keep the checks above expanded for clarity */
416                 Status = STATUS_OBJECT_NAME_INVALID;
417             }
418             else
419             {
420                 /* Allocate the string buffer */
421                 StringBuffer = ObpAllocateObjectNameBuffer(StringLength,
422                                                            UseLookaside,
423                                                            CapturedName);
424                 if (!StringBuffer)
425                 {
426                     /* Set failure code */
427                     Status = STATUS_INSUFFICIENT_RESOURCES;
428                 }
429                 else
430                 {
431                     /* Copy the name */
432                     RtlCopyMemory(StringBuffer, LocalName.Buffer, StringLength);
433                     StringBuffer[StringLength / sizeof(WCHAR)] = UNICODE_NULL;
434                 }
435             }
436         }
437     }
438     _SEH2_EXCEPT(ExSystemExceptionFilter())
439     {
440         /* Handle exception and free the string buffer */
441         Status = _SEH2_GetExceptionCode();
442         if (StringBuffer)
443         {
444             ObpFreeObjectNameBuffer(CapturedName);
445         }
446     }
447     _SEH2_END;
448 
449     /* Return */
450     return Status;
451 }
452 
453 NTSTATUS
454 NTAPI
ObpCaptureObjectCreateInformation(IN POBJECT_ATTRIBUTES ObjectAttributes,IN KPROCESSOR_MODE AccessMode,IN KPROCESSOR_MODE CreatorMode,IN BOOLEAN AllocateFromLookaside,IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,OUT PUNICODE_STRING ObjectName)455 ObpCaptureObjectCreateInformation(IN POBJECT_ATTRIBUTES ObjectAttributes,
456                                   IN KPROCESSOR_MODE AccessMode,
457                                   IN KPROCESSOR_MODE CreatorMode,
458                                   IN BOOLEAN AllocateFromLookaside,
459                                   IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
460                                   OUT PUNICODE_STRING ObjectName)
461 {
462     ULONG SdCharge, QuotaInfoSize;
463     NTSTATUS Status = STATUS_SUCCESS;
464     PSECURITY_DESCRIPTOR SecurityDescriptor;
465     PSECURITY_QUALITY_OF_SERVICE SecurityQos;
466     PUNICODE_STRING LocalObjectName = NULL;
467     PAGED_CODE();
468 
469     /* Zero out the Capture Data */
470     RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION));
471 
472     /* SEH everything here for protection */
473     _SEH2_TRY
474     {
475         /* Check if we got attributes */
476         if (ObjectAttributes)
477         {
478             /* Check if we're in user mode */
479             if (AccessMode != KernelMode)
480             {
481                 /* Probe the attributes */
482                 ProbeForRead(ObjectAttributes,
483                              sizeof(OBJECT_ATTRIBUTES),
484                              sizeof(ULONG));
485             }
486 
487             /* Validate the Size and Attributes */
488             if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) ||
489                 (ObjectAttributes->Attributes & ~OBJ_VALID_KERNEL_ATTRIBUTES))
490             {
491                 /* Invalid combination, fail */
492                 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
493             }
494 
495             /* Set some Create Info and do not allow user-mode kernel handles */
496             ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory;
497             ObjectCreateInfo->Attributes = ObjectAttributes->Attributes & OBJ_VALID_KERNEL_ATTRIBUTES;
498             if (CreatorMode != KernelMode) ObjectCreateInfo->Attributes &= ~OBJ_KERNEL_HANDLE;
499             LocalObjectName = ObjectAttributes->ObjectName;
500             SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
501             SecurityQos = ObjectAttributes->SecurityQualityOfService;
502 
503             /* Check if we have a security descriptor */
504             if (SecurityDescriptor)
505             {
506                 /* Capture it. Note: This has an implicit memory barrier due
507                    to the function call, so cleanup is safe here.) */
508                 Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
509                                                      AccessMode,
510                                                      NonPagedPool,
511                                                      TRUE,
512                                                      &ObjectCreateInfo->
513                                                      SecurityDescriptor);
514                 if (!NT_SUCCESS(Status))
515                 {
516                     /* Capture failed, quit */
517                     ObjectCreateInfo->SecurityDescriptor = NULL;
518                     _SEH2_YIELD(return Status);
519                 }
520 
521                 /*
522                  * By default, assume a SD size of 1024 and allow twice its
523                  * size.
524                  * If SD size happen to be bigger than that, then allow it
525                  */
526                 SdCharge = 2048;
527                 SeComputeQuotaInformationSize(ObjectCreateInfo->SecurityDescriptor,
528                                               &QuotaInfoSize);
529                 if ((2 * QuotaInfoSize) > 2048)
530                 {
531                     SdCharge = 2 * QuotaInfoSize;
532                 }
533 
534                 /* Save the probe mode and security descriptor size */
535                 ObjectCreateInfo->SecurityDescriptorCharge = SdCharge;
536                 ObjectCreateInfo->ProbeMode = AccessMode;
537             }
538 
539             /* Check if we have QoS */
540             if (SecurityQos)
541             {
542                 /* Check if we came from user mode */
543                 if (AccessMode != KernelMode)
544                 {
545                     /* Validate the QoS */
546                     ProbeForRead(SecurityQos,
547                                  sizeof(SECURITY_QUALITY_OF_SERVICE),
548                                  sizeof(ULONG));
549                 }
550 
551                 /* Save Info */
552                 ObjectCreateInfo->SecurityQualityOfService = *SecurityQos;
553                 ObjectCreateInfo->SecurityQos =
554                     &ObjectCreateInfo->SecurityQualityOfService;
555             }
556         }
557         else
558         {
559             /* We don't have a name */
560             LocalObjectName = NULL;
561         }
562     }
563     _SEH2_EXCEPT(ExSystemExceptionFilter())
564     {
565         /* Cleanup and return the exception code */
566         ObpReleaseObjectCreateInformation(ObjectCreateInfo);
567         _SEH2_YIELD(return _SEH2_GetExceptionCode());
568     }
569     _SEH2_END;
570 
571     /* Now check if the Object Attributes had an Object Name */
572     if (LocalObjectName)
573     {
574         Status = ObpCaptureObjectName(ObjectName,
575                                       LocalObjectName,
576                                       AccessMode,
577                                       AllocateFromLookaside);
578     }
579     else
580     {
581         /* Clear the string */
582         RtlInitEmptyUnicodeString(ObjectName, NULL, 0);
583 
584         /* It cannot have specified a Root Directory */
585         if (ObjectCreateInfo->RootDirectory)
586         {
587             Status = STATUS_OBJECT_NAME_INVALID;
588         }
589     }
590 
591     /* Cleanup if we failed */
592     if (!NT_SUCCESS(Status))
593     {
594         ObpReleaseObjectCreateInformation(ObjectCreateInfo);
595     }
596 
597     /* Return status to caller */
598     return Status;
599 }
600 
601 VOID
602 NTAPI
ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)603 ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
604 {
605     /* Call the macro. We use this function to isolate Ob internals from Io */
606     ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
607 }
608 
609 NTSTATUS
610 NTAPI
ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,IN PUNICODE_STRING ObjectName,IN POBJECT_TYPE ObjectType,IN ULONG ObjectSize,IN KPROCESSOR_MODE PreviousMode,IN POBJECT_HEADER * ObjectHeader)611 ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
612                   IN PUNICODE_STRING ObjectName,
613                   IN POBJECT_TYPE ObjectType,
614                   IN ULONG ObjectSize,
615                   IN KPROCESSOR_MODE PreviousMode,
616                   IN POBJECT_HEADER *ObjectHeader)
617 {
618     POBJECT_HEADER Header;
619     ULONG QuotaSize, HandleSize, NameSize, CreatorSize;
620     POBJECT_HEADER_HANDLE_INFO HandleInfo;
621     POBJECT_HEADER_NAME_INFO NameInfo;
622     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
623     POBJECT_HEADER_QUOTA_INFO QuotaInfo;
624     POOL_TYPE PoolType;
625     ULONG FinalSize;
626     ULONG Tag;
627     PAGED_CODE();
628 
629     /* Accounting */
630     ObpObjectsCreated++;
631 
632     /* Check if we don't have an Object Type yet */
633     if (!ObjectType)
634     {
635         /* Use default tag and non-paged pool */
636         PoolType = NonPagedPool;
637         Tag = TAG_OBJECT_TYPE;
638     }
639     else
640     {
641         /* Use the pool and tag given */
642         PoolType = ObjectType->TypeInfo.PoolType;
643         Tag = ObjectType->Key;
644     }
645 
646     /* Check if we have no create information (ie: we're an object type) */
647     if (!ObjectCreateInfo)
648     {
649         /* Use defaults */
650         QuotaSize = HandleSize = 0;
651         NameSize = sizeof(OBJECT_HEADER_NAME_INFO);
652         CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
653     }
654     else
655     {
656         /* Check if we have quota */
657         if ((((ObjectCreateInfo->PagedPoolCharge !=
658                ObjectType->TypeInfo.DefaultPagedPoolCharge) ||
659               (ObjectCreateInfo->NonPagedPoolCharge !=
660                ObjectType->TypeInfo.DefaultNonPagedPoolCharge) ||
661               (ObjectCreateInfo->SecurityDescriptorCharge > 2048)) &&
662              (PsGetCurrentProcess() != PsInitialSystemProcess)) ||
663             (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
664         {
665             /* Set quota size */
666             QuotaSize = sizeof(OBJECT_HEADER_QUOTA_INFO);
667             ObpObjectsWithPoolQuota++;
668         }
669         else
670         {
671             /* No Quota */
672             QuotaSize = 0;
673         }
674 
675         /* Check if we have a handle database */
676         if (ObjectType->TypeInfo.MaintainHandleCount)
677         {
678             /* Set handle database size */
679             HandleSize = sizeof(OBJECT_HEADER_HANDLE_INFO);
680             ObpObjectsWithHandleDB++;
681         }
682         else
683         {
684             /* None */
685             HandleSize = 0;
686         }
687 
688         /* Check if the Object has a name */
689         if (ObjectName->Buffer)
690         {
691             /* Set name size */
692             NameSize = sizeof(OBJECT_HEADER_NAME_INFO);
693             ObpObjectsWithName++;
694         }
695         else
696         {
697             /* No name */
698             NameSize = 0;
699         }
700 
701         /* Check if the Object maintains type lists */
702         if (ObjectType->TypeInfo.MaintainTypeList)
703         {
704             /* Set owner/creator size */
705             CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
706             ObpObjectsWithCreatorInfo++;
707         }
708         else
709         {
710             /* No info */
711             CreatorSize = 0;
712         }
713     }
714 
715     /* Set final header size */
716     FinalSize = QuotaSize +
717                 HandleSize +
718                 NameSize +
719                 CreatorSize +
720                 FIELD_OFFSET(OBJECT_HEADER, Body);
721 
722     /* Allocate memory for the Object and Header */
723     Header = ExAllocatePoolWithTag(PoolType, FinalSize + ObjectSize, Tag);
724     if (!Header) return STATUS_INSUFFICIENT_RESOURCES;
725 
726     /* Check if we have a quota header */
727     if (QuotaSize)
728     {
729         /* Initialize quota info */
730         QuotaInfo = (POBJECT_HEADER_QUOTA_INFO)Header;
731         QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge;
732         QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge;
733         QuotaInfo->SecurityDescriptorCharge = ObjectCreateInfo->SecurityDescriptorCharge;
734         QuotaInfo->ExclusiveProcess = NULL;
735         Header = (POBJECT_HEADER)(QuotaInfo + 1);
736     }
737 
738     /* Check if we have a handle database header */
739     if (HandleSize)
740     {
741         /* Initialize Handle Info */
742         HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header;
743         HandleInfo->SingleEntry.HandleCount = 0;
744         Header = (POBJECT_HEADER)(HandleInfo + 1);
745     }
746 
747     /* Check if we have a name header */
748     if (NameSize)
749     {
750         /* Initialize the Object Name Info */
751         NameInfo = (POBJECT_HEADER_NAME_INFO)Header;
752         NameInfo->Name = *ObjectName;
753         NameInfo->Directory = NULL;
754         NameInfo->QueryReferences = 1;
755 
756         /* Check if this is a call with the special protection flag */
757         if ((PreviousMode == KernelMode) &&
758             (ObjectCreateInfo) &&
759             (ObjectCreateInfo->Attributes & OBJ_KERNEL_EXCLUSIVE))
760         {
761             /* Set flag which will make the object protected from user-mode */
762             NameInfo->QueryReferences |= OB_FLAG_KERNEL_EXCLUSIVE;
763         }
764 
765         /* Set the header pointer */
766         Header = (POBJECT_HEADER)(NameInfo + 1);
767     }
768 
769     /* Check if we have a creator header */
770     if (CreatorSize)
771     {
772         /* Initialize Creator Info */
773         CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header;
774         CreatorInfo->CreatorBackTraceIndex = 0;
775         CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId();
776         InitializeListHead(&CreatorInfo->TypeList);
777         Header = (POBJECT_HEADER)(CreatorInfo + 1);
778     }
779 
780     /* Check for quota information */
781     if (QuotaSize)
782     {
783         /* Set the offset */
784         Header->QuotaInfoOffset = (UCHAR)(QuotaSize +
785                                           HandleSize +
786                                           NameSize +
787                                           CreatorSize);
788     }
789     else
790     {
791         /* No offset */
792         Header->QuotaInfoOffset = 0;
793     }
794 
795     /* Check for handle information */
796     if (HandleSize)
797     {
798         /* Set the offset */
799         Header->HandleInfoOffset = (UCHAR)(HandleSize +
800                                            NameSize +
801                                            CreatorSize);
802     }
803     else
804     {
805         /* No offset */
806         Header->HandleInfoOffset = 0;
807     }
808 
809     /* Check for name information */
810     if (NameSize)
811     {
812         /* Set the offset */
813         Header->NameInfoOffset = (UCHAR)(NameSize + CreatorSize);
814     }
815     else
816     {
817         /* No Name */
818         Header->NameInfoOffset = 0;
819     }
820 
821     /* Set the new object flag */
822     Header->Flags = OB_FLAG_CREATE_INFO;
823 
824     /* Remember if we have creator info */
825     if (CreatorSize) Header->Flags |= OB_FLAG_CREATOR_INFO;
826 
827     /* Remember if we have handle info */
828     if (HandleSize) Header->Flags |= OB_FLAG_SINGLE_PROCESS;
829 
830     /* Initialize the object header */
831     Header->PointerCount = 1;
832     Header->HandleCount = 0;
833     Header->Type = ObjectType;
834     Header->ObjectCreateInfo = ObjectCreateInfo;
835     Header->SecurityDescriptor = NULL;
836 
837     /* Check if this is a permanent object */
838     if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_PERMANENT))
839     {
840         /* Set the needed flag so we can check */
841         Header->Flags |= OB_FLAG_PERMANENT;
842     }
843 
844     /* Check if this is an exclusive object */
845     if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
846     {
847         /* Set the needed flag so we can check */
848         Header->Flags |= OB_FLAG_EXCLUSIVE;
849     }
850 
851     /* Set kernel-mode flag */
852     if (PreviousMode == KernelMode) Header->Flags |= OB_FLAG_KERNEL_MODE;
853 
854     /* Check if we have a type */
855     if (ObjectType)
856     {
857         /* Increase the number of objects of this type */
858         InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfObjects);
859 
860         /* Update the high water */
861         ObjectType->HighWaterNumberOfObjects = max(ObjectType->
862                                                    TotalNumberOfObjects,
863                                                    ObjectType->
864                                                    HighWaterNumberOfObjects);
865     }
866 
867     /* Return Header */
868     *ObjectHeader = Header;
869     return STATUS_SUCCESS;
870 }
871 
872 /**
873  * @brief
874  * Queries the name info size of a given resource object.
875  * The function loops through all the parent directories
876  * of the object and computes the name size.
877  *
878  * @param[in] ObjectHeader
879  * A pointer to an object header, of which name and
880  * directory info are to be retrieved.
881  *
882  * @return
883  * Returns the name info size that is pointed by the
884  * given object by the caller of this function. If
885  * an object does not have a name or no directories,
886  * it returns 0.
887  */
888 static
889 ULONG
ObpQueryNameInfoSize(_In_ POBJECT_HEADER ObjectHeader)890 ObpQueryNameInfoSize(
891     _In_ POBJECT_HEADER ObjectHeader)
892 {
893     ULONG NameSize = 0;
894     POBJECT_DIRECTORY ParentDirectory;
895     POBJECT_HEADER_NAME_INFO NameInfo;
896     PAGED_CODE();
897 
898     /* Get the name info */
899     NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
900     if (!NameInfo)
901     {
902         return 0;
903     }
904 
905     /* Get the parent directory from the object name too */
906     ParentDirectory = NameInfo->Directory;
907     if (!ParentDirectory)
908     {
909         return 0;
910     }
911 
912     /* Take into account the name size of this object and loop for all parent directories */
913     NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + NameInfo->Name.Length;
914     for (;;)
915     {
916         /* Get the name info from the parent directory */
917         NameInfo = OBJECT_HEADER_TO_NAME_INFO(
918             OBJECT_TO_OBJECT_HEADER(ParentDirectory));
919         if (!NameInfo)
920         {
921             /* Stop looking if this is the last one */
922             break;
923         }
924 
925         /* Get the parent directory */
926         ParentDirectory = NameInfo->Directory;
927         if (!ParentDirectory)
928         {
929             /* This is the last directory, stop looking */
930             break;
931         }
932 
933         /*
934          * Take into account the size of this name info,
935          * keep looking for other parent directories.
936          */
937         NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) + NameInfo->Name.Length;
938     }
939 
940     /* Include the size of the object name information as well as the NULL terminator */
941     NameSize += sizeof(OBJECT_NAME_INFORMATION) + sizeof(UNICODE_NULL);
942     return NameSize;
943 }
944 
945 NTSTATUS
946 NTAPI
ObQueryTypeInfo(_In_ POBJECT_TYPE ObjectType,_Out_writes_bytes_to_ (Length,* ReturnLength)POBJECT_TYPE_INFORMATION ObjectTypeInfo,_In_ ULONG Length,_Out_ PULONG ReturnLength)947 ObQueryTypeInfo(
948     _In_ POBJECT_TYPE ObjectType,
949     _Out_writes_bytes_to_(Length, *ReturnLength)
950         POBJECT_TYPE_INFORMATION ObjectTypeInfo,
951     _In_ ULONG Length,
952     _Out_ PULONG ReturnLength)
953 {
954     NTSTATUS Status = STATUS_SUCCESS;
955     PWSTR InfoBuffer;
956 
957     /* The string of the object type name has to be NULL-terminated */
958     ASSERT(ObjectType->Name.MaximumLength >= ObjectType->Name.Length + sizeof(UNICODE_NULL));
959 
960     /* Enter SEH */
961     _SEH2_TRY
962     {
963         /*
964          * Set return length aligned to 4-byte or 8-byte boundary. Windows has a bug
965          * where the returned length pointer is always aligned to a 4-byte boundary.
966          * If one were to allocate a pool of memory in kernel mode to retrieve all
967          * the object types info with this return length, Windows will bugcheck with
968          * BAD_POOL_HEADER in 64-bit upon you free the said allocated memory.
969          *
970          * More than that, Windows uses MaximumLength for the calculation of the returned
971          * length and MaximumLength does not always guarantee the name type is NULL-terminated
972          * leading the ObQueryTypeInfo function to overrun the buffer.
973          */
974         *ReturnLength += sizeof(*ObjectTypeInfo) +
975                          ALIGN_UP(ObjectType->Name.Length + sizeof(UNICODE_NULL), ULONG_PTR);
976 
977         /* Check if that is too much */
978         if (Length < *ReturnLength)
979         {
980             _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH);
981         }
982 
983         /* Build the data */
984         ObjectTypeInfo->TotalNumberOfHandles =
985             ObjectType->TotalNumberOfHandles;
986         ObjectTypeInfo->TotalNumberOfObjects =
987             ObjectType->TotalNumberOfObjects;
988         ObjectTypeInfo->HighWaterNumberOfHandles =
989             ObjectType->HighWaterNumberOfHandles;
990         ObjectTypeInfo->HighWaterNumberOfObjects =
991             ObjectType->HighWaterNumberOfObjects;
992         ObjectTypeInfo->PoolType =
993             ObjectType->TypeInfo.PoolType;
994         ObjectTypeInfo->DefaultNonPagedPoolCharge =
995             ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
996         ObjectTypeInfo->DefaultPagedPoolCharge =
997             ObjectType->TypeInfo.DefaultPagedPoolCharge;
998         ObjectTypeInfo->ValidAccessMask =
999             ObjectType->TypeInfo.ValidAccessMask;
1000         ObjectTypeInfo->SecurityRequired =
1001             ObjectType->TypeInfo.SecurityRequired;
1002         ObjectTypeInfo->InvalidAttributes =
1003             ObjectType->TypeInfo.InvalidAttributes;
1004         ObjectTypeInfo->GenericMapping =
1005             ObjectType->TypeInfo.GenericMapping;
1006         ObjectTypeInfo->MaintainHandleCount =
1007             ObjectType->TypeInfo.MaintainHandleCount;
1008 
1009         /* Setup the name buffer */
1010         InfoBuffer = (PWSTR)(ObjectTypeInfo + 1);
1011         ObjectTypeInfo->TypeName.Buffer = InfoBuffer;
1012         ObjectTypeInfo->TypeName.MaximumLength = ObjectType->Name.MaximumLength;
1013         ObjectTypeInfo->TypeName.Length = ObjectType->Name.Length;
1014 
1015         /* Copy it */
1016         RtlCopyMemory(InfoBuffer,
1017                       ObjectType->Name.Buffer,
1018                       ObjectType->Name.Length);
1019 
1020         /* Null-terminate it */
1021         (InfoBuffer)[ObjectType->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
1022     }
1023     _SEH2_EXCEPT(ExSystemExceptionFilter())
1024     {
1025         /* Otherwise, get the exception code */
1026         Status = _SEH2_GetExceptionCode();
1027     }
1028     _SEH2_END;
1029 
1030     /* Return status to caller */
1031     return Status;
1032 }
1033 
1034 
1035 /* PUBLIC FUNCTIONS **********************************************************/
1036 
1037 NTSTATUS
1038 NTAPI
ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL,IN POBJECT_TYPE Type,IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,IN KPROCESSOR_MODE AccessMode,IN OUT PVOID ParseContext OPTIONAL,IN ULONG ObjectSize,IN ULONG PagedPoolCharge OPTIONAL,IN ULONG NonPagedPoolCharge OPTIONAL,OUT PVOID * Object)1039 ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL,
1040                IN POBJECT_TYPE Type,
1041                IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1042                IN KPROCESSOR_MODE AccessMode,
1043                IN OUT PVOID ParseContext OPTIONAL,
1044                IN ULONG ObjectSize,
1045                IN ULONG PagedPoolCharge OPTIONAL,
1046                IN ULONG NonPagedPoolCharge OPTIONAL,
1047                OUT PVOID *Object)
1048 {
1049     NTSTATUS Status;
1050     POBJECT_CREATE_INFORMATION ObjectCreateInfo;
1051     UNICODE_STRING ObjectName;
1052     POBJECT_HEADER Header;
1053 
1054     /* Allocate a capture buffer */
1055     ObjectCreateInfo = ObpAllocateObjectCreateInfoBuffer(LookasideCreateInfoList);
1056     if (!ObjectCreateInfo) return STATUS_INSUFFICIENT_RESOURCES;
1057 
1058     /* Capture all the info */
1059     Status = ObpCaptureObjectCreateInformation(ObjectAttributes,
1060                                                ProbeMode,
1061                                                AccessMode,
1062                                                FALSE,
1063                                                ObjectCreateInfo,
1064                                                &ObjectName);
1065     if (NT_SUCCESS(Status))
1066     {
1067         /* Validate attributes */
1068         if (Type->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes)
1069         {
1070             /* Fail */
1071             Status = STATUS_INVALID_PARAMETER;
1072         }
1073         else
1074         {
1075             /* Check if we have a paged charge */
1076             if (!PagedPoolCharge)
1077             {
1078                 /* Save it */
1079                 PagedPoolCharge = Type->TypeInfo.DefaultPagedPoolCharge;
1080             }
1081 
1082             /* Check for nonpaged charge */
1083             if (!NonPagedPoolCharge)
1084             {
1085                 /* Save it */
1086                 NonPagedPoolCharge = Type->TypeInfo.DefaultNonPagedPoolCharge;
1087             }
1088 
1089             /* Write the pool charges */
1090             ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge;
1091             ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge;
1092 
1093             /* Allocate the Object */
1094             Status = ObpAllocateObject(ObjectCreateInfo,
1095                                        &ObjectName,
1096                                        Type,
1097                                        ObjectSize,
1098                                        AccessMode,
1099                                        &Header);
1100             if (NT_SUCCESS(Status))
1101             {
1102                 /* Return the Object */
1103                 *Object = &Header->Body;
1104 
1105                 /* Check if this is a permanent object */
1106                 if (Header->Flags & OB_FLAG_PERMANENT)
1107                 {
1108                     /* Do the privilege check */
1109                     if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
1110                                                 ProbeMode))
1111                     {
1112                         /* Fail */
1113                         ObpDeallocateObject(*Object);
1114                         Status = STATUS_PRIVILEGE_NOT_HELD;
1115                     }
1116                 }
1117 
1118                 /* Return status */
1119                 return Status;
1120             }
1121         }
1122 
1123         /* Release the Capture Info, we don't need it */
1124         ObpFreeObjectCreateInformation(ObjectCreateInfo);
1125         if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
1126         return Status;
1127     }
1128 
1129     /* We failed, so release the Buffer */
1130     ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
1131     return Status;
1132 }
1133 
1134 NTSTATUS
1135 NTAPI
ObCreateObjectType(IN PUNICODE_STRING TypeName,IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,IN PVOID Reserved,OUT POBJECT_TYPE * ObjectType)1136 ObCreateObjectType(IN PUNICODE_STRING TypeName,
1137                    IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
1138                    IN PVOID Reserved,
1139                    OUT POBJECT_TYPE *ObjectType)
1140 {
1141     POBJECT_HEADER Header;
1142     POBJECT_TYPE LocalObjectType;
1143     ULONG HeaderSize;
1144     NTSTATUS Status;
1145     OBP_LOOKUP_CONTEXT Context;
1146     PWCHAR p;
1147     ULONG i;
1148     UNICODE_STRING ObjectName;
1149     ANSI_STRING AnsiName;
1150     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
1151 
1152     /* Verify parameters */
1153     if (!(TypeName) ||
1154         !(TypeName->Length) ||
1155         (TypeName->Length % sizeof(WCHAR)) ||
1156         !(ObjectTypeInitializer) ||
1157         (ObjectTypeInitializer->Length != sizeof(*ObjectTypeInitializer)) ||
1158         (ObjectTypeInitializer->InvalidAttributes & ~OBJ_VALID_KERNEL_ATTRIBUTES) ||
1159         (ObjectTypeInitializer->MaintainHandleCount &&
1160          (!(ObjectTypeInitializer->OpenProcedure) &&
1161           !ObjectTypeInitializer->CloseProcedure)) ||
1162         ((!ObjectTypeInitializer->UseDefaultObject) &&
1163          (ObjectTypeInitializer->PoolType != NonPagedPool)))
1164     {
1165         /* Fail */
1166         return STATUS_INVALID_PARAMETER;
1167     }
1168 
1169     /* Make sure the name doesn't have a separator */
1170     p = TypeName->Buffer;
1171     i = TypeName->Length / sizeof(WCHAR);
1172     while (i--)
1173     {
1174         /* Check for one and fail */
1175         if (*p++ == OBJ_NAME_PATH_SEPARATOR) return STATUS_OBJECT_NAME_INVALID;
1176     }
1177 
1178     /* Setup a lookup context */
1179     ObpInitializeLookupContext(&Context);
1180 
1181     /* Check if we've already created the directory of types */
1182     if (ObpTypeDirectoryObject)
1183     {
1184         /* Lock the lookup context */
1185         ObpAcquireLookupContextLock(&Context, ObpTypeDirectoryObject);
1186 
1187         /* Do the lookup */
1188         if (ObpLookupEntryDirectory(ObpTypeDirectoryObject,
1189                                     TypeName,
1190                                     OBJ_CASE_INSENSITIVE,
1191                                     FALSE,
1192                                     &Context))
1193         {
1194             /* We have already created it, so fail */
1195             ObpReleaseLookupContext(&Context);
1196             return STATUS_OBJECT_NAME_COLLISION;
1197         }
1198     }
1199 
1200     /* Now make a copy of the object name */
1201     ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool,
1202                                               TypeName->MaximumLength,
1203                                               OB_NAME_TAG);
1204     if (!ObjectName.Buffer)
1205     {
1206         /* Out of memory, fail */
1207         ObpReleaseLookupContext(&Context);
1208         return STATUS_INSUFFICIENT_RESOURCES;
1209     }
1210 
1211     /* Set the length and copy the name */
1212     ObjectName.MaximumLength = TypeName->MaximumLength;
1213     RtlCopyUnicodeString(&ObjectName, TypeName);
1214 
1215     /* Allocate the Object */
1216     Status = ObpAllocateObject(NULL,
1217                                &ObjectName,
1218                                ObpTypeObjectType,
1219                                sizeof(OBJECT_TYPE),
1220                                KernelMode,
1221                                &Header);
1222     if (!NT_SUCCESS(Status))
1223     {
1224         /* Free the name and fail */
1225         ObpReleaseLookupContext(&Context);
1226         ExFreePool(ObjectName.Buffer);
1227         return Status;
1228     }
1229 
1230     /* Setup the flags and name */
1231     LocalObjectType = (POBJECT_TYPE)&Header->Body;
1232     LocalObjectType->Name = ObjectName;
1233     Header->Flags |= OB_FLAG_KERNEL_MODE | OB_FLAG_PERMANENT;
1234 
1235     /* Clear accounting data */
1236     LocalObjectType->TotalNumberOfObjects =
1237     LocalObjectType->TotalNumberOfHandles =
1238     LocalObjectType->HighWaterNumberOfObjects =
1239     LocalObjectType->HighWaterNumberOfHandles = 0;
1240 
1241     /* Check if this is the first Object Type */
1242     if (!ObpTypeObjectType)
1243     {
1244         /* It is, so set this as the type object */
1245         ObpTypeObjectType = LocalObjectType;
1246         Header->Type = ObpTypeObjectType;
1247 
1248         /* Set the hard-coded key and object count */
1249         LocalObjectType->TotalNumberOfObjects = 1;
1250         LocalObjectType->Key = TAG_OBJECT_TYPE;
1251     }
1252     else
1253     {
1254         /* Convert the tag to ASCII */
1255         Status = RtlUnicodeStringToAnsiString(&AnsiName, TypeName, TRUE);
1256         if (NT_SUCCESS(Status))
1257         {
1258             /* For every missing character, use a space */
1259             for (i = 3; i >= AnsiName.Length; i--) AnsiName.Buffer[i] = ' ';
1260 
1261             /* Set the key and free the converted name */
1262             LocalObjectType->Key = *(PULONG)AnsiName.Buffer;
1263             RtlFreeAnsiString(&AnsiName);
1264         }
1265         else
1266         {
1267             /* Just copy the characters */
1268             LocalObjectType->Key = *(PULONG)TypeName->Buffer;
1269         }
1270     }
1271 
1272     /* Set up the type information */
1273     LocalObjectType->TypeInfo = *ObjectTypeInitializer;
1274     LocalObjectType->TypeInfo.PoolType = ObjectTypeInitializer->PoolType;
1275 
1276     /* Check if we have to maintain a type list */
1277     if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST)
1278     {
1279         /* Enable support */
1280         LocalObjectType->TypeInfo.MaintainTypeList = TRUE;
1281     }
1282 
1283     /* Calculate how much space our header'll take up */
1284     HeaderSize = sizeof(OBJECT_HEADER) +
1285                  sizeof(OBJECT_HEADER_NAME_INFO) +
1286                  (ObjectTypeInitializer->MaintainHandleCount ?
1287                   sizeof(OBJECT_HEADER_HANDLE_INFO) : 0);
1288 
1289     /* Check the pool type */
1290     if (ObjectTypeInitializer->PoolType == NonPagedPool)
1291     {
1292         /* Update the NonPaged Pool charge */
1293         LocalObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderSize;
1294     }
1295     else
1296     {
1297         /* Update the Paged Pool charge */
1298         LocalObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderSize;
1299     }
1300 
1301     /* All objects types need a security procedure */
1302     if (!ObjectTypeInitializer->SecurityProcedure)
1303     {
1304         LocalObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod;
1305     }
1306 
1307     /* Select the Wait Object */
1308     if (LocalObjectType->TypeInfo.UseDefaultObject)
1309     {
1310         /* Add the SYNCHRONIZE access mask since it's waitable */
1311         LocalObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE;
1312 
1313         /* Use the "Default Object", a simple event */
1314         LocalObjectType->DefaultObject = &ObpDefaultObject;
1315     }
1316     /* The File Object gets an optimized hack so it can be waited on */
1317     else if ((TypeName->Length == 8) && !(wcscmp(TypeName->Buffer, L"File")))
1318     {
1319         /* Wait on the File Object's event directly */
1320         LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(FILE_OBJECT,
1321                                                                  Event));
1322     }
1323     else if ((TypeName->Length == 24) && !(wcscmp(TypeName->Buffer, L"WaitablePort")))
1324     {
1325         /* Wait on the LPC Port's object directly */
1326         LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(LPCP_PORT_OBJECT,
1327                                                                  WaitEvent));
1328     }
1329     else
1330     {
1331         /* No default Object */
1332         LocalObjectType->DefaultObject = NULL;
1333     }
1334 
1335     /* Initialize Object Type components */
1336     ExInitializeResourceLite(&LocalObjectType->Mutex);
1337     for (i = 0; i < 4; i++)
1338     {
1339         /* Initialize the object locks */
1340         ExInitializeResourceLite(&LocalObjectType->ObjectLocks[i]);
1341     }
1342     InitializeListHead(&LocalObjectType->TypeList);
1343 
1344     /* Lock the object type */
1345     ObpEnterObjectTypeMutex(ObpTypeObjectType);
1346 
1347     /* Get creator info and insert it into the type list */
1348     CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
1349     if (CreatorInfo)
1350     {
1351         InsertTailList(&ObpTypeObjectType->TypeList,
1352                        &CreatorInfo->TypeList);
1353 
1354         /* CORE-8423: Avoid inserting this a second time if someone creates a
1355          * handle to the object type (bug in Windows 2003) */
1356         Header->Flags &= ~OB_FLAG_CREATE_INFO;
1357     }
1358 
1359     /* Set the index and the entry into the object type array */
1360     LocalObjectType->Index = ObpTypeObjectType->TotalNumberOfObjects;
1361 
1362     ASSERT(LocalObjectType->Index != 0);
1363 
1364     if (LocalObjectType->Index < RTL_NUMBER_OF(ObpObjectTypes))
1365     {
1366         /* It fits, insert it */
1367         ObpObjectTypes[LocalObjectType->Index - 1] = LocalObjectType;
1368     }
1369 
1370     /* Release the object type */
1371     ObpLeaveObjectTypeMutex(ObpTypeObjectType);
1372 
1373     /* Check if we're actually creating the directory object itself */
1374     if (!(ObpTypeDirectoryObject) ||
1375         (ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header)))
1376     {
1377         /* Check if the type directory exists */
1378         if (ObpTypeDirectoryObject)
1379         {
1380             /* Reference it */
1381             ObReferenceObject(ObpTypeDirectoryObject);
1382         }
1383 
1384         /* Cleanup the lookup context */
1385         ObpReleaseLookupContext(&Context);
1386 
1387         /* Return the object type and success */
1388         *ObjectType = LocalObjectType;
1389         return STATUS_SUCCESS;
1390     }
1391 
1392     /* If we got here, then we failed */
1393     ObpReleaseLookupContext(&Context);
1394     return STATUS_INSUFFICIENT_RESOURCES;
1395 }
1396 
1397 VOID
1398 NTAPI
ObDeleteCapturedInsertInfo(IN PVOID Object)1399 ObDeleteCapturedInsertInfo(IN PVOID Object)
1400 {
1401     POBJECT_HEADER ObjectHeader;
1402     PAGED_CODE();
1403 
1404     /* Check if there is anything to free */
1405     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1406     if ((ObjectHeader->Flags & OB_FLAG_CREATE_INFO) &&
1407         (ObjectHeader->ObjectCreateInfo != NULL))
1408     {
1409         /* Free the create info */
1410         ObpFreeObjectCreateInformation(ObjectHeader->ObjectCreateInfo);
1411         ObjectHeader->ObjectCreateInfo = NULL;
1412     }
1413 }
1414 
1415 VOID
1416 NTAPI
ObpDeleteObjectType(IN PVOID Object)1417 ObpDeleteObjectType(IN PVOID Object)
1418 {
1419     ULONG i;
1420     POBJECT_TYPE ObjectType = (PVOID)Object;
1421 
1422     /* Loop our locks */
1423     for (i = 0; i < 4; i++)
1424     {
1425         /* Delete each one */
1426         ExDeleteResourceLite(&ObjectType->ObjectLocks[i]);
1427     }
1428 
1429     /* Delete our main mutex */
1430     ExDeleteResourceLite(&ObjectType->Mutex);
1431 }
1432 
1433 /*++
1434 * @name ObMakeTemporaryObject
1435 * @implemented NT4
1436 *
1437 *     The ObMakeTemporaryObject routine <FILLMEIN>
1438 *
1439 * @param ObjectBody
1440 *        <FILLMEIN>
1441 *
1442 * @return None.
1443 *
1444 * @remarks None.
1445 *
1446 *--*/
1447 VOID
1448 NTAPI
ObMakeTemporaryObject(IN PVOID ObjectBody)1449 ObMakeTemporaryObject(IN PVOID ObjectBody)
1450 {
1451     PAGED_CODE();
1452 
1453     /* Call the internal API */
1454     ObpSetPermanentObject(ObjectBody, FALSE);
1455 }
1456 
1457 /*++
1458 * @name NtMakeTemporaryObject
1459 * @implemented NT4
1460 *
1461 *     The NtMakeTemporaryObject routine <FILLMEIN>
1462 *
1463 * @param ObjectHandle
1464 *        <FILLMEIN>
1465 *
1466 * @return STATUS_SUCCESS or appropriate error value.
1467 *
1468 * @remarks None.
1469 *
1470 *--*/
1471 NTSTATUS
1472 NTAPI
NtMakeTemporaryObject(IN HANDLE ObjectHandle)1473 NtMakeTemporaryObject(IN HANDLE ObjectHandle)
1474 {
1475     PVOID ObjectBody;
1476     NTSTATUS Status;
1477     PAGED_CODE();
1478 
1479     /* Reference the object for DELETE access */
1480     Status = ObReferenceObjectByHandle(ObjectHandle,
1481                                        DELETE,
1482                                        NULL,
1483                                        KeGetPreviousMode(),
1484                                        &ObjectBody,
1485                                        NULL);
1486     if (Status != STATUS_SUCCESS) return Status;
1487 
1488     /* Set it as temporary and dereference it */
1489     ObpSetPermanentObject(ObjectBody, FALSE);
1490     ObDereferenceObject(ObjectBody);
1491     return STATUS_SUCCESS;
1492 }
1493 
1494 /*++
1495 * @name NtMakePermanentObject
1496 * @implemented NT4
1497 *
1498 *     The NtMakePermanentObject routine <FILLMEIN>
1499 *
1500 * @param ObjectHandle
1501 *        <FILLMEIN>
1502 *
1503 * @return STATUS_SUCCESS or appropriate error value.
1504 *
1505 * @remarks None.
1506 *
1507 *--*/
1508 NTSTATUS
1509 NTAPI
NtMakePermanentObject(IN HANDLE ObjectHandle)1510 NtMakePermanentObject(IN HANDLE ObjectHandle)
1511 {
1512     PVOID ObjectBody;
1513     NTSTATUS Status;
1514     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1515     PAGED_CODE();
1516 
1517     /* Make sure that the caller has SeCreatePermanentPrivilege */
1518     if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege, PreviousMode))
1519     {
1520         return STATUS_PRIVILEGE_NOT_HELD;
1521     }
1522 
1523     /* Reference the object */
1524     Status = ObReferenceObjectByHandle(ObjectHandle,
1525                                        0,
1526                                        NULL,
1527                                        PreviousMode,
1528                                        &ObjectBody,
1529                                        NULL);
1530     if (Status != STATUS_SUCCESS) return Status;
1531 
1532     /* Set it as permanent and dereference it */
1533     ObpSetPermanentObject(ObjectBody, TRUE);
1534     ObDereferenceObject(ObjectBody);
1535     return STATUS_SUCCESS;
1536 }
1537 
1538 /*++
1539 * @name NtQueryObject
1540 * @implemented NT4
1541 *
1542 *     The NtQueryObject routine <FILLMEIN>
1543 *
1544 * @param ObjectHandle
1545 *        <FILLMEIN>
1546 *
1547 * @param ObjectInformationClass
1548 *        <FILLMEIN>
1549 *
1550 * @param ObjectInformation
1551 *        <FILLMEIN>
1552 *
1553 * @param Length
1554 *        <FILLMEIN>
1555 *
1556 * @param ResultLength
1557 *        <FILLMEIN>
1558 *
1559 * @return STATUS_SUCCESS or appropriate error value.
1560 *
1561 * @remarks None.
1562 *
1563 *--*/
1564 NTSTATUS
1565 NTAPI
NtQueryObject(IN HANDLE ObjectHandle,IN OBJECT_INFORMATION_CLASS ObjectInformationClass,OUT PVOID ObjectInformation,IN ULONG Length,OUT PULONG ResultLength OPTIONAL)1566 NtQueryObject(IN HANDLE ObjectHandle,
1567               IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1568               OUT PVOID ObjectInformation,
1569               IN ULONG Length,
1570               OUT PULONG ResultLength OPTIONAL)
1571 {
1572     OBJECT_HANDLE_INFORMATION HandleInfo;
1573     POBJECT_HEADER ObjectHeader = NULL;
1574     POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
1575     POBJECT_BASIC_INFORMATION BasicInfo;
1576     ULONG InfoLength = 0;
1577     PVOID Object = NULL;
1578     NTSTATUS Status;
1579     POBJECT_HEADER_QUOTA_INFO ObjectQuota;
1580     SECURITY_INFORMATION SecurityInformation;
1581     POBJECT_TYPE ObjectType;
1582     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1583     PAGED_CODE();
1584 
1585     /* Check if the caller is from user mode */
1586     if (PreviousMode != KernelMode)
1587     {
1588         /* Protect validation with SEH */
1589         _SEH2_TRY
1590         {
1591             /* Probe the input structure */
1592             ProbeForWrite(ObjectInformation, Length, sizeof(UCHAR));
1593 
1594             /* If we have a result length, probe it too */
1595             if (ResultLength) ProbeForWriteUlong(ResultLength);
1596         }
1597         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1598         {
1599             /* Return the exception code */
1600             _SEH2_YIELD(return _SEH2_GetExceptionCode());
1601         }
1602         _SEH2_END;
1603     }
1604 
1605     /*
1606      * Make sure this isn't a generic type query, since the caller doesn't
1607      * have to give a handle for it
1608      */
1609     if (ObjectInformationClass != ObjectTypesInformation)
1610     {
1611         /* Reference the object */
1612         Status = ObReferenceObjectByHandle(ObjectHandle,
1613                                            0,
1614                                            NULL,
1615                                            KeGetPreviousMode(),
1616                                            &Object,
1617                                            &HandleInfo);
1618         if (!NT_SUCCESS (Status)) return Status;
1619 
1620         /* Get the object header */
1621         ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1622         ObjectType = ObjectHeader->Type;
1623     }
1624 
1625     _SEH2_TRY
1626     {
1627         /* Check the information class */
1628         switch (ObjectInformationClass)
1629         {
1630             /* Basic info */
1631             case ObjectBasicInformation:
1632 
1633                 /* Validate length */
1634                 InfoLength = sizeof(OBJECT_BASIC_INFORMATION);
1635                 if (Length != sizeof(OBJECT_BASIC_INFORMATION))
1636                 {
1637                     /* Fail */
1638                     Status = STATUS_INFO_LENGTH_MISMATCH;
1639                     break;
1640                 }
1641 
1642                 /* Fill out the basic information */
1643                 BasicInfo = (POBJECT_BASIC_INFORMATION)ObjectInformation;
1644                 BasicInfo->Attributes = HandleInfo.HandleAttributes;
1645                 BasicInfo->GrantedAccess = HandleInfo.GrantedAccess;
1646                 BasicInfo->HandleCount = ObjectHeader->HandleCount;
1647                 BasicInfo->PointerCount = ObjectHeader->PointerCount;
1648 
1649                 /* Permanent/Exclusive Flags are NOT in Handle attributes! */
1650                 if (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE)
1651                 {
1652                     /* Set the flag */
1653                     BasicInfo->Attributes |= OBJ_EXCLUSIVE;
1654                 }
1655                 if (ObjectHeader->Flags & OB_FLAG_PERMANENT)
1656                 {
1657                     /* Set the flag */
1658                     BasicInfo->Attributes |= OBJ_PERMANENT;
1659                 }
1660 
1661                 /* Copy quota information */
1662                 ObjectQuota = OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader);
1663                 if (ObjectQuota != NULL)
1664                 {
1665                     BasicInfo->PagedPoolCharge = ObjectQuota->PagedPoolCharge;
1666                     BasicInfo->NonPagedPoolCharge = ObjectQuota->NonPagedPoolCharge;
1667                 }
1668                 else
1669                 {
1670                     BasicInfo->PagedPoolCharge = 0;
1671                     BasicInfo->NonPagedPoolCharge = 0;
1672                 }
1673 
1674                 /* Copy name information */
1675                 BasicInfo->NameInfoSize = ObpQueryNameInfoSize(ObjectHeader);
1676                 BasicInfo->TypeInfoSize = sizeof(OBJECT_TYPE_INFORMATION) + ObjectType->Name.Length +
1677                                           sizeof(UNICODE_NULL);
1678 
1679                 /* Check if this is a symlink */
1680                 if (ObjectHeader->Type == ObpSymbolicLinkObjectType)
1681                 {
1682                     /* Return the creation time */
1683                     BasicInfo->CreationTime.QuadPart =
1684                         ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart;
1685                 }
1686                 else
1687                 {
1688                     /* Otherwise return 0 */
1689                     BasicInfo->CreationTime.QuadPart = (ULONGLONG)0;
1690                 }
1691 
1692                 /* Copy security information */
1693                 BasicInfo->SecurityDescriptorSize = 0;
1694                 if (BooleanFlagOn(HandleInfo.GrantedAccess, READ_CONTROL) &&
1695                     ObjectHeader->SecurityDescriptor != NULL)
1696                 {
1697                     SecurityInformation = OWNER_SECURITY_INFORMATION |
1698                                           GROUP_SECURITY_INFORMATION |
1699                                           DACL_SECURITY_INFORMATION |
1700                                           SACL_SECURITY_INFORMATION;
1701 
1702                     ObjectType->TypeInfo.SecurityProcedure(Object,
1703                                                            QuerySecurityDescriptor,
1704                                                            &SecurityInformation,
1705                                                            NULL,
1706                                                            &BasicInfo->SecurityDescriptorSize,
1707                                                            &ObjectHeader->SecurityDescriptor,
1708                                                            ObjectType->TypeInfo.PoolType,
1709                                                            &ObjectType->TypeInfo.GenericMapping);
1710                 }
1711 
1712                 /* Break out with success */
1713                 Status = STATUS_SUCCESS;
1714                 break;
1715 
1716             /* Name information */
1717             case ObjectNameInformation:
1718 
1719                 /* Call the helper and break out */
1720                 Status = ObQueryNameString(Object,
1721                                            (POBJECT_NAME_INFORMATION)
1722                                            ObjectInformation,
1723                                            Length,
1724                                            &InfoLength);
1725                 break;
1726 
1727             /* Information about this type */
1728             case ObjectTypeInformation:
1729 
1730                 /* Call the helper and break out */
1731                 Status = ObQueryTypeInfo(ObjectHeader->Type,
1732                                          (POBJECT_TYPE_INFORMATION)
1733                                          ObjectInformation,
1734                                          Length,
1735                                          &InfoLength);
1736                 break;
1737 
1738             /* Information about all types */
1739             case ObjectTypesInformation:
1740                 DPRINT1("NOT IMPLEMENTED!\n");
1741                 InfoLength = Length;
1742                 Status = STATUS_NOT_IMPLEMENTED;
1743                 break;
1744 
1745             /* Information about the handle flags */
1746             case ObjectHandleFlagInformation:
1747 
1748                 /* Validate length */
1749                 InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION);
1750                 if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1751                 {
1752                     Status = STATUS_INFO_LENGTH_MISMATCH;
1753                     break;
1754                 }
1755 
1756                 /* Get the structure */
1757                 HandleFlags = (POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1758                                ObjectInformation;
1759 
1760                 /* Set the flags */
1761                 HandleFlags->Inherit = HandleInfo.HandleAttributes & OBJ_INHERIT;
1762                 HandleFlags->ProtectFromClose = (HandleInfo.HandleAttributes &
1763                                                  OBJ_PROTECT_CLOSE) != 0;
1764 
1765                 /* Break out with success */
1766                 Status = STATUS_SUCCESS;
1767                 break;
1768 
1769             /* Anything else */
1770             default:
1771 
1772                 /* Fail it */
1773                 InfoLength = Length;
1774                 Status = STATUS_INVALID_INFO_CLASS;
1775                 break;
1776         }
1777 
1778         /* Check if the caller wanted the return length */
1779         if (ResultLength)
1780         {
1781             /* Write the length */
1782             *ResultLength = InfoLength;
1783         }
1784     }
1785     _SEH2_EXCEPT(ExSystemExceptionFilter())
1786     {
1787         /* Otherwise, get the exception code */
1788         Status = _SEH2_GetExceptionCode();
1789     }
1790     _SEH2_END;
1791 
1792     /* Dereference the object if we had referenced it */
1793     if (Object) ObDereferenceObject(Object);
1794 
1795     /* Return status */
1796     return Status;
1797 }
1798 
1799 /*++
1800 * @name NtSetInformationObject
1801 * @implemented NT4
1802 *
1803 *     The NtSetInformationObject routine <FILLMEIN>
1804 *
1805 * @param ObjectHandle
1806 *        <FILLMEIN>
1807 *
1808 * @param ObjectInformationClass
1809 *        <FILLMEIN>
1810 *
1811 * @param ObjectInformation
1812 *        <FILLMEIN>
1813 *
1814 * @param Length
1815 *        <FILLMEIN>
1816 *
1817 * @return STATUS_SUCCESS or appropriate error value.
1818 *
1819 * @remarks None.
1820 *
1821 *--*/
1822 NTSTATUS
1823 NTAPI
NtSetInformationObject(IN HANDLE ObjectHandle,IN OBJECT_INFORMATION_CLASS ObjectInformationClass,IN PVOID ObjectInformation,IN ULONG Length)1824 NtSetInformationObject(IN HANDLE ObjectHandle,
1825                        IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1826                        IN PVOID ObjectInformation,
1827                        IN ULONG Length)
1828 {
1829     NTSTATUS Status;
1830     OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context;
1831     PVOID ObjectTable;
1832     KAPC_STATE ApcState;
1833     POBJECT_DIRECTORY Directory;
1834     KPROCESSOR_MODE PreviousMode;
1835     BOOLEAN AttachedToProcess = FALSE;
1836     PAGED_CODE();
1837 
1838     /* Validate the information class */
1839     switch (ObjectInformationClass)
1840     {
1841         case ObjectHandleFlagInformation:
1842 
1843             /* Validate the length */
1844             if (Length != sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1845             {
1846                 /* Invalid length */
1847                 return STATUS_INFO_LENGTH_MISMATCH;
1848             }
1849 
1850             /* Save the previous mode */
1851             Context.PreviousMode = ExGetPreviousMode();
1852 
1853             /* Check if we were called from user mode */
1854             if (Context.PreviousMode != KernelMode)
1855             {
1856                 /* Enter SEH */
1857                 _SEH2_TRY
1858                 {
1859                     /* Probe and capture the attribute buffer */
1860                     ProbeForRead(ObjectInformation,
1861                                  sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION),
1862                                  sizeof(BOOLEAN));
1863                     Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1864                                             ObjectInformation;
1865                 }
1866                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1867                 {
1868                     /* Return the exception code */
1869                     _SEH2_YIELD(return _SEH2_GetExceptionCode());
1870                 }
1871                 _SEH2_END;
1872             }
1873             else
1874             {
1875                 /* Just copy the buffer directly */
1876                 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1877                                         ObjectInformation;
1878             }
1879 
1880             /* Check if this is a kernel handle */
1881             if (ObpIsKernelHandle(ObjectHandle, Context.PreviousMode))
1882             {
1883                 /* Get the actual handle */
1884                 ObjectHandle = ObKernelHandleToHandle(ObjectHandle);
1885                 ObjectTable = ObpKernelHandleTable;
1886 
1887                 /* Check if we're not in the system process */
1888                 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1889                 {
1890                     /* Attach to it */
1891                     KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1892                     AttachedToProcess = TRUE;
1893                 }
1894             }
1895             else
1896             {
1897                 /* Use the current table */
1898                 ObjectTable = PsGetCurrentProcess()->ObjectTable;
1899             }
1900 
1901             /* Change the handle attributes */
1902             if (!ExChangeHandle(ObjectTable,
1903                                 ObjectHandle,
1904                                 ObpSetHandleAttributes,
1905                                 (ULONG_PTR)&Context))
1906             {
1907                 /* Some failure */
1908                 Status = STATUS_ACCESS_DENIED;
1909             }
1910             else
1911             {
1912                 /* We are done */
1913                 Status = STATUS_SUCCESS;
1914             }
1915 
1916             /* De-attach if we were attached, and return status */
1917             if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1918             break;
1919 
1920         case ObjectSessionInformation:
1921 
1922             /* Only a system process can do this */
1923             PreviousMode = ExGetPreviousMode();
1924             if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1925             {
1926                 /* Fail */
1927                 DPRINT1("Privilege not held\n");
1928                 Status = STATUS_PRIVILEGE_NOT_HELD;
1929             }
1930             else
1931             {
1932                 /* Get the object directory */
1933                 Status = ObReferenceObjectByHandle(ObjectHandle,
1934                                                    0,
1935                                                    ObpDirectoryObjectType,
1936                                                    PreviousMode,
1937                                                    (PVOID*)&Directory,
1938                                                    NULL);
1939                 if (NT_SUCCESS(Status))
1940                 {
1941                     /* Setup a lookup context */
1942                     OBP_LOOKUP_CONTEXT LookupContext;
1943                     ObpInitializeLookupContext(&LookupContext);
1944 
1945                     /* Set the directory session ID */
1946                     ObpAcquireDirectoryLockExclusive(Directory, &LookupContext);
1947                     Directory->SessionId = PsGetCurrentProcessSessionId();
1948                     ObpReleaseDirectoryLock(Directory, &LookupContext);
1949 
1950                     /* We're done, release the context and dereference the directory */
1951                     ObpReleaseLookupContext(&LookupContext);
1952                     ObDereferenceObject(Directory);
1953                 }
1954             }
1955             break;
1956 
1957         default:
1958             /* Unsupported class */
1959             Status = STATUS_INVALID_INFO_CLASS;
1960             break;
1961     }
1962 
1963     return Status;
1964 }
1965 
1966 /* EOF */
1967