wraith/km/
error.rs

1//! Kernel-mode error types
2
3use core::fmt;
4
5/// NTSTATUS type alias
6pub type NtStatus = i32;
7
8/// kernel-mode specific errors
9#[derive(Debug)]
10pub enum KmError {
11    /// NT status code error
12    NtStatus(NtStatus),
13
14    /// pool allocation failed
15    PoolAllocationFailed {
16        size: usize,
17        pool_type: u32,
18    },
19
20    /// MDL operation failed
21    MdlOperationFailed {
22        reason: &'static str,
23    },
24
25    /// physical memory access failed
26    PhysicalMemoryFailed {
27        address: u64,
28        size: usize,
29    },
30
31    /// virtual memory operation failed
32    VirtualMemoryFailed {
33        address: u64,
34        size: usize,
35        reason: &'static str,
36    },
37
38    /// process operation failed
39    ProcessOperationFailed {
40        pid: u32,
41        reason: &'static str,
42    },
43
44    /// device creation failed
45    DeviceCreationFailed {
46        reason: &'static str,
47    },
48
49    /// symbolic link creation failed
50    SymbolicLinkFailed {
51        reason: &'static str,
52    },
53
54    /// IOCTL operation failed
55    IoctlFailed {
56        code: u32,
57        reason: &'static str,
58    },
59
60    /// invalid parameter
61    InvalidParameter {
62        context: &'static str,
63    },
64
65    /// buffer too small
66    BufferTooSmall {
67        required: usize,
68        provided: usize,
69    },
70
71    /// access denied
72    AccessDenied {
73        context: &'static str,
74    },
75
76    /// invalid address
77    InvalidAddress {
78        address: u64,
79    },
80
81    /// not implemented
82    NotImplemented {
83        feature: &'static str,
84    },
85}
86
87impl fmt::Display for KmError {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        match self {
90            Self::NtStatus(status) => write!(f, "NTSTATUS error: {status:#x}"),
91            Self::PoolAllocationFailed { size, pool_type } => {
92                write!(f, "pool allocation failed: {size} bytes, type {pool_type}")
93            }
94            Self::MdlOperationFailed { reason } => {
95                write!(f, "MDL operation failed: {reason}")
96            }
97            Self::PhysicalMemoryFailed { address, size } => {
98                write!(f, "physical memory access failed at {address:#x} ({size} bytes)")
99            }
100            Self::VirtualMemoryFailed { address, size, reason } => {
101                write!(f, "virtual memory operation failed at {address:#x} ({size} bytes): {reason}")
102            }
103            Self::ProcessOperationFailed { pid, reason } => {
104                write!(f, "process operation failed for PID {pid}: {reason}")
105            }
106            Self::DeviceCreationFailed { reason } => {
107                write!(f, "device creation failed: {reason}")
108            }
109            Self::SymbolicLinkFailed { reason } => {
110                write!(f, "symbolic link creation failed: {reason}")
111            }
112            Self::IoctlFailed { code, reason } => {
113                write!(f, "IOCTL {code:#x} failed: {reason}")
114            }
115            Self::InvalidParameter { context } => {
116                write!(f, "invalid parameter in {context}")
117            }
118            Self::BufferTooSmall { required, provided } => {
119                write!(f, "buffer too small: need {required} bytes, got {provided}")
120            }
121            Self::AccessDenied { context } => {
122                write!(f, "access denied: {context}")
123            }
124            Self::InvalidAddress { address } => {
125                write!(f, "invalid address: {address:#x}")
126            }
127            Self::NotImplemented { feature } => {
128                write!(f, "not implemented: {feature}")
129            }
130        }
131    }
132}
133
134/// result type for kernel operations
135pub type KmResult<T> = core::result::Result<T, KmError>;
136
137/// common NTSTATUS codes
138pub mod status {
139    use super::NtStatus;
140
141    pub const STATUS_SUCCESS: NtStatus = 0;
142    pub const STATUS_UNSUCCESSFUL: NtStatus = 0xC0000001_u32 as i32;
143    pub const STATUS_NOT_IMPLEMENTED: NtStatus = 0xC0000002_u32 as i32;
144    pub const STATUS_INVALID_HANDLE: NtStatus = 0xC0000008_u32 as i32;
145    pub const STATUS_INVALID_PARAMETER: NtStatus = 0xC000000D_u32 as i32;
146    pub const STATUS_NO_SUCH_DEVICE: NtStatus = 0xC000000E_u32 as i32;
147    pub const STATUS_NO_SUCH_FILE: NtStatus = 0xC000000F_u32 as i32;
148    pub const STATUS_ACCESS_DENIED: NtStatus = 0xC0000022_u32 as i32;
149    pub const STATUS_BUFFER_TOO_SMALL: NtStatus = 0xC0000023_u32 as i32;
150    pub const STATUS_OBJECT_NAME_NOT_FOUND: NtStatus = 0xC0000034_u32 as i32;
151    pub const STATUS_OBJECT_NAME_COLLISION: NtStatus = 0xC0000035_u32 as i32;
152    pub const STATUS_INSUFFICIENT_RESOURCES: NtStatus = 0xC000009A_u32 as i32;
153    pub const STATUS_INVALID_DEVICE_REQUEST: NtStatus = 0xC0000010_u32 as i32;
154    pub const STATUS_INFO_LENGTH_MISMATCH: NtStatus = 0xC0000004_u32 as i32;
155    pub const STATUS_PARTIAL_COPY: NtStatus = 0x8000000D_u32 as i32;
156    pub const STATUS_NO_MEMORY: NtStatus = 0xC0000017_u32 as i32;
157
158    /// check if NTSTATUS indicates success
159    #[inline]
160    pub const fn nt_success(status: NtStatus) -> bool {
161        status >= 0
162    }
163
164    /// check if NTSTATUS indicates an informational status
165    #[inline]
166    pub const fn nt_information(status: NtStatus) -> bool {
167        (status as u32) >> 30 == 1
168    }
169
170    /// check if NTSTATUS indicates a warning
171    #[inline]
172    pub const fn nt_warning(status: NtStatus) -> bool {
173        (status as u32) >> 30 == 2
174    }
175
176    /// check if NTSTATUS indicates an error
177    #[inline]
178    pub const fn nt_error(status: NtStatus) -> bool {
179        (status as u32) >> 30 == 3
180    }
181}
182
183impl From<NtStatus> for KmError {
184    fn from(status: NtStatus) -> Self {
185        KmError::NtStatus(status)
186    }
187}
188
189impl KmError {
190    /// convert to NTSTATUS for returning from driver dispatch functions
191    pub fn to_ntstatus(&self) -> NtStatus {
192        match self {
193            Self::NtStatus(s) => *s,
194            Self::PoolAllocationFailed { .. } => status::STATUS_INSUFFICIENT_RESOURCES,
195            Self::MdlOperationFailed { .. } => status::STATUS_UNSUCCESSFUL,
196            Self::PhysicalMemoryFailed { .. } => status::STATUS_ACCESS_DENIED,
197            Self::VirtualMemoryFailed { .. } => status::STATUS_ACCESS_DENIED,
198            Self::ProcessOperationFailed { .. } => status::STATUS_UNSUCCESSFUL,
199            Self::DeviceCreationFailed { .. } => status::STATUS_UNSUCCESSFUL,
200            Self::SymbolicLinkFailed { .. } => status::STATUS_UNSUCCESSFUL,
201            Self::IoctlFailed { .. } => status::STATUS_UNSUCCESSFUL,
202            Self::InvalidParameter { .. } => status::STATUS_INVALID_PARAMETER,
203            Self::BufferTooSmall { .. } => status::STATUS_BUFFER_TOO_SMALL,
204            Self::AccessDenied { .. } => status::STATUS_ACCESS_DENIED,
205            Self::InvalidAddress { .. } => status::STATUS_INVALID_PARAMETER,
206            Self::NotImplemented { .. } => status::STATUS_NOT_IMPLEMENTED,
207        }
208    }
209}