memsec-0.5.6/.gitignore010064400017500001750000000000221314402144000131670ustar0000000000000000target Cargo.lock memsec-0.5.6/.travis.yml010064400017500001750000000014051346730214200133270ustar0000000000000000language: rust rust: - nightly - stable cache: cargo os: - linux - osx install: - wget https://github.com/jedisct1/libsodium/releases/download/1.0.17/libsodium-1.0.17.tar.gz - tar xvfz libsodium-1.0.17.tar.gz - cd libsodium-1.0.17 && ./configure --prefix=$HOME/installed_libsodium && make && make install && cd .. - export PKG_CONFIG_PATH=$HOME/installed_libsodium/lib/pkgconfig:$PKG_CONFIG_PATH - export LD_LIBRARY_PATH=$HOME/installed_libsodium/lib:$LD_LIBRARY_PATH script: - cd memsec-test - cargo test --no-default-features - cargo test - if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then cargo test --features nightly; fi - if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then cargo bench --features nightly; fi memsec-0.5.6/Cargo.toml.orig010064400017500001750000000017361347221076100141150ustar0000000000000000[package] name = "memsec" version = "0.5.6" authors = ["quininer kel "] description = "Rust implementation `libsodium/utils`." repository = "https://github.com/quininer/memsec" keywords = [ "protection", "memory", "secure" ] documentation = "https://docs.rs/memsec/" license = "MIT" categories = [ "no-std", "memory-management" ] build = "build.rs" [badges] travis-ci = { repository = "quininer/memsec" } appveyor = { repository = "quininer/memsec" } [dependencies] getrandom = { version = "0.1", optional = true } [target.'cfg(unix)'.dependencies] libc = { version = "0.2", optional = true } [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = [ "memoryapi", "sysinfoapi" ], optional = true } [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] mach_o_sys = { version = "0.1", optional = true } [features] default = [ "use_os", "alloc" ] nightly = [] use_os = [ "libc", "winapi", "mach_o_sys" ] alloc = [ "getrandom" ] memsec-0.5.6/Cargo.toml0000644000000026760000000000000103650ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "memsec" version = "0.5.6" authors = ["quininer kel "] build = "build.rs" description = "Rust implementation `libsodium/utils`." documentation = "https://docs.rs/memsec/" keywords = ["protection", "memory", "secure"] categories = ["no-std", "memory-management"] license = "MIT" repository = "https://github.com/quininer/memsec" [dependencies.getrandom] version = "0.1" optional = true [features] alloc = ["getrandom"] default = ["use_os", "alloc"] nightly = [] use_os = ["libc", "winapi", "mach_o_sys"] [target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.mach_o_sys] version = "0.1" optional = true [target."cfg(unix)".dependencies.libc] version = "0.2" optional = true [target."cfg(windows)".dependencies.winapi] version = "0.3" features = ["memoryapi", "sysinfoapi"] optional = true [badges.appveyor] repository = "quininer/memsec" [badges.travis-ci] repository = "quininer/memsec" memsec-0.5.6/Cargo.toml.orig0000644000000026770000000000000113250ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "memsec" version = "0.5.6" authors = ["quininer kel "] build = "build.rs" description = "Rust implementation `libsodium/utils`." documentation = "https://docs.rs/memsec/" keywords = ["protection", "memory", "secure"] categories = ["no-std", "memory-management"] license = "MIT" repository = "https://github.com/quininer/memsec" [dependencies.getrandom] version = "0.1" optional = true [features] alloc = ["getrandom"] default = ["use_os", "alloc"] nightly = [] use_os = ["libc", "winapi", "mach_o_sys"] [target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.mach_o_sys] version = "0.1" optional = true [target."cfg(unix)".dependencies.libc] version = "0.2" optional = true [target."cfg(windows)".dependencies.winapi] version = "0.3" features = ["memoryapi", "sysinfoapi"] optional = true [badges.appveyor] repository = "quininer/memsec" [badges.travis-ci] repository = "quininer/memsec" memsec-0.5.6/LICENSE010064400017500001750000000020611314402144000122110ustar0000000000000000MIT License Copyright (c) 2016 quininer@live.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. memsec-0.5.6/README.md010064400017500001750000000017271314402144000124730ustar0000000000000000# memsec [![travis-ci](https://travis-ci.org/quininer/memsec.svg?branch=master)](https://travis-ci.org/quininer/memsec) [![appveyor](https://ci.appveyor.com/api/projects/status/1w0qtl0grjfu0uac?svg=true)](https://ci.appveyor.com/project/quininer/memsec) [![crates](https://img.shields.io/crates/v/memsec.svg)](https://crates.io/crates/memsec) [![license](https://img.shields.io/github/license/quininer/memsec.svg)](https://github.com/quininer/memsec/blob/master/LICENSE) [![docs.rs](https://docs.rs/memsec/badge.svg)](https://docs.rs/memsec/) Rust implementation `libsodium/utils`. * [x] `memeq`/`memcmp` * [x] `memset`/`memzero` * [x] `mlock`/`munlock` * [x] `alloc`/`free`/`mprotect` ref --- * [Securing memory allocations](https://download.libsodium.org/doc/helpers/memory_management.html) * [rlibc](https://github.com/alexcrichton/rlibc) * [aligned_alloc.rs](https://github.com/jonas-schievink/aligned_alloc.rs) * [cst_time_memcmp](https://github.com/chmike/cst_time_memcmp) memsec-0.5.6/appveyor.yml010064400017500001750000000010311321571053000135740ustar0000000000000000environment: matrix: - TARGET: i686-pc-windows-msvc - TARGET: x86_64-pc-windows-msvc install: - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init.exe -y --default-host %TARGET% --default-toolchain nightly - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - rustc --version - cargo --version build: false test_script: - 'cd memsec-test' - 'cargo test --no-default-features' - 'cargo test' - 'cargo test --features nightly' - 'cargo bench --features nightly' memsec-0.5.6/build.rs010064400017500001750000000005641347220672500126760ustar0000000000000000use std::env; fn main() { match env::var("CARGO_CFG_TARGET_OS").as_ref().map(String::as_str) { Ok("macos") | Ok("ios") => println!("cargo:rustc-cfg=apple"), Ok("freebsd") | Ok("dragonfly") => println!("cargo:rustc-cfg=freebsdlike"), Ok("openbsd") | Ok("netbsd") | Ok("bitrig") => println!("cargo:rust-cfg=netbsdlike"), _ => () } } memsec-0.5.6/src/alloc.rs010064400017500001750000000153321346703752100134570ustar0000000000000000//! alloc #![cfg(feature = "alloc")] extern crate getrandom; use core::mem; use core::ptr::{ self, NonNull }; use self::getrandom::getrandom; use self::raw_alloc::*; use std::sync::Once; use std::process::abort; const GARBAGE_VALUE: u8 = 0xd0; const CANARY_SIZE: usize = 16; static ALLOC_INIT: Once = Once::new(); static mut PAGE_SIZE: usize = 0; static mut PAGE_MASK: usize = 0; static mut CANARY: [u8; CANARY_SIZE] = [0; CANARY_SIZE]; // -- alloc init -- #[inline] unsafe fn alloc_init() { #[cfg(unix)] { PAGE_SIZE = ::libc::sysconf(::libc::_SC_PAGESIZE) as usize; } #[cfg(windows)] { let mut si = mem::uninitialized(); ::winapi::um::sysinfoapi::GetSystemInfo(&mut si); PAGE_SIZE = si.dwPageSize as usize; } if PAGE_SIZE < CANARY_SIZE || PAGE_SIZE < mem::size_of::() { abort(); } PAGE_MASK = PAGE_SIZE - 1; if getrandom(&mut CANARY).is_err() { abort() } } // -- aligned alloc / aligned free -- mod raw_alloc { use std::alloc::{ alloc, dealloc, Layout }; use super::*; #[inline] pub unsafe fn alloc_aligned(size: usize) -> Option> { let layout = Layout::from_size_align_unchecked(size, PAGE_SIZE); NonNull::new(alloc(layout)) } #[inline] pub unsafe fn free_aligned(memptr: *mut u8, size: usize) { let layout = Layout::from_size_align_unchecked(size, PAGE_SIZE); dealloc(memptr, layout); } } // -- mprotect -- /// Prot enum. #[cfg(unix)] #[allow(non_snake_case, non_upper_case_globals)] pub mod Prot { pub use ::libc::c_int as Ty; pub const NoAccess: Ty = ::libc::PROT_NONE; pub const ReadOnly: Ty = ::libc::PROT_READ; pub const WriteOnly: Ty = ::libc::PROT_WRITE; pub const ReadWrite: Ty = (::libc::PROT_READ | ::libc::PROT_WRITE); pub const Execute: Ty = ::libc::PROT_EXEC; pub const ReadExec: Ty = (::libc::PROT_READ | ::libc::PROT_EXEC); pub const WriteExec: Ty = (::libc::PROT_WRITE | ::libc::PROT_EXEC); pub const ReadWriteExec: Ty = (::libc::PROT_READ | ::libc::PROT_WRITE | ::libc::PROT_EXEC); } /// Prot enum. #[cfg(windows)] #[allow(non_snake_case, non_upper_case_globals)] pub mod Prot { pub use ::winapi::shared::minwindef::DWORD as Ty; pub const NoAccess: Ty = ::winapi::um::winnt::PAGE_NOACCESS; pub const ReadOnly: Ty = ::winapi::um::winnt::PAGE_READONLY; pub const ReadWrite: Ty = ::winapi::um::winnt::PAGE_READWRITE; pub const WriteCopy: Ty = ::winapi::um::winnt::PAGE_WRITECOPY; pub const Execute: Ty = ::winapi::um::winnt::PAGE_EXECUTE; pub const ReadExec: Ty = ::winapi::um::winnt::PAGE_EXECUTE_READ; pub const ReadWriteExec: Ty = ::winapi::um::winnt::PAGE_EXECUTE_READWRITE; pub const WriteCopyExec: Ty = ::winapi::um::winnt::PAGE_EXECUTE_WRITECOPY; pub const Guard: Ty = ::winapi::um::winnt::PAGE_GUARD; pub const NoCache: Ty = ::winapi::um::winnt::PAGE_NOCACHE; pub const WriteCombine: Ty = ::winapi::um::winnt::PAGE_WRITECOMBINE; pub const RevertToFileMap: Ty = ::winapi::um::winnt::PAGE_REVERT_TO_FILE_MAP; pub const TargetsInvalid: Ty = ::winapi::um::winnt::PAGE_TARGETS_INVALID; pub const TargetsNoUpdate: Ty = ::winapi::um::winnt::PAGE_TARGETS_NO_UPDATE; } /// Unix `mprotect`. #[cfg(unix)] #[inline] pub unsafe fn _mprotect(ptr: *mut u8, len: usize, prot: Prot::Ty) -> bool { ::libc::mprotect(ptr as *mut ::libc::c_void, len, prot as ::libc::c_int) == 0 } /// Windows `VirtualProtect`. #[cfg(windows)] #[inline] pub unsafe fn _mprotect(ptr: *mut u8, len: usize, prot: Prot::Ty) -> bool { let mut old = mem::uninitialized(); ::winapi::um::memoryapi::VirtualProtect( ptr as ::winapi::shared::minwindef::LPVOID, len as ::winapi::shared::basetsd::SIZE_T, prot as ::winapi::shared::minwindef::DWORD, &mut old as ::winapi::shared::minwindef::PDWORD ) != 0 } /// Secure `mprotect`. #[cfg(any(unix, windows))] pub unsafe fn mprotect(memptr: NonNull, prot: Prot::Ty) -> bool { let memptr = memptr.as_ptr() as *mut u8; let unprotected_ptr = unprotected_ptr_from_user_ptr(memptr); let base_ptr = unprotected_ptr.sub(PAGE_SIZE * 2); let unprotected_size = ptr::read(base_ptr as *const usize); _mprotect(unprotected_ptr, unprotected_size, prot) } // -- malloc / free -- #[inline] unsafe fn page_round(size: usize) -> usize { (size + PAGE_MASK) & !PAGE_MASK } #[inline] unsafe fn unprotected_ptr_from_user_ptr(memptr: *const u8) -> *mut u8 { let canary_ptr = memptr.sub(CANARY_SIZE); let unprotected_ptr_u = canary_ptr as usize & !PAGE_MASK; if unprotected_ptr_u <= PAGE_SIZE * 2 { abort(); } unprotected_ptr_u as *mut u8 } unsafe fn _malloc() -> Option> { ALLOC_INIT.call_once(|| alloc_init()); let size = mem::size_of::(); if size >= ::core::usize::MAX - PAGE_SIZE * 4 { return None; } // aligned alloc ptr let size_with_canary = CANARY_SIZE + size; let unprotected_size = page_round(size_with_canary); let total_size = PAGE_SIZE + PAGE_SIZE + unprotected_size + PAGE_SIZE; let base_ptr = alloc_aligned(total_size)?.as_ptr(); let unprotected_ptr = base_ptr.add(PAGE_SIZE * 2); // mprotect ptr _mprotect(base_ptr.add(PAGE_SIZE), PAGE_SIZE, Prot::NoAccess); _mprotect(unprotected_ptr.add(unprotected_size), PAGE_SIZE, Prot::NoAccess); ::mlock(unprotected_ptr, unprotected_size); let canary_ptr = unprotected_ptr.add(unprotected_size - size_with_canary); let user_ptr = canary_ptr.add(CANARY_SIZE); ptr::copy_nonoverlapping(CANARY.as_ptr(), canary_ptr, CANARY_SIZE); ptr::write_unaligned(base_ptr as *mut usize, unprotected_size); _mprotect(base_ptr, PAGE_SIZE, Prot::ReadOnly); assert_eq!(unprotected_ptr_from_user_ptr(user_ptr), unprotected_ptr); Some(NonNull::new_unchecked(user_ptr as *mut T)) } /// Secure `malloc`. #[inline] pub unsafe fn malloc() -> Option> { _malloc() .map(|memptr| { ptr::write_bytes(memptr.as_ptr() as *mut u8, GARBAGE_VALUE, mem::size_of::()); memptr }) } /// Secure `free`. pub unsafe fn free(memptr: NonNull) { let memptr = memptr.as_ptr() as *mut u8; // get unprotected ptr let canary_ptr = memptr.sub(CANARY_SIZE); let unprotected_ptr = unprotected_ptr_from_user_ptr(memptr); let base_ptr = unprotected_ptr.sub(PAGE_SIZE * 2); let unprotected_size = ptr::read(base_ptr as *const usize); // check assert!(::memeq(canary_ptr as *const u8, CANARY.as_ptr(), CANARY_SIZE)); // free let total_size = PAGE_SIZE + PAGE_SIZE + unprotected_size + PAGE_SIZE; _mprotect(base_ptr, total_size, Prot::ReadWrite); ::munlock(unprotected_ptr, unprotected_size); free_aligned(base_ptr, total_size); } memsec-0.5.6/src/lib.rs010064400017500001750000000056511346703464700131440ustar0000000000000000#![no_std] #![cfg_attr(feature = "nightly", feature(core_intrinsics))] #[cfg(feature = "use_os")] extern crate std; #[cfg(all(unix, feature = "use_os"))] extern crate libc; #[cfg(all(windows, feature = "use_os"))] extern crate winapi; #[cfg(all(apple, feature = "use_os"))] extern crate mach_o_sys; mod mlock; mod alloc; use core::ptr; #[cfg(feature = "use_os")] pub use mlock::{ mlock, munlock }; #[cfg(feature = "alloc")] pub use alloc::{ Prot, mprotect, malloc, free }; // -- memcmp -- /// Secure `memeq`. #[inline(never)] pub unsafe fn memeq(b1: *const u8, b2: *const u8, len: usize) -> bool { (0..len as isize) .map(|i| ptr::read_volatile(b1.offset(i)) ^ ptr::read_volatile(b2.offset(i))) .fold(0, |sum, next| sum | next) .eq(&0) } /// Secure `memcmp`. #[inline(never)] pub unsafe fn memcmp(b1: *const u8, b2: *const u8, len: usize) -> i32 { let mut res = 0; for i in (0..len as isize).rev() { let diff = i32::from(ptr::read_volatile(b1.offset(i))) - i32::from(ptr::read_volatile(b2.offset(i))); res = (res & (((diff - 1) & !diff) >> 8)) | diff; } ((res - 1) >> 8) + (res >> 8) + 1 } // -- memset / memzero -- /// General `memset`. #[cfg(feature = "nightly")] #[cfg(any(not(apple), not(feature = "use_os")))] #[inline(never)] pub unsafe fn memset(s: *mut u8, c: u8, n: usize) { core::intrinsics::volatile_set_memory(s, c, n); } /// General `memset`. #[cfg(not(feature = "nightly"))] #[cfg(any(not(apple), not(feature = "use_os")))] #[inline(never)] pub unsafe fn memset(s: *mut u8, c: u8, n: usize) { for i in 0..n { ptr::write_volatile(s.add(i), c); } } /// Call `memset_s`. #[cfg(all(apple, feature = "use_os"))] pub unsafe fn memset(s: *mut u8, c: u8, n: usize) { use libc::{ c_void, c_int }; use mach_o_sys::ranlib::{ rsize_t, errno_t }; extern { fn memset_s(s: *mut c_void, smax: rsize_t, c: c_int, n: rsize_t) -> errno_t; } if n > 0 && memset_s(s as *mut c_void, n as _, c as _, n as _) != 0 { std::process::abort() } } /// General `memzero`. #[cfg(any( not(any( all(windows, not(target_env = "msvc")), freebsdlike, netbsdlike )), not(feature = "use_os") ))] #[inline] pub unsafe fn memzero(dest: *mut u8, n: usize) { memset(dest, 0, n); } /// Call `explicit_bzero`. #[cfg(all(any(freebsdlike, netbsdlike), feature = "use_os"))] pub unsafe fn memzero(dest: *mut u8, n: usize) { extern { fn explicit_bzero(s: *mut libc::c_void, n: libc::size_t); } explicit_bzero(dest as *mut libc::c_void, n); } /// Call `SecureZeroMemory`. #[cfg(all(windows, not(target_env = "msvc"), feature = "use_os"))] pub unsafe fn memzero(s: *mut u8, n: usize) { extern "system" { fn RtlSecureZeroMemory(ptr: winapi::shared::ntdef::PVOID, cnt: winapi::shared::basetsd::SIZE_T); } RtlSecureZeroMemory(s as winapi::shared::ntdef::PVOID, n as winapi::shared::basetsd::SIZE_T); } memsec-0.5.6/src/mlock.rs010064400017500001750000000025031323722513000134540ustar0000000000000000//! mlock / munlock #![cfg(feature = "use_os")] /// Unix `mlock`. #[cfg(unix)] pub unsafe fn mlock(addr: *mut u8, len: usize) -> bool { #[cfg(target_os = "linux")] ::libc::madvise(addr as *mut ::libc::c_void, len, ::libc::MADV_DONTDUMP); #[cfg(freebsdlike)] ::libc::madvise(addr as *mut ::libc::c_void, len, ::libc::MADV_NOCORE); ::libc::mlock(addr as *mut ::libc::c_void, len) == 0 } /// Windows `VirtualLock`. #[cfg(windows)] pub unsafe fn mlock(addr: *mut u8, len: usize) -> bool { ::winapi::um::memoryapi::VirtualLock( addr as ::winapi::shared::minwindef::LPVOID, len as ::winapi::shared::basetsd::SIZE_T ) != 0 } /// Unix `munlock`. #[cfg(unix)] pub unsafe fn munlock(addr: *mut u8, len: usize) -> bool { ::memzero(addr, len); #[cfg(target_os = "linux")] ::libc::madvise(addr as *mut ::libc::c_void, len, ::libc::MADV_DODUMP); #[cfg(freebsdlike)] ::libc::madvise(addr as *mut ::libc::c_void, len, ::libc::MADV_CORE); ::libc::munlock(addr as *mut ::libc::c_void, len) == 0 } /// Windows `VirtualUnlock`. #[cfg(windows)] pub unsafe fn munlock(addr: *mut u8, len: usize) -> bool { ::memzero(addr, len); ::winapi::um::memoryapi::VirtualUnlock( addr as ::winapi::shared::minwindef::LPVOID, len as ::winapi::shared::basetsd::SIZE_T ) != 0 } memsec-0.5.6/.cargo_vcs_info.json0000644000000001120000000000000123460ustar00{ "git": { "sha1": "caa8d36965719f4d2026b902d3a19e7151024aa1" } }