diff --git a/.travis.yml b/.travis.yml index 0ac4a21..716757b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -91,13 +91,14 @@ matrix: - cargo test --benches # Check that setting various features does not break the build - cargo build --features=std + - cargo build --features=custom # remove cached documentation, otherwise files from previous PRs can get included - rm -rf target/doc - - cargo doc --no-deps --features=std + - cargo doc --no-deps --features=std,custom - cargo deadlinks --dir target/doc # also test minimum dependency versions are usable - cargo generate-lockfile -Z minimal-versions - - cargo test --features=std + - cargo test --features=std,custom - <<: *nightly_and_docs name: "OSX, nightly, docs" diff --git a/Cargo.toml b/Cargo.toml index 88dd1f3..1a76212 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,10 +36,12 @@ wasm-bindgen-test = "0.2" [features] std = [] +# Feature to enable custom RNG implementations +custom = [] # Unstable feature to support being a libstd dependency rustc-dep-of-std = ["compiler_builtins", "core"] # Unstable feature for testing test-in-browser = ["wasm-bindgen"] [package.metadata.docs.rs] -features = ["std"] +features = ["std", "custom"] diff --git a/src/custom.rs b/src/custom.rs new file mode 100644 index 0000000..11abf0c --- /dev/null +++ b/src/custom.rs @@ -0,0 +1,45 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! An implementation which calls out to an externally defined function. +use crate::Error; +use core::num::NonZeroU32; + +/// Register a function to be invoked by `getrandom` on custom targets. +/// +/// This function will only be invoked on targets not supported by `getrandom`. +/// This prevents crate dependencies from either inadvertently or maliciously +/// overriding the secure RNG implementations in `getrandom`. +/// +/// *This API requires the following crate features to be activated: `custom`* +#[macro_export] +macro_rules! register_custom_getrandom { + ($path:path) => { + // We use an extern "C" function to get the guarantees of a stable ABI. + #[no_mangle] + extern "C" fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 { + let slice = unsafe { ::std::slice::from_raw_parts_mut(dest, len) }; + match $path(slice) { + Ok(()) => 0, + Err(e) => e.code().get(), + } + } + }; +} + +#[allow(dead_code)] +pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { + extern "C" { + fn __getrandom_custom(dest: *mut u8, len: usize) -> u32; + } + let ret = unsafe { __getrandom_custom(dest.as_mut_ptr(), dest.len()) }; + match NonZeroU32::new(ret) { + None => Ok(()), + Some(code) => Err(Error::from(code)), + } +} diff --git a/src/lib.rs b/src/lib.rs index 1ce321e..7612ef0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,7 +134,10 @@ extern crate cfg_if; mod error; mod util; - +// To prevent a breaking change when targets are added, we always export the +// register_custom_getrandom macro, so old Custom RNG crates continue to build. +#[cfg(feature = "custom")] +mod custom; #[cfg(feature = "std")] mod error_impls; @@ -201,6 +204,8 @@ cfg_if! { "); } } + } else if #[cfg(feature = "custom")] { + use custom as imp; } else { compile_error!("\ target is not supported, for more information see: \