From b771a82ea64329dc4513becadcb89040a9391308 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 1 Mar 2019 11:27:43 +0000 Subject: [PATCH 1/9] Revise error types and codes --- src/cloudabi.rs | 3 ++ src/dragonfly_haiku.rs | 8 +++-- src/dummy.rs | 12 +++++--- src/emscripten.rs | 8 +++-- src/error.rs | 66 ++++++++++++++++++++++++++++++++---------- src/freebsd.rs | 6 +++- src/fuchsia.rs | 6 +++- src/lib.rs | 7 ++--- src/linux_android.rs | 8 +++-- src/macos.rs | 6 +++- src/netbsd.rs | 8 +++-- src/openbsd_bitrig.rs | 6 +++- src/redox.rs | 8 +++-- src/sgx.rs | 8 +++-- src/solarish.rs | 6 +++- src/utils.rs | 2 +- src/wasm32_bindgen.rs | 29 ++++++++++++++----- src/wasm32_stdweb.rs | 12 +++++--- src/windows.rs | 6 +++- 19 files changed, 161 insertions(+), 54 deletions(-) diff --git a/src/cloudabi.rs b/src/cloudabi.rs index 1230f31..e769578 100644 --- a/src/cloudabi.rs +++ b/src/cloudabi.rs @@ -22,3 +22,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { Err(Error::from(code)) } } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/dragonfly_haiku.rs b/src/dragonfly_haiku.rs index 751266b..3e11d29 100644 --- a/src/dragonfly_haiku.rs +++ b/src/dragonfly_haiku.rs @@ -7,11 +7,12 @@ // except according to those terms. //! Implementation for DragonFly / Haiku -use super::Error; -use super::utils::use_init; +use error::Error; +use utils::use_init; use std::fs::File; use std::io::Read; use std::cell::RefCell; +use std::num::NonZeroU32; thread_local!(static RNG_FILE: RefCell> = RefCell::new(None)); @@ -23,3 +24,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { ) }) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/dummy.rs b/src/dummy.rs index 96acb91..460c472 100644 --- a/src/dummy.rs +++ b/src/dummy.rs @@ -7,9 +7,13 @@ // except according to those terms. //! A dummy implementation for unsupported targets which always returns -//! `Err(UNAVAILABLE_ERROR)` -use super::UNAVAILABLE_ERROR; +//! `Err(error::UNAVAILABLE)` +use std::num::NonZeroU32; +use error::{Error, UNAVAILABLE}; -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - Err(UNAVAILABLE_ERROR) +pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> { + Err(UNAVAILABLE) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/emscripten.rs b/src/emscripten.rs index dd98985..b87d3a1 100644 --- a/src/emscripten.rs +++ b/src/emscripten.rs @@ -7,11 +7,12 @@ // except according to those terms. //! Implementation for Emscripten -use super::Error; +use error::Error; use std::fs::File; use std::io::Read; use std::cell::RefCell; -use super::utils::use_init; +use std::num::NonZeroU32; +use utils::use_init; thread_local!(static RNG_FILE: RefCell> = RefCell::new(None)); @@ -29,3 +30,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { }) }) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/error.rs b/src/error.rs index 43a03a6..b6057de 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,20 +12,25 @@ use core::fmt; #[cfg(not(target_env = "sgx"))] use std::{io, error}; +// A randomly-chosen 16-bit prefix for our codes +pub(crate) const CODE_PREFIX: u32 = 0x57f40000; +const CODE_UNKNOWN: u32 = CODE_PREFIX | 0; +const CODE_UNAVAILABLE: u32 = CODE_PREFIX | 1; + /// An unknown error. -pub const UNKNOWN_ERROR: Error = Error(unsafe { - NonZeroU32::new_unchecked(0x756e6b6e) // "unkn" +pub const UNKNOWN: Error = Error(unsafe { + NonZeroU32::new_unchecked(CODE_UNKNOWN) }); /// No generator is available. -pub const UNAVAILABLE_ERROR: Error = Error(unsafe { - NonZeroU32::new_unchecked(0x4e416e61) // "NAna" +pub const UNAVAILABLE: Error = Error(unsafe { + NonZeroU32::new_unchecked(CODE_UNAVAILABLE) }); /// The error type. /// /// This type is small and no-std compatible. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq)] pub struct Error(NonZeroU32); impl Error { @@ -38,14 +43,34 @@ impl Error { pub fn code(&self) -> NonZeroU32 { self.0 } + + fn msg(&self) -> Option<&'static str> { + if let Some(msg) = super::error_msg_inner(self.0) { + Some(msg) + } else { + match *self { + UNKNOWN => Some("getrandom: unknown error"), + UNAVAILABLE => Some("getrandom: unavailable"), + _ => None + } + } + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match self.msg() { + Some(msg) => write!(f, "Error(\"{}\")", msg), + None => write!(f, "Error({})", self.0.get()), + } + } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - UNKNOWN_ERROR => write!(f, "Getrandom Error: unknown"), - UNAVAILABLE_ERROR => write!(f, "Getrandom Error: unavailable"), - code => write!(f, "Getrandom Error: {}", code.0.get()), + match self.msg() { + Some(msg) => write!(f, "{}", msg), + None => write!(f, "getrandom: unknown code {}", self.0.get()), } } } @@ -63,22 +88,31 @@ impl From for Error { .and_then(|code| NonZeroU32::new(code as u32)) .map(|code| Error(code)) // in practice this should never happen - .unwrap_or(UNKNOWN_ERROR) + .unwrap_or(UNKNOWN) } } #[cfg(not(target_env = "sgx"))] impl From for io::Error { fn from(err: Error) -> Self { - match err { - UNKNOWN_ERROR => io::Error::new(io::ErrorKind::Other, - "getrandom error: unknown"), - UNAVAILABLE_ERROR => io::Error::new(io::ErrorKind::Other, - "getrandom error: entropy source is unavailable"), - code => io::Error::from_raw_os_error(code.0.get() as i32), + match err.msg() { + Some(msg) => io::Error::new(io::ErrorKind::Other, msg), + None => io::Error::from_raw_os_error(err.0.get() as i32), } } } #[cfg(not(target_env = "sgx"))] impl error::Error for Error { } + +#[cfg(test)] +mod tests { + use std::mem::size_of; + use super::Error; + + #[test] + fn test_size() { + assert_eq!(size_of::(), 4); + assert_eq!(size_of::>(), 4); + } +} diff --git a/src/freebsd.rs b/src/freebsd.rs index 9756d1b..39936ca 100644 --- a/src/freebsd.rs +++ b/src/freebsd.rs @@ -9,9 +9,10 @@ //! Implementation for FreeBSD extern crate libc; -use super::Error; +use error::Error; use core::ptr; use std::io; +use std::num::NonZeroU32; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let mib = [libc::CTL_KERN, libc::KERN_ARND]; @@ -30,3 +31,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { } Ok(()) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/fuchsia.rs b/src/fuchsia.rs index 39741eb..944b73d 100644 --- a/src/fuchsia.rs +++ b/src/fuchsia.rs @@ -9,9 +9,13 @@ //! Implementation for Fuchsia Zircon extern crate fuchsia_cprng; -use super::Error; +use std::num::NonZeroU32; +use error::Error; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { fuchsia_cprng::cprng_draw(dest); Ok(()) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/lib.rs b/src/lib.rs index b697744..0dda9ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,8 +123,7 @@ extern crate wasm_bindgen; target_arch = "wasm32", ))] mod utils; -mod error; -pub use error::{Error, UNKNOWN_ERROR, UNAVAILABLE_ERROR}; +pub mod error; // System-specific implementations. @@ -136,7 +135,7 @@ macro_rules! mod_use { #[$cond] mod $module; #[$cond] - use $module::getrandom_inner; + use $module::{getrandom_inner, error_msg_inner}; } } @@ -221,7 +220,7 @@ mod_use!( /// 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> { +pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> { getrandom_inner(dest) } diff --git a/src/linux_android.rs b/src/linux_android.rs index 4bad074..60a053f 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -9,12 +9,13 @@ //! Implementation for Linux / Android extern crate libc; -use super::Error; -use super::utils::use_init; +use error::Error; +use utils::use_init; use std::fs::File; use std::io; use std::io::Read; use std::cell::RefCell; +use std::num::NonZeroU32; use std::sync::atomic::{AtomicBool, Ordering}; static RNG_INIT: AtomicBool = AtomicBool::new(false); @@ -80,3 +81,6 @@ fn is_getrandom_available() -> bool { AVAILABLE.load(Ordering::Relaxed) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/macos.rs b/src/macos.rs index fb89fb1..fbdeb2a 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -9,8 +9,9 @@ //! Implementation for MacOS / iOS extern crate libc; -use super::Error; +use error::Error; use std::io; +use std::num::NonZeroU32; use self::libc::{c_int, size_t}; enum SecRandom {} @@ -40,3 +41,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { Ok(()) } } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/netbsd.rs b/src/netbsd.rs index 089272a..5413b80 100644 --- a/src/netbsd.rs +++ b/src/netbsd.rs @@ -8,11 +8,12 @@ //! Implementation for NetBSD -use super::Error; -use super::utils::use_init; +use error::Error; +use utils::use_init; use std::fs::File; use std::io::Read; use std::cell::RefCell; +use std::num::NonZeroU32; use std::sync::atomic::{AtomicBool, Ordering}; static RNG_INIT: AtomicBool = AtomicBool::new(false); @@ -32,3 +33,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { }, |f| f.read_exact(dest).map_err(From::from)) }) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/openbsd_bitrig.rs b/src/openbsd_bitrig.rs index abdea21..3231146 100644 --- a/src/openbsd_bitrig.rs +++ b/src/openbsd_bitrig.rs @@ -9,8 +9,9 @@ //! Implementation for OpenBSD / Bitrig extern crate libc; -use super::Error; +use error::Error; use std::io; +use std::num::NonZeroU32; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { for chunk in dest.chunks_mut(256) { @@ -26,3 +27,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { } Ok(()) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/redox.rs b/src/redox.rs index 2302666..0a2e432 100644 --- a/src/redox.rs +++ b/src/redox.rs @@ -7,11 +7,12 @@ // except according to those terms. //! Implementation for Redox -use super::Error; -use super::utils::use_init; +use error::Error; +use utils::use_init; use std::fs::File; use std::io::Read; use std::cell::RefCell; +use std::num::NonZeroU32; thread_local!(static RNG_FILE: RefCell> = RefCell::new(None)); @@ -23,3 +24,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { ) }).map_err(From::from) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/sgx.rs b/src/sgx.rs index 7517d1f..065cb94 100644 --- a/src/sgx.rs +++ b/src/sgx.rs @@ -7,10 +7,11 @@ // except according to those terms. //! Implementation for SGX using RDRAND instruction -use super::{Error, UNKNOWN_ERROR}; +use error::{Error, UNKNOWN}; use core::{mem, ptr}; use core::arch::x86_64::_rdrand64_step; +use core::num::NonZeroU32; #[cfg(not(target_feature = "rdrand"))] compile_error!("enable rdrand target feature!"); @@ -26,7 +27,7 @@ fn get_rand_u64() -> Result { } }; } - Err(UNKNOWN_ERROR) + Err(UNKNOWN) } pub fn getrandom_inner(mut dest: &mut [u8]) -> Result<(), Error> { @@ -46,3 +47,6 @@ pub fn getrandom_inner(mut dest: &mut [u8]) -> Result<(), Error> { } Ok(()) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/solarish.rs b/src/solarish.rs index 8a84fd2..ee2a3f5 100644 --- a/src/solarish.rs +++ b/src/solarish.rs @@ -19,11 +19,12 @@ //! libc::dlsym. extern crate libc; -use super::Error; +use error::Error; use std::cell::RefCell; use std::fs::File; use std::io; use std::io::Read; +use std::num::NonZeroU32; use utils::use_init; #[cfg(target_os = "illumos")] @@ -97,3 +98,6 @@ fn fetch_getrandom() -> Option { let ptr = FPTR.load(Ordering::SeqCst); unsafe { mem::transmute::>(ptr) } } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/utils.rs b/src/utils.rs index 5b70bd1..0221776 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -5,7 +5,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::Error; +use error::Error; use core::cell::RefCell; use core::ops::DerefMut; diff --git a/src/wasm32_bindgen.rs b/src/wasm32_bindgen.rs index 3f04d32..3d286fd 100644 --- a/src/wasm32_bindgen.rs +++ b/src/wasm32_bindgen.rs @@ -10,13 +10,17 @@ use std::cell::RefCell; use std::mem; +use std::num::NonZeroU32; use wasm_bindgen::prelude::*; -use super::__wbg_shims::*; -use super::{Error, UNAVAILABLE_ERROR}; -use super::utils::use_init; +use __wbg_shims::*; +use error::Error; +use utils::use_init; +const CODE_PREFIX: u32 = ::error::CODE_PREFIX | 0x8e00; +const CODE_CRYPTO_UNDEF: u32 = CODE_PREFIX | 1; +const CODE_GRV_UNDEF: u32 = CODE_PREFIX | 2; #[derive(Clone, Debug)] pub enum RngSource { @@ -75,18 +79,29 @@ fn getrandom_init() -> Result { // we're in an older web browser and the OS RNG isn't available. let crypto = this.crypto(); if crypto.is_undefined() { - let msg = "self.crypto is undefined"; - return Err(UNAVAILABLE_ERROR) // TODO: report msg + return Err(Error::from(unsafe { + NonZeroU32::new_unchecked(CODE_CRYPTO_UNDEF) + })); } // Test if `crypto.getRandomValues` is undefined as well let crypto: BrowserCrypto = crypto.into(); if crypto.get_random_values_fn().is_undefined() { - let msg = "crypto.getRandomValues is undefined"; - return Err(UNAVAILABLE_ERROR) // TODO: report msg + return Err(Error::from(unsafe { + NonZeroU32::new_unchecked(CODE_GRV_UNDEF) + })); } // Ok! `self.crypto.getRandomValues` is a defined value, so let's // assume we can do browser crypto. Ok(RngSource::Browser(crypto)) } + +#[inline(always)] +pub fn error_msg_inner(n: NonZeroU32) -> Option<&'static str> { + match n.get() { + CODE_CRYPTO_UNDEF => Some("getrandom: self.crypto is undefined"), + CODE_GRV_UNDEF => Some("crypto.getRandomValues is undefined"), + _ => None + } +} diff --git a/src/wasm32_stdweb.rs b/src/wasm32_stdweb.rs index 2606eaa..e285305 100644 --- a/src/wasm32_stdweb.rs +++ b/src/wasm32_stdweb.rs @@ -10,12 +10,13 @@ use std::cell::RefCell; use std::mem; +use std::num::NonZeroU32; use stdweb::unstable::TryInto; use stdweb::web::error::Error as WebError; -use super::{Error, UNAVAILABLE_ERROR, UNKNOWN_ERROR}; -use super::utils::use_init; +use error::{Error, UNAVAILABLE, UNKNOWN}; +use utils::use_init; #[derive(Clone, Debug)] enum RngSource { @@ -65,7 +66,7 @@ fn getrandom_init() -> Result { else { unreachable!() } } else { let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); - Err(UNAVAILABLE_ERROR) // TODO: forward err + Err(UNAVAILABLE) // TODO: forward err } } @@ -100,8 +101,11 @@ fn getrandom_fill(source: &mut RngSource, dest: &mut [u8]) -> Result<(), Error> if js!{ return @{ result.as_ref() }.success } != true { let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); - return Err(UNKNOWN_ERROR) // TODO: forward err + return Err(UNKNOWN) // TODO: forward err } } Ok(()) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/windows.rs b/src/windows.rs index 1063bdd..1380ab6 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -13,7 +13,8 @@ use self::winapi::shared::minwindef::ULONG; use self::winapi::um::ntsecapi::RtlGenRandom; use self::winapi::um::winnt::PVOID; use std::io; -use super::Error; +use std::num::NonZeroU32; +use error::Error; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { @@ -22,3 +23,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { if ret == 0 { return Err(io::Error::last_os_error().into()); } Ok(()) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } From 1a2dcdc89bc24bb84828ab2dcfe288811cb0929e Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 1 Mar 2019 11:53:46 +0000 Subject: [PATCH 2/9] Set correct requirements for minimal versions; test in CI Versions found by examining API or trial-and-error. CI will now try minimal lib versions with minimal rustc version, but only for select targets. --- .travis.yml | 4 ++++ Cargo.toml | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 41aa192..ae76ed3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,10 +6,14 @@ matrix: - rust: 1.28.0 env: DESCRIPTION="Linux, 1.28.0" os: linux + before_script: + - cargo generate-lockfile -Z minimal-versions - rust: 1.28.0 env: DESCRIPTION="OSX, 1.22.0" os: osx + before_script: + - cargo generate-lockfile -Z minimal-versions - rust: stable env: DESCRIPTION="Linux, stable" diff --git a/Cargo.toml b/Cargo.toml index 7109397..769318e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,10 +15,10 @@ members = [ ] [target.'cfg(unix)'.dependencies] -libc = "0.2" +libc = "0.2.27" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "winnt"] } +winapi = { version = "0.3.6", features = ["minwindef", "ntsecapi", "winnt"] } [target.'cfg(target_os = "cloudabi")'.dependencies] cloudabi = "0.0.3" @@ -27,5 +27,5 @@ cloudabi = "0.0.3" fuchsia-cprng = "0.1" [target.wasm32-unknown-unknown.dependencies] -wasm-bindgen = { version = "0.2.12", optional = true } -stdweb = { version = "0.4", optional = true } +wasm-bindgen = { version = "0.2.29", optional = true } +stdweb = { version = "0.4.9", optional = true } From 1fabf59c967d302d3dabc2a2e3967c473013f1e7 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 1 Mar 2019 12:00:08 +0000 Subject: [PATCH 3/9] Don't test minimal versions in CI Option isn't compatible with stable Rustc. Nightly runners already have important tests for latest version. --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ae76ed3..41aa192 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,14 +6,10 @@ matrix: - rust: 1.28.0 env: DESCRIPTION="Linux, 1.28.0" os: linux - before_script: - - cargo generate-lockfile -Z minimal-versions - rust: 1.28.0 env: DESCRIPTION="OSX, 1.22.0" os: osx - before_script: - - cargo generate-lockfile -Z minimal-versions - rust: stable env: DESCRIPTION="Linux, stable" From 23d8285296c378d538d117a1a65d97adea234b34 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Sat, 2 Mar 2019 10:59:14 +0000 Subject: [PATCH 4/9] Re-enable minimal dependency version testing on nightly runners --- .travis.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.travis.yml b/.travis.yml index 41aa192..e11aaa4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,9 @@ matrix: - rm -rf target/doc - cargo doc --no-deps --all --all-features - cargo deadlinks --dir target/doc + # also test minimum dependency versions are usable + - cargo generate-lockfile -Z minimal-versions + - cargo test - rust: nightly os: osx @@ -52,6 +55,9 @@ matrix: - rm -rf target/doc - cargo doc --no-deps --all --all-features - cargo deadlinks --dir target/doc + # also test minimum dependency versions are usable + - cargo generate-lockfile -Z minimal-versions + - cargo test - rust: nightly env: DESCRIPTION="WASM via emscripten, stdweb and wasm-bindgen" @@ -97,6 +103,14 @@ matrix: #- cargo build --target=x86_64-unknown-fuchsia --all-features - cargo build --target=x86_64-unknown-netbsd --all-features - cargo build --target=x86_64-unknown-redox --all-features + # also test minimum dependency versions are usable + - cargo generate-lockfile -Z minimal-versions + - cargo build --target=x86_64-sun-solaris --all-features + - cargo build --target=x86_64-unknown-cloudabi --all-features + - cargo build --target=x86_64-unknown-freebsd --all-features + #- cargo build --target=x86_64-unknown-fuchsia --all-features + - cargo build --target=x86_64-unknown-netbsd --all-features + - cargo build --target=x86_64-unknown-redox --all-features # Trust cross-built/emulated targets. We must repeat all non-default values. - rust: stable From 7d931042de38156b380e7643052b341731d0a6ba Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 11 Mar 2019 12:54:52 +0000 Subject: [PATCH 5/9] Print error codes in hex; include codes in documentation --- src/error.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index b6057de..2bfe155 100644 --- a/src/error.rs +++ b/src/error.rs @@ -19,11 +19,15 @@ const CODE_UNAVAILABLE: u32 = CODE_PREFIX | 1; /// An unknown error. pub const UNKNOWN: Error = Error(unsafe { +/// +/// This is the following constant: 57F40000 (hex) / 1475608576 (decimal). NonZeroU32::new_unchecked(CODE_UNKNOWN) }); /// No generator is available. pub const UNAVAILABLE: Error = Error(unsafe { +/// +/// This is the following constant: 57F40001 (hex) / 1475608577 (decimal). NonZeroU32::new_unchecked(CODE_UNAVAILABLE) }); @@ -61,7 +65,7 @@ impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self.msg() { Some(msg) => write!(f, "Error(\"{}\")", msg), - None => write!(f, "Error({})", self.0.get()), + None => write!(f, "Error({:08X})", self.0), } } } @@ -70,7 +74,7 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self.msg() { Some(msg) => write!(f, "{}", msg), - None => write!(f, "getrandom: unknown code {}", self.0.get()), + None => write!(f, "getrandom: unknown code {:08X}", self.0), } } } From 13d49ec09aeb06c2d7f1acf6113a115b84390595 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 11 Mar 2019 13:03:35 +0000 Subject: [PATCH 6/9] Remove error module from API --- src/cloudabi.rs | 2 +- src/dragonfly_haiku.rs | 2 +- src/dummy.rs | 6 +++--- src/emscripten.rs | 2 +- src/error.rs | 10 +++++----- src/freebsd.rs | 2 +- src/fuchsia.rs | 2 +- src/lib.rs | 4 ++-- src/linux_android.rs | 2 +- src/macos.rs | 2 +- src/netbsd.rs | 2 +- src/openbsd_bitrig.rs | 2 +- src/redox.rs | 2 +- src/sgx.rs | 4 ++-- src/solarish.rs | 2 +- src/utils.rs | 2 +- src/wasm32_bindgen.rs | 2 +- src/wasm32_stdweb.rs | 6 +++--- src/windows.rs | 2 +- 19 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/cloudabi.rs b/src/cloudabi.rs index e769578..ae9a71a 100644 --- a/src/cloudabi.rs +++ b/src/cloudabi.rs @@ -11,7 +11,7 @@ extern crate cloudabi; use core::num::NonZeroU32; -use error::Error; +use Error; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let errno = unsafe { cloudabi::random_get(dest) }; diff --git a/src/dragonfly_haiku.rs b/src/dragonfly_haiku.rs index 3e11d29..8b8b947 100644 --- a/src/dragonfly_haiku.rs +++ b/src/dragonfly_haiku.rs @@ -7,7 +7,7 @@ // except according to those terms. //! Implementation for DragonFly / Haiku -use error::Error; +use Error; use utils::use_init; use std::fs::File; use std::io::Read; diff --git a/src/dummy.rs b/src/dummy.rs index 460c472..421f060 100644 --- a/src/dummy.rs +++ b/src/dummy.rs @@ -7,12 +7,12 @@ // except according to those terms. //! A dummy implementation for unsupported targets which always returns -//! `Err(error::UNAVAILABLE)` +//! `Err(ERROR_UNAVAILABLE)` use std::num::NonZeroU32; -use error::{Error, UNAVAILABLE}; +use {Error, ERROR_UNAVAILABLE}; pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> { - Err(UNAVAILABLE) + Err(ERROR_UNAVAILABLE) } #[inline(always)] diff --git a/src/emscripten.rs b/src/emscripten.rs index b87d3a1..471fc68 100644 --- a/src/emscripten.rs +++ b/src/emscripten.rs @@ -7,7 +7,7 @@ // except according to those terms. //! Implementation for Emscripten -use error::Error; +use Error; use std::fs::File; use std::io::Read; use std::cell::RefCell; diff --git a/src/error.rs b/src/error.rs index 2bfe155..862919b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -18,16 +18,16 @@ const CODE_UNKNOWN: u32 = CODE_PREFIX | 0; const CODE_UNAVAILABLE: u32 = CODE_PREFIX | 1; /// An unknown error. -pub const UNKNOWN: Error = Error(unsafe { /// /// This is the following constant: 57F40000 (hex) / 1475608576 (decimal). +pub const ERROR_UNKNOWN: Error = Error(unsafe { NonZeroU32::new_unchecked(CODE_UNKNOWN) }); /// No generator is available. -pub const UNAVAILABLE: Error = Error(unsafe { /// /// This is the following constant: 57F40001 (hex) / 1475608577 (decimal). +pub const ERROR_UNAVAILABLE: Error = Error(unsafe { NonZeroU32::new_unchecked(CODE_UNAVAILABLE) }); @@ -53,8 +53,8 @@ impl Error { Some(msg) } else { match *self { - UNKNOWN => Some("getrandom: unknown error"), - UNAVAILABLE => Some("getrandom: unavailable"), + ERROR_UNKNOWN => Some("getrandom: unknown error"), + ERROR_UNAVAILABLE => Some("getrandom: unavailable"), _ => None } } @@ -92,7 +92,7 @@ impl From for Error { .and_then(|code| NonZeroU32::new(code as u32)) .map(|code| Error(code)) // in practice this should never happen - .unwrap_or(UNKNOWN) + .unwrap_or(ERROR_UNKNOWN) } } diff --git a/src/freebsd.rs b/src/freebsd.rs index 39936ca..ea8ef66 100644 --- a/src/freebsd.rs +++ b/src/freebsd.rs @@ -9,7 +9,7 @@ //! Implementation for FreeBSD extern crate libc; -use error::Error; +use Error; use core::ptr; use std::io; use std::num::NonZeroU32; diff --git a/src/fuchsia.rs b/src/fuchsia.rs index 944b73d..59defc0 100644 --- a/src/fuchsia.rs +++ b/src/fuchsia.rs @@ -10,7 +10,7 @@ extern crate fuchsia_cprng; use std::num::NonZeroU32; -use error::Error; +use Error; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { fuchsia_cprng::cprng_draw(dest); diff --git a/src/lib.rs b/src/lib.rs index 0dda9ab..4655f90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,8 +123,8 @@ extern crate wasm_bindgen; target_arch = "wasm32", ))] mod utils; -pub mod error; - +mod error; +pub use error::{Error, ERROR_UNKNOWN, ERROR_UNAVAILABLE}; // System-specific implementations. // diff --git a/src/linux_android.rs b/src/linux_android.rs index 60a053f..2aa8dac 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -9,7 +9,7 @@ //! Implementation for Linux / Android extern crate libc; -use error::Error; +use Error; use utils::use_init; use std::fs::File; use std::io; diff --git a/src/macos.rs b/src/macos.rs index fbdeb2a..6b9905f 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -9,7 +9,7 @@ //! Implementation for MacOS / iOS extern crate libc; -use error::Error; +use Error; use std::io; use std::num::NonZeroU32; use self::libc::{c_int, size_t}; diff --git a/src/netbsd.rs b/src/netbsd.rs index 5413b80..a3a4aee 100644 --- a/src/netbsd.rs +++ b/src/netbsd.rs @@ -8,7 +8,7 @@ //! Implementation for NetBSD -use error::Error; +use Error; use utils::use_init; use std::fs::File; use std::io::Read; diff --git a/src/openbsd_bitrig.rs b/src/openbsd_bitrig.rs index 3231146..82c3e36 100644 --- a/src/openbsd_bitrig.rs +++ b/src/openbsd_bitrig.rs @@ -9,7 +9,7 @@ //! Implementation for OpenBSD / Bitrig extern crate libc; -use error::Error; +use Error; use std::io; use std::num::NonZeroU32; diff --git a/src/redox.rs b/src/redox.rs index 0a2e432..6321fea 100644 --- a/src/redox.rs +++ b/src/redox.rs @@ -7,7 +7,7 @@ // except according to those terms. //! Implementation for Redox -use error::Error; +use Error; use utils::use_init; use std::fs::File; use std::io::Read; diff --git a/src/sgx.rs b/src/sgx.rs index 065cb94..7afd100 100644 --- a/src/sgx.rs +++ b/src/sgx.rs @@ -7,7 +7,7 @@ // except according to those terms. //! Implementation for SGX using RDRAND instruction -use error::{Error, UNKNOWN}; +use {Error, ERROR_UNKNOWN}; use core::{mem, ptr}; use core::arch::x86_64::_rdrand64_step; @@ -27,7 +27,7 @@ fn get_rand_u64() -> Result { } }; } - Err(UNKNOWN) + Err(ERROR_UNKNOWN) } pub fn getrandom_inner(mut dest: &mut [u8]) -> Result<(), Error> { diff --git a/src/solarish.rs b/src/solarish.rs index ee2a3f5..0632872 100644 --- a/src/solarish.rs +++ b/src/solarish.rs @@ -19,7 +19,7 @@ //! libc::dlsym. extern crate libc; -use error::Error; +use Error; use std::cell::RefCell; use std::fs::File; use std::io; diff --git a/src/utils.rs b/src/utils.rs index 0221776..d7722c0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -5,7 +5,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use error::Error; +use Error; use core::cell::RefCell; use core::ops::DerefMut; diff --git a/src/wasm32_bindgen.rs b/src/wasm32_bindgen.rs index 3d286fd..11e2f82 100644 --- a/src/wasm32_bindgen.rs +++ b/src/wasm32_bindgen.rs @@ -15,7 +15,7 @@ use std::num::NonZeroU32; use wasm_bindgen::prelude::*; use __wbg_shims::*; -use error::Error; +use Error; use utils::use_init; const CODE_PREFIX: u32 = ::error::CODE_PREFIX | 0x8e00; diff --git a/src/wasm32_stdweb.rs b/src/wasm32_stdweb.rs index e285305..2c21bc3 100644 --- a/src/wasm32_stdweb.rs +++ b/src/wasm32_stdweb.rs @@ -15,7 +15,7 @@ use std::num::NonZeroU32; use stdweb::unstable::TryInto; use stdweb::web::error::Error as WebError; -use error::{Error, UNAVAILABLE, UNKNOWN}; +use {Error, ERROR_UNAVAILABLE, ERROR_UNKNOWN}; use utils::use_init; #[derive(Clone, Debug)] @@ -66,7 +66,7 @@ fn getrandom_init() -> Result { else { unreachable!() } } else { let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); - Err(UNAVAILABLE) // TODO: forward err + Err(ERROR_UNAVAILABLE) // TODO: forward err } } @@ -101,7 +101,7 @@ fn getrandom_fill(source: &mut RngSource, dest: &mut [u8]) -> Result<(), Error> if js!{ return @{ result.as_ref() }.success } != true { let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); - return Err(UNKNOWN) // TODO: forward err + return Err(ERROR_UNKNOWN) // TODO: forward err } } Ok(()) diff --git a/src/windows.rs b/src/windows.rs index 1380ab6..1059526 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -14,7 +14,7 @@ use self::winapi::um::ntsecapi::RtlGenRandom; use self::winapi::um::winnt::PVOID; use std::io; use std::num::NonZeroU32; -use error::Error; +use Error; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { From d33356f55fa6b1ca53d334cd9ef2ff378e6b38b8 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Tue, 12 Mar 2019 17:39:20 +0000 Subject: [PATCH 7/9] Enable optional logging support --- Cargo.toml | 3 +++ README.md | 3 +++ src/error.rs | 4 ++-- src/lib.rs | 4 ++++ src/wasm32_stdweb.rs | 6 ++++-- 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 769318e..dda4c3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,9 @@ members = [ "tests/wasm_bindgen", ] +[dependencies] +log = { version = "0.4", optional = true } + [target.'cfg(unix)'.dependencies] libc = "0.2.27" diff --git a/README.md b/README.md index 4330a17..6d56630 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,9 @@ fn get_random_buf() -> Result<[u8; 32], getrandom::Error> { This library is `no_std` compatible on SGX but requires `std` on most platforms. +The `log` library is supported as an optional dependency. If enabled, error +reporting will be improved on some platforms. + For WebAssembly (`wasm32`), Enscripten targets are supported directly; otherwise one of the following features must be enabled: diff --git a/src/error.rs b/src/error.rs index 862919b..9639478 100644 --- a/src/error.rs +++ b/src/error.rs @@ -65,7 +65,7 @@ impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self.msg() { Some(msg) => write!(f, "Error(\"{}\")", msg), - None => write!(f, "Error({:08X})", self.0), + None => write!(f, "Error(0x{:08X})", self.0), } } } @@ -74,7 +74,7 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self.msg() { Some(msg) => write!(f, "{}", msg), - None => write!(f, "getrandom: unknown code {:08X}", self.0), + None => write!(f, "getrandom: unknown code 0x{:08X}", self.0), } } } diff --git a/src/lib.rs b/src/lib.rs index 4655f90..f92e359 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,6 +111,10 @@ extern crate wasm_bindgen; feature = "stdweb"))] #[macro_use] extern crate stdweb; +#[cfg(feature = "log")] #[macro_use] extern crate log; +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! warn { ($($x:tt)*) => () } + #[cfg(any( target_os = "android", target_os = "netbsd", diff --git a/src/wasm32_stdweb.rs b/src/wasm32_stdweb.rs index 2c21bc3..de9eea4 100644 --- a/src/wasm32_stdweb.rs +++ b/src/wasm32_stdweb.rs @@ -66,7 +66,8 @@ fn getrandom_init() -> Result { else { unreachable!() } } else { let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); - Err(ERROR_UNAVAILABLE) // TODO: forward err + warn!("getrandom unavailable: {}", err); + Err(ERROR_UNAVAILABLE) } } @@ -101,7 +102,8 @@ fn getrandom_fill(source: &mut RngSource, dest: &mut [u8]) -> Result<(), Error> if js!{ return @{ result.as_ref() }.success } != true { let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); - return Err(ERROR_UNKNOWN) // TODO: forward err + warn!("getrandom failed: {}", err); + return Err(ERROR_UNKNOWN) } } Ok(()) From 214a71386fea3f7266c69ed89b8dcf26d199617f Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Tue, 12 Mar 2019 17:45:28 +0000 Subject: [PATCH 8/9] Enable optional logging of failures --- src/cloudabi.rs | 1 + src/dummy.rs | 1 + src/freebsd.rs | 1 + src/lib.rs | 2 +- src/linux_android.rs | 1 + src/macos.rs | 1 + src/openbsd_bitrig.rs | 1 + src/solarish.rs | 1 + src/wasm32_stdweb.rs | 4 ++-- src/windows.rs | 5 ++++- 10 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/cloudabi.rs b/src/cloudabi.rs index ae9a71a..fc5f49d 100644 --- a/src/cloudabi.rs +++ b/src/cloudabi.rs @@ -19,6 +19,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { Ok(()) } else { let code = NonZeroU32::new(errno as u32).unwrap(); + error!("cloudabi::random_get syscall failed with code {}", code); Err(Error::from(code)) } } diff --git a/src/dummy.rs b/src/dummy.rs index 421f060..12814a7 100644 --- a/src/dummy.rs +++ b/src/dummy.rs @@ -12,6 +12,7 @@ use std::num::NonZeroU32; use {Error, ERROR_UNAVAILABLE}; pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> { + error!("no support for this platform"); Err(ERROR_UNAVAILABLE) } diff --git a/src/freebsd.rs b/src/freebsd.rs index ea8ef66..fcad6e5 100644 --- a/src/freebsd.rs +++ b/src/freebsd.rs @@ -26,6 +26,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { ) }; if ret == -1 || len != chunk.len() { + error!("freebsd: kern.arandom syscall failed"); return Err(io::Error::last_os_error().into()); } } diff --git a/src/lib.rs b/src/lib.rs index f92e359..9d6baac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -113,7 +113,7 @@ extern crate wasm_bindgen; #[cfg(feature = "log")] #[macro_use] extern crate log; #[allow(unused)] -#[cfg(not(feature = "log"))] macro_rules! warn { ($($x:tt)*) => () } +#[cfg(not(feature = "log"))] macro_rules! error { ($($x:tt)*) => () } #[cfg(any( target_os = "android", diff --git a/src/linux_android.rs b/src/linux_android.rs index 2aa8dac..51702c9 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -34,6 +34,7 @@ fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> { libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), 0) }; if ret < 0 || (ret as usize) != dest.len() { + error!("Linux getrandom syscall failed with return value {}", ret); return Err(io::Error::last_os_error()); } Ok(()) diff --git a/src/macos.rs b/src/macos.rs index 6b9905f..776e2a9 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -36,6 +36,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { ) }; if ret == -1 { + error!("SecRandomCopyBytes call failed"); Err(io::Error::last_os_error().into()) } else { Ok(()) diff --git a/src/openbsd_bitrig.rs b/src/openbsd_bitrig.rs index 82c3e36..fa80bb5 100644 --- a/src/openbsd_bitrig.rs +++ b/src/openbsd_bitrig.rs @@ -22,6 +22,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { ) }; if ret == -1 { + error!("libc::getentropy call failed"); return Err(io::Error::last_os_error().into()); } } diff --git a/src/solarish.rs b/src/solarish.rs index 0632872..ec9cff1 100644 --- a/src/solarish.rs +++ b/src/solarish.rs @@ -45,6 +45,7 @@ fn libc_getrandom(rand: GetRandomFn, dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { rand(dest.as_mut_ptr(), dest.len(), 0) as libc::ssize_t }; if ret == -1 || ret != dest.len() as libc::ssize_t { + error!("getrandom syscall failed with ret={}", ret); Err(io::Error::last_os_error().into()) } else { Ok(()) diff --git a/src/wasm32_stdweb.rs b/src/wasm32_stdweb.rs index de9eea4..7cf4279 100644 --- a/src/wasm32_stdweb.rs +++ b/src/wasm32_stdweb.rs @@ -66,7 +66,7 @@ fn getrandom_init() -> Result { else { unreachable!() } } else { let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); - warn!("getrandom unavailable: {}", err); + error!("getrandom unavailable: {}", err); Err(ERROR_UNAVAILABLE) } } @@ -102,7 +102,7 @@ fn getrandom_fill(source: &mut RngSource, dest: &mut [u8]) -> Result<(), Error> if js!{ return @{ result.as_ref() }.success } != true { let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); - warn!("getrandom failed: {}", err); + error!("getrandom failed: {}", err); return Err(ERROR_UNKNOWN) } } diff --git a/src/windows.rs b/src/windows.rs index 1059526..5055783 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -20,7 +20,10 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { RtlGenRandom(dest.as_mut_ptr() as PVOID, dest.len() as ULONG) }; - if ret == 0 { return Err(io::Error::last_os_error().into()); } + if ret == 0 { + error!("RtlGenRandom call failed"); + return Err(io::Error::last_os_error().into()); + } Ok(()) } From f2322f46fef60a312c46b40ec68d4bd25ebfe369 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 14 Mar 2019 09:13:34 +0000 Subject: [PATCH 9/9] Bump libc version requirement to the latest. --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index dda4c3f..99e1dab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,8 @@ members = [ log = { version = "0.4", optional = true } [target.'cfg(unix)'.dependencies] -libc = "0.2.27" +# In general, we need at least 0.2.27. On Solaris, we need some unknown newer version. +libc = "0.2.50" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.6", features = ["minwindef", "ntsecapi", "winnt"] }