|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
obclose.c
Abstract:
Object close system service
Author:
Steve Wood (stevewo) 31-Mar-1989
Revision History:
--*/
#include "obp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,NtMakeTemporaryObject)
#pragma alloc_text(PAGE,NtClose)
#pragma alloc_text(PAGE,ObMakeTemporaryObject)
#pragma alloc_text(PAGE,ObpCloseHandleTableEntry)
#pragma alloc_text(PAGE,ObCloseHandle)
#pragma alloc_text(PAGE,ObpCloseHandle)
#endif
//
// Indicates if auditing is enabled so we have to close down the object
// audit alarm
//
extern BOOLEAN SepAdtAuditingEnabled;
ObpCloseHandleTableEntry ( IN PHANDLE_TABLE ObjectTable, IN PHANDLE_TABLE_ENTRY ObjectTableEntry, IN HANDLE Handle, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN Rundown, IN BOOLEAN CanNotRaise ) /*++
Routine Description:
This function is used to close a handle table entry
Arguments:
ObjectTableEntry - Supplies the entry being closed. It must be locked PreviousMode - Mode of caller Rundown - Called as part of process rundown, ignore protected handles in this mode CanNotRaise - Can not raise user exceptions
Return Value:
An appropriate status value
--*/ { POBJECT_HEADER ObjectHeader; POBJECT_TYPE ObjectType; PVOID Object; ULONG CapturedGrantedAccess; ULONG CapturedAttributes; #if DBG
KIRQL SaveIrql; #endif // DBG
//
// From the object table entry we can grab a pointer to the object
// header, get its type and its body
//
ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(ObjectTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES); ObjectType = ObjectHeader->Type; Object = &ObjectHeader->Body;
//
// If the object type specifies an okay to close procedure then we
// need to invoke that callback. If the callback doesn't want us to
// close handle then unlock the object table and return the error
// to our caller
//
if (ObjectType->TypeInfo.OkayToCloseProcedure != NULL) {
ObpBeginTypeSpecificCallOut( SaveIrql );
if (!(*ObjectType->TypeInfo.OkayToCloseProcedure)( PsGetCurrentProcess(), Object, Handle, PreviousMode )) {
ObpEndTypeSpecificCallOut( SaveIrql, "NtClose", ObjectType, Object );
ExUnlockHandleTableEntry( ObjectTable, ObjectTableEntry );
return STATUS_HANDLE_NOT_CLOSABLE; }
ObpEndTypeSpecificCallOut( SaveIrql, "NtClose", ObjectType, Object ); }
CapturedAttributes = ObpGetHandleAttributes(ObjectTableEntry);
//
// If the previous mode was user and the handle is protected from
// being closed, then we'll either raise or return an error depending
// on the global flags and debugger port situation.
//
if ((CapturedAttributes & OBJ_PROTECT_CLOSE) != 0 && Rundown == FALSE) {
if (PreviousMode != KernelMode) { PETHREAD CurrentThread;
ExUnlockHandleTableEntry( ObjectTable, ObjectTableEntry );
CurrentThread = PsGetCurrentThread ();
if (!CanNotRaise && !KeIsAttachedProcess() && !PsIsThreadTerminating (CurrentThread) && !CurrentThread->Tcb.ApcState.KernelApcInProgress && ((NtGlobalFlag & FLG_ENABLE_CLOSE_EXCEPTIONS) || (PsGetCurrentProcess()->DebugPort != NULL))) {
//
// Raise and exception in user mode
//
return KeRaiseUserException(STATUS_HANDLE_NOT_CLOSABLE);
} else {
return STATUS_HANDLE_NOT_CLOSABLE; }
} else { KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 0, 0, 0); } } //
// Get the granted access for the handle
//
#if i386
if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
CapturedGrantedAccess = ObpTranslateGrantedAccessIndex( ObjectTableEntry->GrantedAccessIndex );
} else {
CapturedGrantedAccess = ObpDecodeGrantedAccess(ObjectTableEntry->GrantedAccess); }
#else
CapturedGrantedAccess = ObpDecodeGrantedAccess(ObjectTableEntry->GrantedAccess);
#endif // i386
//
// Now remove the handle from the handle table
//
ExDestroyHandle( ObjectTable, Handle, ObjectTableEntry );
//
// perform any auditing required
//
//
// Extract the value of the GenerateOnClose bit stored
// after object open auditing is performed. This value
// was stored by a call to ObSetGenerateOnClosed.
//
if (CapturedAttributes & OBJ_AUDIT_OBJECT_CLOSE) {
if ( SepAdtAuditingEnabled ) {
SeCloseObjectAuditAlarm( Object, (HANDLE)((ULONG_PTR)Handle & ~OBJ_HANDLE_TAGBITS), // Mask off the tagbits defined for OB objects.
TRUE ); } }
//
// Since we took the handle away we need to decrement the objects
// handle count, and remove a reference
//
ObpDecrementHandleCount( PsGetCurrentProcess(), ObjectHeader, ObjectType, CapturedGrantedAccess );
ObDereferenceObject( Object );
//
// And return to our caller
//
return STATUS_SUCCESS; }
NTSTATUS ObpCloseHandle ( IN HANDLE Handle, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN CanNotRaise ) /*++
Routine Description:
This function is used to close access to the specified handle with the given mode
Arguments:
Handle - Supplies the handle being closed PreviousMode - Processor mode to be used in the handle access checks. CanNotRaise - We are not allowed to do a user mode raise.
Return Value:
An appropriate status value
--*/ { PHANDLE_TABLE ObjectTable; PHANDLE_TABLE_ENTRY ObjectTableEntry; NTSTATUS Status; BOOLEAN AttachedToProcess = FALSE; KAPC_STATE ApcState; PETHREAD CurrentThread; PEPROCESS CurrentProcess;
ObpValidateIrql( "NtClose" );
CurrentThread = PsGetCurrentThread (); CurrentProcess = PsGetCurrentProcessByThread (CurrentThread); //
// For the current process we will grab its handle/object table and
// translate the handle to its corresponding table entry. If the
// call is successful it also lock down the handle table. But first
// check for a kernel handle and attach and use that table if so.
//
if (IsKernelHandle( Handle, PreviousMode )) {
Handle = DecodeKernelHandle( Handle );
ObjectTable = ObpKernelHandleTable;
//
// Go to the system process if we have to
//
if (CurrentProcess != PsInitialSystemProcess) { KeStackAttachProcess (&PsInitialSystemProcess->Pcb, &ApcState); AttachedToProcess = TRUE; }
} else {
ObjectTable = CurrentProcess->ObjectTable; }
//
// Protect ourselves from being interrupted while we hold a handle table
// entry lock
//
KeEnterCriticalRegionThread(&CurrentThread->Tcb);
ObjectTableEntry = ExMapHandleToPointer( ObjectTable, Handle );
//
// Check that the specified handle is legitimate otherwise we can
// assume the caller just passed in some bogus handle value
//
if (ObjectTableEntry != NULL) {
Status = ObpCloseHandleTableEntry (ObjectTable, ObjectTableEntry, Handle, PreviousMode, FALSE, CanNotRaise);
KeLeaveCriticalRegionThread(&CurrentThread->Tcb); //
// If we are attached to the system process then detach
//
if (AttachedToProcess) {
KeUnstackDetachProcess(&ApcState); AttachedToProcess = FALSE; }
} else {
KeLeaveCriticalRegionThread(&CurrentThread->Tcb);
//
// At this point the input handle did not translate to a valid
// object table entry
//
//
// If we are attached to the system process then return
// back to our caller
//
if (AttachedToProcess) { KeUnstackDetachProcess(&ApcState); AttachedToProcess = FALSE; }
//
// Now if the handle is not null and it does not represent the
// current thread or process then if we're user mode we either raise
// or return an error
//
if ((Handle != NULL) && (Handle != NtCurrentThread()) && (Handle != NtCurrentProcess())) {
if (PreviousMode != KernelMode) {
if ((NtGlobalFlag & FLG_ENABLE_CLOSE_EXCEPTIONS) || (CurrentProcess->DebugPort != NULL)) {
if (!CanNotRaise && !KeIsAttachedProcess() && !PsIsThreadTerminating (CurrentThread) && !CurrentThread->Tcb.ApcState.KernelApcInProgress) { return KeRaiseUserException (STATUS_INVALID_HANDLE); } else { return STATUS_INVALID_HANDLE; }
}
} else {
//
// bugcheck here if kernel debugger is enabled and if kernel mode code is
// closing a bogus handle and process is not exiting. Ignore
// if no PEB as this occurs if process is killed before
// really starting.
//
if (( !PsIsThreadTerminating(CurrentThread)) && (CurrentProcess->Peb != NULL)) {
if (KdDebuggerEnabled) { KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 1, 0, 0); } }
} }
Status = STATUS_INVALID_HANDLE; }
return Status; }
NTSTATUS ObCloseHandle ( IN HANDLE Handle, IN KPROCESSOR_MODE PreviousMode ) /*++
Routine Description:
This function is used to close access to the specified handle with the given mode
Arguments:
Handle - Supplies the handle being closed PreviousMode - Processor mode to be used in the handle access checks.
Return Value:
An appropriate status value
--*/ { return ObpCloseHandle (Handle, PreviousMode, TRUE); }
NTSTATUS NtClose ( IN HANDLE Handle )
/*++
Routine Description:
This function is used to close access to the specified handle
Arguments:
Handle - Supplies the handle being closed
Return Value:
An appropriate status value
--*/
{ return ObpCloseHandle (Handle, KeGetPreviousMode (), FALSE); }
NTSTATUS NtMakeTemporaryObject ( IN HANDLE Handle )
/*++
Routine Description:
This routine makes the specified object non permanent.
Arguments:
Handle - Supplies a handle to the object being modified
Return Value:
An appropriate status value.
--*/
{ KPROCESSOR_MODE PreviousMode; NTSTATUS Status; PVOID Object; OBJECT_HANDLE_INFORMATION HandleInformation;
PAGED_CODE();
//
// Get previous processor mode and probe output argument if necessary.
//
PreviousMode = KeGetPreviousMode();
Status = ObReferenceObjectByHandle( Handle, DELETE, (POBJECT_TYPE)NULL, PreviousMode, &Object, &HandleInformation ); if (!NT_SUCCESS( Status )) {
return( Status ); }
//
// Make the object temporary. Note that the object should still
// have a name and directory entry because its handle count is not
// zero
//
ObMakeTemporaryObject( Object );
//
// Check if we need to generate a delete object audit/alarm
//
if (HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE) {
SeDeleteObjectAuditAlarm( Object, Handle ); }
ObDereferenceObject( Object );
return( Status ); }
VOID ObMakeTemporaryObject ( IN PVOID Object )
/*++
Routine Description:
This routine removes the name of the object from its parent directory. The object is only removed if it has a non zero handle count and a name. Otherwise the object is simply made non permanent
Arguments:
Object - Supplies the object being modified
Return Value:
None.
--*/
{ POBJECT_HEADER ObjectHeader; POBJECT_TYPE ObjectType;
PAGED_CODE();
ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object ); ObjectType = ObjectHeader->Type;
//
// Other bits are set in this flags field by the handle database code. Synchronise with that.
//
ObpLockObject( ObjectHeader );
ObjectHeader->Flags &= ~OB_FLAG_PERMANENT_OBJECT;
ObpUnlockObject( ObjectHeader );
//
// Now delete the object name if no more handles are present.
//
ObpDeleteNameCheck( Object );
return; }
|