| Crates.io | os-memlock |
| lib.rs | os-memlock |
| version | 0.2.0 |
| created_at | 2025-10-02 17:28:07.60378+00 |
| updated_at | 2025-10-03 13:53:31.188739+00 |
| description | Unsafe thin wrappers around OS memory locking syscalls (mlock/munlock/madvise) |
| homepage | https://github.com/thatnewyorker/os-memlock |
| repository | https://github.com/thatnewyorker/os-memlock |
| max_upload_size | |
| id | 1864716 |
| size | 77,545 |
Quick links:
The detailed guide covers:
Small, focused crate providing thin, unsafe wrappers around OS memory-locking syscalls:
mlock / munlock (prevent swapping)madvise_dontdump (best-effort exclusion from core dumps: Linux MADV_DONTDUMP, FreeBSD MADV_NOCORE)This crate isolates the minimal unsafe FFI surface so higher-level modules can remain
#![forbid(unsafe_code)]. The public functions are intentionally unsafe to make
pointer-safety obligations explicit to callers.
unsafe and FFI details in a single, well-documented crate so the rest of
the codebase can use a safe abstraction that validates inputs before calling into this
crate when appropriate.The crate re-exports the platform-specific implementations at the crate root:
unsafe fn mlock(addr: *const std::os::raw::c_void, len: usize) -> std::io::Result<()>
Err(io::ErrorKind::Unsupported).unsafe fn munlock(addr: *const std::os::raw::c_void, len: usize) -> std::io::Result<()>
mlock.Err(io::ErrorKind::Unsupported).unsafe fn madvise_dontdump(addr: *mut std::os::raw::c_void, len: usize) -> std::io::Result<()>
MADV_DONTDUMP, FreeBSD: MADV_NOCORE).Err(io::ErrorKind::Unsupported).Notes on signatures:
usize lengths to mirror the OS call
semantics and to avoid hiding important safety obligations behind false safety.Ok(()) for ergonomic callers.All functions are unsafe. Callers must uphold the following preconditions for each call:
The (addr, len) pair must denote a valid memory region that the caller owns for
the duration of the call and for as long as the OS considers the lock to be held.
The memory region must not be concurrently deallocated, unmapped, or remapped while the system call is in-flight. Concurrent unmapping or reallocation may cause the OS call to operate on a different mapping and can lead to undefined behavior or kernel errors.
Callers must ensure alignment and fractional-page concerns are addressed if required
by their higher-level policy; the OS operates at page granularity, but mlock is
defined on an arbitrary address and length.
When using mlock to protect secrets, callers must consider:
munlock/drop, where appropriate.mlock failures may be transient or platform-dependent — be prepared
to treat Err(Unsupported) and other error kinds as operational signals.For madvise_dontdump:
Unix (Linux, *BSD, macOS):
mlock and munlock call through to libc::mlock and libc::munlock.madvise_dontdump:
madvise(..., MADV_DONTDUMP).madvise(..., MADV_NOCORE).Err(io::ErrorKind::Unsupported).Non-Unix platforms:
Err(io::ErrorKind::Unsupported).Unsupported gracefully.Use mlock to lock a buffer you control. Wrap calls in unsafe and uphold the safety contract:
unsafe { os_memlock::mlock(buf.as_ptr() as *const _, buf.len())?; }
Later, before drop/unmapping:
unsafe { os_memlock::munlock(buf.as_ptr() as *const _, buf.len())?; }
Call madvise_dontdump on Linux/FreeBSD to reduce chance of core dump exposure:
unsafe { os_memlock::madvise_dontdump(buf.as_mut_ptr() as *mut _, buf.len())?; }
mlock at allocation or when the secret is installed,munlock and ensures munlock is called (via Drop).src/mem/locked.rs in this repository for an example of a safe LockedVec style wrapper.io::ErrorKind::Unsupported signals platform/build-time unavailability;
do not treat it as a panic-worthy error unless your feature policy requires it.io::Error with kernel
errno translated into std::io::Error. These must be handled by the caller or
propagated with context.macOS does not expose a per-region dump-exclusion advice via madvise (there is no MADV_DONTDUMP/MADV_NOCORE on Darwin). To offer a practical alternative, this crate provides opt-in, process-wide helpers:
disable_core_dumps_for_process():
io::ErrorKind::Unsupported.RLIMIT_CORE soft limit to 0 to disable generation of core dumps for the process.io::Result<()> on failure/success.disable_core_dumps_with_guard() -> CoreDumpsDisabledGuard:
io::ErrorKind::Unsupported.RLIMIT_CORE soft limit to 0 and returns a guard. When the guard is dropped, the previous limits are restored for the current process.io::Result<CoreDumpsDisabledGuard>.Recommended usage:
disable_core_dumps_with_guard() to ensure restoration even on panic or early returns.disable_core_dumps_for_process() early in startup.mlock/munlock to reduce the risk of secrets being paged to disk.Windows does not provide a per-region dump-exclusion API analogous to MADV_DONTDUMP. To improve operational behavior (avoiding certain error UI), this crate provides opt-in, process-wide helpers:
set_windows_error_mode(new_mode: u32) -> io::Result<u32>:
io::ErrorKind::Unsupported.SetErrorMode with the provided flags and returns the previous mode.suppress_windows_error_dialogs_for_process() -> io::Result<u32>:
io::ErrorKind::Unsupported.SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX) via SetErrorMode and returns the previous mode.Recommended usage:
mlock/munlock for memory handling as needed.This crate is dual-licensed under Apache-2.0 OR MIT; see Cargo.toml for details.