memf_linux/
timerfd_signalfd.rs1use memf_core::object_reader::ObjectReader;
4use memf_format::PhysicalMemoryProvider;
5
6use crate::types::FdAbuseInfo;
7use crate::Result;
8
9pub fn is_suspicious_fd_count(count: usize, threshold: usize) -> bool {
16 count > threshold
17}
18
19pub fn scan_fd_abuse<P: PhysicalMemoryProvider>(
23 reader: &ObjectReader<P>,
24) -> Result<Vec<FdAbuseInfo>> {
25 let _ = reader;
26 Ok(vec![])
27}
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32 use crate::types::FdAbuseType;
33 use memf_core::test_builders::PageTableBuilder;
34 use memf_core::vas::{TranslationMode, VirtualAddressSpace};
35 use memf_symbols::isf::IsfResolver;
36 use memf_symbols::test_builders::IsfBuilder;
37
38 fn make_minimal_reader() -> ObjectReader<memf_core::test_builders::SyntheticPhysMem> {
39 let isf = IsfBuilder::new().build_json();
40 let resolver = IsfResolver::from_value(&isf).unwrap();
41 let (cr3, mem) = PageTableBuilder::new().build();
42 let vas = VirtualAddressSpace::new(mem, cr3, TranslationMode::X86_64FourLevel);
43 ObjectReader::new(vas, Box::new(resolver))
44 }
45
46 #[test]
47 fn empty_memory_returns_ok_empty() {
48 let reader = make_minimal_reader();
49 let result = scan_fd_abuse(&reader);
50 assert!(result.is_ok(), "should succeed with minimal reader");
51 assert!(
52 result.unwrap().is_empty(),
53 "empty memory → no fd abuse hits"
54 );
55 }
56
57 #[test]
58 fn result_is_vec_of_fd_abuse_info() {
59 let reader = make_minimal_reader();
60 let result: Result<Vec<FdAbuseInfo>> = scan_fd_abuse(&reader);
61 assert!(result.is_ok());
62 }
63
64 #[test]
65 fn fd_abuse_info_timerfd_constructible() {
66 let info = FdAbuseInfo {
67 pid: 200,
68 comm: "evil_timer".to_string(),
69 fd_type: FdAbuseType::TimerFd,
70 signal_mask: 0,
71 interval_ns: 1_000_000_000,
72 is_cross_process_shared: false,
73 };
74 assert_eq!(info.pid, 200);
75 assert_eq!(info.fd_type, FdAbuseType::TimerFd);
76 assert_eq!(info.interval_ns, 1_000_000_000);
77 }
78
79 #[test]
80 fn fd_abuse_info_signalfd_constructible() {
81 let info = FdAbuseInfo {
82 pid: 300,
83 comm: "sigmon".to_string(),
84 fd_type: FdAbuseType::SignalFd,
85 signal_mask: 0b1100,
86 interval_ns: 0,
87 is_cross_process_shared: true,
88 };
89 assert_eq!(info.fd_type, FdAbuseType::SignalFd);
90 assert_eq!(info.signal_mask, 0b1100);
91 assert!(info.is_cross_process_shared);
92 }
93
94 #[test]
95 fn fd_abuse_info_serializes() {
96 let info = FdAbuseInfo {
97 pid: 7,
98 comm: "efd".to_string(),
99 fd_type: FdAbuseType::EventFd,
100 signal_mask: 0,
101 interval_ns: 0,
102 is_cross_process_shared: false,
103 };
104 let json = serde_json::to_string(&info).unwrap();
105 assert!(json.contains("\"pid\":7"));
106 assert!(json.contains("EventFd"));
107 }
108
109 #[test]
112 fn fd_count_above_threshold_is_suspicious() {
113 assert!(is_suspicious_fd_count(101, 100));
114 }
115
116 #[test]
117 fn fd_count_at_threshold_is_not_suspicious() {
118 assert!(!is_suspicious_fd_count(100, 100));
119 }
120
121 #[test]
122 fn fd_count_below_threshold_is_not_suspicious() {
123 assert!(!is_suspicious_fd_count(5, 100));
124 }
125}