Skip to main content

hematite/tools/
hardening.rs

1#[cfg(unix)]
2use std::ffi::OsString;
3#[cfg(unix)]
4use std::os::unix::ffi::OsStrExt;
5
6/// Per-main process hardening steps:
7/// - Disables core dumps (to protect model weights/memory).
8/// - Disables ptrace attach on Linux/macOS (prevents memory sniffing).
9/// - Sanitizes dangerous environment variables (LD_PRELOAD, etc).
10pub fn pre_main_hardening() {
11    #[cfg(any(target_os = "linux", target_os = "macos"))]
12    pre_main_hardening_unix();
13
14    #[cfg(windows)]
15    pre_main_hardening_windows();
16}
17
18#[cfg(any(target_os = "linux", target_os = "macos"))]
19fn pre_main_hardening_unix() {
20    // 1. Disable core dumps
21    let rlim = libc::rlimit {
22        rlim_cur: 0,
23        rlim_max: 0,
24    };
25    unsafe {
26        libc::setrlimit(libc::RLIMIT_CORE, &rlim);
27    }
28
29    // 2. Disable ptrace (Anti-Debugging)
30    #[cfg(target_os = "macos")]
31    unsafe {
32        // PT_DENY_ATTACH = 31
33        libc::ptrace(31, 0, std::ptr::null_mut(), 0);
34    }
35    #[cfg(target_os = "linux")]
36    unsafe {
37        // PR_SET_DUMPABLE = 4
38        libc::prctl(4, 0, 0, 0, 0);
39    }
40
41    // 3. Sanitize Environment
42    remove_env_vars_with_prefix("LD_");
43    remove_env_vars_with_prefix("DYLD_");
44    remove_env_vars_with_prefix("MallocStackLogging");
45}
46
47#[cfg(windows)]
48fn pre_main_hardening_windows() {
49    // Windows Phase 1: Environment sanitization for risky shells
50    // (Note: LD_PRELOAD is Unix-only, but we clear it here in case of cross-platform shells)
51    let risky_prefixes = ["LD_", "DYLD_"];
52    for prefix in risky_prefixes {
53        for (key, _) in std::env::vars() {
54            if key.starts_with(prefix) {
55                std::env::remove_var(key);
56            }
57        }
58    }
59}
60
61#[cfg(unix)]
62fn remove_env_vars_with_prefix(prefix: &str) {
63    let prefix_bytes = prefix.as_bytes();
64    let keys_to_remove: Vec<OsString> = std::env::vars_os()
65        .filter_map(|(key, _)| {
66            if key.as_os_str().as_bytes().starts_with(prefix_bytes) {
67                Some(key)
68            } else {
69                None
70            }
71        })
72        .collect();
73
74    for key in keys_to_remove {
75        std::env::remove_var(key);
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn test_env_sanitization_prefixes() {
85        std::env::set_var("LD_TEST_LOG", "1");
86        std::env::set_var("DYLD_LIBRARY_PATH", "/tmp");
87        std::env::set_var("SAFE_VAR", "preserved");
88
89        // Use the platform-specific internal helper or the main entry
90        pre_main_hardening();
91
92        assert!(std::env::var("LD_TEST_LOG").is_err());
93        assert!(std::env::var("DYLD_LIBRARY_PATH").is_err());
94        assert_eq!(std::env::var("SAFE_VAR").unwrap(), "preserved");
95    }
96}