feat: works
This commit is contained in:
17
__wasm/wit-bindgen-sample/engine/getrandom/src/3ds.rs
Normal file
17
__wasm/wit-bindgen-sample/engine/getrandom/src/3ds.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2021 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 Nintendo 3DS
|
||||
use crate::util_libc::sys_fill_exact;
|
||||
use crate::Error;
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
sys_fill_exact(dest, |buf| unsafe {
|
||||
libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// 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, 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 {
|
||||
-1
|
||||
} else {
|
||||
len as libc::ssize_t
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
// getrandom(2) was introduced in FreeBSD 12.0 and NetBSD 10.0
|
||||
#[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) });
|
||||
}
|
||||
}
|
||||
// Both FreeBSD and NetBSD will only return up to 256 bytes at a time, and
|
||||
// older NetBSD kernels will fail on longer buffers.
|
||||
for chunk in dest.chunks_mut(256) {
|
||||
sys_fill_exact(chunk, kern_arnd)?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
102
__wasm/wit-bindgen-sample/engine/getrandom/src/custom.rs
Normal file
102
__wasm/wit-bindgen-sample/engine/getrandom/src/custom.rs
Normal file
@@ -0,0 +1,102 @@
|
||||
// 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.
|
||||
|
||||
//! An implementation which calls out to an externally defined function.
|
||||
use crate::Error;
|
||||
use core::num::NonZeroU32;
|
||||
|
||||
/// Register a function to be invoked by `getrandom` on unsupported targets.
|
||||
///
|
||||
/// ## Writing a custom `getrandom` implementation
|
||||
///
|
||||
/// The function to register must have the same signature as
|
||||
/// [`getrandom::getrandom`](crate::getrandom). The function can be defined
|
||||
/// wherever you want, either in root crate or a dependent crate.
|
||||
///
|
||||
/// For example, if we wanted a `failure-getrandom` crate containing an
|
||||
/// implementation that always fails, we would first depend on `getrandom`
|
||||
/// (for the [`Error`] type) in `failure-getrandom/Cargo.toml`:
|
||||
/// ```toml
|
||||
/// [dependencies]
|
||||
/// getrandom = "0.2"
|
||||
/// ```
|
||||
/// Note that the crate containing this function does **not** need to enable the
|
||||
/// `"custom"` Cargo feature.
|
||||
///
|
||||
/// Next, in `failure-getrandom/src/lib.rs`, we define our function:
|
||||
/// ```rust
|
||||
/// use core::num::NonZeroU32;
|
||||
/// use getrandom::Error;
|
||||
///
|
||||
/// // Some application-specific error code
|
||||
/// const MY_CUSTOM_ERROR_CODE: u32 = Error::CUSTOM_START + 42;
|
||||
/// pub fn always_fail(buf: &mut [u8]) -> Result<(), Error> {
|
||||
/// let code = NonZeroU32::new(MY_CUSTOM_ERROR_CODE).unwrap();
|
||||
/// Err(Error::from(code))
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Registering a custom `getrandom` implementation
|
||||
///
|
||||
/// Functions can only be registered in the root binary crate. Attempting to
|
||||
/// register a function in a non-root crate will result in a linker error.
|
||||
/// This is similar to
|
||||
/// [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) or
|
||||
/// [`#[global_allocator]`](https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/global-allocators.html),
|
||||
/// where helper crates define handlers/allocators but only the binary crate
|
||||
/// actually _uses_ the functionality.
|
||||
///
|
||||
/// To register the function, we first depend on `failure-getrandom` _and_
|
||||
/// `getrandom` in `Cargo.toml`:
|
||||
/// ```toml
|
||||
/// [dependencies]
|
||||
/// failure-getrandom = "0.1"
|
||||
/// getrandom = { version = "0.2", features = ["custom"] }
|
||||
/// ```
|
||||
///
|
||||
/// Then, we register the function in `src/main.rs`:
|
||||
/// ```rust
|
||||
/// # mod failure_getrandom { pub fn always_fail(_: &mut [u8]) -> Result<(), getrandom::Error> { unimplemented!() } }
|
||||
/// use failure_getrandom::always_fail;
|
||||
/// use getrandom::register_custom_getrandom;
|
||||
///
|
||||
/// register_custom_getrandom!(always_fail);
|
||||
/// ```
|
||||
///
|
||||
/// Now any user of `getrandom` (direct or indirect) on this target will use the
|
||||
/// registered function. As noted in the
|
||||
/// [top-level documentation](index.html#custom-implementations) this
|
||||
/// registration only has an effect on unsupported targets.
|
||||
#[macro_export]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "custom")))]
|
||||
macro_rules! register_custom_getrandom {
|
||||
($path:path) => {
|
||||
// We use an extern "C" function to get the guarantees of a stable ABI.
|
||||
#[no_mangle]
|
||||
extern "C" fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 {
|
||||
let f: fn(&mut [u8]) -> Result<(), $crate::Error> = $path;
|
||||
let slice = unsafe { ::core::slice::from_raw_parts_mut(dest, len) };
|
||||
match f(slice) {
|
||||
Ok(()) => 0,
|
||||
Err(e) => e.code().get(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
extern "C" {
|
||||
fn __getrandom_custom(dest: *mut u8, len: usize) -> u32;
|
||||
}
|
||||
let ret = unsafe { __getrandom_custom(dest.as_mut_ptr(), dest.len()) };
|
||||
match NonZeroU32::new(ret) {
|
||||
None => Ok(()),
|
||||
Some(code) => Err(Error::from(code)),
|
||||
}
|
||||
}
|
||||
27
__wasm/wit-bindgen-sample/engine/getrandom/src/dragonfly.rs
Normal file
27
__wasm/wit-bindgen-sample/engine/getrandom/src/dragonfly.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 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 DragonFly BSD
|
||||
use crate::{
|
||||
use_file,
|
||||
util_libc::{sys_fill_exact, Weak},
|
||||
Error,
|
||||
};
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
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;
|
||||
|
||||
// getrandom(2) was introduced in DragonflyBSD 5.7
|
||||
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) });
|
||||
} else {
|
||||
use_file::getrandom_inner(dest)
|
||||
}
|
||||
}
|
||||
187
__wasm/wit-bindgen-sample/engine/getrandom/src/error.rs
Normal file
187
__wasm/wit-bindgen-sample/engine/getrandom/src/error.rs
Normal file
@@ -0,0 +1,187 @@
|
||||
// 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, 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`].
|
||||
///
|
||||
/// *If this crate's `"std"` Cargo feature is enabled*, then:
|
||||
/// - [`getrandom::Error`][Error] implements
|
||||
/// [`std::error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)
|
||||
/// - [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) implements
|
||||
/// [`From<getrandom::Error>`](https://doc.rust-lang.org/std/convert/trait.From.html).
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct Error(NonZeroU32);
|
||||
|
||||
const fn internal_error(n: u16) -> Error {
|
||||
// SAFETY: code > 0 as INTERNAL_START > 0 and adding n won't overflow a u32.
|
||||
let code = Error::INTERNAL_START + (n as u32);
|
||||
Error(unsafe { NonZeroU32::new_unchecked(code) })
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// This target/platform is not supported by `getrandom`.
|
||||
pub const UNSUPPORTED: Error = internal_error(0);
|
||||
/// The platform-specific `errno` returned a non-positive value.
|
||||
pub const ERRNO_NOT_POSITIVE: Error = internal_error(1);
|
||||
/// Call to iOS [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) failed.
|
||||
pub const IOS_SEC_RANDOM: Error = internal_error(3);
|
||||
/// Call to Windows [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) failed.
|
||||
pub const WINDOWS_RTL_GEN_RANDOM: Error = internal_error(4);
|
||||
/// RDRAND instruction failed due to a hardware issue.
|
||||
pub const FAILED_RDRAND: Error = internal_error(5);
|
||||
/// RDRAND instruction unsupported on this target.
|
||||
pub const NO_RDRAND: Error = internal_error(6);
|
||||
/// The browser does not have support for `self.crypto`.
|
||||
pub const WEB_CRYPTO: Error = internal_error(7);
|
||||
/// The browser does not have support for `crypto.getRandomValues`.
|
||||
pub const WEB_GET_RANDOM_VALUES: Error = internal_error(8);
|
||||
/// On VxWorks, call to `randSecure` failed (random number generator is not yet initialized).
|
||||
pub const VXWORKS_RAND_SECURE: Error = internal_error(11);
|
||||
/// NodeJS does not have support for the `crypto` module.
|
||||
pub const NODE_CRYPTO: Error = internal_error(12);
|
||||
/// NodeJS does not have support for `crypto.randomFillSync`.
|
||||
pub const NODE_RANDOM_FILL_SYNC: Error = internal_error(13);
|
||||
|
||||
/// 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()`][1], except
|
||||
/// that it works in `no_std` contexts. If this method returns `None`, the
|
||||
/// error value can still be formatted via the `Display` implementation.
|
||||
///
|
||||
/// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error
|
||||
#[inline]
|
||||
pub fn raw_os_error(self) -> Option<i32> {
|
||||
if self.0.get() < Self::INTERNAL_START {
|
||||
match () {
|
||||
#[cfg(target_os = "solid_asp3")]
|
||||
// On SOLID, negate the error code again to obtain the original
|
||||
// error code.
|
||||
() => Some(-(self.0.get() as i32)),
|
||||
#[cfg(not(target_os = "solid_asp3"))]
|
||||
() => 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 const fn code(self) -> NonZeroU32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(unix)] {
|
||||
fn os_err(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 {
|
||||
fn os_err(_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(err) = os_err(errno, &mut buf) {
|
||||
dbg.field("description", &err);
|
||||
}
|
||||
} 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(errno, &mut buf) {
|
||||
Some(err) => err.fmt(f),
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
fn internal_desc(error: Error) -> Option<&'static str> {
|
||||
match error {
|
||||
Error::UNSUPPORTED => Some("getrandom: this target is not supported"),
|
||||
Error::ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"),
|
||||
Error::IOS_SEC_RANDOM => Some("SecRandomCopyBytes: iOS Security framework failure"),
|
||||
Error::WINDOWS_RTL_GEN_RANDOM => Some("RtlGenRandom: Windows system function failure"),
|
||||
Error::FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"),
|
||||
Error::NO_RDRAND => Some("RDRAND: instruction not supported"),
|
||||
Error::WEB_CRYPTO => Some("Web Crypto API is unavailable"),
|
||||
Error::WEB_GET_RANDOM_VALUES => Some("Web API crypto.getRandomValues is unavailable"),
|
||||
Error::VXWORKS_RAND_SECURE => Some("randSecure: VxWorks RNG module is not initialized"),
|
||||
Error::NODE_CRYPTO => Some("Node.js crypto module is unavailable"),
|
||||
Error::NODE_RANDOM_FILL_SYNC => Some("Node.js API crypto.randomFillSync is unavailable"),
|
||||
_ => 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// 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.
|
||||
#![cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
extern crate std;
|
||||
|
||||
use crate::Error;
|
||||
use core::convert::From;
|
||||
use std::io;
|
||||
|
||||
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 {}
|
||||
26
__wasm/wit-bindgen-sample/engine/getrandom/src/espidf.rs
Normal file
26
__wasm/wit-bindgen-sample/engine/getrandom/src/espidf.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2021 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 ESP-IDF
|
||||
use crate::Error;
|
||||
use core::ffi::c_void;
|
||||
|
||||
extern "C" {
|
||||
fn esp_fill_random(buf: *mut c_void, len: usize) -> u32;
|
||||
}
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
// Not that NOT enabling WiFi, BT, or the voltage noise entropy source (via `bootloader_random_enable`)
|
||||
// will cause ESP-IDF to return pseudo-random numbers based on the voltage noise entropy, after the initial boot process:
|
||||
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html
|
||||
//
|
||||
// However tracking if some of these entropy sources is enabled is way too difficult to implement here
|
||||
unsafe { esp_fill_random(dest.as_mut_ptr().cast(), dest.len()) };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
20
__wasm/wit-bindgen-sample/engine/getrandom/src/fuchsia.rs
Normal file
20
__wasm/wit-bindgen-sample/engine/getrandom/src/fuchsia.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
// 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(())
|
||||
}
|
||||
27
__wasm/wit-bindgen-sample/engine/getrandom/src/ios.rs
Normal file
27
__wasm/wit-bindgen-sample/engine/getrandom/src/ios.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
// 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;
|
||||
use core::{ffi::c_void, ptr::null};
|
||||
|
||||
#[link(name = "Security", kind = "framework")]
|
||||
extern "C" {
|
||||
fn SecRandomCopyBytes(rnd: *const c_void, count: usize, bytes: *mut u8) -> i32;
|
||||
}
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
// Apple's documentation guarantees kSecRandomDefault is a synonym for NULL.
|
||||
let ret = unsafe { SecRandomCopyBytes(null(), dest.len(), dest.as_mut_ptr()) };
|
||||
// errSecSuccess (from SecBase.h) is always zero.
|
||||
if ret != 0 {
|
||||
Err(Error::IOS_SEC_RANDOM)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
130
__wasm/wit-bindgen-sample/engine/getrandom/src/js.rs
Normal file
130
__wasm/wit-bindgen-sample/engine/getrandom/src/js.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
// 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 crate::Error;
|
||||
|
||||
extern crate std;
|
||||
// use std::thread_local;
|
||||
|
||||
// use js_sys::{global, Uint8Array};
|
||||
// use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
|
||||
|
||||
// Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
|
||||
// const BROWSER_CRYPTO_BUFFER_SIZE: usize = 256;
|
||||
|
||||
// enum RngSource {
|
||||
// Node(NodeCrypto),
|
||||
// Browser(BrowserCrypto, Uint8Array),
|
||||
// }
|
||||
|
||||
// // 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: Result<RngSource, Error> = getrandom_init();
|
||||
// );
|
||||
|
||||
pub(crate) fn getrandom_inner(_dest: &mut [u8]) -> Result<(), Error> {
|
||||
// RNG_SOURCE.with(|result| {
|
||||
// let source = result.as_ref().map_err(|&e| e)?;
|
||||
//
|
||||
// match source {
|
||||
// RngSource::Node(n) => {
|
||||
// if n.random_fill_sync(dest).is_err() {
|
||||
// return Err(Error::NODE_RANDOM_FILL_SYNC);
|
||||
// }
|
||||
// }
|
||||
// RngSource::Browser(crypto, buf) => {
|
||||
// // getRandomValues does not work with all types of WASM memory,
|
||||
// // so we initially write to browser memory to avoid exceptions.
|
||||
// for chunk in dest.chunks_mut(BROWSER_CRYPTO_BUFFER_SIZE) {
|
||||
// // The chunk can be smaller than buf's length, so we call to
|
||||
// // JS to create a smaller view of buf without allocation.
|
||||
// let sub_buf = buf.subarray(0, chunk.len() as u32);
|
||||
//
|
||||
// if crypto.get_random_values(&sub_buf).is_err() {
|
||||
// return Err(Error::WEB_GET_RANDOM_VALUES);
|
||||
// }
|
||||
// sub_buf.copy_to(chunk);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// Ok(())
|
||||
// })
|
||||
Err(Error::UNSUPPORTED)
|
||||
}
|
||||
|
||||
// fn getrandom_init() -> Result<RngSource, Error> {
|
||||
// let global: Global = global().unchecked_into();
|
||||
// if is_node(&global) {
|
||||
// let crypto = NODE_MODULE
|
||||
// .require("crypto")
|
||||
// .map_err(|_| Error::NODE_CRYPTO)?;
|
||||
// return Ok(RngSource::Node(crypto));
|
||||
// }
|
||||
//
|
||||
// // Assume we are in some Web environment (browser or web worker). We get
|
||||
// // `self.crypto` (called `msCrypto` on IE), so we can call
|
||||
// // `crypto.getRandomValues`. If `crypto` isn't defined, we assume that
|
||||
// // we are in an older web browser and the OS RNG isn't available.
|
||||
// let crypto = match (global.crypto(), global.ms_crypto()) {
|
||||
// (c, _) if c.is_object() => c,
|
||||
// (_, c) if c.is_object() => c,
|
||||
// _ => return Err(Error::WEB_CRYPTO),
|
||||
// };
|
||||
//
|
||||
// let buf = Uint8Array::new_with_length(BROWSER_CRYPTO_BUFFER_SIZE as u32);
|
||||
// Ok(RngSource::Browser(crypto, buf))
|
||||
// }
|
||||
|
||||
// // Taken from https://www.npmjs.com/package/browser-or-node
|
||||
// fn is_node(global: &Global) -> bool {
|
||||
// let process = global.process();
|
||||
// if process.is_object() {
|
||||
// let versions = process.versions();
|
||||
// if versions.is_object() {
|
||||
// return versions.node().is_string();
|
||||
// }
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
|
||||
// #[wasm_bindgen]
|
||||
// extern "C" {
|
||||
// type Global; // Return type of js_sys::global()
|
||||
//
|
||||
// // Web Crypto API (https://www.w3.org/TR/WebCryptoAPI/)
|
||||
// #[wasm_bindgen(method, getter, js_name = "msCrypto")]
|
||||
// fn ms_crypto(this: &Global) -> BrowserCrypto;
|
||||
// #[wasm_bindgen(method, getter)]
|
||||
// fn crypto(this: &Global) -> BrowserCrypto;
|
||||
// type BrowserCrypto;
|
||||
// #[wasm_bindgen(method, js_name = getRandomValues, catch)]
|
||||
// fn get_random_values(this: &BrowserCrypto, buf: &Uint8Array) -> Result<(), JsValue>;
|
||||
//
|
||||
// // We use a "module" object here instead of just annotating require() with
|
||||
// // js_name = "module.require", so that Webpack doesn't give a warning. See:
|
||||
// // https://github.com/rust-random/getrandom/issues/224
|
||||
// type NodeModule;
|
||||
// #[wasm_bindgen(js_name = module)]
|
||||
// static NODE_MODULE: NodeModule;
|
||||
// // Node JS crypto module (https://nodejs.org/api/crypto.html)
|
||||
// #[wasm_bindgen(method, catch)]
|
||||
// fn require(this: &NodeModule, s: &str) -> Result<NodeCrypto, JsValue>;
|
||||
// type NodeCrypto;
|
||||
// #[wasm_bindgen(method, js_name = randomFillSync, catch)]
|
||||
// fn random_fill_sync(this: &NodeCrypto, buf: &mut [u8]) -> Result<(), JsValue>;
|
||||
//
|
||||
// // Node JS process Object (https://nodejs.org/api/process.html)
|
||||
// #[wasm_bindgen(method, getter)]
|
||||
// fn process(this: &Global) -> Process;
|
||||
// type Process;
|
||||
// #[wasm_bindgen(method, getter)]
|
||||
// fn versions(this: &Process) -> Versions;
|
||||
// type Versions;
|
||||
// #[wasm_bindgen(method, getter)]
|
||||
// fn node(this: &Versions) -> JsValue;
|
||||
// }
|
||||
263
__wasm/wit-bindgen-sample/engine/getrandom/src/lib.rs
Normal file
263
__wasm/wit-bindgen-sample/engine/getrandom/src/lib.rs
Normal file
@@ -0,0 +1,263 @@
|
||||
// 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 operating system's random number generator.
|
||||
//!
|
||||
//! # Supported targets
|
||||
//!
|
||||
//! | Target | Target Triple | Implementation
|
||||
//! | ----------------- | ------------------ | --------------
|
||||
//! | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random`
|
||||
//! | Windows | `*‑windows‑*` | [`BCryptGenRandom`]
|
||||
//! | macOS | `*‑apple‑darwin` | [`getentropy`][3] if available, otherwise [`/dev/random`][4] (identical to `/dev/urandom`)
|
||||
//! | iOS | `*‑apple‑ios` | [`SecRandomCopyBytes`]
|
||||
//! | FreeBSD | `*‑freebsd` | [`getrandom`][5] if available, otherwise [`kern.arandom`][6]
|
||||
//! | OpenBSD | `*‑openbsd` | [`getentropy`][7]
|
||||
//! | NetBSD | `*‑netbsd` | [`kern.arandom`][8]
|
||||
//! | Dragonfly BSD | `*‑dragonfly` | [`getrandom`][9] if available, otherwise [`/dev/random`][10]
|
||||
//! | Solaris, illumos | `*‑solaris`, `*‑illumos` | [`getrandom`][11] if available, otherwise [`/dev/random`][12]
|
||||
//! | Fuchsia OS | `*‑fuchsia` | [`cprng_draw`]
|
||||
//! | Redox | `*‑redox` | `/dev/urandom`
|
||||
//! | Haiku | `*‑haiku` | `/dev/random` (identical to `/dev/urandom`)
|
||||
//! | Hermit | `x86_64-*-hermit` | [`RDRAND`]
|
||||
//! | SGX | `x86_64‑*‑sgx` | [`RDRAND`]
|
||||
//! | VxWorks | `*‑wrs‑vxworks‑*` | `randABytes` after checking entropy pool initialization with `randSecure`
|
||||
//! | ESP-IDF | `*‑espidf` | [`esp_fill_random`]
|
||||
//! | Emscripten | `*‑emscripten` | `/dev/random` (identical to `/dev/urandom`)
|
||||
//! | WASI | `wasm32‑wasi` | [`random_get`]
|
||||
//! | Web Browser | `wasm32‑*‑unknown` | [`Crypto.getRandomValues`], see [WebAssembly support]
|
||||
//! | Node.js | `wasm32‑*‑unknown` | [`crypto.randomBytes`], see [WebAssembly support]
|
||||
//! | SOLID | `*-kmc-solid_*` | `SOLID_RNG_SampleRandomBytes`
|
||||
//! | Nintendo 3DS | `armv6k-nintendo-3ds` | [`getrandom`][1]
|
||||
//!
|
||||
//! There is no blanket implementation on `unix` targets that reads from
|
||||
//! `/dev/urandom`. This ensures all supported targets are using the recommended
|
||||
//! interface and respect maximum buffer sizes.
|
||||
//!
|
||||
//! Pull Requests that add support for new targets to `getrandom` are always welcome.
|
||||
//!
|
||||
//! ## Unsupported targets
|
||||
//!
|
||||
//! By default, `getrandom` will not compile on unsupported targets, but certain
|
||||
//! features allow a user to select a "fallback" implementation if no supported
|
||||
//! implementation exists.
|
||||
//!
|
||||
//! All of the below mechanisms only affect unsupported
|
||||
//! targets. Supported targets will _always_ use their supported implementations.
|
||||
//! This prevents a crate from overriding a secure source of randomness
|
||||
//! (either accidentally or intentionally).
|
||||
//!
|
||||
//! ### RDRAND on x86
|
||||
//!
|
||||
//! *If the `rdrand` Cargo feature is enabled*, `getrandom` will fallback to using
|
||||
//! the [`RDRAND`] instruction to get randomness on `no_std` `x86`/`x86_64`
|
||||
//! targets. This feature has no effect on other CPU architectures.
|
||||
//!
|
||||
//! ### WebAssembly support
|
||||
//!
|
||||
//! This crate fully supports the
|
||||
//! [`wasm32-wasi`](https://github.com/CraneStation/wasi) and
|
||||
//! [`wasm32-unknown-emscripten`](https://www.hellorust.com/setup/emscripten/)
|
||||
//! targets. However, the `wasm32-unknown-unknown` target (i.e. the target used
|
||||
//! by `wasm-pack`) is not automatically
|
||||
//! supported since, from the target name alone, we cannot deduce which
|
||||
//! JavaScript interface is in use (or if JavaScript is available at all).
|
||||
//!
|
||||
//! Instead, *if the `js` Cargo feature is enabled*, this crate will assume
|
||||
//! that you are building for an environment containing JavaScript, and will
|
||||
//! call the appropriate methods. Both web browser (main window and Web Workers)
|
||||
//! and Node.js environments are supported, invoking the methods
|
||||
//! [described above](#supported-targets) using the
|
||||
//! [wasm-bindgen](https://github.com/rust-lang/rust-bindgen) toolchain.
|
||||
//!
|
||||
//! This feature has no effect on targets other than `wasm32-unknown-unknown`.
|
||||
//!
|
||||
//! ### Custom implementations
|
||||
//!
|
||||
//! The [`register_custom_getrandom!`] macro allows a user to mark their own
|
||||
//! function as the backing implementation for [`getrandom`]. See the macro's
|
||||
//! documentation for more information about writing and registering your own
|
||||
//! custom implementations.
|
||||
//!
|
||||
//! Note that registering a custom implementation only has an effect on targets
|
||||
//! that would otherwise not compile. Any supported targets (including those
|
||||
//! using `rdrand` and `js` Cargo features) continue using their normal
|
||||
//! implementations even if a function is registered.
|
||||
//!
|
||||
//! ### Indirect Dependencies
|
||||
//!
|
||||
//! If `getrandom` is not a direct dependency of your crate, you can still
|
||||
//! enable any of the above fallback behaviors by enabling the relevant
|
||||
//! feature in your root crate's `Cargo.toml`:
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! getrandom = { version = "0.2", features = ["js"] }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Early boot
|
||||
//!
|
||||
//! Sometimes, early in the boot process, the OS has not collected enough
|
||||
//! entropy to securely seed its RNG. This is especially common on virtual
|
||||
//! machines, where standard "random" events are hard to come by.
|
||||
//!
|
||||
//! Some operating system interfaces always block until the RNG is securely
|
||||
//! seeded. This can take anywhere from a few seconds to more than a minute.
|
||||
//! 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), reading from
|
||||
//! `/dev/urandom` never blocks, even when the OS hasn't collected enough
|
||||
//! entropy yet. To avoid returning low-entropy bytes, we first poll
|
||||
//! `/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.
|
||||
//!
|
||||
//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html
|
||||
//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html
|
||||
//! [3]: https://www.unix.com/man-page/mojave/2/getentropy/
|
||||
//! [4]: https://www.unix.com/man-page/mojave/4/random/
|
||||
//! [5]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable
|
||||
//! [6]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
|
||||
//! [7]: https://man.openbsd.org/getentropy.2
|
||||
//! [8]: https://man.netbsd.org/sysctl.7
|
||||
//! [9]: https://leaf.dragonflybsd.org/cgi/web-man?command=getrandom
|
||||
//! [10]: https://leaf.dragonflybsd.org/cgi/web-man?command=random§ion=4
|
||||
//! [11]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
|
||||
//! [12]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
|
||||
//!
|
||||
//! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
|
||||
//! [`Crypto.getRandomValues`]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
|
||||
//! [`RDRAND`]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
|
||||
//! [`SecRandomCopyBytes`]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
|
||||
//! [`cprng_draw`]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw
|
||||
//! [`crypto.randomBytes`]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
|
||||
//! [`esp_fill_random`]: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html#_CPPv415esp_fill_randomPv6size_t
|
||||
//! [`random_get`]: https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-random_getbuf-pointeru8-buf_len-size---errno
|
||||
//! [WebAssembly support]: #webassembly-support
|
||||
|
||||
#![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://docs.rs/getrandom/0.2.7"
|
||||
)]
|
||||
#![no_std]
|
||||
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate cfg_if;
|
||||
|
||||
mod error;
|
||||
mod util;
|
||||
// To prevent a breaking change when targets are added, we always export the
|
||||
// register_custom_getrandom macro, so old Custom RNG crates continue to build.
|
||||
#[cfg(feature = "custom")]
|
||||
mod custom;
|
||||
#[cfg(feature = "std")]
|
||||
mod error_impls;
|
||||
|
||||
pub use crate::error::Error;
|
||||
|
||||
// System-specific implementations.
|
||||
//
|
||||
// These should all provide getrandom_inner with the same signature as getrandom.
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "emscripten", target_os = "haiku",
|
||||
target_os = "redox"))] {
|
||||
mod util_libc;
|
||||
#[path = "use_file.rs"] mod imp;
|
||||
} else if #[cfg(any(target_os = "android", target_os = "linux"))] {
|
||||
mod util_libc;
|
||||
mod use_file;
|
||||
#[path = "linux_android.rs"] mod imp;
|
||||
} else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
|
||||
mod util_libc;
|
||||
mod use_file;
|
||||
#[path = "solaris_illumos.rs"] mod imp;
|
||||
} else if #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] {
|
||||
mod util_libc;
|
||||
#[path = "bsd_arandom.rs"] mod imp;
|
||||
} else if #[cfg(target_os = "dragonfly")] {
|
||||
mod util_libc;
|
||||
mod use_file;
|
||||
#[path = "dragonfly.rs"] mod imp;
|
||||
} else if #[cfg(target_os = "fuchsia")] {
|
||||
#[path = "fuchsia.rs"] mod imp;
|
||||
} else if #[cfg(target_os = "ios")] {
|
||||
#[path = "ios.rs"] mod imp;
|
||||
} else if #[cfg(target_os = "macos")] {
|
||||
mod util_libc;
|
||||
mod use_file;
|
||||
#[path = "macos.rs"] mod imp;
|
||||
} else if #[cfg(target_os = "openbsd")] {
|
||||
mod util_libc;
|
||||
#[path = "openbsd.rs"] mod imp;
|
||||
} else if #[cfg(target_os = "wasi")] {
|
||||
#[path = "wasi.rs"] mod imp;
|
||||
} else if #[cfg(all(target_arch = "x86_64", target_os = "hermit"))] {
|
||||
#[path = "rdrand.rs"] mod imp;
|
||||
} else if #[cfg(target_os = "vxworks")] {
|
||||
mod util_libc;
|
||||
#[path = "vxworks.rs"] mod imp;
|
||||
} else if #[cfg(target_os = "solid_asp3")] {
|
||||
#[path = "solid.rs"] mod imp;
|
||||
} else if #[cfg(target_os = "espidf")] {
|
||||
#[path = "espidf.rs"] mod imp;
|
||||
} else if #[cfg(windows)] {
|
||||
#[path = "windows.rs"] mod imp;
|
||||
} else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] {
|
||||
#[path = "rdrand.rs"] mod imp;
|
||||
} else if #[cfg(all(feature = "rdrand",
|
||||
any(target_arch = "x86_64", target_arch = "x86")))] {
|
||||
#[path = "rdrand.rs"] mod imp;
|
||||
} else if #[cfg(all(feature = "js",
|
||||
target_arch = "wasm32", target_os = "unknown"))] {
|
||||
#[path = "js.rs"] mod imp;
|
||||
} else if #[cfg(all(target_os = "horizon", target_arch = "arm"))] {
|
||||
// We check for target_arch = "arm" because the Nintendo Switch also
|
||||
// uses Horizon OS (it is aarch64).
|
||||
mod util_libc;
|
||||
#[path = "3ds.rs"] mod imp;
|
||||
} else if #[cfg(feature = "custom")] {
|
||||
use custom as imp;
|
||||
} else if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] {
|
||||
compile_error!("the wasm32-unknown-unknown target is not supported by \
|
||||
default, you may need to enable the \"js\" feature. \
|
||||
For more information see: \
|
||||
https://docs.rs/getrandom/#webassembly-support");
|
||||
} 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> {
|
||||
if dest.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
imp::getrandom_inner(dest)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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,
|
||||
util_libc::{last_os_error, sys_fill_exact},
|
||||
{use_file, Error},
|
||||
};
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
// getrandom(2) was introduced in Linux 3.17
|
||||
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
|
||||
}
|
||||
36
__wasm/wit-bindgen-sample/engine/getrandom/src/macos.rs
Normal file
36
__wasm/wit-bindgen-sample/engine/getrandom/src/macos.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
// 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::{
|
||||
use_file,
|
||||
util_libc::{last_os_error, Weak},
|
||||
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> {
|
||||
// getentropy(2) was added in 10.12, Rust supports 10.7+
|
||||
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 {
|
||||
return Err(last_os_error());
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
21
__wasm/wit-bindgen-sample/engine/getrandom/src/openbsd.rs
Normal file
21
__wasm/wit-bindgen-sample/engine/getrandom/src/openbsd.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
// 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, Error};
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
// getentropy(2) was added in OpenBSD 5.6, so we can use it unconditionally.
|
||||
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 {
|
||||
return Err(last_os_error());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
97
__wasm/wit-bindgen-sample/engine/getrandom/src/rdrand.rs
Normal file
97
__wasm/wit-bindgen-sample/engine/getrandom/src/rdrand.rs
Normal file
@@ -0,0 +1,97 @@
|
||||
// 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;
|
||||
use core::mem;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_arch = "x86_64")] {
|
||||
use core::arch::x86_64 as arch;
|
||||
use arch::_rdrand64_step as rdrand_step;
|
||||
} else if #[cfg(target_arch = "x86")] {
|
||||
use core::arch::x86 as arch;
|
||||
use arch::_rdrand32_step as rdrand_step;
|
||||
}
|
||||
}
|
||||
|
||||
// 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::<usize>();
|
||||
|
||||
#[target_feature(enable = "rdrand")]
|
||||
unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
|
||||
for _ in 0..RETRY_LIMIT {
|
||||
let mut el = mem::zeroed();
|
||||
if rdrand_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());
|
||||
}
|
||||
// Keep looping in case this was a false positive.
|
||||
}
|
||||
}
|
||||
Err(Error::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 crate::util::LazyBool;
|
||||
|
||||
// SAFETY: All Rust x86 targets are new enough to have CPUID, and if CPUID
|
||||
// is supported, CPUID leaf 1 is always supported.
|
||||
const FLAG: u32 = 1 << 30;
|
||||
static HAS_RDRAND: LazyBool = LazyBool::new();
|
||||
HAS_RDRAND.unsync_init(|| unsafe { (arch::__cpuid(1).ecx & FLAG) != 0 })
|
||||
}
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
if !is_rdrand_supported() {
|
||||
return Err(Error::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(())
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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::{
|
||||
use_file,
|
||||
util_libc::{sys_fill_exact, Weak},
|
||||
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> {
|
||||
// getrandom(2) was introduced in Solaris 11.3 for Illumos in 2015.
|
||||
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)
|
||||
}
|
||||
}
|
||||
26
__wasm/wit-bindgen-sample/engine/getrandom/src/solid.rs
Normal file
26
__wasm/wit-bindgen-sample/engine/getrandom/src/solid.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2021 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 SOLID
|
||||
use crate::Error;
|
||||
use core::num::NonZeroU32;
|
||||
|
||||
extern "C" {
|
||||
pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> i32;
|
||||
}
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
let ret = unsafe { SOLID_RNG_SampleRandomBytes(dest.as_mut_ptr(), dest.len()) };
|
||||
if ret >= 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
// ITRON error numbers are always negative, so we negate it so that it
|
||||
// falls in the dedicated OS error range (1..INTERNAL_START).
|
||||
Err(NonZeroU32::new((-ret) as u32).unwrap().into())
|
||||
}
|
||||
}
|
||||
139
__wasm/wit-bindgen-sample/engine/getrandom/src/use_file.rs
Normal file
139
__wasm/wit-bindgen-sample/engine/getrandom/src/use_file.rs
Normal file
@@ -0,0 +1,139 @@
|
||||
// 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::LazyUsize,
|
||||
util_libc::{open_readonly, sys_fill_exact},
|
||||
Error,
|
||||
};
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
sync::atomic::{AtomicUsize, Ordering::Relaxed},
|
||||
};
|
||||
|
||||
#[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";
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
|
||||
const FILE_PATH: &str = "/dev/urandom\0";
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
let fd = get_rng_fd()?;
|
||||
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(())
|
||||
}
|
||||
|
||||
// Returns the file descriptor for the device file used to retrieve random
|
||||
// bytes. The file will be opened exactly once. All subsequent calls will
|
||||
// return the same file descriptor. This file descriptor is never closed.
|
||||
fn get_rng_fd() -> Result<libc::c_int, Error> {
|
||||
static FD: AtomicUsize = AtomicUsize::new(LazyUsize::UNINIT);
|
||||
fn get_fd() -> Option<libc::c_int> {
|
||||
match FD.load(Relaxed) {
|
||||
LazyUsize::UNINIT => None,
|
||||
val => Some(val as libc::c_int),
|
||||
}
|
||||
}
|
||||
|
||||
// Use double-checked locking to avoid acquiring the lock if possible.
|
||||
if let Some(fd) = get_fd() {
|
||||
return Ok(fd);
|
||||
}
|
||||
|
||||
// SAFETY: We use the mutex only in this method, and we always unlock it
|
||||
// before returning, making sure we don't violate the pthread_mutex_t API.
|
||||
static MUTEX: Mutex = Mutex::new();
|
||||
unsafe { MUTEX.lock() };
|
||||
let _guard = DropGuard(|| unsafe { MUTEX.unlock() });
|
||||
|
||||
if let Some(fd) = get_fd() {
|
||||
return Ok(fd);
|
||||
}
|
||||
|
||||
// On Linux, /dev/urandom might return insecure values.
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
wait_until_rng_ready()?;
|
||||
|
||||
let fd = unsafe { open_readonly(FILE_PATH)? };
|
||||
// The fd always fits in a usize without conflicting with UNINIT.
|
||||
debug_assert!(fd >= 0 && (fd as usize) < LazyUsize::UNINIT);
|
||||
FD.store(fd as usize, Relaxed);
|
||||
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
// Succeeds once /dev/urandom is safe to read from
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn wait_until_rng_ready() -> Result<(), Error> {
|
||||
// Poll /dev/random to make sure it is ok to read from /dev/urandom.
|
||||
let fd = unsafe { open_readonly("/dev/random\0")? };
|
||||
let mut pfd = libc::pollfd {
|
||||
fd,
|
||||
events: libc::POLLIN,
|
||||
revents: 0,
|
||||
};
|
||||
let _guard = DropGuard(|| unsafe {
|
||||
libc::close(fd);
|
||||
});
|
||||
|
||||
loop {
|
||||
// A negative timeout means an infinite timeout.
|
||||
let res = unsafe { libc::poll(&mut pfd, 1, -1) };
|
||||
if res >= 0 {
|
||||
debug_assert_eq!(res, 1); // We only used one fd, and cannot timeout.
|
||||
return Ok(());
|
||||
}
|
||||
let err = crate::util_libc::last_os_error();
|
||||
match err.raw_os_error() {
|
||||
Some(libc::EINTR) | Some(libc::EAGAIN) => continue,
|
||||
_ => return Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Mutex(UnsafeCell<libc::pthread_mutex_t>);
|
||||
|
||||
impl Mutex {
|
||||
const fn new() -> Self {
|
||||
Self(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER))
|
||||
}
|
||||
unsafe fn lock(&self) {
|
||||
let r = libc::pthread_mutex_lock(self.0.get());
|
||||
debug_assert_eq!(r, 0);
|
||||
}
|
||||
unsafe fn unlock(&self) {
|
||||
let r = libc::pthread_mutex_unlock(self.0.get());
|
||||
debug_assert_eq!(r, 0);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for Mutex {}
|
||||
|
||||
struct DropGuard<F: FnMut()>(F);
|
||||
|
||||
impl<F: FnMut()> Drop for DropGuard<F> {
|
||||
fn drop(&mut self) {
|
||||
self.0()
|
||||
}
|
||||
}
|
||||
64
__wasm/wit-bindgen-sample/engine/getrandom/src/util.rs
Normal file
64
__wasm/wit-bindgen-sample/engine/getrandom/src/util.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
// 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.
|
||||
#![allow(dead_code)]
|
||||
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();
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
160
__wasm/wit-bindgen-sample/engine/getrandom/src/util_libc.rs
Normal file
160
__wasm/wit-bindgen-sample/engine/getrandom/src/util_libc.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
// 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.
|
||||
#![allow(dead_code)]
|
||||
use crate::Error;
|
||||
use core::{
|
||||
num::NonZeroU32,
|
||||
ptr::NonNull,
|
||||
sync::atomic::{fence, AtomicPtr, Ordering},
|
||||
};
|
||||
use libc::c_void;
|
||||
|
||||
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"))] {
|
||||
use libc::__error as errno_location;
|
||||
} else if #[cfg(target_os = "haiku")] {
|
||||
use libc::_errnop as errno_location;
|
||||
} else if #[cfg(all(target_os = "horizon", target_arch = "arm"))] {
|
||||
extern "C" {
|
||||
// Not provided by libc: https://github.com/rust-lang/libc/issues/1995
|
||||
fn __errno() -> *mut libc::c_int;
|
||||
}
|
||||
use __errno as errno_location;
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_os = "vxworks")] {
|
||||
use libc::errnoGet as get_errno;
|
||||
} else if #[cfg(target_os = "dragonfly")] {
|
||||
// Until rust-lang/rust#29594 is stable, we cannot get the errno value
|
||||
// on DragonFlyBSD. So we just return an out-of-range errno.
|
||||
unsafe fn get_errno() -> libc::c_int { -1 }
|
||||
} else {
|
||||
unsafe fn get_errno() -> libc::c_int { *errno_location() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn last_os_error() -> Error {
|
||||
let errno = unsafe { get_errno() };
|
||||
if errno > 0 {
|
||||
Error::from(NonZeroU32::new(errno as u32).unwrap())
|
||||
} else {
|
||||
Error::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.
|
||||
// Based off of the DlsymWeak struct in libstd:
|
||||
// https://github.com/rust-lang/rust/blob/1.61.0/library/std/src/sys/unix/weak.rs#L84
|
||||
// except that the caller must manually cast self.ptr() to a function pointer.
|
||||
pub struct Weak {
|
||||
name: &'static str,
|
||||
addr: AtomicPtr<c_void>,
|
||||
}
|
||||
|
||||
impl Weak {
|
||||
// A non-null pointer value which indicates we are uninitialized. This
|
||||
// constant should ideally not be a valid address of a function pointer.
|
||||
// However, if by chance libc::dlsym does return UNINIT, there will not
|
||||
// be undefined behavior. libc::dlsym will just be called each time ptr()
|
||||
// is called. This would be inefficient, but correct.
|
||||
// TODO: Replace with core::ptr::invalid_mut(1) when that is stable.
|
||||
const UNINIT: *mut c_void = 1 as *mut c_void;
|
||||
|
||||
// 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: AtomicPtr::new(Self::UNINIT),
|
||||
}
|
||||
}
|
||||
|
||||
// Return the address of a function if present at runtime. Otherwise,
|
||||
// return None. Multiple callers can call ptr() concurrently. It will
|
||||
// always return _some_ value returned by libc::dlsym. However, the
|
||||
// dlsym function may be called multiple times.
|
||||
pub fn ptr(&self) -> Option<NonNull<c_void>> {
|
||||
// Despite having only a single atomic variable (self.addr), we still
|
||||
// cannot always use Ordering::Relaxed, as we need to make sure a
|
||||
// successful call to dlsym() is "ordered before" any data read through
|
||||
// the returned pointer (which occurs when the function is called).
|
||||
// Our implementation mirrors that of the one in libstd, meaning that
|
||||
// the use of non-Relaxed operations is probably unnecessary.
|
||||
match self.addr.load(Ordering::Relaxed) {
|
||||
Self::UNINIT => {
|
||||
let symbol = self.name.as_ptr() as *const _;
|
||||
let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, symbol) };
|
||||
// Synchronizes with the Acquire fence below
|
||||
self.addr.store(addr, Ordering::Release);
|
||||
NonNull::new(addr)
|
||||
}
|
||||
addr => {
|
||||
let func = NonNull::new(addr)?;
|
||||
fence(Ordering::Acquire);
|
||||
Some(func)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) -> Result<libc::c_int, Error> {
|
||||
debug_assert_eq!(path.as_bytes().last(), Some(&0));
|
||||
loop {
|
||||
let fd = open(path.as_ptr() as *const _, libc::O_RDONLY | libc::O_CLOEXEC);
|
||||
if fd >= 0 {
|
||||
return Ok(fd);
|
||||
}
|
||||
let err = last_os_error();
|
||||
// We should try again if open() was interrupted.
|
||||
if err.raw_os_error() != Some(libc::EINTR) {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
__wasm/wit-bindgen-sample/engine/getrandom/src/vxworks.rs
Normal file
34
__wasm/wit-bindgen-sample/engine/getrandom/src/vxworks.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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::{util_libc::last_os_error, 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(Error::VXWORKS_RAND_SECURE);
|
||||
} 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(())
|
||||
}
|
||||
19
__wasm/wit-bindgen-sample/engine/getrandom/src/wasi.rs
Normal file
19
__wasm/wit-bindgen-sample/engine/getrandom/src/wasi.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
// 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::NonZeroU32;
|
||||
use wasi::wasi_snapshot_preview1::random_get;
|
||||
|
||||
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
|
||||
match unsafe { random_get(dest.as_mut_ptr() as i32, dest.len() as i32) } {
|
||||
0 => Ok(()),
|
||||
err => Err(unsafe { NonZeroU32::new_unchecked(err as u32) }.into()),
|
||||
}
|
||||
}
|
||||
49
__wasm/wit-bindgen-sample/engine/getrandom/src/windows.rs
Normal file
49
__wasm/wit-bindgen-sample/engine/getrandom/src/windows.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
// 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 crate::Error;
|
||||
use core::{ffi::c_void, num::NonZeroU32, ptr};
|
||||
|
||||
const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;
|
||||
|
||||
#[link(name = "bcrypt")]
|
||||
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) {
|
||||
// BCryptGenRandom was introduced in Windows Vista
|
||||
let ret = unsafe {
|
||||
BCryptGenRandom(
|
||||
ptr::null_mut(),
|
||||
chunk.as_mut_ptr(),
|
||||
chunk.len() as u32,
|
||||
BCRYPT_USE_SYSTEM_PREFERRED_RNG,
|
||||
)
|
||||
};
|
||||
// NTSTATUS codes use the two highest bits for severity status.
|
||||
if ret >> 30 == 0b11 {
|
||||
// We zeroize the highest bit, so the error code will reside
|
||||
// inside the range 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 the type
|
||||
// system does not have a way to express this yet.
|
||||
let code = unsafe { NonZeroU32::new_unchecked(code) };
|
||||
return Err(Error::from(code));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user