windows-nt/Source/XPSP1/NT/base/ntos/verifier/vfdevobj.c
2020-09-26 16:20:57 +08:00

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;
}
}