understanding windows kernel -- critical region

critical region is one of the most confusing and poorly documented concepts in windows kernel dev

critical region is not the same as critical section

they’re even not related

your code can enter critical region by calling keentercriticalregion or fsrtlenterfilesystem, it is just a wrapper for keentercriticalregion

leave critical region by calling kelevecriticalregion or fsrtlexitfilesystem

the first important thing to not about critical region is that they’re a thread specific construct

therefor, when you enter a critical region, you’re entering for the current thread only, because of this, critical regions are most definitely not a sync mechanism

CRITICAL REGION IS NOT A SYNCHRONIZATION MECHANISM

then what is it then?

the answer lies in an insightful comment provided with the fsrtlenterfilesystem macro

//++
//
//  VOID
//  FsRtlEnterFileSystem (
//      );
//
//  Routine Description:
//
//      This routine is used when entering a file system (e.g., through its
//      Fsd entry point).  It ensures that the file system cannot be suspended
//      while running and thus block other file I/O requests.  Upon exit
//      the file system must call FsRtlExitFileSystem.
//
//  Arguments:
//
//  Return Value:
//
//      None.
//
//--

#define FsRtlEnterFileSystem() { \
    KeEnterCriticalRegion();     \
}

what this comment is trying to say that entering a Critical Region prevents the current thread from being suspended, thread suspension is performed by a normal kernel apc, which is simply a kernel mode callback directed to a particular thread,

by entering a critical region, your code prevents normal kapc from execution on the current thread

not that other things are done via normal kapc as well, such as hard error popups

but for out discussion we just care that critical regions prevent thread suspension

given this, we can make two statements:

  • threads in a critical region can not be suspended
  • thread not in a critical region can be suspend as long as the thread is running at irql passive_level

at first this sounds pretty hideous, I mean, have you ever given serious consideration to what would happen if a thread running in your driver was suspended?

most driver devs don’t think of this and if they do, they assume that they’re immune to suspension simply by running in kernel mode
no such luck, any code in your driver that runs at passive level and not in a critical region can be suspended

we’re doomed then?

what prevents this from being a complete mess is that in order to forcibly suspend a thread, a caller must have sufficient access to hte thread in question

thus if a process has sufficient rights and wants to puse a running thread, they’re allowed to do that

if this causes the process owning the thread to hang or otherwise malfunction, oh well! we can just document that under “Don’t Do That”

why bither having critical region at all then, well, the problem comes when there’s a knock on effect that causees problems in other threads or processes

waht if suspending a thread in process a caues threads in process B to hang?

just because I have the authority to suspend threads in process A doesn’t mean I have the sam autority with Process B
though I effectiely achieved the same result

even worse, imagine an unprivileged application that suspends own of its own threads, causing other privileged applications to hang or crash, this would be very bad indeed

thus, as you’re writing your code you need to ask yourself, if the current thread was suspended, would that affect any other threads in the system? Most problem cases will occur when acquiring lock; what happens to other potential users of a lock if you acquire that lock and then your thread is suspended?

take the file system for example, the fs uses a significat amount of file and voulme level locking while processing IO requests from user mode
what if a thread is currently holding one of these locks when it is suspended? this could potentially result in a system-wide deadlock as other threads come along and try to acquire the same lock to perform io operations of the file or volume

we solve this problem in one of two ways, the first way is to acquire a lock that also implicitly enters a critical region

examples of these types of locks are:

  • spinlocks
  • kernel mutexes
  • fast mutexes
  • guarded mutexes

however, if you acquire a lock that does not implicitly enter a critical region then you must explicitly call keentercriticalregion before acquiring the lock and keleavecriticalregion after releasing it

examples of locks that do not enter a critical region are:

  • executive resources
  • unsafe fast mutex
  • kevent
  • ksemaphore
    if you’re using one of the above as a synchronization mechanism and therefor acquire it from multiple different thread contexts, you really need a critical region to keep yourself safe from a DoS

Conclusion

in a nutshell, the critical region can be thought of simply as a way to prevent thread suspension

threads executing in kernel mode are subject to being suspended, which is fine unless your driver creates cross thread dependencies such as a lock

in that case, it’s up to you to properly enter and leae a critical region at the right times

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值