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