How to pass HLK "PNP surprise device remove test"?

74 Views Asked by At

Recently I faced a problem regarding HLK testing against WDM drivers. When I perform HLK tests against the KMDF driver, every test passes. But when I do the same for the WDM driver some of the PNP tests fail.

At first, I thought there must be something wrong with the code. But while I was debugging the driver with WinDbg I found nothing suspicious.

So I went to https://github.com/microsoft/Windows-driver-samples/tree/main/general/ioctl/wdm and compiled this sample. And I was surprised that this sample also can not pass the same PNP tests on HLK.

For example, the test PNPSurpriseRemoveAndRestartDevice always fails with the error PNP_VetoLegacyDevice.

enter image description here

Also, I noticed the message

WDTF_PNP : EDT driver is not installed on the Target

right before the failure. Then I thought it might be because of the absent IRP_MJ_PNP handler.

So I slightly modified the code:

#include <ntddk.h>
#include "Driver.h"

IO_REMOVE_LOCK RemoveLock;

NTSTATUS MyWDMDevice_CreateClose(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
    UNREFERENCED_PARAMETER(DeviceObject);

    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;

    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}

NTSTATUS MyWDMDevice_IoControl(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
    UNREFERENCED_PARAMETER(DeviceObject);

    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
    ULONG code = irpStack->Parameters.DeviceIoControl.IoControlCode;

    switch (code) {
        // Add your specific IOCTL handling here
    default:
        Irp->IoStatus.Status = STATUS_SUCCESS;
        break;
    }

    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}

NTSTATUS MyWDMDevice_PnP(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
    PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

    UNREFERENCED_PARAMETER(DeviceObject);

    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
    NTSTATUS status = STATUS_SUCCESS;

    switch (irpStack->MinorFunction) {
    case IRP_MN_START_DEVICE:
        IoInitializeRemoveLock(&deviceExtension->RemoveLock, '1ock', 0, 0);
        Irp->IoStatus.Status = STATUS_SUCCESS;
        break;

    case IRP_MN_REMOVE_DEVICE:
        Irp->IoStatus.Status = STATUS_SUCCESS;
        IoReleaseRemoveLockAndWait(&deviceExtension->RemoveLock, Irp);
        IoDetachDevice(DeviceObject);
        IoDeleteDevice(DeviceObject);
        break;

    case IRP_MN_SURPRISE_REMOVAL:
        Irp->IoStatus.Status = STATUS_SUCCESS;
        IoReleaseRemoveLockAndWait(&deviceExtension->RemoveLock, Irp);
        break;

    case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:
        Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
        break;

    default:
        break;
    }

    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return status;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
    UNREFERENCED_PARAMETER(RegistryPath);

    NTSTATUS status;

    UNICODE_STRING DeviceName;
    UNICODE_STRING SymLinkName;

    RtlInitUnicodeString(&DeviceName, L"\\Device\\TSTDVCE");
    RtlInitUnicodeString(&SymLinkName, L"\\DosDevices\\TDVC");

    DriverObject->DriverUnload = NULL;

    DriverObject->MajorFunction[IRP_MJ_CREATE] = MyWDMDevice_CreateClose;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = MyWDMDevice_CreateClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyWDMDevice_IoControl;
    DriverObject->MajorFunction[IRP_MJ_PNP] = MyWDMDevice_PnP;

    PDEVICE_OBJECT DeviceObject;

    status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &SymLinkName,
        FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject);

    if (!NT_SUCCESS(status)) {
        return status;
    }

    DeviceObject->Flags |= DO_BUFFERED_IO;

    IoCreateSymbolicLink(&SymLinkName, &DeviceName);

    PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
    RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION));

    DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

    return STATUS_SUCCESS;
}

Unfortunately, it didn't help. And I still have the same errors. The Static Driver Verifier also found nothing related. No errors while debugging, nor while testing the driver with install/uninstall by devcon or Device Manager

The driver has to be WDM because it has to work with a file system and registry using absolute paths.

Environment/Tools I use for the driver development:

  • Win11,
  • VS2019 Comunity (16.7),
  • HLKStudio (10.0.22621.2428),
  • PlayList (HLK Version 22H2 CompatPlaylist x64 ARM64)}
0

There are 0 best solutions below