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