456 lines
11 KiB
C
456 lines
11 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
vfdevobj.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module verifies drivers properly manage device objects.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Adrian J. Oney (adriao) 09-May-1998
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Kernel mode
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
AdriaO 05/02/2000 - Seperated out from ntos\io\trackirp.c
|
||
|
|
||
|
--*/
|
||
|
|
||
|
//
|
||
|
// Disable W4 level warnings generated by public headers.
|
||
|
//
|
||
|
|
||
|
#include "vfpragma.h"
|
||
|
|
||
|
|
||
|
#include "..\io\iop.h" // Includes vfdef.h
|
||
|
|
||
|
#if (( defined(_X86_) ) && ( FPO ))
|
||
|
#pragma optimize( "y", off ) // disable FPO for consistent stack traces
|
||
|
#endif
|
||
|
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
#pragma alloc_text(PAGEVRFY, VerifierIoAttachDeviceToDeviceStack)
|
||
|
#pragma alloc_text(PAGEVRFY, VerifierIoDetachDevice)
|
||
|
#pragma alloc_text(PAGEVRFY, VerifierIoDeleteDevice)
|
||
|
#pragma alloc_text(PAGEVRFY, VfDevObjPreAddDevice)
|
||
|
#pragma alloc_text(PAGEVRFY, VfDevObjPostAddDevice)
|
||
|
#pragma alloc_text(PAGEVRFY, VfDevObjAdjustFdoForVerifierFilters)
|
||
|
#endif
|
||
|
|
||
|
VOID
|
||
|
VerifierIoAttachDeviceToDeviceStack(
|
||
|
IN PDEVICE_OBJECT NewDevice,
|
||
|
IN PDEVICE_OBJECT ExistingDevice
|
||
|
)
|
||
|
{
|
||
|
UNREFERENCED_PARAMETER (NewDevice);
|
||
|
|
||
|
IovUtilFlushStackCache(ExistingDevice, DATABASELOCKSTATE_HELD);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
VerifierIoDetachDevice(
|
||
|
IN PDEVICE_OBJECT LowerDevice
|
||
|
)
|
||
|
{
|
||
|
PVOID callerAddress;
|
||
|
ULONG stackHash;
|
||
|
|
||
|
if (LowerDevice->AttachedDevice == NULL) {
|
||
|
|
||
|
if (RtlCaptureStackBackTrace(2, 1, &callerAddress, &stackHash) != 1) {
|
||
|
|
||
|
callerAddress = NULL;
|
||
|
}
|
||
|
|
||
|
WDM_FAIL_ROUTINE((
|
||
|
DCERROR_DETACH_NOT_ATTACHED,
|
||
|
DCPARAM_ROUTINE + DCPARAM_DEVOBJ,
|
||
|
callerAddress,
|
||
|
LowerDevice
|
||
|
));
|
||
|
}
|
||
|
|
||
|
IovUtilFlushStackCache(LowerDevice, DATABASELOCKSTATE_HELD);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
VerifierIoDeleteDevice(
|
||
|
IN PDEVICE_OBJECT DeviceObject
|
||
|
)
|
||
|
{
|
||
|
PDEVICE_OBJECT deviceBelow;
|
||
|
PVOID callerAddress;
|
||
|
ULONG stackHash;
|
||
|
|
||
|
if (RtlCaptureStackBackTrace(2, 1, &callerAddress, &stackHash) != 1) {
|
||
|
|
||
|
callerAddress = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// ADRIAO N.B. 06/16/2000 - A good thing to do here would be to send a
|
||
|
// second remove IRP to every deleted device object that was a member
|
||
|
// of a WDM device stack. Just to check.
|
||
|
//
|
||
|
if (IovUtilIsDeviceObjectMarked(DeviceObject, MARKTYPE_DELETED)) {
|
||
|
|
||
|
WDM_FAIL_ROUTINE((
|
||
|
DCERROR_DOUBLE_DELETION,
|
||
|
DCPARAM_ROUTINE,
|
||
|
callerAddress
|
||
|
));
|
||
|
}
|
||
|
|
||
|
IovUtilMarkDeviceObject(DeviceObject, MARKTYPE_DELETED);
|
||
|
|
||
|
IovUtilGetLowerDeviceObject(DeviceObject, &deviceBelow);
|
||
|
if (deviceBelow) {
|
||
|
|
||
|
WDM_FAIL_ROUTINE((
|
||
|
DCERROR_DELETE_WHILE_ATTACHED,
|
||
|
DCPARAM_ROUTINE,
|
||
|
callerAddress
|
||
|
));
|
||
|
|
||
|
ObDereferenceObject(deviceBelow);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
VfDevObjPreAddDevice(
|
||
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
||
|
IN PDRIVER_OBJECT DriverObject,
|
||
|
IN PDRIVER_ADD_DEVICE AddDeviceFunction,
|
||
|
IN VF_DEVOBJ_TYPE DevObjType
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine is called before the specified driver's AddDevice has been
|
||
|
invoked.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
PhysicalDeviceObject - Device object at the bottom of the PnP stack.
|
||
|
|
||
|
DriverObject - Driver object of the driver who's AddDevice has been
|
||
|
invoked.
|
||
|
|
||
|
AddDeviceFunction - Address of the AddDevice routine.
|
||
|
|
||
|
DevObjType - Type of device object (lower device filter, FDO, etc.)
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
VF_DEVOBJ_TYPE objType;
|
||
|
|
||
|
UNREFERENCED_PARAMETER(AddDeviceFunction);
|
||
|
|
||
|
if (!MmIsDriverVerifying(DriverObject)) {
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (VfSettingsIsOptionEnabled(NULL, VERIFIER_OPTION_INSERT_WDM_FILTERS)) {
|
||
|
|
||
|
if (DevObjType == VF_DEVOBJ_FDO) {
|
||
|
|
||
|
//
|
||
|
// If we are calling AddDevice for the FDO, first attempt to attach
|
||
|
// a lower class filter.
|
||
|
//
|
||
|
objType = VF_DEVOBJ_LOWER_CLASS_FILTER;
|
||
|
|
||
|
|
||
|
} else {
|
||
|
|
||
|
objType = DevObjType;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Attach a filter, cause pain.
|
||
|
//
|
||
|
VfDriverAttachFilter(PhysicalDeviceObject, objType);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
VfDevObjPostAddDevice(
|
||
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
||
|
IN PDRIVER_OBJECT DriverObject,
|
||
|
IN PDRIVER_ADD_DEVICE AddDeviceFunction,
|
||
|
IN VF_DEVOBJ_TYPE DevObjType,
|
||
|
IN NTSTATUS Result
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine is called after the specified driver's AddDevice has been
|
||
|
invoked.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
PhysicalDeviceObject - Device object at the bottom of the PnP stack.
|
||
|
|
||
|
DriverObject - Driver object of the driver who's AddDevice has been
|
||
|
invoked.
|
||
|
|
||
|
AddDeviceFunction - Address of the AddDevice routine.
|
||
|
|
||
|
DevObjType - Type of device object (lower device filter, FDO, etc.)
|
||
|
|
||
|
Result - Result returned by the AddDevice Routine
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PDEVICE_OBJECT deviceAbove, deviceBelow;
|
||
|
BOOLEAN powerFailure;
|
||
|
VF_DEVOBJ_TYPE objType;
|
||
|
|
||
|
UNREFERENCED_PARAMETER(DriverObject);
|
||
|
|
||
|
if (NT_SUCCESS(Result) &&
|
||
|
VfSettingsIsOptionEnabled(NULL, VERIFIER_OPTION_INSERT_WDM_FILTERS) &&
|
||
|
MmIsDriverVerifying(DriverObject)) {
|
||
|
|
||
|
if (DevObjType == VF_DEVOBJ_FDO) {
|
||
|
|
||
|
//
|
||
|
// If we've just attached an FDO, try to add a upper device filter
|
||
|
// on top of it.
|
||
|
//
|
||
|
objType = VF_DEVOBJ_UPPER_DEVICE_FILTER;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
objType = DevObjType;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Attach filter, cause pain.
|
||
|
//
|
||
|
VfDriverAttachFilter(PhysicalDeviceObject, objType);
|
||
|
}
|
||
|
|
||
|
if (!VfSettingsIsOptionEnabled(NULL, VERIFIER_OPTION_VERIFY_DO_FLAGS)) {
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Take this opportunity to check the PDO.
|
||
|
//
|
||
|
if (!IovUtilIsDeviceObjectMarked(PhysicalDeviceObject, MARKTYPE_DEVICE_CHECKED)) {
|
||
|
|
||
|
if ((PhysicalDeviceObject->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO)) ==
|
||
|
(DO_BUFFERED_IO | DO_DIRECT_IO)) {
|
||
|
|
||
|
//
|
||
|
// Both direct I/O and buffered I/O are set. These are mutually
|
||
|
// exclusive.
|
||
|
//
|
||
|
WDM_FAIL_ROUTINE((
|
||
|
DCERROR_INCONSISTANT_DO_FLAGS,
|
||
|
DCPARAM_ROUTINE + DCPARAM_DEVOBJ,
|
||
|
PhysicalDeviceObject->DriverObject->DriverExtension->AddDevice,
|
||
|
PhysicalDeviceObject
|
||
|
));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// No need to check DO_DEVICE_INITIALIZING as PDO's get them cleared
|
||
|
// automagically.
|
||
|
//
|
||
|
|
||
|
IovUtilMarkDeviceObject(PhysicalDeviceObject, MARKTYPE_DEVICE_CHECKED);
|
||
|
}
|
||
|
|
||
|
powerFailure = FALSE;
|
||
|
deviceBelow = PhysicalDeviceObject;
|
||
|
ObReferenceObject(deviceBelow);
|
||
|
while(1) {
|
||
|
IovUtilGetUpperDeviceObject(deviceBelow, &deviceAbove);
|
||
|
|
||
|
if (deviceAbove == NULL) {
|
||
|
|
||
|
ObDereferenceObject(deviceBelow);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!IovUtilIsDeviceObjectMarked(deviceAbove, MARKTYPE_DEVICE_CHECKED)) {
|
||
|
|
||
|
if ((deviceAbove->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO)) ==
|
||
|
(DO_BUFFERED_IO | DO_DIRECT_IO)) {
|
||
|
|
||
|
//
|
||
|
// Both direct I/O and buffered I/O are set. These are mutually
|
||
|
// exclusive.
|
||
|
//
|
||
|
WDM_FAIL_ROUTINE((
|
||
|
DCERROR_INCONSISTANT_DO_FLAGS,
|
||
|
DCPARAM_ROUTINE + DCPARAM_DEVOBJ,
|
||
|
AddDeviceFunction,
|
||
|
deviceAbove
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if (deviceAbove->Flags & DO_DEVICE_INITIALIZING) {
|
||
|
|
||
|
//
|
||
|
// A device didn't clear the DO_DEVICE_INITIALIZING flag during
|
||
|
// AddDevice. Fail it now.
|
||
|
//
|
||
|
WDM_FAIL_ROUTINE((
|
||
|
DCERROR_DO_INITIALIZING_NOT_CLEARED,
|
||
|
DCPARAM_ROUTINE + DCPARAM_DEVOBJ,
|
||
|
AddDeviceFunction,
|
||
|
deviceAbove
|
||
|
));
|
||
|
|
||
|
//
|
||
|
// Clean up the mess.
|
||
|
//
|
||
|
deviceAbove->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
|
}
|
||
|
|
||
|
if ((deviceBelow->Flags & DO_POWER_PAGABLE) &&
|
||
|
(!(deviceAbove->Flags & DO_POWER_PAGABLE))) {
|
||
|
|
||
|
if (!powerFailure) {
|
||
|
|
||
|
//
|
||
|
// We have caught a driver bug. deviceAbove didn't inherit the
|
||
|
// DO_POWER_PAGABLE flag.
|
||
|
//
|
||
|
WDM_FAIL_ROUTINE((
|
||
|
DCERROR_POWER_PAGABLE_NOT_INHERITED,
|
||
|
DCPARAM_ROUTINE + DCPARAM_DEVOBJ,
|
||
|
AddDeviceFunction,
|
||
|
deviceAbove
|
||
|
));
|
||
|
|
||
|
//
|
||
|
// Don't blame anyone else.
|
||
|
//
|
||
|
powerFailure = TRUE;
|
||
|
}
|
||
|
|
||
|
deviceAbove->Flags |= DO_POWER_PAGABLE;
|
||
|
}
|
||
|
|
||
|
if ((deviceBelow->Flags & DO_BUFFERED_IO) &&
|
||
|
(!(deviceAbove->Flags & DO_BUFFERED_IO))) {
|
||
|
|
||
|
//
|
||
|
// Buffered I/O flag not copied. Broken filter!
|
||
|
//
|
||
|
WDM_FAIL_ROUTINE((
|
||
|
DCERROR_DO_FLAG_NOT_COPIED,
|
||
|
DCPARAM_ROUTINE + DCPARAM_DEVOBJ,
|
||
|
AddDeviceFunction,
|
||
|
deviceAbove
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if ((deviceBelow->Flags & DO_DIRECT_IO) &&
|
||
|
(!(deviceAbove->Flags & DO_DIRECT_IO))) {
|
||
|
|
||
|
//
|
||
|
// Direct I/O flag not copied. Broken filter!
|
||
|
//
|
||
|
WDM_FAIL_ROUTINE((
|
||
|
DCERROR_DO_FLAG_NOT_COPIED,
|
||
|
DCPARAM_ROUTINE + DCPARAM_DEVOBJ,
|
||
|
AddDeviceFunction,
|
||
|
deviceAbove
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if ((deviceBelow->DeviceType != FILE_DEVICE_UNKNOWN) &&
|
||
|
(deviceAbove->DeviceType == FILE_DEVICE_UNKNOWN)) {
|
||
|
|
||
|
//
|
||
|
// The device type wasn't copied by a filter!
|
||
|
//
|
||
|
WDM_FAIL_ROUTINE((
|
||
|
DCERROR_DEVICE_TYPE_NOT_COPIED,
|
||
|
DCPARAM_ROUTINE + DCPARAM_DEVOBJ,
|
||
|
AddDeviceFunction,
|
||
|
deviceAbove
|
||
|
));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Characteristics don't have to be checked because PnP takes care
|
||
|
// of propogating them appropriately.
|
||
|
//
|
||
|
}
|
||
|
|
||
|
IovUtilMarkDeviceObject(deviceAbove, MARKTYPE_DEVICE_CHECKED);
|
||
|
|
||
|
ObDereferenceObject(deviceBelow);
|
||
|
deviceBelow = deviceAbove;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
VfDevObjAdjustFdoForVerifierFilters(
|
||
|
IN OUT PDEVICE_OBJECT *FunctionalDeviceObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine adjusts the designated FDO to take into account any verifier
|
||
|
filter DO's added by this file.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FunctionalDeviceObject - On input, contains FDO. Adjusted to point to the
|
||
|
correct FDO if verifier added a filter.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PDEVICE_OBJECT fdo;
|
||
|
|
||
|
fdo = *FunctionalDeviceObject;
|
||
|
|
||
|
if (VfDriverIsVerifierFilterObject(fdo)) {
|
||
|
|
||
|
fdo = fdo->AttachedDevice;
|
||
|
ASSERT(fdo);
|
||
|
|
||
|
*FunctionalDeviceObject = fdo;
|
||
|
}
|
||
|
}
|
||
|
|