use crate::internals::zeroize as internals;
use crate::macros::{
debug_precondition_logaligned, debug_precondition_logmultiple, precondition_memory_range,
};
use crate::util::is_aligned_ptr_mut;
pub trait MemZeroizer {
unsafe fn zeroize_mem_blocks<const LOG_ALIGN: u8, const LOG_MULTIPLE: u8>(
&self,
ptr: *mut u8,
len: usize,
);
unsafe fn zeroize_mem(&self, ptr: *mut u8, len: usize) {
unsafe { self.zeroize_mem_blocks::<0, 0>(ptr, len) }
}
}
cfg_if::cfg_if! {
if #[cfg(miri)] {
pub type DefaultMemZeroizer = VolatileWrite8Zeroizer;
pub(crate) use VolatileWrite8Zeroizer as DefaultMemZeroizerConstructor;
} else if #[cfg(feature = "nightly_core_intrinsics")] {
pub type DefaultMemZeroizer = VolatileMemsetZeroizer;
pub(crate) use VolatileMemsetZeroizer as DefaultMemZeroizerConstructor;
} else if #[cfg(any(
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "netbsd",
target_os = "macos",
target_os = "ios",
target_env = "gnu",
target_env = "musl"
))] {
pub type DefaultMemZeroizer = LibcZeroizer;
pub(crate) use LibcZeroizer as DefaultMemZeroizerConstructor;
} else if #[cfg(all(target_arch = "x86_64", target_feature = "avx"))] {
pub type DefaultMemZeroizer = X86_64AvxZeroizer;
pub(crate) use X86_64AvxZeroizer as DefaultMemZeroizerConstructor;
} else if #[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] {
pub type DefaultMemZeroizer = X86_64Sse2Zeroizer;
pub(crate) use X86_64Sse2Zeroizer as DefaultMemZeroizerConstructor;
} else {
pub type DefaultMemZeroizer = VolatileWrite8Zeroizer;
pub(crate) use VolatileWrite8Zeroizer as DefaultMemZeroizerConstructor;
}
}
#[cfg(test)]
pub(crate) use VolatileWrite8Zeroizer as TestZeroizer;
#[cfg(feature = "nightly_core_intrinsics")]
#[derive(Debug, Copy, Clone, Default)]
pub struct VolatileMemsetZeroizer;
#[cfg(feature = "nightly_core_intrinsics")]
impl MemZeroizer for VolatileMemsetZeroizer {
unsafe fn zeroize_mem_blocks<const A: u8, const B: u8>(&self, ptr: *mut u8, len: usize) {
precondition_memory_range!(ptr, len);
debug_precondition_logaligned!(A, ptr);
unsafe {
internals::volatile_memset(ptr, 0, len);
}
fence();
}
}
#[cfg(any(
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "netbsd",
target_os = "macos",
target_os = "ios",
target_env = "gnu",
target_env = "musl"
))]
#[derive(Debug, Copy, Clone, Default)]
pub struct LibcZeroizer;
#[cfg(any(
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "netbsd",
target_os = "macos",
target_os = "ios",
target_env = "gnu",
target_env = "musl"
))]
impl MemZeroizer for LibcZeroizer {
unsafe fn zeroize_mem_blocks<const A: u8, const B: u8>(&self, ptr: *mut u8, len: usize) {
precondition_memory_range!(ptr, len);
debug_precondition_logaligned!(A, ptr);
debug_precondition_logmultiple!(B, len);
unsafe {
internals::libc_explicit_bzero(ptr, len);
}
fence();
}
}
#[cfg(all(target_arch = "x86_64", target_feature = "ermsb"))]
#[derive(Debug, Copy, Clone, Default)]
pub struct AsmRepStosZeroizer;
#[cfg(all(target_arch = "x86_64", target_feature = "ermsb"))]
impl MemZeroizer for AsmRepStosZeroizer {
unsafe fn zeroize_mem_blocks<const A: u8, const B: u8>(&self, ptr: *mut u8, len: usize) {
precondition_memory_range!(ptr, len);
debug_precondition_logaligned!(A, ptr);
debug_precondition_logmultiple!(B, len);
unsafe {
internals::asm_ermsb_zeroize(ptr, len);
}
fence();
}
}
#[derive(Debug, Copy, Clone, Default)]
pub struct VolatileWriteZeroizer;
impl MemZeroizer for VolatileWriteZeroizer {
unsafe fn zeroize_mem_blocks<const A: u8, const B: u8>(&self, ptr: *mut u8, len: usize) {
precondition_memory_range!(ptr, len);
debug_precondition_logaligned!(A, ptr);
debug_precondition_logmultiple!(B, len);
unsafe {
internals::volatile_write_zeroize(ptr, len);
}
fence();
}
}
#[derive(Debug, Copy, Clone, Default)]
pub struct VolatileWrite8Zeroizer;
impl MemZeroizer for VolatileWrite8Zeroizer {
unsafe fn zeroize_mem_blocks<const A: u8, const B: u8>(&self, mut ptr: *mut u8, len: usize) {
precondition_memory_range!(ptr, len);
debug_precondition_logaligned!(A, ptr);
debug_precondition_logmultiple!(B, len);
if (A >= 3) | is_aligned_ptr_mut(ptr, 8) {
ptr = unsafe { internals::zeroize_align8_block8(ptr, len) };
if B < 3 {
unsafe { internals::zeroize_align4_tail8(ptr, len) };
}
} else {
unsafe {
internals::volatile_write_zeroize(ptr, len);
}
}
fence();
}
}
#[cfg(all(target_arch = "x86_64", target_feature = "avx"))]
#[derive(Debug, Copy, Clone, Default)]
pub struct X86_64AvxZeroizer;
#[cfg(all(target_arch = "x86_64", target_feature = "avx"))]
impl MemZeroizer for X86_64AvxZeroizer {
unsafe fn zeroize_mem_blocks<const A: u8, const B: u8>(&self, mut ptr: *mut u8, len: usize) {
precondition_memory_range!(ptr, len);
debug_precondition_logaligned!(A, ptr);
debug_precondition_logmultiple!(B, len);
if (A >= 5) | is_aligned_ptr_mut(ptr, 32) {
ptr = unsafe { internals::x86_64_simd32_unroll2_zeroize_align32_block32(ptr, len) };
if B < 5 {
ptr = unsafe { internals::zeroize_align8_block8(ptr, len % 32) };
}
if B < 3 {
unsafe { internals::zeroize_align4_tail8(ptr, len % 8) };
}
} else if (A >= 3) | is_aligned_ptr_mut(ptr, 8) {
ptr = unsafe { internals::zeroize_align8_block8(ptr, len % 32) };
if B < 3 {
unsafe { internals::zeroize_align4_tail8(ptr, len % 8) };
}
} else {
unsafe {
internals::volatile_write_zeroize(ptr, len);
}
}
fence();
}
}
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
#[derive(Debug, Copy, Clone, Default)]
pub struct X86_64Sse2Zeroizer;
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
impl MemZeroizer for X86_64Sse2Zeroizer {
unsafe fn zeroize_mem_blocks<const A: u8, const B: u8>(&self, mut ptr: *mut u8, len: usize) {
precondition_memory_range!(ptr, len);
debug_precondition_logaligned!(A, ptr);
debug_precondition_logmultiple!(B, len);
if (A >= 4) | is_aligned_ptr_mut(ptr, 16) {
ptr = unsafe { internals::x86_64_simd16_unroll2_zeroize_align16_block16(ptr, len) };
if B < 4 {
ptr = unsafe { internals::zeroize_align8_block8(ptr, len % 16) };
}
if B < 3 {
unsafe { internals::zeroize_align4_tail8(ptr, len % 8) };
}
} else if (A >= 3) | is_aligned_ptr_mut(ptr, 8) {
ptr = unsafe { internals::zeroize_align8_block8(ptr, len % 16) };
if B < 3 {
unsafe { internals::zeroize_align4_tail8(ptr, len % 8) };
}
} else {
unsafe {
internals::volatile_write_zeroize(ptr, len);
}
}
fence();
}
}
#[inline]
fn fence() {
use core::sync::atomic::{compiler_fence, Ordering};
compiler_fence(Ordering::SeqCst);
}
#[cfg(test)]
mod tests;