Skip to content

Commit

Permalink
Add IRQL Violation by calling KeEnterCriticalRegion() in EVT_DEVICE_D…
Browse files Browse the repository at this point in the history
…0_EXIT callback
  • Loading branch information
svasista-ms committed Sep 26, 2024
1 parent 44ce636 commit a70b3ab
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 18 deletions.
2 changes: 1 addition & 1 deletion tools/dv/kmdf/fail_driver_irql_violation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ NOTE: The driver uses WDM's ExAllocatePool2 API directly to allocate memory for
run ```!analyze -v``` for detailed bugcheck report
run ```!verifier 3 fail_driver_irql_violation.sys``` for info on the allocations that were leaked that caused the bugcheck.
11. (Alternatively), the bugcheck can be observed when all the devices managed by this driver are removed, i.e, when the driver is unloaded from the system.
11. (Alternatively), the bugcheck can be observed when a device managed by this driver is removed, i.e, when the EVT_WDF_DEVICE_D0_EXIT callback function is executed.
You may use pnputil/devcon to enumerate and remove the devices -
```
# To enumerate the devices
Expand Down
67 changes: 52 additions & 15 deletions tools/dv/kmdf/fail_driver_irql_violation/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use wdk_sys::{
WDF_NO_HANDLE,
WDF_NO_OBJECT_ATTRIBUTES,
WDF_OBJECT_ATTRIBUTES,
WDF_PNPPOWER_EVENT_CALLBACKS,
_WDF_EXECUTION_LEVEL,
_WDF_SYNCHRONIZATION_SCOPE,
};
Expand Down Expand Up @@ -94,13 +95,19 @@ extern "system" fn driver_entry(
return nt_status;
}

// Allocate non-paged memory pool of 64 bytes (arbitrarily chosen) for the
// Allocate non-paged memory pool of 1 byte (arbitrarily chosen) for the
// Global buffer
unsafe {
const LENGTH: usize = 64;
const LENGTH: usize = 1;
GLOBAL_BUFFER = ExAllocatePool2(POOL_FLAG_NON_PAGED, LENGTH as SIZE_T, 's' as u32);
}

// Initialize a spinlock that can be used to synchronize access to the buffer
if let Err(status) = initialize_spinlock() {
println!("Failed to initialize spinlock: {status:#010X}");
return status;
}

println!("Exit: driver_entry");

nt_status
Expand Down Expand Up @@ -128,6 +135,21 @@ extern "C" fn evt_driver_device_add(

println!("Enter: evt_driver_device_add");

let mut pnp_power_callbacks = WDF_PNPPOWER_EVENT_CALLBACKS {
Size: core::mem::size_of::<WDF_PNPPOWER_EVENT_CALLBACKS>() as ULONG,
EvtDeviceD0Entry: Some(evt_device_d0_entry),
EvtDeviceD0Exit: Some(evt_device_d0_exit),
..WDF_PNPPOWER_EVENT_CALLBACKS::default()
};

let [()] = [unsafe {
macros::call_unsafe_wdf_function_binding!(
WdfDeviceInitSetPnpPowerEventCallbacks,
device_init,
&mut pnp_power_callbacks
);
}];

#[allow(clippy::cast_possible_truncation)]
let mut attributes = WDF_OBJECT_ATTRIBUTES {
Size: core::mem::size_of::<WDF_OBJECT_ATTRIBUTES>() as ULONG,
Expand Down Expand Up @@ -165,11 +187,6 @@ extern "C" fn evt_driver_device_add(
return nt_status;
}

// Initialize spinlock
if let Err(status) = initialize_spinlock() {
println!("Failed to initialize spinlock: {status:#010X}");
}

println!("Exit: evt_driver_device_add");

nt_status
Expand All @@ -191,15 +208,37 @@ extern "C" fn evt_driver_device_add(
extern "C" fn evt_driver_unload(_driver: WDFDRIVER) {
println!("Enter: evt_driver_unload");

unsafe { wdk_sys::ntddk::ExFreePool(GLOBAL_BUFFER) };

println!("Exit: evt_driver_unload");
}

extern "C" fn evt_device_d0_entry(_device: WDFDEVICE, _prev_state: i32) -> i32 {
println!("Enter: evt_device_d0_entry");
unsafe {
if let Some(ref spinlock) = SPINLOCK {
spinlock.acquire();
if !GLOBAL_BUFFER.is_null() {
// Access and modify the global buffer here
println!("Accessing and modifying global buffer");
// Example: Write to the global buffer
core::ptr::write_bytes(GLOBAL_BUFFER, 0, 64);
core::ptr::write_bytes(GLOBAL_BUFFER, 1, 1);
} else {
println!("Global buffer is null");
}
spinlock.release();
} else {
println!("Spinlock is not initialized");
}
}
println!("Exit: evt_device_d0_entry");
0
}

extern "C" fn evt_device_d0_exit(_device: WDFDEVICE, _prev_state: i32) -> i32 {
println!("Enter: evt_device_d0_exit");
unsafe {
if let Some(ref spinlock) = SPINLOCK {
spinlock.acquire();
if !GLOBAL_BUFFER.is_null() {
core::ptr::write_bytes(GLOBAL_BUFFER, 0, 1);
// Illegal call to KeEnterCriticalRegion will lead to a
// violation of 'IrqlKeApcLte2' rule
KeEnterCriticalRegion();
Expand All @@ -211,8 +250,6 @@ extern "C" fn evt_driver_unload(_driver: WDFDRIVER) {
println!("Spinlock is not initialized");
}
}

unsafe { wdk_sys::ntddk::ExFreePool(GLOBAL_BUFFER) };

println!("Exit: evt_driver_unload");
println!("Exit: evt_device_d0_exit");
0
}
4 changes: 2 additions & 2 deletions tools/dv/kmdf/fail_driver_irql_violation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ static mut GLOBAL_BUFFER: PVOID = core::ptr::null_mut();
static mut SPINLOCK: Option<SpinLock> = None;

/// `initialize_spinlock` is called by
fn initialize_spinlock() -> Result<(), usize> {
fn initialize_spinlock() -> Result<(), i32> {
let mut attributes = WDF_OBJECT_ATTRIBUTES {
Size: core::mem::size_of::<WDF_OBJECT_ATTRIBUTES>() as ULONG,
ExecutionLevel: _WDF_EXECUTION_LEVEL::WdfExecutionLevelInheritFromParent,
Expand All @@ -73,7 +73,7 @@ fn initialize_spinlock() -> Result<(), usize> {
match SpinLock::create(&mut attributes) {
Err(status) => {
println!("SpinLock create failed {status:#010X}");
return Err(status as usize);
return Err(status);
}
Ok(spin_lock) => unsafe {
SPINLOCK = Some(spin_lock);
Expand Down

0 comments on commit a70b3ab

Please sign in to comment.