You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WDM驱动RemoveLockForward规则合规问题求助

WDM驱动RemoveLockForward规则校验失败问题排查

接手一个WDM驱动,正尝试使其符合微软标准。运行Static Driver Verifier(SDV)时,发现该驱动未通过RemoveLockForward规则校验。该规则用于验证将IRP转发至其他设备时,IoAcquireRemoveLock与IoReleaseRemoveLock的调用是否合规。

相关源码

Cam_PnpAddDevice函数

NTSTATUS Cam_PnpAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject)
{
  NTSTATUS               ntStatus = STATUS_SUCCESS;
  PDEVICE_OBJECT         DeviceObject;
  PDEVICE_EXTENSION      deviceExtension;
  GUID                   camGUID;
  PCAMERA_STATE          cameraState;
  PNODE_DEVICE_EXTENSION pNodeExt;
  POWER_STATE            state;

  ntStatus             = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_UNKNOWN,0, FALSE, &DeviceObject);
  DeviceObject->Flags |= DO_DIRECT_IO;
  deviceExtension      = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  cameraState          = &(deviceExtension->CameraState);
  RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION));
  deviceExtension->CSR_offset = 0xFFFFFFFF;

  camGUID  = GUID_CAMERA;
  ntStatus = IoRegisterDeviceInterface(PhysicalDeviceObject, &camGUID, NULL, &deviceExtension->SymbolicLinkName);
  if (!NT_SUCCESS(ntStatus))
  {
    IoDeleteDevice(DeviceObject);
    ntStatus = STATUS_NO_SUCH_DEVICE;
    goto Exit_Cam_PnpAddDevice;
  }

  deviceExtension->StackDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
  if (!deviceExtension->StackDeviceObject)
  {
    // Free up the symbolic link
    RtlFreeUnicodeString(&deviceExtension->SymbolicLinkName);

    IoDeleteDevice(DeviceObject);
    ntStatus = STATUS_NO_SUCH_DEVICE;
    goto Exit_Cam_PnpAddDevice;
  }

  // Save the device object we created as our physical device object
  deviceExtension->PhysicalDeviceObject = DeviceObject;

  // Get the port device object
  pNodeExt                          = PhysicalDeviceObject->DeviceExtension;
  deviceExtension->PortDeviceObject = pNodeExt->PortDeviceObject;

  // Initialize power states
  deviceExtension->CurrentDevicePowerState.DeviceState = PowerDeviceD0;
  deviceExtension->CurrentSystemPowerState             = PowerSystemWorking;

  state = deviceExtension->CurrentDevicePowerState;
  PoSetPowerState(DeviceObject, DevicePowerState, state);

  // Initialize the spinlock/list to store the bus reset irps...
  KeInitializeSpinLock(&deviceExtension->ResetSpinLock);
  KeInitializeSpinLock(&deviceExtension->CromSpinLock);
  KeInitializeSpinLock(&deviceExtension->AsyncSpinLock);
  KeInitializeSpinLock(&deviceExtension->IsochSpinLock);
  KeInitializeSpinLock(&deviceExtension->IsochResourceSpinLock);
  InitializeListHead(&deviceExtension->BusResetIrps);
  InitializeListHead(&deviceExtension->CromData);
  InitializeListHead(&deviceExtension->AsyncAddressData);
  InitializeListHead(&deviceExtension->IsochDetachData);
  InitializeListHead(&deviceExtension->IsochResourceData);

  DeviceObject->Flags      &= DO_POWER_PAGABLE;
  DeviceObject->Flags      &= ~DO_DEVICE_INITIALIZING;
  cameraState->IsochChannel = (ULONG)-1;

  // Free up the symbolic link
  RtlFreeUnicodeString(&deviceExtension->SymbolicLinkName);

  IoInitializeRemoveLock(&deviceExtension->ioRemoveLock, (ULONG)'TCAM', 0, 0);

Exit_Cam_PnpAddDevice:
  return (ntStatus);
}

Cam_Pnp函数

NTSTATUS Cam_Pnp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
  NTSTATUS           ntStatus        = STATUS_SUCCESS;
  PDEVICE_EXTENSION  deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  PIO_STACK_LOCATION IrpSp;

  IrpSp = IoGetCurrentIrpStackLocation(Irp);

  // This is the line that fails
  IoAcquireRemoveLock(&deviceExtension->ioRemoveLock, Irp);
  switch (IrpSp->MinorFunction)
  {
  case IRP_MN_STOP_DEVICE:
    ntStatus = Cam_PnpStopDevice(DeviceObject, Irp);

    Irp->IoStatus.Status = STATUS_SUCCESS;

    // Pass down to layer below us...
    ntStatus = Cam_SubmitIrpAsync(deviceExtension->StackDeviceObject, Irp, NULL);
    break;
  }

  IoReleaseRemoveLock(&deviceExtension->ioRemoveLock, Irp);
  return (ntStatus);
}

SDV输出信息

1: Cam_PnpAddDevice
  3:   NTSTATUS ntStatus = STATUS_SUCCESS;
  11:   IoCreateDevice
  12:   DeviceObject->Flags |= DO_DIRECT_IO;
  13:   deviceExtension      = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  14:   cameraState          = &(deviceExtension->CameraState);
  15:   sdv_RtlZeroMemory
  16:   deviceExtension->CSR_offset = 0xFFFFFFFF;
  18:   camGUID  = GUID_CAMERA;
  19:   IoRegisterDeviceInterface
  20:   if (!NT_SUCCESS(ntStatus))
  27:   IoAttachDeviceToDeviceStack
  28:   if (!deviceExtension->StackDeviceObject)
  39:   deviceExtension->PhysicalDeviceObject = DeviceObject;
  42:   pNodeExt                          = PhysicalDeviceObject->DeviceExtension;
  43:   deviceExtension->PortDeviceObject = pNodeExt->PortDeviceObject;
  46:   deviceExtension->CurrentDevicePowerState.DeviceState = PowerDeviceD0;
  47:   deviceExtension->CurrentSystemPowerState             = PowerSystemWorking;
  49:   state = deviceExtension->CurrentDevicePowerState;
  50:   PoSetPowerState
  53:   sdv_KeInitializeSpinLock
  54:   sdv_KeInitializeSpinLock
  55:   sdv_KeInitializeSpinLock
  56:   sdv_KeInitializeSpinLock
  57:   sdv_KeInitializeSpinLock
  58:   InitializeListHead
  59:   InitializeListHead
  60:   InitializeListHead
  61:   InitializeListHead
  62:   InitializeListHead
  64:   DeviceObject->Flags      &= DO_POWER_PAGABLE;
  65:   DeviceObject->Flags      &= ~DO_DEVICE_INITIALIZING;
  66:   cameraState->IsochChannel = (ULONG)-1;
  69:   RtlFreeUnicodeString
  71:   sdv_IoInitializeRemoveLock
  74:   return (ntStatus);
...  // There is messages here from the SDV that I did not include because I didn't
...  // think they were relevant.  If anyone asks I will happily include them.
  78: Cam_Pnp
    80: NTSTATUS           ntStatus        = STATUS_SUCCESS;
    81: PDEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
    84: sdv_IoGetCurrentIrpStackLocation
    87: sdv_IoAcquireRemoveLock
      9645: switch (choice)
      9647: case 0: return STATUS_UNSUCCESSFUL;break;
      9659: SLIC_sdv_IoAcquireRemoveLock_exit
        82: if(LockDepth > 0 && $return!=STATUS_SUCCESS)
        86: else if($return==STATUS_SUCCESS)
      9659: Return

问题定位与解决方案

问题根源

在Cam_Pnp函数的IRP_MN_STOP_DEVICE分支中,调用Cam_SubmitIrpAsync将IRP转发至下层设备后,代码仍执行了IoReleaseRemoveLock。RemoveLock的生命周期需与IRP的所有权绑定:当IRP被转发到下层驱动时,当前驱动已不再拥有该IRP的控制权,此时调用IoReleaseRemoveLock属于违规操作——因为RemoveLock是和当前驱动对IRP的处理绑定的,转发后应由下层驱动负责相关的锁操作,或者当前驱动需在转发前确保锁的处理逻辑正确。

另外,当前代码未检查IoAcquireRemoveLock的返回值,如果获取锁失败,后续逻辑仍会执行,这也可能引发问题。

修复方案

  1. 处理转发IRP后的锁释放逻辑
    对于需要转发的IRP,在调用Cam_SubmitIrpAsync后直接返回,跳过后续的IoReleaseRemoveLock调用,避免对已转交所有权的IRP进行锁操作:

    case IRP_MN_STOP_DEVICE:
        ntStatus = Cam_PnpStopDevice(DeviceObject, Irp);
        Irp->IoStatus.Status = STATUS_SUCCESS;
        // Pass down to layer below us...
        ntStatus = Cam_SubmitIrpAsync(deviceExtension->StackDeviceObject, Irp, NULL);
        // 转发IRP后直接返回,不释放RemoveLock
        return ntStatus;
    
  2. 检查IoAcquireRemoveLock的返回值
    在获取RemoveLock后立即检查返回状态,若获取失败则直接完成IRP并返回,避免后续错误逻辑:

    NTSTATUS acquireStatus = IoAcquireRemoveLock(&deviceExtension->ioRemoveLock, Irp);
    if (!NT_SUCCESS(acquireStatus)) {
        Irp->IoStatus.Status = acquireStatus;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return acquireStatus;
    }
    

内容的提问来源于stack exchange,提问作者Gary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 10:57:02