Preventing driver unload

Hi All,

I am writing WDM based legacy driver, it is not a hardware driver. I am starting the driver as a Windows service.
For some reason, I want to prevent driver unload using sc/net stop. I tried few methods like leaking device object handle, creating one more dummy device object. But nothing prevents the driver unload execution callback from the system.

Using the below approach, I am able to stop the driver unload.

  1. Setting unload function to NULL.
    DriverObject->DriverUnload = NULL;

  2. Another approach:

DriverObject->DriverExtension->AddDevice = TestAddDevice;

NTSTATUS TestAddDevice(
PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT PhysicalDeviceObject)

{
return STATUS_NO_SUCH_DEVICE;
}

But the above methods prevent the unload till the system reboot.
Actually, I want to customize the driver unload callback, kind of switching on/off the unload, based on some action from the upper layer.
Is there anyway to dynamically enable/disable driver unload.

Thanks,

The AddDevice callback is only used for PnP devices. That’s not what you want.

We’re getting into my personal bugaboos here, but if I am the administrator, I ought to have the right to unload your driver. You shouldn’t be able to stop me.

You can’t customize unload behavior at runtime. Eiter you are unloadable or you are not. Implementation wise (and not the documented contract), the presence of DriverUnload is evaluated the stop service API is executed the first time. So any time until that point, DriverUnload can change value. Once it is evaluated and if it is NULL, the result is cached and subsequent unload attempts will fail.

1 Like

I have seen filtermanger doc, and it says the admin stop request can be blocked using this flag FLTFL_REGISTRATION_DO_NOT_SUPPORT_SERVICE_STOP. So I am expecting something like that for other drivers also.

https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/fltkernel/ns-fltkernel-_flt_registration

I am expecting something like that for other drivers also.

That is a Filter Manager feature… not a WDM or WDF feature.

What Doron said.

Enter

1 Like

As far as I remember keeping a handle to a FILE_OBJECT that points to a device of your driver should prevent the DriverUnload from being called (it will be marked as “needs to unload” and it will be unloaded when the handle to your file object is closed) however I don’t think it’s a good idea, I agree with @Tim_Roberts

The file handle keeps the image loaded after DriverUnload has run, but does nothing to prevent DriverUnload from executing.

1 Like

@0xrepnz Doron was correct.

@Doron I saw this post in the MS site.

If the driver is a legacy driver then a client of the driver (typically user-mode process calling SC) must explicitly make an attempt to unload the driver. If there are no open handles to any deviceobjects created by the driver, then the system will call driver’s DriverUnload routine to get the driver to delete all the deviceobjects. After the unload routine returns, system will drop the reference it has taken on the driverobject. If there are no more references on the driverobject then the driver image gets unloaded from memory.

https://techcommunity.microsoft.com/t5/microsoft-usb-blog/why-doesn-t-my-driver-unload/ba-p/270680

The blog post doesn’t quite get all the small details right.

1 Like

@Doron Is there any msdn link that says the same information you have mentioned in your previous posts.

I don’t know. If not submit feedback on the DriverUnload page and link to this discussion

@Doron_Holan said:
The file handle keeps the image loaded after DriverUnload has run, but does nothing to prevent DriverUnload from executing.

Not according to msdn https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/unload-routine-environment

And just to be absolutely sure I tried to unload non-pnp driver with control device opened. Unload wasn’t called until application closed it’s handle to cdo.

The doc page you are referring to is describing unload behavior for pnp drivers. The rules are different for a non pnp driver.

@Doron_Holan said:
The doc page you are referring to is describing unload behavior for pnp drivers. The rules are different for a non pnp driver.

To me it looks like this page is for both.

Still, unload isn’t called for non-pnp driver as long as control device is opened by application. Maybe it is not how it should work, but it’s how it works in fact.

I just checked this with non-pnp driver registered by sc create.
My application opens cdo.
I try to unload driver with net stop
DriverUnload is not called

#include <wdm.h>
#include <wdmsec.h>

#include <common.h>

PDEVICE_OBJECT cdo{ nullptr };

void unload(PDRIVER_OBJECT)
{
UNICODE_STRING cdoDosName = RTL_CONSTANT_STRING(Common::cdoNameDOS);
IoDeleteSymbolicLink(&cdoDosName);

IoDeleteDevice(cdo);
cdo = nullptr;

}

NTSTATUS dispatch(PDEVICE_OBJECT, PIRP irp)
{
const IO_STACK_LOCATION* sl{ IoGetCurrentIrpStackLocation(irp) };
switch (sl->MajorFunction)
{
case IRP_MJ_CREATE:
KdPrint((“IRP_MJ_CREATE\n”));
break;
case IRP_MJ_CLEANUP:
KdPrint((“IRP_MJ_CLEANUP\n”));
break;
case IRP_MJ_CLOSE:
KdPrint((“IRP_MJ_CLOSE\n”));
break;
}

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

IoCompleteRequest(irp, IO_NO_INCREMENT);

return STATUS_SUCCESS;

}

extern “C” NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING)
{
driver->DriverUnload = unload;

driver->MajorFunction[IRP_MJ_CREATE] = driver->MajorFunction[IRP_MJ_CLEANUP] = driver->MajorFunction[IRP_MJ_CLOSE] = dispatch;

UNICODE_STRING deviceName = RTL_CONSTANT_STRING(Common::cdoNameNT);
NTSTATUS stat{ WdmlibIoCreateDeviceSecure(driver,
    0,
    &deviceName,
    FILE_DEVICE_UNKNOWN,
    FILE_DEVICE_SECURE_OPEN,
    FALSE,
    &SDDL_DEVOBJ_SYS_ALL_ADM_ALL,
    nullptr,
    &cdo) };
if (NT_SUCCESS(stat))
{
    UNICODE_STRING cdoDosName = RTL_CONSTANT_STRING(Common::cdoNameDOS);
    stat = IoCreateSymbolicLink(&cdoDosName, &deviceName);
    if (!NT_SUCCESS(stat))
    {
        IoDeleteDevice(cdo);
        cdo = nullptr;
    }
}
else
{
    cdo = nullptr;
}

return stat;

}