1#![deny(unsafe_code)]
2#![warn(missing_docs)]
3#![allow(clippy::manual_let_else)]
4#![allow(clippy::too_many_lines)]
5pub mod arp;
11pub mod bash;
12pub mod bash_history;
13pub mod boot_time;
14pub mod bpf;
15pub mod capabilities;
16pub mod cgroups;
17pub mod check_afinfo;
18pub mod check_creds;
19pub mod check_fops;
20pub mod check_hooks;
21pub mod check_idt;
22pub mod check_modules;
23pub mod cmdline;
24pub mod container_escape;
25pub mod correlate;
26pub mod cpu_pinning;
27pub mod crontab;
28pub mod deleted_exe;
29pub mod dentry_cache;
30pub mod dmesg;
31pub mod ebpf_progs;
32pub mod elf_analysis;
33pub mod elfinfo;
34pub mod envvars;
35pub mod files;
36pub mod framebuffer;
39pub mod fs;
40pub mod ftrace;
41pub mod fuse_abuse;
42pub mod futex_forensics;
43pub mod heuristics;
44pub mod io_uring;
45pub mod iomem;
46pub mod ipc;
47pub mod kaslr;
48pub mod kernel_timers;
49pub mod keyboard_notifiers;
50pub mod kmsg;
51pub mod kthread;
52pub mod ld_preload;
53pub mod library_list;
54pub mod magic_gid;
55pub mod malfind;
56pub mod maps;
57pub mod memfd_create;
58pub mod modules;
59pub mod modxview;
60pub mod mountinfo;
61pub mod namespaces;
62pub mod netfilter;
63pub mod netlink_audit;
64pub mod network;
65pub mod oom_events;
66pub mod pam_hooks;
67pub mod perf_event;
68pub mod preload_scanner;
69pub mod proc_cmdline;
70pub mod proc_hidden;
71pub mod process;
72pub mod psaux;
73pub mod psxview;
74pub mod ptrace;
75pub mod raw_sockets;
76pub mod seccomp;
77pub mod shared_mem_anomaly;
78pub mod signal_handlers;
79pub mod ssh_keys;
80pub mod syscalls;
81pub mod systemd_units;
82pub mod thread;
83pub mod timerfd_signalfd;
84pub mod tmpfs_recovery;
85pub mod tty_check;
86pub mod types;
87pub mod unix_sockets;
88pub mod user_ns_escalation;
89pub mod vdso_tamper;
90pub mod vma_walker;
91pub mod zombie_orphan;
92
93#[cfg(test)]
94pub mod testing;
95
96use memf_core::object_reader::ObjectReader;
97use memf_format::PhysicalMemoryProvider;
98
99pub use types::*;
100
101#[derive(Debug, thiserror::Error)]
103pub enum Error {
104 #[error("core error: {0}")]
106 Core(#[from] memf_core::Error),
107
108 #[error("symbol error: {0}")]
110 Symbol(#[from] memf_symbols::Error),
111
112 #[error("walker error: {0}")]
116 Walker(String),
117
118 #[error("kernel symbol not found: {name}")]
120 MissingKernelSymbol {
121 name: String,
123 },
124
125 #[error("ISF missing field: {struct_name}.{field_name}")]
127 MissingField {
128 struct_name: String,
130 field_name: String,
132 },
133
134 #[error("walker '{walker}' failed: {reason}")]
136 WalkFailed {
137 walker: &'static str,
139 reason: String,
141 },
142
143 #[error("list walk failed in walker '{walker}': {reason}")]
145 ListWalkFailed {
146 walker: &'static str,
148 reason: String,
150 },
151}
152
153pub type Result<T> = std::result::Result<T, Error>;
155
156pub trait WalkerPlugin: Send + Sync {
161 fn name(&self) -> &str;
163
164 fn probe<P: PhysicalMemoryProvider>(&self, reader: &ObjectReader<P>) -> u8;
167
168 fn processes<P: PhysicalMemoryProvider>(
170 &self,
171 reader: &ObjectReader<P>,
172 ) -> Result<Vec<ProcessInfo>>;
173
174 fn connections<P: PhysicalMemoryProvider>(
176 &self,
177 reader: &ObjectReader<P>,
178 ) -> Result<Vec<ConnectionInfo>>;
179
180 fn modules<P: PhysicalMemoryProvider>(
182 &self,
183 reader: &ObjectReader<P>,
184 ) -> Result<Vec<ModuleInfo>>;
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn error_display() {
193 let e = Error::Walker("test error".into());
194 assert_eq!(e.to_string(), "walker error: test error");
195 }
196
197 #[test]
198 fn error_missing_kernel_symbol_contains_name() {
199 let e = Error::MissingKernelSymbol {
200 name: "init_task".to_owned(),
201 };
202 assert!(e.to_string().contains("init_task"));
203 }
204
205 #[test]
206 fn error_missing_field_contains_struct_and_field() {
207 let e = Error::MissingField {
208 struct_name: "task_struct".to_owned(),
209 field_name: "mm".to_owned(),
210 };
211 assert!(e.to_string().contains("task_struct"));
212 assert!(e.to_string().contains("mm"));
213 }
214
215 #[test]
216 fn error_walk_failed_contains_walker_name() {
217 let e = Error::WalkFailed {
218 walker: "walk_processes",
219 reason: "list corrupted".to_owned(),
220 };
221 assert!(e.to_string().contains("walk_processes"));
222 assert!(e.to_string().contains("list corrupted"));
223 }
224
225 #[test]
226 fn error_list_walk_failed_contains_walker_and_reason() {
227 let e = Error::ListWalkFailed {
228 walker: "walk_processes",
229 reason: "cycle detected".to_owned(),
230 };
231 assert!(e.to_string().contains("walk_processes"));
232 assert!(e.to_string().contains("cycle detected"));
233 }
234}