|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
iovutil.c
Abstract:
This module implements various utilities required to do driver verification.
Author:
Adrian J. Oney (adriao) 20-Apr-1998
Environment:
Kernel mode
Revision History:
AdriaO 02/10/2000 - Seperated out from ntos\io\trackirp.c
--*/
#include "iop.h"
#include "pnpi.h"
#include "arbiter.h"
#include "dockintf.h"
#include "pnprlist.h"
#include "pnpiop.h"
#include "iovputil.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGEVRFY, IovUtilInit)
//#pragma alloc_text(PAGEVRFY, IovUtilMarkDeviceObject)
//#pragma alloc_text(PAGEVRFY, IovUtilMarkStack)
//#pragma alloc_text(PAGEVRFY, IovUtilWatermarkIrp)
#ifndef NO_VERIFIER
#pragma alloc_text(PAGEVRFY, IovUtilGetLowerDeviceObject)
#pragma alloc_text(PAGEVRFY, IovUtilGetBottomDeviceObject)
#pragma alloc_text(PAGEVRFY, IovUtilGetUpperDeviceObject)
#pragma alloc_text(PAGEVRFY, IovUtilIsVerifiedDeviceStack)
#pragma alloc_text(PAGEVRFY, IovUtilFlushStackCache)
#pragma alloc_text(PAGEVRFY, IovUtilFlushVerifierDriverListCache)
#pragma alloc_text(PAGEVRFY, IovpUtilFlushListCallback)
#pragma alloc_text(PAGEVRFY, IovUtilIsPdo)
#pragma alloc_text(PAGEVRFY, IovUtilIsWdmStack)
#pragma alloc_text(PAGEVRFY, IovUtilHasDispatchHandler)
#pragma alloc_text(PAGEVRFY, IovUtilIsInFdoStack)
#pragma alloc_text(PAGEVRFY, IovUtilIsRawPdo)
#pragma alloc_text(PAGEVRFY, IovUtilIsDesignatedFdo)
#pragma alloc_text(PAGEVRFY, IovUtilIsDeviceObjectMarked)
#endif // NO_VERIFIER
#endif // ALLOC_PRAGMA
//
// This entire implementation is specific to the verifier
//
#ifndef NO_VERIFIER
BOOLEAN IovUtilVerifierEnabled = FALSE;
VOID FASTCALL IovUtilInit( VOID ) { IovUtilVerifierEnabled = TRUE; }
VOID FASTCALL IovUtilGetLowerDeviceObject( IN PDEVICE_OBJECT UpperDeviceObject, OUT PDEVICE_OBJECT *LowerDeviceObject ) /*++
Routine Description:
This routine returns the device object below the passed in parameter. In other words, it is the inverse of DeviceObject->AttachedDevice. Note that the returned device object is referenced by this routine.
Arguments:
UpperDeviceObject - Device object to look beneath. LowerDeviceObject - Receives device object beneath UpperDeviceObject, or NULL if none.
Return Value:
None.
--*/ { PDEVOBJ_EXTENSION deviceExtension; PDEVICE_OBJECT deviceAttachedTo; KIRQL irql;
irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
deviceExtension = UpperDeviceObject->DeviceObjectExtension; deviceAttachedTo = deviceExtension->AttachedTo;
if (deviceAttachedTo) {
ObReferenceObject(deviceAttachedTo); }
KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
*LowerDeviceObject = deviceAttachedTo; }
VOID FASTCALL IovUtilGetBottomDeviceObject( IN PDEVICE_OBJECT DeviceObject, OUT PDEVICE_OBJECT *BottomDeviceObject ) /*++
Routine Description:
This routine returns the device object at the bottom of the stack in which the passed in parameter is a member. In other words, it is the inverse of IoGetAttachedDeviceReference. Note that the returned device object is referenced by this routine.
Arguments:
DeviceObject - Device object to examine. BottomDeviceObject - Receives device object at the bottom of DeviceObject's stack, NULL if none.
Return Value:
None.
--*/ { PDEVOBJ_EXTENSION deviceExtension; PDEVICE_OBJECT lowerDeviceObject, deviceAttachedTo; KIRQL irql;
deviceAttachedTo = DeviceObject;
irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
do { lowerDeviceObject = deviceAttachedTo; deviceExtension = lowerDeviceObject->DeviceObjectExtension; deviceAttachedTo = deviceExtension->AttachedTo;
} while ( deviceAttachedTo );
ObReferenceObject(lowerDeviceObject);
KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
*BottomDeviceObject = lowerDeviceObject; }
VOID FASTCALL IovUtilGetUpperDeviceObject( IN PDEVICE_OBJECT LowerDeviceObject, OUT PDEVICE_OBJECT *UpperDeviceObject ) /*++
Routine Description:
This routine returns the device object above the passed in parameter. In other words, it retrieves DeviceObject->AttachedDevice under the database lock.. Note that the returned device object is referenced by this routine.
Arguments:
LowerDeviceObject - Device object to look above. UpperDeviceObject - Receives device object above LowerDeviceObject, or NULL if none.
Return Value:
None.
--*/ { PDEVICE_OBJECT deviceAbove; KIRQL irql;
irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
deviceAbove = LowerDeviceObject->AttachedDevice; if (deviceAbove) {
ObReferenceObject(deviceAbove); }
KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
*UpperDeviceObject = deviceAbove; }
BOOLEAN FASTCALL IovUtilIsVerifiedDeviceStack( IN PDEVICE_OBJECT DeviceObject ) /*++
Routine Description:
This routine determines whether a device object in the stack is marked for verification.
Arguments:
DeviceObject - Device object to examine.
Return Value:
TRUE if at least one device object in the stack is marked for verification, FALSE otherwise.
--*/ { PDEVOBJ_EXTENSION deviceExtension; PDEVICE_OBJECT currentDevObj, deviceAttachedTo; BOOLEAN stackIsInteresting; KIRQL irql;
//
// Quickly check the cached result stored on the device object...
//
if (DeviceObject->DeviceObjectExtension->ExtensionFlags & DOV_EXAMINED) {
stackIsInteresting = ((DeviceObject->DeviceObjectExtension->ExtensionFlags & DOV_TRACKED) != 0);
return stackIsInteresting; }
//
// Walk the entire stack and update everything appropriately.
//
irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
stackIsInteresting = FALSE; deviceAttachedTo = DeviceObject; do { currentDevObj = deviceAttachedTo; deviceExtension = currentDevObj->DeviceObjectExtension; deviceAttachedTo = deviceExtension->AttachedTo;
//
// Remember this...
//
if (MmIsDriverVerifying(currentDevObj->DriverObject)) {
stackIsInteresting = TRUE; }
} while (deviceAttachedTo && (!(deviceAttachedTo->DeviceObjectExtension->ExtensionFlags & DOV_EXAMINED)) );
if (deviceAttachedTo && (deviceAttachedTo->DeviceObjectExtension->ExtensionFlags & DOV_TRACKED)) {
//
// Propogate upwards the "interesting-ness" of the last examined device
// in the stack...
//
stackIsInteresting = TRUE; }
//
// Walk upwards, marking everything examined and appropriately tracked.
//
do { deviceExtension = currentDevObj->DeviceObjectExtension;
if (stackIsInteresting) {
deviceExtension->ExtensionFlags |= DOV_TRACKED;
} else {
deviceExtension->ExtensionFlags &=~ DOV_TRACKED; }
deviceExtension->ExtensionFlags |= DOV_EXAMINED;
currentDevObj = currentDevObj->AttachedDevice;
} while (currentDevObj);
KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
return stackIsInteresting; }
VOID FASTCALL IovUtilFlushStackCache( IN PDEVICE_OBJECT DeviceObject, IN DATABASELOCKSTATE DatabaseLockState ) /*++
Routine Description:
This routine causes the verifier to reexamine the stack of which the given device object is a member. This needs to be done whenever the attachment chain is updated.
Arguments:
DeviceObject - Device that is a member of the stack requiring reexamination. DatabaseLockState - Indicates current state of Database lock, either DATABASELOCKSTATE_HELD or DATABASELOCKSTATE_NOT_HELD. If the lock is not held, this routine will acquire and release it.
Return Value:
None.
--*/ { PDEVICE_OBJECT pBottomDeviceObject, pCurrentDeviceObject; PDEVOBJ_EXTENSION deviceExtension; KIRQL irql;
if (DatabaseLockState == DATABASELOCKSTATE_NOT_HELD) {
irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock ); }
//
// Walk to the bottom of the stack
//
pCurrentDeviceObject = DeviceObject; do { pBottomDeviceObject = pCurrentDeviceObject; deviceExtension = pBottomDeviceObject->DeviceObjectExtension; pCurrentDeviceObject = deviceExtension->AttachedTo;
} while ( pCurrentDeviceObject );
//
// Walk back up clearing the appropriate flags.
//
pCurrentDeviceObject = pBottomDeviceObject; while(pCurrentDeviceObject) {
deviceExtension = pCurrentDeviceObject->DeviceObjectExtension; deviceExtension->ExtensionFlags &= ~(DOV_EXAMINED | DOV_TRACKED); pCurrentDeviceObject = pCurrentDeviceObject->AttachedDevice; }
if (DatabaseLockState == DATABASELOCKSTATE_NOT_HELD) {
KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql ); } }
VOID FASTCALL IovUtilFlushVerifierDriverListCache( VOID ) /*++
Routine Description:
This routine causes the verifier to reexamine all previously examined stacks. This is a prerequisite for updating the list of verified drivers.
Arguments:
None.
Return Value:
None.
--*/ { //
// We must be called at PASSIVE_LEVEL!
//
PAGED_CODE();
ObEnumerateObjectsByType( IoDeviceObjectType, IovpUtilFlushListCallback, NULL ); }
BOOLEAN IovpUtilFlushListCallback( IN PVOID Object, IN PUNICODE_STRING ObjectName, IN ULONG_PTR HandleCount, IN ULONG_PTR PointerCount, IN PVOID Context ) /*++
Routine Description:
This is a worker routine for IovUtilFlushVerifierDriverListCache. It is called on each device object in the system.
Arguments:
Object - Device Object enumerated by ObEnumerateObjectsByType. ObjectName - Name of the object HandleCount - Handle count of the object PointerCount - Pointer count of the object Context - Context supplied to ObEnumerateObjectsByType (not used)
Return Value:
BOOLEAN that indicates whether the enumeration should continue.
--*/ { PDEVICE_OBJECT deviceObject; PDEVOBJ_EXTENSION deviceExtension;
deviceObject = (PDEVICE_OBJECT) Object; deviceExtension = deviceObject->DeviceObjectExtension;
if (PointerCount || HandleCount) {
deviceExtension->ExtensionFlags &= ~(DOV_EXAMINED | DOV_TRACKED); }
return TRUE; }
VOID IovUtilRelateDeviceObjects( IN PDEVICE_OBJECT FirstDeviceObject, IN PDEVICE_OBJECT SecondDeviceObject, OUT DEVOBJ_RELATION *DeviceObjectRelation ) /*++
Routine Description:
This routine determines the relationship between two device objects, relative to their stacks.
Arguments:
FirstDeviceObject - First device object
SecondDeviceObject - Second device object
DeviceObjectRelation - Receives stack relationship of device objects:
DEVOBJ_RELATION_IDENTICAL - The two device objects are identical.
DEVOBJ_RELATION_FIRST_IMMEDIATELY_ABOVE_SECOND - The first device object is immediately above the second device object in the same stack.
DEVOBJ_RELATION_FIRST_ABOVE_SECOND - The first device object is above the second device object in the same stack, but not immediately above.
DEVOBJ_RELATION_FIRST_IMMEDIATELY_BELOW_SECOND - The first device object is immediately below the second device object in the same stack.
DEVOBJ_RELATION_FIRST_BELOW_SECOND - The first device object is below the second device object in the same stack, but not immediately above.
DEVOBJ_RELATION_NOT_IN_SAME_STACK - The device objects do not belong to the same stack.
Return Value:
None.
--*/ { PDEVOBJ_EXTENSION deviceExtension; PDEVICE_OBJECT upperDevobj, lowerDeviceObject, deviceAttachedTo; ULONG result; KIRQL irql;
//
// Try the easiest early out
//
if (FirstDeviceObject == SecondDeviceObject) {
*DeviceObjectRelation = DEVOBJ_RELATION_IDENTICAL; return; }
irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
//
// Try the most common early out
//
if (FirstDeviceObject == SecondDeviceObject->AttachedDevice){
*DeviceObjectRelation = DEVOBJ_RELATION_FIRST_IMMEDIATELY_ABOVE_SECOND; KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql ); return;
} else if (FirstDeviceObject->AttachedDevice == SecondDeviceObject) {
*DeviceObjectRelation = DEVOBJ_RELATION_FIRST_IMMEDIATELY_BELOW_SECOND; KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql ); return; }
//
// We'll have to walk a stack. Start by getting the bottom of the first
// device object.
//
deviceAttachedTo = FirstDeviceObject; do { if (deviceAttachedTo == SecondDeviceObject) {
break; }
lowerDeviceObject = deviceAttachedTo; deviceExtension = lowerDeviceObject->DeviceObjectExtension; deviceAttachedTo = deviceExtension->AttachedTo;
} while ( deviceAttachedTo );
//
// If deviceAttachedTo isn't NULL, then we walked down from
// FirstDeviceObject and found SecondDeviceObject.
//
if (deviceAttachedTo) {
*DeviceObjectRelation = DEVOBJ_RELATION_FIRST_ABOVE_SECOND; KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql ); return; }
//
// Now try walking *up* FirstDeviceObject and see if we find
// SecondDeviceObject.
//
upperDevobj = FirstDeviceObject->AttachedDevice; while(upperDevobj && (upperDevobj != SecondDeviceObject)) {
upperDevobj = upperDevobj->AttachedDevice; }
if (upperDevobj == NULL) {
*DeviceObjectRelation = DEVOBJ_RELATION_NOT_IN_SAME_STACK;
} else {
*DeviceObjectRelation = DEVOBJ_RELATION_FIRST_BELOW_SECOND; }
KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql ); }
BOOLEAN IovUtilIsPdo( IN PDEVICE_OBJECT DeviceObject ) { PDEVICE_NODE deviceNode; PDEVICE_OBJECT possiblePdo; BOOLEAN isPdo;
IovUtilGetBottomDeviceObject(DeviceObject, &possiblePdo); if (possiblePdo != DeviceObject) {
ObDereferenceObject(possiblePdo); return FALSE; }
deviceNode = possiblePdo->DeviceObjectExtension->DeviceNode;
isPdo = (deviceNode && (!(deviceNode->Flags & DNF_LEGACY_RESOURCE_DEVICENODE)));
//
// Free our reference.
//
ObDereferenceObject(possiblePdo);
return isPdo; }
BOOLEAN IovUtilIsWdmStack( IN PDEVICE_OBJECT DeviceObject ) { PDEVICE_NODE deviceNode; PDEVICE_OBJECT possiblePdo; BOOLEAN isWdmStack;
IovUtilGetBottomDeviceObject(DeviceObject, &possiblePdo);
deviceNode = possiblePdo->DeviceObjectExtension->DeviceNode;
isWdmStack = (deviceNode && (!(deviceNode->Flags & DNF_LEGACY_RESOURCE_DEVICENODE)));
//
// Free our reference.
//
ObDereferenceObject(possiblePdo);
return isWdmStack; }
BOOLEAN FASTCALL IovUtilHasDispatchHandler( IN PDRIVER_OBJECT DriverObject, IN UCHAR MajorFunction ) { return (DriverObject->MajorFunction[MajorFunction] != IopInvalidDeviceRequest); }
BOOLEAN FASTCALL IovUtilIsInFdoStack( IN PDEVICE_OBJECT DeviceObject ) { PDEVOBJ_EXTENSION deviceExtension; PDEVICE_OBJECT deviceAttachedTo, lowerDevobj; KIRQL irql;
deviceAttachedTo = DeviceObject;
irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
do {
if (IovUtilIsDeviceObjectMarked(DeviceObject, MARKTYPE_BOTTOM_OF_FDO_STACK)) {
break; }
deviceAttachedTo = deviceAttachedTo->DeviceObjectExtension->AttachedTo;
} while ( deviceAttachedTo );
KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql ); return (deviceAttachedTo != NULL); }
BOOLEAN FASTCALL IovUtilIsRawPdo( IN PDEVICE_OBJECT DeviceObject ) { return IovUtilIsDeviceObjectMarked(DeviceObject, MARKTYPE_RAW_PDO); }
BOOLEAN FASTCALL IovUtilIsDesignatedFdo( IN PDEVICE_OBJECT DeviceObject ) { return IovUtilIsDeviceObjectMarked(DeviceObject, MARKTYPE_DESIGNATED_FDO); }
VOID FASTCALL IovUtilMarkDeviceObject( IN PDEVICE_OBJECT DeviceObject, IN MARK_TYPE MarkType ) { PULONG extensionFlags;
if (!IovUtilVerifierEnabled) {
return; }
extensionFlags = &DeviceObject->DeviceObjectExtension->ExtensionFlags;
switch(MarkType) {
case MARKTYPE_DELETED: *extensionFlags |= DOV_DELETED; break;
case MARKTYPE_BOTTOM_OF_FDO_STACK: *extensionFlags |= DOV_BOTTOM_OF_FDO_STACK; break;
case MARKTYPE_DESIGNATED_FDO: *extensionFlags |= DOV_DESIGNATED_FDO; break;
case MARKTYPE_RAW_PDO: *extensionFlags |= DOV_RAW_PDO; break;
case MARKTYPE_DEVICE_CHECKED: *extensionFlags |= DOV_FLAGS_CHECKED; break;
case MARKTYPE_RELATION_PDO_EXAMINED: *extensionFlags |= DOV_FLAGS_RELATION_EXAMINED; break;
default: ASSERT(0); break; } }
BOOLEAN FASTCALL IovUtilIsDeviceObjectMarked( IN PDEVICE_OBJECT DeviceObject, IN MARK_TYPE MarkType ) { ULONG extensionFlags;
extensionFlags = DeviceObject->DeviceObjectExtension->ExtensionFlags;
switch(MarkType) {
case MARKTYPE_DELETED: return ((extensionFlags & DOV_DELETED) != 0);
case MARKTYPE_BOTTOM_OF_FDO_STACK: return ((extensionFlags & DOV_BOTTOM_OF_FDO_STACK) != 0);
case MARKTYPE_DESIGNATED_FDO: return ((extensionFlags & DOV_DESIGNATED_FDO) != 0);
case MARKTYPE_RAW_PDO: return ((extensionFlags & DOV_RAW_PDO) != 0);
case MARKTYPE_DEVICE_CHECKED: return ((extensionFlags & DOV_FLAGS_CHECKED) != 0);
case MARKTYPE_RELATION_PDO_EXAMINED: return ((extensionFlags & DOV_FLAGS_RELATION_EXAMINED) != 0);
default: ASSERT(0); return FALSE; } }
VOID FASTCALL IovUtilMarkStack( IN PDEVICE_OBJECT PhysicalDeviceObject, IN PDEVICE_OBJECT BottomOfFdoStack OPTIONAL, IN PDEVICE_OBJECT FunctionalDeviceObject OPTIONAL, IN BOOLEAN RawStack ) /*++
Description:
This routine marks device objects in a PnP stack appropriately. It is called by AddDevice once the stack is properly constructed.
Arguments:
PhysicalDeviceObject - Device object at the bottom of the PnP stack.
BottomOfFdoStack - First device object added during AddDevice. Below this device object is either a bus filter or the PDO itself.
FunctionalDeviceObject - Specifies the device object as identified in the service branch. This should be NULL if the devnode is raw and no overriding service was specified.
RawStack - True if stack was marked raw.
Return Value:
None.
--*/ { PDEVICE_OBJECT trueFunctionalDeviceObject;
if (BottomOfFdoStack) {
IovUtilMarkDeviceObject(BottomOfFdoStack, MARKTYPE_BOTTOM_OF_FDO_STACK); }
if (FunctionalDeviceObject) {
trueFunctionalDeviceObject = FunctionalDeviceObject;
if (IovUtilVerifierEnabled) {
VfDevObjAdjustFdoForVerifierFilters(&trueFunctionalDeviceObject); }
IovUtilMarkDeviceObject(trueFunctionalDeviceObject, MARKTYPE_DESIGNATED_FDO);
} else if (RawStack) {
IovUtilMarkDeviceObject(PhysicalDeviceObject, MARKTYPE_DESIGNATED_FDO); IovUtilMarkDeviceObject(PhysicalDeviceObject, MARKTYPE_RAW_PDO); } }
VOID FASTCALL IovUtilWatermarkIrp( IN PIRP Irp, IN ULONG Flags ) { if (IovUtilVerifierEnabled) {
VfIrpWatermark(Irp, Flags); } }
#else // NO_VERIFIER
//
// The code below should be built into a future stub that deadens out IO
// support for the verifier.
//
VOID FASTCALL IovUtilInit( VOID ) { }
VOID FASTCALL IovUtilMarkDeviceObject( IN PDEVICE_OBJECT DeviceObject, IN MARK_TYPE MarkType ) { UNREFERENCED_PARAMETER(DeviceObject); UNREFERENCED_PARAMETER(MarkType); }
VOID FASTCALL IovUtilMarkStack( IN PDEVICE_OBJECT PhysicalDeviceObject, IN PDEVICE_OBJECT BottomOfFdoStack OPTIONAL, IN PDEVICE_OBJECT FunctionalDeviceObject OPTIONAL, IN BOOLEAN RawStack ) { UNREFERENCED_PARAMETER(PhysicalDeviceObject); UNREFERENCED_PARAMETER(BottomOfFdoStack); UNREFERENCED_PARAMETER(FunctionalDeviceObject); UNREFERENCED_PARAMETER(RawStack); }
VOID FASTCALL IovUtilWatermarkIrp( IN PIRP Irp, IN ULONG Flags ) { UNREFERENCED_PARAMETER(Irp); UNREFERENCED_PARAMETER(Flags); }
#endif // NO_VERIFIER
|