diff options
Diffstat (limited to 'getrandom/src')
-rw-r--r-- | getrandom/src/bsd_arandom.rs | 49 | ||||
-rw-r--r-- | getrandom/src/cloudabi.rs | 25 | ||||
-rw-r--r-- | getrandom/src/dummy.rs | 14 | ||||
-rw-r--r-- | getrandom/src/error.rs | 178 | ||||
-rw-r--r-- | getrandom/src/error_impls.rs | 35 | ||||
-rw-r--r-- | getrandom/src/fuchsia.rs | 20 | ||||
-rw-r--r-- | getrandom/src/ios.rs | 31 | ||||
-rw-r--r-- | getrandom/src/lib.rs | 282 | ||||
-rw-r--r-- | getrandom/src/linux_android.rs | 44 | ||||
-rw-r--r-- | getrandom/src/macos.rs | 34 | ||||
-rw-r--r-- | getrandom/src/openbsd.rs | 23 | ||||
-rw-r--r-- | getrandom/src/rdrand.rs | 90 | ||||
-rw-r--r-- | getrandom/src/solaris_illumos.rs | 44 | ||||
-rw-r--r-- | getrandom/src/use_file.rs | 73 | ||||
-rw-r--r-- | getrandom/src/util.rs | 96 | ||||
-rw-r--r-- | getrandom/src/util_libc.rs | 143 | ||||
-rw-r--r-- | getrandom/src/vxworks.rs | 35 | ||||
-rw-r--r-- | getrandom/src/wasi.rs | 19 | ||||
-rw-r--r-- | getrandom/src/wasm32_bindgen.rs | 113 | ||||
-rw-r--r-- | getrandom/src/wasm32_stdweb.rs | 114 | ||||
-rw-r--r-- | getrandom/src/windows.rs | 26 | ||||
-rw-r--r-- | getrandom/src/windows_uwp.rs | 59 |
22 files changed, 0 insertions, 1547 deletions
diff --git a/getrandom/src/bsd_arandom.rs b/getrandom/src/bsd_arandom.rs deleted file mode 100644 index eb564ff..0000000 --- a/getrandom/src/bsd_arandom.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for FreeBSD and NetBSD -use crate::util_libc::sys_fill_exact; -use crate::Error; -use core::ptr; - -fn kern_arnd(buf: &mut [u8]) -> libc::ssize_t { - static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND]; - let mut len = buf.len(); - let ret = unsafe { - libc::sysctl( - MIB.as_ptr(), - MIB.len() as libc::c_uint, - buf.as_mut_ptr() as *mut _, - &mut len, - ptr::null(), - 0, - ) - }; - if ret == -1 { - error!("sysctl kern.arandom: syscall failed"); - -1 - } else { - len as libc::ssize_t - } -} - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - #[cfg(target_os = "freebsd")] - { - use crate::util_libc::Weak; - static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") }; - type GetRandomFn = - unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t; - - if let Some(fptr) = GETRANDOM.ptr() { - let func: GetRandomFn = unsafe { core::mem::transmute(fptr) }; - return sys_fill_exact(dest, |buf| unsafe { func(buf.as_mut_ptr(), buf.len(), 0) }); - } - } - sys_fill_exact(dest, kern_arnd) -} diff --git a/getrandom/src/cloudabi.rs b/getrandom/src/cloudabi.rs deleted file mode 100644 index d3d0928..0000000 --- a/getrandom/src/cloudabi.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for CloudABI -use crate::Error; -use core::num::NonZeroU32; - -extern "C" { - fn cloudabi_sys_random_get(buf: *mut u8, buf_len: usize) -> u16; -} - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - let errno = unsafe { cloudabi_sys_random_get(dest.as_mut_ptr(), dest.len()) }; - if let Some(code) = NonZeroU32::new(errno as u32) { - error!("cloudabi_sys_random_get: failed with {}", errno); - Err(Error::from(code)) - } else { - Ok(()) // Zero means success for CloudABI - } -} diff --git a/getrandom/src/dummy.rs b/getrandom/src/dummy.rs deleted file mode 100644 index 0c24ba0..0000000 --- a/getrandom/src/dummy.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A dummy implementation for unsupported targets which always fails -use crate::{error::UNSUPPORTED, Error}; - -pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> { - Err(UNSUPPORTED) -} diff --git a/getrandom/src/error.rs b/getrandom/src/error.rs deleted file mode 100644 index b2cb9a8..0000000 --- a/getrandom/src/error.rs +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -use core::fmt; -use core::num::NonZeroU32; - -/// A small and `no_std` compatible error type. -/// -/// The [`Error::raw_os_error()`] will indicate if the error is from the OS, and -/// if so, which error code the OS gave the application. If such an error is -/// encountered, please consult with your system documentation. -/// -/// Internally this type is a NonZeroU32, with certain values reserved for -/// certain purposes, see [`Error::INTERNAL_START`] and [`Error::CUSTOM_START`]. -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct Error(NonZeroU32); - -impl Error { - #[deprecated(since = "0.1.7")] - /// Unknown error. - pub const UNKNOWN: Error = UNSUPPORTED; - #[deprecated(since = "0.1.7")] - /// System entropy source is unavailable. - pub const UNAVAILABLE: Error = UNSUPPORTED; - - /// Codes below this point represent OS Errors (i.e. positive i32 values). - /// Codes at or above this point, but below [`Error::CUSTOM_START`] are - /// reserved for use by the `rand` and `getrandom` crates. - pub const INTERNAL_START: u32 = 1 << 31; - - /// Codes at or above this point can be used by users to define their own - /// custom errors. - pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30); - - /// Extract the raw OS error code (if this error came from the OS) - /// - /// This method is identical to `std::io::Error::raw_os_error()`, except - /// that it works in `no_std` contexts. If this method returns `None`, the - /// error value can still be formatted via the `Display` implementation. - #[inline] - pub fn raw_os_error(self) -> Option<i32> { - if self.0.get() < Self::INTERNAL_START { - Some(self.0.get() as i32) - } else { - None - } - } - - /// Extract the bare error code. - /// - /// This code can either come from the underlying OS, or be a custom error. - /// Use [`Error::raw_os_error()`] to disambiguate. - #[inline] - pub fn code(self) -> NonZeroU32 { - self.0 - } -} - -cfg_if! { - if #[cfg(unix)] { - fn os_err_desc(errno: i32, buf: &mut [u8]) -> Option<&str> { - let buf_ptr = buf.as_mut_ptr() as *mut libc::c_char; - if unsafe { libc::strerror_r(errno, buf_ptr, buf.len()) } != 0 { - return None; - } - - // Take up to trailing null byte - let n = buf.len(); - let idx = buf.iter().position(|&b| b == 0).unwrap_or(n); - core::str::from_utf8(&buf[..idx]).ok() - } - } else if #[cfg(target_os = "wasi")] { - fn os_err_desc(errno: i32, _buf: &mut [u8]) -> Option<&str> { - core::num::NonZeroU16::new(errno as u16) - .and_then(wasi::wasi_unstable::error_str) - } - } else { - fn os_err_desc(_errno: i32, _buf: &mut [u8]) -> Option<&str> { - None - } - } -} - -impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut dbg = f.debug_struct("Error"); - if let Some(errno) = self.raw_os_error() { - dbg.field("os_error", &errno); - let mut buf = [0u8; 128]; - if let Some(desc) = os_err_desc(errno, &mut buf) { - dbg.field("description", &desc); - } - } else if let Some(desc) = internal_desc(*self) { - dbg.field("internal_code", &self.0.get()); - dbg.field("description", &desc); - } else { - dbg.field("unknown_code", &self.0.get()); - } - dbg.finish() - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(errno) = self.raw_os_error() { - let mut buf = [0u8; 128]; - match os_err_desc(errno, &mut buf) { - Some(desc) => f.write_str(desc), - None => write!(f, "OS Error: {}", errno), - } - } else if let Some(desc) = internal_desc(*self) { - f.write_str(desc) - } else { - write!(f, "Unknown Error: {}", self.0.get()) - } - } -} - -impl From<NonZeroU32> for Error { - fn from(code: NonZeroU32) -> Self { - Self(code) - } -} - -// TODO: Convert to a function when min_version >= 1.33 -macro_rules! internal_error { - ($n:expr) => { - Error(unsafe { NonZeroU32::new_unchecked(Error::INTERNAL_START + $n as u16 as u32) }) - }; -} - -/// Internal Error constants -pub(crate) const UNSUPPORTED: Error = internal_error!(0); -pub(crate) const ERRNO_NOT_POSITIVE: Error = internal_error!(1); -pub(crate) const UNKNOWN_IO_ERROR: Error = internal_error!(2); -pub(crate) const SEC_RANDOM_FAILED: Error = internal_error!(3); -pub(crate) const RTL_GEN_RANDOM_FAILED: Error = internal_error!(4); -pub(crate) const FAILED_RDRAND: Error = internal_error!(5); -pub(crate) const NO_RDRAND: Error = internal_error!(6); -pub(crate) const BINDGEN_CRYPTO_UNDEF: Error = internal_error!(7); -pub(crate) const BINDGEN_GRV_UNDEF: Error = internal_error!(8); -pub(crate) const STDWEB_NO_RNG: Error = internal_error!(9); -pub(crate) const STDWEB_RNG_FAILED: Error = internal_error!(10); -pub(crate) const RAND_SECURE_FATAL: Error = internal_error!(11); - -fn internal_desc(error: Error) -> Option<&'static str> { - match error { - UNSUPPORTED => Some("getrandom: this target is not supported"), - ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"), - UNKNOWN_IO_ERROR => Some("Unknown std::io::Error"), - SEC_RANDOM_FAILED => Some("SecRandomCopyBytes: call failed"), - RTL_GEN_RANDOM_FAILED => Some("RtlGenRandom: call failed"), - FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"), - NO_RDRAND => Some("RDRAND: instruction not supported"), - BINDGEN_CRYPTO_UNDEF => Some("wasm-bindgen: self.crypto is undefined"), - BINDGEN_GRV_UNDEF => Some("wasm-bindgen: crypto.getRandomValues is undefined"), - STDWEB_NO_RNG => Some("stdweb: no randomness source available"), - STDWEB_RNG_FAILED => Some("stdweb: failed to get randomness"), - RAND_SECURE_FATAL => Some("randSecure: random number generator module is not initialized"), - _ => None, - } -} - -#[cfg(test)] -mod tests { - use super::Error; - use core::mem::size_of; - - #[test] - fn test_size() { - assert_eq!(size_of::<Error>(), 4); - assert_eq!(size_of::<Result<(), Error>>(), 4); - } -} diff --git a/getrandom/src/error_impls.rs b/getrandom/src/error_impls.rs deleted file mode 100644 index 007472e..0000000 --- a/getrandom/src/error_impls.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -extern crate std; - -use crate::{error::UNKNOWN_IO_ERROR, Error}; -use core::convert::From; -use core::num::NonZeroU32; -use std::io; - -impl From<io::Error> for Error { - fn from(err: io::Error) -> Self { - if let Some(errno) = err.raw_os_error() { - if let Some(code) = NonZeroU32::new(errno as u32) { - return Error::from(code); - } - } - UNKNOWN_IO_ERROR - } -} - -impl From<Error> for io::Error { - fn from(err: Error) -> Self { - match err.raw_os_error() { - Some(errno) => io::Error::from_raw_os_error(errno), - None => io::Error::new(io::ErrorKind::Other, err), - } - } -} - -impl std::error::Error for Error {} diff --git a/getrandom/src/fuchsia.rs b/getrandom/src/fuchsia.rs deleted file mode 100644 index 572ff53..0000000 --- a/getrandom/src/fuchsia.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for Fuchsia Zircon -use crate::Error; - -#[link(name = "zircon")] -extern "C" { - fn zx_cprng_draw(buffer: *mut u8, length: usize); -} - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - unsafe { zx_cprng_draw(dest.as_mut_ptr(), dest.len()) } - Ok(()) -} diff --git a/getrandom/src/ios.rs b/getrandom/src/ios.rs deleted file mode 100644 index 30c008c..0000000 --- a/getrandom/src/ios.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for iOS -use crate::{error::SEC_RANDOM_FAILED, Error}; - -// TODO: Make extern once extern_types feature is stabilized. See: -// https://github.com/rust-lang/rust/issues/43467 -#[repr(C)] -struct SecRandom([u8; 0]); - -#[link(name = "Security", kind = "framework")] -extern "C" { - static kSecRandomDefault: *const SecRandom; - - fn SecRandomCopyBytes(rnd: *const SecRandom, count: usize, bytes: *mut u8) -> i32; -} - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, dest.len(), dest.as_mut_ptr()) }; - if ret == -1 { - Err(SEC_RANDOM_FAILED) - } else { - Ok(()) - } -} diff --git a/getrandom/src/lib.rs b/getrandom/src/lib.rs deleted file mode 100644 index c305406..0000000 --- a/getrandom/src/lib.rs +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2019 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Interface to the random number generator of the operating system. -//! -//! # Platform sources -//! -//! | OS | interface -//! |------------------|--------------------------------------------------------- -//! | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` -//! | Windows | [`RtlGenRandom`][3] -//! | macOS | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`) -//! | iOS | [`SecRandomCopyBytes`][4] -//! | FreeBSD | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5] -//! | OpenBSD | [`getentropy`][6] -//! | NetBSD | [`kern.arandom`][7] -//! | Dragonfly BSD | [`/dev/random`][8] -//! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10] -//! | Fuchsia OS | [`cprng_draw`][11] -//! | Redox | [`rand:`][12] -//! | CloudABI | [`cloudabi_sys_random_get`][13] -//! | Haiku | `/dev/random` (identical to `/dev/urandom`) -//! | L4RE, SGX, UEFI | [RDRAND][18] -//! | Hermit | [RDRAND][18] as [`sys_rand`][22] is currently broken. -//! | VxWorks | `randABytes` after checking entropy pool initialization with `randSecure` -//! | Web browsers | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and asm.js][16]) -//! | Node.js | [`crypto.randomBytes`][15] (see [Support for WebAssembly and asm.js][16]) -//! | WASI | [`__wasi_random_get`][17] -//! -//! Getrandom doesn't have a blanket implementation for all Unix-like operating -//! systems that reads from `/dev/urandom`. This ensures all supported operating -//! systems are using the recommended interface and respect maximum buffer -//! sizes. -//! -//! ## Unsupported targets -//! -//! By default, compiling `getrandom` for an unsupported target will result in -//! a compilation error. If you want to build an application which uses `getrandom` -//! for such target, you can either: -//! - Use [`[replace]`][replace] or [`[patch]`][patch] section in your `Cargo.toml` -//! to switch to a custom implementation with a support of your target. -//! - Enable the `dummy` feature to have getrandom use an implementation that always -//! fails at run-time on unsupported targets. -//! -//! [replace]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-replace-section -//! [patch]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section -//! -//! ## Support for WebAssembly and asm.js -//! -//! Getrandom supports all of Rust's current `wasm32` targets, and it works with -//! both Node.js and web browsers. The three Emscripten targets -//! `asmjs-unknown-emscripten`, `wasm32-unknown-emscripten`, and -//! `wasm32-experimental-emscripten` use Emscripten's `/dev/random` emulation. -//! The WASI target `wasm32-wasi` uses the [`__wasi_random_get`][17] function -//! defined by the WASI standard. -//! -//! Getrandom also supports `wasm32-unknown-unknown` by directly calling -//! JavaScript methods. Rust currently has two ways to do this: [bindgen] and -//! [stdweb]. Getrandom supports using either one by enabling the -//! `wasm-bindgen` or `stdweb` crate features. Note that if both features are -//! enabled, `wasm-bindgen` will be used. If neither feature is enabled, calls -//! to `getrandom` will always fail at runtime. -//! -//! [bindgen]: https://github.com/rust-lang/rust-bindgen -//! [stdweb]: https://github.com/koute/stdweb -//! -//! ## Early boot -//! -//! It is possible that early in the boot process the OS hasn't had enough time -//! yet to collect entropy to securely seed its RNG, especially on virtual -//! machines. -//! -//! Some operating systems always block the thread until the RNG is securely -//! seeded. This can take anywhere from a few seconds to more than a minute. -//! Others make a best effort to use a seed from before the shutdown and don't -//! document much. -//! -//! A few, Linux, NetBSD and Solaris, offer a choice between blocking and -//! getting an error; in these cases we always choose to block. -//! -//! On Linux (when the `getrandom` system call is not available) and on NetBSD -//! reading from `/dev/urandom` never blocks, even when the OS hasn't collected -//! enough entropy yet. To avoid returning low-entropy bytes, we first read from -//! `/dev/random` and only switch to `/dev/urandom` once this has succeeded. -//! -//! # Error handling -//! -//! We always choose failure over returning insecure "random" bytes. In general, -//! on supported platforms, failure is highly unlikely, though not impossible. -//! If an error does occur, then it is likely that it will occur on every call to -//! `getrandom`, hence after the first successful call one can be reasonably -//! confident that no errors will occur. -//! -//! On unsupported platforms, `getrandom` always fails. See the [`Error`] type -//! for more information on what data is returned on failure. -//! -//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html -//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html -//! [3]: https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/nf-ntsecapi-rtlgenrandom -//! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc -//! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4 -//! [6]: https://man.openbsd.org/getentropy.2 -//! [7]: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7+NetBSD-8.0 -//! [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random§ion=4 -//! [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html -//! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html -//! [11]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw -//! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs -//! [13]: https://github.com/nuxinl/cloudabi#random_get -//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues -//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback -//! [16]: #support-for-webassembly-and-asmjs -//! [17]: https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md#__wasi_random_get -//! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide -//! [19]: https://www.unix.com/man-page/mojave/2/getentropy/ -//! [20]: https://www.unix.com/man-page/mojave/4/random/ -//! [21]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable -//! [22]: https://github.com/hermitcore/libhermit-rs/blob/09c38b0371cee6f56a541400ba453e319e43db53/src/syscalls/random.rs#L21 - -#![doc( - html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", - html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://rust-random.github.io/rand/" -)] -#![no_std] -#![cfg_attr(feature = "stdweb", recursion_limit = "128")] -#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)] - -#[macro_use] -extern crate cfg_if; - -cfg_if! { - if #[cfg(feature = "log")] { - #[allow(unused)] - #[macro_use] - extern crate log; - } else { - #[allow(unused)] - macro_rules! error { - ($($x:tt)*) => {}; - } - #[allow(unused)] - macro_rules! warn { - ($($x:tt)*) => {}; - } - #[allow(unused)] - macro_rules! info { - ($($x:tt)*) => {}; - } - } -} - -mod error; -pub use crate::error::Error; - -#[allow(dead_code)] -mod util; - -#[cfg(target_os = "vxworks")] -#[allow(dead_code)] -mod util_libc; - -cfg_if! { - // Unlike the other Unix, Fuchsia and iOS don't use the libc to make any calls. - if #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "emscripten", - target_os = "freebsd", target_os = "haiku", target_os = "illumos", - target_os = "linux", target_os = "macos", target_os = "netbsd", - target_os = "openbsd", target_os = "redox", target_os = "solaris"))] { - #[allow(dead_code)] - mod util_libc; - // Keep std-only trait definitions for backwards compatibility - mod error_impls; - } else if #[cfg(feature = "std")] { - mod error_impls; - } -} - -// These targets read from a file as a fallback method. -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "macos", - target_os = "solaris", - target_os = "illumos", -))] -mod use_file; - -// System-specific implementations. -// -// These should all provide getrandom_inner with the same signature as getrandom. -cfg_if! { - if #[cfg(target_os = "android")] { - #[path = "linux_android.rs"] mod imp; - } else if #[cfg(target_os = "cloudabi")] { - #[path = "cloudabi.rs"] mod imp; - } else if #[cfg(target_os = "dragonfly")] { - #[path = "use_file.rs"] mod imp; - } else if #[cfg(target_os = "emscripten")] { - #[path = "use_file.rs"] mod imp; - } else if #[cfg(target_os = "freebsd")] { - #[path = "bsd_arandom.rs"] mod imp; - } else if #[cfg(target_os = "fuchsia")] { - #[path = "fuchsia.rs"] mod imp; - } else if #[cfg(target_os = "haiku")] { - #[path = "use_file.rs"] mod imp; - } else if #[cfg(target_os = "illumos")] { - #[path = "solaris_illumos.rs"] mod imp; - } else if #[cfg(target_os = "ios")] { - #[path = "ios.rs"] mod imp; - } else if #[cfg(target_os = "linux")] { - #[path = "linux_android.rs"] mod imp; - } else if #[cfg(target_os = "macos")] { - #[path = "macos.rs"] mod imp; - } else if #[cfg(target_os = "netbsd")] { - #[path = "bsd_arandom.rs"] mod imp; - } else if #[cfg(target_os = "openbsd")] { - #[path = "openbsd.rs"] mod imp; - } else if #[cfg(target_os = "redox")] { - #[path = "use_file.rs"] mod imp; - } else if #[cfg(target_os = "solaris")] { - #[path = "solaris_illumos.rs"] mod imp; - } else if #[cfg(target_os = "wasi")] { - #[path = "wasi.rs"] mod imp; - } else if #[cfg(target_os = "vxworks")] { - #[path = "vxworks.rs"] mod imp; - } else if #[cfg(all(windows, getrandom_uwp))] { - #[path = "windows_uwp.rs"] mod imp; - } else if #[cfg(windows)] { - #[path = "windows.rs"] mod imp; - } else if #[cfg(all(target_arch = "x86_64", any( - target_os = "hermit", - target_os = "l4re", - target_os = "uefi", - target_env = "sgx", - )))] { - #[path = "rdrand.rs"] mod imp; - } else if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] { - cfg_if! { - if #[cfg(feature = "wasm-bindgen")] { - #[path = "wasm32_bindgen.rs"] mod imp; - } else if #[cfg(feature = "stdweb")] { - #[path = "wasm32_stdweb.rs"] mod imp; - } else { - // Always have an implementation for wasm32-unknown-unknown. - // See https://github.com/rust-random/getrandom/issues/87 - #[path = "dummy.rs"] mod imp; - } - } - } else if #[cfg(feature = "dummy")] { - #[path = "dummy.rs"] mod imp; - } else { - compile_error!("\ - target is not supported, for more information see: \ - https://docs.rs/getrandom/#unsupported-targets\ - "); - } -} - -/// Fill `dest` with random bytes from the system's preferred random number -/// source. -/// -/// This function returns an error on any failure, including partial reads. We -/// make no guarantees regarding the contents of `dest` on error. If `dest` is -/// empty, `getrandom` immediately returns success, making no calls to the -/// underlying operating system. -/// -/// Blocking is possible, at least during early boot; see module documentation. -/// -/// In general, `getrandom` will be fast enough for interactive usage, though -/// significantly slower than a user-space CSPRNG; for the latter consider -/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html). -pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> { - if dest.is_empty() { - return Ok(()); - } - imp::getrandom_inner(dest) -} diff --git a/getrandom/src/linux_android.rs b/getrandom/src/linux_android.rs deleted file mode 100644 index a29feb5..0000000 --- a/getrandom/src/linux_android.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for Linux / Android -use crate::util::LazyBool; -use crate::util_libc::{last_os_error, sys_fill_exact}; -use crate::{use_file, Error}; - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - static HAS_GETRANDOM: LazyBool = LazyBool::new(); - if HAS_GETRANDOM.unsync_init(is_getrandom_available) { - sys_fill_exact(dest, |buf| unsafe { - getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0) - }) - } else { - use_file::getrandom_inner(dest) - } -} - -fn is_getrandom_available() -> bool { - let res = unsafe { getrandom(core::ptr::null_mut(), 0, libc::GRND_NONBLOCK) }; - if res < 0 { - match last_os_error().raw_os_error() { - Some(libc::ENOSYS) => false, // No kernel support - Some(libc::EPERM) => false, // Blocked by seccomp - _ => true, - } - } else { - true - } -} - -unsafe fn getrandom( - buf: *mut libc::c_void, - buflen: libc::size_t, - flags: libc::c_uint, -) -> libc::ssize_t { - libc::syscall(libc::SYS_getrandom, buf, buflen, flags) as libc::ssize_t -} diff --git a/getrandom/src/macos.rs b/getrandom/src/macos.rs deleted file mode 100644 index c3bc533..0000000 --- a/getrandom/src/macos.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for macOS -use crate::util_libc::{last_os_error, Weak}; -use crate::{use_file, Error}; -use core::mem; - -type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int; - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - static GETENTROPY: Weak = unsafe { Weak::new("getentropy\0") }; - if let Some(fptr) = GETENTROPY.ptr() { - let func: GetEntropyFn = unsafe { mem::transmute(fptr) }; - for chunk in dest.chunks_mut(256) { - let ret = unsafe { func(chunk.as_mut_ptr(), chunk.len()) }; - if ret != 0 { - let err = last_os_error(); - error!("getentropy syscall failed"); - return Err(err); - } - } - Ok(()) - } else { - // We fallback to reading from /dev/random instead of SecRandomCopyBytes - // to avoid high startup costs and linking the Security framework. - use_file::getrandom_inner(dest) - } -} diff --git a/getrandom/src/openbsd.rs b/getrandom/src/openbsd.rs deleted file mode 100644 index e1ac179..0000000 --- a/getrandom/src/openbsd.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for OpenBSD -use crate::util_libc::last_os_error; -use crate::Error; - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - for chunk in dest.chunks_mut(256) { - let ret = unsafe { libc::getentropy(chunk.as_mut_ptr() as *mut libc::c_void, chunk.len()) }; - if ret == -1 { - let err = last_os_error(); - error!("libc::getentropy call failed"); - return Err(err); - } - } - Ok(()) -} diff --git a/getrandom/src/rdrand.rs b/getrandom/src/rdrand.rs deleted file mode 100644 index e441682..0000000 --- a/getrandom/src/rdrand.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for SGX using RDRAND instruction -use crate::error::{FAILED_RDRAND, NO_RDRAND}; -#[cfg(not(target_feature = "rdrand"))] -use crate::util::LazyBool; -use crate::Error; -use core::arch::x86_64::_rdrand64_step; -use core::mem; - -// Recommendation from "Intel® Digital Random Number Generator (DRNG) Software -// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures -// Software Developer’s Manual" - Volume 1 - Section 7.3.17.1. -const RETRY_LIMIT: usize = 10; -const WORD_SIZE: usize = mem::size_of::<u64>(); - -#[target_feature(enable = "rdrand")] -unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> { - for _ in 0..RETRY_LIMIT { - let mut el = mem::zeroed(); - if _rdrand64_step(&mut el) == 1 { - // AMD CPUs from families 14h to 16h (pre Ryzen) sometimes fail to - // set CF on bogus random data, so we check these values explicitly. - // See https://github.com/systemd/systemd/issues/11810#issuecomment-489727505 - // We perform this check regardless of target to guard against - // any implementation that incorrectly fails to set CF. - if el != 0 && el != !0 { - return Ok(el.to_ne_bytes()); - } - error!("RDRAND returned {:X}, CPU RNG may be broken", el); - // Keep looping in case this was a false positive. - } - } - Err(FAILED_RDRAND) -} - -// "rdrand" target feature requires "+rdrnd" flag, see https://github.com/rust-lang/rust/issues/49653. -#[cfg(all(target_env = "sgx", not(target_feature = "rdrand")))] -compile_error!( - "SGX targets require 'rdrand' target feature. Enable by using -C target-feature=+rdrnd." -); - -#[cfg(target_feature = "rdrand")] -fn is_rdrand_supported() -> bool { - true -} - -// TODO use is_x86_feature_detected!("rdrand") when that works in core. See: -// https://github.com/rust-lang-nursery/stdsimd/issues/464 -#[cfg(not(target_feature = "rdrand"))] -fn is_rdrand_supported() -> bool { - use core::arch::x86_64::__cpuid; - // SAFETY: All x86_64 CPUs support CPUID leaf 1 - const FLAG: u32 = 1 << 30; - static HAS_RDRAND: LazyBool = LazyBool::new(); - HAS_RDRAND.unsync_init(|| unsafe { (__cpuid(1).ecx & FLAG) != 0 }) -} - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - if !is_rdrand_supported() { - return Err(NO_RDRAND); - } - - // SAFETY: After this point, rdrand is supported, so calling the rdrand - // functions is not undefined behavior. - unsafe { rdrand_exact(dest) } -} - -#[target_feature(enable = "rdrand")] -unsafe fn rdrand_exact(dest: &mut [u8]) -> Result<(), Error> { - // We use chunks_exact_mut instead of chunks_mut as it allows almost all - // calls to memcpy to be elided by the compiler. - let mut chunks = dest.chunks_exact_mut(WORD_SIZE); - for chunk in chunks.by_ref() { - chunk.copy_from_slice(&rdrand()?); - } - - let tail = chunks.into_remainder(); - let n = tail.len(); - if n > 0 { - tail.copy_from_slice(&rdrand()?[..n]); - } - Ok(()) -} diff --git a/getrandom/src/solaris_illumos.rs b/getrandom/src/solaris_illumos.rs deleted file mode 100644 index 9473123..0000000 --- a/getrandom/src/solaris_illumos.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for the Solaris family -//! -//! Read from `/dev/random`, with chunks of limited size (256 bytes). -//! `/dev/random` uses the Hash_DRBG with SHA512 algorithm from NIST SP 800-90A. -//! `/dev/urandom` uses the FIPS 186-2 algorithm, which is considered less -//! secure. We choose to read from `/dev/random`. -//! -//! Since Solaris 11.3 and mid-2015 illumos, the `getrandom` syscall is available. -//! To make sure we can compile on both Solaris and its derivatives, as well as -//! function, we check for the existence of getrandom(2) in libc by calling -//! libc::dlsym. -use crate::util_libc::{sys_fill_exact, Weak}; -use crate::{use_file, Error}; -use core::mem; - -#[cfg(target_os = "illumos")] -type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t; -#[cfg(target_os = "solaris")] -type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::c_int; - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") }; - if let Some(fptr) = GETRANDOM.ptr() { - let func: GetRandomFn = unsafe { mem::transmute(fptr) }; - // 256 bytes is the lowest common denominator across all the Solaris - // derived platforms for atomically obtaining random data. - for chunk in dest.chunks_mut(256) { - sys_fill_exact(chunk, |buf| unsafe { - func(buf.as_mut_ptr(), buf.len(), 0) as libc::ssize_t - })? - } - Ok(()) - } else { - use_file::getrandom_inner(dest) - } -} diff --git a/getrandom/src/use_file.rs b/getrandom/src/use_file.rs deleted file mode 100644 index d3adaf2..0000000 --- a/getrandom/src/use_file.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementations that just need to read from a file -use crate::util_libc::{last_os_error, open_readonly, sys_fill_exact, LazyFd}; -use crate::Error; - -#[cfg(target_os = "redox")] -const FILE_PATH: &str = "rand:\0"; -#[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "haiku", - target_os = "macos", - target_os = "solaris", - target_os = "illumos" -))] -const FILE_PATH: &str = "/dev/random\0"; - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - static FD: LazyFd = LazyFd::new(); - let fd = FD.init(init_file).ok_or_else(last_os_error)?; - let read = |buf: &mut [u8]| unsafe { libc::read(fd, buf.as_mut_ptr() as *mut _, buf.len()) }; - - if cfg!(target_os = "emscripten") { - // `Crypto.getRandomValues` documents `dest` should be at most 65536 bytes. - for chunk in dest.chunks_mut(65536) { - sys_fill_exact(chunk, read)?; - } - } else { - sys_fill_exact(dest, read)?; - } - Ok(()) -} - -cfg_if! { - if #[cfg(any(target_os = "android", target_os = "linux"))] { - fn init_file() -> Option<libc::c_int> { - // Poll /dev/random to make sure it is ok to read from /dev/urandom. - let mut pfd = libc::pollfd { - fd: unsafe { open_readonly("/dev/random\0")? }, - events: libc::POLLIN, - revents: 0, - }; - - let ret = loop { - // A negative timeout means an infinite timeout. - let res = unsafe { libc::poll(&mut pfd, 1, -1) }; - if res == 1 { - break unsafe { open_readonly("/dev/urandom\0") }; - } else if res < 0 { - let e = last_os_error().raw_os_error(); - if e == Some(libc::EINTR) || e == Some(libc::EAGAIN) { - continue; - } - } - // We either hard failed, or poll() returned the wrong pfd. - break None; - }; - unsafe { libc::close(pfd.fd) }; - ret - } - } else { - fn init_file() -> Option<libc::c_int> { - unsafe { open_readonly(FILE_PATH) } - } - } -} diff --git a/getrandom/src/util.rs b/getrandom/src/util.rs deleted file mode 100644 index e0e9307..0000000 --- a/getrandom/src/util.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2019 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; - -// This structure represents a lazily initialized static usize value. Useful -// when it is preferable to just rerun initialization instead of locking. -// Both unsync_init and sync_init will invoke an init() function until it -// succeeds, then return the cached value for future calls. -// -// Both methods support init() "failing". If the init() method returns UNINIT, -// that value will be returned as normal, but will not be cached. -// -// Users should only depend on the _value_ returned by init() functions. -// Specifically, for the following init() function: -// fn init() -> usize { -// a(); -// let v = b(); -// c(); -// v -// } -// the effects of c() or writes to shared memory will not necessarily be -// observed and additional synchronization methods with be needed. -pub struct LazyUsize(AtomicUsize); - -impl LazyUsize { - pub const fn new() -> Self { - Self(AtomicUsize::new(Self::UNINIT)) - } - - // The initialization is not completed. - pub const UNINIT: usize = usize::max_value(); - // The initialization is currently running. - pub const ACTIVE: usize = usize::max_value() - 1; - - // Runs the init() function at least once, returning the value of some run - // of init(). Multiple callers can run their init() functions in parallel. - // init() should always return the same value, if it succeeds. - pub fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize { - // Relaxed ordering is fine, as we only have a single atomic variable. - let mut val = self.0.load(Relaxed); - if val == Self::UNINIT { - val = init(); - self.0.store(val, Relaxed); - } - val - } - - // Synchronously runs the init() function. Only one caller will have their - // init() function running at a time, and exactly one successful call will - // be run. init() returning UNINIT or ACTIVE will be considered a failure, - // and future calls to sync_init will rerun their init() function. - pub fn sync_init(&self, init: impl FnOnce() -> usize, mut wait: impl FnMut()) -> usize { - // Common and fast path with no contention. Don't wast time on CAS. - match self.0.load(Relaxed) { - Self::UNINIT | Self::ACTIVE => {} - val => return val, - } - // Relaxed ordering is fine, as we only have a single atomic variable. - loop { - match self.0.compare_and_swap(Self::UNINIT, Self::ACTIVE, Relaxed) { - Self::UNINIT => { - let val = init(); - self.0.store( - match val { - Self::UNINIT | Self::ACTIVE => Self::UNINIT, - val => val, - }, - Relaxed, - ); - return val; - } - Self::ACTIVE => wait(), - val => return val, - } - } - } -} - -// Identical to LazyUsize except with bool instead of usize. -pub struct LazyBool(LazyUsize); - -impl LazyBool { - pub const fn new() -> Self { - Self(LazyUsize::new()) - } - - pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool { - self.0.unsync_init(|| init() as usize) != 0 - } -} diff --git a/getrandom/src/util_libc.rs b/getrandom/src/util_libc.rs deleted file mode 100644 index 5a05170..0000000 --- a/getrandom/src/util_libc.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2019 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -use crate::error::ERRNO_NOT_POSITIVE; -use crate::util::LazyUsize; -use crate::Error; -use core::num::NonZeroU32; -use core::ptr::NonNull; - -cfg_if! { - if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] { - use libc::__errno as errno_location; - } else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "redox"))] { - use libc::__errno_location as errno_location; - } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] { - use libc::___errno as errno_location; - } else if #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly"))] { - use libc::__error as errno_location; - } else if #[cfg(target_os = "haiku")] { - use libc::_errnop as errno_location; - } -} - -pub fn last_os_error() -> Error { - #[cfg(not(target_os = "vxworks"))] - let errno = unsafe { *errno_location() }; - #[cfg(target_os = "vxworks")] - let errno = unsafe { libc::errnoGet() }; - if errno > 0 { - Error::from(NonZeroU32::new(errno as u32).unwrap()) - } else { - ERRNO_NOT_POSITIVE - } -} - -// Fill a buffer by repeatedly invoking a system call. The `sys_fill` function: -// - should return -1 and set errno on failure -// - should return the number of bytes written on success -pub fn sys_fill_exact( - mut buf: &mut [u8], - sys_fill: impl Fn(&mut [u8]) -> libc::ssize_t, -) -> Result<(), Error> { - while !buf.is_empty() { - let res = sys_fill(buf); - if res < 0 { - let err = last_os_error(); - // We should try again if the call was interrupted. - if err.raw_os_error() != Some(libc::EINTR) { - return Err(err); - } - } else { - // We don't check for EOF (ret = 0) as the data we are reading - // should be an infinite stream of random bytes. - buf = &mut buf[(res as usize)..]; - } - } - Ok(()) -} - -// A "weak" binding to a C function that may or may not be present at runtime. -// Used for supporting newer OS features while still building on older systems. -// F must be a function pointer of type `unsafe extern "C" fn`. Based off of the -// weak! macro in libstd. -pub struct Weak { - name: &'static str, - addr: LazyUsize, -} - -impl Weak { - // Construct a binding to a C function with a given name. This function is - // unsafe because `name` _must_ be null terminated. - pub const unsafe fn new(name: &'static str) -> Self { - Self { - name, - addr: LazyUsize::new(), - } - } - - // Return a function pointer if present at runtime. Otherwise, return null. - pub fn ptr(&self) -> Option<NonNull<libc::c_void>> { - let addr = self.addr.unsync_init(|| unsafe { - libc::dlsym(libc::RTLD_DEFAULT, self.name.as_ptr() as *const _) as usize - }); - NonNull::new(addr as *mut _) - } -} - -pub struct LazyFd(LazyUsize); - -impl LazyFd { - pub const fn new() -> Self { - Self(LazyUsize::new()) - } - - // If init() returns Some(x), x should be nonnegative. - pub fn init(&self, init: impl FnOnce() -> Option<libc::c_int>) -> Option<libc::c_int> { - let fd = self.0.sync_init( - || match init() { - // OK as val >= 0 and val <= c_int::MAX < usize::MAX - Some(val) => val as usize, - None => LazyUsize::UNINIT, - }, - || unsafe { - // We are usually waiting on an open(2) syscall to complete, - // which typically takes < 10us if the file is a device. - // However, we might end up waiting much longer if the entropy - // pool isn't initialized, but even in that case, this loop will - // consume a negligible amount of CPU on most platforms. - libc::usleep(10); - }, - ); - match fd { - LazyUsize::UNINIT => None, - val => Some(val as libc::c_int), - } - } -} - -cfg_if! { - if #[cfg(any(target_os = "linux", target_os = "emscripten"))] { - use libc::open64 as open; - } else { - use libc::open; - } -} - -// SAFETY: path must be null terminated, FD must be manually closed. -pub unsafe fn open_readonly(path: &str) -> Option<libc::c_int> { - debug_assert!(path.as_bytes().last() == Some(&0)); - let fd = open(path.as_ptr() as *mut _, libc::O_RDONLY | libc::O_CLOEXEC); - if fd < 0 { - return None; - } - // O_CLOEXEC works on all Unix targets except for older Linux kernels (pre - // 2.6.23), so we also use an ioctl to make sure FD_CLOEXEC is set. - #[cfg(target_os = "linux")] - libc::ioctl(fd, libc::FIOCLEX); - Some(fd) -} diff --git a/getrandom/src/vxworks.rs b/getrandom/src/vxworks.rs deleted file mode 100644 index a2fe52a..0000000 --- a/getrandom/src/vxworks.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for VxWorks -use crate::error::{Error, RAND_SECURE_FATAL}; -use crate::util_libc::last_os_error; -use core::sync::atomic::{AtomicBool, Ordering::Relaxed}; - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - static RNG_INIT: AtomicBool = AtomicBool::new(false); - while !RNG_INIT.load(Relaxed) { - let ret = unsafe { libc::randSecure() }; - if ret < 0 { - return Err(RAND_SECURE_FATAL); - } else if ret > 0 { - RNG_INIT.store(true, Relaxed); - break; - } - unsafe { libc::usleep(10) }; - } - - // Prevent overflow of i32 - for chunk in dest.chunks_mut(i32::max_value() as usize) { - let ret = unsafe { libc::randABytes(chunk.as_mut_ptr(), chunk.len() as i32) }; - if ret != 0 { - return Err(last_os_error()); - } - } - Ok(()) -} diff --git a/getrandom/src/wasi.rs b/getrandom/src/wasi.rs deleted file mode 100644 index 713c1ab..0000000 --- a/getrandom/src/wasi.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for WASI -use crate::Error; -use core::num; -use wasi::wasi_unstable::random_get; - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - random_get(dest).map_err(|e: num::NonZeroU16| { - // convert wasi's NonZeroU16 error into getrandom's NonZeroU32 error - num::NonZeroU32::new(e.get() as u32).unwrap().into() - }) -} diff --git a/getrandom/src/wasm32_bindgen.rs b/getrandom/src/wasm32_bindgen.rs deleted file mode 100644 index 86839a0..0000000 --- a/getrandom/src/wasm32_bindgen.rs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for WASM via wasm-bindgen -extern crate std; - -use core::cell::RefCell; -use core::mem; -use std::thread_local; - -use wasm_bindgen::prelude::*; - -use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF}; -use crate::Error; - -#[derive(Clone, Debug)] -enum RngSource { - Node(NodeCrypto), - Browser(BrowserCrypto), -} - -// JsValues are always per-thread, so we initialize RngSource for each thread. -// See: https://github.com/rustwasm/wasm-bindgen/pull/955 -thread_local!( - static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None); -); - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - assert_eq!(mem::size_of::<usize>(), 4); - - RNG_SOURCE.with(|f| { - let mut source = f.borrow_mut(); - if source.is_none() { - *source = Some(getrandom_init()?); - } - - match source.as_ref().unwrap() { - RngSource::Node(n) => n.random_fill_sync(dest), - RngSource::Browser(n) => { - // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues - // - // where it says: - // - // > A QuotaExceededError DOMException is thrown if the - // > requested length is greater than 65536 bytes. - for chunk in dest.chunks_mut(65536) { - n.get_random_values(chunk) - } - } - }; - Ok(()) - }) -} - -fn getrandom_init() -> Result<RngSource, Error> { - if let Ok(self_) = Global::get_self() { - // If `self` is defined then we're in a browser somehow (main window - // or web worker). Here we want to try to use - // `crypto.getRandomValues`, but if `crypto` isn't defined we assume - // we're in an older web browser and the OS RNG isn't available. - - let crypto = self_.crypto(); - if crypto.is_undefined() { - return Err(BINDGEN_CRYPTO_UNDEF); - } - - // Test if `crypto.getRandomValues` is undefined as well - let crypto: BrowserCrypto = crypto.into(); - if crypto.get_random_values_fn().is_undefined() { - return Err(BINDGEN_GRV_UNDEF); - } - - return Ok(RngSource::Browser(crypto)); - } - - return Ok(RngSource::Node(node_require("crypto"))); -} - -#[wasm_bindgen] -extern "C" { - type Global; - #[wasm_bindgen(getter, catch, static_method_of = Global, js_class = self, js_name = self)] - fn get_self() -> Result<Self_, JsValue>; - - type Self_; - #[wasm_bindgen(method, getter, structural)] - fn crypto(me: &Self_) -> JsValue; - - #[derive(Clone, Debug)] - type BrowserCrypto; - - // TODO: these `structural` annotations here ideally wouldn't be here to - // avoid a JS shim, but for now with feature detection they're - // unavoidable. - #[wasm_bindgen(method, js_name = getRandomValues, structural, getter)] - fn get_random_values_fn(me: &BrowserCrypto) -> JsValue; - #[wasm_bindgen(method, js_name = getRandomValues, structural)] - fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]); - - #[wasm_bindgen(js_name = require)] - fn node_require(s: &str) -> NodeCrypto; - - #[derive(Clone, Debug)] - type NodeCrypto; - - #[wasm_bindgen(method, js_name = randomFillSync, structural)] - fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]); -} diff --git a/getrandom/src/wasm32_stdweb.rs b/getrandom/src/wasm32_stdweb.rs deleted file mode 100644 index 6e5e78a..0000000 --- a/getrandom/src/wasm32_stdweb.rs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for WASM via stdweb -extern crate std; - -use core::mem; - -use stdweb::js; -use stdweb::unstable::TryInto; -use stdweb::web::error::Error as WebError; - -use crate::error::{STDWEB_NO_RNG, STDWEB_RNG_FAILED}; -use crate::Error; -use std::sync::Once; - -#[derive(Clone, Copy, Debug)] -enum RngSource { - Browser, - Node, -} - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - assert_eq!(mem::size_of::<usize>(), 4); - static ONCE: Once = Once::new(); - static mut RNG_SOURCE: Result<RngSource, Error> = Ok(RngSource::Node); - - // SAFETY: RNG_SOURCE is only written once, before being read. - ONCE.call_once(|| unsafe { - RNG_SOURCE = getrandom_init(); - }); - getrandom_fill(unsafe { RNG_SOURCE }?, dest) -} - -fn getrandom_init() -> Result<RngSource, Error> { - let result = js! { - try { - if ( - typeof self === "object" && - typeof self.crypto === "object" && - typeof self.crypto.getRandomValues === "function" - ) { - return { success: true, ty: 1 }; - } - - if (typeof require("crypto").randomBytes === "function") { - return { success: true, ty: 2 }; - } - - return { success: false, error: new Error("not supported") }; - } catch(err) { - return { success: false, error: err }; - } - }; - - if js! { return @{ result.as_ref() }.success } == true { - let ty = js! { return @{ result }.ty }; - - if ty == 1 { - Ok(RngSource::Browser) - } else if ty == 2 { - Ok(RngSource::Node) - } else { - unreachable!() - } - } else { - let _err: WebError = js! { return @{ result }.error }.try_into().unwrap(); - error!("getrandom unavailable: {}", _err); - Err(STDWEB_NO_RNG) - } -} - -fn getrandom_fill(source: RngSource, dest: &mut [u8]) -> Result<(), Error> { - for chunk in dest.chunks_mut(65536) { - let len = chunk.len() as u32; - let ptr = chunk.as_mut_ptr() as i32; - - let result = match source { - RngSource::Browser => js! { - try { - let array = new Uint8Array(@{ len }); - self.crypto.getRandomValues(array); - HEAPU8.set(array, @{ ptr }); - - return { success: true }; - } catch(err) { - return { success: false, error: err }; - } - }, - RngSource::Node => js! { - try { - let bytes = require("crypto").randomBytes(@{ len }); - HEAPU8.set(new Uint8Array(bytes), @{ ptr }); - - return { success: true }; - } catch(err) { - return { success: false, error: err }; - } - }, - }; - - if js! { return @{ result.as_ref() }.success } != true { - let _err: WebError = js! { return @{ result }.error }.try_into().unwrap(); - error!("getrandom failed: {}", _err); - return Err(STDWEB_RNG_FAILED); - } - } - Ok(()) -} diff --git a/getrandom/src/windows.rs b/getrandom/src/windows.rs deleted file mode 100644 index e1b8df6..0000000 --- a/getrandom/src/windows.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for Windows -use crate::{error::RTL_GEN_RANDOM_FAILED, Error}; - -extern "system" { - #[link_name = "SystemFunction036"] - fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u8; -} - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - // Prevent overflow of u32 - for chunk in dest.chunks_mut(u32::max_value() as usize) { - let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr(), chunk.len() as u32) }; - if ret == 0 { - return Err(RTL_GEN_RANDOM_FAILED); - } - } - Ok(()) -} diff --git a/getrandom/src/windows_uwp.rs b/getrandom/src/windows_uwp.rs deleted file mode 100644 index 586c6f6..0000000 --- a/getrandom/src/windows_uwp.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for Windows UWP targets. After deprecation of Windows XP -//! and Vista, this can supersede the `RtlGenRandom`-based implementation. -use crate::Error; -use core::{ffi::c_void, num::NonZeroU32, ptr}; - -const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002; - -extern "system" { - fn BCryptGenRandom( - hAlgorithm: *mut c_void, - pBuffer: *mut u8, - cbBuffer: u32, - dwFlags: u32, - ) -> u32; -} - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - // Prevent overflow of u32 - for chunk in dest.chunks_mut(u32::max_value() as usize) { - let ret = unsafe { - BCryptGenRandom( - ptr::null_mut(), - chunk.as_mut_ptr(), - chunk.len() as u32, - BCRYPT_USE_SYSTEM_PREFERRED_RNG, - ) - }; - // NTSTATUS codes use two highest bits for severity status - match ret >> 30 { - 0b01 => { - info!("BCryptGenRandom: information code 0x{:08X}", ret); - } - 0b10 => { - warn!("BCryptGenRandom: warning code 0x{:08X}", ret); - } - 0b11 => { - error!("BCryptGenRandom: failed with 0x{:08X}", ret); - // We zeroize the highest bit, so the error code will reside - // inside the range of designated for OS codes. - let code = ret ^ (1 << 31); - // SAFETY: the second highest bit is always equal to one, - // so it's impossible to get zero. Unfortunately compiler - // is not smart enough to figure out it yet. - let code = unsafe { NonZeroU32::new_unchecked(code) }; - return Err(Error::from(code)); - } - _ => (), - } - } - Ok(()) -} |