Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTDEV

Before Posting...

Please check out the Community Guidelines in the Announcements and Administration Category.

More Info on Driver Writing and Debugging


The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.


Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/


Considerations when inside a Resource Lock(Mutex)

Greg_LindorGreg_Lindor Member Posts: 7

Hey everyone,

I wanted to understand the limitations (if any) I would have inside the context of a call to ExAcquireResourceExclusiveLite(). Namely the documentation suggests the code inside of this should either enter a Critical Region to disable all Kernel APCs.

What I'm failing to understand is what limitations does this impose on the function running within this 'Mutex'. So lets say I am executing callback functions like:

if ExAcquireResourceExclusiveLite
 then CallFunc()
ExReleaseResourceLite()

Assuming KeEnterCriticalRegion is called before the acqusition is made (or not?). Is there anything specific that I need to know about the limitations imposed on CallFunc() , besides the fact it can't Queue any APCs, can it hold a Lock? Is IRQL important or relevant here?

Comments

  • Jeremy_HurrenJeremy_Hurren Member - All Emails Posts: 34

    The docs are pretty clear that disabling APC delivery is a requirement: "Normal kernel APC delivery must be disabled before calling this routine."

    Some implications beyond that of APC delivery that I am aware of:

    • You should avoid calling code that that could reenter, which may cause deadlocks.
    • Your CallFunc() can acquire additional locks, but you should be careful about the potential deadlocks if different threads acquire the two locks in a different order. (KeEnterCriticalRegion can be called recursively so that every resource acquire is paired with the critical region. There's even a function ExEnterCriticalRegionAndAcquireResourceExclusive() that does this for you.)
  • Greg_LindorGreg_Lindor Member Posts: 7

    ok I think what I might actually need here is something closer to a RundownProtection. Thanks for the clarification Jeremy

  • Scott_Noone_(OSR)Scott_Noone_(OSR) Administrator Posts: 3,678

    Just a note about the Critical Region thing because it's always confusing: practically speaking all KeEnterCriticalRegion does is disable thread suspension. The majority of locks in Windows already do this for you but the ERESOURCE doesn't as a potential performance optimization. The idea being that because they're recursively acquirable you only need to enter the Critical Region once even if you recursively acquire the lock multiple times. I suspect that this optimization was much more important back when this code was first written and now it is just yet another way to confuse people 😂

    For a bit more background on WHY you need to disable thread suspension:

    Drivers are generally called in the context of the requesting thread*. Imagine you're writing a file system and using a global lock acquired around all I/O operations. These I/O operations sometimes come from privileged applications, sometimes from unprivileged, sometimes the OS, etc.

    Now say you get an I/O request from some unprivileged thread/application. While running in the context of this unprivileged thread, you grab the global lock and - WHAM! - someone suspends the unprivileged thread holding the lock. You've now caused a DoS for every other thread that tries to access your file system as everyone goes to sleep waiting for the lock held by the suspended thread. If you enter the Critical Region before acquiring the lock then you're all good...The worst that happens is the unprivileged app gets DoS'd and "that's life".

    And, lastly, RundownProtection is awesome. We've used it a bunch of times and it usually turns out to be an elegant solution to the "accessing a resource that comes and goes" problem.

    -scott

    *There are a LOT of exceptions to this, but that's another discussion...The key point is that the I/O Manager always initially dispatches the IRP synchronously and in the context of the requesting thread. Once the drivers are involved lots of other stuff can happen...

    -scott
    OSR

  • Scott_Noone_(OSR)Scott_Noone_(OSR) Administrator Posts: 3,678

    Also, just to be clear: This issues applies to any driver. The file system case I used is meant "by way of example and not limitation".

    -scott
    OSR

  • MBond2MBond2 Member Posts: 705

    rundown protection, also called reference tracking and other names, has been independently invented by many people over the years - including once by me. It is an indispensable technique in a high performance multi-threaded environment. tracking the number of, and location of, pointers to 'objects' that are 'visible' to multiple threads and also must be deallocated at some point, can dramatically reduce the lock scope and allows the safe use of such pointers from stack local variables

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. Sign in or register to get started.

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Kernel Debugging 13-17 May 2024 Live, Online
Developing Minifilters 1-5 Apr 2024 Live, Online
Internals & Software Drivers 11-15 Mar 2024 Live, Online
Writing WDF Drivers 20-24 May 2024 Live, Online