redoubt_buffer/lib.rs
1// Copyright (c) 2025-2026 Federico Hoerth <memparanoid@gmail.com>
2// SPDX-License-Identifier: GPL-3.0-only
3// See LICENSE in the repository root for full license text.
4
5//! Memory buffers with platform-specific protections and automatic zeroization.
6//!
7//! This crate provides buffer implementations that combine automatic zeroization
8//! with platform-specific memory protection capabilities.
9//!
10//! # Buffer Types
11//!
12//! ## PortableBuffer
13//!
14//! Cross-platform buffer that works everywhere:
15//! - Uses standard heap allocation
16//! - Automatic zeroization on drop
17//! - No platform-specific protections
18//! - Available on all platforms
19//!
20//! ## PageBuffer (Unix only)
21//!
22//! Platform-specific buffer with memory protection:
23//! - Uses `mmap` for allocation
24//! - Optional `mlock` to prevent swapping to disk
25//! - Optional `mprotect` to make pages read-only when not in use
26//! - Automatic zeroization on drop
27//! - Only available on Unix platforms
28//!
29//! # Protection Strategies
30//!
31//! `PageBuffer` supports two protection strategies:
32//!
33//! - **MemProtected**: Uses `mprotect` to make pages read-only by default.
34//! Data can only be accessed through closures that temporarily unprotect the page.
35//! - **MemNonProtected**: Pages remain readable/writable. Data can be accessed
36//! directly through slices.
37//!
38//! # Example: PortableBuffer
39//!
40//! ```rust
41//! use redoubt_buffer::{Buffer, PortableBuffer, BufferError};
42//!
43//! fn example() -> Result<(), BufferError> {
44//! let mut buffer = PortableBuffer::create(32);
45//!
46//! buffer.open_mut(&mut |slice: &mut [u8]| {
47//! slice[0] = 42;
48//! Ok(())
49//! })?;
50//!
51//! buffer.open(&mut |slice: &[u8]| {
52//! assert_eq!(slice[0], 42);
53//! Ok(())
54//! })?;
55//!
56//! // Buffer is zeroized on drop
57//! Ok(())
58//! }
59//! # example().unwrap();
60//! ```
61//!
62//! # Example: PageBuffer with Protection
63//!
64//! ```rust
65//! #[cfg(unix)]
66//! fn example() -> Result<(), redoubt_buffer::BufferError> {
67//! use redoubt_buffer::{Buffer, PageBuffer, ProtectionStrategy};
68//!
69//! let mut buffer = PageBuffer::new(ProtectionStrategy::MemProtected, 32)?;
70//!
71//! // Page is protected (read-only)
72//! // Must use closures to access data
73//! buffer.open_mut(&mut |slice: &mut [u8]| {
74//! slice[0] = 42;
75//! Ok(())
76//! })?;
77//!
78//! buffer.open(&mut |slice: &[u8]| {
79//! assert_eq!(slice[0], 42);
80//! Ok(())
81//! })?;
82//!
83//! // Page is automatically unprotected, zeroized, and freed on drop
84//! Ok(())
85//! }
86//! # #[cfg(unix)]
87//! # example().unwrap();
88//! ```
89//!
90//! ## License
91//!
92//! GPL-3.0-only
93
94#![cfg_attr(not(test), no_std)]
95#![warn(missing_docs)]
96
97extern crate alloc;
98
99#[cfg(test)]
100mod tests;
101
102#[cfg(unix)]
103mod page_buffer;
104
105#[cfg(unix)]
106mod page;
107
108mod error;
109mod portable_buffer;
110mod traits;
111
112#[cfg(unix)]
113pub use page_buffer::{PageBuffer, ProtectionStrategy};
114
115pub use error::BufferError;
116pub use portable_buffer::PortableBuffer;
117pub use traits::Buffer;