Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

181
vendor/getrandom/src/backends.rs vendored Normal file
View File

@@ -0,0 +1,181 @@
//! System-specific implementations.
//!
//! This module should provide `fill_inner` with the signature
//! `fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error>`.
//! The function MUST fully initialize `dest` when `Ok(())` is returned.
//! The function MUST NOT ever write uninitialized bytes into `dest`,
//! regardless of what value it returns.
cfg_if! {
if #[cfg(getrandom_backend = "custom")] {
mod custom;
pub use custom::*;
} else if #[cfg(getrandom_backend = "linux_getrandom")] {
mod getrandom;
pub use getrandom::*;
} else if #[cfg(getrandom_backend = "linux_raw")] {
mod linux_raw;
pub use linux_raw::*;
} else if #[cfg(getrandom_backend = "rdrand")] {
mod rdrand;
pub use rdrand::*;
} else if #[cfg(getrandom_backend = "rndr")] {
mod rndr;
pub use rndr::*;
} else if #[cfg(getrandom_backend = "efi_rng")] {
mod efi_rng;
pub use efi_rng::*;
} else if #[cfg(all(getrandom_backend = "wasm_js"))] {
cfg_if! {
if #[cfg(feature = "wasm_js")] {
mod wasm_js;
pub use wasm_js::*;
} else {
compile_error!(concat!(
"The \"wasm_js\" backend requires the `wasm_js` feature \
for `getrandom`. For more information see: \
https://docs.rs/getrandom/", env!("CARGO_PKG_VERSION"), "/#webassembly-support"
));
}
}
} else if #[cfg(all(target_os = "linux", target_env = ""))] {
mod linux_raw;
pub use linux_raw::*;
} else if #[cfg(target_os = "espidf")] {
mod esp_idf;
pub use esp_idf::*;
} else if #[cfg(any(
target_os = "haiku",
target_os = "redox",
target_os = "nto",
target_os = "aix",
))] {
mod use_file;
pub use use_file::*;
} else if #[cfg(any(
target_os = "macos",
target_os = "openbsd",
target_os = "vita",
target_os = "emscripten",
))] {
mod getentropy;
pub use getentropy::*;
} else if #[cfg(any(
// Rust supports Android API level 19 (KitKat) [0] and the next upgrade targets
// level 21 (Lollipop) [1], while `getrandom(2)` was added only in
// level 23 (Marshmallow). Note that it applies only to the "old" `target_arch`es,
// RISC-V Android targets sufficiently new API level, same will apply for potential
// new Android `target_arch`es.
// [0]: https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html
// [1]: https://github.com/rust-lang/rust/pull/120593
all(
target_os = "android",
any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "x86",
target_arch = "x86_64",
),
),
// Only on these `target_arch`es Rust supports Linux kernel versions (3.2+)
// that precede the version (3.17) in which `getrandom(2)` was added:
// https://doc.rust-lang.org/stable/rustc/platform-support.html
all(
target_os = "linux",
any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "s390x",
target_arch = "x86",
target_arch = "x86_64",
// Minimum supported Linux kernel version for MUSL targets
// is not specified explicitly (as of Rust 1.77) and they
// are used in practice to target pre-3.17 kernels.
target_env = "musl",
),
)
))] {
mod use_file;
mod linux_android_with_fallback;
pub use linux_android_with_fallback::*;
} else if #[cfg(any(
target_os = "android",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "hurd",
target_os = "illumos",
target_os = "cygwin",
// Check for target_arch = "arm" to only include the 3DS. Does not
// include the Nintendo Switch (which is target_arch = "aarch64").
all(target_os = "horizon", target_arch = "arm"),
))] {
mod getrandom;
pub use getrandom::*;
} else if #[cfg(target_os = "solaris")] {
mod solaris;
pub use solaris::*;
} else if #[cfg(target_os = "netbsd")] {
mod netbsd;
pub use netbsd::*;
} else if #[cfg(target_os = "fuchsia")] {
mod fuchsia;
pub use fuchsia::*;
} else if #[cfg(any(
target_os = "ios",
target_os = "visionos",
target_os = "watchos",
target_os = "tvos",
))] {
mod apple_other;
pub use apple_other::*;
} else if #[cfg(all(target_arch = "wasm32", target_os = "wasi"))] {
cfg_if! {
if #[cfg(target_env = "p1")] {
mod wasi_p1;
pub use wasi_p1::*;
} else if #[cfg(target_env = "p2")] {
mod wasi_p2;
pub use wasi_p2::*;
} else {
compile_error!(
"Unknown version of WASI (only previews 1 and 2 are supported) \
or Rust version older than 1.80 was used"
);
}
}
} else if #[cfg(target_os = "hermit")] {
mod hermit;
pub use hermit::*;
} else if #[cfg(target_os = "vxworks")] {
mod vxworks;
pub use vxworks::*;
} else if #[cfg(target_os = "solid_asp3")] {
mod solid;
pub use solid::*;
} else if #[cfg(all(windows, any(target_vendor = "win7", getrandom_windows_legacy)))] {
mod windows7;
pub use windows7::*;
} else if #[cfg(windows)] {
mod windows;
pub use windows::*;
} else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] {
mod rdrand;
pub use rdrand::*;
} else if #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))] {
compile_error!(concat!(
"The wasm32-unknown-unknown targets are not supported by default; \
you may need to enable the \"wasm_js\" configuration flag. Note \
that enabling the `wasm_js` feature flag alone is insufficient. \
For more information see: \
https://docs.rs/getrandom/", env!("CARGO_PKG_VERSION"), "/#webassembly-support"
));
} else {
compile_error!(concat!(
"target is not supported. You may need to define a custom backend see: \
https://docs.rs/getrandom/", env!("CARGO_PKG_VERSION"), "/#custom-backend"
));
}
}

View File

@@ -0,0 +1,21 @@
//! Implementation for iOS, tvOS, and watchOS where `getentropy` is unavailable.
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};
pub use crate::util::{inner_u32, inner_u64};
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
let dst_ptr = dest.as_mut_ptr().cast::<c_void>();
let ret = unsafe { libc::CCRandomGenerateBytes(dst_ptr, dest.len()) };
if ret == libc::kCCSuccess {
Ok(())
} else {
Err(Error::IOS_RANDOM_GEN)
}
}
impl Error {
/// Call to `CCRandomGenerateBytes` failed.
pub(crate) const IOS_RANDOM_GEN: Error = Self::new_internal(10);
}

13
vendor/getrandom/src/backends/custom.rs vendored Normal file
View File

@@ -0,0 +1,13 @@
//! An implementation which calls out to an externally defined function.
use crate::Error;
use core::mem::MaybeUninit;
pub use crate::util::{inner_u32, inner_u64};
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
extern "Rust" {
fn __getrandom_v03_custom(dest: *mut u8, len: usize) -> Result<(), Error>;
}
unsafe { __getrandom_v03_custom(dest.as_mut_ptr().cast(), dest.len()) }
}

124
vendor/getrandom/src/backends/efi_rng.rs vendored Normal file
View File

@@ -0,0 +1,124 @@
//! Implementation for UEFI using EFI_RNG_PROTOCOL
use crate::Error;
use core::{
mem::MaybeUninit,
ptr::{self, null_mut, NonNull},
sync::atomic::{AtomicPtr, Ordering::Relaxed},
};
use r_efi::{
efi::{BootServices, Handle},
protocols::rng,
};
extern crate std;
pub use crate::util::{inner_u32, inner_u64};
#[cfg(not(target_os = "uefi"))]
compile_error!("`efi_rng` backend can be enabled only for UEFI targets!");
static RNG_PROTOCOL: AtomicPtr<rng::Protocol> = AtomicPtr::new(null_mut());
#[cold]
#[inline(never)]
fn init() -> Result<NonNull<rng::Protocol>, Error> {
const HANDLE_SIZE: usize = size_of::<Handle>();
let boot_services = std::os::uefi::env::boot_services()
.ok_or(Error::BOOT_SERVICES_UNAVAILABLE)?
.cast::<BootServices>();
let mut handles = [ptr::null_mut(); 16];
// `locate_handle` operates with length in bytes
let mut buf_size = handles.len() * HANDLE_SIZE;
let mut guid = rng::PROTOCOL_GUID;
let ret = unsafe {
((*boot_services.as_ptr()).locate_handle)(
r_efi::efi::BY_PROTOCOL,
&mut guid,
null_mut(),
&mut buf_size,
handles.as_mut_ptr(),
)
};
if ret.is_error() {
return Err(Error::from_uefi_code(ret.as_usize()));
}
let handles_len = buf_size / HANDLE_SIZE;
let handles = handles.get(..handles_len).ok_or(Error::UNEXPECTED)?;
let system_handle = std::os::uefi::env::image_handle();
for &handle in handles {
let mut protocol: MaybeUninit<*mut rng::Protocol> = MaybeUninit::uninit();
let mut protocol_guid = rng::PROTOCOL_GUID;
let ret = unsafe {
((*boot_services.as_ptr()).open_protocol)(
handle,
&mut protocol_guid,
protocol.as_mut_ptr().cast(),
system_handle.as_ptr(),
ptr::null_mut(),
r_efi::system::OPEN_PROTOCOL_GET_PROTOCOL,
)
};
let protocol = if ret.is_error() {
continue;
} else {
let protocol = unsafe { protocol.assume_init() };
NonNull::new(protocol).ok_or(Error::UNEXPECTED)?
};
// Try to use the acquired protocol handle
let mut buf = [0u8; 8];
let mut alg_guid = rng::ALGORITHM_RAW;
let ret = unsafe {
((*protocol.as_ptr()).get_rng)(
protocol.as_ptr(),
&mut alg_guid,
buf.len(),
buf.as_mut_ptr(),
)
};
if ret.is_error() {
continue;
}
RNG_PROTOCOL.store(protocol.as_ptr(), Relaxed);
return Ok(protocol);
}
Err(Error::NO_RNG_HANDLE)
}
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
let protocol = match NonNull::new(RNG_PROTOCOL.load(Relaxed)) {
Some(p) => p,
None => init()?,
};
let mut alg_guid = rng::ALGORITHM_RAW;
let ret = unsafe {
((*protocol.as_ptr()).get_rng)(
protocol.as_ptr(),
&mut alg_guid,
dest.len(),
dest.as_mut_ptr().cast::<u8>(),
)
};
if ret.is_error() {
Err(Error::from_uefi_code(ret.as_usize()))
} else {
Ok(())
}
}
impl Error {
pub(crate) const BOOT_SERVICES_UNAVAILABLE: Error = Self::new_internal(10);
pub(crate) const NO_RNG_HANDLE: Error = Self::new_internal(11);
}

View File

@@ -0,0 +1,21 @@
//! Implementation for ESP-IDF
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};
pub use crate::util::{inner_u32, inner_u64};
extern "C" {
fn esp_fill_random(buf: *mut c_void, len: usize) -> u32;
}
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<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(())
}

View File

@@ -0,0 +1,16 @@
//! Implementation for Fuchsia Zircon
use crate::Error;
use core::mem::MaybeUninit;
pub use crate::util::{inner_u32, inner_u64};
#[link(name = "zircon")]
extern "C" {
fn zx_cprng_draw(buffer: *mut u8, length: usize);
}
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
unsafe { zx_cprng_draw(dest.as_mut_ptr().cast::<u8>(), dest.len()) }
Ok(())
}

View File

@@ -0,0 +1,27 @@
//! Implementation using getentropy(2)
//!
//! Available since:
//! - macOS 10.12
//! - OpenBSD 5.6
//! - Emscripten 2.0.5
//! - vita newlib since Dec 2021
//!
//! For these targets, we use getentropy(2) because getrandom(2) doesn't exist.
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};
pub use crate::util::{inner_u32, inner_u64};
#[path = "../util_libc.rs"]
mod util_libc;
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
for chunk in dest.chunks_mut(256) {
let ret = unsafe { libc::getentropy(chunk.as_mut_ptr().cast::<c_void>(), chunk.len()) };
if ret != 0 {
return Err(util_libc::last_os_error());
}
}
Ok(())
}

View File

@@ -0,0 +1,31 @@
//! Implementation using getrandom(2).
//!
//! Available since:
//! - Linux Kernel 3.17, Glibc 2.25, Musl 1.1.20
//! - Android API level 23 (Marshmallow)
//! - NetBSD 10.0
//! - FreeBSD 12.0
//! - illumos since Dec 2018
//! - DragonFly 5.7
//! - Hurd Glibc 2.31
//! - shim-3ds since Feb 2022
//!
//! For these platforms, we always use the default pool and never set the
//! GRND_RANDOM flag to use the /dev/random pool. On Linux/Android/Hurd, using
//! GRND_RANDOM is not recommended. On NetBSD/FreeBSD/Dragonfly/3ds, it does
//! nothing. On illumos, the default pool is used to implement getentropy(2),
//! so we assume it is acceptable here.
use crate::Error;
use core::mem::MaybeUninit;
pub use crate::util::{inner_u32, inner_u64};
#[path = "../util_libc.rs"]
mod util_libc;
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
util_libc::sys_fill_exact(dest, |buf| unsafe {
libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0)
})
}

53
vendor/getrandom/src/backends/hermit.rs vendored Normal file
View File

@@ -0,0 +1,53 @@
//! Implementation for Hermit
use crate::Error;
use core::mem::MaybeUninit;
extern "C" {
fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize;
// Note that `sys_secure_rand32/64` are implemented using `sys_read_entropy`:
// https://github.com/hermit-os/kernel/blob/430da84/src/syscalls/entropy.rs#L62-L104
// But this may change in future and can depend on compilation target,
// so to future-proof we use these "syscalls".
fn sys_secure_rand32(value: *mut u32) -> i32;
fn sys_secure_rand64(value: *mut u64) -> i32;
}
#[inline]
pub fn inner_u32() -> Result<u32, Error> {
let mut res = MaybeUninit::uninit();
let ret = unsafe { sys_secure_rand32(res.as_mut_ptr()) };
match ret {
0 => Ok(unsafe { res.assume_init() }),
-1 => Err(Error::UNSUPPORTED),
_ => Err(Error::UNEXPECTED),
}
}
#[inline]
pub fn inner_u64() -> Result<u64, Error> {
let mut res = MaybeUninit::uninit();
let ret = unsafe { sys_secure_rand64(res.as_mut_ptr()) };
match ret {
0 => Ok(unsafe { res.assume_init() }),
-1 => Err(Error::UNSUPPORTED),
_ => Err(Error::UNEXPECTED),
}
}
#[inline]
pub fn fill_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
while !dest.is_empty() {
let res = unsafe { sys_read_entropy(dest.as_mut_ptr().cast::<u8>(), dest.len(), 0) };
match res {
res if res > 0 => {
let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?;
dest = dest.get_mut(len..).ok_or(Error::UNEXPECTED)?;
}
code => {
let code = i32::try_from(code).map_err(|_| Error::UNEXPECTED)?;
return Err(Error::from_neg_error_code(code));
}
}
}
Ok(())
}

View File

@@ -0,0 +1,101 @@
//! Implementation for Linux / Android with `/dev/urandom` fallback
use super::use_file;
use crate::Error;
use core::{
ffi::c_void,
mem::{transmute, MaybeUninit},
ptr::NonNull,
sync::atomic::{AtomicPtr, Ordering},
};
use use_file::util_libc;
pub use crate::util::{inner_u32, inner_u64};
type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) -> libc::ssize_t;
/// Sentinel value which indicates that `libc::getrandom` either not available,
/// or not supported by kernel.
const NOT_AVAILABLE: NonNull<c_void> = unsafe { NonNull::new_unchecked(usize::MAX as *mut c_void) };
static GETRANDOM_FN: AtomicPtr<c_void> = AtomicPtr::new(core::ptr::null_mut());
#[cold]
#[inline(never)]
fn init() -> NonNull<c_void> {
// Use static linking to `libc::getrandom` on MUSL targets and `dlsym` everywhere else
#[cfg(not(target_env = "musl"))]
let raw_ptr = {
static NAME: &[u8] = b"getrandom\0";
let name_ptr = NAME.as_ptr().cast::<libc::c_char>();
unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) }
};
#[cfg(target_env = "musl")]
let raw_ptr = {
let fptr: GetRandomFn = libc::getrandom;
unsafe { transmute::<GetRandomFn, *mut c_void>(fptr) }
};
let res_ptr = match NonNull::new(raw_ptr) {
Some(fptr) => {
let getrandom_fn = unsafe { transmute::<NonNull<c_void>, GetRandomFn>(fptr) };
let dangling_ptr = NonNull::dangling().as_ptr();
// Check that `getrandom` syscall is supported by kernel
let res = unsafe { getrandom_fn(dangling_ptr, 0, 0) };
if cfg!(getrandom_test_linux_fallback) {
NOT_AVAILABLE
} else if res.is_negative() {
match util_libc::last_os_error().raw_os_error() {
Some(libc::ENOSYS) => NOT_AVAILABLE, // No kernel support
// The fallback on EPERM is intentionally not done on Android since this workaround
// seems to be needed only for specific Linux-based products that aren't based
// on Android. See https://github.com/rust-random/getrandom/issues/229.
#[cfg(target_os = "linux")]
Some(libc::EPERM) => NOT_AVAILABLE, // Blocked by seccomp
_ => fptr,
}
} else {
fptr
}
}
None => NOT_AVAILABLE,
};
#[cfg(getrandom_test_linux_without_fallback)]
if res_ptr == NOT_AVAILABLE {
panic!("Fallback is triggered with enabled `getrandom_test_linux_without_fallback`")
}
GETRANDOM_FN.store(res_ptr.as_ptr(), Ordering::Release);
res_ptr
}
// Prevent inlining of the fallback implementation
#[inline(never)]
fn use_file_fallback(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
use_file::fill_inner(dest)
}
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// Despite being only a single atomic variable, we still cannot always use
// Ordering::Relaxed, as we need to make sure a successful call to `init`
// 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.
let raw_ptr = GETRANDOM_FN.load(Ordering::Acquire);
let fptr = match NonNull::new(raw_ptr) {
Some(p) => p,
None => init(),
};
if fptr == NOT_AVAILABLE {
use_file_fallback(dest)
} else {
// note: `transmute` is currently the only way to convert a pointer into a function reference
let getrandom_fn = unsafe { transmute::<NonNull<c_void>, GetRandomFn>(fptr) };
util_libc::sys_fill_exact(dest, |buf| unsafe {
getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0)
})
}
}

View File

@@ -0,0 +1,136 @@
//! Implementation for Linux / Android using `asm!`-based syscalls.
use crate::{Error, MaybeUninit};
pub use crate::util::{inner_u32, inner_u64};
#[cfg(not(any(target_os = "android", target_os = "linux")))]
compile_error!("`linux_raw` backend can be enabled only for Linux/Android targets!");
#[allow(non_upper_case_globals)]
unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize {
let r0;
// Based on `rustix` and `linux-raw-sys` code.
cfg_if! {
if #[cfg(target_arch = "arm")] {
const __NR_getrandom: u32 = 384;
// In thumb-mode, r7 is the frame pointer and is not permitted to be used in
// an inline asm operand, so we have to use a different register and copy it
// into r7 inside the inline asm.
// Theoretically, we could detect thumb mode in the build script, but several
// register moves are cheap enough compared to the syscall cost, so we do not
// bother with it.
core::arch::asm!(
"mov {tmp}, r7",
"mov r7, {nr}",
"svc 0",
"mov r7, {tmp}",
nr = const __NR_getrandom,
tmp = out(reg) _,
inlateout("r0") buf => r0,
in("r1") buflen,
in("r2") flags,
options(nostack, preserves_flags)
);
} else if #[cfg(target_arch = "aarch64")] {
const __NR_getrandom: u32 = 278;
core::arch::asm!(
"svc 0",
in("x8") __NR_getrandom,
inlateout("x0") buf => r0,
in("x1") buflen,
in("x2") flags,
options(nostack, preserves_flags)
);
} else if #[cfg(target_arch = "loongarch64")] {
const __NR_getrandom: u32 = 278;
core::arch::asm!(
"syscall 0",
in("$a7") __NR_getrandom,
inlateout("$a0") buf => r0,
in("$a1") buflen,
in("$a2") flags,
options(nostack, preserves_flags)
);
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
const __NR_getrandom: u32 = 278;
core::arch::asm!(
"ecall",
in("a7") __NR_getrandom,
inlateout("a0") buf => r0,
in("a1") buflen,
in("a2") flags,
options(nostack, preserves_flags)
);
} else if #[cfg(target_arch = "s390x")] {
const __NR_getrandom: u32 = 349;
core::arch::asm!(
"svc 0",
in("r1") __NR_getrandom,
inlateout("r2") buf => r0,
in("r3") buflen,
in("r4") flags,
options(nostack, preserves_flags)
);
} else if #[cfg(target_arch = "x86")] {
const __NR_getrandom: u32 = 355;
// `int 0x80` is famously slow, but implementing vDSO is too complex
// and `sysenter`/`syscall` have their own portability issues,
// so we use the simple "legacy" way of doing syscalls.
core::arch::asm!(
"int $$0x80",
in("eax") __NR_getrandom,
in("ebx") buf,
in("ecx") buflen,
in("edx") flags,
lateout("eax") r0,
options(nostack, preserves_flags)
);
} else if #[cfg(target_arch = "x86_64")] {
#[cfg(target_pointer_width = "64")]
const __NR_getrandom: u32 = 318;
#[cfg(target_pointer_width = "32")]
const __NR_getrandom: u32 = (1 << 30) + 318;
core::arch::asm!(
"syscall",
in("rax") __NR_getrandom,
in("rdi") buf,
in("rsi") buflen,
in("rdx") flags,
lateout("rax") r0,
lateout("rcx") _,
lateout("r11") _,
options(nostack, preserves_flags)
);
} else {
compile_error!("`linux_raw` backend does not support this target arch");
}
}
r0
}
#[inline]
pub fn fill_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// Value of this error code is stable across all target arches.
const EINTR: isize = -4;
loop {
let ret = unsafe { getrandom_syscall(dest.as_mut_ptr().cast(), dest.len(), 0) };
match usize::try_from(ret) {
Ok(0) => return Err(Error::UNEXPECTED),
Ok(len) => {
dest = dest.get_mut(len..).ok_or(Error::UNEXPECTED)?;
if dest.is_empty() {
return Ok(());
}
}
Err(_) if ret == EINTR => continue,
Err(_) => {
let code = i32::try_from(ret).map_err(|_| Error::UNEXPECTED)?;
return Err(Error::from_neg_error_code(code));
}
}
}
}

78
vendor/getrandom/src/backends/netbsd.rs vendored Normal file
View File

@@ -0,0 +1,78 @@
//! Implementation for NetBSD
//!
//! `getrandom(2)` was introduced in NetBSD 10. To support older versions we
//! implement our own weak linkage to it, and provide a fallback based on the
//! KERN_ARND sysctl.
use crate::Error;
use core::{
cmp,
ffi::c_void,
mem::{self, MaybeUninit},
ptr,
sync::atomic::{AtomicPtr, Ordering},
};
pub use crate::util::{inner_u32, inner_u64};
#[path = "../util_libc.rs"]
mod util_libc;
unsafe extern "C" fn polyfill_using_kern_arand(
buf: *mut c_void,
buflen: libc::size_t,
flags: libc::c_uint,
) -> libc::ssize_t {
debug_assert_eq!(flags, 0);
const MIB_LEN: libc::c_uint = 2;
static MIB: [libc::c_int; MIB_LEN as usize] = [libc::CTL_KERN, libc::KERN_ARND];
// NetBSD will only return up to 256 bytes at a time, and
// older NetBSD kernels will fail on longer buffers.
let mut len = cmp::min(buflen, 256);
let ret = unsafe { libc::sysctl(MIB.as_ptr(), MIB_LEN, buf, &mut len, ptr::null(), 0) };
match ret {
0 if len <= 256 => libc::ssize_t::try_from(len).expect("len is in the range of 0..=256"),
-1 => -1,
// Zero return result will be converted into `Error::UNEXPECTED` by `sys_fill_exact`
_ => 0,
}
}
type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) -> libc::ssize_t;
static GETRANDOM: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
#[cold]
#[inline(never)]
fn init() -> *mut c_void {
static NAME: &[u8] = b"getrandom\0";
let name_ptr = NAME.as_ptr().cast::<libc::c_char>();
let mut ptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) };
if ptr.is_null() || cfg!(getrandom_test_netbsd_fallback) {
// Verify `polyfill_using_kern_arand` has the right signature.
const POLYFILL: GetRandomFn = polyfill_using_kern_arand;
ptr = POLYFILL as *mut c_void;
}
GETRANDOM.store(ptr, Ordering::Release);
ptr
}
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// Despite being only a single atomic variable, we still cannot always use
// Ordering::Relaxed, as we need to make sure a successful call to `init`
// 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.
let mut fptr = GETRANDOM.load(Ordering::Acquire);
if fptr.is_null() {
fptr = init();
}
let fptr = unsafe { mem::transmute::<*mut c_void, GetRandomFn>(fptr) };
util_libc::sys_fill_exact(dest, |buf| unsafe {
fptr(buf.as_mut_ptr().cast::<c_void>(), buf.len(), 0)
})
}

182
vendor/getrandom/src/backends/rdrand.rs vendored Normal file
View File

@@ -0,0 +1,182 @@
//! RDRAND backend for x86(-64) targets
use crate::{util::slice_as_uninit, Error};
use core::mem::{size_of, MaybeUninit};
#[path = "../lazy.rs"]
mod lazy;
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
compile_error!("`rdrand` backend can be enabled only for x86 and x86-64 targets!");
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
use core::arch::x86_64 as arch;
use arch::_rdrand64_step as rdrand_step;
type Word = u64;
} else if #[cfg(target_arch = "x86")] {
use core::arch::x86 as arch;
use arch::_rdrand32_step as rdrand_step;
type Word = u32;
}
}
static RDRAND_GOOD: lazy::LazyBool = lazy::LazyBool::new();
// Recommendation from "Intel® Digital Random Number Generator (DRNG) Software
// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
// Software Developers Manual" - Volume 1 - Section 7.3.17.1.
const RETRY_LIMIT: usize = 10;
#[target_feature(enable = "rdrand")]
unsafe fn rdrand() -> Option<Word> {
for _ in 0..RETRY_LIMIT {
let mut val = 0;
if rdrand_step(&mut val) == 1 {
return Some(val);
}
}
None
}
// "rdrand" target feature requires "+rdrand" 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=+rdrand."
);
// Run a small self-test to make sure we aren't repeating values
// Adapted from Linux's test in arch/x86/kernel/cpu/rdrand.c
// Fails with probability < 2^(-90) on 32-bit systems
#[target_feature(enable = "rdrand")]
unsafe fn self_test() -> bool {
// On AMD, RDRAND returns 0xFF...FF on failure, count it as a collision.
let mut prev = !0; // TODO(MSRV 1.43): Move to usize::MAX
let mut fails = 0;
for _ in 0..8 {
match rdrand() {
Some(val) if val == prev => fails += 1,
Some(val) => prev = val,
None => return false,
};
}
fails <= 2
}
fn is_rdrand_good() -> bool {
#[cfg(not(target_feature = "rdrand"))]
{
// SAFETY: All Rust x86 targets are new enough to have CPUID, and we
// check that leaf 1 is supported before using it.
let cpuid0 = unsafe { arch::__cpuid(0) };
if cpuid0.eax < 1 {
return false;
}
let cpuid1 = unsafe { arch::__cpuid(1) };
let vendor_id = [
cpuid0.ebx.to_le_bytes(),
cpuid0.edx.to_le_bytes(),
cpuid0.ecx.to_le_bytes(),
];
if vendor_id == [*b"Auth", *b"enti", *b"cAMD"] {
let mut family = (cpuid1.eax >> 8) & 0xF;
if family == 0xF {
family += (cpuid1.eax >> 20) & 0xFF;
}
// AMD CPUs families before 17h (Zen) sometimes fail to set CF when
// RDRAND fails after suspend. Don't use RDRAND on those families.
// See https://bugzilla.redhat.com/show_bug.cgi?id=1150286
if family < 0x17 {
return false;
}
}
const RDRAND_FLAG: u32 = 1 << 30;
if cpuid1.ecx & RDRAND_FLAG == 0 {
return false;
}
}
// SAFETY: We have already checked that rdrand is available.
unsafe { self_test() }
}
// TODO: make this function safe when we have feature(target_feature_11)
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_exact(dest: &mut [MaybeUninit<u8>]) -> Option<()> {
// 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(size_of::<Word>());
for chunk in chunks.by_ref() {
let src = rdrand()?.to_ne_bytes();
chunk.copy_from_slice(slice_as_uninit(&src));
}
let tail = chunks.into_remainder();
let n = tail.len();
if n > 0 {
let src = rdrand()?.to_ne_bytes();
tail.copy_from_slice(slice_as_uninit(&src[..n]));
}
Some(())
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u32() -> Option<u32> {
rdrand().map(crate::util::truncate)
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u64() -> Option<u64> {
rdrand()
}
#[cfg(target_arch = "x86")]
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u32() -> Option<u32> {
rdrand()
}
#[cfg(target_arch = "x86")]
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u64() -> Option<u64> {
let a = rdrand()?;
let b = rdrand()?;
Some((u64::from(a) << 32) | u64::from(b))
}
#[inline]
pub fn inner_u32() -> Result<u32, Error> {
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, we know rdrand is supported.
unsafe { rdrand_u32() }.ok_or(Error::FAILED_RDRAND)
}
#[inline]
pub fn inner_u64() -> Result<u64, Error> {
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, we know rdrand is supported.
unsafe { rdrand_u64() }.ok_or(Error::FAILED_RDRAND)
}
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, we know rdrand is supported.
unsafe { rdrand_exact(dest) }.ok_or(Error::FAILED_RDRAND)
}
impl Error {
/// RDRAND instruction failed due to a hardware issue.
pub(crate) const FAILED_RDRAND: Error = Self::new_internal(10);
/// RDRAND instruction unsupported on this target.
pub(crate) const NO_RDRAND: Error = Self::new_internal(11);
}

145
vendor/getrandom/src/backends/rndr.rs vendored Normal file
View File

@@ -0,0 +1,145 @@
//! RNDR register backend for aarch64 targets
//!
//! Arm Architecture Reference Manual for A-profile architecture:
//! ARM DDI 0487K.a, ID032224, D23.2.147 RNDR, Random Number
use crate::{
util::{slice_as_uninit, truncate},
Error,
};
use core::arch::asm;
use core::mem::{size_of, MaybeUninit};
#[cfg(not(target_arch = "aarch64"))]
compile_error!("the `rndr` backend can be enabled only for AArch64 targets!");
const RETRY_LIMIT: usize = 5;
/// Read a random number from the aarch64 RNDR register
///
/// Callers must ensure that FEAT_RNG is available on the system
/// The function assumes that the RNDR register is available
/// If it fails to read a random number, it will retry up to 5 times
/// After 5 failed reads the function will return `None`
#[target_feature(enable = "rand")]
unsafe fn rndr() -> Option<u64> {
for _ in 0..RETRY_LIMIT {
let mut x: u64;
let mut nzcv: u64;
// AArch64 RNDR register is accessible by s3_3_c2_c4_0
asm!(
"mrs {x}, RNDR",
"mrs {nzcv}, NZCV",
x = out(reg) x,
nzcv = out(reg) nzcv,
);
// If the hardware returns a genuine random number, PSTATE.NZCV is set to 0b0000
if nzcv == 0 {
return Some(x);
}
}
None
}
#[target_feature(enable = "rand")]
unsafe fn rndr_fill(dest: &mut [MaybeUninit<u8>]) -> Option<()> {
let mut chunks = dest.chunks_exact_mut(size_of::<u64>());
for chunk in chunks.by_ref() {
let src = rndr()?.to_ne_bytes();
chunk.copy_from_slice(slice_as_uninit(&src));
}
let tail = chunks.into_remainder();
let n = tail.len();
if n > 0 {
let src = rndr()?.to_ne_bytes();
tail.copy_from_slice(slice_as_uninit(&src[..n]));
}
Some(())
}
#[cfg(target_feature = "rand")]
fn is_rndr_available() -> bool {
true
}
#[cfg(not(target_feature = "rand"))]
fn is_rndr_available() -> bool {
#[path = "../lazy.rs"]
mod lazy;
static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new();
cfg_if::cfg_if! {
if #[cfg(feature = "std")] {
extern crate std;
RNDR_GOOD.unsync_init(|| std::arch::is_aarch64_feature_detected!("rand"))
} else if #[cfg(target_os = "linux")] {
/// Check whether FEAT_RNG is available on the system
///
/// Requires the caller either be running in EL1 or be on a system supporting MRS
/// emulation. Due to the above, the implementation is currently restricted to Linux.
///
/// Relying on runtime detection bumps minimum supported Linux kernel version to 4.11.
fn mrs_check() -> bool {
let mut id_aa64isar0: u64;
// If FEAT_RNG is implemented, ID_AA64ISAR0_EL1.RNDR (bits 60-63) are 0b0001
// This is okay to do from EL0 in Linux because Linux will emulate MRS as per
// https://docs.kernel.org/arch/arm64/cpu-feature-registers.html
unsafe {
asm!(
"mrs {id}, ID_AA64ISAR0_EL1",
id = out(reg) id_aa64isar0,
);
}
(id_aa64isar0 >> 60) & 0xf >= 1
}
RNDR_GOOD.unsync_init(mrs_check)
} else {
compile_error!(
"RNDR `no_std` runtime detection is currently supported only on Linux targets. \
Either enable the `std` crate feature, or `rand` target feature at compile time."
);
}
}
}
#[inline]
pub fn inner_u32() -> Result<u32, Error> {
if !is_rndr_available() {
return Err(Error::RNDR_NOT_AVAILABLE);
}
// SAFETY: after this point, we know the `rand` target feature is enabled
let res = unsafe { rndr() };
res.map(truncate).ok_or(Error::RNDR_FAILURE)
}
#[inline]
pub fn inner_u64() -> Result<u64, Error> {
if !is_rndr_available() {
return Err(Error::RNDR_NOT_AVAILABLE);
}
// SAFETY: after this point, we know the `rand` target feature is enabled
let res = unsafe { rndr() };
res.ok_or(Error::RNDR_FAILURE)
}
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
if !is_rndr_available() {
return Err(Error::RNDR_NOT_AVAILABLE);
}
// SAFETY: after this point, we know the `rand` target feature is enabled
unsafe { rndr_fill(dest).ok_or(Error::RNDR_FAILURE) }
}
impl Error {
/// RNDR register read failed due to a hardware issue.
pub(crate) const RNDR_FAILURE: Error = Self::new_internal(10);
/// RNDR register is not supported on this target.
pub(crate) const RNDR_NOT_AVAILABLE: Error = Self::new_internal(11);
}

View File

@@ -0,0 +1,42 @@
//! Solaris implementation using getrandom(2).
//!
//! While getrandom(2) has been available since Solaris 11.3, it has a few
//! quirks not present on other OSes. First, on Solaris 11.3, calls will always
//! fail if bufsz > 1024. Second, it will always either fail or completely fill
//! the buffer (returning bufsz). Third, error is indicated by returning 0,
//! rather than by returning -1. Finally, "if GRND_RANDOM is not specified
//! then getrandom(2) is always a non blocking call". This _might_ imply that
//! in early-boot scenarios with low entropy, getrandom(2) will not properly
//! block. To be safe, we set GRND_RANDOM, mirroring the man page examples.
//!
//! For more information, see the man page linked in lib.rs and this blog post:
//! https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2
//! which also explains why this crate should not use getentropy(2).
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};
pub use crate::util::{inner_u32, inner_u64};
#[path = "../util_libc.rs"]
mod util_libc;
const MAX_BYTES: usize = 1024;
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
for chunk in dest.chunks_mut(MAX_BYTES) {
let ptr = chunk.as_mut_ptr().cast::<c_void>();
let ret = unsafe { libc::getrandom(ptr, chunk.len(), libc::GRND_RANDOM) };
// In case the man page has a typo, we also check for negative ret.
// If getrandom(2) succeeds, it should have completely filled chunk.
match usize::try_from(ret) {
// Good. Keep going.
Ok(ret) if ret == chunk.len() => {}
// The syscall failed.
Ok(0) => return Err(util_libc::last_os_error()),
// All other cases should be impossible.
_ => return Err(Error::UNEXPECTED),
}
}
Ok(())
}

19
vendor/getrandom/src/backends/solid.rs vendored Normal file
View File

@@ -0,0 +1,19 @@
//! Implementation for SOLID
use crate::Error;
use core::mem::MaybeUninit;
pub use crate::util::{inner_u32, inner_u64};
extern "C" {
pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> i32;
}
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
let ret = unsafe { SOLID_RNG_SampleRandomBytes(dest.as_mut_ptr().cast::<u8>(), dest.len()) };
if ret >= 0 {
Ok(())
} else {
Err(Error::from_neg_error_code(ret))
}
}

View File

@@ -0,0 +1,234 @@
//! Implementations that just need to read from a file
use crate::Error;
use core::{
ffi::c_void,
mem::MaybeUninit,
sync::atomic::{AtomicI32, Ordering},
};
#[cfg(not(any(target_os = "android", target_os = "linux")))]
pub use crate::util::{inner_u32, inner_u64};
#[path = "../util_libc.rs"]
pub(super) mod util_libc;
/// For all platforms, we use `/dev/urandom` rather than `/dev/random`.
/// For more information see the linked man pages in lib.rs.
/// - On Linux, "/dev/urandom is preferred and sufficient in all use cases".
/// - On Redox, only /dev/urandom is provided.
/// - On AIX, /dev/urandom will "provide cryptographically secure output".
/// - On Haiku and QNX Neutrino they are identical.
const FILE_PATH: &[u8] = b"/dev/urandom\0";
// File descriptor is a "nonnegative integer", so we can safely use negative sentinel values.
const FD_UNINIT: libc::c_int = -1;
const FD_ONGOING_INIT: libc::c_int = -2;
// In theory `libc::c_int` could be something other than `i32`, but for the
// targets we currently support that use `use_file`, it is always `i32`.
// If/when we add support for a target where that isn't the case, we may
// need to use a different atomic type or make other accomodations. The
// compiler will let us know if/when that is the case, because the
// `FD.store(fd)` would fail to compile.
//
// The opening of the file, by libc/libstd/etc. may write some unknown
// state into in-process memory. (Such state may include some sanitizer
// bookkeeping, or we might be operating in a unikernal-like environment
// where all the "kernel" file descriptor bookkeeping is done in our
// process.) `get_fd_locked` stores into FD using `Ordering::Release` to
// ensure any such state is synchronized. `get_fd` loads from `FD` with
// `Ordering::Acquire` to synchronize with it.
static FD: AtomicI32 = AtomicI32::new(FD_UNINIT);
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
let mut fd = FD.load(Ordering::Acquire);
if fd == FD_UNINIT || fd == FD_ONGOING_INIT {
fd = open_or_wait()?;
}
util_libc::sys_fill_exact(dest, |buf| unsafe {
libc::read(fd, buf.as_mut_ptr().cast::<c_void>(), buf.len())
})
}
/// Open a file in read-only mode.
///
/// # Panics
/// If `path` does not contain any zeros.
// TODO: Move `path` to `CStr` and use `CStr::from_bytes_until_nul` (MSRV 1.69)
// or C-string literals (MSRV 1.77) for statics
fn open_readonly(path: &[u8]) -> Result<libc::c_int, Error> {
assert!(path.contains(&0));
loop {
let fd = unsafe {
libc::open(
path.as_ptr().cast::<libc::c_char>(),
libc::O_RDONLY | libc::O_CLOEXEC,
)
};
if fd >= 0 {
return Ok(fd);
}
let err = util_libc::last_os_error();
// We should try again if open() was interrupted.
if err.raw_os_error() != Some(libc::EINTR) {
return Err(err);
}
}
}
#[cold]
#[inline(never)]
fn open_or_wait() -> Result<libc::c_int, Error> {
loop {
match FD.load(Ordering::Acquire) {
FD_UNINIT => {
let res = FD.compare_exchange_weak(
FD_UNINIT,
FD_ONGOING_INIT,
Ordering::AcqRel,
Ordering::Relaxed,
);
if res.is_ok() {
break;
}
}
FD_ONGOING_INIT => sync::wait(),
fd => return Ok(fd),
}
}
let res = open_fd();
let val = match res {
Ok(fd) => fd,
Err(_) => FD_UNINIT,
};
FD.store(val, Ordering::Release);
// On non-Linux targets `wait` is just 1 ms sleep,
// so we don't need any explicit wake up in addition
// to updating value of `FD`.
#[cfg(any(target_os = "android", target_os = "linux"))]
sync::wake();
res
}
fn open_fd() -> Result<libc::c_int, Error> {
#[cfg(any(target_os = "android", target_os = "linux"))]
sync::wait_until_rng_ready()?;
let fd = open_readonly(FILE_PATH)?;
debug_assert!(fd >= 0);
Ok(fd)
}
#[cfg(not(any(target_os = "android", target_os = "linux")))]
mod sync {
/// Sleep 1 ms before checking `FD` again.
///
/// On non-Linux targets the critical section only opens file,
/// which should not block, so in the unlikely contended case,
/// we can sleep-wait for the opening operation to finish.
pub(super) fn wait() {
let rqtp = libc::timespec {
tv_sec: 0,
tv_nsec: 1_000_000,
};
let mut rmtp = libc::timespec {
tv_sec: 0,
tv_nsec: 0,
};
// We do not care if sleep gets interrupted, so the return value is ignored
unsafe {
libc::nanosleep(&rqtp, &mut rmtp);
}
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
mod sync {
use super::{open_readonly, util_libc::last_os_error, Error, FD, FD_ONGOING_INIT};
/// Wait for atomic `FD` to change value from `FD_ONGOING_INIT` to something else.
///
/// Futex syscall with `FUTEX_WAIT` op puts the current thread to sleep
/// until futex syscall with `FUTEX_WAKE` op gets executed for `FD`.
///
/// For more information read: https://www.man7.org/linux/man-pages/man2/futex.2.html
pub(super) fn wait() {
let op = libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG;
let timeout_ptr = core::ptr::null::<libc::timespec>();
let ret = unsafe { libc::syscall(libc::SYS_futex, &FD, op, FD_ONGOING_INIT, timeout_ptr) };
// FUTEX_WAIT should return either 0 or EAGAIN error
debug_assert!({
match ret {
0 => true,
-1 => last_os_error().raw_os_error() == Some(libc::EAGAIN),
_ => false,
}
});
}
/// Wake up all threads which wait for value of atomic `FD` to change.
pub(super) fn wake() {
let op = libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG;
let ret = unsafe { libc::syscall(libc::SYS_futex, &FD, op, libc::INT_MAX) };
debug_assert!(ret >= 0);
}
// Polls /dev/random to make sure it is ok to read from /dev/urandom.
//
// Polling avoids draining the estimated entropy from /dev/random;
// short-lived processes reading even a single byte from /dev/random could
// be problematic if they are being executed faster than entropy is being
// collected.
//
// OTOH, reading a byte instead of polling is more compatible with
// sandboxes that disallow `poll()` but which allow reading /dev/random,
// e.g. sandboxes that assume that `poll()` is for network I/O. This way,
// fewer applications will have to insert pre-sandbox-initialization logic.
// Often (blocking) file I/O is not allowed in such early phases of an
// application for performance and/or security reasons.
//
// It is hard to write a sandbox policy to support `libc::poll()` because
// it may invoke the `poll`, `ppoll`, `ppoll_time64` (since Linux 5.1, with
// newer versions of glibc), and/or (rarely, and probably only on ancient
// systems) `select`. depending on the libc implementation (e.g. glibc vs
// musl), libc version, potentially the kernel version at runtime, and/or
// the target architecture.
//
// BoringSSL and libstd don't try to protect against insecure output from
// `/dev/urandom'; they don't open `/dev/random` at all.
//
// OpenSSL uses `libc::select()` unless the `dev/random` file descriptor
// is too large; if it is too large then it does what we do here.
//
// libsodium uses `libc::poll` similarly to this.
pub(super) fn wait_until_rng_ready() -> Result<(), Error> {
let fd = open_readonly(b"/dev/random\0")?;
let mut pfd = libc::pollfd {
fd,
events: libc::POLLIN,
revents: 0,
};
let res = loop {
// A negative timeout means an infinite timeout.
let res = unsafe { libc::poll(&mut pfd, 1, -1) };
if res >= 0 {
// We only used one fd, and cannot timeout.
debug_assert_eq!(res, 1);
break Ok(());
}
let err = last_os_error();
// Assuming that `poll` is called correctly,
// on Linux it can return only EINTR and ENOMEM errors.
match err.raw_os_error() {
Some(libc::EINTR) => continue,
_ => break Err(err),
}
};
unsafe { libc::close(fd) };
res
}
}

View File

@@ -0,0 +1,54 @@
//! Implementation for VxWorks
use crate::Error;
use core::{
cmp::Ordering::{Equal, Greater, Less},
mem::MaybeUninit,
sync::atomic::{AtomicBool, Ordering::Relaxed},
};
#[path = "../util_libc.rs"]
mod util_libc;
pub use crate::util::{inner_u32, inner_u64};
static RNG_INIT: AtomicBool = AtomicBool::new(false);
#[cold]
fn init() -> Result<(), Error> {
let ret = unsafe { libc::randSecure() };
match ret.cmp(&0) {
Greater => RNG_INIT.store(true, Relaxed),
Equal => unsafe {
libc::usleep(10);
},
Less => return Err(Error::VXWORKS_RAND_SECURE),
}
Ok(())
}
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
while !RNG_INIT.load(Relaxed) {
init()?;
}
// Prevent overflow of i32
let chunk_size = usize::try_from(i32::MAX).expect("VxWorks does not support 16-bit targets");
for chunk in dest.chunks_mut(chunk_size) {
let chunk_len: libc::c_int = chunk
.len()
.try_into()
.expect("chunk size is bounded by i32::MAX");
let p: *mut libc::c_uchar = chunk.as_mut_ptr().cast();
let ret = unsafe { libc::randABytes(p, chunk_len) };
if ret != 0 {
return Err(util_libc::last_os_error());
}
}
Ok(())
}
impl Error {
/// On VxWorks, call to `randSecure` failed (random number generator is not yet initialized).
pub(crate) const VXWORKS_RAND_SECURE: Error = Self::new_internal(10);
}

View File

@@ -0,0 +1,32 @@
//! Implementation for WASI Preview 1
use crate::Error;
use core::mem::MaybeUninit;
pub use crate::util::{inner_u32, inner_u64};
// This linking is vendored from the wasi crate:
// https://docs.rs/wasi/0.11.0+wasi-snapshot-preview1/src/wasi/lib_generated.rs.html#2344-2350
#[link(wasm_import_module = "wasi_snapshot_preview1")]
extern "C" {
fn random_get(arg0: i32, arg1: i32) -> i32;
}
/// WASI p1 uses `u16` for error codes in its witx definitions:
/// https://github.com/WebAssembly/WASI/blob/38454e9e/legacy/preview1/witx/typenames.witx#L34-L39
const MAX_ERROR_CODE: i32 = u16::MAX as i32;
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// Based on the wasi code:
// https://docs.rs/wasi/0.11.0+wasi-snapshot-preview1/src/wasi/lib_generated.rs.html#2046-2062
// Note that size of an allocated object can not be bigger than isize::MAX bytes.
// WASI 0.1 supports only 32-bit WASM, so casting length to `i32` is safe.
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
let ret = unsafe { random_get(dest.as_mut_ptr() as i32, dest.len() as i32) };
match ret {
0 => Ok(()),
// WASI functions should return positive error codes which are smaller than `MAX_ERROR_CODE`
code if code <= MAX_ERROR_CODE => Err(Error::from_neg_error_code(-code)),
_ => Err(Error::UNEXPECTED),
}
}

View File

@@ -0,0 +1,50 @@
//! Implementation for WASI Preview 2.
use crate::Error;
use core::mem::MaybeUninit;
use wasi::random::random::get_random_u64;
#[inline]
pub fn inner_u32() -> Result<u32, Error> {
let val = get_random_u64();
Ok(crate::util::truncate(val))
}
#[inline]
pub fn inner_u64() -> Result<u64, Error> {
Ok(get_random_u64())
}
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
use core::ptr::copy_nonoverlapping;
use wasi::random::random::get_random_u64;
let (prefix, chunks, suffix) = unsafe { dest.align_to_mut::<MaybeUninit<u64>>() };
// We use `get_random_u64` instead of `get_random_bytes` because the latter creates
// an allocation due to the Wit IDL [restrictions][0]. This should be fine since
// the main use case of `getrandom` is seed generation.
//
// [0]: https://github.com/WebAssembly/wasi-random/issues/27
if !prefix.is_empty() {
let val = get_random_u64();
let src = (&val as *const u64).cast();
unsafe {
copy_nonoverlapping(src, prefix.as_mut_ptr(), prefix.len());
}
}
for dst in chunks {
dst.write(get_random_u64());
}
if !suffix.is_empty() {
let val = get_random_u64();
let src = (&val as *const u64).cast();
unsafe {
copy_nonoverlapping(src, suffix.as_mut_ptr(), suffix.len());
}
}
Ok(())
}

View File

@@ -0,0 +1,72 @@
//! Implementation for WASM based on Web and Node.js
use crate::Error;
use core::mem::MaybeUninit;
pub use crate::util::{inner_u32, inner_u64};
#[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
compile_error!("`wasm_js` backend can be enabled only for OS-less WASM targets!");
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
// Maximum buffer size allowed in `Crypto.getRandomValuesSize` is 65536 bytes.
// See https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
const MAX_BUFFER_SIZE: usize = 65536;
#[cfg(not(target_feature = "atomics"))]
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
for chunk in dest.chunks_mut(MAX_BUFFER_SIZE) {
if get_random_values(chunk).is_err() {
return Err(Error::WEB_CRYPTO);
}
}
Ok(())
}
#[cfg(target_feature = "atomics")]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// getRandomValues does not work with all types of WASM memory,
// so we initially write to browser memory to avoid exceptions.
let buf_len = usize::min(dest.len(), MAX_BUFFER_SIZE);
let buf_len_u32 = buf_len
.try_into()
.expect("buffer length is bounded by MAX_BUFFER_SIZE");
let buf = js_sys::Uint8Array::new_with_length(buf_len_u32);
for chunk in dest.chunks_mut(buf_len) {
let chunk_len = chunk
.len()
.try_into()
.expect("chunk length is bounded by MAX_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 = if chunk_len == buf_len_u32 {
&buf
} else {
&buf.subarray(0, chunk_len)
};
if get_random_values(sub_buf).is_err() {
return Err(Error::WEB_CRYPTO);
}
sub_buf.copy_to_uninit(chunk);
}
Ok(())
}
#[wasm_bindgen]
extern "C" {
// Crypto.getRandomValues()
#[cfg(not(target_feature = "atomics"))]
#[wasm_bindgen(js_namespace = ["globalThis", "crypto"], js_name = getRandomValues, catch)]
fn get_random_values(buf: &mut [MaybeUninit<u8>]) -> Result<(), JsValue>;
#[cfg(target_feature = "atomics")]
#[wasm_bindgen(js_namespace = ["globalThis", "crypto"], js_name = getRandomValues, catch)]
fn get_random_values(buf: &js_sys::Uint8Array) -> Result<(), JsValue>;
}
impl Error {
/// The environment does not support the Web Crypto API.
pub(crate) const WEB_CRYPTO: Error = Self::new_internal(10);
}

View File

@@ -0,0 +1,61 @@
//! Implementation for Windows 10 and later
//!
//! On Windows 10 and later, ProcessPrng "is the primary interface to the
//! user-mode per-processor PRNGs" and only requires bcryptprimitives.dll,
//! making it a better option than the other Windows RNG APIs:
//! - BCryptGenRandom: https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
//! - Requires bcrypt.dll (which loads bcryptprimitives.dll anyway)
//! - Can cause crashes/hangs as BCrypt accesses the Windows Registry:
//! https://github.com/rust-lang/rust/issues/99341
//! - Causes issues inside sandboxed code:
//! https://issues.chromium.org/issues/40277768
//! - CryptGenRandom: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom
//! - Deprecated and not available on UWP targets
//! - Requires advapi32.lib/advapi32.dll (in addition to bcryptprimitives.dll)
//! - Thin wrapper around ProcessPrng
//! - RtlGenRandom: https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
//! - Deprecated and not available on UWP targets
//! - Requires advapi32.dll (in addition to bcryptprimitives.dll)
//! - Requires using name "SystemFunction036"
//! - Thin wrapper around ProcessPrng
//!
//! For more information see the Windows RNG Whitepaper: https://aka.ms/win10rng
use crate::Error;
use core::mem::MaybeUninit;
pub use crate::util::{inner_u32, inner_u64};
// Binding to the Windows.Win32.Security.Cryptography.ProcessPrng API. As
// bcryptprimitives.dll lacks an import library, we use "raw-dylib". This
// was added in Rust 1.65 for x86_64/aarch64 and in Rust 1.71 for x86.
// We don't need MSRV 1.71, as we only use this backend on Rust 1.78 and later.
#[cfg_attr(
target_arch = "x86",
link(
name = "bcryptprimitives",
kind = "raw-dylib",
import_name_type = "undecorated"
)
)]
#[cfg_attr(
not(target_arch = "x86"),
link(name = "bcryptprimitives", kind = "raw-dylib")
)]
extern "system" {
fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
}
#[allow(clippy::upper_case_acronyms)]
type BOOL = core::ffi::c_int; // MSRV 1.64, similarly OK for this backend.
const TRUE: BOOL = 1;
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
let result = unsafe { ProcessPrng(dest.as_mut_ptr().cast::<u8>(), dest.len()) };
// Since Windows 10, calls to the user-mode RNG are guaranteed to never
// fail during runtime (rare windows W); `ProcessPrng` will only ever
// return 1 (which is how windows represents TRUE).
// See the bottom of page 6 of the aforementioned Windows RNG
// whitepaper for more information.
debug_assert!(result == TRUE);
Ok(())
}

View File

@@ -0,0 +1,45 @@
//! Legacy implementation for Windows XP and later
//!
//! For targets where we cannot use ProcessPrng (added in Windows 10), we use
//! RtlGenRandom. See windows.rs for a more detailed discussion of the Windows
//! RNG APIs (and why we don't use BCryptGenRandom). On versions prior to
//! Windows 10, this implementation is secure. On Windows 10 and later, this
//! implementation behaves identically to the windows.rs implementation, except
//! that it forces the loading of an additonal DLL (advapi32.dll).
//!
//! This implementation will not work on UWP targets (which lack advapi32.dll),
//! but such targets require Windows 10, so can use the standard implementation.
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};
pub use crate::util::{inner_u32, inner_u64};
// Binding to the Windows.Win32.Security.Authentication.Identity.RtlGenRandom
// API. Don't use windows-targets as it doesn't support Windows 7 targets.
#[link(name = "advapi32")]
extern "system" {
#[link_name = "SystemFunction036"]
fn RtlGenRandom(randombuffer: *mut c_void, randombufferlength: u32) -> BOOLEAN;
}
#[allow(clippy::upper_case_acronyms)]
type BOOLEAN = u8;
const TRUE: BOOLEAN = 1u8;
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// Prevent overflow of u32
let chunk_size = usize::try_from(i32::MAX).expect("Windows does not support 16-bit targets");
for chunk in dest.chunks_mut(chunk_size) {
let chunk_len = u32::try_from(chunk.len()).expect("chunk size is bounded by i32::MAX");
let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr().cast::<c_void>(), chunk_len) };
if ret != TRUE {
return Err(Error::WINDOWS_RTL_GEN_RANDOM);
}
}
Ok(())
}
impl Error {
/// Call to Windows [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) failed.
pub(crate) const WINDOWS_RTL_GEN_RANDOM: Error = Self::new_internal(10);
}

212
vendor/getrandom/src/error.rs vendored Normal file
View File

@@ -0,0 +1,212 @@
#[cfg(feature = "std")]
extern crate std;
use core::fmt;
// This private alias mirrors `std::io::RawOsError`:
// https://doc.rust-lang.org/std/io/type.RawOsError.html)
cfg_if::cfg_if!(
if #[cfg(target_os = "uefi")] {
// See the UEFI spec for more information:
// https://uefi.org/specs/UEFI/2.10/Apx_D_Status_Codes.html
type RawOsError = usize;
type NonZeroRawOsError = core::num::NonZeroUsize;
const UEFI_ERROR_FLAG: RawOsError = 1 << (RawOsError::BITS - 1);
} else {
type RawOsError = i32;
type NonZeroRawOsError = core::num::NonZeroI32;
}
);
/// 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.
///
/// *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).
// note: on non-UEFI targets OS errors are represented as negative integers,
// while on UEFI targets OS errors have the highest bit set to 1.
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Error(NonZeroRawOsError);
impl Error {
/// This target/platform is not supported by `getrandom`.
pub const UNSUPPORTED: Error = Self::new_internal(0);
/// The platform-specific `errno` returned a non-positive value.
pub const ERRNO_NOT_POSITIVE: Error = Self::new_internal(1);
/// Encountered an unexpected situation which should not happen in practice.
pub const UNEXPECTED: Error = Self::new_internal(2);
/// Internal errors can be in the range of 2^16..2^17
const INTERNAL_START: RawOsError = 1 << 16;
/// Custom errors can be in the range of 2^17..(2^17 + 2^16)
const CUSTOM_START: RawOsError = 1 << 17;
/// Creates a new instance of an `Error` from a negative error code.
#[cfg(not(target_os = "uefi"))]
#[allow(dead_code)]
pub(super) fn from_neg_error_code(code: RawOsError) -> Self {
if code < 0 {
let code = NonZeroRawOsError::new(code).expect("`code` is negative");
Self(code)
} else {
Error::UNEXPECTED
}
}
/// Creates a new instance of an `Error` from an UEFI error code.
#[cfg(target_os = "uefi")]
#[allow(dead_code)]
pub(super) fn from_uefi_code(code: RawOsError) -> Self {
if code & UEFI_ERROR_FLAG != 0 {
let code = NonZeroRawOsError::new(code).expect("The highest bit of `code` is set to 1");
Self(code)
} else {
Self::UNEXPECTED
}
}
/// 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. On most targets this method returns
/// `Option<i32>`, but some platforms (e.g. UEFI) may use a different primitive
/// type like `usize`. Consult with the [`RawOsError`] docs for more information.
///
/// 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
/// [`RawOsError`]: https://doc.rust-lang.org/std/io/type.RawOsError.html
#[inline]
pub fn raw_os_error(self) -> Option<RawOsError> {
let code = self.0.get();
// note: in this method we need to cover only backends which rely on
// `Error::{from_error_code, from_errno, from_uefi_code}` methods,
// on all other backends this method always returns `None`.
#[cfg(target_os = "uefi")]
{
if code & UEFI_ERROR_FLAG != 0 {
Some(code)
} else {
None
}
}
#[cfg(not(target_os = "uefi"))]
{
// On most targets `std` expects positive error codes while retrieving error strings:
// - `libc`-based targets use `strerror_r` which expects positive error codes.
// - Hermit relies on the `hermit-abi` crate, which expects positive error codes:
// https://docs.rs/hermit-abi/0.4.0/src/hermit_abi/errno.rs.html#400-532
// - WASIp1 uses the same conventions as `libc`:
// https://github.com/rust-lang/rust/blob/1.85.0/library/std/src/sys/pal/wasi/os.rs#L57-L67
//
// The only exception is Solid, `std` expects negative system error codes, see:
// https://github.com/rust-lang/rust/blob/1.85.0/library/std/src/sys/pal/solid/error.rs#L5-L31
if code >= 0 {
None
} else if cfg!(not(target_os = "solid_asp3")) {
code.checked_neg()
} else {
Some(code)
}
}
}
/// Creates a new instance of an `Error` from a particular custom error code.
pub const fn new_custom(n: u16) -> Error {
// SAFETY: code > 0 as CUSTOM_START > 0 and adding `n` won't overflow `RawOsError`.
let code = Error::CUSTOM_START + (n as RawOsError);
Error(unsafe { NonZeroRawOsError::new_unchecked(code) })
}
/// Creates a new instance of an `Error` from a particular internal error code.
pub(crate) const fn new_internal(n: u16) -> Error {
// SAFETY: code > 0 as INTERNAL_START > 0 and adding `n` won't overflow `RawOsError`.
let code = Error::INTERNAL_START + (n as RawOsError);
Error(unsafe { NonZeroRawOsError::new_unchecked(code) })
}
fn internal_desc(&self) -> Option<&'static str> {
let desc = match *self {
Error::UNSUPPORTED => "getrandom: this target is not supported",
Error::ERRNO_NOT_POSITIVE => "errno: did not return a positive value",
Error::UNEXPECTED => "unexpected situation",
#[cfg(any(
target_os = "ios",
target_os = "visionos",
target_os = "watchos",
target_os = "tvos",
))]
Error::IOS_RANDOM_GEN => "SecRandomCopyBytes: iOS Security framework failure",
#[cfg(all(windows, target_vendor = "win7"))]
Error::WINDOWS_RTL_GEN_RANDOM => "RtlGenRandom: Windows system function failure",
#[cfg(all(feature = "wasm_js", getrandom_backend = "wasm_js"))]
Error::WEB_CRYPTO => "Web Crypto API is unavailable",
#[cfg(target_os = "vxworks")]
Error::VXWORKS_RAND_SECURE => "randSecure: VxWorks RNG module is not initialized",
#[cfg(any(
getrandom_backend = "rdrand",
all(target_arch = "x86_64", target_env = "sgx")
))]
Error::FAILED_RDRAND => "RDRAND: failed multiple times: CPU issue likely",
#[cfg(any(
getrandom_backend = "rdrand",
all(target_arch = "x86_64", target_env = "sgx")
))]
Error::NO_RDRAND => "RDRAND: instruction not supported",
#[cfg(getrandom_backend = "rndr")]
Error::RNDR_FAILURE => "RNDR: Could not generate a random number",
#[cfg(getrandom_backend = "rndr")]
Error::RNDR_NOT_AVAILABLE => "RNDR: Register not supported",
_ => return None,
};
Some(desc)
}
}
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);
#[cfg(feature = "std")]
dbg.field("description", &std::io::Error::from_raw_os_error(errno));
} else if let Some(desc) = self.internal_desc() {
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() {
cfg_if! {
if #[cfg(feature = "std")] {
std::io::Error::from_raw_os_error(errno).fmt(f)
} else {
write!(f, "OS Error: {}", errno)
}
}
} else if let Some(desc) = self.internal_desc() {
f.write_str(desc)
} else {
write!(f, "Unknown Error: {}", self.0.get())
}
}
}

15
vendor/getrandom/src/error_std_impls.rs vendored Normal file
View File

@@ -0,0 +1,15 @@
extern crate std;
use crate::Error;
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 {}

64
vendor/getrandom/src/lazy.rs vendored Normal file
View File

@@ -0,0 +1,64 @@
//! Helpers built around pointer-sized atomics.
use core::sync::atomic::{AtomicUsize, Ordering};
// This structure represents a lazily initialized static usize value. Useful
// when it is preferable to just rerun initialization instead of locking.
// unsync_init will invoke an init() function until it succeeds, then return the
// cached value for future calls.
//
// unsync_init supports 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 may be needed.
struct LazyUsize(AtomicUsize);
impl LazyUsize {
// The initialization is not completed.
const UNINIT: usize = usize::MAX;
const fn new() -> Self {
Self(AtomicUsize::new(Self::UNINIT))
}
// Runs the init() function at most 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.
fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize {
#[cold]
fn do_init(this: &LazyUsize, init: impl FnOnce() -> usize) -> usize {
let val = init();
this.0.store(val, Ordering::Relaxed);
val
}
// Relaxed ordering is fine, as we only have a single atomic variable.
let val = self.0.load(Ordering::Relaxed);
if val != Self::UNINIT {
val
} else {
do_init(self, init)
}
}
}
// Identical to LazyUsize except with bool instead of usize.
pub(crate) 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(|| usize::from(init())) != 0
}
}

143
vendor/getrandom/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,143 @@
// Overwrite links to crate items with intra-crate links
//! [`Error::UNEXPECTED`]: Error::UNEXPECTED
//! [`fill_uninit`]: fill_uninit
#![no_std]
#![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"
)]
#![doc = include_str!("../README.md")]
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(getrandom_backend = "efi_rng", feature(uefi_std))]
#![deny(
clippy::cast_lossless,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_precision_loss,
clippy::cast_ptr_alignment,
clippy::cast_sign_loss,
clippy::char_lit_as_u8,
clippy::checked_conversions,
clippy::fn_to_numeric_cast,
clippy::fn_to_numeric_cast_with_truncation,
clippy::ptr_as_ptr,
clippy::unnecessary_cast,
clippy::useless_conversion
)]
#[macro_use]
extern crate cfg_if;
use core::mem::MaybeUninit;
mod backends;
mod error;
mod util;
#[cfg(feature = "std")]
mod error_std_impls;
pub use crate::error::Error;
/// 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).
///
/// # Examples
///
/// ```
/// # fn main() -> Result<(), getrandom::Error> {
/// let mut buf = [0u8; 32];
/// getrandom::fill(&mut buf)?;
/// # Ok(()) }
/// ```
#[inline]
pub fn fill(dest: &mut [u8]) -> Result<(), Error> {
// SAFETY: The `&mut MaybeUninit<_>` reference doesn't escape,
// and `fill_uninit` guarantees it will never de-initialize
// any part of `dest`.
fill_uninit(unsafe { util::slice_as_uninit_mut(dest) })?;
Ok(())
}
/// Fill potentially uninitialized buffer `dest` with random bytes from
/// the system's preferred random number source and return a mutable
/// reference to those bytes.
///
/// On successful completion this function is guaranteed to return a slice
/// which points to the same memory as `dest` and has the same length.
/// In other words, it's safe to assume that `dest` is initialized after
/// this function has returned `Ok`.
///
/// No part of `dest` will ever be de-initialized at any point, regardless
/// of what is returned.
///
/// # Examples
///
/// ```ignore
/// # // We ignore this test since `uninit_array` is unstable.
/// #![feature(maybe_uninit_uninit_array)]
/// # fn main() -> Result<(), getrandom::Error> {
/// let mut buf = core::mem::MaybeUninit::uninit_array::<1024>();
/// let buf: &mut [u8] = getrandom::fill_uninit(&mut buf)?;
/// # Ok(()) }
/// ```
#[inline]
pub fn fill_uninit(dest: &mut [MaybeUninit<u8>]) -> Result<&mut [u8], Error> {
if !dest.is_empty() {
backends::fill_inner(dest)?;
}
#[cfg(getrandom_msan)]
extern "C" {
fn __msan_unpoison(a: *mut core::ffi::c_void, size: usize);
}
// SAFETY: `dest` has been fully initialized by `imp::fill_inner`
// since it returned `Ok`.
Ok(unsafe {
#[cfg(getrandom_msan)]
__msan_unpoison(dest.as_mut_ptr().cast(), dest.len());
util::slice_assume_init_mut(dest)
})
}
/// Get random `u32` from the system's preferred random number source.
///
/// # Examples
///
/// ```
/// # fn main() -> Result<(), getrandom::Error> {
/// let rng_seed = getrandom::u32()?;
/// # Ok(()) }
/// ```
#[inline]
pub fn u32() -> Result<u32, Error> {
backends::inner_u32()
}
/// Get random `u64` from the system's preferred random number source.
///
/// # Examples
///
/// ```
/// # fn main() -> Result<(), getrandom::Error> {
/// let rng_seed = getrandom::u64()?;
/// # Ok(()) }
/// ```
#[inline]
pub fn u64() -> Result<u64, Error> {
backends::inner_u64()
}

84
vendor/getrandom/src/util.rs vendored Normal file
View File

@@ -0,0 +1,84 @@
#![allow(dead_code)]
use crate::Error;
use core::{mem::MaybeUninit, ptr, slice};
/// Polyfill for `maybe_uninit_slice` feature's
/// `MaybeUninit::slice_assume_init_mut`. Every element of `slice` must have
/// been initialized.
#[inline(always)]
#[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this.
pub unsafe fn slice_assume_init_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T] {
let ptr = ptr_from_mut::<[MaybeUninit<T>]>(slice) as *mut [T];
// SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`.
unsafe { &mut *ptr }
}
#[inline]
pub fn uninit_slice_fill_zero(slice: &mut [MaybeUninit<u8>]) -> &mut [u8] {
unsafe { ptr::write_bytes(slice.as_mut_ptr(), 0, slice.len()) };
unsafe { slice_assume_init_mut(slice) }
}
#[inline(always)]
pub fn slice_as_uninit<T>(slice: &[T]) -> &[MaybeUninit<T>] {
let ptr = ptr_from_ref::<[T]>(slice) as *const [MaybeUninit<T>];
// SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`.
unsafe { &*ptr }
}
/// View an mutable initialized array as potentially-uninitialized.
///
/// This is unsafe because it allows assigning uninitialized values into
/// `slice`, which would be undefined behavior.
#[inline(always)]
#[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this.
pub unsafe fn slice_as_uninit_mut<T>(slice: &mut [T]) -> &mut [MaybeUninit<T>] {
let ptr = ptr_from_mut::<[T]>(slice) as *mut [MaybeUninit<T>];
// SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`.
unsafe { &mut *ptr }
}
// TODO: MSRV(1.76.0): Replace with `core::ptr::from_mut`.
fn ptr_from_mut<T: ?Sized>(r: &mut T) -> *mut T {
r
}
// TODO: MSRV(1.76.0): Replace with `core::ptr::from_ref`.
fn ptr_from_ref<T: ?Sized>(r: &T) -> *const T {
r
}
/// Default implementation of `inner_u32` on top of `fill_uninit`
#[inline]
pub fn inner_u32() -> Result<u32, Error> {
let mut res = MaybeUninit::<u32>::uninit();
// SAFETY: the created slice has the same size as `res`
let dst = unsafe {
let p: *mut MaybeUninit<u8> = res.as_mut_ptr().cast();
slice::from_raw_parts_mut(p, core::mem::size_of::<u32>())
};
crate::fill_uninit(dst)?;
// SAFETY: `dst` has been fully initialized by `imp::fill_inner`
// since it returned `Ok`.
Ok(unsafe { res.assume_init() })
}
/// Default implementation of `inner_u64` on top of `fill_uninit`
#[inline]
pub fn inner_u64() -> Result<u64, Error> {
let mut res = MaybeUninit::<u64>::uninit();
// SAFETY: the created slice has the same size as `res`
let dst = unsafe {
let p: *mut MaybeUninit<u8> = res.as_mut_ptr().cast();
slice::from_raw_parts_mut(p, core::mem::size_of::<u64>())
};
crate::fill_uninit(dst)?;
// SAFETY: `dst` has been fully initialized by `imp::fill_inner`
// since it returned `Ok`.
Ok(unsafe { res.assume_init() })
}
/// Truncates `u64` and returns the lower 32 bits as `u32`
pub(crate) fn truncate(val: u64) -> u32 {
u32::try_from(val & u64::from(u32::MAX)).expect("The higher 32 bits are masked")
}

81
vendor/getrandom/src/util_libc.rs vendored Normal file
View File

@@ -0,0 +1,81 @@
use crate::Error;
use core::mem::MaybeUninit;
cfg_if! {
if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "cygwin"))] {
use libc::__errno as errno_location;
} else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd", target_os = "redox", target_os = "dragonfly"))] {
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(target_os = "nto")] {
use libc::__get_errno_ptr as errno_location;
} else if #[cfg(any(all(target_os = "horizon", target_arch = "arm"), target_os = "vita"))] {
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;
} else if #[cfg(target_os = "aix")] {
use libc::_Errno as errno_location;
}
}
cfg_if! {
if #[cfg(target_os = "vxworks")] {
use libc::errnoGet as get_errno;
} else {
unsafe fn get_errno() -> libc::c_int { *errno_location() }
}
}
pub(crate) fn last_os_error() -> Error {
// We assume that on all targets which use the `util_libc` module `c_int` is equal to `i32`
let errno: i32 = unsafe { get_errno() };
if errno > 0 {
let code = errno
.checked_neg()
.expect("Positive number can be always negated");
Error::from_neg_error_code(code)
} else {
Error::ERRNO_NOT_POSITIVE
}
}
/// Fill a buffer by repeatedly invoking `sys_fill`.
///
/// The `sys_fill` function:
/// - should return -1 and set errno on failure
/// - should return the number of bytes written on success
#[allow(dead_code)]
pub(crate) fn sys_fill_exact(
mut buf: &mut [MaybeUninit<u8>],
sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> libc::ssize_t,
) -> Result<(), Error> {
while !buf.is_empty() {
let res = sys_fill(buf);
match res {
res if res > 0 => {
let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?;
buf = buf.get_mut(len..).ok_or(Error::UNEXPECTED)?;
}
-1 => {
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);
}
}
// Negative return codes not equal to -1 should be impossible.
// EOF (ret = 0) should be impossible, as the data we are reading
// should be an infinite stream of random bytes.
_ => return Err(Error::UNEXPECTED),
}
}
Ok(())
}