feat: Migrate to memsec

This commit is contained in:
Karolin Varner
2023-12-27 16:57:30 +01:00
committed by wucke13
parent b2a64ed17a
commit 85c447052e
16 changed files with 258 additions and 155 deletions

View File

@@ -154,5 +154,5 @@ jobs:
cargo fuzz run fuzz_handle_msg -- -max_total_time=5 cargo fuzz run fuzz_handle_msg -- -max_total_time=5
ulimit -s 8192000 && RUST_MIN_STACK=33554432000 && cargo fuzz run fuzz_kyber_encaps -- -max_total_time=5 ulimit -s 8192000 && RUST_MIN_STACK=33554432000 && cargo fuzz run fuzz_kyber_encaps -- -max_total_time=5
cargo fuzz run fuzz_mceliece_encaps -- -max_total_time=5 cargo fuzz run fuzz_mceliece_encaps -- -max_total_time=5
cargo fuzz run fuzz_box_sodium_alloc -- -max_total_time=5 cargo fuzz run fuzz_box_secret_alloc -- -max_total_time=5
cargo fuzz run fuzz_vec_sodium_alloc -- -max_total_time=5 cargo fuzz run fuzz_vec_secret_alloc -- -max_total_time=5

94
Cargo.lock generated
View File

@@ -46,9 +46,18 @@ dependencies = [
[[package]] [[package]]
name = "allocator-api2" name = "allocator-api2"
version = "0.2.16" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" checksum = "c4f263788a35611fba42eb41ff811c5d0360c58b97402570312a350736e2542e"
[[package]]
name = "allocator-api2-tests"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82e6d832cc75b9841b21c847420f1334645387f088324f34eac923a98efa3d89"
dependencies = [
"allocator-api2",
]
[[package]] [[package]]
name = "anes" name = "anes"
@@ -804,6 +813,17 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "memsec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa0916b001582d253822171bd23f4a0229d32b9507fae236f5da8cad515ba7c"
dependencies = [
"getrandom",
"libc",
"windows-sys 0.45.0",
]
[[package]] [[package]]
name = "minimal-lexical" name = "minimal-lexical"
version = "0.2.1" version = "0.2.1"
@@ -1190,9 +1210,13 @@ dependencies = [
name = "rosenpass-secret-memory" name = "rosenpass-secret-memory"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"allocator-api2",
"allocator-api2-tests",
"anyhow", "anyhow",
"lazy_static", "lazy_static",
"libsodium-sys-stable", "libsodium-sys-stable",
"log",
"memsec",
"rand", "rand",
"rosenpass-sodium", "rosenpass-sodium",
"rosenpass-to", "rosenpass-to",
@@ -1704,6 +1728,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.48.0" version = "0.48.0"
@@ -1722,6 +1755,21 @@ dependencies = [
"windows-targets 0.52.0", "windows-targets 0.52.0",
] ]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.48.5" version = "0.48.5"
@@ -1752,6 +1800,12 @@ dependencies = [
"windows_x86_64_msvc 0.52.0", "windows_x86_64_msvc 0.52.0",
] ]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.48.5" version = "0.48.5"
@@ -1764,6 +1818,12 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.48.5" version = "0.48.5"
@@ -1776,6 +1836,12 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.48.5" version = "0.48.5"
@@ -1788,6 +1854,12 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.48.5" version = "0.48.5"
@@ -1800,6 +1872,12 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.48.5" version = "0.48.5"
@@ -1812,6 +1890,12 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.48.5" version = "0.48.5"
@@ -1824,6 +1908,12 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.48.5" version = "0.48.5"

View File

@@ -48,7 +48,9 @@ paste = "1.0.14"
env_logger = "0.10.1" env_logger = "0.10.1"
toml = "0.7.8" toml = "0.7.8"
static_assertions = "1.1.0" static_assertions = "1.1.0"
allocator-api2 = "0.2.16" allocator-api2 = "0.2.14"
allocator-api2-tests = "0.2.14"
memsec = "0.6.3"
rand = "0.8.5" rand = "0.8.5"
log = { version = "0.4.20" } log = { version = "0.4.20" }
clap = { version = "4.4.10", features = ["derive"] } clap = { version = "4.4.10", features = ["derive"] }

View File

@@ -49,13 +49,13 @@ test = false
doc = false doc = false
[[bin]] [[bin]]
name = "fuzz_box_sodium_alloc" name = "fuzz_box_secret_alloc"
path = "fuzz_targets/box_sodium_alloc.rs" path = "fuzz_targets/box_secret_alloc.rs"
test = false test = false
doc = false doc = false
[[bin]] [[bin]]
name = "fuzz_vec_sodium_alloc" name = "fuzz_vec_secret_alloc"
path = "fuzz_targets/vec_sodium_alloc.rs" path = "fuzz_targets/vec_secret_alloc.rs"
test = false test = false
doc = false doc = false

View File

@@ -0,0 +1,8 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use rosenpass_secret_memory::alloc::secret_box;
fuzz_target!(|data: &[u8]| {
let _ = secret_box(data);
});

View File

@@ -1,12 +0,0 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use rosenpass_sodium::{
alloc::{Alloc as SodiumAlloc, Box as SodiumBox},
init,
};
fuzz_target!(|data: &[u8]| {
let _ = init();
let _ = SodiumBox::new_in(data, SodiumAlloc::new());
});

View File

@@ -0,0 +1,9 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use rosenpass_secret_memory::alloc::secret_vec;
fuzz_target!(|data: &[u8]| {
let mut vec = secret_vec();
vec.extend_from_slice(data);
});

View File

@@ -1,13 +0,0 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use rosenpass_sodium::{
alloc::{Alloc as SodiumAlloc, Vec as SodiumVec},
init,
};
fuzz_target!(|data: &[u8]| {
let _ = init();
let mut vec = SodiumVec::new_in(SodiumAlloc::new());
vec.extend_from_slice(data);
});

View File

@@ -18,3 +18,9 @@ libsodium-sys-stable = { workspace = true }
lazy_static = { workspace = true } lazy_static = { workspace = true }
zeroize = { workspace = true } zeroize = { workspace = true }
rand = { workspace = true } rand = { workspace = true }
memsec = { workspace = true }
allocator-api2 = { workspace = true }
log = { workspace = true }
[dev-dependencies]
allocator-api2-tests = { workspace = true }

View File

@@ -0,0 +1,108 @@
use std::fmt;
use std::ptr::NonNull;
use allocator_api2::alloc::{AllocError, Allocator, Layout};
#[derive(Copy, Clone, Default)]
struct MemsecAllocatorContents;
/// Memory allocation using sodium_malloc/sodium_free
#[derive(Copy, Clone, Default)]
pub struct MemsecAllocator {
_dummy_private_data: MemsecAllocatorContents,
}
/// A box backed by the memsec allocator
pub type MemsecBox<T> = allocator_api2::boxed::Box<T, MemsecAllocator>;
/// A vector backed by the memsec allocator
pub type MemsecVec<T> = allocator_api2::vec::Vec<T, MemsecAllocator>;
pub fn memsec_box<T>(x: T) -> MemsecBox<T> {
MemsecBox::<T>::new_in(x, MemsecAllocator::new())
}
pub fn memsec_vec<T>() -> MemsecVec<T> {
MemsecVec::<T>::new_in(MemsecAllocator::new())
}
impl MemsecAllocator {
pub fn new() -> Self {
Self {
_dummy_private_data: MemsecAllocatorContents,
}
}
}
unsafe impl Allocator for MemsecAllocator {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
// Call memsec allocator
let mem: Option<NonNull<[u8]>> = unsafe { memsec::malloc_sized(layout.size()) };
// Unwrap the option
let Some(mem) = mem else {
log::error!("Allocation {layout:?} was requested but memsec returned a null pointer");
return Err(AllocError);
};
// Ensure the right alignment is used
let off = (mem.as_ptr() as *const u8).align_offset(layout.align());
if off != 0 {
log::error!("Allocation {layout:?} was requested but memsec returned allocation \
with offset {off} from the requested alignment. Memsec always allocates values \
at the end of a memory page for security reasons, custom alignments are not supported. \
You could try allocating an oversized value.");
unsafe { memsec::free(mem) };
return Err(AllocError);
};
Ok(mem)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, _layout: Layout) {
unsafe {
memsec::free(ptr);
}
}
}
impl fmt::Debug for MemsecAllocator {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("<memsec based Rust allocator>")
}
}
#[cfg(test)]
mod test {
use allocator_api2_tests::make_test;
use super::*;
make_test! { test_sizes(MemsecAllocator::new()) }
make_test! { test_vec(MemsecAllocator::new()) }
make_test! { test_many_boxes(MemsecAllocator::new()) }
#[test]
fn memsec_allocation() {
let alloc = MemsecAllocator::new();
memsec_allocation_impl::<0>(&alloc);
memsec_allocation_impl::<7>(&alloc);
memsec_allocation_impl::<8>(&alloc);
memsec_allocation_impl::<64>(&alloc);
memsec_allocation_impl::<999>(&alloc);
}
fn memsec_allocation_impl<const N: usize>(alloc: &MemsecAllocator) {
let layout = Layout::new::<[u8; N]>();
let mem = alloc.allocate(layout).unwrap();
// https://libsodium.gitbook.io/doc/memory_management#guarded-heap-allocations
// promises us that allocated memory is initialized with the magic byte 0xDB
// and memsec promises to provide a reimplementation of the libsodium mechanism;
// it uses the magic value 0xD0 though
assert_eq!(unsafe { mem.as_ref() }, &[0xD0u8; N]);
let mem = NonNull::new(mem.as_ptr() as *mut u8).unwrap();
unsafe { alloc.deallocate(mem, layout) };
}
}

View File

@@ -0,0 +1,6 @@
pub mod memsec;
pub use crate::alloc::memsec::{
memsec_box as secret_box, memsec_vec as secret_vec, MemsecAllocator as SecretAllocator,
MemsecBox as SecretBox, MemsecVec as SecretVec,
};

View File

@@ -2,6 +2,8 @@ pub mod debug;
pub mod file; pub mod file;
pub mod rand; pub mod rand;
pub mod alloc;
mod public; mod public;
pub use crate::public::Public; pub use crate::public::Public;

View File

@@ -1,15 +1,18 @@
use crate::file::StoreSecret; use std::{collections::HashMap, convert::TryInto, fmt, path::Path, sync::Mutex};
use anyhow::Context; use anyhow::Context;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use rand::{Fill as Randomize, Rng}; use rand::{Fill as Randomize, Rng};
use rosenpass_sodium::alloc::{Alloc as SodiumAlloc, Box as SodiumBox, Vec as SodiumVec}; use zeroize::{Zeroize, ZeroizeOnDrop};
use rosenpass_util::{ use rosenpass_util::{
b64::b64_reader, b64::b64_reader,
file::{fopen_r, LoadValue, LoadValueB64, ReadExactToEnd}, file::{fopen_r, LoadValue, LoadValueB64, ReadExactToEnd},
functional::mutating, functional::mutating,
}; };
use std::{collections::HashMap, convert::TryInto, fmt, path::Path, sync::Mutex};
use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::alloc::{secret_box, SecretBox, SecretVec};
use crate::file::StoreSecret;
// This might become a problem in library usage; it's effectively a memory // This might become a problem in library usage; it's effectively a memory
// leak which probably isn't a problem right now because most memory will // leak which probably isn't a problem right now because most memory will
@@ -28,7 +31,7 @@ lazy_static! {
/// [libsodium documentation](https://libsodium.gitbook.io/doc/memory_management#guarded-heap-allocations) /// [libsodium documentation](https://libsodium.gitbook.io/doc/memory_management#guarded-heap-allocations)
#[derive(Debug)] // TODO check on Debug derive, is that clever #[derive(Debug)] // TODO check on Debug derive, is that clever
struct SecretMemoryPool { struct SecretMemoryPool {
pool: HashMap<usize, Vec<SodiumBox<[u8]>>>, pool: HashMap<usize, Vec<SecretBox<[u8]>>>,
} }
impl SecretMemoryPool { impl SecretMemoryPool {
@@ -41,13 +44,13 @@ impl SecretMemoryPool {
} }
/// Return secret back to the pool for future re-use /// Return secret back to the pool for future re-use
pub fn release<const N: usize>(&mut self, mut sec: SodiumBox<[u8; N]>) { pub fn release<const N: usize>(&mut self, mut sec: SecretBox<[u8; N]>) {
sec.zeroize(); sec.zeroize();
// This conversion sequence is weird but at least it guarantees // This conversion sequence is weird but at least it guarantees
// that the heap allocation is preserved according to the docs // that the heap allocation is preserved according to the docs
let sec: SodiumVec<u8> = sec.into(); let sec: SecretVec<u8> = sec.into();
let sec: SodiumBox<[u8]> = sec.into(); let sec: SecretBox<[u8]> = sec.into();
self.pool.entry(N).or_default().push(sec); self.pool.entry(N).or_default().push(sec);
} }
@@ -56,10 +59,10 @@ impl SecretMemoryPool {
/// chunk is found in the inventory. /// chunk is found in the inventory.
/// ///
/// The secret is guaranteed to be full of nullbytes /// The secret is guaranteed to be full of nullbytes
pub fn take<const N: usize>(&mut self) -> SodiumBox<[u8; N]> { pub fn take<const N: usize>(&mut self) -> SecretBox<[u8; N]> {
let entry = self.pool.entry(N).or_default(); let entry = self.pool.entry(N).or_default();
match entry.pop() { match entry.pop() {
None => SodiumBox::new_in([0u8; N], SodiumAlloc::default()), None => secret_box([0u8; N]),
Some(sec) => sec.try_into().unwrap(), Some(sec) => sec.try_into().unwrap(),
} }
} }
@@ -67,7 +70,7 @@ impl SecretMemoryPool {
/// Storeage for a secret backed by [rosenpass_sodium::alloc::Alloc] /// Storeage for a secret backed by [rosenpass_sodium::alloc::Alloc]
pub struct Secret<const N: usize> { pub struct Secret<const N: usize> {
storage: Option<SodiumBox<[u8; N]>>, storage: Option<SecretBox<[u8; N]>>,
} }
impl<const N: usize> Secret<N> { impl<const N: usize> Secret<N> {
@@ -200,7 +203,7 @@ mod test {
rosenpass_sodium::init().unwrap(); rosenpass_sodium::init().unwrap();
const N: usize = 0x100; const N: usize = 0x100;
let mut pool = SecretMemoryPool::new(); let mut pool = SecretMemoryPool::new();
let secret: SodiumBox<[u8; N]> = pool.take(); let secret: SecretBox<[u8; N]> = pool.take();
assert_eq!(secret.as_ref(), &[0; N]); assert_eq!(secret.as_ref(), &[0; N]);
} }
@@ -210,7 +213,7 @@ mod test {
rosenpass_sodium::init().unwrap(); rosenpass_sodium::init().unwrap();
const N: usize = 0x100; const N: usize = 0x100;
let mut pool = SecretMemoryPool::new(); let mut pool = SecretMemoryPool::new();
let secret: SodiumBox<[u8; N]> = pool.take(); let secret: SecretBox<[u8; N]> = pool.take();
std::mem::drop(pool); std::mem::drop(pool);
assert_eq!(secret.as_ref(), &[0; N]); assert_eq!(secret.as_ref(), &[0; N]);
} }
@@ -221,14 +224,14 @@ mod test {
rosenpass_sodium::init().unwrap(); rosenpass_sodium::init().unwrap();
const N: usize = 1; const N: usize = 1;
let mut pool = SecretMemoryPool::new(); let mut pool = SecretMemoryPool::new();
let mut secret: SodiumBox<[u8; N]> = pool.take(); let mut secret: SecretBox<[u8; N]> = pool.take();
let old_secret_ptr = secret.as_ref().as_ptr(); let old_secret_ptr = secret.as_ref().as_ptr();
secret.as_mut()[0] = 0x13; secret.as_mut()[0] = 0x13;
pool.release(secret); pool.release(secret);
// now check that we get the same ptr // now check that we get the same ptr
let new_secret: SodiumBox<[u8; N]> = pool.take(); let new_secret: SecretBox<[u8; N]> = pool.take();
assert_eq!(old_secret_ptr, new_secret.as_ref().as_ptr()); assert_eq!(old_secret_ptr, new_secret.as_ref().as_ptr());
// and that the secret was zeroized // and that the secret was zeroized

View File

@@ -1,95 +0,0 @@
use allocator_api2::alloc::{AllocError, Allocator, Layout};
use libsodium_sys as libsodium;
use std::fmt;
use std::os::raw::c_void;
use std::ptr::NonNull;
#[derive(Clone, Default)]
struct AllocatorContents;
/// Memory allocation using sodium_malloc/sodium_free
#[derive(Clone, Default)]
pub struct Alloc {
_dummy_private_data: AllocatorContents,
}
impl Alloc {
pub fn new() -> Self {
Alloc {
_dummy_private_data: AllocatorContents,
}
}
}
unsafe impl Allocator for Alloc {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
// Call sodium allocator
let ptr = unsafe { libsodium::sodium_malloc(layout.size()) };
// Ensure the right allocation is used
let off = ptr.align_offset(layout.align());
if off != 0 {
log::error!("Allocation {layout:?} was requested but libsodium returned allocation \
with offset {off} from the requested alignment. Libsodium always allocates values \
at the end of a memory page for security reasons, custom alignments are not supported. \
You could try allocating an oversized value.");
return Err(AllocError);
}
// Convert to a pointer size
let ptr = core::ptr::slice_from_raw_parts_mut(ptr as *mut u8, layout.size());
// Conversion to a *const u8, then to a &[u8]
match NonNull::new(ptr) {
None => {
log::error!(
"Allocation {layout:?} was requested but libsodium returned a null pointer"
);
Err(AllocError)
}
Some(ret) => Ok(ret),
}
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, _layout: Layout) {
unsafe {
libsodium::sodium_free(ptr.as_ptr() as *mut c_void);
}
}
}
impl fmt::Debug for Alloc {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("<libsodium based Rust allocator>")
}
}
#[cfg(test)]
mod test {
use super::*;
/// checks that the can malloc with libsodium
#[test]
fn sodium_allocation() {
crate::init().unwrap();
let alloc = Alloc::new();
sodium_allocation_impl::<0>(&alloc);
sodium_allocation_impl::<7>(&alloc);
sodium_allocation_impl::<8>(&alloc);
sodium_allocation_impl::<64>(&alloc);
sodium_allocation_impl::<999>(&alloc);
}
fn sodium_allocation_impl<const N: usize>(alloc: &Alloc) {
crate::init().unwrap();
let layout = Layout::new::<[u8; N]>();
let mem = alloc.allocate(layout).unwrap();
// https://libsodium.gitbook.io/doc/memory_management#guarded-heap-allocations
// promises us that allocated memory is initialized with the magic byte 0xDB
assert_eq!(unsafe { mem.as_ref() }, &[0xDBu8; N]);
let mem = NonNull::new(mem.as_ptr() as *mut u8).unwrap();
unsafe { alloc.deallocate(mem, layout) };
}
}

View File

@@ -1,10 +0,0 @@
//! Access to sodium_malloc/sodium_free
mod allocator;
pub use allocator::Alloc;
/// A box backed by sodium_malloc
pub type Box<T> = allocator_api2::boxed::Box<T, Alloc>;
/// A vector backed by sodium_malloc
pub type Vec<T> = allocator_api2::vec::Vec<T, Alloc>;

View File

@@ -16,6 +16,5 @@ pub fn init() -> anyhow::Result<()> {
} }
pub mod aead; pub mod aead;
pub mod alloc;
pub mod hash; pub mod hash;
pub mod helpers; pub mod helpers;