#![allow(dead_code, unused_imports, unused_qualifications, unreachable_patterns)]
pub fn harden_process() {
disable_core_dumps();
#[cfg(target_os = "linux")]
{
set_dumpable_zero();
set_no_new_privs();
}
#[cfg(target_os = "windows")]
{
apply_windows_mitigations();
}
}
#[cfg(unix)]
fn disable_core_dumps() {
#[allow(unsafe_code)]
{
let rlimit = libc::rlimit {
rlim_cur: 0,
rlim_max: 0,
};
let result = unsafe { libc::setrlimit(libc::RLIMIT_CORE, &rlimit) };
if result != 0 {
tracing::warn!(
"failed to disable core dumps: {}",
std::io::Error::last_os_error()
);
}
}
}
#[cfg(not(unix))]
fn disable_core_dumps() {
}
#[cfg(target_os = "linux")]
#[allow(unsafe_code)]
fn set_dumpable_zero() {
let result = unsafe { libc::prctl(libc::PR_SET_DUMPABLE, 0_u64, 0, 0, 0) };
if result != 0 {
tracing::warn!(
"failed to set PR_SET_DUMPABLE=0: {}",
std::io::Error::last_os_error()
);
}
}
#[cfg(target_os = "linux")]
#[allow(unsafe_code)]
fn set_no_new_privs() {
let result = unsafe { libc::prctl(libc::PR_SET_NO_NEW_PRIVS, 1_u64, 0, 0, 0) };
if result != 0 {
tracing::warn!(
"failed to set PR_SET_NO_NEW_PRIVS=1: {}",
std::io::Error::last_os_error()
);
}
}
#[cfg(target_os = "windows")]
#[allow(unsafe_code)]
fn apply_windows_mitigations() {
use windows::Win32::System::SystemServices::{
PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY, PROCESS_MITIGATION_IMAGE_LOAD_POLICY,
PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY,
};
use windows::Win32::System::Threading::{
ProcessExtensionPointDisablePolicy, ProcessImageLoadPolicy, ProcessStrictHandleCheckPolicy,
SetProcessMitigationPolicy,
};
let mut strict = PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY::default();
unsafe {
strict.Anonymous.Flags = 0b11;
if let Err(e) = SetProcessMitigationPolicy(
ProcessStrictHandleCheckPolicy,
std::ptr::addr_of!(strict).cast(),
size_of::<PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY>(),
) {
tracing::warn!("SetProcessMitigationPolicy(StrictHandleCheck) failed: {e}");
}
}
let mut extpt = PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY::default();
unsafe {
extpt.Anonymous.Flags = 0b1;
if let Err(e) = SetProcessMitigationPolicy(
ProcessExtensionPointDisablePolicy,
std::ptr::addr_of!(extpt).cast(),
size_of::<PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY>(),
) {
tracing::warn!("SetProcessMitigationPolicy(ExtensionPointDisable) failed: {e}");
}
}
let mut imgload = PROCESS_MITIGATION_IMAGE_LOAD_POLICY::default();
unsafe {
imgload.Anonymous.Flags = 0b11;
if let Err(e) = SetProcessMitigationPolicy(
ProcessImageLoadPolicy,
std::ptr::addr_of!(imgload).cast(),
size_of::<PROCESS_MITIGATION_IMAGE_LOAD_POLICY>(),
) {
tracing::warn!("SetProcessMitigationPolicy(ImageLoad) failed: {e}");
}
}
}
#[cfg(unix)]
#[allow(unsafe_code)]
pub fn mlock_buffer(ptr: *const u8, len: usize) -> bool {
if len == 0 {
return true;
}
unsafe { libc::mlock(ptr.cast::<libc::c_void>(), len) == 0 }
}
#[cfg(unix)]
#[allow(unsafe_code)]
pub fn munlock_buffer(ptr: *const u8, len: usize) -> bool {
if len == 0 {
return true;
}
unsafe { libc::munlock(ptr.cast::<libc::c_void>(), len) == 0 }
}
#[cfg(not(unix))]
pub fn mlock_buffer(_ptr: *const u8, len: usize) -> bool {
len == 0
}
#[cfg(not(unix))]
pub fn munlock_buffer(_ptr: *const u8, len: usize) -> bool {
len == 0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn harden_process_does_not_panic() {
harden_process();
}
#[cfg(unix)]
#[test]
fn core_dumps_are_disabled() {
disable_core_dumps();
let mut rlimit = libc::rlimit {
rlim_cur: 999,
rlim_max: 999,
};
#[allow(unsafe_code)]
unsafe {
libc::getrlimit(libc::RLIMIT_CORE, &mut rlimit);
}
assert_eq!(rlimit.rlim_cur, 0);
}
#[test]
fn mlock_empty_buffer() {
assert!(mlock_buffer(std::ptr::null(), 0));
}
#[test]
fn munlock_empty_buffer() {
assert!(munlock_buffer(std::ptr::null(), 0));
}
#[cfg(unix)]
#[test]
fn mlock_buffer_nonzero_length_does_not_panic() {
let data = [0_u8; 64];
let _result = mlock_buffer(data.as_ptr(), data.len());
}
#[cfg(unix)]
#[test]
fn munlock_after_mlock_does_not_panic() {
let data = [0_u8; 64];
if mlock_buffer(data.as_ptr(), data.len()) {
assert!(munlock_buffer(data.as_ptr(), data.len()));
}
}
}