Files
portmaster/windows_kext/wdk/src/irp_helpers.rs
2024-06-28 16:12:07 +03:00

199 lines
5.5 KiB
Rust

use windows_sys::{
Wdk::{
Foundation::{IO_STACK_LOCATION_0_4, IRP},
Storage::FileSystem::IO_NO_INCREMENT,
System::SystemServices::IofCompleteRequest,
},
Win32::Foundation::{
NTSTATUS, STATUS_END_OF_FILE, STATUS_NOT_IMPLEMENTED, STATUS_SUCCESS, STATUS_TIMEOUT,
},
};
pub struct ReadRequest<'a> {
irp: &'a mut IRP,
buffer: &'a mut [u8],
fill_index: usize,
}
impl ReadRequest<'_> {
pub fn new(irp: &mut IRP) -> ReadRequest {
unsafe {
let irp_sp = irp.Tail.Overlay.Anonymous2.Anonymous.CurrentStackLocation;
let device_io = (*irp_sp).Parameters.Read;
let system_buffer = irp.AssociatedIrp.SystemBuffer;
let buffer = core::slice::from_raw_parts_mut(
system_buffer as *mut u8,
device_io.Length as usize,
);
ReadRequest {
irp,
buffer,
fill_index: 0,
}
}
}
pub fn free_space(&self) -> usize {
self.buffer.len() - self.fill_index
}
pub fn complete(&mut self) {
self.irp.IoStatus.Information = self.fill_index;
self.irp.IoStatus.Anonymous.Status = STATUS_SUCCESS;
}
pub fn end_of_file(&mut self) {
self.irp.IoStatus.Information = self.fill_index;
self.irp.IoStatus.Anonymous.Status = STATUS_END_OF_FILE;
}
pub fn timeout(&mut self) {
self.irp.IoStatus.Anonymous.Status = STATUS_TIMEOUT;
}
pub fn get_status(&self) -> NTSTATUS {
unsafe { self.irp.IoStatus.Anonymous.Status }
}
pub fn write(&mut self, bytes: &[u8]) -> usize {
let mut bytes_to_write: usize = bytes.len();
// Check if we have enough space
if bytes_to_write > self.free_space() {
bytes_to_write = self.free_space();
}
for i in 0..bytes_to_write {
self.buffer[self.fill_index + i] = bytes[i];
}
self.fill_index += bytes_to_write;
bytes_to_write
}
}
pub struct WriteRequest<'a> {
irp: &'a mut IRP,
buffer: &'a mut [u8],
}
impl WriteRequest<'_> {
pub fn new(irp: &mut IRP) -> WriteRequest {
unsafe {
let irp_sp = irp.Tail.Overlay.Anonymous2.Anonymous.CurrentStackLocation;
let device_io = (*irp_sp).Parameters.Write;
let system_buffer = irp.AssociatedIrp.SystemBuffer;
let buffer = core::slice::from_raw_parts_mut(
system_buffer as *mut u8,
device_io.Length as usize,
);
WriteRequest { irp, buffer }
}
}
pub fn get_buffer(&self) -> &[u8] {
self.buffer
}
pub fn mark_all_as_read(&mut self) {
self.irp.IoStatus.Information = self.buffer.len();
}
pub fn complete(&mut self) {
self.irp.IoStatus.Anonymous.Status = STATUS_SUCCESS;
}
pub fn get_status(&self) -> NTSTATUS {
unsafe { self.irp.IoStatus.Anonymous.Status }
}
}
pub struct DeviceControlRequest<'a> {
irp: &'a mut IRP,
buffer: &'a mut [u8],
fill_index: usize,
control_code: u32,
}
// Windows-rs version of the struct is incorrect (18.01.2024).
// TODO: Use the official version when fixed.
// For future reference: https://github.com/microsoft/windows-rs/issues/2805
#[repr(C)]
struct DeviceIOControlParams {
output_buffer_length: u32,
_padding1: u32,
input_buffer_length: u32,
_padding2: u32,
io_control_code: u32,
_padding3: u32,
}
impl DeviceControlRequest<'_> {
pub fn new(irp: &mut IRP) -> DeviceControlRequest {
unsafe {
let irp_sp = irp.Tail.Overlay.Anonymous2.Anonymous.CurrentStackLocation;
// Use the struct directly when replaced with proper version.
let device_io: DeviceIOControlParams =
core::mem::transmute::<IO_STACK_LOCATION_0_4, DeviceIOControlParams>(
(*irp_sp).Parameters.DeviceIoControl,
);
let system_buffer = irp.AssociatedIrp.SystemBuffer;
let buffer = core::slice::from_raw_parts_mut(
system_buffer as *mut u8,
device_io.output_buffer_length as usize,
);
DeviceControlRequest {
irp,
buffer,
fill_index: 0,
control_code: device_io.io_control_code,
}
}
}
pub fn get_buffer(&self) -> &[u8] {
self.buffer
}
pub fn write(&mut self, bytes: &[u8]) -> usize {
let mut bytes_to_write: usize = bytes.len();
// Check if we have enough space
if bytes_to_write > self.free_space() {
bytes_to_write = self.free_space();
}
for i in 0..bytes_to_write {
self.buffer[self.fill_index + i] = bytes[i];
}
self.fill_index += bytes_to_write;
bytes_to_write
}
pub fn complete(&mut self) {
self.irp.IoStatus.Information = self.buffer.len();
self.irp.IoStatus.Anonymous.Status = STATUS_SUCCESS;
unsafe { IofCompleteRequest(self.irp, IO_NO_INCREMENT as i8) };
}
pub fn not_implemented(&mut self) {
self.irp.IoStatus.Anonymous.Status = STATUS_NOT_IMPLEMENTED;
unsafe { IofCompleteRequest(self.irp, IO_NO_INCREMENT as i8) };
}
pub fn get_status(&self) -> NTSTATUS {
unsafe { self.irp.IoStatus.Anonymous.Status }
}
pub fn get_control_code(&self) -> u32 {
self.control_code
}
pub fn free_space(&self) -> usize {
self.buffer.len() - self.fill_index
}
}