Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

obhandle.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 obhandle.c 00008 00009 Abstract: 00010 00011 Object handle routines 00012 00013 Author: 00014 00015 Steve Wood (stevewo) 31-Mar-1989 00016 00017 Revision History: 00018 00019 --*/ 00020 00021 #include "obp.h" 00022 00023 // 00024 // Define logical sum of all generic accesses. 00025 // 00026 00027 #define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL) 00028 00029 // 00030 // The following variable is declared in obinit.c and is used to protect the 00031 // process object table 00032 // 00033 00034 extern KMUTANT ObpInitKillMutant; 00035 00036 // 00037 // Define local prototypes 00038 // 00039 00040 NTSTATUS 00041 ObpIncrementHandleDataBase ( 00042 IN POBJECT_HEADER ObjectHeader, 00043 IN PEPROCESS Process, 00044 OUT PULONG NewProcessHandleCount 00045 ); 00046 00047 NTSTATUS 00048 ObpCaptureHandleInformation ( 00049 IN OUT PSYSTEM_HANDLE_TABLE_ENTRY_INFO *HandleEntryInfo, 00050 IN HANDLE UniqueProcessId, 00051 IN PVOID HandleTableEntry, 00052 IN HANDLE HandleIndex, 00053 IN ULONG Length, 00054 IN OUT PULONG RequiredLength 00055 ); 00056 00057 #ifdef ALLOC_PRAGMA 00058 #pragma alloc_text(PAGE,NtDuplicateObject) 00059 #pragma alloc_text(PAGE,ObGetHandleInformation) 00060 #pragma alloc_text(PAGE,ObpInsertHandleCount) 00061 #pragma alloc_text(PAGE,ObpIncrementHandleCount) 00062 #pragma alloc_text(PAGE,ObpIncrementUnnamedHandleCount) 00063 #pragma alloc_text(PAGE,ObpDecrementHandleCount) 00064 #pragma alloc_text(PAGE,ObpCreateHandle) 00065 #pragma alloc_text(PAGE,ObpCreateUnnamedHandle) 00066 #pragma alloc_text(PAGE,ObpIncrementHandleDataBase) 00067 #endif 00068 00069 00070 // 00071 // Define routines for incrementing and decrementing the object header 00072 // counters. These routines are only used if MPSAFE handle count check 00073 // is defined 00074 // 00075 00076 #ifdef MPSAFE_HANDLE_COUNT_CHECK 00077 00078 VOID 00079 FASTCALL 00080 ObpIncrPointerCount ( 00081 IN POBJECT_HEADER ObjectHeader 00082 ) 00083 { 00084 KIRQL OldIrql; 00085 00086 ExAcquireFastLock( &ObpLock, &OldIrql ); 00087 ObjectHeader->PointerCount += 1; 00088 ExReleaseFastLock( &ObpLock, OldIrql ); 00089 } 00090 00091 VOID 00092 FASTCALL 00093 ObpDecrPointerCount ( 00094 IN POBJECT_HEADER ObjectHeader 00095 ) 00096 { 00097 KIRQL OldIrql; 00098 00099 ExAcquireFastLock( &ObpLock, &OldIrql ); 00100 ObjectHeader->PointerCount -= 1; 00101 ExReleaseFastLock( &ObpLock, OldIrql ); 00102 } 00103 00104 BOOLEAN 00105 FASTCALL 00106 ObpDecrPointerCountWithResult ( 00107 IN POBJECT_HEADER ObjectHeader 00108 ) 00109 { 00110 KIRQL OldIrql; 00111 LONG Result; 00112 00113 ExAcquireFastLock( &ObpLock, &OldIrql ); 00114 00115 if (ObjectHeader->PointerCount <= ObjectHeader->HandleCount) { 00116 00117 DbgPrint( "OB: About to over-dereference object %x (ObjectHeader at %x)\n", 00118 ObjectHeader->Object, ObjectHeader ); 00119 00120 DbgBreakPoint(); 00121 } 00122 00123 ObjectHeader->PointerCount -= 1; 00124 Result = ObjectHeader->PointerCount; 00125 ExReleaseFastLock( &ObpLock, OldIrql ); 00126 return Result == 0; 00127 } 00128 00129 VOID 00130 FASTCALL 00131 ObpIncrHandleCount ( 00132 IN POBJECT_HEADER ObjectHeader 00133 ) 00134 { 00135 KIRQL OldIrql; 00136 00137 ExAcquireFastLock( &ObpLock, &OldIrql ); 00138 ObjectHeader->HandleCount += 1; 00139 ExReleaseFastLock( &ObpLock, OldIrql ); 00140 } 00141 00142 BOOLEAN 00143 FASTCALL 00144 ObpDecrHandleCount ( 00145 IN POBJECT_HEADER ObjectHeader 00146 ) 00147 { 00148 KIRQL OldIrql; 00149 LONG Old; 00150 00151 ExAcquireFastLock( &ObpLock, &OldIrql ); 00152 Old = ObjectHeader->HandleCount; 00153 ObjectHeader->HandleCount -= 1; 00154 ExReleaseFastLock( &ObpLock, OldIrql ); 00155 00156 return Old == 1; 00157 } 00158 00159 #endif // MPSAFE_HANDLE_COUNT_CHECK 00160 00161 00162 NTSTATUS 00163 NtDuplicateObject ( 00164 IN HANDLE SourceProcessHandle, 00165 IN HANDLE SourceHandle, 00166 IN HANDLE TargetProcessHandle OPTIONAL, 00167 OUT PHANDLE TargetHandle OPTIONAL, 00168 IN ACCESS_MASK DesiredAccess, 00169 IN ULONG HandleAttributes, 00170 IN ULONG Options 00171 ) 00172 00173 /*++ 00174 00175 Routine Description: 00176 00177 This function creates a handle that is a duplicate of the specified 00178 source handle. The source handle is evaluated in the context of the 00179 specified source process. The calling process must have 00180 PROCESS_DUP_HANDLE access to the source process. The duplicate 00181 handle is created with the specified attributes and desired access. 00182 The duplicate handle is created in the handle table of the specified 00183 target process. The calling process must have PROCESS_DUP_HANDLE 00184 access to the target process. 00185 00186 Arguments: 00187 00188 SourceProcessHandle - Supplies a handle to the source process for the 00189 handle being duplicated 00190 00191 SourceHandle - Supplies the handle being duplicated 00192 00193 TargetProcessHandle - Optionally supplies a handle to the target process 00194 that is to receive the new handle 00195 00196 TargetHandle - Optionally returns a the new duplicated handle 00197 00198 DesiredAccess - Desired access for the new handle 00199 00200 HandleAttributes - Desired attributes for the new handle 00201 00202 Options - Duplication options that control things like close source, 00203 same access, and same attributes. 00204 00205 Return Value: 00206 00207 TBS 00208 00209 --*/ 00210 00211 { 00212 KPROCESSOR_MODE PreviousMode; 00213 NTSTATUS Status; 00214 PVOID SourceObject; 00215 POBJECT_HEADER ObjectHeader; 00216 POBJECT_TYPE ObjectType; 00217 PEPROCESS SourceProcess; 00218 PEPROCESS TargetProcess; 00219 BOOLEAN Attached; 00220 PVOID ObjectTable; 00221 HANDLE_TABLE_ENTRY ObjectTableEntry; 00222 OBJECT_HANDLE_INFORMATION HandleInformation; 00223 HANDLE NewHandle; 00224 ACCESS_STATE AccessState; 00225 AUX_ACCESS_DATA AuxData; 00226 ACCESS_MASK SourceAccess; 00227 ACCESS_MASK TargetAccess; 00228 PACCESS_STATE PassedAccessState = NULL; 00229 00230 // 00231 // Get previous processor mode and probe output arguments if necessary. 00232 // 00233 00234 PreviousMode = KeGetPreviousMode(); 00235 00236 if (ARGUMENT_PRESENT( TargetHandle ) && (PreviousMode != KernelMode)) { 00237 00238 try { 00239 00240 ProbeForWriteHandle( TargetHandle ); 00241 00242 } except( EXCEPTION_EXECUTE_HANDLER ) { 00243 00244 return( GetExceptionCode() ); 00245 } 00246 } 00247 00248 // 00249 // If the caller is not asking for the same access then 00250 // validate the access they are requesting doesn't contain 00251 // any bad bits 00252 // 00253 00254 if (!(Options & DUPLICATE_SAME_ACCESS)) { 00255 00256 Status = ObpValidateDesiredAccess( DesiredAccess ); 00257 00258 if (!NT_SUCCESS( Status )) { 00259 00260 return( Status ); 00261 } 00262 } 00263 00264 // 00265 // The Attached variable indicates if we needed to 00266 // attach to the source process because it was not the 00267 // current process. 00268 // 00269 00270 Attached = FALSE; 00271 00272 // 00273 // Given the input source process handle get a pointer 00274 // to the source process object 00275 // 00276 00277 Status = ObReferenceObjectByHandle( SourceProcessHandle, 00278 PROCESS_DUP_HANDLE, 00279 PsProcessType, 00280 PreviousMode, 00281 (PVOID *)&SourceProcess, 00282 NULL ); 00283 00284 if (!NT_SUCCESS( Status )) { 00285 00286 return Status; 00287 } 00288 00289 // 00290 // Lock down access to the process object tables 00291 // 00292 00293 KeEnterCriticalRegion(); 00294 00295 KeWaitForSingleObject( &ObpInitKillMutant, 00296 Executive, 00297 KernelMode, 00298 FALSE, 00299 NULL ); 00300 00301 // 00302 // Make sure the source process has an object table still 00303 // 00304 00305 if ( SourceProcess->ObjectTable == NULL ) { 00306 00307 KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE ); 00308 00309 KeLeaveCriticalRegion(); 00310 00311 ObDereferenceObject( SourceProcess ); 00312 00313 return STATUS_PROCESS_IS_TERMINATING; 00314 } 00315 00316 // 00317 // If the specified source process is not the current process, attach 00318 // to the specified source process. Then after we reference the object 00319 // we can detach from the process. 00320 // 00321 00322 if (PsGetCurrentProcess() != SourceProcess) { 00323 00324 KeAttachProcess( &SourceProcess->Pcb ); 00325 00326 Attached = TRUE; 00327 } 00328 00329 // 00330 // The the input source handle get a pointer to the 00331 // source object itself, then detach from the process 00332 // if necessary and check if we were given a good 00333 // source handle. 00334 // 00335 00336 Status = ObReferenceObjectByHandle( SourceHandle, 00337 0, 00338 (POBJECT_TYPE)NULL, 00339 PreviousMode, 00340 &SourceObject, 00341 &HandleInformation ); 00342 00343 if (Attached) { 00344 00345 KeDetachProcess(); 00346 00347 Attached = FALSE; 00348 } 00349 00350 if (!NT_SUCCESS( Status )) { 00351 00352 KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE ); 00353 00354 KeLeaveCriticalRegion(); 00355 00356 ObDereferenceObject( SourceProcess ); 00357 00358 return( Status ); 00359 } 00360 00361 // 00362 // We are all done if no target process handle was specified. 00363 // This is practially a noop because the only really end result 00364 // could be that we've closed the source handle. 00365 // 00366 00367 if (!ARGUMENT_PRESENT( TargetProcessHandle )) { 00368 00369 // 00370 // If no TargetProcessHandle, then only possible option is to close 00371 // the source handle in the context of the source process. 00372 // 00373 00374 if (!(Options & DUPLICATE_CLOSE_SOURCE)) { 00375 00376 Status = STATUS_INVALID_PARAMETER; 00377 } 00378 00379 if (Options & DUPLICATE_CLOSE_SOURCE) { 00380 00381 KeAttachProcess( &SourceProcess->Pcb ); 00382 00383 NtClose( SourceHandle ); 00384 00385 KeDetachProcess(); 00386 } 00387 00388 KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE ); 00389 00390 KeLeaveCriticalRegion(); 00391 00392 ObDereferenceObject( SourceObject ); 00393 ObDereferenceObject( SourceProcess ); 00394 00395 return( Status ); 00396 } 00397 00398 SourceAccess = HandleInformation.GrantedAccess; 00399 00400 // 00401 // At this point the caller did specify for a target process 00402 // So from the target process handle get a pointer to the 00403 // target process object. 00404 // 00405 00406 Status = ObReferenceObjectByHandle( TargetProcessHandle, 00407 PROCESS_DUP_HANDLE, 00408 PsProcessType, 00409 PreviousMode, 00410 (PVOID *)&TargetProcess, 00411 NULL ); 00412 00413 // 00414 // If we cannot get the traget process object then close the 00415 // source down if requsted, cleanup and return to our caller 00416 // 00417 00418 if (!NT_SUCCESS( Status )) { 00419 00420 if (Options & DUPLICATE_CLOSE_SOURCE) { 00421 00422 KeAttachProcess( &SourceProcess->Pcb ); 00423 00424 NtClose( SourceHandle ); 00425 00426 KeDetachProcess(); 00427 } 00428 00429 KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE ); 00430 00431 KeLeaveCriticalRegion(); 00432 00433 ObDereferenceObject( SourceObject ); 00434 ObDereferenceObject( SourceProcess ); 00435 00436 return( Status ); 00437 } 00438 00439 // 00440 // Make sure the target process has not exited 00441 // 00442 00443 if ( TargetProcess->ObjectTable == NULL ) { 00444 00445 if (Options & DUPLICATE_CLOSE_SOURCE) { 00446 00447 KeAttachProcess( &SourceProcess->Pcb ); 00448 00449 NtClose( SourceHandle ); 00450 00451 KeDetachProcess(); 00452 } 00453 00454 KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE ); 00455 00456 KeLeaveCriticalRegion(); 00457 00458 ObDereferenceObject( SourceObject ); 00459 ObDereferenceObject( SourceProcess ); 00460 ObDereferenceObject( TargetProcess ); 00461 00462 return STATUS_PROCESS_IS_TERMINATING; 00463 } 00464 00465 // 00466 // If the specified target process is not the current process, attach 00467 // to the specified target process. 00468 // 00469 00470 if (PsGetCurrentProcess() != TargetProcess) { 00471 00472 KeAttachProcess( &TargetProcess->Pcb ); 00473 00474 Attached = TRUE; 00475 } 00476 00477 // 00478 // Construct the proper desired access and attributes for the new handle 00479 // 00480 00481 if (Options & DUPLICATE_SAME_ACCESS) { 00482 00483 DesiredAccess = SourceAccess; 00484 } 00485 00486 if (Options & DUPLICATE_SAME_ATTRIBUTES) { 00487 00488 HandleAttributes = HandleInformation.HandleAttributes; 00489 00490 } else { 00491 00492 // 00493 // Always propogate auditing information. 00494 // 00495 00496 HandleAttributes |= HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE; 00497 } 00498 00499 // 00500 // Get the object header for the source object 00501 // 00502 00503 ObjectHeader = OBJECT_TO_OBJECT_HEADER( SourceObject ); 00504 ObjectType = ObjectHeader->Type; 00505 00506 ObjectTableEntry.Object = ObjectHeader; 00507 ObjectTableEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES); 00508 00509 // 00510 // If any of the generic access bits are specified then map those to more 00511 // specific access bits 00512 // 00513 00514 if ((DesiredAccess & GENERIC_ACCESS) != 0) { 00515 00516 RtlMapGenericMask( &DesiredAccess, 00517 &ObjectType->TypeInfo.GenericMapping ); 00518 } 00519 00520 // 00521 // Make sure to preserve ACCESS_SYSTEM_SECURITY, which most likely is not 00522 // found in the ValidAccessMask 00523 // 00524 00525 TargetAccess = DesiredAccess & 00526 (ObjectType->TypeInfo.ValidAccessMask | ACCESS_SYSTEM_SECURITY); 00527 00528 // 00529 // If the access requested for the target is a superset of the 00530 // access allowed in the source, perform full AVR. If it is a 00531 // subset or equal, do not perform any access validation. 00532 // 00533 // Do not allow superset access if object type has a private security 00534 // method, as there is no means to call them in this case to do the 00535 // access check. 00536 // 00537 // If the AccessState is not passed to ObpIncrementHandleCount 00538 // there will be no AVR. 00539 // 00540 00541 if (TargetAccess & ~SourceAccess) { 00542 00543 if (ObjectType->TypeInfo.SecurityProcedure == SeDefaultObjectMethod) { 00544 00545 Status = SeCreateAccessState( &AccessState, 00546 &AuxData, 00547 TargetAccess, // DesiredAccess 00548 &ObjectType->TypeInfo.GenericMapping ); 00549 00550 PassedAccessState = &AccessState; 00551 00552 } else { 00553 00554 Status = STATUS_ACCESS_DENIED; 00555 } 00556 00557 } else { 00558 00559 // 00560 // Do not perform AVR 00561 // 00562 00563 PassedAccessState = NULL; 00564 00565 Status = STATUS_SUCCESS; 00566 } 00567 00568 // 00569 // Increment the new handle count and get a pointer to 00570 // the target processes object table 00571 // 00572 00573 if ( NT_SUCCESS( Status )) { 00574 00575 Status = ObpIncrementHandleCount( ObDuplicateHandle, 00576 PsGetCurrentProcess(), // this is already the target process 00577 SourceObject, 00578 ObjectType, 00579 PassedAccessState, 00580 PreviousMode, 00581 HandleAttributes ); 00582 00583 ObjectTable = ObpGetObjectTable(); 00584 00585 ASSERT(ObjectTable); 00586 } 00587 00588 if (Attached) { 00589 00590 KeDetachProcess(); 00591 00592 Attached = FALSE; 00593 } 00594 00595 if (Options & DUPLICATE_CLOSE_SOURCE) { 00596 00597 KeAttachProcess( &SourceProcess->Pcb ); 00598 00599 NtClose( SourceHandle ); 00600 00601 KeDetachProcess(); 00602 } 00603 00604 if (!NT_SUCCESS( Status )) { 00605 00606 if (PassedAccessState != NULL) { 00607 00608 SeDeleteAccessState( PassedAccessState ); 00609 } 00610 00611 KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE ); 00612 00613 KeLeaveCriticalRegion(); 00614 00615 ObDereferenceObject( SourceObject ); 00616 ObDereferenceObject( SourceProcess ); 00617 ObDereferenceObject( TargetProcess ); 00618 00619 return( Status ); 00620 } 00621 00622 if ((PassedAccessState != NULL) && (PassedAccessState->GenerateOnClose == TRUE)) { 00623 00624 // 00625 // If we performed AVR opening the handle, then mark the handle as needing 00626 // auditing when it's closed. 00627 // 00628 00629 ObjectTableEntry.ObAttributes |= OBJ_AUDIT_OBJECT_CLOSE; 00630 } 00631 00632 #if i386 && !FPO 00633 00634 if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) { 00635 00636 ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( TargetAccess ); 00637 ObjectTableEntry.CreatorBackTraceIndex = RtlLogStackBackTrace(); 00638 00639 } else { 00640 00641 ObjectTableEntry.GrantedAccess = TargetAccess; 00642 } 00643 00644 #else 00645 00646 ObjectTableEntry.GrantedAccess = TargetAccess; 00647 00648 #endif // i386 && !FPO 00649 00650 // 00651 // Now that we've constructed a new object table entry for the duplicated handle 00652 // we need to add it to the object table of the target process 00653 00654 00655 NewHandle = ExCreateHandle( ObjectTable, &ObjectTableEntry ); 00656 00657 if (NewHandle) { 00658 00659 // 00660 // We have a new handle to audit the creation of the new handle if 00661 // AVR was done. And set the optional output handle variable. Note 00662 // that if we reach here the status variable is already a success 00663 // 00664 00665 if (PassedAccessState != NULL) { 00666 00667 SeAuditHandleCreation( PassedAccessState, NewHandle ); 00668 } 00669 00670 if (SeDetailedAuditing && (ObjectTableEntry.ObAttributes & OBJ_AUDIT_OBJECT_CLOSE)) { 00671 00672 SeAuditHandleDuplication( SourceHandle, 00673 NewHandle, 00674 SourceProcess, 00675 TargetProcess ); 00676 } 00677 00678 if (ARGUMENT_PRESENT( TargetHandle )) { 00679 00680 try { 00681 00682 *TargetHandle = NewHandle; 00683 00684 } except( EXCEPTION_EXECUTE_HANDLER ) { 00685 00686 // 00687 // Fall through, since we cannot undo what we have done. 00688 // 00689 } 00690 } 00691 00692 } else { 00693 00694 // 00695 // We didn't get a new handle to decrement the handle count dereference 00696 // the necessary objects, set the optional output variable and indicate 00697 // why we're failing 00698 // 00699 00700 ObpDecrementHandleCount( TargetProcess, 00701 ObjectHeader, 00702 ObjectType, 00703 TargetAccess ); 00704 00705 ObDereferenceObject( SourceObject ); 00706 00707 if (ARGUMENT_PRESENT( TargetHandle )) { 00708 00709 try { 00710 00711 *TargetHandle = (HANDLE)NULL; 00712 00713 } except( EXCEPTION_EXECUTE_HANDLER ) { 00714 00715 // 00716 // Fall through so we can return the correct status. 00717 // 00718 } 00719 } 00720 00721 Status = STATUS_INSUFFICIENT_RESOURCES; 00722 } 00723 00724 // 00725 // Cleanup from our selfs and then return to our caller 00726 // 00727 00728 if (PassedAccessState != NULL) { 00729 00730 SeDeleteAccessState( PassedAccessState ); 00731 } 00732 00733 KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE ); 00734 00735 KeLeaveCriticalRegion(); 00736 00737 ObDereferenceObject( SourceProcess ); 00738 ObDereferenceObject( TargetProcess ); 00739 00740 return( Status ); 00741 } 00742 00743 00744 NTSTATUS 00745 ObGetHandleInformation ( 00746 OUT PSYSTEM_HANDLE_INFORMATION HandleInformation, 00747 IN ULONG Length, 00748 OUT PULONG ReturnLength OPTIONAL 00749 ) 00750 00751 /*++ 00752 00753 Routine Description: 00754 00755 This routine returns information about the specified handle. 00756 00757 Arguments: 00758 00759 HandleInformation - Supplies an array of handle information 00760 structures to fill in 00761 00762 Length - Supplies the length the handle information array in bytes 00763 00764 ReturnLength - Receives the number of bytes used by this call 00765 00766 Return Value: 00767 00768 An appropriate status value 00769 00770 --*/ 00771 00772 { 00773 NTSTATUS Status; 00774 ULONG RequiredLength; 00775 00776 PAGED_CODE(); 00777 00778 RequiredLength = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handles ); 00779 00780 if (Length < RequiredLength) { 00781 00782 return( STATUS_INFO_LENGTH_MISMATCH ); 00783 } 00784 00785 HandleInformation->NumberOfHandles = 0; 00786 00787 // 00788 // For every handle in every handle table we'll be calling 00789 // our callback routine 00790 // 00791 00792 Status = ExSnapShotHandleTables( ObpCaptureHandleInformation, 00793 HandleInformation, 00794 Length, 00795 &RequiredLength ); 00796 00797 if (ARGUMENT_PRESENT( ReturnLength )) { 00798 00799 *ReturnLength = RequiredLength; 00800 } 00801 00802 return( Status ); 00803 } 00804 00805 00806 NTSTATUS 00807 ObpCaptureHandleInformation ( 00808 IN OUT PSYSTEM_HANDLE_TABLE_ENTRY_INFO *HandleEntryInfo, 00809 IN HANDLE UniqueProcessId, 00810 IN PHANDLE_TABLE_ENTRY ObjectTableEntry, 00811 IN HANDLE HandleIndex, 00812 IN ULONG Length, 00813 IN OUT PULONG RequiredLength 00814 ) 00815 00816 /*++ 00817 00818 Routine Description: 00819 00820 This is the callback routine of ObGetHandleInformation 00821 00822 Arguments: 00823 00824 HandleEntryInfo - Supplies a pointer to the output buffer to receive 00825 the handle information 00826 00827 UniqueProcessId - Supplies the process id of the caller 00828 00829 ObjectTableEntry - Supplies the handle table entry that is being 00830 captured 00831 00832 HandleIndex - Supplies the index for the preceding handle table entry 00833 00834 Length - Specifies the length, in bytes, of the original user buffer 00835 00836 RequiredLength - Specifies the length, in bytes, that has already been 00837 used in the buffer to store information. On return this receives 00838 the updated number of bytes being used. 00839 00840 Note that the HandleEntryInfo does not necessarily point to the 00841 start of the original user buffer. It will have been offset by 00842 the feed-in RequiredLength value. 00843 00844 Return Value: 00845 00846 An appropriate status value 00847 00848 --*/ 00849 00850 { 00851 NTSTATUS Status; 00852 POBJECT_HEADER ObjectHeader; 00853 00854 // 00855 // Figure out who much size we really need to contain this extra record 00856 // and then check that it fits. 00857 // 00858 00859 *RequiredLength += sizeof( SYSTEM_HANDLE_TABLE_ENTRY_INFO ); 00860 00861 if (Length < *RequiredLength) { 00862 00863 Status = STATUS_INFO_LENGTH_MISMATCH; 00864 00865 } else { 00866 00867 // 00868 // Get the object header from the table entry and then copy over the information 00869 // 00870 00871 ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(ObjectTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES); 00872 00873 (*HandleEntryInfo)->UniqueProcessId = (USHORT)((ULONG_PTR)UniqueProcessId); 00874 (*HandleEntryInfo)->HandleAttributes = (UCHAR)(ObjectTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES); 00875 (*HandleEntryInfo)->ObjectTypeIndex = (UCHAR)(ObjectHeader->Type->Index); 00876 (*HandleEntryInfo)->HandleValue = (USHORT)((ULONG_PTR)(HandleIndex)); 00877 (*HandleEntryInfo)->Object = &ObjectHeader->Body; 00878 (*HandleEntryInfo)->CreatorBackTraceIndex = 0; 00879 00880 #if i386 && !FPO 00881 00882 if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) { 00883 00884 (*HandleEntryInfo)->CreatorBackTraceIndex = ObjectTableEntry->CreatorBackTraceIndex; 00885 (*HandleEntryInfo)->GrantedAccess = ObpTranslateGrantedAccessIndex( ObjectTableEntry->GrantedAccessIndex ); 00886 00887 } else { 00888 00889 (*HandleEntryInfo)->GrantedAccess = ObjectTableEntry->GrantedAccess; 00890 } 00891 00892 #else 00893 00894 (*HandleEntryInfo)->GrantedAccess = ObjectTableEntry->GrantedAccess; 00895 00896 #endif // i386 && !FPO 00897 00898 (*HandleEntryInfo)++; 00899 00900 Status = STATUS_SUCCESS; 00901 } 00902 00903 return( Status ); 00904 } 00905 00906 00907 POBJECT_HANDLE_COUNT_ENTRY 00908 ObpInsertHandleCount ( 00909 POBJECT_HEADER ObjectHeader 00910 ) 00911 00912 /*++ 00913 00914 Routine Description: 00915 00916 This function will increase the size of the handle database 00917 stored in the handle information of an object header. If 00918 necessary it will allocate new and free old handle databases. 00919 00920 This routine should not be called if there is already free 00921 space in the handle table. 00922 00923 Arguments: 00924 00925 ObjectHeader - The object whose handle count is being incremented 00926 00927 Return Value: 00928 00929 The pointer to the next free handle count entry within the 00930 handle database. 00931 00932 --*/ 00933 00934 { 00935 POBJECT_HEADER_HANDLE_INFO HandleInfo; 00936 POBJECT_HANDLE_COUNT_DATABASE OldHandleCountDataBase; 00937 POBJECT_HANDLE_COUNT_DATABASE NewHandleCountDataBase; 00938 POBJECT_HANDLE_COUNT_ENTRY FreeHandleCountEntry; 00939 ULONG CountEntries; 00940 ULONG OldSize; 00941 ULONG NewSize; 00942 OBJECT_HANDLE_COUNT_DATABASE SingleEntryDataBase; 00943 00944 PAGED_CODE(); 00945 00946 // 00947 // Check if the object has any handle information 00948 // 00949 00950 HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader); 00951 00952 if (HandleInfo == NULL) { 00953 00954 return NULL; 00955 } 00956 00957 // 00958 // The object does have some handle information. If it has 00959 // a single handle entry then we'll construct a local dummy 00960 // handle count database and come up with a new data base for 00961 // storing two entries. 00962 // 00963 00964 if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) { 00965 00966 SingleEntryDataBase.CountEntries = 1; 00967 SingleEntryDataBase.HandleCountEntries[0] = HandleInfo->SingleEntry; 00968 00969 OldHandleCountDataBase = &SingleEntryDataBase; 00970 00971 OldSize = sizeof( SingleEntryDataBase ); 00972 00973 CountEntries = 2; 00974 00975 NewSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) + 00976 ((CountEntries - 1) * sizeof( OBJECT_HANDLE_COUNT_ENTRY )); 00977 00978 } else { 00979 00980 // 00981 // The object already has multiple handles so we reference the 00982 // current handle database, and compute a new size bumped by four 00983 // 00984 00985 OldHandleCountDataBase = HandleInfo->HandleCountDataBase; 00986 00987 CountEntries = OldHandleCountDataBase->CountEntries; 00988 00989 OldSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) + 00990 ((CountEntries - 1) * sizeof( OBJECT_HANDLE_COUNT_ENTRY)); 00991 00992 CountEntries += 4; 00993 00994 NewSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) + 00995 ((CountEntries - 1) * sizeof( OBJECT_HANDLE_COUNT_ENTRY)); 00996 } 00997 00998 // 00999 // Now allocate pool for the new handle database. 01000 // 01001 01002 NewHandleCountDataBase = ExAllocatePoolWithTag(PagedPool, NewSize,'dHbO'); 01003 01004 if (NewHandleCountDataBase == NULL) { 01005 01006 return NULL; 01007 } 01008 01009 // 01010 // Copy over the old database. Note that this might just copy our 01011 // local dummy entry for the single entry case 01012 // 01013 01014 RtlMoveMemory(NewHandleCountDataBase, OldHandleCountDataBase, OldSize); 01015 01016 // 01017 // If the previous mode was a single entry then remove that 01018 // indication otherwise free up with previous handle database 01019 // 01020 01021 if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) { 01022 01023 ObjectHeader->Flags &= ~OB_FLAG_SINGLE_HANDLE_ENTRY; 01024 01025 } else { 01026 01027 ExFreePool( OldHandleCountDataBase ); 01028 } 01029 01030 // 01031 // Find the end of the new database that is used and zero out 01032 // the memory 01033 // 01034 01035 FreeHandleCountEntry = 01036 (POBJECT_HANDLE_COUNT_ENTRY)((PCHAR)NewHandleCountDataBase + OldSize); 01037 01038 RtlZeroMemory(FreeHandleCountEntry, NewSize - OldSize); 01039 01040 // 01041 // Set the new database to the proper entry count and put it 01042 // all in the object 01043 // 01044 01045 NewHandleCountDataBase->CountEntries = CountEntries; 01046 01047 HandleInfo->HandleCountDataBase = NewHandleCountDataBase; 01048 01049 // 01050 // And return to our caller 01051 // 01052 01053 return FreeHandleCountEntry; 01054 } 01055 01056 01057 NTSTATUS 01058 ObpIncrementHandleDataBase ( 01059 IN POBJECT_HEADER ObjectHeader, 01060 IN PEPROCESS Process, 01061 OUT PULONG NewProcessHandleCount 01062 ) 01063 01064 /*++ 01065 01066 Routine Description: 01067 01068 This function increments the handle count database associated with the 01069 specified object for a specified process. 01070 01071 Arguments: 01072 01073 ObjectHeader - Supplies a pointer to the object. 01074 01075 Process - Supplies a pointer to the process whose handle count is to be 01076 updated. 01077 01078 NewProcessHandleCount - Supplies a pointer to a variable that receives 01079 the new handle count for the process. 01080 01081 Return Value: 01082 01083 An appropriate status value 01084 01085 --*/ 01086 01087 { 01088 POBJECT_HEADER_HANDLE_INFO HandleInfo; 01089 POBJECT_HANDLE_COUNT_DATABASE HandleCountDataBase; 01090 POBJECT_HANDLE_COUNT_ENTRY HandleCountEntry; 01091 POBJECT_HANDLE_COUNT_ENTRY FreeHandleCountEntry; 01092 ULONG CountEntries; 01093 ULONG ProcessHandleCount; 01094 01095 PAGED_CODE(); 01096 01097 // 01098 // Translate the object header to the handle information. 01099 // 01100 01101 HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader); 01102 01103 // 01104 // Check if the object has space for only a single handle 01105 // 01106 01107 if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) { 01108 01109 // 01110 // If the single handle isn't in use then set the entry 01111 // and tell the caller there is only one handle 01112 // 01113 01114 if (HandleInfo->SingleEntry.HandleCount == 0) { 01115 01116 *NewProcessHandleCount = 1; 01117 HandleInfo->SingleEntry.HandleCount = 1; 01118 HandleInfo->SingleEntry.Process = Process; 01119 01120 return STATUS_SUCCESS; 01121 01122 // 01123 // If the single entry is for the same process as specified 01124 // then increment the count and we're done 01125 // 01126 01127 } else if (HandleInfo->SingleEntry.Process == Process) { 01128 01129 *NewProcessHandleCount = ++HandleInfo->SingleEntry.HandleCount; 01130 01131 return STATUS_SUCCESS; 01132 01133 // 01134 // Finally we have a object with a single handle entry already 01135 // in use, so we need to grow the handle database before 01136 // we can set this new value 01137 // 01138 01139 } else { 01140 01141 FreeHandleCountEntry = ObpInsertHandleCount( ObjectHeader ); 01142 01143 if (FreeHandleCountEntry == NULL) { 01144 01145 return STATUS_INSUFFICIENT_RESOURCES; 01146 } 01147 01148 FreeHandleCountEntry->Process = Process; 01149 FreeHandleCountEntry->HandleCount = 1; 01150 *NewProcessHandleCount = 1; 01151 01152 return STATUS_SUCCESS; 01153 } 01154 } 01155 01156 // 01157 // The object does not contain a single entry, therefore we're 01158 // assuming it already has a handle count database 01159 // 01160 01161 // 01162 // **** HandleInfo should first be checked for null 01163 // 01164 01165 HandleCountDataBase = HandleInfo->HandleCountDataBase; 01166 01167 FreeHandleCountEntry = NULL; 01168 01169 // 01170 // **** can we with success if the database is null 01171 // 01172 01173 if (HandleCountDataBase != NULL) { 01174 01175 // 01176 // Get the number of entries and a pointer to the first one 01177 // in the handle database 01178 // 01179 01180 CountEntries = HandleCountDataBase->CountEntries; 01181 HandleCountEntry = &HandleCountDataBase->HandleCountEntries[ 0 ]; 01182 01183 // 01184 // For each entry in the handle database check for a process 01185 // match and if so then increment the handle count and return 01186 // to our caller. Otherwise if the entry is free then remember 01187 // it so we can store to it later 01188 // 01189 01190 while (CountEntries) { 01191 01192 if (HandleCountEntry->Process == Process) { 01193 01194 *NewProcessHandleCount = ++HandleCountEntry->HandleCount; 01195 01196 return STATUS_SUCCESS; 01197 01198 } else if (HandleCountEntry->HandleCount == 0) { 01199 01200 FreeHandleCountEntry = HandleCountEntry; 01201 } 01202 01203 ++HandleCountEntry; 01204 --CountEntries; 01205 } 01206 01207 // 01208 // If we did not find a free handle entry then we have to grow the 01209 // handle database before we can set this new value 01210 // 01211 01212 if (FreeHandleCountEntry == NULL) { 01213 01214 FreeHandleCountEntry = ObpInsertHandleCount( ObjectHeader ); 01215 01216 if (FreeHandleCountEntry == NULL) { 01217 01218 return(STATUS_INSUFFICIENT_RESOURCES); 01219 } 01220 } 01221 01222 FreeHandleCountEntry->Process = Process; 01223 FreeHandleCountEntry->HandleCount = 1; 01224 *NewProcessHandleCount = 1; 01225 } 01226 01227 return STATUS_SUCCESS; 01228 } 01229 01230 01231 NTSTATUS 01232 ObpIncrementHandleCount ( 01233 OB_OPEN_REASON OpenReason, 01234 PEPROCESS Process, 01235 PVOID Object, 01236 POBJECT_TYPE ObjectType, 01237 PACCESS_STATE AccessState OPTIONAL, 01238 KPROCESSOR_MODE AccessMode, 01239 ULONG Attributes 01240 ) 01241 01242 /*++ 01243 01244 Routine Description: 01245 01246 Increments the count of number of handles to the given object. 01247 01248 If the object is being opened or created, access validation and 01249 auditing will be performed as appropriate. 01250 01251 Arguments: 01252 01253 OpenReason - Supplies the reason the handle count is being incremented. 01254 01255 Process - Pointer to the process in which the new handle will reside. 01256 01257 Object - Supplies a pointer to the body of the object. 01258 01259 ObjectType - Supplies the type of the object. 01260 01261 AccessState - Optional parameter supplying the current accumulated 01262 security information describing the attempt to access the object. 01263 01264 AccessMode - Supplies the mode of the requestor. 01265 01266 Attributes - Desired attributes for the handle 01267 01268 Return Value: 01269 01270 An appropriate status value 01271 01272 --*/ 01273 01274 { 01275 NTSTATUS Status; 01276 ULONG ProcessHandleCount; 01277 BOOLEAN ExclusiveHandle; 01278 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 01279 POBJECT_HEADER_QUOTA_INFO QuotaInfo; 01280 POBJECT_HEADER ObjectHeader; 01281 BOOLEAN HasPrivilege = FALSE; 01282 PRIVILEGE_SET Privileges; 01283 BOOLEAN NewObject; 01284 BOOLEAN HoldObjectTypeMutex = FALSE; 01285 01286 PAGED_CODE(); 01287 01288 ObpValidateIrql( "ObpIncrementHandleCount" ); 01289 01290 // 01291 // Get a pointer to the object header 01292 // 01293 01294 ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object ); 01295 01296 // 01297 // Charge the user quota for the object 01298 // 01299 01300 Status = ObpChargeQuotaForObject( ObjectHeader, ObjectType, &NewObject ); 01301 01302 if (!NT_SUCCESS( Status )) { 01303 01304 return Status; 01305 } 01306 01307 ObpEnterObjectTypeMutex( ObjectType ); 01308 HoldObjectTypeMutex = TRUE; 01309 01310 try { 01311 01312 ExclusiveHandle = FALSE; 01313 01314 // 01315 // Check if the caller wants exlusive access and if so then 01316 // make sure the attributes and header flags match up correctly 01317 // 01318 01319 if (Attributes & OBJ_EXCLUSIVE) { 01320 01321 if ((Attributes & OBJ_INHERIT) || 01322 ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) == 0)) { 01323 01324 Status = STATUS_INVALID_PARAMETER; 01325 leave; 01326 } 01327 01328 if (((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) == NULL) && 01329 (ObjectHeader->HandleCount != 0)) 01330 01331 || 01332 01333 ((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL) && 01334 (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != PsGetCurrentProcess()))) { 01335 01336 Status = STATUS_ACCESS_DENIED; 01337 leave; 01338 } 01339 01340 ExclusiveHandle = TRUE; 01341 01342 // 01343 // The user doesn't want exclusive access so now check to make sure 01344 // the attriutes and header flags match up correctly 01345 // 01346 01347 } else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) && 01348 (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL)) { 01349 01350 Status = STATUS_ACCESS_DENIED; 01351 leave; 01352 } 01353 01354 // 01355 // If handle count going from zero to one for an existing object that 01356 // maintains a handle count database, but does not have an open procedure 01357 // just a close procedure, then fail the call as they are trying to 01358 // reopen an object by pointer and the close procedure will not know 01359 // that the object has been 'recreated' 01360 // 01361 01362 if ((ObjectHeader->HandleCount == 0) && 01363 (!NewObject) && 01364 (ObjectType->TypeInfo.MaintainHandleCount) && 01365 (ObjectType->TypeInfo.OpenProcedure == NULL) && 01366 (ObjectType->TypeInfo.CloseProcedure != NULL)) { 01367 01368 Status = STATUS_UNSUCCESSFUL; 01369 leave; 01370 } 01371 01372 if ((OpenReason == ObOpenHandle) || 01373 ((OpenReason == ObDuplicateHandle) && ARGUMENT_PRESENT(AccessState))) { 01374 01375 // 01376 // Perform Access Validation to see if we can open this 01377 // (already existing) object. 01378 // 01379 01380 if (!ObCheckObjectAccess( Object, 01381 AccessState, 01382 TRUE, 01383 AccessMode, 01384 &Status )) { 01385 01386 leave; 01387 } 01388 01389 } else if ((OpenReason == ObCreateHandle)) { 01390 01391 // 01392 // We are creating a new instance of this object type. 01393 // A total of three audit messages may be generated: 01394 // 01395 // 1 - Audit the attempt to create an instance of this 01396 // object type. 01397 // 01398 // 2 - Audit the successful creation. 01399 // 01400 // 3 - Audit the allocation of the handle. 01401 // 01402 01403 // 01404 // At this point, the RemainingDesiredAccess field in 01405 // the AccessState may still contain either Generic access 01406 // types, or MAXIMUM_ALLOWED. We will map the generics 01407 // and substitute GenericAll for MAXIMUM_ALLOWED. 01408 // 01409 01410 if ( AccessState->RemainingDesiredAccess & MAXIMUM_ALLOWED ) { 01411 01412 AccessState->RemainingDesiredAccess &= ~MAXIMUM_ALLOWED; 01413 AccessState->RemainingDesiredAccess |= GENERIC_ALL; 01414 } 01415 01416 if ((GENERIC_ACCESS & AccessState->RemainingDesiredAccess) != 0) { 01417 01418 RtlMapGenericMask( &AccessState->RemainingDesiredAccess, 01419 &ObjectType->TypeInfo.GenericMapping ); 01420 } 01421 01422 // 01423 // Since we are creating the object, we can give any access the caller 01424 // wants. The only exception is ACCESS_SYSTEM_SECURITY, which requires 01425 // a privilege. 01426 // 01427 01428 if ( AccessState->RemainingDesiredAccess & ACCESS_SYSTEM_SECURITY ) { 01429 01430 // 01431 // We could use SeSinglePrivilegeCheck here, but it 01432 // captures the subject context again, and we don't 01433 // want to do that in this path for performance reasons. 01434 // 01435 01436 Privileges.PrivilegeCount = 1; 01437 Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY; 01438 Privileges.Privilege[0].Luid = SeSecurityPrivilege; 01439 Privileges.Privilege[0].Attributes = 0; 01440 01441 HasPrivilege = SePrivilegeCheck( &Privileges, 01442 &AccessState->SubjectSecurityContext, 01443 KeGetPreviousMode() ); 01444 01445 if (!HasPrivilege) { 01446 01447 SePrivilegedServiceAuditAlarm ( NULL, 01448 &AccessState->SubjectSecurityContext, 01449 &Privileges, 01450 FALSE ); 01451 01452 Status = STATUS_PRIVILEGE_NOT_HELD; 01453 leave; 01454 } 01455 01456 AccessState->RemainingDesiredAccess &= ~ACCESS_SYSTEM_SECURITY; 01457 AccessState->PreviouslyGrantedAccess |= ACCESS_SYSTEM_SECURITY; 01458 01459 (VOID) SeAppendPrivileges( AccessState, 01460 &Privileges ); 01461 } 01462 01463 // 01464 // Get the objects creator info block and insert it on the 01465 // global list of objects for that type 01466 // 01467 01468 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader ); 01469 01470 if (CreatorInfo != NULL) { 01471 01472 InsertTailList( &ObjectType->TypeList, &CreatorInfo->TypeList ); 01473 } 01474 } 01475 01476 if (ExclusiveHandle) { 01477 01478 OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process; 01479 } 01480 01481 ObpIncrHandleCount( ObjectHeader ); 01482 ProcessHandleCount = 0; 01483 01484 // 01485 // If the object type wants us to keep try of the handle counts 01486 // then call our routine to do the work 01487 // 01488 01489 if (ObjectType->TypeInfo.MaintainHandleCount) { 01490 01491 Status = ObpIncrementHandleDataBase( ObjectHeader, 01492 Process, 01493 &ProcessHandleCount ); 01494 01495 if (!NT_SUCCESS(Status)) { 01496 // BUG BUG, We probably need more backout than this, NeillC 01497 ObpDecrHandleCount( ObjectHeader ); 01498 01499 leave; 01500 } 01501 } 01502 01503 // 01504 // Set our preliminary status now to success because 01505 // the call to the open procedure might change this 01506 // 01507 01508 Status = STATUS_SUCCESS; 01509 01510 // 01511 // If the object type has an open procedure 01512 // then invoke that procedure 01513 // 01514 01515 if (ObjectType->TypeInfo.OpenProcedure != NULL) { 01516 01517 KIRQL SaveIrql; 01518 01519 // 01520 // Leave the object type mutex when call the OpenProcedure. If an exception 01521 // while OpenProcedure the HoldObjectTypeMutex disable leaving the mutex 01522 // on finally block 01523 // 01524 01525 ObpLeaveObjectTypeMutex( ObjectType ); 01526 HoldObjectTypeMutex = FALSE; 01527 01528 ObpBeginTypeSpecificCallOut( SaveIrql ); 01529 01530 try { 01531 01532 (*ObjectType->TypeInfo.OpenProcedure)( OpenReason, 01533 Process, 01534 Object, 01535 AccessState ? 01536 AccessState->PreviouslyGrantedAccess : 01537 0, 01538 ProcessHandleCount ); 01539 01540 } except( EXCEPTION_EXECUTE_HANDLER ) { 01541 01542 Status = GetExceptionCode(); 01543 } 01544 01545 ObpEndTypeSpecificCallOut( SaveIrql, "Open", ObjectType, Object ); 01546 01547 // 01548 // Hold back the object type mutex and set the HoldObjectTypeMutex variable 01549 // to allow releasing the mutex while leaving this procedure 01550 // 01551 01552 ObpEnterObjectTypeMutex( ObjectType ); 01553 HoldObjectTypeMutex = TRUE; 01554 01555 if (!NT_SUCCESS(Status)) { 01556 01557 (VOID)ObpDecrHandleCount( ObjectHeader ); 01558 leave; 01559 } 01560 } 01561 01562 // 01563 // Do some simple bookkeeping for the handle counts 01564 // and then return to our caller 01565 // 01566 01567 ObjectType->TotalNumberOfHandles += 1; 01568 01569 if (ObjectType->TotalNumberOfHandles > ObjectType->HighWaterNumberOfHandles) { 01570 01571 ObjectType->HighWaterNumberOfHandles = ObjectType->TotalNumberOfHandles; 01572 } 01573 01574 } finally { 01575 01576 if ( HoldObjectTypeMutex ) { 01577 01578 ObpLeaveObjectTypeMutex( ObjectType ); 01579 } 01580 } 01581 01582 return( Status ); 01583 } 01584 01585 01586 NTSTATUS 01587 ObpIncrementUnnamedHandleCount ( 01588 PACCESS_MASK DesiredAccess, 01589 PEPROCESS Process, 01590 PVOID Object, 01591 POBJECT_TYPE ObjectType, 01592 KPROCESSOR_MODE AccessMode, 01593 ULONG Attributes 01594 ) 01595 01596 /*++ 01597 01598 Routine Description: 01599 01600 Increments the count of number of handles to the given object. 01601 01602 Arguments: 01603 01604 Desired Access - Supplies the desired access to the object and receives 01605 the assign access mask 01606 01607 Process - Pointer to the process in which the new handle will reside. 01608 01609 Object - Supplies a pointer to the body of the object. 01610 01611 ObjectType - Supplies the type of the object. 01612 01613 AccessMode - Supplies the mode of the requestor. 01614 01615 Attributes - Desired attributes for the handle 01616 01617 Return Value: 01618 01619 An appropriate status value 01620 01621 --*/ 01622 01623 { 01624 NTSTATUS Status; 01625 BOOLEAN ExclusiveHandle; 01626 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 01627 POBJECT_HEADER_QUOTA_INFO QuotaInfo; 01628 POBJECT_HEADER ObjectHeader; 01629 BOOLEAN NewObject; 01630 ULONG ProcessHandleCount; 01631 BOOLEAN HoldObjectTypeMutex = FALSE; 01632 01633 PAGED_CODE(); 01634 01635 ObpValidateIrql( "ObpIncrementUnnamedHandleCount" ); 01636 01637 // 01638 // Get a pointer to the object header 01639 // 01640 01641 ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object ); 01642 01643 // 01644 // Charge the user quota for the object 01645 // 01646 01647 Status = ObpChargeQuotaForObject( ObjectHeader, ObjectType, &NewObject ); 01648 01649 if (!NT_SUCCESS( Status )) { 01650 01651 return Status; 01652 } 01653 01654 ObpEnterObjectTypeMutex( ObjectType ); 01655 HoldObjectTypeMutex = TRUE; 01656 01657 try { 01658 01659 ExclusiveHandle = FALSE; 01660 01661 // 01662 // Check if the caller wants exlusive access and if so then 01663 // make sure the attributes and header flags match up correctly 01664 // 01665 01666 if (Attributes & OBJ_EXCLUSIVE) { 01667 01668 if ((Attributes & OBJ_INHERIT) || 01669 ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) == 0)) { 01670 01671 Status = STATUS_INVALID_PARAMETER; 01672 leave; 01673 } 01674 01675 if (((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) == NULL) && 01676 (ObjectHeader->HandleCount != 0)) 01677 01678 || 01679 01680 ((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL) && 01681 (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != PsGetCurrentProcess()))) { 01682 01683 Status = STATUS_ACCESS_DENIED; 01684 leave; 01685 } 01686 01687 ExclusiveHandle = TRUE; 01688 01689 // 01690 // The user doesn't want exclusive access so now check to make sure 01691 // the attriutes and header flags match up correctly 01692 // 01693 01694 } else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) && 01695 (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL)) { 01696 01697 Status = STATUS_ACCESS_DENIED; 01698 leave; 01699 } 01700 01701 // 01702 // If handle count going from zero to one for an existing object that 01703 // maintains a handle count database, but does not have an open procedure 01704 // just a close procedure, then fail the call as they are trying to 01705 // reopen an object by pointer and the close procedure will not know 01706 // that the object has been 'recreated' 01707 // 01708 01709 if ((ObjectHeader->HandleCount == 0) && 01710 (!NewObject) && 01711 (ObjectType->TypeInfo.MaintainHandleCount) && 01712 (ObjectType->TypeInfo.OpenProcedure == NULL) && 01713 (ObjectType->TypeInfo.CloseProcedure != NULL)) { 01714 01715 Status = STATUS_UNSUCCESSFUL; 01716 01717 leave; 01718 } 01719 01720 // 01721 // If the user asked for the maximum allowed then remove the bit and 01722 // or in generic all access 01723 // 01724 01725 if ( *DesiredAccess & MAXIMUM_ALLOWED ) { 01726 01727 *DesiredAccess &= ~MAXIMUM_ALLOWED; 01728 *DesiredAccess |= GENERIC_ALL; 01729 } 01730 01731 // If the user asked for any generic bit then translate it to 01732 // someone more appropriate for the object type 01733 // 01734 01735 if ((GENERIC_ACCESS & *DesiredAccess) != 0) { 01736 01737 RtlMapGenericMask( DesiredAccess, 01738 &ObjectType->TypeInfo.GenericMapping ); 01739 } 01740 01741 // 01742 // Get a pointer to the creator info block for the object and insert 01743 // it on the global list of object for that type 01744 // 01745 01746 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader ); 01747 01748 if (CreatorInfo != NULL) { 01749 01750 InsertTailList( &ObjectType->TypeList, &CreatorInfo->TypeList ); 01751 } 01752 01753 if (ExclusiveHandle) { 01754 01755 OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process; 01756 } 01757 01758 ObpIncrHandleCount( ObjectHeader ); 01759 ProcessHandleCount = 0; 01760 01761 // 01762 // If the object type wants us to keep try of the handle counts 01763 // then call our routine to do the work 01764 // 01765 01766 if (ObjectType->TypeInfo.MaintainHandleCount) { 01767 01768 Status = ObpIncrementHandleDataBase( ObjectHeader, 01769 Process, 01770 &ProcessHandleCount ); 01771 01772 if (!NT_SUCCESS(Status)) { 01773 // BUG BUG, We probably need more backout than this, NeillC 01774 ObpDecrHandleCount( ObjectHeader ); 01775 leave; 01776 } 01777 } 01778 01779 // 01780 // Set our preliminary status now to success because 01781 // the call to the open procedure might change this 01782 // 01783 01784 Status = STATUS_SUCCESS; 01785 01786 // 01787 // If the object type has an open procedure 01788 // then invoke that procedure 01789 // 01790 01791 if (ObjectType->TypeInfo.OpenProcedure != NULL) { 01792 01793 KIRQL SaveIrql; 01794 01795 // 01796 // Leave the object type mutex when call the OpenProcedure. If an exception 01797 // while OpenProcedure the HoldObjectTypeMutex disable leaving the mutex 01798 // on finally block 01799 // 01800 01801 ObpLeaveObjectTypeMutex( ObjectType ); 01802 HoldObjectTypeMutex = FALSE; 01803 01804 ObpBeginTypeSpecificCallOut( SaveIrql ); 01805 01806 try { 01807 01808 (*ObjectType->TypeInfo.OpenProcedure)( ObCreateHandle, 01809 Process, 01810 Object, 01811 *DesiredAccess, 01812 ProcessHandleCount ); 01813 01814 } except( EXCEPTION_EXECUTE_HANDLER ) { 01815 01816 Status = GetExceptionCode(); 01817 } 01818 01819 ObpEndTypeSpecificCallOut( SaveIrql, "Open", ObjectType, Object ); 01820 01821 // 01822 // Hold back the object type mutex and set the HoldObjectTypeMutex variable 01823 // to allow releasing the mutex while leaving this procedure 01824 // 01825 01826 ObpEnterObjectTypeMutex( ObjectType ); 01827 HoldObjectTypeMutex = TRUE; 01828 01829 if (!NT_SUCCESS(Status)) { 01830 01831 (VOID)ObpDecrHandleCount( ObjectHeader ); 01832 leave; 01833 } 01834 } 01835 01836 // 01837 // Do some simple bookkeeping for the handle counts 01838 // and then return to our caller 01839 // 01840 01841 ObjectType->TotalNumberOfHandles += 1; 01842 01843 if (ObjectType->TotalNumberOfHandles > ObjectType->HighWaterNumberOfHandles) { 01844 01845 ObjectType->HighWaterNumberOfHandles = ObjectType->TotalNumberOfHandles; 01846 } 01847 01848 } finally { 01849 01850 if ( HoldObjectTypeMutex ) { 01851 01852 ObpLeaveObjectTypeMutex( ObjectType ); 01853 } 01854 } 01855 01856 return( Status ); 01857 } 01858 01859 01860 NTSTATUS 01861 ObpChargeQuotaForObject ( 01862 IN POBJECT_HEADER ObjectHeader, 01863 IN POBJECT_TYPE ObjectType, 01864 OUT PBOOLEAN NewObject 01865 ) 01866 01867 /*++ 01868 01869 Routine Description: 01870 01871 This routine charges quota against the current process for the new 01872 object 01873 01874 Arguments: 01875 01876 ObjectHeader - Supplies a pointer to the new object being charged for 01877 01878 ObjectType - Supplies the type of the new object 01879 01880 NewObject - Returns true if the object is really new and false otherwise 01881 01882 Return Value: 01883 01884 An appropriate status value 01885 01886 --*/ 01887 01888 { 01889 POBJECT_HEADER_QUOTA_INFO QuotaInfo; 01890 ULONG NonPagedPoolCharge; 01891 ULONG PagedPoolCharge; 01892 01893 // 01894 // Get a pointer to the quota block for this object 01895 // 01896 01897 QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader ); 01898 01899 *NewObject = FALSE; 01900 01901 // 01902 // If the object is new then we have work to do otherwise 01903 // we'll return with NewObject set to false 01904 // 01905 01906 if (ObjectHeader->Flags & OB_FLAG_NEW_OBJECT) { 01907 01908 // 01909 // Say the object now isn't new 01910 // 01911 01912 ObjectHeader->Flags &= ~OB_FLAG_NEW_OBJECT; 01913 01914 // 01915 // If there does exist a quota info structure for this 01916 // object then calculate what our charge should be from 01917 // the information stored in that structure 01918 // 01919 01920 if (QuotaInfo != NULL) { 01921 01922 PagedPoolCharge = QuotaInfo->PagedPoolCharge + 01923 QuotaInfo->SecurityDescriptorCharge; 01924 NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge; 01925 01926 } else { 01927 01928 // 01929 // There isn't any quota information so we're on our own 01930 // Paged pool charge is the default for the object plus 01931 // the security descriptor if present. Nonpaged pool charge 01932 // is the default for the object. 01933 // 01934 01935 PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge; 01936 01937 if (ObjectHeader->SecurityDescriptor != NULL) { 01938 01939 ObjectHeader->Flags |= OB_FLAG_DEFAULT_SECURITY_QUOTA; 01940 PagedPoolCharge += SE_DEFAULT_SECURITY_QUOTA; 01941 } 01942 01943 NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge; 01944 } 01945 01946 // 01947 // Now charge for the quota and make sure it succeeds 01948 // 01949 01950 ObjectHeader->QuotaBlockCharged = (PVOID)PsChargeSharedPoolQuota( PsGetCurrentProcess(), 01951 PagedPoolCharge, 01952 NonPagedPoolCharge ); 01953 01954 if (ObjectHeader->QuotaBlockCharged == NULL) { 01955 01956 return STATUS_QUOTA_EXCEEDED; 01957 } 01958 01959 *NewObject = TRUE; 01960 } 01961 01962 return STATUS_SUCCESS; 01963 } 01964 01965 01966 VOID 01967 ObpDecrementHandleCount ( 01968 PEPROCESS Process, 01969 POBJECT_HEADER ObjectHeader, 01970 POBJECT_TYPE ObjectType, 01971 ACCESS_MASK GrantedAccess 01972 ) 01973 01974 /*++ 01975 01976 Routine Description: 01977 01978 This procedure decrements the handle count for the specified object 01979 01980 Arguments: 01981 01982 Process - Supplies the process where the handle existed 01983 01984 ObjectHeader - Supplies a pointer to the object header for the object 01985 01986 ObjectType - Supplies a type of the object 01987 01988 GrantedAccess - Supplies the current access mask to the object 01989 01990 Return Value: 01991 01992 None. 01993 01994 --*/ 01995 01996 { 01997 POBJECT_HEADER_HANDLE_INFO HandleInfo; 01998 POBJECT_HANDLE_COUNT_DATABASE HandleCountDataBase; 01999 POBJECT_HANDLE_COUNT_ENTRY HandleCountEntry; 02000 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 02001 PVOID Object; 02002 ULONG CountEntries; 02003 ULONG ProcessHandleCount; 02004 ULONG SystemHandleCount; 02005 BOOLEAN HandleCountIsZero; 02006 02007 PAGED_CODE(); 02008 02009 ObpEnterObjectTypeMutex( ObjectType ); 02010 02011 Object = (PVOID)&ObjectHeader->Body; 02012 02013 SystemHandleCount = ObjectHeader->HandleCount; 02014 ProcessHandleCount = 0; 02015 02016 // 02017 // Decrement the handle count and it was one and it 02018 // was an exclusive object then zero out the exclusive 02019 // process 02020 // 02021 02022 HandleCountIsZero = ObpDecrHandleCount( ObjectHeader ); 02023 02024 if ( HandleCountIsZero && 02025 (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT)) { 02026 02027 OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader )->ExclusiveProcess = NULL; 02028 } 02029 02030 if ( HandleCountIsZero ) { 02031 02032 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader ); 02033 02034 // 02035 // If there is a creator info record and we are on the list 02036 // for the object type then remove this object from the list 02037 // 02038 02039 if (CreatorInfo != NULL && !IsListEmpty( &CreatorInfo->TypeList )) { 02040 02041 RemoveEntryList( &CreatorInfo->TypeList ); 02042 02043 InitializeListHead( &CreatorInfo->TypeList ); 02044 } 02045 } 02046 02047 // 02048 // If the object maintains a handle count database then 02049 // search through the handle database and decrement 02050 // the necessary information 02051 // 02052 02053 if (ObjectType->TypeInfo.MaintainHandleCount) { 02054 02055 HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO( ObjectHeader ); 02056 02057 // 02058 // Check if there is a single handle entry, then it better 02059 // be ours 02060 // 02061 02062 if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) { 02063 02064 ASSERT(HandleInfo->SingleEntry.Process == Process); 02065 ASSERT(HandleInfo->SingleEntry.HandleCount > 0); 02066 02067 ProcessHandleCount = HandleInfo->SingleEntry.HandleCount--; 02068 HandleCountEntry = &HandleInfo->SingleEntry; 02069 02070 } else { 02071 02072 // 02073 // Otherwise search the database for a process match 02074 // 02075 02076 HandleCountDataBase = HandleInfo->HandleCountDataBase; 02077 02078 if (HandleCountDataBase != NULL) { 02079 02080 CountEntries = HandleCountDataBase->CountEntries; 02081 HandleCountEntry = &HandleCountDataBase->HandleCountEntries[ 0 ]; 02082 02083 while (CountEntries) { 02084 02085 if ((HandleCountEntry->HandleCount != 0) && 02086 (HandleCountEntry->Process == Process)) { 02087 02088 ProcessHandleCount = HandleCountEntry->HandleCount--; 02089 02090 break; 02091 } 02092 02093 HandleCountEntry++; 02094 CountEntries--; 02095 } 02096 } 02097 } 02098 02099 // 02100 // Now if the process is giving up all handles to the object 02101 // then zero out the handle count entry. For a single handle 02102 // entry this is just the single entry in the header handle info 02103 // structure 02104 // 02105 02106 if (ProcessHandleCount == 1) { 02107 02108 HandleCountEntry->Process = NULL; 02109 HandleCountEntry->HandleCount = 0; 02110 } 02111 } 02112 02113 // 02114 // If the Object Type has a Close Procedure, then release the type 02115 // mutex before calling it, and then call ObpDeleteNameCheck without 02116 // the mutex held. 02117 // 02118 02119 if (ObjectType->TypeInfo.CloseProcedure) { 02120 02121 KIRQL SaveIrql; 02122 02123 ObpLeaveObjectTypeMutex( ObjectType ); 02124 02125 ObpBeginTypeSpecificCallOut( SaveIrql ); 02126 02127 (*ObjectType->TypeInfo.CloseProcedure)( Process, 02128 Object, 02129 GrantedAccess, 02130 ProcessHandleCount, 02131 SystemHandleCount ); 02132 02133 ObpEndTypeSpecificCallOut( SaveIrql, "Close", ObjectType, Object ); 02134 02135 ObpDeleteNameCheck( Object, FALSE ); 02136 02137 } else { 02138 02139 // 02140 // If there is no Close Procedure, then just call ObpDeleteNameCheck 02141 // with the mutex held. 02142 // 02143 // The following call will release the type mutex 02144 // 02145 02146 ObpDeleteNameCheck( Object, TRUE ); 02147 } 02148 02149 ObpEnterObjectTypeMutex( ObjectType ); 02150 02151 ObjectType->TotalNumberOfHandles -= 1; 02152 02153 ObpLeaveObjectTypeMutex( ObjectType ); 02154 02155 return; 02156 } 02157 02158 02159 NTSTATUS 02160 ObpCreateHandle ( 02161 IN OB_OPEN_REASON OpenReason, 02162 IN PVOID Object, 02163 IN POBJECT_TYPE ExpectedObjectType OPTIONAL, 02164 IN PACCESS_STATE AccessState, 02165 IN ULONG ObjectPointerBias OPTIONAL, 02166 IN ULONG Attributes, 02167 IN BOOLEAN DirectoryLocked, 02168 IN KPROCESSOR_MODE AccessMode, 02169 OUT PVOID *ReferencedNewObject OPTIONAL, 02170 OUT PHANDLE Handle 02171 ) 02172 02173 /*++ 02174 02175 Routine Description: 02176 02177 This function creates a new handle to an existing object 02178 02179 Arguments: 02180 02181 OpenReason - The reason why we are doing this work 02182 02183 Object - A pointer to the body of the new object 02184 02185 ExpectedObjectType - Optionally Supplies the object type that 02186 the caller is expecting 02187 02188 AccessState - Supplies the access state for the handle requested 02189 by the caller 02190 02191 ObjectPointerBias - Optionally supplies a count of addition 02192 increments we do to the pointer count for the object 02193 02194 Attributes - Desired attributes for the handle 02195 02196 DirectoryLocked - Indicates if the root directory mutex is already held 02197 02198 AccessMode - Supplies the mode of the requestor. 02199 02200 ReferencedNewObject - Optionally receives a pointer to the body 02201 of the new object 02202 02203 Handle - Receives the new handle value 02204 02205 Return Value: 02206 02207 An appropriate status value 02208 02209 --*/ 02210 02211 { 02212 NTSTATUS Status; 02213 POBJECT_HEADER ObjectHeader; 02214 POBJECT_TYPE ObjectType; 02215 PVOID ObjectTable; 02216 HANDLE_TABLE_ENTRY ObjectTableEntry; 02217 HANDLE NewHandle; 02218 ACCESS_MASK DesiredAccess; 02219 ACCESS_MASK GrantedAccess; 02220 ULONG BiasCount; 02221 BOOLEAN AttachedToProcess = FALSE; 02222 BOOLEAN KernelHandle = FALSE; 02223 KAPC_STATE ApcState; 02224 02225 PAGED_CODE(); 02226 02227 ObpValidateIrql( "ObpCreateHandle" ); 02228 02229 // 02230 // Merge both the remaining desired access and the currently 02231 // granted access states into one mask 02232 // 02233 // **** why is this being done here and then later in the this 02234 // same routine. 02235 // 02236 02237 DesiredAccess = AccessState->RemainingDesiredAccess | 02238 AccessState->PreviouslyGrantedAccess; 02239 02240 // 02241 // Get a pointer to the object header and object type 02242 // 02243 02244 ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object ); 02245 ObjectType = ObjectHeader->Type; 02246 02247 // 02248 // If the object type isn't what was expected then 02249 // return an error to our caller, but first see if 02250 // we should release the directory mutex 02251 // 02252 02253 if ((ARGUMENT_PRESENT( ExpectedObjectType )) && 02254 (ObjectType != ExpectedObjectType )) { 02255 02256 if (DirectoryLocked) { 02257 02258 ObpLeaveRootDirectoryMutex(); 02259 } 02260 02261 return( STATUS_OBJECT_TYPE_MISMATCH ); 02262 } 02263 02264 // 02265 // Set the first ulong of the object table entry to point 02266 // back to the object header 02267 // 02268 02269 ObjectTableEntry.Object = ObjectHeader; 02270 02271 // 02272 // Now get a pointer to the object table for either the current process 02273 // of the kernel handle table 02274 // 02275 02276 if ((Attributes & OBJ_KERNEL_HANDLE) && (AccessMode == KernelMode)) { 02277 02278 ObjectTable = ObpKernelHandleTable; 02279 KernelHandle = TRUE; 02280 02281 // 02282 // Go to the system process if we have to 02283 // 02284 02285 if (PsGetCurrentProcess() != PsInitialSystemProcess) { 02286 KeStackAttachProcess (&PsInitialSystemProcess->Pcb, &ApcState); 02287 AttachedToProcess = TRUE; 02288 } 02289 02290 02291 } else { 02292 02293 ObjectTable = ObpGetObjectTable(); 02294 } 02295 02296 // 02297 // ObpIncrementHandleCount will perform access checking on the 02298 // object being opened as appropriate. 02299 // 02300 02301 Status = ObpIncrementHandleCount( OpenReason, 02302 PsGetCurrentProcess(), 02303 Object, 02304 ObjectType, 02305 AccessState, 02306 AccessMode, 02307 Attributes ); 02308 02309 if (AccessState->GenerateOnClose) { 02310 02311 Attributes |= OBJ_AUDIT_OBJECT_CLOSE; 02312 } 02313 02314 // 02315 // Or in some low order bits into the first ulong of the object 02316 // table entry 02317 // 02318 02319 ObjectTableEntry.ObAttributes |= (Attributes & OBJ_HANDLE_ATTRIBUTES); 02320 02321 // 02322 // Merge both the remaining desired access and the currently 02323 // granted access states into one mask and then compute 02324 // the granted access 02325 // 02326 02327 DesiredAccess = AccessState->RemainingDesiredAccess | 02328 AccessState->PreviouslyGrantedAccess; 02329 02330 GrantedAccess = DesiredAccess & 02331 (ObjectType->TypeInfo.ValidAccessMask | ACCESS_SYSTEM_SECURITY ); 02332 02333 // 02334 // Unlock the directory if it is locked and make sure 02335 // we've been successful so far 02336 // 02337 02338 if (DirectoryLocked) { 02339 02340 ObpLeaveRootDirectoryMutex(); 02341 } 02342 02343 if (!NT_SUCCESS( Status )) { 02344 02345 // 02346 // If we are attached to the system process then return 02347 // back to our caller 02348 // 02349 02350 if (AttachedToProcess) { 02351 KeUnstackDetachProcess(&ApcState); 02352 AttachedToProcess = FALSE; 02353 } 02354 02355 return( Status ); 02356 } 02357 02358 // 02359 // Bias the pointer count if that is what the caller wanted 02360 // 02361 02362 if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) { 02363 02364 BiasCount = ObjectPointerBias; 02365 02366 while (BiasCount--) { 02367 02368 ObpIncrPointerCount( ObjectHeader ); 02369 } 02370 } 02371 02372 // 02373 // Set the granted access mask in the object table entry (second ulong) 02374 // 02375 02376 #if i386 && !FPO 02377 02378 if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) { 02379 02380 ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( GrantedAccess ); 02381 ObjectTableEntry.CreatorBackTraceIndex = RtlLogStackBackTrace(); 02382 02383 } else { 02384 02385 ObjectTableEntry.GrantedAccess = GrantedAccess; 02386 } 02387 02388 #else 02389 02390 ObjectTableEntry.GrantedAccess = GrantedAccess; 02391 02392 #endif // i386 && !FPO 02393 02394 // 02395 // Add this new object table entry to the object table for the process 02396 // 02397 02398 NewHandle = ExCreateHandle( ObjectTable, &ObjectTableEntry ); 02399 02400 // 02401 // If we didn't get a handle then cleanup after ourselves and return 02402 // the error to our caller 02403 // 02404 02405 if (NewHandle == NULL) { 02406 02407 if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) { 02408 02409 BiasCount = ObjectPointerBias; 02410 02411 while (BiasCount--) { 02412 02413 ObpDecrPointerCount( ObjectHeader ); 02414 } 02415 } 02416 02417 ObpDecrementHandleCount( PsGetCurrentProcess(), 02418 ObjectHeader, 02419 ObjectType, 02420 GrantedAccess ); 02421 02422 // 02423 // If we are attached to the system process then return 02424 // back to our caller 02425 // 02426 02427 if (AttachedToProcess) { 02428 KeUnstackDetachProcess(&ApcState); 02429 AttachedToProcess = FALSE; 02430 } 02431 02432 return( STATUS_INSUFFICIENT_RESOURCES ); 02433 } 02434 02435 // 02436 // We have a new Ex style handle now make it an ob style handle and also 02437 // adjust for the kernel handle by setting the sign bit in the handle 02438 // value 02439 // 02440 02441 if (KernelHandle) { 02442 02443 NewHandle = EncodeKernelHandle( NewHandle ); 02444 } 02445 02446 *Handle = NewHandle; 02447 02448 // 02449 // If requested, generate audit messages to indicate that a new handle 02450 // has been allocated. 02451 // 02452 // This is the final security operation in the creation/opening of the 02453 // object. 02454 // 02455 02456 if ( AccessState->GenerateAudit ) { 02457 02458 SeAuditHandleCreation( AccessState, 02459 *Handle ); 02460 } 02461 02462 if (OpenReason == ObCreateHandle) { 02463 02464 PAUX_ACCESS_DATA AuxData = AccessState->AuxData; 02465 02466 if ( ( AuxData->PrivilegesUsed != NULL) && (AuxData->PrivilegesUsed->PrivilegeCount > 0) ) { 02467 02468 SePrivilegeObjectAuditAlarm( *Handle, 02469 &AccessState->SubjectSecurityContext, 02470 GrantedAccess, 02471 AuxData->PrivilegesUsed, 02472 TRUE, 02473 KeGetPreviousMode() ); 02474 } 02475 } 02476 02477 // 02478 // If the caller had a pointer bias and wanted the new reference object 02479 // then return that value 02480 // 02481 02482 if ((ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) && 02483 (ARGUMENT_PRESENT( ReferencedNewObject ))) { 02484 02485 *ReferencedNewObject = Object; 02486 } 02487 02488 // 02489 // If we are attached to the system process then return 02490 // back to our caller 02491 // 02492 02493 if (AttachedToProcess) { 02494 KeUnstackDetachProcess(&ApcState); 02495 AttachedToProcess = FALSE; 02496 } 02497 02498 // 02499 // And return to our caller 02500 // 02501 02502 return( STATUS_SUCCESS ); 02503 } 02504 02505 02506 NTSTATUS 02507 ObpCreateUnnamedHandle ( 02508 IN PVOID Object, 02509 IN ACCESS_MASK DesiredAccess, 02510 IN ULONG ObjectPointerBias OPTIONAL, 02511 IN ULONG Attributes, 02512 IN KPROCESSOR_MODE AccessMode, 02513 OUT PVOID *ReferencedNewObject OPTIONAL, 02514 OUT PHANDLE Handle 02515 ) 02516 02517 /*++ 02518 02519 Routine Description: 02520 02521 This function creates a new unnamed handle for an existing object 02522 02523 Arguments: 02524 02525 Object - A pointer to the body of the new object 02526 02527 DesiredAccess - Supplies the access mask being requsted 02528 02529 ObjectPointerBias - Optionally supplies a count of addition 02530 increments we do to the pointer count for the object 02531 02532 Attributes - Desired attributes for the handle 02533 02534 AccessMode - Supplies the mode of the requestor. 02535 02536 ReferencedNewObject - Optionally receives a pointer to the body 02537 of the new object 02538 02539 Handle - Receives the new handle value 02540 02541 Return Value: 02542 02543 An appropriate status value 02544 02545 --*/ 02546 02547 { 02548 NTSTATUS Status; 02549 POBJECT_HEADER ObjectHeader; 02550 POBJECT_TYPE ObjectType; 02551 PVOID ObjectTable; 02552 HANDLE_TABLE_ENTRY ObjectTableEntry; 02553 HANDLE NewHandle; 02554 ULONG BiasCount; 02555 ACCESS_MASK GrantedAccess; 02556 BOOLEAN AttachedToProcess = FALSE; 02557 BOOLEAN KernelHandle = FALSE; 02558 KAPC_STATE ApcState; 02559 02560 PAGED_CODE(); 02561 02562 ObpValidateIrql( "ObpCreateUnnamedHandle" ); 02563 02564 // 02565 // Get the object header and type for the new object 02566 // 02567 02568 ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object ); 02569 ObjectType = ObjectHeader->Type; 02570 02571 // 02572 // Set the first ulong of the object table entry to point 02573 // to the object header and then or in the low order attribute 02574 // bits 02575 // 02576 02577 ObjectTableEntry.Object = ObjectHeader; 02578 02579 ObjectTableEntry.ObAttributes |= (Attributes & OBJ_HANDLE_ATTRIBUTES); 02580 02581 // 02582 // Now get a pointer to the object table for either the current process 02583 // of the kernel handle table 02584 // 02585 02586 if ((Attributes & OBJ_KERNEL_HANDLE) && (AccessMode == KernelMode)) { 02587 02588 ObjectTable = ObpKernelHandleTable; 02589 KernelHandle = TRUE; 02590 02591 // 02592 // Go to the system process if we have to 02593 // 02594 02595 if (PsGetCurrentProcess() != PsInitialSystemProcess) { 02596 KeStackAttachProcess (&PsInitialSystemProcess->Pcb, &ApcState); 02597 AttachedToProcess = TRUE; 02598 } 02599 02600 } else { 02601 02602 ObjectTable = ObpGetObjectTable(); 02603 } 02604 02605 // 02606 // Increment the handle count, this routine also does the access 02607 // check if necessary 02608 // 02609 02610 Status = ObpIncrementUnnamedHandleCount( &DesiredAccess, 02611 PsGetCurrentProcess(), 02612 Object, 02613 ObjectType, 02614 AccessMode, 02615 Attributes ); 02616 02617 02618 GrantedAccess = DesiredAccess & 02619 (ObjectType->TypeInfo.ValidAccessMask | ACCESS_SYSTEM_SECURITY ); 02620 02621 if (!NT_SUCCESS( Status )) { 02622 02623 // 02624 // If we are attached to the system process then return 02625 // back to our caller 02626 // 02627 02628 if (AttachedToProcess) { 02629 KeUnstackDetachProcess(&ApcState); 02630 AttachedToProcess = FALSE; 02631 } 02632 02633 return( Status ); 02634 } 02635 02636 // 02637 // Bias the pointer count if that is what the caller wanted 02638 // 02639 02640 if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) { 02641 02642 BiasCount = ObjectPointerBias; 02643 02644 while (BiasCount--) { 02645 02646 ObpIncrPointerCount( ObjectHeader ); 02647 } 02648 } 02649 02650 // 02651 // Set the granted access mask in the object table entry (second ulong) 02652 // 02653 02654 #if i386 && !FPO 02655 02656 if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) { 02657 02658 ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( GrantedAccess ); 02659 ObjectTableEntry.CreatorBackTraceIndex = RtlLogStackBackTrace(); 02660 02661 } else { 02662 02663 ObjectTableEntry.GrantedAccess = GrantedAccess; 02664 } 02665 02666 #else 02667 02668 ObjectTableEntry.GrantedAccess = GrantedAccess; 02669 02670 #endif // i386 && !FPO 02671 02672 // 02673 // Add this new object table entry to the object table for the process 02674 // 02675 02676 NewHandle = ExCreateHandle( ObjectTable, &ObjectTableEntry ); 02677 02678 // 02679 // If we didn't get a handle then cleanup after ourselves and return 02680 // the error to our caller 02681 // 02682 02683 if (NewHandle == NULL) { 02684 02685 if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) { 02686 02687 BiasCount = ObjectPointerBias; 02688 02689 while (BiasCount--) { 02690 02691 ObpDecrPointerCount( ObjectHeader ); 02692 } 02693 } 02694 02695 ObpDecrementHandleCount( PsGetCurrentProcess(), 02696 ObjectHeader, 02697 ObjectType, 02698 GrantedAccess ); 02699 02700 // 02701 // If we are attached to the system process then return 02702 // back to our caller 02703 // 02704 02705 if (AttachedToProcess) { 02706 KeUnstackDetachProcess(&ApcState); 02707 AttachedToProcess = FALSE; 02708 } 02709 02710 return( STATUS_INSUFFICIENT_RESOURCES ); 02711 } 02712 02713 // 02714 // We have a new Ex style handle now make it an ob style handle and also 02715 // adjust for the kernel handle by setting the sign bit in the handle 02716 // value 02717 // 02718 02719 if (KernelHandle) { 02720 02721 NewHandle = EncodeKernelHandle( NewHandle ); 02722 } 02723 02724 *Handle = NewHandle; 02725 02726 // 02727 // If the caller had a pointer bias and wanted the new reference object 02728 // then return that value 02729 // 02730 02731 if ((ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) && 02732 (ARGUMENT_PRESENT( ReferencedNewObject ))) { 02733 02734 *ReferencedNewObject = Object; 02735 } 02736 02737 // 02738 // If we are attached to the system process then return 02739 // back to our caller 02740 // 02741 02742 if (AttachedToProcess) { 02743 KeUnstackDetachProcess(&ApcState); 02744 AttachedToProcess = FALSE; 02745 } 02746 02747 return( STATUS_SUCCESS ); 02748 } 02749 02750 02751 NTSTATUS 02752 ObpValidateDesiredAccess ( 02753 IN ACCESS_MASK DesiredAccess 02754 ) 02755 02756 /*++ 02757 02758 Routine Description: 02759 02760 This routine checks the input desired access mask to see that 02761 some invalid bits are not set. The invalid bits are the top 02762 two reserved bits and the top three standard rights bits. 02763 See \nt\public\sdk\inc\ntseapi.h for more details. 02764 02765 Arguments: 02766 02767 DesiredAccess - Supplies the mask being checked 02768 02769 Return Value: 02770 02771 STATUS_ACCESS_DENIED if one or more of the wrongs bits are set and 02772 STATUS_SUCCESS otherwise 02773 02774 --*/ 02775 02776 { 02777 if (DesiredAccess & 0x0CE00000) { 02778 02779 return( STATUS_ACCESS_DENIED ); 02780 02781 } else { 02782 02783 return( STATUS_SUCCESS ); 02784 } 02785 } 02786 02787 02788 #if i386 && !FPO 02789 02790 // 02791 // The following three variables are just performance counters 02792 // for the following two routines 02793 // 02794 02795 ULONG ObpXXX1; 02796 ULONG ObpXXX2; 02797 ULONG ObpXXX3; 02798 02799 USHORT 02800 ObpComputeGrantedAccessIndex ( 02801 ACCESS_MASK GrantedAccess 02802 ) 02803 02804 /*++ 02805 02806 Routine Description: 02807 02808 This routine takes a granted access and returns and index 02809 back to our cache of granted access masks. 02810 02811 Arguments: 02812 02813 GrantedAccess - Supplies the access mask being added to the cache 02814 02815 Return Value: 02816 02817 USHORT - returns an index in the cache for the input granted access 02818 02819 --*/ 02820 02821 { 02822 KIRQL OldIrql; 02823 ULONG GrantedAccessIndex, n; 02824 PACCESS_MASK p; 02825 02826 ObpXXX1 += 1; 02827 02828 // 02829 // Lock the global data structure 02830 // 02831 02832 ExAcquireFastLock( &ObpLock, &OldIrql ); 02833 02834 n = ObpCurCachedGrantedAccessIndex; 02835 p = ObpCachedGrantedAccesses; 02836 02837 // 02838 // For each index in our cache look for a match and if found 02839 // then unlock the data structure and return that index 02840 // 02841 02842 for (GrantedAccessIndex = 0; GrantedAccessIndex < n; GrantedAccessIndex++, p++ ) { 02843 02844 ObpXXX2 += 1; 02845 02846 if (*p == GrantedAccess) { 02847 02848 ExReleaseFastLock( &ObpLock, OldIrql ); 02849 return (USHORT)GrantedAccessIndex; 02850 } 02851 } 02852 02853 // 02854 // We didn't find a match now see if we've maxed out the cache 02855 // 02856 02857 if (ObpCurCachedGrantedAccessIndex == ObpMaxCachedGrantedAccessIndex) { 02858 02859 DbgPrint( "OB: GrantedAccess cache limit hit.\n" ); 02860 DbgBreakPoint(); 02861 } 02862 02863 // 02864 // Set the granted access to the next free slot and increment the 02865 // number used in the cache, release the lock, and return the 02866 // new index to our caller 02867 // 02868 02869 *p = GrantedAccess; 02870 ObpCurCachedGrantedAccessIndex += 1; 02871 02872 ExReleaseFastLock( &ObpLock, OldIrql ); 02873 02874 return (USHORT)GrantedAccessIndex; 02875 } 02876 02877 ACCESS_MASK 02878 ObpTranslateGrantedAccessIndex ( 02879 USHORT GrantedAccessIndex 02880 ) 02881 02882 /*++ 02883 02884 Routine Description: 02885 02886 This routine takes as input a cache index and returns 02887 the corresponding granted access mask 02888 02889 Arguments: 02890 02891 GrantedAccessIndex - Supplies the cache index to look up 02892 02893 Return Value: 02894 02895 ACCESS_MASK - Returns the corresponding desired access mask 02896 02897 --*/ 02898 02899 { 02900 KIRQL OldIrql; 02901 ACCESS_MASK GrantedAccess = (ACCESS_MASK)0; 02902 02903 ObpXXX3 += 1; 02904 02905 // 02906 // Lock the global data structure 02907 // 02908 02909 ExAcquireFastLock( &ObpLock, &OldIrql ); 02910 02911 // 02912 // If the input index is within bounds then get the granted 02913 // access 02914 // 02915 02916 if (GrantedAccessIndex < ObpCurCachedGrantedAccessIndex) { 02917 02918 GrantedAccess = ObpCachedGrantedAccesses[ GrantedAccessIndex ]; 02919 } 02920 02921 // 02922 // Release the lock and return the granted access to our caller 02923 // 02924 02925 ExReleaseFastLock( &ObpLock, OldIrql ); 02926 02927 return GrantedAccess; 02928 } 02929 02930 #endif // i386 && !FPO 02931

Generated on Sat May 15 19:41:05 2004 for test by doxygen 1.3.7