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.
- Create a device object via
IoCreateDevice
- Create a symbolic link via
IoCreateSymbolicLink
- Assigning dispatch routines
- Assigning unload routine
The DriverUnload
function does mostly standard stuff (more on that in a second).
- Delete the symbolic link via
IoDeleteSymbolicLink
- Delete the
DeviceObject
viaIoDeleteDevice
.
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.