📄 fspyhash.c
字号:
/*++
Copyright (c) 1989-1999 Microsoft Corporation
Module Name:
filespy.c
Abstract:
This module contains all of the routines for tracking names by
hashing the FileObject. This cache is limited in size by the
following registry setting "MaxNames".
Environment:
Kernel mode
--*/
#include <ntifs.h>
#include "filespy.h"
#include "fspyKern.h"
#include "namelookup.h"
#if !USE_STREAM_CONTEXTS
////////////////////////////////////////////////////////////////////////
//
// Local definitions
//
////////////////////////////////////////////////////////////////////////
#define HASH_FUNC(FileObject) \
(((UINT_PTR)(FileObject) >> 8) & (HASH_SIZE - 1))
////////////////////////////////////////////////////////////////////////
//
// Global Variables
//
////////////////////////////////////////////////////////////////////////
//
// NOTE: Must use KSPIN_LOCKs to synchronize access to hash buckets since
// we may try to acquire them at DISPATCH_LEVEL.
//
LIST_ENTRY gHashTable[HASH_SIZE];
KSPIN_LOCK gHashLockTable[HASH_SIZE];
ULONG gHashMaxCounters[HASH_SIZE];
ULONG gHashCurrentCounters[HASH_SIZE];
UNICODE_STRING OutOfBuffers = CONSTANT_UNICODE_STRING(L"[-=Out Of Buffers=-]");
UNICODE_STRING PagingFile = CONSTANT_UNICODE_STRING(L"[-=Paging File=-]");
////////////////////////////////////////////////////////////////////////
//
// Local prototypes
//
////////////////////////////////////////////////////////////////////////
VOID
SpyDeleteContextCallback(
IN PVOID Context
);
//
// Linker commands
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, SpyInitNamingEnvironment)
#pragma alloc_text(PAGE, SpyInitDeviceNamingEnvironment)
#pragma alloc_text(PAGE, SpyCleanupDeviceNamingEnvironment)
#endif // ALLOC_PRAGMA
////////////////////////////////////////////////////////////////////////
//
// Main routines
//
////////////////////////////////////////////////////////////////////////
VOID
SpyInitNamingEnvironment(
VOID
)
/*++
Routine Description:
Init global variables.
Arguments:
None
Return Value:
None.
--*/
{
int i;
//
// Initialize the hash table.
//
for (i = 0; i < HASH_SIZE; i++){
InitializeListHead( &gHashTable[i] );
KeInitializeSpinLock( &gHashLockTable[i] );
}
}
VOID
SpyInitDeviceNamingEnvironment (
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Initialize the per DeviceObject naming environment.
Arguments:
DeviceObject - The device object to initialize.
Return Value:
None.
--*/
{
UNREFERENCED_PARAMETER( DeviceObject );
}
VOID
SpyCleanupDeviceNamingEnvironment (
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Initialize the per DeviceObject naming environment.
Arguments:
DeviceObject - The device object to initialize.
Return Value:
None.
--*/
{
UNREFERENCED_PARAMETER( DeviceObject );
}
VOID
SpyLogIrp (
IN PIRP Irp,
OUT PRECORD_LIST RecordList
)
/*++
Routine Description:
Records the Irp necessary information according to LoggingFlags in
RecordList. For any activity on the Irp path of a device being
logged, this function should get called twice: once on the IRPs
originating path and once on the IRPs completion path.
Arguments:
Irp - The Irp that contains the information we want to record.
LoggingFlags - The flags that say what to log.
RecordList - The PRECORD_LIST in which the Irp information is stored.
Return Value:
None.
--*/
{
PIO_STACK_LOCATION pIrpStack;
PRECORD_IRP pRecordIrp;
ULONG lookupFlags;
pRecordIrp = &RecordList->LogRecord.Record.RecordIrp;
pIrpStack = IoGetCurrentIrpStackLocation(Irp);
//
// Record the information we use for an originating Irp. We first
// need to initialize some of the RECORD_LIST and RECORD_IRP fields.
// Then get the interesting information from the Irp.
//
SetFlag(RecordList->LogRecord.RecordType, RECORD_TYPE_IRP);
pRecordIrp->IrpMajor = pIrpStack->MajorFunction;
pRecordIrp->IrpMinor = pIrpStack->MinorFunction;
pRecordIrp->IrpFlags = Irp->Flags;
pRecordIrp->FileObject = (FILE_ID)pIrpStack->FileObject;
pRecordIrp->DeviceObject = (FILE_ID)pIrpStack->DeviceObject;
pRecordIrp->ProcessId = (FILE_ID)PsGetCurrentProcessId();
pRecordIrp->ThreadId = (FILE_ID)PsGetCurrentThreadId();
pRecordIrp->Argument1 = pIrpStack->Parameters.Others.Argument1;
pRecordIrp->Argument2 = pIrpStack->Parameters.Others.Argument2;
pRecordIrp->Argument3 = pIrpStack->Parameters.Others.Argument3;
pRecordIrp->Argument4 = pIrpStack->Parameters.Others.Argument4;
if (IRP_MJ_CREATE == pRecordIrp->IrpMajor) {
//
// Only record the desired access if this is a CREATE IRP.
//
pRecordIrp->DesiredAccess = pIrpStack->Parameters.Create.SecurityContext->DesiredAccess;
}
KeQuerySystemTime(&(pRecordIrp->OriginatingTime));
lookupFlags = 0;
switch (pIrpStack->MajorFunction) {
case IRP_MJ_CREATE:
//
// This is a CREATE so we need to invalidate the name currently
// stored in the name cache for this FileObject.
//
SpyNameDelete( pIrpStack->FileObject );
//
// Flag in Create
//
SetFlag(lookupFlags, NLFL_IN_CREATE);
//
// Flag if opening the directory of the given file.
//
if (FlagOn(pIrpStack->Flags, SL_OPEN_TARGET_DIRECTORY)) {
SetFlag(lookupFlags, NLFL_OPEN_TARGET_DIR);
}
//
// Flag if opening by ID.
//
if (FlagOn(pIrpStack->Parameters.Create.Options,
FILE_OPEN_BY_FILE_ID )) {
SetFlag(lookupFlags, NLFL_OPEN_BY_ID);
}
break;
case IRP_MJ_CLOSE:
//
// We can only look up the name in the name cache if this is a
// CLOSE. It is possible that the close could be occurring during
// a cleanup operation in the file system (i.e., before we have
// received the cleanup completion) and requesting the name would
// cause a deadlock in the file system.
//
SetFlag(lookupFlags, NLFL_ONLY_CHECK_CACHE);
break;
}
//
// If the flag IRP_PAGING_IO is set in this IRP, we cannot query the name
// because it can lead to deadlocks. Therefore, add in the flag so that
// we will only try to find the name in our cache.
//
if (FlagOn(Irp->Flags, IRP_PAGING_IO)) {
ASSERT( !FlagOn( lookupFlags, NLFL_NO_LOOKUP ) );
SetFlag( lookupFlags, NLFL_ONLY_CHECK_CACHE );
}
SpySetName( RecordList,
pIrpStack->DeviceObject,
pIrpStack->FileObject,
lookupFlags,
NULL );
}
VOID
SpyLogIrpCompletion (
IN PIRP Irp,
OUT PRECORD_LIST RecordList
)
/*++
Routine Description:
Records the Irp necessary information according to LoggingFlags in
RecordList. For any activity on the Irp path of a device being
logged, this function should get called twice: once on the IRPs
originating path and once on the IRPs completion path.
Arguments:
Irp - The Irp that contains the information we want to record.
LoggingFlags - The flags that say what to log.
RecordList - The PRECORD_LIST in which the Irp information is stored.
Return Value:
None.
--*/
{
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_OBJECT deviceObject = pIrpStack->DeviceObject;
PRECORD_IRP pRecordIrp;
//
// Process the log record
//
if (SHOULD_LOG( deviceObject )) {
pRecordIrp = &RecordList->LogRecord.Record.RecordIrp;
//
// Record the information we use for a completion Irp.
//
pRecordIrp->ReturnStatus = Irp->IoStatus.Status;
pRecordIrp->ReturnInformation = Irp->IoStatus.Information;
KeQuerySystemTime(&pRecordIrp->CompletionTime);
//
// Add RecordList to our gOutputBufferList so that it gets up to
// the user
//
SpyLog( RecordList );
} else {
if (RecordList) {
//
// Context is set with a RECORD_LIST, but we are no longer
// logging so free this record.
//
SpyFreeRecord( RecordList );
}
}
switch (pIrpStack->MajorFunction) {
case IRP_MJ_CREATE:
//
// If the operation failed remove the name from the cache because
// it is stale
//
if (!NT_SUCCESS(Irp->IoStatus.Status) &&
(pIrpStack->FileObject != NULL)) {
SpyNameDelete(pIrpStack->FileObject);
}
break;
case IRP_MJ_CLOSE:
//
// Always remove the name on close
//
SpyNameDelete(pIrpStack->FileObject);
break;
case IRP_MJ_SET_INFORMATION:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -