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