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 /** 873 * @brief 874 * Queries the name info size of a given resource object. 875 * The function loops through all the parent directories 876 * of the object and computes the name size. 877 * 878 * @param[in] ObjectHeader 879 * A pointer to an object header, of which name and 880 * directory info are to be retrieved. 881 * 882 * @return 883 * Returns the name info size that is pointed by the 884 * given object by the caller of this function. If 885 * an object does not have a name or no directories, 886 * it returns 0. 887 */ 888 static 889 ULONG 890 ObpQueryNameInfoSize( 891 _In_ POBJECT_HEADER ObjectHeader) 892 { 893 ULONG NameSize = 0; 894 POBJECT_DIRECTORY ParentDirectory; 895 POBJECT_HEADER_NAME_INFO NameInfo; 896 PAGED_CODE(); 897 898 /* Get the name info */ 899 NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 900 if (!NameInfo) 901 { 902 return 0; 903 } 904 905 /* Get the parent directory from the object name too */ 906 ParentDirectory = NameInfo->Directory; 907 if (!ParentDirectory) 908 { 909 return 0; 910 } 911 912 /* Take into account the name size of this object and loop for all parent directories */ 913 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + NameInfo->Name.Length; 914 for (;;) 915 { 916 /* Get the name info from the parent directory */ 917 NameInfo = OBJECT_HEADER_TO_NAME_INFO( 918 OBJECT_TO_OBJECT_HEADER(ParentDirectory)); 919 if (!NameInfo) 920 { 921 /* Stop looking if this is the last one */ 922 break; 923 } 924 925 /* Get the parent directory */ 926 ParentDirectory = NameInfo->Directory; 927 if (!ParentDirectory) 928 { 929 /* This is the last directory, stop looking */ 930 break; 931 } 932 933 /* 934 * Take into account the size of this name info, 935 * keep looking for other parent directories. 936 */ 937 NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) + NameInfo->Name.Length; 938 } 939 940 /* Include the size of the object name information as well as the NULL terminator */ 941 NameSize += sizeof(OBJECT_NAME_INFORMATION) + sizeof(UNICODE_NULL); 942 return NameSize; 943 } 944 945 NTSTATUS 946 NTAPI 947 ObQueryTypeInfo( 948 _In_ POBJECT_TYPE ObjectType, 949 _Out_writes_bytes_to_(Length, *ReturnLength) 950 POBJECT_TYPE_INFORMATION ObjectTypeInfo, 951 _In_ ULONG Length, 952 _Out_ PULONG ReturnLength) 953 { 954 NTSTATUS Status = STATUS_SUCCESS; 955 PWSTR InfoBuffer; 956 957 /* The string of the object type name has to be NULL-terminated */ 958 ASSERT(ObjectType->Name.MaximumLength >= ObjectType->Name.Length + sizeof(UNICODE_NULL)); 959 960 /* Enter SEH */ 961 _SEH2_TRY 962 { 963 /* 964 * Set return length aligned to 4-byte or 8-byte boundary. Windows has a bug 965 * where the returned length pointer is always aligned to a 4-byte boundary. 966 * If one were to allocate a pool of memory in kernel mode to retrieve all 967 * the object types info with this return length, Windows will bugcheck with 968 * BAD_POOL_HEADER in 64-bit upon you free the said allocated memory. 969 * 970 * More than that, Windows uses MaximumLength for the calculation of the returned 971 * length and MaximumLength does not always guarantee the name type is NULL-terminated 972 * leading the ObQueryTypeInfo function to overrun the buffer. 973 */ 974 *ReturnLength += sizeof(*ObjectTypeInfo) + 975 ALIGN_UP(ObjectType->Name.Length + sizeof(UNICODE_NULL), ULONG_PTR); 976 977 /* Check if that is too much */ 978 if (Length < *ReturnLength) 979 { 980 _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); 981 } 982 983 /* Build the data */ 984 ObjectTypeInfo->TotalNumberOfHandles = 985 ObjectType->TotalNumberOfHandles; 986 ObjectTypeInfo->TotalNumberOfObjects = 987 ObjectType->TotalNumberOfObjects; 988 ObjectTypeInfo->HighWaterNumberOfHandles = 989 ObjectType->HighWaterNumberOfHandles; 990 ObjectTypeInfo->HighWaterNumberOfObjects = 991 ObjectType->HighWaterNumberOfObjects; 992 ObjectTypeInfo->PoolType = 993 ObjectType->TypeInfo.PoolType; 994 ObjectTypeInfo->DefaultNonPagedPoolCharge = 995 ObjectType->TypeInfo.DefaultNonPagedPoolCharge; 996 ObjectTypeInfo->DefaultPagedPoolCharge = 997 ObjectType->TypeInfo.DefaultPagedPoolCharge; 998 ObjectTypeInfo->ValidAccessMask = 999 ObjectType->TypeInfo.ValidAccessMask; 1000 ObjectTypeInfo->SecurityRequired = 1001 ObjectType->TypeInfo.SecurityRequired; 1002 ObjectTypeInfo->InvalidAttributes = 1003 ObjectType->TypeInfo.InvalidAttributes; 1004 ObjectTypeInfo->GenericMapping = 1005 ObjectType->TypeInfo.GenericMapping; 1006 ObjectTypeInfo->MaintainHandleCount = 1007 ObjectType->TypeInfo.MaintainHandleCount; 1008 1009 /* Setup the name buffer */ 1010 InfoBuffer = (PWSTR)(ObjectTypeInfo + 1); 1011 ObjectTypeInfo->TypeName.Buffer = InfoBuffer; 1012 ObjectTypeInfo->TypeName.MaximumLength = ObjectType->Name.MaximumLength; 1013 ObjectTypeInfo->TypeName.Length = ObjectType->Name.Length; 1014 1015 /* Copy it */ 1016 RtlCopyMemory(InfoBuffer, 1017 ObjectType->Name.Buffer, 1018 ObjectType->Name.Length); 1019 1020 /* Null-terminate it */ 1021 (InfoBuffer)[ObjectType->Name.Length / sizeof(WCHAR)] = UNICODE_NULL; 1022 } 1023 _SEH2_EXCEPT(ExSystemExceptionFilter()) 1024 { 1025 /* Otherwise, get the exception code */ 1026 Status = _SEH2_GetExceptionCode(); 1027 } 1028 _SEH2_END; 1029 1030 /* Return status to caller */ 1031 return Status; 1032 } 1033 1034 1035 /* PUBLIC FUNCTIONS **********************************************************/ 1036 1037 NTSTATUS 1038 NTAPI 1039 ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL, 1040 IN POBJECT_TYPE Type, 1041 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 1042 IN KPROCESSOR_MODE AccessMode, 1043 IN OUT PVOID ParseContext OPTIONAL, 1044 IN ULONG ObjectSize, 1045 IN ULONG PagedPoolCharge OPTIONAL, 1046 IN ULONG NonPagedPoolCharge OPTIONAL, 1047 OUT PVOID *Object) 1048 { 1049 NTSTATUS Status; 1050 POBJECT_CREATE_INFORMATION ObjectCreateInfo; 1051 UNICODE_STRING ObjectName; 1052 POBJECT_HEADER Header; 1053 1054 /* Allocate a capture buffer */ 1055 ObjectCreateInfo = ObpAllocateObjectCreateInfoBuffer(LookasideCreateInfoList); 1056 if (!ObjectCreateInfo) return STATUS_INSUFFICIENT_RESOURCES; 1057 1058 /* Capture all the info */ 1059 Status = ObpCaptureObjectCreateInformation(ObjectAttributes, 1060 ProbeMode, 1061 AccessMode, 1062 FALSE, 1063 ObjectCreateInfo, 1064 &ObjectName); 1065 if (NT_SUCCESS(Status)) 1066 { 1067 /* Validate attributes */ 1068 if (Type->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes) 1069 { 1070 /* Fail */ 1071 Status = STATUS_INVALID_PARAMETER; 1072 } 1073 else 1074 { 1075 /* Check if we have a paged charge */ 1076 if (!PagedPoolCharge) 1077 { 1078 /* Save it */ 1079 PagedPoolCharge = Type->TypeInfo.DefaultPagedPoolCharge; 1080 } 1081 1082 /* Check for nonpaged charge */ 1083 if (!NonPagedPoolCharge) 1084 { 1085 /* Save it */ 1086 NonPagedPoolCharge = Type->TypeInfo.DefaultNonPagedPoolCharge; 1087 } 1088 1089 /* Write the pool charges */ 1090 ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge; 1091 ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge; 1092 1093 /* Allocate the Object */ 1094 Status = ObpAllocateObject(ObjectCreateInfo, 1095 &ObjectName, 1096 Type, 1097 ObjectSize, 1098 AccessMode, 1099 &Header); 1100 if (NT_SUCCESS(Status)) 1101 { 1102 /* Return the Object */ 1103 *Object = &Header->Body; 1104 1105 /* Check if this is a permanent object */ 1106 if (Header->Flags & OB_FLAG_PERMANENT) 1107 { 1108 /* Do the privilege check */ 1109 if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege, 1110 ProbeMode)) 1111 { 1112 /* Fail */ 1113 ObpDeallocateObject(*Object); 1114 Status = STATUS_PRIVILEGE_NOT_HELD; 1115 } 1116 } 1117 1118 /* Return status */ 1119 return Status; 1120 } 1121 } 1122 1123 /* Release the Capture Info, we don't need it */ 1124 ObpFreeObjectCreateInformation(ObjectCreateInfo); 1125 if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName); 1126 return Status; 1127 } 1128 1129 /* We failed, so release the Buffer */ 1130 ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList); 1131 return Status; 1132 } 1133 1134 NTSTATUS 1135 NTAPI 1136 ObCreateObjectType(IN PUNICODE_STRING TypeName, 1137 IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, 1138 IN PVOID Reserved, 1139 OUT POBJECT_TYPE *ObjectType) 1140 { 1141 POBJECT_HEADER Header; 1142 POBJECT_TYPE LocalObjectType; 1143 ULONG HeaderSize; 1144 NTSTATUS Status; 1145 OBP_LOOKUP_CONTEXT Context; 1146 PWCHAR p; 1147 ULONG i; 1148 UNICODE_STRING ObjectName; 1149 ANSI_STRING AnsiName; 1150 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 1151 1152 /* Verify parameters */ 1153 if (!(TypeName) || 1154 !(TypeName->Length) || 1155 (TypeName->Length % sizeof(WCHAR)) || 1156 !(ObjectTypeInitializer) || 1157 (ObjectTypeInitializer->Length != sizeof(*ObjectTypeInitializer)) || 1158 (ObjectTypeInitializer->InvalidAttributes & ~OBJ_VALID_KERNEL_ATTRIBUTES) || 1159 (ObjectTypeInitializer->MaintainHandleCount && 1160 (!(ObjectTypeInitializer->OpenProcedure) && 1161 !ObjectTypeInitializer->CloseProcedure)) || 1162 ((!ObjectTypeInitializer->UseDefaultObject) && 1163 (ObjectTypeInitializer->PoolType != NonPagedPool))) 1164 { 1165 /* Fail */ 1166 return STATUS_INVALID_PARAMETER; 1167 } 1168 1169 /* Make sure the name doesn't have a separator */ 1170 p = TypeName->Buffer; 1171 i = TypeName->Length / sizeof(WCHAR); 1172 while (i--) 1173 { 1174 /* Check for one and fail */ 1175 if (*p++ == OBJ_NAME_PATH_SEPARATOR) return STATUS_OBJECT_NAME_INVALID; 1176 } 1177 1178 /* Setup a lookup context */ 1179 ObpInitializeLookupContext(&Context); 1180 1181 /* Check if we've already created the directory of types */ 1182 if (ObpTypeDirectoryObject) 1183 { 1184 /* Lock the lookup context */ 1185 ObpAcquireLookupContextLock(&Context, ObpTypeDirectoryObject); 1186 1187 /* Do the lookup */ 1188 if (ObpLookupEntryDirectory(ObpTypeDirectoryObject, 1189 TypeName, 1190 OBJ_CASE_INSENSITIVE, 1191 FALSE, 1192 &Context)) 1193 { 1194 /* We have already created it, so fail */ 1195 ObpReleaseLookupContext(&Context); 1196 return STATUS_OBJECT_NAME_COLLISION; 1197 } 1198 } 1199 1200 /* Now make a copy of the object name */ 1201 ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool, 1202 TypeName->MaximumLength, 1203 OB_NAME_TAG); 1204 if (!ObjectName.Buffer) 1205 { 1206 /* Out of memory, fail */ 1207 ObpReleaseLookupContext(&Context); 1208 return STATUS_INSUFFICIENT_RESOURCES; 1209 } 1210 1211 /* Set the length and copy the name */ 1212 ObjectName.MaximumLength = TypeName->MaximumLength; 1213 RtlCopyUnicodeString(&ObjectName, TypeName); 1214 1215 /* Allocate the Object */ 1216 Status = ObpAllocateObject(NULL, 1217 &ObjectName, 1218 ObpTypeObjectType, 1219 sizeof(OBJECT_TYPE), 1220 KernelMode, 1221 &Header); 1222 if (!NT_SUCCESS(Status)) 1223 { 1224 /* Free the name and fail */ 1225 ObpReleaseLookupContext(&Context); 1226 ExFreePool(ObjectName.Buffer); 1227 return Status; 1228 } 1229 1230 /* Setup the flags and name */ 1231 LocalObjectType = (POBJECT_TYPE)&Header->Body; 1232 LocalObjectType->Name = ObjectName; 1233 Header->Flags |= OB_FLAG_KERNEL_MODE | OB_FLAG_PERMANENT; 1234 1235 /* Clear accounting data */ 1236 LocalObjectType->TotalNumberOfObjects = 1237 LocalObjectType->TotalNumberOfHandles = 1238 LocalObjectType->HighWaterNumberOfObjects = 1239 LocalObjectType->HighWaterNumberOfHandles = 0; 1240 1241 /* Check if this is the first Object Type */ 1242 if (!ObpTypeObjectType) 1243 { 1244 /* It is, so set this as the type object */ 1245 ObpTypeObjectType = LocalObjectType; 1246 Header->Type = ObpTypeObjectType; 1247 1248 /* Set the hard-coded key and object count */ 1249 LocalObjectType->TotalNumberOfObjects = 1; 1250 LocalObjectType->Key = TAG_OBJECT_TYPE; 1251 } 1252 else 1253 { 1254 /* Convert the tag to ASCII */ 1255 Status = RtlUnicodeStringToAnsiString(&AnsiName, TypeName, TRUE); 1256 if (NT_SUCCESS(Status)) 1257 { 1258 /* For every missing character, use a space */ 1259 for (i = 3; i >= AnsiName.Length; i--) AnsiName.Buffer[i] = ' '; 1260 1261 /* Set the key and free the converted name */ 1262 LocalObjectType->Key = *(PULONG)AnsiName.Buffer; 1263 RtlFreeAnsiString(&AnsiName); 1264 } 1265 else 1266 { 1267 /* Just copy the characters */ 1268 LocalObjectType->Key = *(PULONG)TypeName->Buffer; 1269 } 1270 } 1271 1272 /* Set up the type information */ 1273 LocalObjectType->TypeInfo = *ObjectTypeInitializer; 1274 LocalObjectType->TypeInfo.PoolType = ObjectTypeInitializer->PoolType; 1275 1276 /* Check if we have to maintain a type list */ 1277 if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST) 1278 { 1279 /* Enable support */ 1280 LocalObjectType->TypeInfo.MaintainTypeList = TRUE; 1281 } 1282 1283 /* Calculate how much space our header'll take up */ 1284 HeaderSize = sizeof(OBJECT_HEADER) + 1285 sizeof(OBJECT_HEADER_NAME_INFO) + 1286 (ObjectTypeInitializer->MaintainHandleCount ? 1287 sizeof(OBJECT_HEADER_HANDLE_INFO) : 0); 1288 1289 /* Check the pool type */ 1290 if (ObjectTypeInitializer->PoolType == NonPagedPool) 1291 { 1292 /* Update the NonPaged Pool charge */ 1293 LocalObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderSize; 1294 } 1295 else 1296 { 1297 /* Update the Paged Pool charge */ 1298 LocalObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderSize; 1299 } 1300 1301 /* All objects types need a security procedure */ 1302 if (!ObjectTypeInitializer->SecurityProcedure) 1303 { 1304 LocalObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod; 1305 } 1306 1307 /* Select the Wait Object */ 1308 if (LocalObjectType->TypeInfo.UseDefaultObject) 1309 { 1310 /* Add the SYNCHRONIZE access mask since it's waitable */ 1311 LocalObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE; 1312 1313 /* Use the "Default Object", a simple event */ 1314 LocalObjectType->DefaultObject = &ObpDefaultObject; 1315 } 1316 /* The File Object gets an optimized hack so it can be waited on */ 1317 else if ((TypeName->Length == 8) && !(wcscmp(TypeName->Buffer, L"File"))) 1318 { 1319 /* Wait on the File Object's event directly */ 1320 LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(FILE_OBJECT, 1321 Event)); 1322 } 1323 else if ((TypeName->Length == 24) && !(wcscmp(TypeName->Buffer, L"WaitablePort"))) 1324 { 1325 /* Wait on the LPC Port's object directly */ 1326 LocalObjectType->DefaultObject = UlongToPtr(FIELD_OFFSET(LPCP_PORT_OBJECT, 1327 WaitEvent)); 1328 } 1329 else 1330 { 1331 /* No default Object */ 1332 LocalObjectType->DefaultObject = NULL; 1333 } 1334 1335 /* Initialize Object Type components */ 1336 ExInitializeResourceLite(&LocalObjectType->Mutex); 1337 for (i = 0; i < 4; i++) 1338 { 1339 /* Initialize the object locks */ 1340 ExInitializeResourceLite(&LocalObjectType->ObjectLocks[i]); 1341 } 1342 InitializeListHead(&LocalObjectType->TypeList); 1343 1344 /* Lock the object type */ 1345 ObpEnterObjectTypeMutex(ObpTypeObjectType); 1346 1347 /* Get creator info and insert it into the type list */ 1348 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header); 1349 if (CreatorInfo) 1350 { 1351 InsertTailList(&ObpTypeObjectType->TypeList, 1352 &CreatorInfo->TypeList); 1353 1354 /* CORE-8423: Avoid inserting this a second time if someone creates a 1355 * handle to the object type (bug in Windows 2003) */ 1356 Header->Flags &= ~OB_FLAG_CREATE_INFO; 1357 } 1358 1359 /* Set the index and the entry into the object type array */ 1360 LocalObjectType->Index = ObpTypeObjectType->TotalNumberOfObjects; 1361 1362 ASSERT(LocalObjectType->Index != 0); 1363 1364 if (LocalObjectType->Index < RTL_NUMBER_OF(ObpObjectTypes)) 1365 { 1366 /* It fits, insert it */ 1367 ObpObjectTypes[LocalObjectType->Index - 1] = LocalObjectType; 1368 } 1369 1370 /* Release the object type */ 1371 ObpLeaveObjectTypeMutex(ObpTypeObjectType); 1372 1373 /* Check if we're actually creating the directory object itself */ 1374 if (!(ObpTypeDirectoryObject) || 1375 (ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header))) 1376 { 1377 /* Check if the type directory exists */ 1378 if (ObpTypeDirectoryObject) 1379 { 1380 /* Reference it */ 1381 ObReferenceObject(ObpTypeDirectoryObject); 1382 } 1383 1384 /* Cleanup the lookup context */ 1385 ObpReleaseLookupContext(&Context); 1386 1387 /* Return the object type and success */ 1388 *ObjectType = LocalObjectType; 1389 return STATUS_SUCCESS; 1390 } 1391 1392 /* If we got here, then we failed */ 1393 ObpReleaseLookupContext(&Context); 1394 return STATUS_INSUFFICIENT_RESOURCES; 1395 } 1396 1397 VOID 1398 NTAPI 1399 ObDeleteCapturedInsertInfo(IN PVOID Object) 1400 { 1401 POBJECT_HEADER ObjectHeader; 1402 PAGED_CODE(); 1403 1404 /* Check if there is anything to free */ 1405 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 1406 if ((ObjectHeader->Flags & OB_FLAG_CREATE_INFO) && 1407 (ObjectHeader->ObjectCreateInfo != NULL)) 1408 { 1409 /* Free the create info */ 1410 ObpFreeObjectCreateInformation(ObjectHeader->ObjectCreateInfo); 1411 ObjectHeader->ObjectCreateInfo = NULL; 1412 } 1413 } 1414 1415 VOID 1416 NTAPI 1417 ObpDeleteObjectType(IN PVOID Object) 1418 { 1419 ULONG i; 1420 POBJECT_TYPE ObjectType = (PVOID)Object; 1421 1422 /* Loop our locks */ 1423 for (i = 0; i < 4; i++) 1424 { 1425 /* Delete each one */ 1426 ExDeleteResourceLite(&ObjectType->ObjectLocks[i]); 1427 } 1428 1429 /* Delete our main mutex */ 1430 ExDeleteResourceLite(&ObjectType->Mutex); 1431 } 1432 1433 /*++ 1434 * @name ObMakeTemporaryObject 1435 * @implemented NT4 1436 * 1437 * The ObMakeTemporaryObject routine <FILLMEIN> 1438 * 1439 * @param ObjectBody 1440 * <FILLMEIN> 1441 * 1442 * @return None. 1443 * 1444 * @remarks None. 1445 * 1446 *--*/ 1447 VOID 1448 NTAPI 1449 ObMakeTemporaryObject(IN PVOID ObjectBody) 1450 { 1451 PAGED_CODE(); 1452 1453 /* Call the internal API */ 1454 ObpSetPermanentObject(ObjectBody, FALSE); 1455 } 1456 1457 /*++ 1458 * @name NtMakeTemporaryObject 1459 * @implemented NT4 1460 * 1461 * The NtMakeTemporaryObject routine <FILLMEIN> 1462 * 1463 * @param ObjectHandle 1464 * <FILLMEIN> 1465 * 1466 * @return STATUS_SUCCESS or appropriate error value. 1467 * 1468 * @remarks None. 1469 * 1470 *--*/ 1471 NTSTATUS 1472 NTAPI 1473 NtMakeTemporaryObject(IN HANDLE ObjectHandle) 1474 { 1475 PVOID ObjectBody; 1476 NTSTATUS Status; 1477 PAGED_CODE(); 1478 1479 /* Reference the object for DELETE access */ 1480 Status = ObReferenceObjectByHandle(ObjectHandle, 1481 DELETE, 1482 NULL, 1483 KeGetPreviousMode(), 1484 &ObjectBody, 1485 NULL); 1486 if (Status != STATUS_SUCCESS) return Status; 1487 1488 /* Set it as temporary and dereference it */ 1489 ObpSetPermanentObject(ObjectBody, FALSE); 1490 ObDereferenceObject(ObjectBody); 1491 return STATUS_SUCCESS; 1492 } 1493 1494 /*++ 1495 * @name NtMakePermanentObject 1496 * @implemented NT4 1497 * 1498 * The NtMakePermanentObject routine <FILLMEIN> 1499 * 1500 * @param ObjectHandle 1501 * <FILLMEIN> 1502 * 1503 * @return STATUS_SUCCESS or appropriate error value. 1504 * 1505 * @remarks None. 1506 * 1507 *--*/ 1508 NTSTATUS 1509 NTAPI 1510 NtMakePermanentObject(IN HANDLE ObjectHandle) 1511 { 1512 PVOID ObjectBody; 1513 NTSTATUS Status; 1514 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1515 PAGED_CODE(); 1516 1517 /* Make sure that the caller has SeCreatePermanentPrivilege */ 1518 if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege, PreviousMode)) 1519 { 1520 return STATUS_PRIVILEGE_NOT_HELD; 1521 } 1522 1523 /* Reference the object */ 1524 Status = ObReferenceObjectByHandle(ObjectHandle, 1525 0, 1526 NULL, 1527 PreviousMode, 1528 &ObjectBody, 1529 NULL); 1530 if (Status != STATUS_SUCCESS) return Status; 1531 1532 /* Set it as permanent and dereference it */ 1533 ObpSetPermanentObject(ObjectBody, TRUE); 1534 ObDereferenceObject(ObjectBody); 1535 return STATUS_SUCCESS; 1536 } 1537 1538 /*++ 1539 * @name NtQueryObject 1540 * @implemented NT4 1541 * 1542 * The NtQueryObject routine <FILLMEIN> 1543 * 1544 * @param ObjectHandle 1545 * <FILLMEIN> 1546 * 1547 * @param ObjectInformationClass 1548 * <FILLMEIN> 1549 * 1550 * @param ObjectInformation 1551 * <FILLMEIN> 1552 * 1553 * @param Length 1554 * <FILLMEIN> 1555 * 1556 * @param ResultLength 1557 * <FILLMEIN> 1558 * 1559 * @return STATUS_SUCCESS or appropriate error value. 1560 * 1561 * @remarks None. 1562 * 1563 *--*/ 1564 NTSTATUS 1565 NTAPI 1566 NtQueryObject(IN HANDLE ObjectHandle, 1567 IN OBJECT_INFORMATION_CLASS ObjectInformationClass, 1568 OUT PVOID ObjectInformation, 1569 IN ULONG Length, 1570 OUT PULONG ResultLength OPTIONAL) 1571 { 1572 OBJECT_HANDLE_INFORMATION HandleInfo; 1573 POBJECT_HEADER ObjectHeader = NULL; 1574 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags; 1575 POBJECT_BASIC_INFORMATION BasicInfo; 1576 ULONG InfoLength = 0; 1577 PVOID Object = NULL; 1578 NTSTATUS Status; 1579 POBJECT_HEADER_QUOTA_INFO ObjectQuota; 1580 SECURITY_INFORMATION SecurityInformation; 1581 POBJECT_TYPE ObjectType; 1582 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1583 PAGED_CODE(); 1584 1585 /* Check if the caller is from user mode */ 1586 if (PreviousMode != KernelMode) 1587 { 1588 /* Protect validation with SEH */ 1589 _SEH2_TRY 1590 { 1591 /* Probe the input structure */ 1592 ProbeForWrite(ObjectInformation, Length, sizeof(UCHAR)); 1593 1594 /* If we have a result length, probe it too */ 1595 if (ResultLength) ProbeForWriteUlong(ResultLength); 1596 } 1597 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1598 { 1599 /* Return the exception code */ 1600 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1601 } 1602 _SEH2_END; 1603 } 1604 1605 /* 1606 * Make sure this isn't a generic type query, since the caller doesn't 1607 * have to give a handle for it 1608 */ 1609 if (ObjectInformationClass != ObjectTypesInformation) 1610 { 1611 /* Reference the object */ 1612 Status = ObReferenceObjectByHandle(ObjectHandle, 1613 0, 1614 NULL, 1615 KeGetPreviousMode(), 1616 &Object, 1617 &HandleInfo); 1618 if (!NT_SUCCESS (Status)) return Status; 1619 1620 /* Get the object header */ 1621 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 1622 ObjectType = ObjectHeader->Type; 1623 } 1624 1625 _SEH2_TRY 1626 { 1627 /* Check the information class */ 1628 switch (ObjectInformationClass) 1629 { 1630 /* Basic info */ 1631 case ObjectBasicInformation: 1632 1633 /* Validate length */ 1634 InfoLength = sizeof(OBJECT_BASIC_INFORMATION); 1635 if (Length != sizeof(OBJECT_BASIC_INFORMATION)) 1636 { 1637 /* Fail */ 1638 Status = STATUS_INFO_LENGTH_MISMATCH; 1639 break; 1640 } 1641 1642 /* Fill out the basic information */ 1643 BasicInfo = (POBJECT_BASIC_INFORMATION)ObjectInformation; 1644 BasicInfo->Attributes = HandleInfo.HandleAttributes; 1645 BasicInfo->GrantedAccess = HandleInfo.GrantedAccess; 1646 BasicInfo->HandleCount = ObjectHeader->HandleCount; 1647 BasicInfo->PointerCount = ObjectHeader->PointerCount; 1648 1649 /* Permanent/Exclusive Flags are NOT in Handle attributes! */ 1650 if (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) 1651 { 1652 /* Set the flag */ 1653 BasicInfo->Attributes |= OBJ_EXCLUSIVE; 1654 } 1655 if (ObjectHeader->Flags & OB_FLAG_PERMANENT) 1656 { 1657 /* Set the flag */ 1658 BasicInfo->Attributes |= OBJ_PERMANENT; 1659 } 1660 1661 /* Copy quota information */ 1662 ObjectQuota = OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader); 1663 if (ObjectQuota != NULL) 1664 { 1665 BasicInfo->PagedPoolCharge = ObjectQuota->PagedPoolCharge; 1666 BasicInfo->NonPagedPoolCharge = ObjectQuota->NonPagedPoolCharge; 1667 } 1668 else 1669 { 1670 BasicInfo->PagedPoolCharge = 0; 1671 BasicInfo->NonPagedPoolCharge = 0; 1672 } 1673 1674 /* Copy name information */ 1675 BasicInfo->NameInfoSize = ObpQueryNameInfoSize(ObjectHeader); 1676 BasicInfo->TypeInfoSize = sizeof(OBJECT_TYPE_INFORMATION) + ObjectType->Name.Length + 1677 sizeof(UNICODE_NULL); 1678 1679 /* Check if this is a symlink */ 1680 if (ObjectHeader->Type == ObpSymbolicLinkObjectType) 1681 { 1682 /* Return the creation time */ 1683 BasicInfo->CreationTime.QuadPart = 1684 ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart; 1685 } 1686 else 1687 { 1688 /* Otherwise return 0 */ 1689 BasicInfo->CreationTime.QuadPart = (ULONGLONG)0; 1690 } 1691 1692 /* Copy security information */ 1693 BasicInfo->SecurityDescriptorSize = 0; 1694 if (BooleanFlagOn(HandleInfo.GrantedAccess, READ_CONTROL) && 1695 ObjectHeader->SecurityDescriptor != NULL) 1696 { 1697 SecurityInformation = OWNER_SECURITY_INFORMATION | 1698 GROUP_SECURITY_INFORMATION | 1699 DACL_SECURITY_INFORMATION | 1700 SACL_SECURITY_INFORMATION; 1701 1702 ObjectType->TypeInfo.SecurityProcedure(Object, 1703 QuerySecurityDescriptor, 1704 &SecurityInformation, 1705 NULL, 1706 &BasicInfo->SecurityDescriptorSize, 1707 &ObjectHeader->SecurityDescriptor, 1708 ObjectType->TypeInfo.PoolType, 1709 &ObjectType->TypeInfo.GenericMapping); 1710 } 1711 1712 /* Break out with success */ 1713 Status = STATUS_SUCCESS; 1714 break; 1715 1716 /* Name information */ 1717 case ObjectNameInformation: 1718 1719 /* Call the helper and break out */ 1720 Status = ObQueryNameString(Object, 1721 (POBJECT_NAME_INFORMATION) 1722 ObjectInformation, 1723 Length, 1724 &InfoLength); 1725 break; 1726 1727 /* Information about this type */ 1728 case ObjectTypeInformation: 1729 1730 /* Call the helper and break out */ 1731 Status = ObQueryTypeInfo(ObjectHeader->Type, 1732 (POBJECT_TYPE_INFORMATION) 1733 ObjectInformation, 1734 Length, 1735 &InfoLength); 1736 break; 1737 1738 /* Information about all types */ 1739 case ObjectTypesInformation: 1740 DPRINT1("NOT IMPLEMENTED!\n"); 1741 InfoLength = Length; 1742 Status = STATUS_NOT_IMPLEMENTED; 1743 break; 1744 1745 /* Information about the handle flags */ 1746 case ObjectHandleFlagInformation: 1747 1748 /* Validate length */ 1749 InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION); 1750 if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION)) 1751 { 1752 Status = STATUS_INFO_LENGTH_MISMATCH; 1753 break; 1754 } 1755 1756 /* Get the structure */ 1757 HandleFlags = (POBJECT_HANDLE_ATTRIBUTE_INFORMATION) 1758 ObjectInformation; 1759 1760 /* Set the flags */ 1761 HandleFlags->Inherit = HandleInfo.HandleAttributes & OBJ_INHERIT; 1762 HandleFlags->ProtectFromClose = (HandleInfo.HandleAttributes & 1763 OBJ_PROTECT_CLOSE) != 0; 1764 1765 /* Break out with success */ 1766 Status = STATUS_SUCCESS; 1767 break; 1768 1769 /* Anything else */ 1770 default: 1771 1772 /* Fail it */ 1773 InfoLength = Length; 1774 Status = STATUS_INVALID_INFO_CLASS; 1775 break; 1776 } 1777 1778 /* Check if the caller wanted the return length */ 1779 if (ResultLength) 1780 { 1781 /* Write the length */ 1782 *ResultLength = InfoLength; 1783 } 1784 } 1785 _SEH2_EXCEPT(ExSystemExceptionFilter()) 1786 { 1787 /* Otherwise, get the exception code */ 1788 Status = _SEH2_GetExceptionCode(); 1789 } 1790 _SEH2_END; 1791 1792 /* Dereference the object if we had referenced it */ 1793 if (Object) ObDereferenceObject(Object); 1794 1795 /* Return status */ 1796 return Status; 1797 } 1798 1799 /*++ 1800 * @name NtSetInformationObject 1801 * @implemented NT4 1802 * 1803 * The NtSetInformationObject routine <FILLMEIN> 1804 * 1805 * @param ObjectHandle 1806 * <FILLMEIN> 1807 * 1808 * @param ObjectInformationClass 1809 * <FILLMEIN> 1810 * 1811 * @param ObjectInformation 1812 * <FILLMEIN> 1813 * 1814 * @param Length 1815 * <FILLMEIN> 1816 * 1817 * @return STATUS_SUCCESS or appropriate error value. 1818 * 1819 * @remarks None. 1820 * 1821 *--*/ 1822 NTSTATUS 1823 NTAPI 1824 NtSetInformationObject(IN HANDLE ObjectHandle, 1825 IN OBJECT_INFORMATION_CLASS ObjectInformationClass, 1826 IN PVOID ObjectInformation, 1827 IN ULONG Length) 1828 { 1829 NTSTATUS Status; 1830 OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context; 1831 PVOID ObjectTable; 1832 KAPC_STATE ApcState; 1833 POBJECT_DIRECTORY Directory; 1834 KPROCESSOR_MODE PreviousMode; 1835 BOOLEAN AttachedToProcess = FALSE; 1836 PAGED_CODE(); 1837 1838 /* Validate the information class */ 1839 switch (ObjectInformationClass) 1840 { 1841 case ObjectHandleFlagInformation: 1842 1843 /* Validate the length */ 1844 if (Length != sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION)) 1845 { 1846 /* Invalid length */ 1847 return STATUS_INFO_LENGTH_MISMATCH; 1848 } 1849 1850 /* Save the previous mode */ 1851 Context.PreviousMode = ExGetPreviousMode(); 1852 1853 /* Check if we were called from user mode */ 1854 if (Context.PreviousMode != KernelMode) 1855 { 1856 /* Enter SEH */ 1857 _SEH2_TRY 1858 { 1859 /* Probe and capture the attribute buffer */ 1860 ProbeForRead(ObjectInformation, 1861 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION), 1862 sizeof(BOOLEAN)); 1863 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION) 1864 ObjectInformation; 1865 } 1866 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1867 { 1868 /* Return the exception code */ 1869 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1870 } 1871 _SEH2_END; 1872 } 1873 else 1874 { 1875 /* Just copy the buffer directly */ 1876 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION) 1877 ObjectInformation; 1878 } 1879 1880 /* Check if this is a kernel handle */ 1881 if (ObpIsKernelHandle(ObjectHandle, Context.PreviousMode)) 1882 { 1883 /* Get the actual handle */ 1884 ObjectHandle = ObKernelHandleToHandle(ObjectHandle); 1885 ObjectTable = ObpKernelHandleTable; 1886 1887 /* Check if we're not in the system process */ 1888 if (PsGetCurrentProcess() != PsInitialSystemProcess) 1889 { 1890 /* Attach to it */ 1891 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState); 1892 AttachedToProcess = TRUE; 1893 } 1894 } 1895 else 1896 { 1897 /* Use the current table */ 1898 ObjectTable = PsGetCurrentProcess()->ObjectTable; 1899 } 1900 1901 /* Change the handle attributes */ 1902 if (!ExChangeHandle(ObjectTable, 1903 ObjectHandle, 1904 ObpSetHandleAttributes, 1905 (ULONG_PTR)&Context)) 1906 { 1907 /* Some failure */ 1908 Status = STATUS_ACCESS_DENIED; 1909 } 1910 else 1911 { 1912 /* We are done */ 1913 Status = STATUS_SUCCESS; 1914 } 1915 1916 /* De-attach if we were attached, and return status */ 1917 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState); 1918 break; 1919 1920 case ObjectSessionInformation: 1921 1922 /* Only a system process can do this */ 1923 PreviousMode = ExGetPreviousMode(); 1924 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1925 { 1926 /* Fail */ 1927 DPRINT1("Privilege not held\n"); 1928 Status = STATUS_PRIVILEGE_NOT_HELD; 1929 } 1930 else 1931 { 1932 /* Get the object directory */ 1933 Status = ObReferenceObjectByHandle(ObjectHandle, 1934 0, 1935 ObpDirectoryObjectType, 1936 PreviousMode, 1937 (PVOID*)&Directory, 1938 NULL); 1939 if (NT_SUCCESS(Status)) 1940 { 1941 /* Setup a lookup context */ 1942 OBP_LOOKUP_CONTEXT LookupContext; 1943 ObpInitializeLookupContext(&LookupContext); 1944 1945 /* Set the directory session ID */ 1946 ObpAcquireDirectoryLockExclusive(Directory, &LookupContext); 1947 Directory->SessionId = PsGetCurrentProcessSessionId(); 1948 ObpReleaseDirectoryLock(Directory, &LookupContext); 1949 1950 /* We're done, release the context and dereference the directory */ 1951 ObpReleaseLookupContext(&LookupContext); 1952 ObDereferenceObject(Directory); 1953 } 1954 } 1955 break; 1956 1957 default: 1958 /* Unsupported class */ 1959 Status = STATUS_INVALID_INFO_CLASS; 1960 break; 1961 } 1962 1963 return Status; 1964 } 1965 1966 /* EOF */ 1967