Improve Error handling (#54)
This commit is contained in:
parent
b3e609f8b5
commit
00c3cff101
@ -22,7 +22,7 @@ log = { version = "0.4", optional = true }
|
||||
cfg-if = "0.1"
|
||||
|
||||
[target.'cfg(any(unix, target_os = "redox", target_os = "wasi"))'.dependencies]
|
||||
libc = "0.2.54"
|
||||
libc = "0.2.60"
|
||||
|
||||
[target.wasm32-unknown-unknown.dependencies]
|
||||
wasm-bindgen = { version = "0.2.29", optional = true }
|
||||
|
@ -17,14 +17,9 @@ extern "C" {
|
||||
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 code {}", code);
|
||||
error!("cloudabi_sys_random_get: failed with {}", errno);
|
||||
Err(Error::from(code))
|
||||
} else {
|
||||
Ok(()) // Zero means success for CloudABI
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
14
src/dummy.rs
14
src/dummy.rs
@ -6,17 +6,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A dummy implementation for unsupported targets which always returns
|
||||
//! `Err(Error::UNAVAILABLE)`
|
||||
use crate::Error;
|
||||
use core::num::NonZeroU32;
|
||||
//! A dummy implementation for unsupported targets which always fails
|
||||
use crate::{error::UNSUPPORTED, Error};
|
||||
|
||||
pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> {
|
||||
error!("no support for this platform");
|
||||
Err(Error::UNAVAILABLE)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
Err(UNSUPPORTED)
|
||||
}
|
||||
|
151
src/error.rs
151
src/error.rs
@ -5,78 +5,151 @@
|
||||
// <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::convert::From;
|
||||
use core::fmt;
|
||||
use core::num::NonZeroU32;
|
||||
|
||||
// A randomly-chosen 24-bit prefix for our codes
|
||||
pub(crate) const CODE_PREFIX: u32 = 0x57f4c500;
|
||||
const CODE_UNKNOWN: u32 = CODE_PREFIX | 0x00;
|
||||
const CODE_UNAVAILABLE: u32 = CODE_PREFIX | 0x01;
|
||||
|
||||
/// The error type.
|
||||
/// A small and `no_std` compatible error type.
|
||||
///
|
||||
/// This type is small and no-std compatible.
|
||||
/// 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(pub(crate) NonZeroU32);
|
||||
pub struct Error(NonZeroU32);
|
||||
|
||||
impl Error {
|
||||
/// An unknown error.
|
||||
pub const UNKNOWN: Error = Error(unsafe { NonZeroU32::new_unchecked(CODE_UNKNOWN) });
|
||||
#[deprecated(since = "0.1.7")]
|
||||
pub const UNKNOWN: Error = UNSUPPORTED;
|
||||
#[deprecated(since = "0.1.7")]
|
||||
pub const UNAVAILABLE: Error = UNSUPPORTED;
|
||||
|
||||
/// No generator is available.
|
||||
pub const UNAVAILABLE: Error = Error(unsafe { NonZeroU32::new_unchecked(CODE_UNAVAILABLE) });
|
||||
/// 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;
|
||||
|
||||
/// Extract the error code.
|
||||
/// 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 may equal one of the codes defined in this library or may be a
|
||||
/// system error code.
|
||||
/// 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 `Diplay` 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.
|
||||
///
|
||||
/// One may attempt to format this error via the `Display` implementation.
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn msg(&self) -> Option<&'static str> {
|
||||
if let Some(msg) = crate::imp::error_msg_inner(self.0) {
|
||||
Some(msg)
|
||||
} else {
|
||||
match *self {
|
||||
Error::UNKNOWN => Some("getrandom: unknown error"),
|
||||
Error::UNAVAILABLE => Some("getrandom: unavailable"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
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 idx = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
|
||||
core::str::from_utf8(&buf[..idx]).ok()
|
||||
}
|
||||
|
||||
#[cfg(not(any(unix, target_os = "redox")))]
|
||||
fn os_err_desc(_errno: i32, _buf: &mut [u8]) -> Option<&str> {
|
||||
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(0x{:08X})", self.0),
|
||||
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) -> Result<(), fmt::Error> {
|
||||
match self.msg() {
|
||||
Some(msg) => write!(f, "{}", msg),
|
||||
None => write!(f, "getrandom: unknown code 0x{:08X}", self.0),
|
||||
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 {
|
||||
Error(code)
|
||||
Self(code)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Error> for Error {
|
||||
fn from(error: &Error) -> Self {
|
||||
*error
|
||||
// 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);
|
||||
|
||||
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"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,28 +7,29 @@
|
||||
// except according to those terms.
|
||||
extern crate std;
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::{error::UNKNOWN_IO_ERROR, Error};
|
||||
use core::convert::From;
|
||||
use core::num::NonZeroU32;
|
||||
use std::{error, io};
|
||||
use std::io;
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(err: io::Error) -> Self {
|
||||
err.raw_os_error()
|
||||
.and_then(|code| NonZeroU32::new(code as u32))
|
||||
.map(|code| Error(code))
|
||||
// in practice this should never happen
|
||||
.unwrap_or(Error::UNKNOWN)
|
||||
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.msg() {
|
||||
Some(msg) => io::Error::new(io::ErrorKind::Other, msg),
|
||||
None => io::Error::from_raw_os_error(err.0.get() as i32),
|
||||
match err.raw_os_error() {
|
||||
Some(errno) => io::Error::from_raw_os_error(errno),
|
||||
None => io::Error::new(io::ErrorKind::Other, err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {}
|
||||
impl std::error::Error for Error {}
|
||||
|
@ -9,7 +9,6 @@
|
||||
//! Implementation for FreeBSD
|
||||
use crate::util_libc::{sys_fill_exact, Weak};
|
||||
use crate::Error;
|
||||
use core::num::NonZeroU32;
|
||||
use core::{mem, ptr};
|
||||
|
||||
type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t;
|
||||
@ -44,8 +43,3 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
sys_fill_exact(dest, kern_arnd)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
//! Implementation for Fuchsia Zircon
|
||||
use crate::Error;
|
||||
use core::num::NonZeroU32;
|
||||
|
||||
#[link(name = "zircon")]
|
||||
extern "C" {
|
||||
@ -19,8 +18,3 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
unsafe { zx_cprng_draw(dest.as_mut_ptr(), dest.len()) }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
13
src/ios.rs
13
src/ios.rs
@ -7,10 +7,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
//! Implementation for iOS
|
||||
extern crate std;
|
||||
|
||||
use crate::Error;
|
||||
use core::num::NonZeroU32;
|
||||
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
|
||||
@ -27,14 +24,8 @@ extern "C" {
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, dest.len(), dest.as_mut_ptr()) };
|
||||
if ret == -1 {
|
||||
error!("SecRandomCopyBytes call failed");
|
||||
Err(Error::UNKNOWN)
|
||||
Err(SEC_RANDOM_FAILED)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
26
src/lib.rs
26
src/lib.rs
@ -79,25 +79,8 @@
|
||||
//! `getrandom`, hence after the first successful call one can be reasonably
|
||||
//! confident that no errors will occur.
|
||||
//!
|
||||
//! On unsupported platforms, `getrandom` always fails with [`Error::UNAVAILABLE`].
|
||||
//!
|
||||
//! ## Error codes
|
||||
//! The crate uses the following custom error codes:
|
||||
//! - `0x57f4c500` (dec: 1475659008) - an unknown error. Constant:
|
||||
//! [`Error::UNKNOWN`]
|
||||
//! - `0x57f4c501` (dec: 1475659009) - no generator is available. Constant:
|
||||
//! [`Error::UNAVAILABLE`]
|
||||
//! - `0x57f4c580` (dec: 1475659136) - `self.crypto` is undefined,
|
||||
//! `wasm-bindgen` specific error.
|
||||
//! - `0x57f4c581` (dec: 1475659137) - `crypto.getRandomValues` is undefined,
|
||||
//! `wasm-bindgen` specific error.
|
||||
//!
|
||||
//! These codes are provided for reference only and should not be matched upon
|
||||
//! (but you can match on `Error` constants). The codes may change in future and
|
||||
//! such change will not be considered a breaking one.
|
||||
//!
|
||||
//! Other error codes will originate from an underlying system. In case if such
|
||||
//! error is encountered, please consult with your system documentation.
|
||||
//! 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
|
||||
@ -146,14 +129,12 @@ cfg_if! {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
mod error;
|
||||
pub use crate::error::Error;
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod util;
|
||||
// Unlike the other Unix, Fuchsia and iOS don't use the libc to make any calls.
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
@ -197,7 +178,6 @@ mod error_impls;
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
))]
|
||||
#[allow(dead_code)]
|
||||
mod use_file;
|
||||
|
||||
// System-specific implementations.
|
||||
|
@ -7,13 +7,9 @@
|
||||
// except according to those terms.
|
||||
|
||||
//! Implementation for Linux / Android
|
||||
extern crate std;
|
||||
|
||||
use crate::util::LazyBool;
|
||||
use crate::util_libc::sys_fill_exact;
|
||||
use crate::util_libc::{last_os_error, sys_fill_exact};
|
||||
use crate::{use_file, Error};
|
||||
use core::num::NonZeroU32;
|
||||
use std::io;
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
static HAS_GETRANDOM: LazyBool = LazyBool::new();
|
||||
@ -29,7 +25,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
fn is_getrandom_available() -> bool {
|
||||
let res = unsafe { libc::syscall(libc::SYS_getrandom, 0, 0, libc::GRND_NONBLOCK) };
|
||||
if res < 0 {
|
||||
match io::Error::last_os_error().raw_os_error() {
|
||||
match last_os_error().raw_os_error() {
|
||||
Some(libc::ENOSYS) => false, // No kernel support
|
||||
Some(libc::EPERM) => false, // Blocked by seccomp
|
||||
_ => true,
|
||||
@ -38,8 +34,3 @@ fn is_getrandom_available() -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
16
src/macos.rs
16
src/macos.rs
@ -7,13 +7,9 @@
|
||||
// except according to those terms.
|
||||
|
||||
//! Implementation for macOS
|
||||
extern crate std;
|
||||
|
||||
use crate::util_libc::Weak;
|
||||
use crate::util_libc::{last_os_error, Weak};
|
||||
use crate::{use_file, Error};
|
||||
use core::mem;
|
||||
use core::num::NonZeroU32;
|
||||
use std::io;
|
||||
|
||||
type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int;
|
||||
|
||||
@ -24,8 +20,9 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
for chunk in dest.chunks_mut(256) {
|
||||
let ret = unsafe { func(chunk.as_mut_ptr(), chunk.len()) };
|
||||
if ret != 0 {
|
||||
error!("getentropy syscall failed with ret={}", ret);
|
||||
return Err(io::Error::last_os_error().into());
|
||||
let err = last_os_error();
|
||||
error!("getentropy syscall failed");
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@ -35,8 +32,3 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
use_file::getrandom_inner(dest)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
@ -7,24 +7,17 @@
|
||||
// except according to those terms.
|
||||
|
||||
//! Implementation for OpenBSD
|
||||
extern crate std;
|
||||
|
||||
use crate::util_libc::last_os_error;
|
||||
use crate::Error;
|
||||
use core::num::NonZeroU32;
|
||||
use std::io;
|
||||
|
||||
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(io::Error::last_os_error().into());
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
@ -7,12 +7,12 @@
|
||||
// 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;
|
||||
use core::num::NonZeroU32;
|
||||
|
||||
// Recommendation from "Intel® Digital Random Number Generator (DRNG) Software
|
||||
// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
|
||||
@ -37,8 +37,7 @@ unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
|
||||
// Keep looping in case this was a false positive.
|
||||
}
|
||||
}
|
||||
error!("RDRAND failed, CPU issue likely");
|
||||
Err(Error::UNKNOWN)
|
||||
Err(FAILED_RDRAND)
|
||||
}
|
||||
|
||||
// "rdrand" target feature requires "+rdrnd" flag, see https://github.com/rust-lang/rust/issues/49653.
|
||||
@ -65,7 +64,7 @@ fn is_rdrand_supported() -> bool {
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
if !is_rdrand_supported() {
|
||||
return Err(Error::UNAVAILABLE);
|
||||
return Err(NO_RDRAND);
|
||||
}
|
||||
|
||||
// SAFETY: After this point, rdrand is supported, so calling the rdrand
|
||||
@ -89,8 +88,3 @@ unsafe fn rdrand_exact(dest: &mut [u8]) -> Result<(), Error> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
@ -20,7 +20,6 @@
|
||||
use crate::util_libc::{sys_fill_exact, Weak};
|
||||
use crate::{use_file, Error};
|
||||
use core::mem;
|
||||
use core::num::NonZeroU32;
|
||||
|
||||
#[cfg(target_os = "illumos")]
|
||||
type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t;
|
||||
@ -43,8 +42,3 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
use_file::getrandom_inner(dest)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
@ -9,15 +9,11 @@
|
||||
//! Implementations that just need to read from a file
|
||||
extern crate std;
|
||||
|
||||
use crate::util_libc::LazyFd;
|
||||
use crate::util_libc::{last_os_error, LazyFd};
|
||||
use crate::Error;
|
||||
use core::mem::ManuallyDrop;
|
||||
use core::num::NonZeroU32;
|
||||
use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{self, Read},
|
||||
};
|
||||
use std::{fs::File, io::Read};
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
const FILE_PATH: &str = "rand:";
|
||||
@ -35,7 +31,7 @@ const FILE_PATH: &str = "/dev/random";
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
static FD: LazyFd = LazyFd::new();
|
||||
let fd = FD.init(init_file).ok_or(io::Error::last_os_error())?;
|
||||
let fd = FD.init(init_file).ok_or(last_os_error())?;
|
||||
let file = ManuallyDrop::new(unsafe { File::from_raw_fd(fd) });
|
||||
let mut file_ref: &File = &file;
|
||||
|
||||
@ -60,9 +56,3 @@ fn init_file() -> Option<RawFd> {
|
||||
}
|
||||
Some(File::open(FILE_PATH).ok()?.into_raw_fd())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
@ -5,12 +5,34 @@
|
||||
// <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::ERRNO_NOT_POSITIVE;
|
||||
use crate::util::LazyUsize;
|
||||
use crate::Error;
|
||||
use core::num::NonZeroU32;
|
||||
use core::ptr::NonNull;
|
||||
use std::io;
|
||||
|
||||
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 {
|
||||
let errno = unsafe { *errno_location() };
|
||||
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
|
||||
@ -22,10 +44,10 @@ pub fn sys_fill_exact(
|
||||
while !buf.is_empty() {
|
||||
let res = sys_fill(buf);
|
||||
if res < 0 {
|
||||
let err = io::Error::last_os_error();
|
||||
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.into());
|
||||
return Err(err);
|
||||
}
|
||||
} else {
|
||||
// We don't check for EOF (ret = 0) as the data we are reading
|
||||
|
@ -14,14 +14,9 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
let ret =
|
||||
unsafe { libc::__wasi_random_get(dest.as_mut_ptr() as *mut libc::c_void, dest.len()) };
|
||||
if let Some(code) = NonZeroU32::new(ret as u32) {
|
||||
error!("WASI: __wasi_random_get failed with return value {}", code);
|
||||
error!("WASI: __wasi_random_get: failed with {}", ret);
|
||||
Err(Error::from(code))
|
||||
} else {
|
||||
Ok(()) // Zero means success for WASI
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
@ -11,17 +11,13 @@ extern crate std;
|
||||
|
||||
use core::cell::RefCell;
|
||||
use core::mem;
|
||||
use core::num::NonZeroU32;
|
||||
use std::thread_local;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::error::CODE_PREFIX;
|
||||
use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF};
|
||||
use crate::Error;
|
||||
|
||||
const CODE_CRYPTO_UNDEF: u32 = CODE_PREFIX | 0x80;
|
||||
const CODE_GRV_UNDEF: u32 = CODE_PREFIX | 0x81;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum RngSource {
|
||||
Node(NodeCrypto),
|
||||
@ -83,17 +79,13 @@ fn getrandom_init() -> Result<RngSource, Error> {
|
||||
// we're in an older web browser and the OS RNG isn't available.
|
||||
let crypto = this.crypto();
|
||||
if crypto.is_undefined() {
|
||||
return Err(Error::from(unsafe {
|
||||
NonZeroU32::new_unchecked(CODE_CRYPTO_UNDEF)
|
||||
}));
|
||||
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(Error::from(unsafe {
|
||||
NonZeroU32::new_unchecked(CODE_GRV_UNDEF)
|
||||
}));
|
||||
return Err(BINDGEN_GRV_UNDEF);
|
||||
}
|
||||
|
||||
// Ok! `self.crypto.getRandomValues` is a defined value, so let's
|
||||
@ -101,15 +93,6 @@ fn getrandom_init() -> Result<RngSource, Error> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
type Function;
|
||||
|
@ -8,12 +8,12 @@
|
||||
|
||||
//! Implementation for WASM via stdweb
|
||||
use core::mem;
|
||||
use core::num::NonZeroU32;
|
||||
|
||||
use stdweb::unstable::TryInto;
|
||||
use stdweb::web::error::Error as WebError;
|
||||
use stdweb::{_js_impl, js};
|
||||
|
||||
use crate::error::{STDWEB_NO_RNG, STDWEB_RNG_FAILED};
|
||||
use crate::Error;
|
||||
use std::sync::Once;
|
||||
|
||||
@ -26,7 +26,7 @@ enum RngSource {
|
||||
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> = Err(Error::UNAVAILABLE);
|
||||
static mut RNG_SOURCE: Result<RngSource, Error> = Ok(RngSource::Node);
|
||||
|
||||
// SAFETY: RNG_SOURCE is only written once, before being read.
|
||||
ONCE.call_once(|| unsafe {
|
||||
@ -69,7 +69,7 @@ fn getrandom_init() -> Result<RngSource, Error> {
|
||||
} else {
|
||||
let err: WebError = js! { return @{ result }.error }.try_into().unwrap();
|
||||
error!("getrandom unavailable: {}", err);
|
||||
Err(Error::UNAVAILABLE)
|
||||
Err(STDWEB_NO_RNG)
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,13 +105,8 @@ fn getrandom_fill(source: RngSource, dest: &mut [u8]) -> Result<(), Error> {
|
||||
if js! { return @{ result.as_ref() }.success } != true {
|
||||
let err: WebError = js! { return @{ result }.error }.try_into().unwrap();
|
||||
error!("getrandom failed: {}", err);
|
||||
return Err(Error::UNKNOWN);
|
||||
return Err(STDWEB_RNG_FAILED);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
@ -7,10 +7,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
//! Implementation for Windows
|
||||
extern crate std;
|
||||
|
||||
use crate::Error;
|
||||
use core::num::NonZeroU32;
|
||||
use crate::{error::RTL_GEN_RANDOM_FAILED, Error};
|
||||
|
||||
extern "system" {
|
||||
#[link_name = "SystemFunction036"]
|
||||
@ -22,14 +19,8 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
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 {
|
||||
error!("RtlGenRandom call failed");
|
||||
return Err(Error::UNKNOWN);
|
||||
return Err(RTL_GEN_RANDOM_FAILED);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user