Skip to main content

memf_linux/
lib.rs

1#![deny(unsafe_code)]
2#![warn(missing_docs)]
3#![allow(clippy::manual_let_else)]
4#![allow(clippy::too_many_lines)]
5//! Linux kernel memory forensic walkers.
6//!
7//! Provides process, network connection, and kernel module enumeration
8//! by walking kernel data structures in physical memory dumps.
9
10pub 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;
36/// Linux EFI/VESA linear framebuffer recovery — locates the framebuffer via
37/// `boot_params.screen_info` and encodes the captured screen as PNG.
38pub 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/// Error type for memf-linux operations.
102#[derive(Debug, thiserror::Error)]
103pub enum Error {
104    /// Core memory reading error.
105    #[error("core error: {0}")]
106    Core(#[from] memf_core::Error),
107
108    /// Symbol resolution error.
109    #[error("symbol error: {0}")]
110    Symbol(#[from] memf_symbols::Error),
111
112    /// Walker-specific error.
113    ///
114    /// Prefer [`WalkFailed`] for new code.
115    #[error("walker error: {0}")]
116    Walker(String),
117
118    /// A required kernel symbol was not found in the ISF.
119    #[error("kernel symbol not found: {name}")]
120    MissingKernelSymbol {
121        /// The symbol name that was not found.
122        name: String,
123    },
124
125    /// A required struct field was not found in the ISF.
126    #[error("ISF missing field: {struct_name}.{field_name}")]
127    MissingField {
128        /// The struct type name (e.g. `"task_struct"`).
129        struct_name: String,
130        /// The field name that was not found.
131        field_name: String,
132    },
133
134    /// A walker-specific failure with context.
135    #[error("walker '{walker}' failed: {reason}")]
136    WalkFailed {
137        /// Name of the walker; must be a `'static` string literal.
138        walker: &'static str,
139        /// Human-readable description of the failure.
140        reason: String,
141    },
142
143    /// A list walk failure with context.
144    #[error("list walk failed in walker '{walker}': {reason}")]
145    ListWalkFailed {
146        /// Name of the walker; must be a `'static` string literal.
147        walker: &'static str,
148        /// Human-readable description of the failure.
149        reason: String,
150    },
151}
152
153/// A Result alias for memf-linux.
154pub type Result<T> = std::result::Result<T, Error>;
155
156/// A plugin that walks Linux kernel data structures.
157///
158/// Implementations provide specific enumeration logic (processes,
159/// connections, modules) using an [`ObjectReader`] for memory access.
160pub trait WalkerPlugin: Send + Sync {
161    /// Human-readable name of this walker.
162    fn name(&self) -> &str;
163
164    /// Probe whether this walker can operate on the current memory image.
165    /// Returns a confidence score 0-100.
166    fn probe<P: PhysicalMemoryProvider>(&self, reader: &ObjectReader<P>) -> u8;
167
168    /// Enumerate running processes.
169    fn processes<P: PhysicalMemoryProvider>(
170        &self,
171        reader: &ObjectReader<P>,
172    ) -> Result<Vec<ProcessInfo>>;
173
174    /// Enumerate network connections.
175    fn connections<P: PhysicalMemoryProvider>(
176        &self,
177        reader: &ObjectReader<P>,
178    ) -> Result<Vec<ConnectionInfo>>;
179
180    /// Enumerate loaded kernel modules.
181    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}