memf_linux/
shared_mem_anomaly.rs1use memf_core::object_reader::ObjectReader;
4use memf_format::PhysicalMemoryProvider;
5
6use crate::types::SharedMemAnomalyInfo;
7use crate::Result;
8
9pub fn is_suspicious_shm(nattch: u64, threshold: u64) -> bool {
16 nattch > threshold
17}
18
19pub fn scan_shared_mem_anomalies<P: PhysicalMemoryProvider>(
23 reader: &ObjectReader<P>,
24) -> Result<Vec<SharedMemAnomalyInfo>> {
25 let _ = reader;
26 Ok(vec![])
27}
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32 use memf_core::test_builders::PageTableBuilder;
33 use memf_core::vas::{TranslationMode, VirtualAddressSpace};
34 use memf_symbols::isf::IsfResolver;
35 use memf_symbols::test_builders::IsfBuilder;
36
37 fn make_minimal_reader() -> ObjectReader<memf_core::test_builders::SyntheticPhysMem> {
38 let isf = IsfBuilder::new().build_json();
39 let resolver = IsfResolver::from_value(&isf).unwrap();
40 let (cr3, mem) = PageTableBuilder::new().build();
41 let vas = VirtualAddressSpace::new(mem, cr3, TranslationMode::X86_64FourLevel);
42 ObjectReader::new(vas, Box::new(resolver))
43 }
44
45 #[test]
46 fn empty_memory_returns_ok_empty() {
47 let reader = make_minimal_reader();
48 let result = scan_shared_mem_anomalies(&reader);
49 assert!(result.is_ok(), "should succeed with minimal reader");
50 assert!(
51 result.unwrap().is_empty(),
52 "empty memory → no shared mem anomalies"
53 );
54 }
55
56 #[test]
57 fn result_is_vec_of_shared_mem_anomaly_info() {
58 let reader = make_minimal_reader();
59 let result: Result<Vec<SharedMemAnomalyInfo>> = scan_shared_mem_anomalies(&reader);
60 assert!(result.is_ok());
61 }
62
63 #[test]
64 fn shared_mem_anomaly_info_fields_constructible() {
65 let info = SharedMemAnomalyInfo {
66 pid: 500,
67 comm: "loader".to_string(),
68 shm_base: 0x7f00_0000_0000,
69 shm_size: 65536,
70 is_memfd: true,
71 is_executable: true,
72 is_cross_uid: false,
73 has_elf_header: true,
74 };
75 assert_eq!(info.pid, 500);
76 assert!(info.is_memfd);
77 assert!(info.is_executable);
78 assert!(!info.is_cross_uid);
79 assert!(info.has_elf_header);
80 }
81
82 #[test]
83 fn shared_mem_anomaly_info_serializes() {
84 let info = SharedMemAnomalyInfo {
85 pid: 88,
86 comm: "inject".to_string(),
87 shm_base: 0x1000,
88 shm_size: 4096,
89 is_memfd: false,
90 is_executable: true,
91 is_cross_uid: true,
92 has_elf_header: false,
93 };
94 let json = serde_json::to_string(&info).unwrap();
95 assert!(json.contains("\"pid\":88"));
96 assert!(json.contains("\"is_executable\":true"));
97 assert!(json.contains("\"is_cross_uid\":true"));
98 }
99
100 #[test]
103 fn nattch_above_threshold_is_suspicious_shm() {
104 assert!(is_suspicious_shm(100, 50));
105 }
106
107 #[test]
108 fn nattch_at_threshold_is_not_suspicious() {
109 assert!(!is_suspicious_shm(50, 50));
110 }
111
112 #[test]
113 fn nattch_below_threshold_is_not_suspicious() {
114 assert!(!is_suspicious_shm(10, 50));
115 }
116}