test: obclose.c Source File

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

# obclose.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     obclose.c
    00008
    00009 Abstract:
    00010
    00011     Object close system service
    00012
    00013 Author:
    00014
    00015     Steve Wood (stevewo) 31-Mar-1989
    00016
    00017 Revision History:
    00018
    00019 --*/
    00020
    00021 #include "obp.h"
    00022
    00023 #ifdef ALLOC_PRAGMA
    00024 #pragma alloc_text(PAGE,NtMakeTemporaryObject)
    00025 #pragma alloc_text(PAGE,ObMakeTemporaryObject)
    00026 #endif
    00027
    00028 //
    00029 //  Indicates if auditing is enabled so we have to close down the object
    00030 //  audit alarm
    00031 //
    00032
    00033 extern BOOLEAN SepAdtAuditingEnabled;
    00034
    00035
    00036 NTSTATUS
    00037 NtClose (
    00038     IN HANDLE Handle
    00039     )
    00040
    00041 /*++
    00042
    00043 Routine Description:
    00044
    00045     This function is used to close access to the specified handle
    00046
    00047 Arguments:
    00048
    00049     Handle - Supplies the handle being closed
    00050
    00051 Return Value:
    00052
    00053     An appropriate status value
    00054
    00055 --*/
    00056
    00057 {
    00058     PHANDLE_TABLE ObjectTable;
    00059     PHANDLE_TABLE_ENTRY ObjectTableEntry;
    00060     PVOID Object;
    00061     ULONG CapturedGrantedAccess;
    00062     ULONG CapturedAttributes;
    00063     POBJECT_HEADER ObjectHeader;
    00064     POBJECT_TYPE ObjectType;
    00065     NTSTATUS Status;
    00066     BOOLEAN AttachedToProcess = FALSE;
    00067     KAPC_STATE ApcState;
    00068
    00069     //
    00070     //  Protect ourselves from being interrupted while we hold a handle table
    00071     //  entry lock
    00072     //
    00073
    00074     KeEnterCriticalRegion();
    00075
    00076     try {
    00077
    00078     #if DBG
    00079         KIRQL SaveIrql;
    00080     #endif // DBG
    00081
    00082         ObpValidateIrql( "NtClose" );
    00083
    00084         ObpBeginTypeSpecificCallOut( SaveIrql );
    00085
    00086     #if DBG
    00087
    00088         //
    00089         //  On checked builds, check that if the Kernel handle bit is set, then
    00090         //  we're coming from Kernel mode. We should probably fail the call if
    00091         //  bit set && !Kmode
    00092         //
    00093
    00094         if ((Handle != NtCurrentThread()) && (Handle != NtCurrentProcess())) {
    00095
    00096             ASSERT((Handle < 0 ) ? (KeGetPreviousMode() == KernelMode) : TRUE);
    00097         }
    00098
    00099     #endif
    00100         //
    00101         //  For the current process we will grab its handle/object table and
    00102         //  translate the handle to its corresponding table entry.  If the
    00103         //  call is successful it also lock down the handle table.  But first
    00104         //  check for a kernel handle and attach and use that table if so.
    00105         //
    00106
    00107         if (IsKernelHandle( Handle, KeGetPreviousMode() ))  {
    00108
    00109             Handle = DecodeKernelHandle( Handle );
    00110
    00111             ObjectTable = ObpKernelHandleTable;
    00112
    00113             //
    00114             //  Go to the system process if we have to
    00115             //
    00116             if (PsGetCurrentProcess() != PsInitialSystemProcess) {
    00117                KeStackAttachProcess (&PsInitialSystemProcess->Pcb, &ApcState);
    00118                AttachedToProcess = TRUE;
    00119             }
    00120
    00121         } else {
    00122
    00123             ObjectTable = ObpGetObjectTable();
    00124         }
    00125
    00126         ObjectTableEntry = ExMapHandleToPointer( ObjectTable,
    00127                                                  Handle );
    00128
    00129         //
    00130         //  Check that the specified handle is legitimate otherwise we can
    00131         //  assume the caller just passed in some bogus handle value
    00132         //
    00133
    00134         if (ObjectTableEntry != NULL) {
    00135
    00136             //
    00137             //  From the object table entry we can grab a pointer to the object
    00138             //  header, get its type and its body
    00139             //
    00140
    00141             ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(ObjectTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);
    00142             ObjectType = ObjectHeader->Type;
    00143             Object = &ObjectHeader->Body;
    00144
    00145             //
    00146             //  If the object type specifies an okay to close procedure then we
    00147             //  need to invoke that callback.  If the callback doesn't want us to
    00148             //  close handle then unlock the object table and return the error
    00149             //  to our caller
    00150             //
    00151
    00152             if (ObjectType->TypeInfo.OkayToCloseProcedure != NULL) {
    00153
    00154                 if (!(*ObjectType->TypeInfo.OkayToCloseProcedure)( PsGetCurrentProcess(), Object, Handle )) {
    00155
    00156                     ObpEndTypeSpecificCallOut( SaveIrql, "NtClose", ObjectType, Object );
    00157
    00158                     ExUnlockHandleTableEntry( ObjectTable, ObjectTableEntry );
    00159
    00160                     //
    00161                     //  If we are attached to the system process then return
    00162                     //  back to our caller
    00163                     //
    00164
    00165                     if (AttachedToProcess) {
    00166
    00167                         KeUnstackDetachProcess(&ApcState);
    00168                         AttachedToProcess = FALSE;
    00169                     }
    00170
    00171                     Status = STATUS_HANDLE_NOT_CLOSABLE;
    00172                     leave;
    00173                 }
    00174             }
    00175
    00176             CapturedAttributes = ObjectTableEntry->ObAttributes;
    00177
    00178             //
    00179             //  If the previous mode was user and the handle is protected from
    00180             //  being closed, then we'll either raise or return an error depending
    00181             //  on the global flags and debugger port situation.
    00182             //
    00183
    00184             if ((CapturedAttributes & OBJ_PROTECT_CLOSE) != 0) {
    00185
    00186                 if (KeGetPreviousMode() != KernelMode) {
    00187
    00188                     ExUnlockHandleTableEntry( ObjectTable, ObjectTableEntry );
    00189
    00190                     if ((NtGlobalFlag & FLG_ENABLE_CLOSE_EXCEPTIONS) ||
    00191                         (PsGetCurrentProcess()->DebugPort != NULL)) {
    00192
    00193                         //
    00194                         //  If we are attached to the system process then return
    00195                         //  back to our caller
    00196                         //
    00197
    00198                         if (AttachedToProcess) {
    00199                             KeUnstackDetachProcess(&ApcState);
    00200                             AttachedToProcess = FALSE;
    00201                         }
    00202
    00203                         Status = KeRaiseUserException(STATUS_HANDLE_NOT_CLOSABLE);
    00204                         leave;
    00205
    00206                     } else {
    00207
    00208                         //
    00209                         //  If we are attached to the system process then return
    00210                         //  back to our caller
    00211                         //
    00212
    00213                         if (AttachedToProcess) {
    00214                             KeUnstackDetachProcess(&ApcState);
    00215                             AttachedToProcess = FALSE;
    00216                         }
    00217
    00218                         Status = STATUS_HANDLE_NOT_CLOSABLE;
    00219                         leave;
    00220                     }
    00221
    00222                 } else {
    00223
    00224                     if ((!PsIsThreadTerminating(PsGetCurrentThread())) &&
    00225                         (PsGetCurrentProcess()->Peb != NULL)) {
    00226
    00227                         ExUnlockHandleTableEntry( ObjectTable, ObjectTableEntry );
    00228
    00229     #if DBG
    00230                         //
    00231                         //  bugcheck here on checked builds if kernel mode code is
    00232                         //  closing a protected handle and process is not exiting.
    00233                         //  Ignore if no PEB as this occurs if process is killed
    00234                         //  before really starting.
    00235                         //
    00236
    00237                         KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 0, 0, 0);
    00238     #else
    00239                         //
    00240                         //  If we are attached to the system process then return
    00241                         //  back to our caller
    00242                         //
    00243
    00244                         if (AttachedToProcess) {
    00245                             KeUnstackDetachProcess(&ApcState);
    00246                             AttachedToProcess = FALSE;
    00247                         }
    00248
    00249                         Status = STATUS_HANDLE_NOT_CLOSABLE;
    00250                         leave;
    00251     #endif // DBG
    00252
    00253                     }
    00254                 }
    00255             }
    00256
    00257             //
    00258             //  Get the granted access for the handle
    00259             //
    00260
    00261     #if i386 && !FPO
    00262
    00263             if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
    00264
    00265                 CapturedGrantedAccess = ObpTranslateGrantedAccessIndex( ObjectTableEntry->GrantedAccessIndex );
    00266
    00267             } else {
    00268
    00269                 CapturedGrantedAccess = ObjectTableEntry->GrantedAccess;
    00270             }
    00271
    00272     #else
    00273
    00274             CapturedGrantedAccess = ObjectTableEntry->GrantedAccess;
    00275
    00276     #endif // i386 && !FPO
    00277
    00278             //
    00279             //  Now remove the handle from the handle table
    00280             //
    00281
    00282             ExDestroyHandle( ObjectTable,
    00283                              Handle,
    00284                              ObjectTableEntry );
    00285
    00286             //
    00287             //  perform any auditing required
    00288             //
    00289
    00290             //
    00291             //  Extract the value of the GenerateOnClose bit stored
    00292             //  after object open auditing is performed.  This value
    00293             //  was stored by a call to ObSetGenerateOnClosed.
    00294             //
    00295
    00296             if (CapturedAttributes & OBJ_AUDIT_OBJECT_CLOSE) {
    00297
    00298                 if ( SepAdtAuditingEnabled ) {
    00299
    00300                     SeCloseObjectAuditAlarm( Object,
    00301                                              (HANDLE)((ULONG_PTR)Handle & ~OBJ_HANDLE_TAGBITS),  // Mask off the tagbits defined for OB objects.
    00302                                              TRUE );
    00303                 }
    00304             }
    00305
    00306             //
    00307             //  Since we took the handle away we need to decrement the objects
    00308             //  handle count, and remove a reference
    00309             //
    00310
    00311             ObpDecrementHandleCount( PsGetCurrentProcess(),
    00312                                      ObjectHeader,
    00313                                      ObjectHeader->Type,
    00314                                      CapturedGrantedAccess );
    00315
    00316             ObDereferenceObject( Object );
    00317
    00318             ObpEndTypeSpecificCallOut( SaveIrql, "NtClose", ObjectType, Object );
    00319
    00320             //
    00321             //  If we are attached to the system process then return
    00322             //  back to our caller
    00323             //
    00324
    00325             if (AttachedToProcess) {
    00326                 KeUnstackDetachProcess(&ApcState);
    00327                 AttachedToProcess = FALSE;
    00328             }
    00329
    00330             //
    00331             //  And return to our caller
    00332             //
    00333
    00334             Status = STATUS_SUCCESS;
    00335             leave;
    00336
    00337         } else {
    00338
    00339             //
    00340             //  At this point the input handle did not translate to a valid
    00341             //  object table entry
    00342             //
    00343
    00344             ObpEndTypeSpecificCallOut( SaveIrql, "NtClose", ObpTypeObjectType, Handle );
    00345
    00346             //
    00347             //  If we are attached to the system process then return
    00348             //  back to our caller
    00349             //
    00350
    00351             if (AttachedToProcess) {
    00352                 KeUnstackDetachProcess(&ApcState);
    00353                 AttachedToProcess = FALSE;
    00354             }
    00355
    00356             //
    00357             //  Now if the handle is not null and it does not represent the
    00358             //  current thread or process then if we're user mode we either raise
    00359             //  or return an error
    00360             //
    00361
    00362             if ((Handle != NULL) &&
    00363                 (Handle != NtCurrentThread()) &&
    00364                 (Handle != NtCurrentProcess())) {
    00365
    00366                 if (KeGetPreviousMode() != KernelMode) {
    00367
    00368                     if ((NtGlobalFlag & FLG_ENABLE_CLOSE_EXCEPTIONS) ||
    00369                         (PsGetCurrentProcess()->DebugPort != NULL)) {
    00370
    00371                         Status = KeRaiseUserException(STATUS_INVALID_HANDLE);
    00372                         leave;
    00373
    00374                     } else {
    00375
    00376                         Status = STATUS_INVALID_HANDLE;
    00377                         leave;
    00378                     }
    00379
    00380                 } else {
    00381
    00382                     //
    00383                     //  bugcheck here if kernel debugger is enabled and if kernel mode code is
    00384                     //  closing a bogus handle and process is not exiting.  Ignore
    00385                     //  if no PEB as this occurs if process is killed before
    00386                     //  really starting.
    00387                     //
    00388
    00389                     if (( !PsIsThreadTerminating(PsGetCurrentThread())) &&
    00390                         (PsGetCurrentProcess()->Peb != NULL)) {
    00391
    00392                         if (KdDebuggerEnabled) {
    00393                             KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 1, 0, 0);
    00394                         }
    00395                     }
    00396
    00397                 }
    00398             }
    00399
    00400             Status = STATUS_INVALID_HANDLE;
    00401             leave;
    00402         }
    00403
    00404     } finally {
    00405
    00406         KeLeaveCriticalRegion();
    00407     }
    00408
    00409     return Status;
    00410 }
    00411
    00412
    00413 NTSTATUS
    00414 NtMakeTemporaryObject (
    00415     IN HANDLE Handle
    00416     )
    00417
    00418 /*++
    00419
    00420 Routine Description:
    00421
    00422     This routine makes the specified object non permanent.
    00423
    00424 Arguments:
    00425
    00426     Handle - Supplies a handle to the object being modified
    00427
    00428 Return Value:
    00429
    00430     An appropriate status value.
    00431
    00432 --*/
    00433
    00434 {
    00435     KPROCESSOR_MODE PreviousMode;
    00436     NTSTATUS Status;
    00437     PVOID Object;
    00438     OBJECT_HANDLE_INFORMATION HandleInformation;
    00439
    00440     PAGED_CODE();
    00441
    00442     //
    00443     //  Get previous processor mode and probe output argument if necessary.
    00444     //
    00445
    00446     PreviousMode = KeGetPreviousMode();
    00447
    00448     Status = ObReferenceObjectByHandle( Handle,
    00449                                         DELETE,
    00450                                         (POBJECT_TYPE)NULL,
    00451                                         PreviousMode,
    00452                                         &Object,
    00453                                         &HandleInformation );
    00454     if (!NT_SUCCESS( Status )) {
    00455
    00456         return( Status );
    00457     }
    00458
    00459     //
    00460     //  Make the object temporary.  Note that the object should still
    00461     //  have a name and directory entry because its handle count is not
    00462     //  zero
    00463     //
    00464
    00465     ObMakeTemporaryObject( Object );
    00466
    00467     //
    00468     //  Check if we need to generate a delete object audit/alarm
    00469     //
    00470
    00471     if (HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE) {
    00472
    00473         SeDeleteObjectAuditAlarm( Object,
    00474                                   Handle );
    00475     }
    00476
    00477     ObDereferenceObject( Object );
    00478
    00479     return( Status );
    00480 }
    00481
    00482
    00483 VOID
    00484 ObMakeTemporaryObject (
    00485     IN PVOID Object
    00486     )
    00487
    00488 /*++
    00489
    00490 Routine Description:
    00491
    00492     This routine removes the name of the object from its parent
    00493     directory.  The object is only removed if it has a non zero
    00494     handle count and a name.  Otherwise the object is simply
    00495     made non permanent
    00496
    00497 Arguments:
    00498
    00499     Object - Supplies the object being modified
    00500
    00501 Return Value:
    00502
    00503     None.
    00504
    00505 --*/
    00506
    00507 {
    00508     POBJECT_HEADER ObjectHeader;
    00509
    00510     PAGED_CODE();
    00511
    00512     ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    00513     ObjectHeader->Flags &= ~OB_FLAG_PERMANENT_OBJECT;
    00514
    00515     ObpDeleteNameCheck( Object, FALSE );
    00516
    00517     return;
    00518 }
    00519