Indiscriminately wrapping DriveryEntry and UnloadDriver with FAST_MUTEX

So I’ve been asked to get an old NT driver of ours signed by MS.
This driver was originally written back in 2006 and had been used almost as-is.
The driver is a non-PNP software driver.

I should say first and foremost I’m an application developer (trying to set the readers expectations of my current level of knowledge).

Problem:

While running the HCK tests I ran into the following failure during the Sleep and PNP test.
DRIVER_VERIFIER_DETECTED_VIOLATION (c4)
DV_VIOLATED_CONDITION: IoCreateSymbolicLink should only be called at IRQL = PASSIVE_LEVEL.

Examining the failure via WinDbg I see that we’re attempting to call IoCreateSymbolicLink after calling ExAcquireFastMutex in the DriverEntry function.
This of course is problematic as ExAcquireFastMutex sets the IRQL to APC_LEVEL but IoCreateSymbolicLink expects an IRQL of PASSIVE_LEVEL.

Looking at the source code I see that the original developer wrapped DriverEntry and DriverUnload with a FAST_MUTEX.

Within DriverEntry we’re doing what appears to be fairly standard initialization logic.

  1. Create a device object via IoCreateDevice
  2. Create a symbolic link via IoCreateSymbolicLink
  3. Assigning dispatch routines
  4. Assigning unload routine

The DriverUnload function does mostly standard stuff (more on that in a second).

  1. Delete the symbolic link via IoDeleteSymbolicLink
  2. Delete the DeviceObject via IoDeleteDevice.

The part I’m unsure of is the following piece of code:

// These are the globals the developer defined.
// They're only used in the DriverUnload routine and are curiously defined as volatile which I find suspicious. 
volatile LONG		s_bRegUnhooking = 0;
volatile LONG		s_lRegEntryCounter = 0;

void RegUnloadDriver(IN PDRIVER_OBJECT pDriverObject)
{
     ExAcquireFastMutex((PFAST_MUTEX)&s_mtxInitializing);
     // Other stuff..

    if (1 < InterlockedIncrement((PLONG)&s_bRegUnhooking))
    return /*STATUS_UNSUCCESSFUL*/; // we are already unhooked or unhooking

    // Wait until we are idle, no callers in hooked apis. 
    BOOLEAN bWaited = FALSE;
    while (1 < InterlockedIncrement((PLONG)&s_lRegEntryCounter))
    {
        InterlockedDecrement((PLONG)&s_lRegEntryCounter);
        bWaited = TRUE;
        LARGE_INTEGER iDelay;
        iDelay.QuadPart = (__int64)-(1024L * 1024L);  // 100 ms. relative to current time
        KeDelayExecutionThread(KernelMode, FALSE, &iDelay);
    }
    // Other stuff...
    ExReleaseFastMutex((PFAST_MUTEX)&s_mtxInitializing);
}

Assumption
We have several “agents” which utilize this driver, I suspect what the original developer was trying to accomplish was preventing the driver from being initialized more than once as well as preventing the driver from being unloaded for one agent while another agent is currently attempting to initialize the driver…

Question
Does a FAST_MUTEX make sense here?
Would a FAST_MUTEX in conjunction with the code I showed in the DriverUnload routine prevent the driver from being concurrently initialized/unloaded? I have my doubts here…
If a FAST_MUTEX makes sense here, how can I acquire a FAST_MUTEX and then create a symbolic link via IoCreateSymbolicLink?

I appreciate that some of these questions may be impossible to answer without knowing more about the application.
If you need more information I can provide it.

DriverEntry and Unload are both called exactly once in the lifetime of a driver. There is absolutely no reason to do any synchronization in either one…

@Tim_Roberts said:
DriverEntry and Unload are both called exactly once in the lifetime of a driver. There is absolutely no reason to do any synchronization in either one…

This is exactly what I was thinking, but I wanted to ask seasoned driver dev’s first before deciding on the best course of action.

“Seasoned”. That’s a nice way to put it. I once described a colleague as a “fixture” in the graphics industry. He said it made him feel like plumbing.

I guess you must now feel like a steak :slight_smile: