1use crate::consts::*;
7use crate::error::{Error, Result};
8use crate::proc_event::ProcEvent;
9
10#[inline]
16fn read_u32(buf: &[u8], off: usize) -> u32 {
17 let arr: [u8; 4] = buf[off..off + 4].try_into().unwrap();
18 u32::from_ne_bytes(arr)
19}
20
21#[inline]
23fn read_u16(buf: &[u8], off: usize) -> u16 {
24 let arr: [u8; 2] = buf[off..off + 2].try_into().unwrap();
25 u16::from_ne_bytes(arr)
26}
27
28#[inline]
30fn read_i32(buf: &[u8], off: usize) -> i32 {
31 let arr: [u8; 4] = buf[off..off + 4].try_into().unwrap();
32 i32::from_ne_bytes(arr)
33}
34
35#[inline]
37fn read_u64(buf: &[u8], off: usize) -> u64 {
38 let arr: [u8; 8] = buf[off..off + 8].try_into().unwrap();
39 u64::from_ne_bytes(arr)
40}
41
42pub fn parse_netlink_message(payload: &[u8], len: usize) -> Result<Option<ProcEvent>> {
77 if len > payload.len() {
78 return Err(Error::Truncated);
79 }
80 let payload = &payload[..len];
81
82 if payload.len() < SIZE_NLMSGHDR {
83 return Err(Error::Truncated);
84 }
85
86 let nlmsg_type = read_u16(payload, 4);
87 let nlmsg_len = read_u32(payload, 0) as usize;
88
89 if nlmsg_len > payload.len() {
90 return Err(Error::Truncated);
91 }
92
93 match nlmsg_type {
94 NLMSG_NOOP => Ok(None),
95 NLMSG_DONE if nlmsg_len == SIZE_NLMSGHDR => Ok(None),
96 NLMSG_ERROR => {
97 if payload.len() < SIZE_NLMSGERR {
98 return Err(Error::Truncated);
99 }
100 let errno = read_i32(payload, SIZE_NLMSGHDR);
101 if errno == 0 {
102 return Ok(None);
104 }
105 let pos_errno = errno.checked_neg().unwrap_or(errno);
108 Err(Error::Os(std::io::Error::from_raw_os_error(pos_errno)))
109 }
110 NLMSG_OVERRUN => Err(Error::Overrun),
111 _ => {
112 let cn_offset = nlmsg_hdrlen();
115 if nlmsg_len < cn_offset {
116 return Err(Error::Truncated);
117 }
118 let cn_payload = &payload[cn_offset..nlmsg_len];
119 parse_cn_msg(cn_payload).map(Some)
120 }
121 }
122}
123
124pub fn parse_cn_msg(buf: &[u8]) -> Result<ProcEvent> {
141 if buf.len() < SIZE_CN_MSG {
142 return Err(Error::Truncated);
143 }
144
145 let idx = read_u32(buf, 0);
146 let val = read_u32(buf, 4);
147
148 if idx != CN_IDX_PROC || val != CN_VAL_PROC {
150 return Err(Error::UnexpectedConnector);
151 }
152
153 let data_len = read_u16(buf, 16) as usize;
154
155 let proc_off = SIZE_CN_MSG;
157 let proc_data = if buf.len() >= proc_off + data_len {
158 &buf[proc_off..proc_off + data_len]
159 } else {
160 return Err(Error::Truncated);
161 };
162
163 parse_proc_event(proc_data)
164}
165
166fn parse_proc_event(buf: &[u8]) -> Result<ProcEvent> {
168 if buf.len() < PROC_EVENT_HEADER_SIZE {
169 return Err(Error::Truncated);
170 }
171
172 let what = read_u32(buf, 0);
173 let cpu = read_u32(buf, 4);
174 let timestamp_ns = read_u64(buf, 8);
175 let data = &buf[PROC_EVENT_HEADER_SIZE..];
176
177 build_proc_event(what, cpu, timestamp_ns, data)
178}
179
180fn build_proc_event(what: u32, cpu: u32, timestamp_ns: u64, data: &[u8]) -> Result<ProcEvent> {
181 match what {
182 PROC_EVENT_EXEC => {
183 if data.len() < SIZE_EXEC_EVENT {
184 return Err(Error::Truncated);
185 }
186 Ok(ProcEvent::Exec {
187 cpu,
188 pid: read_i32(data, EXEC_PID) as u32,
189 tgid: read_i32(data, EXEC_TGID) as u32,
190 timestamp_ns,
191 })
192 }
193
194 PROC_EVENT_FORK => {
195 if data.len() < SIZE_FORK_EVENT {
196 return Err(Error::Truncated);
197 }
198 Ok(ProcEvent::Fork {
199 cpu,
200 parent_pid: read_i32(data, FORK_PARENT_PID) as u32,
201 parent_tgid: read_i32(data, FORK_PARENT_TGID) as u32,
202 child_pid: read_i32(data, FORK_CHILD_PID) as u32,
203 child_tgid: read_i32(data, FORK_CHILD_TGID) as u32,
204 timestamp_ns,
205 })
206 }
207
208 PROC_EVENT_EXIT => {
209 if data.len() < SIZE_EXIT_EVENT {
210 return Err(Error::Truncated);
211 }
212 Ok(ProcEvent::Exit {
213 cpu,
214 pid: read_i32(data, EXIT_PID) as u32,
215 tgid: read_i32(data, EXIT_TGID) as u32,
216 exit_code: read_u32(data, EXIT_CODE),
217 exit_signal: read_u32(data, EXIT_SIGNAL),
218 parent_pid: read_i32(data, EXIT_PARENT_PID) as u32,
219 parent_tgid: read_i32(data, EXIT_PARENT_TGID) as u32,
220 timestamp_ns,
221 })
222 }
223
224 PROC_EVENT_UID => {
225 if data.len() < SIZE_ID_EVENT {
226 return Err(Error::Truncated);
227 }
228 Ok(ProcEvent::Uid {
229 cpu,
230 pid: read_i32(data, ID_PID) as u32,
231 tgid: read_i32(data, ID_TGID) as u32,
232 ruid: read_u32(data, ID_RUID_RGID),
233 euid: read_u32(data, ID_EUID_EGID),
234 timestamp_ns,
235 })
236 }
237
238 PROC_EVENT_GID => {
239 if data.len() < SIZE_ID_EVENT {
240 return Err(Error::Truncated);
241 }
242 Ok(ProcEvent::Gid {
243 cpu,
244 pid: read_i32(data, ID_PID) as u32,
245 tgid: read_i32(data, ID_TGID) as u32,
246 rgid: read_u32(data, ID_RUID_RGID),
247 egid: read_u32(data, ID_EUID_EGID),
248 timestamp_ns,
249 })
250 }
251
252 PROC_EVENT_SID => {
253 if data.len() < SIZE_SID_EVENT {
254 return Err(Error::Truncated);
255 }
256 Ok(ProcEvent::Sid {
257 cpu,
258 pid: read_i32(data, SID_PID) as u32,
259 tgid: read_i32(data, SID_TGID) as u32,
260 timestamp_ns,
261 })
262 }
263
264 PROC_EVENT_PTRACE => {
265 if data.len() < SIZE_PTRACE_EVENT {
266 return Err(Error::Truncated);
267 }
268 Ok(ProcEvent::Ptrace {
269 cpu,
270 pid: read_i32(data, PTRACE_PID) as u32,
271 tgid: read_i32(data, PTRACE_TGID) as u32,
272 tracer_pid: read_i32(data, PTRACE_TRACER_PID) as u32,
273 tracer_tgid: read_i32(data, PTRACE_TRACER_TGID) as u32,
274 timestamp_ns,
275 })
276 }
277
278 PROC_EVENT_COMM => {
279 if data.len() < SIZE_COMM_EVENT {
280 return Err(Error::Truncated);
281 }
282 let mut comm = [0u8; 16];
283 comm.copy_from_slice(&data[COMM_DATA..COMM_DATA + 16]);
284 Ok(ProcEvent::Comm {
285 cpu,
286 pid: read_i32(data, COMM_PID) as u32,
287 tgid: read_i32(data, COMM_TGID) as u32,
288 comm,
289 timestamp_ns,
290 })
291 }
292
293 PROC_EVENT_COREDUMP => {
294 if data.len() < SIZE_COREDUMP_EVENT {
295 return Err(Error::Truncated);
296 }
297 Ok(ProcEvent::Coredump {
298 cpu,
299 pid: read_i32(data, COREDUMP_PID) as u32,
300 tgid: read_i32(data, COREDUMP_TGID) as u32,
301 parent_pid: read_i32(data, COREDUMP_PARENT_PID) as u32,
302 parent_tgid: read_i32(data, COREDUMP_PARENT_TGID) as u32,
303 timestamp_ns,
304 })
305 }
306
307 _ => Ok(ProcEvent::Unknown {
308 what,
309 raw_data: data.to_vec(),
310 }),
311 }
312}
313
314pub fn first_event_from_buf(buf: &[u8], n: usize) -> Result<Option<ProcEvent>> {
320 let iter = crate::iter::NetlinkMessageIter::new(buf, n);
321 for msg in iter {
322 match msg? {
323 Some(event) => return Ok(Some(event)),
324 None => continue,
325 }
326 }
327 Ok(None)
328}