1use memf_core::object_reader::ObjectReader;
4use memf_format::PhysicalMemoryProvider;
5
6use crate::types::FuseAbuseInfo;
7use crate::Result;
8
9pub fn is_suspicious_fuse_mount(uid: u32, is_setuid: bool) -> bool {
15 uid != 0 && is_setuid
16}
17
18pub fn scan_fuse_abuse<P: PhysicalMemoryProvider>(
22 reader: &ObjectReader<P>,
23) -> Result<Vec<FuseAbuseInfo>> {
24 let _ = reader;
25 Ok(vec![])
26}
27
28#[cfg(test)]
29mod tests {
30 use super::*;
31 use memf_core::test_builders::PageTableBuilder;
32 use memf_core::vas::{TranslationMode, VirtualAddressSpace};
33 use memf_symbols::isf::IsfResolver;
34 use memf_symbols::test_builders::IsfBuilder;
35
36 fn make_minimal_reader() -> ObjectReader<memf_core::test_builders::SyntheticPhysMem> {
37 let isf = IsfBuilder::new().build_json();
38 let resolver = IsfResolver::from_value(&isf).unwrap();
39 let (cr3, mem) = PageTableBuilder::new().build();
40 let vas = VirtualAddressSpace::new(mem, cr3, TranslationMode::X86_64FourLevel);
41 ObjectReader::new(vas, Box::new(resolver))
42 }
43
44 #[test]
45 fn empty_memory_returns_ok_empty() {
46 let reader = make_minimal_reader();
47 let result = scan_fuse_abuse(&reader);
48 assert!(result.is_ok(), "should succeed with minimal reader");
49 assert!(
50 result.unwrap().is_empty(),
51 "empty memory → no FUSE abuse hits"
52 );
53 }
54
55 #[test]
56 fn result_is_vec_of_fuse_abuse_info() {
57 let reader = make_minimal_reader();
58 let result: Result<Vec<FuseAbuseInfo>> = scan_fuse_abuse(&reader);
59 assert!(result.is_ok());
60 }
61
62 #[test]
63 fn fuse_abuse_info_fields_constructible() {
64 let info = FuseAbuseInfo {
65 pid: 333,
66 comm: "sshfs".to_string(),
67 mount_point: "/proc".to_string(),
68 is_over_sensitive_path: true,
69 daemon_is_root: true,
70 allow_other: true,
71 };
72 assert_eq!(info.pid, 333);
73 assert_eq!(info.mount_point, "/proc");
74 assert!(info.is_over_sensitive_path);
75 assert!(info.allow_other);
76 }
77
78 #[test]
79 fn fuse_abuse_info_serializes() {
80 let info = FuseAbuseInfo {
81 pid: 1,
82 comm: "fusermount".to_string(),
83 mount_point: "/etc".to_string(),
84 is_over_sensitive_path: true,
85 daemon_is_root: false,
86 allow_other: false,
87 };
88 let json = serde_json::to_string(&info).unwrap();
89 assert!(json.contains("\"pid\":1"));
90 assert!(json.contains("/etc"));
91 assert!(json.contains("\"is_over_sensitive_path\":true"));
92 }
93
94 #[test]
97 fn non_root_uid_with_setuid_is_suspicious_fuse_mount() {
98 assert!(is_suspicious_fuse_mount(1000, true));
100 }
101
102 #[test]
103 fn root_uid_with_setuid_is_not_suspicious() {
104 assert!(!is_suspicious_fuse_mount(0, true));
105 }
106
107 #[test]
108 fn non_root_uid_without_setuid_is_not_suspicious() {
109 assert!(!is_suspicious_fuse_mount(1000, false));
110 }
111}