From bcbadc1883ae1ab825f53687bd4cb4164bce9aa8 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 22 May 2024 05:24:08 +0300 Subject: [PATCH 001/201] Rename `Weak` to `LazyPtr` and move it to `lazy.rs` (#427) Currently the `Weak` type is used only by the NetBSD backend, but in future it may be used by other backends. To simplify code a bit and prepare for potential use on Windows, `Weak` now accepts a "pointer initialization function" instead of a function name, i.e. it now works similarly to `LazyUsize` and `LazyBool`. --- src/lazy.rs | 66 +++++++++++++++++++++++++++++++++++++++++++----- src/lib.rs | 1 + src/netbsd.rs | 21 +++++++++------ src/util_libc.rs | 64 +--------------------------------------------- 4 files changed, 75 insertions(+), 77 deletions(-) diff --git a/src/lazy.rs b/src/lazy.rs index 100ce1eaf..693bb7ff7 100644 --- a/src/lazy.rs +++ b/src/lazy.rs @@ -1,4 +1,8 @@ -use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; +#![allow(dead_code)] +use core::{ + ffi::c_void, + sync::atomic::{AtomicPtr, AtomicUsize, Ordering}, +}; // This structure represents a lazily initialized static usize value. Useful // when it is preferable to just rerun initialization instead of locking. @@ -21,22 +25,22 @@ use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; pub(crate) struct LazyUsize(AtomicUsize); impl LazyUsize { + // The initialization is not completed. + const UNINIT: usize = usize::max_value(); + 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 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. 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); + let mut val = self.0.load(Ordering::Relaxed); if val == Self::UNINIT { val = init(); - self.0.store(val, Relaxed); + self.0.store(val, Ordering::Relaxed); } val } @@ -54,3 +58,53 @@ impl LazyBool { self.0.unsync_init(|| init() as usize) != 0 } } + +// This structure represents a lazily initialized static pointer value. +/// +/// It's intended to be used for weak linking of a C function that may +/// or may not be present at runtime. +/// +/// 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 LazyPtr { + addr: AtomicPtr, +} + +impl LazyPtr { + /// A non-null pointer value which indicates we are uninitialized. + /// + /// This constant should ideally not be a valid pointer. However, + /// if by chance initialization function passed to the `unsync_init` + /// method does return UNINIT, there will not be undefined behavior. + /// The initialization function will just be called each time `get()` + /// is called. This would be inefficient, but correct. + const UNINIT: *mut c_void = !0usize as *mut c_void; + + /// Construct new `LazyPtr` in uninitialized state. + pub const fn new() -> Self { + Self { + addr: AtomicPtr::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. + pub fn unsync_init(&self, init: impl Fn() -> *mut c_void) -> *mut 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 `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. + match self.addr.load(Ordering::Acquire) { + Self::UNINIT => { + let addr = init(); + self.addr.store(addr, Ordering::Release); + addr + } + addr => addr, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index bc3695b6a..eb8c7fc5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -306,6 +306,7 @@ cfg_if! { #[path = "solaris.rs"] mod imp; } else if #[cfg(target_os = "netbsd")] { mod util_libc; + mod lazy; #[path = "netbsd.rs"] mod imp; } else if #[cfg(target_os = "fuchsia")] { #[path = "fuchsia.rs"] mod imp; diff --git a/src/netbsd.rs b/src/netbsd.rs index b8a770f5d..4211a8650 100644 --- a/src/netbsd.rs +++ b/src/netbsd.rs @@ -1,9 +1,6 @@ //! Implementation for NetBSD -use crate::{ - util_libc::{sys_fill_exact, Weak}, - Error, -}; -use core::{mem::MaybeUninit, ptr}; +use crate::{lazy::LazyPtr, util_libc::sys_fill_exact, Error}; +use core::{ffi::c_void, mem::MaybeUninit, ptr}; fn kern_arnd(buf: &mut [MaybeUninit]) -> libc::ssize_t { static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND]; @@ -27,10 +24,18 @@ fn kern_arnd(buf: &mut [MaybeUninit]) -> libc::ssize_t { type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t; +// getrandom(2) was introduced in NetBSD 10.0 +static GETRANDOM: LazyPtr = LazyPtr::new(); + +fn dlsym_getrandom() -> *mut c_void { + static NAME: &[u8] = b"getrandom\0"; + let name_ptr = NAME.as_ptr() as *const libc::c_char; + unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) } +} + pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - // getrandom(2) was introduced in NetBSD 10.0 - static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") }; - if let Some(fptr) = GETRANDOM.ptr() { + let fptr = GETRANDOM.unsync_init(dlsym_getrandom); + if !fptr.is_null() { let func: GetRandomFn = unsafe { core::mem::transmute(fptr) }; return sys_fill_exact(dest, |buf| unsafe { func(buf.as_mut_ptr() as *mut u8, buf.len(), 0) diff --git a/src/util_libc.rs b/src/util_libc.rs index 129362d5d..765d5fd4b 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -1,12 +1,6 @@ #![allow(dead_code)] use crate::Error; -use core::{ - mem::MaybeUninit, - num::NonZeroU32, - ptr::NonNull, - sync::atomic::{fence, AtomicPtr, Ordering}, -}; -use libc::c_void; +use core::{mem::MaybeUninit, num::NonZeroU32}; cfg_if! { if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] { @@ -76,62 +70,6 @@ pub fn sys_fill_exact( 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, -} - -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> { - // 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) - } - } - } -} - // SAFETY: path must be null terminated, FD must be manually closed. pub unsafe fn open_readonly(path: &str) -> Result { debug_assert_eq!(path.as_bytes().last(), Some(&0)); From 13903863c7ec4e466a1fef196e5e616667264437 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Sat, 25 May 2024 19:49:05 -0700 Subject: [PATCH 002/201] Increase MSRV to 1.38 and use `ptr.cast::()` whenever practical to clarify casts. (#425) Avoid anonymous type casts of the form `as *{const,mut} _`. Make it clearer that we're never casting away constness by avoiding `as *mut T` whenever practical. --- .clippy.toml | 2 +- .github/workflows/tests.yml | 2 +- CHANGELOG.md | 7 +++++++ README.md | 2 +- src/apple-other.rs | 2 +- src/error.rs | 2 +- src/fuchsia.rs | 2 +- src/getentropy.rs | 4 ++-- src/getrandom.rs | 4 ++-- src/hermit.rs | 2 +- src/js.rs | 4 ++-- src/netbsd.rs | 6 +++--- src/solaris.rs | 4 ++-- src/solid.rs | 2 +- src/use_file.rs | 3 ++- src/util_libc.rs | 7 +++++-- src/vxworks.rs | 2 +- src/wasi.rs | 2 +- src/windows.rs | 7 ++++--- 19 files changed, 39 insertions(+), 27 deletions(-) diff --git a/.clippy.toml b/.clippy.toml index 992016c29..749c3b58a 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1 +1 @@ -msrv = "1.36" +msrv = "1.38" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 40db0124d..6847a4e7a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,7 +44,7 @@ jobs: strategy: matrix: os: [ubuntu-22.04, windows-2022] - toolchain: [nightly, beta, stable, 1.36] + toolchain: [nightly, beta, stable, 1.38] # Only Test macOS on stable to reduce macOS CI jobs include: # x86_64-apple-darwin. diff --git a/CHANGELOG.md b/CHANGELOG.md index b6763b58f..d32a369e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Breaking Changes +- Update MSRV to 1.38 [#425] + +[#425]: https://github.com/rust-random/getrandom/pull/425 + ## [0.2.15] - 2024-05-06 ### Added - Apple visionOS support [#410] diff --git a/README.md b/README.md index b4b5a2b56..fcebbafa0 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ crate features, WASM support and Custom RNGs see the ## Minimum Supported Rust Version -This crate requires Rust 1.36.0 or later. +This crate requires Rust 1.38.0 or later. ## Platform Support diff --git a/src/apple-other.rs b/src/apple-other.rs index 167d8cf0f..e54b4cb27 100644 --- a/src/apple-other.rs +++ b/src/apple-other.rs @@ -14,7 +14,7 @@ extern "C" { } pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - let ret = unsafe { CCRandomGenerateBytes(dest.as_mut_ptr() as *mut c_void, dest.len()) }; + let ret = unsafe { CCRandomGenerateBytes(dest.as_mut_ptr().cast::(), dest.len()) }; // kCCSuccess (from CommonCryptoError.h) is always zero. if ret != 0 { Err(Error::IOS_SEC_RANDOM) diff --git a/src/error.rs b/src/error.rs index 13c81c7af..5dc451103 100644 --- a/src/error.rs +++ b/src/error.rs @@ -99,7 +99,7 @@ impl Error { 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; + let buf_ptr = buf.as_mut_ptr().cast::(); if unsafe { libc::strerror_r(errno, buf_ptr, buf.len()) } != 0 { return None; } diff --git a/src/fuchsia.rs b/src/fuchsia.rs index 11970685c..22ae77961 100644 --- a/src/fuchsia.rs +++ b/src/fuchsia.rs @@ -8,6 +8,6 @@ extern "C" { } pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - unsafe { zx_cprng_draw(dest.as_mut_ptr() as *mut u8, dest.len()) } + unsafe { zx_cprng_draw(dest.as_mut_ptr().cast::(), dest.len()) } Ok(()) } diff --git a/src/getentropy.rs b/src/getentropy.rs index 41bab8fe9..eee47403d 100644 --- a/src/getentropy.rs +++ b/src/getentropy.rs @@ -8,11 +8,11 @@ //! //! For these targets, we use getentropy(2) because getrandom(2) doesn't exist. use crate::{util_libc::last_os_error, Error}; -use core::mem::MaybeUninit; +use core::{ffi::c_void, mem::MaybeUninit}; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { for chunk in dest.chunks_mut(256) { - let ret = unsafe { libc::getentropy(chunk.as_mut_ptr() as *mut libc::c_void, chunk.len()) }; + let ret = unsafe { libc::getentropy(chunk.as_mut_ptr().cast::(), chunk.len()) }; if ret != 0 { return Err(last_os_error()); } diff --git a/src/getrandom.rs b/src/getrandom.rs index bc5836530..88c077c6d 100644 --- a/src/getrandom.rs +++ b/src/getrandom.rs @@ -16,10 +16,10 @@ //! nothing. On illumos, the default pool is used to implement getentropy(2), //! so we assume it is acceptable here. use crate::{util_libc::sys_fill_exact, Error}; -use core::mem::MaybeUninit; +use core::{ffi::c_void, mem::MaybeUninit}; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { sys_fill_exact(dest, |buf| unsafe { - libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0) + libc::getrandom(buf.as_mut_ptr().cast::(), buf.len(), 0) }) } diff --git a/src/hermit.rs b/src/hermit.rs index c4f619417..d797f74af 100644 --- a/src/hermit.rs +++ b/src/hermit.rs @@ -13,7 +13,7 @@ extern "C" { pub fn getrandom_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { while !dest.is_empty() { - let res = unsafe { sys_read_entropy(dest.as_mut_ptr() as *mut u8, dest.len(), 0) }; + let res = unsafe { sys_read_entropy(dest.as_mut_ptr().cast::(), dest.len(), 0) }; // Positive `isize`s can be safely casted to `usize` if res > 0 && (res as usize) <= dest.len() { dest = &mut dest[res as usize..]; diff --git a/src/js.rs b/src/js.rs index e5428f50d..bec31ee5a 100644 --- a/src/js.rs +++ b/src/js.rs @@ -40,7 +40,7 @@ pub(crate) fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> // have a notion of "uninitialized memory", this is purely // a Rust/C/C++ concept. let res = n.random_fill_sync(unsafe { - Uint8Array::view_mut_raw(chunk.as_mut_ptr() as *mut u8, chunk.len()) + Uint8Array::view_mut_raw(chunk.as_mut_ptr().cast::(), chunk.len()) }); if res.is_err() { return Err(Error::NODE_RANDOM_FILL_SYNC); @@ -60,7 +60,7 @@ pub(crate) fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> } // SAFETY: `sub_buf`'s length is the same length as `chunk` - unsafe { sub_buf.raw_copy_to_ptr(chunk.as_mut_ptr() as *mut u8) }; + unsafe { sub_buf.raw_copy_to_ptr(chunk.as_mut_ptr().cast::()) }; } } }; diff --git a/src/netbsd.rs b/src/netbsd.rs index 4211a8650..c4ea75e4d 100644 --- a/src/netbsd.rs +++ b/src/netbsd.rs @@ -9,7 +9,7 @@ fn kern_arnd(buf: &mut [MaybeUninit]) -> libc::ssize_t { libc::sysctl( MIB.as_ptr(), MIB.len() as libc::c_uint, - buf.as_mut_ptr() as *mut _, + buf.as_mut_ptr().cast::(), &mut len, ptr::null(), 0, @@ -29,7 +29,7 @@ static GETRANDOM: LazyPtr = LazyPtr::new(); fn dlsym_getrandom() -> *mut c_void { static NAME: &[u8] = b"getrandom\0"; - let name_ptr = NAME.as_ptr() as *const libc::c_char; + let name_ptr = NAME.as_ptr().cast::(); unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) } } @@ -38,7 +38,7 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { if !fptr.is_null() { let func: GetRandomFn = unsafe { core::mem::transmute(fptr) }; return sys_fill_exact(dest, |buf| unsafe { - func(buf.as_mut_ptr() as *mut u8, buf.len(), 0) + func(buf.as_mut_ptr().cast::(), buf.len(), 0) }); } diff --git a/src/solaris.rs b/src/solaris.rs index 8a3401e0f..c96ae2a32 100644 --- a/src/solaris.rs +++ b/src/solaris.rs @@ -13,13 +13,13 @@ //! 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::{util_libc::last_os_error, Error}; -use core::mem::MaybeUninit; +use core::{ffi::c_void, mem::MaybeUninit}; const MAX_BYTES: usize = 1024; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { for chunk in dest.chunks_mut(MAX_BYTES) { - let ptr = chunk.as_mut_ptr() as *mut libc::c_void; + let ptr = chunk.as_mut_ptr().cast::(); 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 ret <= 0 { diff --git a/src/solid.rs b/src/solid.rs index cae8caf66..56a47eeba 100644 --- a/src/solid.rs +++ b/src/solid.rs @@ -7,7 +7,7 @@ extern "C" { } pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - let ret = unsafe { SOLID_RNG_SampleRandomBytes(dest.as_mut_ptr() as *mut u8, dest.len()) }; + let ret = unsafe { SOLID_RNG_SampleRandomBytes(dest.as_mut_ptr().cast::(), dest.len()) }; if ret >= 0 { Ok(()) } else { diff --git a/src/use_file.rs b/src/use_file.rs index bd643ae5a..d2fe244f2 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -5,6 +5,7 @@ use crate::{ }; use core::{ cell::UnsafeCell, + ffi::c_void, mem::MaybeUninit, sync::atomic::{AtomicUsize, Ordering::Relaxed}, }; @@ -21,7 +22,7 @@ const FD_UNINIT: usize = usize::max_value(); pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let fd = get_rng_fd()?; sys_fill_exact(dest, |buf| unsafe { - libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len()) + libc::read(fd, buf.as_mut_ptr().cast::(), buf.len()) }) } diff --git a/src/util_libc.rs b/src/util_libc.rs index 765d5fd4b..1d6bf9a2c 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -74,7 +74,10 @@ pub fn sys_fill_exact( pub unsafe fn open_readonly(path: &str) -> Result { debug_assert_eq!(path.as_bytes().last(), Some(&0)); loop { - let fd = libc::open(path.as_ptr() as *const _, libc::O_RDONLY | libc::O_CLOEXEC); + let fd = libc::open( + path.as_ptr().cast::(), + libc::O_RDONLY | libc::O_CLOEXEC, + ); if fd >= 0 { return Ok(fd); } @@ -92,7 +95,7 @@ pub fn getrandom_syscall(buf: &mut [MaybeUninit]) -> libc::ssize_t { unsafe { libc::syscall( libc::SYS_getrandom, - buf.as_mut_ptr() as *mut libc::c_void, + buf.as_mut_ptr().cast::(), buf.len(), 0, ) as libc::ssize_t diff --git a/src/vxworks.rs b/src/vxworks.rs index 7ca9d6bfd..5c75847b3 100644 --- a/src/vxworks.rs +++ b/src/vxworks.rs @@ -20,7 +20,7 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // Prevent overflow of i32 for chunk in dest.chunks_mut(i32::max_value() as usize) { - let ret = unsafe { libc::randABytes(chunk.as_mut_ptr() as *mut u8, chunk.len() as i32) }; + let ret = unsafe { libc::randABytes(chunk.as_mut_ptr().cast::(), chunk.len() as i32) }; if ret != 0 { return Err(last_os_error()); } diff --git a/src/wasi.rs b/src/wasi.rs index d6c8a912c..a5b23070b 100644 --- a/src/wasi.rs +++ b/src/wasi.rs @@ -7,7 +7,7 @@ use core::{ use wasi::random_get; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - unsafe { random_get(dest.as_mut_ptr() as *mut u8, dest.len()) }.map_err(|e| { + unsafe { random_get(dest.as_mut_ptr().cast::(), dest.len()) }.map_err(|e| { // The WASI errno will always be non-zero, but we check just in case. match NonZeroU16::new(e.raw()) { Some(r) => Error::from(NonZeroU32::from(r)), diff --git a/src/windows.rs b/src/windows.rs index 2d1c48351..0aa8dde2d 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -29,7 +29,7 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let ret = unsafe { BCryptGenRandom( ptr::null_mut(), - chunk.as_mut_ptr() as *mut u8, + chunk.as_mut_ptr().cast::(), chunk.len() as u32, BCRYPT_USE_SYSTEM_PREFERRED_RNG, ) @@ -39,8 +39,9 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // Failed. Try RtlGenRandom as a fallback. #[cfg(not(target_vendor = "uwp"))] { - let ret = - unsafe { RtlGenRandom(chunk.as_mut_ptr() as *mut c_void, chunk.len() as u32) }; + let ret = unsafe { + RtlGenRandom(chunk.as_mut_ptr().cast::(), chunk.len() as u32) + }; if ret != 0 { continue; } From 0afee65d7d200c6d3e4271b054f9482802add4ad Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Tue, 28 May 2024 19:54:02 -0700 Subject: [PATCH 003/201] Clarify safety properties of casts between `[MaybeUninit]` <-> `[T]`. (#431) Reduce the scope of the `unsafe` blocks to the unsafe operations. --- src/util.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/util.rs b/src/util.rs index 1c4e70ba4..9eeba9a7f 100644 --- a/src/util.rs +++ b/src/util.rs @@ -5,9 +5,11 @@ use core::{mem::MaybeUninit, ptr}; /// `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(slice: &mut [MaybeUninit]) -> &mut [T] { + let ptr = ptr_from_mut::<[MaybeUninit]>(slice) as *mut [T]; // SAFETY: `MaybeUninit` is guaranteed to be layout-compatible with `T`. - &mut *(slice as *mut [MaybeUninit] as *mut [T]) + unsafe { &mut *ptr } } #[inline] @@ -18,10 +20,9 @@ pub fn uninit_slice_fill_zero(slice: &mut [MaybeUninit]) -> &mut [u8] { #[inline(always)] pub fn slice_as_uninit(slice: &[T]) -> &[MaybeUninit] { + let ptr = ptr_from_ref::<[T]>(slice) as *const [MaybeUninit]; // SAFETY: `MaybeUninit` is guaranteed to be layout-compatible with `T`. - // There is no risk of writing a `MaybeUninit` into the result since - // the result isn't mutable. - unsafe { &*(slice as *const [T] as *const [MaybeUninit]) } + unsafe { &*ptr } } /// View an mutable initialized array as potentially-uninitialized. @@ -29,7 +30,19 @@ pub fn slice_as_uninit(slice: &[T]) -> &[MaybeUninit] { /// 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(slice: &mut [T]) -> &mut [MaybeUninit] { + let ptr = ptr_from_mut::<[T]>(slice) as *mut [MaybeUninit]; // SAFETY: `MaybeUninit` is guaranteed to be layout-compatible with `T`. - &mut *(slice as *mut [T] as *mut [MaybeUninit]) + unsafe { &mut *ptr } +} + +// TODO: MSRV(1.76.0): Replace with `core::ptr::from_mut`. +fn ptr_from_mut(r: &mut T) -> *mut T { + r +} + +// TODO: MSRV(1.76.0): Replace with `core::ptr::from_ref`. +fn ptr_from_ref(r: &T) -> *const T { + r } From 875081b66da2c91cefe0fe2c099116a94caed754 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 28 May 2024 21:19:54 -0700 Subject: [PATCH 004/201] Use ProcessPrng on Windows (#415) Use [`ProcessPrng`](https://learn.microsoft.com/en-us/windows/win32/seccng/processprng) on Windows 10 and up, and use [`RtlGenRandom`](https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) on older legacy Windows versions. Don't use [`BCryptGenRandom`](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom) due to stability issues. --------- Signed-off-by: Joe Richey --- .github/workflows/tests.yml | 16 ++++++- Cargo.toml | 4 ++ README.md | 2 +- src/error.rs | 3 ++ src/lib.rs | 8 +++- src/windows.rs | 86 ++++++++++++++----------------------- src/windows7.rs | 34 +++++++++++++++ 7 files changed, 95 insertions(+), 58 deletions(-) create mode 100644 src/windows7.rs diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6847a4e7a..53ebd05e0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,7 +44,7 @@ jobs: strategy: matrix: os: [ubuntu-22.04, windows-2022] - toolchain: [nightly, beta, stable, 1.38] + toolchain: [nightly, beta, stable, 1.56] # Only Test macOS on stable to reduce macOS CI jobs include: # x86_64-apple-darwin. @@ -159,6 +159,20 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: cargo test --features=std + windows7: + name: Test Windows 7 impl on Windows 10 + runs-on: windows-2022 + steps: + - uses: actions/checkout@v3 + # Win7 targets are Tier3, so pin a nightly where libstd builds. + - uses: dtolnay/rust-toolchain@master + with: + toolchain: nightly-2024-05-20 + components: rust-src + - uses: Swatinem/rust-cache@v2 + - run: cargo test --target=x86_64-win7-windows-msvc -Z build-std --features=std + - run: cargo test --target=i686-win7-windows-msvc -Z build-std --features=std + cross-tests: name: Cross Test runs-on: ubuntu-22.04 diff --git a/Cargo.toml b/Cargo.toml index 4de6dcfd6..d7e65bfaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "getrandom" version = "0.2.15" # Also update html_root_url in lib.rs when bumping this edition = "2018" +rust-version = "1.56" authors = ["The Rand Project Developers"] license = "MIT OR Apache-2.0" description = "A small cross-platform library for retrieving random data from system source" @@ -23,6 +24,9 @@ libc = { version = "0.2.154", default-features = false } [target.'cfg(target_os = "wasi")'.dependencies] wasi = { version = "0.11", default-features = false } +[target.'cfg(all(windows, not(target_vendor = "win7")))'.dependencies] +windows-targets = "0.52" + [target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies] wasm-bindgen = { version = "0.2.62", default-features = false, optional = true } js-sys = { version = "0.3", optional = true } diff --git a/README.md b/README.md index fcebbafa0..2ca14a666 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ crate features, WASM support and Custom RNGs see the ## Minimum Supported Rust Version -This crate requires Rust 1.38.0 or later. +This crate requires Rust 1.56.0 or later. ## Platform Support diff --git a/src/error.rs b/src/error.rs index 5dc451103..3ba4ff6c1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -53,6 +53,8 @@ impl Error { /// Called from an ES module on Node.js. This is unsupported, see: /// . pub const NODE_ES_MODULE: Error = internal_error(14); + /// Calling Windows ProcessPrng failed. + pub const WINDOWS_PROCESS_PRNG: Error = internal_error(15); /// Codes below this point represent OS Errors (i.e. positive i32 values). /// Codes at or above this point, but below [`Error::CUSTOM_START`] are @@ -172,6 +174,7 @@ fn internal_desc(error: Error) -> Option<&'static str> { Error::NODE_CRYPTO => Some("Node.js crypto CommonJS module is unavailable"), Error::NODE_RANDOM_FILL_SYNC => Some("Calling Node.js API crypto.randomFillSync failed"), Error::NODE_ES_MODULE => Some("Node.js ES modules are not directly supported, see https://docs.rs/getrandom#nodejs-es-module-support"), + Error::WINDOWS_PROCESS_PRNG => Some("ProcessPrng: Windows system function failure"), _ => None, } } diff --git a/src/lib.rs b/src/lib.rs index eb8c7fc5a..e4f110069 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,8 @@ //! | 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`] +//! | Windows 10+ | `*‑windows‑*` | [`ProcessPrng`] +//! | Windows 7 and 8 | `*-win7‑windows‑*` | [`RtlGenRandom`] //! | macOS | `*‑apple‑darwin` | [`getentropy`][3] //! | iOS, tvOS, watchOS | `*‑apple‑ios`, `*-apple-tvos`, `*-apple-watchos` | [`CCRandomGenerateBytes`] //! | FreeBSD | `*‑freebsd` | [`getrandom`][5] @@ -182,7 +183,8 @@ //! [17]: https://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getrandom //! [18]: https://github.com/rust3ds/shim-3ds/commit/b01d2568836dea2a65d05d662f8e5f805c64389d //! -//! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom +//! [`ProcessPrng`]: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng +//! [`RtlGenRandom`]: https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom //! [`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 //! [`CCRandomGenerateBytes`]: https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html @@ -323,6 +325,8 @@ cfg_if! { #[path = "solid.rs"] mod imp; } else if #[cfg(target_os = "espidf")] { #[path = "espidf.rs"] mod imp; + } else if #[cfg(all(windows, target_vendor = "win7"))] { + #[path = "windows7.rs"] mod imp; } else if #[cfg(windows)] { #[path = "windows.rs"] mod imp; } else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] { diff --git a/src/windows.rs b/src/windows.rs index 0aa8dde2d..e28c1e533 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,60 +1,38 @@ -//! Implementation for Windows +//! Implementation for Windows 10 and later +//! +//! On Windows 10 and later, ProcessPrng "is the primary interface to the +//! user-mode per-processer 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::{ffi::c_void, mem::MaybeUninit, num::NonZeroU32, ptr}; +use core::mem::MaybeUninit; -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; -} - -// Forbidden when targetting UWP -#[cfg(not(target_vendor = "uwp"))] -#[link(name = "advapi32")] -extern "system" { - #[link_name = "SystemFunction036"] - fn RtlGenRandom(RandomBuffer: *mut c_void, RandomBufferLength: u32) -> u8; -} +// Binding to the Windows.Win32.Security.Cryptography.ProcessPrng API. As +// bcryptprimitives.dll lacks an import library, we use the windows-targets +// crate to link to it. +windows_targets::link!("bcryptprimitives.dll" "system" fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL); +pub type BOOL = i32; +pub const TRUE: BOOL = 1i32; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> 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().cast::(), - chunk.len() as u32, - BCRYPT_USE_SYSTEM_PREFERRED_RNG, - ) - }; - // NTSTATUS codes use the two highest bits for severity status. - if ret >> 30 == 0b11 { - // Failed. Try RtlGenRandom as a fallback. - #[cfg(not(target_vendor = "uwp"))] - { - let ret = unsafe { - RtlGenRandom(chunk.as_mut_ptr().cast::(), chunk.len() as u32) - }; - if ret != 0 { - continue; - } - } - // 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)); - } + // ProcessPrng should always return TRUE, but we check just in case. + match unsafe { ProcessPrng(dest.as_mut_ptr().cast::(), dest.len()) } { + TRUE => Ok(()), + _ => Err(Error::WINDOWS_PROCESS_PRNG), } - Ok(()) } diff --git a/src/windows7.rs b/src/windows7.rs new file mode 100644 index 000000000..72f5695d8 --- /dev/null +++ b/src/windows7.rs @@ -0,0 +1,34 @@ +//! 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}; + +// 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; +} +type BOOLEAN = u8; +const TRUE: BOOLEAN = 1u8; + +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { + // Prevent overflow of u32 + for chunk in dest.chunks_mut(u32::max_value() as usize) { + let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr().cast::(), chunk.len() as u32) }; + if ret != TRUE { + return Err(Error::WINDOWS_RTL_GEN_RANDOM); + } + } + Ok(()) +} From 0afdaf1346893038ce48a9fbf44c2fac869b5446 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 29 May 2024 15:29:43 +0300 Subject: [PATCH 005/201] Tweak `util_libc::open_readonly` (#434) `open_readonly` now accepts `&[u8]` instead of `&str` for path and asserts that it contains at least one zero byte. This allows to make the function safe. The compiler should be able to remove the assert since we use static paths. --- src/use_file.rs | 6 +++--- src/util_libc.rs | 22 +++++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/use_file.rs b/src/use_file.rs index d2fe244f2..9167445eb 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -16,7 +16,7 @@ use core::{ /// - 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: &str = "/dev/urandom\0"; +const FILE_PATH: &[u8] = b"/dev/urandom\0"; const FD_UNINIT: usize = usize::max_value(); pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { @@ -57,7 +57,7 @@ fn get_rng_fd() -> Result { #[cfg(any(target_os = "android", target_os = "linux"))] wait_until_rng_ready()?; - let fd = unsafe { open_readonly(FILE_PATH)? }; + let fd = open_readonly(FILE_PATH)?; // The fd always fits in a usize without conflicting with FD_UNINIT. debug_assert!(fd >= 0 && (fd as usize) < FD_UNINIT); FD.store(fd as usize, Relaxed); @@ -69,7 +69,7 @@ fn get_rng_fd() -> Result { #[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 fd = open_readonly(b"/dev/random\0")?; let mut pfd = libc::pollfd { fd, events: libc::POLLIN, diff --git a/src/util_libc.rs b/src/util_libc.rs index 1d6bf9a2c..add966dea 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -70,14 +70,22 @@ pub fn sys_fill_exact( Ok(()) } -// SAFETY: path must be null terminated, FD must be manually closed. -pub unsafe fn open_readonly(path: &str) -> Result { - debug_assert_eq!(path.as_bytes().last(), Some(&0)); +/// 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 +#[inline(always)] +pub fn open_readonly(path: &[u8]) -> Result { + assert!(path.iter().any(|&b| b == 0)); loop { - let fd = libc::open( - path.as_ptr().cast::(), - libc::O_RDONLY | libc::O_CLOEXEC, - ); + let fd = unsafe { + libc::open( + path.as_ptr().cast::(), + libc::O_RDONLY | libc::O_CLOEXEC, + ) + }; if fd >= 0 { return Ok(fd); } From 867392a58d58da7f32c1c9f553a0107ddfa67444 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Wed, 29 May 2024 13:33:05 -0700 Subject: [PATCH 006/201] Update MSRV in .clippy.toml and silence new Windows warnings. (#436) --- .clippy.toml | 2 +- src/windows.rs | 1 + src/windows7.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.clippy.toml b/.clippy.toml index 749c3b58a..62ca74234 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1 +1 @@ -msrv = "1.38" +msrv = "1.56" diff --git a/src/windows.rs b/src/windows.rs index e28c1e533..e0e8049ef 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -26,6 +26,7 @@ use core::mem::MaybeUninit; // bcryptprimitives.dll lacks an import library, we use the windows-targets // crate to link to it. windows_targets::link!("bcryptprimitives.dll" "system" fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL); +#[allow(clippy::upper_case_acronyms)] pub type BOOL = i32; pub const TRUE: BOOL = 1i32; diff --git a/src/windows7.rs b/src/windows7.rs index 72f5695d8..df83c5e6b 100644 --- a/src/windows7.rs +++ b/src/windows7.rs @@ -19,6 +19,7 @@ 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; From f8899bdb6e0d94d2930f8706a960d57db277b4c8 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Fri, 31 May 2024 09:19:32 -0700 Subject: [PATCH 007/201] Replace more type casts with non-cast equivalents (#437) --- .clippy.toml | 2 +- .github/workflows/tests.yml | 2 +- Cargo.toml | 4 ++-- README.md | 2 +- benches/buffer.rs | 2 +- src/hermit.rs | 15 +++++++-------- src/lazy.rs | 2 +- src/solid.rs | 2 +- src/util_libc.rs | 15 +++++++++------ 9 files changed, 24 insertions(+), 22 deletions(-) diff --git a/.clippy.toml b/.clippy.toml index 62ca74234..5cccb362c 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1 +1 @@ -msrv = "1.56" +msrv = "1.57" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 53ebd05e0..f3831d5ca 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,7 +44,7 @@ jobs: strategy: matrix: os: [ubuntu-22.04, windows-2022] - toolchain: [nightly, beta, stable, 1.56] + toolchain: [nightly, beta, stable, 1.57] # Only Test macOS on stable to reduce macOS CI jobs include: # x86_64-apple-darwin. diff --git a/Cargo.toml b/Cargo.toml index d7e65bfaf..b9357bcef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "getrandom" version = "0.2.15" # Also update html_root_url in lib.rs when bumping this -edition = "2018" -rust-version = "1.56" +edition = "2021" +rust-version = "1.57" # Sync .clippy.toml, tests.yml, and README.md. authors = ["The Rand Project Developers"] license = "MIT OR Apache-2.0" description = "A small cross-platform library for retrieving random data from system source" diff --git a/README.md b/README.md index 2ca14a666..56af89dd2 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ crate features, WASM support and Custom RNGs see the ## Minimum Supported Rust Version -This crate requires Rust 1.56.0 or later. +This crate requires Rust 1.57.0 or later. ## Platform Support diff --git a/benches/buffer.rs b/benches/buffer.rs index b32be4336..303bc3e47 100644 --- a/benches/buffer.rs +++ b/benches/buffer.rs @@ -8,7 +8,7 @@ use std::mem::MaybeUninit; fn bench_getrandom() { let mut buf = [0u8; N]; getrandom::getrandom(&mut buf).unwrap(); - test::black_box(&buf as &[u8]); + test::black_box(&buf[..]); } // Call getrandom_uninit on an uninitialized stack buffer diff --git a/src/hermit.rs b/src/hermit.rs index d797f74af..056e1b147 100644 --- a/src/hermit.rs +++ b/src/hermit.rs @@ -2,11 +2,6 @@ use crate::Error; use core::{mem::MaybeUninit, num::NonZeroU32}; -/// Minimum return value which we should get from syscalls in practice, -/// because Hermit uses positive `i32`s for error codes: -/// https://github.com/hermitcore/libhermit-rs/blob/main/src/errno.rs -const MIN_RET_CODE: isize = -(i32::MAX as isize); - extern "C" { fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize; } @@ -18,9 +13,13 @@ pub fn getrandom_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { if res > 0 && (res as usize) <= dest.len() { dest = &mut dest[res as usize..]; } else { - let err = match res { - MIN_RET_CODE..=-1 => NonZeroU32::new(-res as u32).unwrap().into(), - _ => Error::UNEXPECTED, + let err = if res < 0 { + u32::try_from(res.unsigned_abs()) + .ok() + .and_then(NonZeroU32::new) + .map_or(Error::UNEXPECTED, Error::from) + } else { + Error::UNEXPECTED }; return Err(err); } diff --git a/src/lazy.rs b/src/lazy.rs index 693bb7ff7..ca65bb7f1 100644 --- a/src/lazy.rs +++ b/src/lazy.rs @@ -55,7 +55,7 @@ impl LazyBool { } pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool { - self.0.unsync_init(|| init() as usize) != 0 + self.0.unsync_init(|| usize::from(init())) != 0 } } diff --git a/src/solid.rs b/src/solid.rs index 56a47eeba..f31813137 100644 --- a/src/solid.rs +++ b/src/solid.rs @@ -13,6 +13,6 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { } 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()) + Err(NonZeroU32::new(ret.unsigned_abs()).map_or(Error::UNEXPECTED, Error::from)) } } diff --git a/src/util_libc.rs b/src/util_libc.rs index add966dea..2ec7ff358 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -35,12 +35,15 @@ cfg_if! { } 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 - } + let errno: libc::c_int = unsafe { get_errno() }; + + // c_int-to-u32 conversion is lossless for nonnegative values if they are the same size. + const _: () = assert!(core::mem::size_of::() == core::mem::size_of::()); + + u32::try_from(errno) + .ok() + .and_then(NonZeroU32::new) + .map_or(Error::ERRNO_NOT_POSITIVE, Error::from) } // Fill a buffer by repeatedly invoking a system call. The `sys_fill` function: From b2bca0f6acbf4fb8c2fd7e7ebd30b2826fd95f5e Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Fri, 31 May 2024 11:13:38 -0700 Subject: [PATCH 008/201] rdrand: Avoid assuming `usize` is the native word size. (#442) `x86_64-unknown-linux-gnux32` has target_pointer_width = "32", so usize is 32-bits. In this case, we were throwing away half of each RDRAND result and doing twice as many RDRAND invocations as necessary. This wasn't noticed because `as` silently does a lossy conversion. --- src/rdrand.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/rdrand.rs b/src/rdrand.rs index f527c8c64..f4c593bdf 100644 --- a/src/rdrand.rs +++ b/src/rdrand.rs @@ -6,9 +6,11 @@ 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; } } @@ -18,11 +20,11 @@ cfg_if! { const RETRY_LIMIT: usize = 10; #[target_feature(enable = "rdrand")] -unsafe fn rdrand() -> Option { +unsafe fn rdrand() -> Option { for _ in 0..RETRY_LIMIT { let mut val = 0; if rdrand_step(&mut val) == 1 { - return Some(val as usize); + return Some(val); } } None @@ -105,7 +107,7 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { unsafe fn rdrand_exact(dest: &mut [MaybeUninit]) -> 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::()); + let mut chunks = dest.chunks_exact_mut(size_of::()); for chunk in chunks.by_ref() { let src = rdrand()?.to_ne_bytes(); chunk.copy_from_slice(slice_as_uninit(&src)); From 40e873d5fcc244d3b27c7146e8a8cf29d28a8eb2 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Fri, 31 May 2024 15:43:20 -0700 Subject: [PATCH 009/201] Remove use of locale-specific `strerror_r` (#440) strerror_r doesn't necessarily return UTF-8 but we assume it does. strerror_r is locale-sensitive but we are better off not being locale-sensitive. strerror_r requires us to use libc but increasingly we want to avoid libc, e.g. to support x86_64-unknown-linux-none. Just remove the use of the function. --- src/error.rs | 39 +++++++++++---------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/src/error.rs b/src/error.rs index 3ba4ff6c1..20892ec59 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "std")] +extern crate std; + use core::{fmt, num::NonZeroU32}; /// A small and `no_std` compatible error type @@ -98,35 +101,13 @@ impl Error { } } -cfg_if! { - if #[cfg(unix)] { - fn os_err(errno: i32, buf: &mut [u8]) -> Option<&str> { - let buf_ptr = buf.as_mut_ptr().cast::(); - 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); - } + #[cfg(feature = "std")] + dbg.field("description", &std::io::Error::from_raw_os_error(errno)); } else if let Some(desc) = internal_desc(*self) { dbg.field("internal_code", &self.0.get()); dbg.field("description", &desc); @@ -140,10 +121,12 @@ impl fmt::Debug for Error { 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), + 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) = internal_desc(*self) { f.write_str(desc) From c1e0d310a9a77ff0c37a5b3b44a543b86e6da874 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Sun, 2 Jun 2024 14:09:02 -0700 Subject: [PATCH 010/201] Solaris: Do not read from errno when libc did not indicate error (#448) errno is only guaranteed to be set correctly when the function's return value indicates that the function failed. Handle the case where an unexpected negative result is returned separately from the case where the function failed. --- src/solaris.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/solaris.rs b/src/solaris.rs index c96ae2a32..203000b01 100644 --- a/src/solaris.rs +++ b/src/solaris.rs @@ -22,12 +22,11 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let ptr = chunk.as_mut_ptr().cast::(); 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 ret <= 0 { - return Err(last_os_error()); - } // If getrandom(2) succeeds, it should have completely filled chunk. - if (ret as usize) != chunk.len() { - return Err(Error::UNEXPECTED); + match usize::try_from(ret) { + Ok(ret) if ret == chunk.len() => {} // Good. Keep going. + Ok(0) => return Err(last_os_error()), // The syscall failed. + _ => return Err(Error::UNEXPECTED), } } Ok(()) From a4b1f2f5697e5f57830ff8766e8cff4efa17daeb Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Tue, 4 Jun 2024 10:48:22 -0700 Subject: [PATCH 011/201] Linux/Android: Document /dev/random polling considerations. (#452) See the added comment for details. --- src/use_file.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/use_file.rs b/src/use_file.rs index 9167445eb..508499b18 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -65,10 +65,36 @@ fn get_rng_fd() -> Result { Ok(fd) } -// Succeeds once /dev/urandom is safe to read from +// 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. #[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 = open_readonly(b"/dev/random\0")?; let mut pfd = libc::pollfd { fd, From 8933c05a6e5af10405d444d64f4594d5850553cc Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Tue, 4 Jun 2024 15:40:24 -0700 Subject: [PATCH 012/201] Help the compiler avoid inlining lazy init functions (#443) Before this change, the compiler generates code that looks like this: ``` if not initialized: goto init do_work: do the actual work goto exit init: inilned init() goto do_work exit: ret ``` If the initialization code is small, this works fine. But, for (bad) reasons, is_rdrand_good is particularly huge. Thus, jumping over its inined code is wasteful because it puts bad pressure on the instruction cache. With this change, the generated code looks like this: ``` if not initialized: goto init do_work: do the actual work goto exit init: call init() goto do_work exit: ret ``` I verified these claims by running: ``` $ cargo asm --rust getrandom_inner --lib --target=x86_64-fortanix-unknown-sgx ``` This is also what other implementations (e.g. OnceCell) do. While here, I made the analogous change to LazyPtr, and rewrote LazyPtr to the same form as LazyUsize. I didn't check the generated code for LazyPtr though. (Why is `is_rdrand_good` huge? The compiler unrolls the 10 iteration retry loop, and then it unrolls the 8 iteration self-test loop, so the result is `rdrand()` is inlined 80 times inside is_rdrand_good. This is something to address separately as it also affects `getrandom_inner` itself.) --- src/lazy.rs | 36 ++++++++++++++++++++++++------------ src/use_file.rs | 49 +++++++++++++++++++++++++++++-------------------- 2 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/lazy.rs b/src/lazy.rs index ca65bb7f1..2b04c61db 100644 --- a/src/lazy.rs +++ b/src/lazy.rs @@ -36,13 +36,20 @@ impl LazyUsize { // 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 { + #[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 mut val = self.0.load(Ordering::Relaxed); - if val == Self::UNINIT { - val = init(); - self.0.store(val, Ordering::Relaxed); + let val = self.0.load(Ordering::Relaxed); + if val != Self::UNINIT { + val + } else { + do_init(self, init) } - val } } @@ -92,19 +99,24 @@ impl LazyPtr { // 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 Fn() -> *mut c_void) -> *mut c_void { + #[cold] + fn do_init(this: &LazyPtr, init: impl Fn() -> *mut c_void) -> *mut c_void { + let addr = init(); + this.addr.store(addr, Ordering::Release); + addr + } + // 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 `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. - match self.addr.load(Ordering::Acquire) { - Self::UNINIT => { - let addr = init(); - self.addr.store(addr, Ordering::Release); - addr - } - addr => addr, + let val = self.addr.load(Ordering::Acquire); + if val != Self::UNINIT { + val + } else { + do_init(self, init) } } } diff --git a/src/use_file.rs b/src/use_file.rs index 508499b18..36210dee9 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -19,6 +19,9 @@ use core::{ const FILE_PATH: &[u8] = b"/dev/urandom\0"; const FD_UNINIT: usize = usize::max_value(); +// Do not inline this when it is the fallback implementation, but don't mark it +// `#[cold]` because it is hot when it is actually used. +#[cfg_attr(any(target_os = "android", target_os = "linux"), inline(never))] pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let fd = get_rng_fd()?; sys_fill_exact(dest, |buf| unsafe { @@ -31,6 +34,7 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // return the same file descriptor. This file descriptor is never closed. fn get_rng_fd() -> Result { static FD: AtomicUsize = AtomicUsize::new(FD_UNINIT); + fn get_fd() -> Option { match FD.load(Relaxed) { FD_UNINIT => None, @@ -38,31 +42,36 @@ fn get_rng_fd() -> Result { } } - // Use double-checked locking to avoid acquiring the lock if possible. - if let Some(fd) = get_fd() { - return Ok(fd); - } + #[cold] + fn get_fd_locked() -> Result { + // 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() }); - // 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); + } - 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()?; - // On Linux, /dev/urandom might return insecure values. - #[cfg(any(target_os = "android", target_os = "linux"))] - wait_until_rng_ready()?; + let fd = open_readonly(FILE_PATH)?; + // The fd always fits in a usize without conflicting with FD_UNINIT. + debug_assert!(fd >= 0 && (fd as usize) < FD_UNINIT); + FD.store(fd as usize, Relaxed); - let fd = open_readonly(FILE_PATH)?; - // The fd always fits in a usize without conflicting with FD_UNINIT. - debug_assert!(fd >= 0 && (fd as usize) < FD_UNINIT); - FD.store(fd as usize, Relaxed); + Ok(fd) + } - Ok(fd) + // Use double-checked locking to avoid acquiring the lock if possible. + if let Some(fd) = get_fd() { + Ok(fd) + } else { + get_fd_locked() + } } // Polls /dev/random to make sure it is ok to read from /dev/urandom. From 05cdf6f52efebeefab625d8ce516e7be92fed3b2 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Tue, 4 Jun 2024 16:30:31 -0700 Subject: [PATCH 013/201] Enforce OS errors are in the allowed range (#441) Avoid the `From` implementation in favor of a constructor that centralizes all the range checking in one place. Besides being more consistent in the range checking, this also reduces the boilerplate in callers, which makes it easier to maintain the ports to less-common operating systems. --- src/error.rs | 17 +++++++++++++++++ src/hermit.rs | 5 ++--- src/solid.rs | 4 ++-- src/util_libc.rs | 10 +++++----- src/wasi.rs | 14 +++----------- 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/error.rs b/src/error.rs index 20892ec59..5eff99eb7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -68,6 +68,23 @@ impl Error { /// custom errors. pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30); + /// Creates a new instance of an `Error` from a particular OS error code. + /// + /// This method is analogous to [`std::io::Error::from_raw_os_error()`][1], + /// except that it works in `no_std` contexts and `code` will be + /// replaced with `Error::UNEXPECTED` if it isn't in the range + /// `1..Error::INTERNAL_START`. Thus, for the result `r`, + /// `r == Self::UNEXPECTED || r.raw_os_error().unsigned_abs() == code`. + /// + /// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.from_raw_os_error + #[allow(dead_code)] + pub(super) fn from_os_error(code: u32) -> Self { + match NonZeroU32::new(code) { + Some(code) if code.get() < Self::INTERNAL_START => Self(code), + _ => 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 diff --git a/src/hermit.rs b/src/hermit.rs index 056e1b147..c869372a7 100644 --- a/src/hermit.rs +++ b/src/hermit.rs @@ -1,6 +1,6 @@ //! Implementation for Hermit use crate::Error; -use core::{mem::MaybeUninit, num::NonZeroU32}; +use core::mem::MaybeUninit; extern "C" { fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize; @@ -16,8 +16,7 @@ pub fn getrandom_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { let err = if res < 0 { u32::try_from(res.unsigned_abs()) .ok() - .and_then(NonZeroU32::new) - .map_or(Error::UNEXPECTED, Error::from) + .map_or(Error::UNEXPECTED, Error::from_os_error) } else { Error::UNEXPECTED }; diff --git a/src/solid.rs b/src/solid.rs index f31813137..36f51caab 100644 --- a/src/solid.rs +++ b/src/solid.rs @@ -1,6 +1,6 @@ //! Implementation for SOLID use crate::Error; -use core::{mem::MaybeUninit, num::NonZeroU32}; +use core::mem::MaybeUninit; extern "C" { pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> i32; @@ -13,6 +13,6 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { } 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.unsigned_abs()).map_or(Error::UNEXPECTED, Error::from)) + Err(Error::from_os_error(ret.unsigned_abs())) } } diff --git a/src/util_libc.rs b/src/util_libc.rs index 2ec7ff358..5095cf90c 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] use crate::Error; -use core::{mem::MaybeUninit, num::NonZeroU32}; +use core::mem::MaybeUninit; cfg_if! { if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] { @@ -40,10 +40,10 @@ pub fn last_os_error() -> Error { // c_int-to-u32 conversion is lossless for nonnegative values if they are the same size. const _: () = assert!(core::mem::size_of::() == core::mem::size_of::()); - u32::try_from(errno) - .ok() - .and_then(NonZeroU32::new) - .map_or(Error::ERRNO_NOT_POSITIVE, Error::from) + match u32::try_from(errno) { + Ok(code) if code != 0 => Error::from_os_error(code), + _ => Error::ERRNO_NOT_POSITIVE, + } } // Fill a buffer by repeatedly invoking a system call. The `sys_fill` function: diff --git a/src/wasi.rs b/src/wasi.rs index a5b23070b..10d8ae79b 100644 --- a/src/wasi.rs +++ b/src/wasi.rs @@ -1,17 +1,9 @@ //! Implementation for WASI use crate::Error; -use core::{ - mem::MaybeUninit, - num::{NonZeroU16, NonZeroU32}, -}; +use core::mem::MaybeUninit; use wasi::random_get; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - unsafe { random_get(dest.as_mut_ptr().cast::(), dest.len()) }.map_err(|e| { - // The WASI errno will always be non-zero, but we check just in case. - match NonZeroU16::new(e.raw()) { - Some(r) => Error::from(NonZeroU32::from(r)), - None => Error::ERRNO_NOT_POSITIVE, - } - }) + unsafe { random_get(dest.as_mut_ptr().cast::(), dest.len()) } + .map_err(|e| Error::from_os_error(e.raw().into())) } From 10a0ae044dc00bb4dc81b64847baf420d9c4e991 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 6 Jun 2024 15:11:11 -0700 Subject: [PATCH 014/201] Delegate to `linux_android` from `linux_android_with_fallback` (#459) Instead of duplicating the implementation of `linux_android::getrandom_inner` inline, call `linux_android::getrandom_inner`, like we do for `use_file::getrandom_inner`. This way, there is no doubt that they do exactly the same thing. This then allows us to move `getrandom_syscall` to linux_android, which is where it belongs, since it is Linux/Android-specific. --- src/lib.rs | 1 + src/linux_android.rs | 14 +++++++++++++- src/linux_android_with_fallback.rs | 10 +++------- src/util_libc.rs | 13 ------------- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e4f110069..d1e9ef09d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -299,6 +299,7 @@ cfg_if! { mod util_libc; mod use_file; mod lazy; + mod linux_android; #[path = "linux_android_with_fallback.rs"] mod imp; } else if #[cfg(any(target_os = "android", target_os = "linux"))] { mod util_libc; diff --git a/src/linux_android.rs b/src/linux_android.rs index 93a649452..7c1fede4c 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -3,5 +3,17 @@ use crate::{util_libc, Error}; use core::mem::MaybeUninit; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - util_libc::sys_fill_exact(dest, util_libc::getrandom_syscall) + util_libc::sys_fill_exact(dest, getrandom_syscall) +} + +// Also used by linux_android_with_fallback to check if the syscall is available. +pub fn getrandom_syscall(buf: &mut [MaybeUninit]) -> libc::ssize_t { + unsafe { + libc::syscall( + libc::SYS_getrandom, + buf.as_mut_ptr().cast::(), + buf.len(), + 0, + ) as libc::ssize_t + } } diff --git a/src/linux_android_with_fallback.rs b/src/linux_android_with_fallback.rs index 0f5ea8a99..98fa15e89 100644 --- a/src/linux_android_with_fallback.rs +++ b/src/linux_android_with_fallback.rs @@ -1,23 +1,19 @@ //! Implementation for Linux / Android with `/dev/urandom` fallback -use crate::{ - lazy::LazyBool, - util_libc::{getrandom_syscall, last_os_error, sys_fill_exact}, - {use_file, Error}, -}; +use crate::{lazy::LazyBool, linux_android, use_file, util_libc::last_os_error, Error}; use core::mem::MaybeUninit; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> 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, getrandom_syscall) + linux_android::getrandom_inner(dest) } else { use_file::getrandom_inner(dest) } } fn is_getrandom_available() -> bool { - if getrandom_syscall(&mut []) < 0 { + if linux_android::getrandom_syscall(&mut []) < 0 { match last_os_error().raw_os_error() { Some(libc::ENOSYS) => false, // No kernel support // The fallback on EPERM is intentionally not done on Android since this workaround diff --git a/src/util_libc.rs b/src/util_libc.rs index 5095cf90c..7708bfcc8 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -99,16 +99,3 @@ pub fn open_readonly(path: &[u8]) -> Result { } } } - -/// Thin wrapper around the `getrandom()` Linux system call -#[cfg(any(target_os = "android", target_os = "linux"))] -pub fn getrandom_syscall(buf: &mut [MaybeUninit]) -> libc::ssize_t { - unsafe { - libc::syscall( - libc::SYS_getrandom, - buf.as_mut_ptr().cast::(), - buf.len(), - 0, - ) as libc::ssize_t - } -} From a1ae804e0ceb91e77654bd2acc93f72d0d3c9165 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Fri, 7 Jun 2024 15:30:52 -0700 Subject: [PATCH 015/201] Avoid depending on "rustc-dep-of-std" features of dependencies. (#465) AFAICT, this is not needed. When libstd builds libc, it will activate that feature for it. This makes it easier to make libc a conditional dependency. Do the same for WASI. --- Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b9357bcef..cea1309a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,8 +49,6 @@ custom = [] rustc-dep-of-std = [ "compiler_builtins", "core", - "libc/rustc-dep-of-std", - "wasi/rustc-dep-of-std", ] # Unstable/test-only feature to run wasm-bindgen tests in a browser test-in-browser = [] From 79c29da0d286347b3c6c31025f29426ffb123509 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 7 Jun 2024 15:35:19 -0700 Subject: [PATCH 016/201] Cleanup Auxiliary Linux tests (#466) This PR explictly installs libc and libgcc (to make it clear these are the only extra dev dependancies). I also added building/linking of the x32 target. As noted in #464, this will not run in the current github actions runner due to an incompatible kernel config. Signed-off-by: Joe Richey --- .github/workflows/tests.yml | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f3831d5ca..b40f1c6f9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -71,20 +71,26 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - target: [ - x86_64-unknown-linux-musl, - i686-unknown-linux-gnu, - i686-unknown-linux-musl, - ] + target: [x86_64-unknown-linux-musl, i686-unknown-linux-musl] + include: + - target: i686-unknown-linux-gnu + packages: libc6-dev-i386 lib32gcc-11-dev + - target: x86_64-unknown-linux-gnux32 + packages: libc6-dev-x32 libx32gcc-11-dev + # TODO: Find a Linux image/runner with CONFIG_X86_X32_ABI set + cargo_test_opts: --no-run steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} - - name: Install multilib - run: sudo apt-get update && sudo apt-get install gcc-multilib + - name: Install libc and libgcc + if: matrix.packages + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends ${{ matrix.packages }} - uses: Swatinem/rust-cache@v2 - - run: cargo test --target=${{ matrix.target }} --features=std + - run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std ios-tests: name: iOS Simulator Test From 3174f0caa091a0e02ebef082e114f9754f3a933b Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 11 Jun 2024 19:13:00 -0700 Subject: [PATCH 017/201] MSRV 1.60: Conditionally import lazy.rs module (#472) This simplifies lib.rs and allows for our testing code to be less convoluted. Split out from #471. CC @briansmith The MSRV for rand 0.9 is 1.61 and Debian stable is 1.63, so this is a fine MSRV bump. Signed-off-by: Joe Richey --- .clippy.toml | 2 +- .github/workflows/tests.yml | 2 +- Cargo.toml | 2 +- README.md | 2 +- src/lazy.rs | 2 ++ src/lib.rs | 5 +---- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.clippy.toml b/.clippy.toml index 5cccb362c..13f202e9e 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1 +1 @@ -msrv = "1.57" +msrv = "1.60" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b40f1c6f9..787838545 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,7 +44,7 @@ jobs: strategy: matrix: os: [ubuntu-22.04, windows-2022] - toolchain: [nightly, beta, stable, 1.57] + toolchain: [nightly, beta, stable, "1.60"] # Only Test macOS on stable to reduce macOS CI jobs include: # x86_64-apple-darwin. diff --git a/Cargo.toml b/Cargo.toml index cea1309a4..47c7fd282 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "getrandom" version = "0.2.15" # Also update html_root_url in lib.rs when bumping this edition = "2021" -rust-version = "1.57" # Sync .clippy.toml, tests.yml, and README.md. +rust-version = "1.60" # Sync .clippy.toml, tests.yml, and README.md. authors = ["The Rand Project Developers"] license = "MIT OR Apache-2.0" description = "A small cross-platform library for retrieving random data from system source" diff --git a/README.md b/README.md index 56af89dd2..ef8a6ce25 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ crate features, WASM support and Custom RNGs see the ## Minimum Supported Rust Version -This crate requires Rust 1.57.0 or later. +This crate requires Rust 1.60.0 or later. ## Platform Support diff --git a/src/lazy.rs b/src/lazy.rs index 2b04c61db..10a43d0cb 100644 --- a/src/lazy.rs +++ b/src/lazy.rs @@ -1,3 +1,5 @@ +//! Helpers built around pointer-sized atomics. +#![cfg(target_has_atomic = "ptr")] #![allow(dead_code)] use core::{ ffi::c_void, diff --git a/src/lib.rs b/src/lib.rs index d1e9ef09d..f5e13c360 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -216,6 +216,7 @@ use crate::util::{slice_as_uninit_mut, slice_assume_init_mut}; use core::mem::MaybeUninit; mod error; +mod lazy; 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. @@ -298,7 +299,6 @@ cfg_if! { ))] { mod util_libc; mod use_file; - mod lazy; mod linux_android; #[path = "linux_android_with_fallback.rs"] mod imp; } else if #[cfg(any(target_os = "android", target_os = "linux"))] { @@ -309,7 +309,6 @@ cfg_if! { #[path = "solaris.rs"] mod imp; } else if #[cfg(target_os = "netbsd")] { mod util_libc; - mod lazy; #[path = "netbsd.rs"] mod imp; } else if #[cfg(target_os = "fuchsia")] { #[path = "fuchsia.rs"] mod imp; @@ -331,11 +330,9 @@ cfg_if! { } else if #[cfg(windows)] { #[path = "windows.rs"] mod imp; } else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] { - mod lazy; #[path = "rdrand.rs"] mod imp; } else if #[cfg(all(feature = "rdrand", any(target_arch = "x86_64", target_arch = "x86")))] { - mod lazy; #[path = "rdrand.rs"] mod imp; } else if #[cfg(all(feature = "js", any(target_arch = "wasm32", target_arch = "wasm64"), From b7bba166bc074896ec503552b51069a61924c0c9 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 14 Jun 2024 23:27:50 +0400 Subject: [PATCH 018/201] CI: run Clippy for all backends, rework the rustdoc job (#477) Consolidates Clippy runs into one job which uses fixed Nightly version. Moves Clippy, rustdoc, and rustfmt jobs into a separate workflow file. Additionally, tweaks the rustdoc job to use only rustdoc with `-Dwarnings` flag. Minimal versions job has nothing to do with docs and should be done separately for each target. `cargo deadlinks` was not used to check external links and internal links are checked by rustdoc. --- .github/workflows/tests.yml | 64 +++++----------------- .github/workflows/workspace.yml | 94 +++++++++++++++++++++++++++++++++ src/lazy.rs | 2 +- src/use_file.rs | 2 +- src/vxworks.rs | 19 ++++--- src/windows.rs | 1 + src/windows7.rs | 3 +- 7 files changed, 125 insertions(+), 60 deletions(-) create mode 100644 .github/workflows/workspace.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 787838545..922e8fd40 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,28 +16,6 @@ env: RUSTFLAGS: "-Dwarnings" jobs: - check-doc: - name: Docs, deadlinks, minimal dependencies - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@nightly # Needed for -Z minimal-versions and doc_cfg - - name: Install precompiled cargo-deadlinks - run: | - VERSION=0.8.1 - URL="https://github.com/deadlinks/cargo-deadlinks/releases/download/${VERSION}/cargo-deadlinks-linux" - wget -O ~/.cargo/bin/cargo-deadlinks $URL - chmod +x ~/.cargo/bin/cargo-deadlinks - cargo deadlinks --version - - uses: Swatinem/rust-cache@v2 - - name: Generate Docs - env: - RUSTDOCFLAGS: --cfg docsrs - run: cargo deadlinks -- --features=custom,std - - run: | - cargo generate-lockfile -Z minimal-versions - cargo test --features=custom,std - main-tests: name: Tier 1 Test runs-on: ${{ matrix.os }} @@ -54,7 +32,7 @@ jobs: - os: macos-14 toolchain: stable steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.toolchain }} @@ -80,7 +58,7 @@ jobs: # TODO: Find a Linux image/runner with CONFIG_X86_X32_ABI set cargo_test_opts: --no-run steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} @@ -111,7 +89,7 @@ jobs: target: aarch64-apple-ios-sim ios_platform: auto-ios-aarch64-sim steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} @@ -158,7 +136,7 @@ jobs: stable-i686-msvc, ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.toolchain }} @@ -169,7 +147,7 @@ jobs: name: Test Windows 7 impl on Windows 10 runs-on: windows-2022 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Win7 targets are Tier3, so pin a nightly where libstd builds. - uses: dtolnay/rust-toolchain@master with: @@ -193,7 +171,7 @@ jobs: wasm32-unknown-emscripten, ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install precompiled cross run: | VERSION=v0.2.5 @@ -207,7 +185,7 @@ jobs: name: macOS ARM64 Build/Link runs-on: macos-12 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly with: targets: aarch64-apple-darwin, aarch64-apple-ios @@ -229,7 +207,7 @@ jobs: x86_64-unknown-netbsd, ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install precompiled cross run: | VERSION=v0.2.5 @@ -256,7 +234,7 @@ jobs: host: x86_64-apple-darwin runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - run: choco install wget if: runner.os == 'Windows' @@ -287,7 +265,7 @@ jobs: name: wasm64 Build/Link runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly # Need to build libstd with: components: rust-src @@ -302,7 +280,7 @@ jobs: name: WASI Test runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: targets: wasm32-wasi @@ -326,7 +304,7 @@ jobs: x86_64-fortanix-unknown-sgx, ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} @@ -368,7 +346,7 @@ jobs: - target: i686-unknown-hurd-gnu features: ["std"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly # Required to build libcore with: components: rust-src @@ -379,23 +357,9 @@ jobs: name: No Atomics Build runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: targets: riscv32i-unknown-none-elf - uses: Swatinem/rust-cache@v2 - run: cargo build --features custom --target riscv32i-unknown-none-elf - - clippy-fmt: - name: Clippy + rustfmt - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v1 - - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt, clippy - - uses: Swatinem/rust-cache@v2 - - name: clippy - run: cargo clippy --all --features=custom,std - - name: fmt - run: cargo fmt --all -- --check diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml new file mode 100644 index 000000000..5c029aada --- /dev/null +++ b/.github/workflows/workspace.yml @@ -0,0 +1,94 @@ +name: Workspace + +on: + push: + branches: master + pull_request: + branches: master + +permissions: + contents: read + +jobs: + clippy: + name: Clippy + runs-on: ubuntu-latest + env: + RUSTFLAGS: "-Dwarnings" + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + # We need Nightly for -Zbuild-std. + # Fixed Nigthly version is used to prevent + # CI failures which are not relevant to PR changes + # on introduction of new Clippy lints. + toolchain: nightly-2024-06-11 + components: clippy,rust-src + - name: std feature + run: cargo clippy --features std + - name: custom feature + run: cargo clippy -Zbuild-std=core --target riscv32i-unknown-none-elf --features custom + - name: iOS (apple-other.rs) + run: cargo clippy -Zbuild-std=core --target x86_64-apple-ios + - name: ESP-IDF (espidf.rs) + run: cargo clippy -Zbuild-std=core --target riscv32imc-esp-espidf + - name: Fuchsia (fuchsia.rs) + run: cargo clippy -Zbuild-std=core --target x86_64-unknown-fuchsia + - name: OpenBSD (getentropy.rs) + run: cargo clippy -Zbuild-std=core --target x86_64-unknown-openbsd + - name: FreeBSD (getrandom.rs) + run: cargo clippy -Zbuild-std=core --target x86_64-unknown-freebsd + - name: Hermit (hermit.rs) + run: cargo clippy -Zbuild-std=core --target x86_64-unknown-hermit + - name: Web WASM (js.rs) + run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown --features js + - name: Linux (linux_android.rs) + run: cargo clippy --target x86_64-unknown-linux-gnu --features linux_disable_fallback + - name: Linux (linux_android_with_fallback.rs) + run: cargo clippy --target x86_64-unknown-linux-gnu + - name: NetBSD (netbsd.rs) + run: cargo clippy -Zbuild-std=core --target x86_64-unknown-netbsd + - name: Fortranix SGX (rdrand.rs) + run: cargo clippy -Zbuild-std=core --target x86_64-fortanix-unknown-sgx + - name: Solaris (solaris.rs) + run: cargo clippy -Zbuild-std=core --target x86_64-pc-solaris + - name: SOLID (solid.rs) + run: cargo clippy -Zbuild-std=core --target aarch64-kmc-solid_asp3 + - name: Redox (use_file.rs) + run: cargo clippy -Zbuild-std=core --target x86_64-unknown-redox + - name: VxWorks (vxworks.rs) + run: cargo clippy -Zbuild-std=core --target x86_64-wrs-vxworks + - name: WASI (wasi.rs) + run: cargo clippy -Zbuild-std=core --target wasm32-wasip2 + - name: Windows 7 (windows7.rs) + run: cargo clippy -Zbuild-std=core --target x86_64-win7-windows-msvc + - name: Windows (windows.rs) + run: cargo clippy -Zbuild-std=core --target x86_64-pc-windows-msvc + + fmt: + name: rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - uses: Swatinem/rust-cache@v2 + - name: fmt + run: cargo fmt --all -- --check + + check-doc: + name: rustdoc + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + # We need Nightly for doc_auto_cfg + toolchain: nightly-2024-06-11 + - uses: Swatinem/rust-cache@v2 + - name: Generate Docs + env: + RUSTDOCFLAGS: "-Dwarnings --cfg docsrs" + run: cargo doc --no-deps --features custom diff --git a/src/lazy.rs b/src/lazy.rs index 10a43d0cb..73cece0ec 100644 --- a/src/lazy.rs +++ b/src/lazy.rs @@ -28,7 +28,7 @@ pub(crate) struct LazyUsize(AtomicUsize); impl LazyUsize { // The initialization is not completed. - const UNINIT: usize = usize::max_value(); + const UNINIT: usize = usize::MAX; pub const fn new() -> Self { Self(AtomicUsize::new(Self::UNINIT)) diff --git a/src/use_file.rs b/src/use_file.rs index 36210dee9..0764766be 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -17,7 +17,7 @@ use core::{ /// - 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"; -const FD_UNINIT: usize = usize::max_value(); +const FD_UNINIT: usize = usize::MAX; // Do not inline this when it is the fallback implementation, but don't mark it // `#[cold]` because it is hot when it is actually used. diff --git a/src/vxworks.rs b/src/vxworks.rs index 5c75847b3..7f0613d2e 100644 --- a/src/vxworks.rs +++ b/src/vxworks.rs @@ -1,6 +1,7 @@ //! Implementation for VxWorks use crate::{util_libc::last_os_error, Error}; use core::{ + cmp::Ordering::{Equal, Greater, Less}, mem::MaybeUninit, sync::atomic::{AtomicBool, Ordering::Relaxed}, }; @@ -9,17 +10,21 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> 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; + match ret.cmp(&0) { + Greater => { + RNG_INIT.store(true, Relaxed); + break; + } + Equal => unsafe { + libc::usleep(10); + }, + Less => return Err(Error::VXWORKS_RAND_SECURE), } - unsafe { libc::usleep(10) }; } // Prevent overflow of i32 - for chunk in dest.chunks_mut(i32::max_value() as usize) { + 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 ret = unsafe { libc::randABytes(chunk.as_mut_ptr().cast::(), chunk.len() as i32) }; if ret != 0 { return Err(last_os_error()); diff --git a/src/windows.rs b/src/windows.rs index e0e8049ef..e44c42926 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -18,6 +18,7 @@ //! - 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; diff --git a/src/windows7.rs b/src/windows7.rs index df83c5e6b..6714f66b3 100644 --- a/src/windows7.rs +++ b/src/windows7.rs @@ -25,7 +25,8 @@ const TRUE: BOOLEAN = 1u8; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // Prevent overflow of u32 - for chunk in dest.chunks_mut(u32::max_value() as usize) { + 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 ret = unsafe { RtlGenRandom(chunk.as_mut_ptr().cast::(), chunk.len() as u32) }; if ret != TRUE { return Err(Error::WINDOWS_RTL_GEN_RANDOM); From 15c6be883528d906f09df8363a57c3c1878cca6c Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 17 Jun 2024 11:31:31 -0700 Subject: [PATCH 019/201] CI: Test `std` feature on Aarch64 QNX (#479) --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 922e8fd40..1d86ee270 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -331,6 +331,8 @@ jobs: aarch64-apple-tvos, ] include: + - target: aarch64-unknown-nto-qnx710 + features: ["std"] # Supported tier 3 targets with libstd support - target: x86_64-unknown-openbsd features: ["std"] From 480d6b01a37a835ff08fc72f2540adc38ca231fb Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 17 Jun 2024 12:09:00 -0700 Subject: [PATCH 020/201] use_file: Use `AtomicI32` instead of `AtomicUsize` to avoid conversions (#480) All the targets that use `use_file` support `AtomicI32`. Using `AtomicI32` eliminates `as` conversions and thus avoids any possibility of truncation or confusion between `FD_UNINIT` and a valid file descriptor. Use -1 as the sentinel value for `FD_UNINIT` since libstd (only) guarantees that -1 is not a valid file descriptor value. Minimize the scope of `FD_UNINIT`. --- src/use_file.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/use_file.rs b/src/use_file.rs index 0764766be..6dae1d108 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -7,7 +7,7 @@ use core::{ cell::UnsafeCell, ffi::c_void, mem::MaybeUninit, - sync::atomic::{AtomicUsize, Ordering::Relaxed}, + sync::atomic::{AtomicI32, Ordering::Relaxed}, }; /// For all platforms, we use `/dev/urandom` rather than `/dev/random`. @@ -17,7 +17,6 @@ use core::{ /// - 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"; -const FD_UNINIT: usize = usize::MAX; // Do not inline this when it is the fallback implementation, but don't mark it // `#[cold]` because it is hot when it is actually used. @@ -33,12 +32,21 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // 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 { - static FD: AtomicUsize = AtomicUsize::new(FD_UNINIT); + // std::os::fd::{BorrowedFd, OwnedFd} guarantee that -1 is not a valid file descriptor. + const FD_UNINIT: libc::c_int = -1; + + // 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. + static FD: AtomicI32 = AtomicI32::new(FD_UNINIT); fn get_fd() -> Option { match FD.load(Relaxed) { FD_UNINIT => None, - val => Some(val as libc::c_int), + val => Some(val), } } @@ -59,9 +67,8 @@ fn get_rng_fd() -> Result { wait_until_rng_ready()?; let fd = open_readonly(FILE_PATH)?; - // The fd always fits in a usize without conflicting with FD_UNINIT. - debug_assert!(fd >= 0 && (fd as usize) < FD_UNINIT); - FD.store(fd as usize, Relaxed); + debug_assert!(fd != FD_UNINIT); + FD.store(fd, Relaxed); Ok(fd) } From a8712f35512189091d5c709e6167f1b7128c106c Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 17 Jun 2024 13:42:06 -0700 Subject: [PATCH 021/201] use_file: use `Acquire`/`Release` ordering instead of `Relaxed` (#469) --- src/use_file.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/use_file.rs b/src/use_file.rs index 6dae1d108..4fdbe3d7e 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -7,7 +7,7 @@ use core::{ cell::UnsafeCell, ffi::c_void, mem::MaybeUninit, - sync::atomic::{AtomicI32, Ordering::Relaxed}, + sync::atomic::{AtomicI32, Ordering}, }; /// For all platforms, we use `/dev/urandom` rather than `/dev/random`. @@ -41,10 +41,18 @@ fn get_rng_fd() -> Result { // 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); fn get_fd() -> Option { - match FD.load(Relaxed) { + match FD.load(Ordering::Acquire) { FD_UNINIT => None, val => Some(val), } @@ -52,6 +60,11 @@ fn get_rng_fd() -> Result { #[cold] fn get_fd_locked() -> Result { + // This mutex is used to prevent multiple threads from opening file + // descriptors concurrently, which could run into the limit on the + // number of open file descriptors. Our goal is to have no more than one + // file descriptor open, ever. + // // 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(); @@ -68,7 +81,7 @@ fn get_rng_fd() -> Result { let fd = open_readonly(FILE_PATH)?; debug_assert!(fd != FD_UNINIT); - FD.store(fd, Relaxed); + FD.store(fd, Ordering::Release); Ok(fd) } From c740f03dc2f3953298e86e4b9c5f255d3c6682b3 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Tue, 18 Jun 2024 12:24:27 -0700 Subject: [PATCH 022/201] lazy: Make `LazyUsize` private. (#482) It is an implementation detail of the other Lazy* types. It isn't used outside of its own module. --- src/lazy.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lazy.rs b/src/lazy.rs index 73cece0ec..5f949c7f5 100644 --- a/src/lazy.rs +++ b/src/lazy.rs @@ -24,20 +24,20 @@ use core::{ // } // the effects of c() or writes to shared memory will not necessarily be // observed and additional synchronization methods may be needed. -pub(crate) struct LazyUsize(AtomicUsize); +struct LazyUsize(AtomicUsize); impl LazyUsize { // The initialization is not completed. const UNINIT: usize = usize::MAX; - pub const fn new() -> Self { + 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. - pub fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize { + fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize { #[cold] fn do_init(this: &LazyUsize, init: impl FnOnce() -> usize) -> usize { let val = init(); From 267639ea9abdbabface7b77d8bd53e3553250c34 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Tue, 18 Jun 2024 21:03:07 -0700 Subject: [PATCH 023/201] netbsd: Simplify weak lookup. (#484) Remove LazyPtr. Avoid constructing an invalid pointer as a sentinel to indicate that the pointer is uninitialized. Now, a null pointer means it is uninitialized, and a non-null pointer means it is initialized. This is less questionable from a safety perspective, and should also be more efficient. Reduce duplication between the "getrandom is available" and the fallback case. --- src/lazy.rs | 60 +----------------------------------------- src/netbsd.rs | 73 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 51 insertions(+), 82 deletions(-) diff --git a/src/lazy.rs b/src/lazy.rs index 5f949c7f5..0b4730e65 100644 --- a/src/lazy.rs +++ b/src/lazy.rs @@ -1,10 +1,7 @@ //! Helpers built around pointer-sized atomics. #![cfg(target_has_atomic = "ptr")] #![allow(dead_code)] -use core::{ - ffi::c_void, - sync::atomic::{AtomicPtr, AtomicUsize, Ordering}, -}; +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. @@ -67,58 +64,3 @@ impl LazyBool { self.0.unsync_init(|| usize::from(init())) != 0 } } - -// This structure represents a lazily initialized static pointer value. -/// -/// It's intended to be used for weak linking of a C function that may -/// or may not be present at runtime. -/// -/// 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 LazyPtr { - addr: AtomicPtr, -} - -impl LazyPtr { - /// A non-null pointer value which indicates we are uninitialized. - /// - /// This constant should ideally not be a valid pointer. However, - /// if by chance initialization function passed to the `unsync_init` - /// method does return UNINIT, there will not be undefined behavior. - /// The initialization function will just be called each time `get()` - /// is called. This would be inefficient, but correct. - const UNINIT: *mut c_void = !0usize as *mut c_void; - - /// Construct new `LazyPtr` in uninitialized state. - pub const fn new() -> Self { - Self { - addr: AtomicPtr::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. - pub fn unsync_init(&self, init: impl Fn() -> *mut c_void) -> *mut c_void { - #[cold] - fn do_init(this: &LazyPtr, init: impl Fn() -> *mut c_void) -> *mut c_void { - let addr = init(); - this.addr.store(addr, Ordering::Release); - addr - } - - // 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 `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 val = self.addr.load(Ordering::Acquire); - if val != Self::UNINIT { - val - } else { - do_init(self, init) - } - } -} diff --git a/src/netbsd.rs b/src/netbsd.rs index c4ea75e4d..2842617b6 100644 --- a/src/netbsd.rs +++ b/src/netbsd.rs @@ -1,15 +1,35 @@ //! Implementation for NetBSD -use crate::{lazy::LazyPtr, util_libc::sys_fill_exact, Error}; -use core::{ffi::c_void, mem::MaybeUninit, ptr}; +//! +//! `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::{util_libc::sys_fill_exact, Error}; +use core::{ + cmp, + ffi::c_void, + mem::{self, MaybeUninit}, + ptr, + sync::atomic::{AtomicPtr, Ordering}, +}; + +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); -fn kern_arnd(buf: &mut [MaybeUninit]) -> libc::ssize_t { static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND]; - let mut len = buf.len(); + + // 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() as libc::c_uint, - buf.as_mut_ptr().cast::(), + buf, &mut len, ptr::null(), 0, @@ -22,30 +42,37 @@ fn kern_arnd(buf: &mut [MaybeUninit]) -> libc::ssize_t { } } -type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t; +type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) -> libc::ssize_t; -// getrandom(2) was introduced in NetBSD 10.0 -static GETRANDOM: LazyPtr = LazyPtr::new(); +static GETRANDOM: AtomicPtr = AtomicPtr::new(ptr::null_mut()); -fn dlsym_getrandom() -> *mut c_void { +#[cold] +fn init() -> *mut c_void { static NAME: &[u8] = b"getrandom\0"; let name_ptr = NAME.as_ptr().cast::(); - unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) } + let mut ptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) }; + if ptr.is_null() { + // 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 } pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - let fptr = GETRANDOM.unsync_init(dlsym_getrandom); - if !fptr.is_null() { - let func: GetRandomFn = unsafe { core::mem::transmute(fptr) }; - return sys_fill_exact(dest, |buf| unsafe { - func(buf.as_mut_ptr().cast::(), buf.len(), 0) - }); - } - - // 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)? + // 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(); } - Ok(()) + let fptr = unsafe { mem::transmute::<*mut c_void, GetRandomFn>(fptr) }; + sys_fill_exact(dest, |buf| unsafe { + fptr(buf.as_mut_ptr().cast::(), buf.len(), 0) + }) } From f345775deaa4936f97779b4aae79478fe7050177 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Wed, 19 Jun 2024 02:20:48 -0700 Subject: [PATCH 024/201] Cleanup Custom Tests (#473) This moves the tests for the custom RNG registration into custom.rs. It also: - Simplifies the registered custom RNG - Makes sure the custom RNG _is not_ used on supported platforms - Makes sure the custom RNG _is_ used on unsupported platforms --- .github/workflows/tests.yml | 6 ++-- Cargo.toml | 4 +++ tests/custom.rs | 72 ++++++++++++++++++------------------- 3 files changed, 43 insertions(+), 39 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1d86ee270..26f0760cf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,9 +38,9 @@ jobs: toolchain: ${{ matrix.toolchain }} - uses: Swatinem/rust-cache@v2 - run: cargo test - - run: cargo test --features=std + # Make sure enabling the std and custom features don't break anything + - run: cargo test --features=std,custom - run: cargo test --features=linux_disable_fallback - - run: cargo test --features=custom # custom should do nothing here - if: ${{ matrix.toolchain == 'nightly' }} run: cargo test --benches @@ -260,6 +260,8 @@ jobs: run: wasm-pack test --headless --safari --features=js,test-in-browser - name: Test (custom getrandom) run: wasm-pack test --node --features=custom + - name: Test (JS overrides custom) + run: wasm-pack test --node --features=custom,js wasm64-tests: name: wasm64 Build/Link diff --git a/Cargo.toml b/Cargo.toml index 47c7fd282..032ae083d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,10 @@ rustc-dep-of-std = [ # Unstable/test-only feature to run wasm-bindgen tests in a browser test-in-browser = [] +[[test]] +name = "custom" +required-features = ["custom"] + [package.metadata.docs.rs] features = ["std", "custom"] rustdoc-args = ["--cfg", "docsrs"] diff --git a/tests/custom.rs b/tests/custom.rs index b085094be..30934e941 100644 --- a/tests/custom.rs +++ b/tests/custom.rs @@ -1,54 +1,52 @@ -// Test that a custom handler works on wasm32-unknown-unknown -#![cfg(all( - target_arch = "wasm32", - target_os = "unknown", - feature = "custom", - not(feature = "js") -))] - -use wasm_bindgen_test::wasm_bindgen_test as test; - use core::num::NonZeroU32; use getrandom::{getrandom, register_custom_getrandom, Error}; +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +use wasm_bindgen_test::wasm_bindgen_test as test; -fn len7_err() -> Error { - NonZeroU32::new(Error::INTERNAL_START + 7).unwrap().into() -} - -fn super_insecure_rng(buf: &mut [u8]) -> Result<(), Error> { +const LEN7_CODE: u32 = Error::CUSTOM_START + 7; +// Returns a custom error if input is length 7, otherwise fills with 0x55. +fn mock_rng(buf: &mut [u8]) -> Result<(), Error> { // `getrandom` guarantees it will not call any implementation if the output // buffer is empty. assert!(!buf.is_empty()); - // Length 7 buffers return a custom error if buf.len() == 7 { - return Err(len7_err()); - } - // Otherwise, fill bytes based on input length - let mut start = buf.len() as u8; - for b in buf { - *b = start; - start = start.wrapping_mul(3); + return Err(NonZeroU32::new(LEN7_CODE).unwrap().into()); } + buf.fill(0x55); Ok(()) } -register_custom_getrandom!(super_insecure_rng); - -use getrandom::getrandom as getrandom_impl; -mod common; +// Test registering a custom implementation, even on supported platforms. +register_custom_getrandom!(mock_rng); +// Invoking with an empty buffer should never call the custom implementation. #[test] -fn custom_rng_output() { - let mut buf = [0u8; 4]; - assert_eq!(getrandom(&mut buf), Ok(())); - assert_eq!(buf, [4, 12, 36, 108]); - - let mut buf = [0u8; 3]; - assert_eq!(getrandom(&mut buf), Ok(())); - assert_eq!(buf, [3, 9, 27]); +fn custom_empty() { + getrandom(&mut []).unwrap(); } +// On a supported platform, make sure the custom implementation isn't used. We +// test on a few common platfroms, rather than duplicating the lib.rs logic. +#[cfg(any( + target_os = "linux", + target_os = "windows", + target_os = "macos", + target_os = "espidf", + target_os = "wasi", + all(target_family = "wasm", target_os = "unknown", feature = "js"), +))] #[test] -fn rng_err_output() { - assert_eq!(getrandom(&mut [0; 7]), Err(len7_err())); +fn custom_not_used() { + getrandom(&mut [0; 7]).unwrap(); +} +// On an unsupported platform, make sure the custom implementation is used. +#[cfg(all(target_family = "wasm", target_os = "unknown", not(feature = "js")))] +#[test] +fn custom_used() { + let err = getrandom(&mut [0; 7]).unwrap_err(); + assert_eq!(err.code().get(), LEN7_CODE); + + let mut buf = [0; 12]; + getrandom(&mut buf).unwrap(); + assert_eq!(buf, [0x55; 12]); } From baae5fcb1cb508b7b7717b35a6c6f313be8d8ed2 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 19 Jun 2024 19:08:49 +0300 Subject: [PATCH 025/201] Completely disable Web tests on Windows (#486) `continue-on-error` does not work as I was expecting. AFAIK GitHub Action does not have a straightforward solution for optionally failing jobs, see: https://github.com/actions/runner/issues/2347 Closes #400 --- .github/workflows/tests.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 26f0760cf..4cfa41de7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -225,13 +225,12 @@ jobs: include: - os: ubuntu-22.04 host: x86_64-unknown-linux-musl - - os: windows-2022 - host: x86_64-pc-windows-msvc - # We get spurious failures on Windows, see: - # https://github.com/rust-random/getrandom/issues/400 - continue-on-error: true - os: macos-12 host: x86_64-apple-darwin + # We get spurious failures on Windows, see: + # https://github.com/rust-random/getrandom/issues/400 + # - os: windows-2022 + # host: x86_64-pc-windows-msvc runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 From 6bb19a21dede30af90e7efcea2edf2f7e81c149e Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 20 Jun 2024 18:50:30 -0700 Subject: [PATCH 026/201] Upgrade to cargo-dinghy 0.7.2 (#488) There is now a universal binary after https://github.com/sonos/dinghy/pull/209. --- .github/workflows/tests.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4cfa41de7..e4ed5ebc6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -93,20 +93,11 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} - # There is no precompiled cargo-dinghy for Aarch64. The precompiled - # x86_64 binary runs on ARM64 macOS via Rosetta 2, but it fails to - # correctly interface with macOS toolchain. - name: Install precompiled cargo-dinghy - if: ${{ matrix.target == 'x86_64-apple-ios' }} run: | - VERSION=0.6.2 + VERSION=0.7.2 URL="https://github.com/sonos/dinghy/releases/download/${VERSION}/cargo-dinghy-macos-${VERSION}.tgz" wget -O - $URL | tar -xz --strip-components=1 -C ~/.cargo/bin - - name: cargo install cargo-dinghy - if: ${{ matrix.target == 'aarch64-apple-ios-sim' }} - run: | - VERSION=0.6.2 - cargo install cargo-dinghy --version ${VERSION} - name: Check cargo-dinghy version. run: cargo dinghy --version - name: Setup Simulator From 5edb0453b3ab46e352c7f3463f192b4959770c2e Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 20 Jun 2024 22:16:02 -0700 Subject: [PATCH 027/201] CI: Build and link tvOS and watchOS targets (#489) --- .github/workflows/tests.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e4ed5ebc6..963a0fcb5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -174,7 +174,8 @@ jobs: macos-link: name: macOS ARM64 Build/Link - runs-on: macos-12 + # visionOS requires Xcode 15.2+, which is only available on the arm64 runners. + runs-on: macos-14 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly @@ -184,7 +185,11 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: cargo test --no-run --target=aarch64-apple-darwin --features=std - run: cargo test --no-run --target=aarch64-apple-ios --features=std - - run: cargo test --no-run --target=aarch64-apple-watchos-sim -Zbuild-std --features=std + - run: cargo test --no-run --target=aarch64-apple-tvos -Zbuild-std --features=std + - run: cargo test --no-run --target=aarch64-apple-watchos -Zbuild-std --features=std + # visionOS requires Xcode 15.2+, GitHub Actions defaults to an older version. + - run: sudo xcode-select -switch /Applications/Xcode_15.2.app + - run: cargo test --no-run --target=aarch64-apple-visionos -Zbuild-std --features=std cross-link: name: Cross Build/Link @@ -318,9 +323,6 @@ jobs: armv7-sony-vita-newlibeabihf, riscv32imc-esp-espidf, aarch64-unknown-nto-qnx710, - # `std` support still in progress. Can be moved up with the other - # apple targets after https://github.com/rust-lang/rust/pull/103503 - aarch64-apple-tvos, ] include: - target: aarch64-unknown-nto-qnx710 From aa13fa58821180248507b81c967d3c731a2ca1d5 Mon Sep 17 00:00:00 2001 From: Jubilee Date: Sun, 25 Aug 2024 18:46:40 -0700 Subject: [PATCH 028/201] wasm: Depend on wasm-bindgen 0.2.89 or higher (#497) wasm-bindgen 0.2.62 is not compatible with a wasm ABI change that rustc wishes to enable by default for wasm32-unknown-unknown, currently gated behind passing the -Zwasm-c-abi flag to rustc. wasm-bindgen 0.2.89 should exhibit seamless behavior before and after the ABI change to match the C ABI, so depend on that. For more information, see - https://github.com/rust-lang/rust/issues/115666 - https://github.com/rust-lang/rust/pull/117918 - https://github.com/rust-lang/rust/issues/122532 --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 032ae083d..6ba57f37e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,10 +28,10 @@ wasi = { version = "0.11", default-features = false } windows-targets = "0.52" [target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies] -wasm-bindgen = { version = "0.2.62", default-features = false, optional = true } +wasm-bindgen = { version = "0.2.89", default-features = false, optional = true } js-sys = { version = "0.3", optional = true } [target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dev-dependencies] -wasm-bindgen-test = "0.3.18" +wasm-bindgen-test = "0.3.39" [features] # Implement std-only traits for getrandom::Error From 6c6fbefed7455bf903a9c299c18349c30d7082dd Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 27 Sep 2024 19:31:00 +0300 Subject: [PATCH 029/201] Add support for `wasm32-wasip1` and `wasm32-wasip2`, remove support for `wasm32-wasi` (#499) The `wasm32-wasi` target will be removed in Rust 1.84 (https://blog.rust-lang.org/2024/04/09/updates-to-rusts-wasi-targets.html) and existing users are encouraged to migrate to either `wasm32-wasip1`, or `wasm32-wasip2`. Strictly speaking, this is a breaking change despite affecting only deprecated target, so it's probably better to release it in `getrandom` v0.3. --- .cargo/config.toml | 4 ++- .github/workflows/tests.yml | 16 +++++++---- .github/workflows/workspace.yml | 10 ++++--- CHANGELOG.md | 5 ++++ Cargo.toml | 22 +++++++-------- src/lib.rs | 6 ++-- src/wasi.rs | 50 +++++++++++++++++++++++++++++++-- 7 files changed, 86 insertions(+), 27 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index be3061aba..567208e3d 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,7 +1,9 @@ # Allow normal use of "cargo run" and "cargo test" on these wasm32 platforms. [target.wasm32-unknown-unknown] runner = 'wasm-bindgen-test-runner' -[target.wasm32-wasi] +[target.wasm32-wasip1] +runner = 'wasmtime' +[target.wasm32-wasip2] runner = 'wasmtime' # Just run on node by default (that's where emscripten is tested) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 963a0fcb5..c4e1cf53b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -274,21 +274,25 @@ jobs: run: cargo test --no-run -Z build-std=std,panic_abort --target=wasm64-unknown-unknown --features=js wasi-tests: - name: WASI Test + name: WASI Tests runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@master with: - targets: wasm32-wasi - - name: Install precompiled wasmtime + toolchain: nightly # TODO: Use stable after 1.82 is released as stable + targets: wasm32-wasip1,wasm32-wasip2 + - name: Install Wasmtime run: | - VERSION=v2.0.0 + VERSION=v24.0.0 URL=https://github.com/bytecodealliance/wasmtime/releases/download/${VERSION}/wasmtime-${VERSION}-x86_64-linux.tar.xz wget -O - $URL | tar -xJ --strip-components=1 -C ~/.cargo/bin wasmtime --version - uses: Swatinem/rust-cache@v2 - - run: cargo test --target wasm32-wasi + - name: WASI 0.1 Test + run: cargo test --target wasm32-wasip1 + - name: WASI 0.2 Test + run: cargo test --target wasm32-wasip2 build-tier2: name: Tier 2 Build diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 5c029aada..db7b1568f 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -23,7 +23,7 @@ jobs: # Fixed Nigthly version is used to prevent # CI failures which are not relevant to PR changes # on introduction of new Clippy lints. - toolchain: nightly-2024-06-11 + toolchain: nightly-2024-09-04 components: clippy,rust-src - name: std feature run: cargo clippy --features std @@ -59,8 +59,10 @@ jobs: run: cargo clippy -Zbuild-std=core --target x86_64-unknown-redox - name: VxWorks (vxworks.rs) run: cargo clippy -Zbuild-std=core --target x86_64-wrs-vxworks - - name: WASI (wasi.rs) - run: cargo clippy -Zbuild-std=core --target wasm32-wasip2 + - name: WASI preview 1 (wasi.rs) + run: cargo clippy -Zbuild-std=core --target wasm32-wasip1 + - name: WASI preview 2 (wasi.rs) + run: cargo clippy -Zbuild-std=core,alloc --target wasm32-wasip2 - name: Windows 7 (windows7.rs) run: cargo clippy -Zbuild-std=core --target x86_64-win7-windows-msvc - name: Windows (windows.rs) @@ -86,7 +88,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: # We need Nightly for doc_auto_cfg - toolchain: nightly-2024-06-11 + toolchain: nightly-2024-09-04 - uses: Swatinem/rust-cache@v2 - name: Generate Docs env: diff --git a/CHANGELOG.md b/CHANGELOG.md index d32a369e1..fc39b075b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Breaking Changes - Update MSRV to 1.38 [#425] +- Remove support of the `wasm32-wasi` target (use `wasm32-wasip1` or `wasm32-wasip2` instead) [#499] + +### Added +- `wasm32-wasip1` and `wasm32-wasip2` support [#499] [#425]: https://github.com/rust-random/getrandom/pull/425 +[#499]: https://github.com/rust-random/getrandom/pull/499 ## [0.2.15] - 2024-05-06 ### Added diff --git a/Cargo.toml b/Cargo.toml index 6ba57f37e..34dbd3a58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,9 +21,12 @@ core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" [target.'cfg(unix)'.dependencies] libc = { version = "0.2.154", default-features = false } -[target.'cfg(target_os = "wasi")'.dependencies] +[target.'cfg(all(target_arch = "wasm32", target_os = "wasi", target_env = "p1"))'.dependencies] wasi = { version = "0.11", default-features = false } +[target.'cfg(all(target_arch = "wasm32", target_os = "wasi", target_env = "p2"))'.dependencies] +wasi = { version = "0.13", default-features = false } + [target.'cfg(all(windows, not(target_vendor = "win7")))'.dependencies] windows-targets = "0.52" @@ -46,10 +49,7 @@ js = ["wasm-bindgen", "js-sys"] # Feature to enable custom RNG implementations custom = [] # Unstable feature to support being a libstd dependency -rustc-dep-of-std = [ - "compiler_builtins", - "core", -] +rustc-dep-of-std = ["compiler_builtins", "core"] # Unstable/test-only feature to run wasm-bindgen tests in a browser test-in-browser = [] @@ -64,10 +64,10 @@ rustdoc-args = ["--cfg", "docsrs"] # workaround for https://github.com/cross-rs/cross/issues/1345 [package.metadata.cross.target.x86_64-unknown-netbsd] pre-build = [ - "mkdir -p /tmp/netbsd", - "curl https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.2/amd64/binary/sets/base.tar.xz -O", - "tar -C /tmp/netbsd -xJf base.tar.xz", - "cp /tmp/netbsd/usr/lib/libexecinfo.so /usr/local/x86_64-unknown-netbsd/lib", - "rm base.tar.xz", - "rm -rf /tmp/netbsd", + "mkdir -p /tmp/netbsd", + "curl https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.2/amd64/binary/sets/base.tar.xz -O", + "tar -C /tmp/netbsd -xJf base.tar.xz", + "cp /tmp/netbsd/usr/lib/libexecinfo.so /usr/local/x86_64-unknown-netbsd/lib", + "rm base.tar.xz", + "rm -rf /tmp/netbsd", ] diff --git a/src/lib.rs b/src/lib.rs index f5e13c360..97622ecfb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,8 @@ //! | VxWorks | `*‑wrs‑vxworks‑*` | `randABytes` after checking entropy pool initialization with `randSecure` //! | ESP-IDF | `*‑espidf` | [`esp_fill_random`] //! | Emscripten | `*‑emscripten` | [`getentropy`][13] -//! | WASI | `wasm32‑wasi` | [`random_get`] +//! | WASI 0.1 | `wasm32‑wasip1` | [`random_get`] +//! | WASI 0.2 | `wasm32‑wasip2` | [`get-random-u64`] //! | Web Browser and Node.js | `wasm*‑*‑unknown` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js, see [WebAssembly support] //! | SOLID | `*-kmc-solid_*` | `SOLID_RNG_SampleRandomBytes` //! | Nintendo 3DS | `*-nintendo-3ds` | [`getrandom`][18] @@ -191,7 +192,8 @@ //! [`cprng_draw`]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw //! [`crypto.randomFillSync`]: https://nodejs.org/api/crypto.html#cryptorandomfillsyncbuffer-offset-size //! [`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 +//! [`random_get`]: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-buf_len-size---errno +//! [`get-random-u64`]: https://github.com/WebAssembly/WASI/blob/v0.2.1/wasip2/random/random.wit#L23-L28 //! [WebAssembly support]: #webassembly-support //! [`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen //! [`module`]: https://rustwasm.github.io/wasm-bindgen/reference/attributes/on-js-imports/module.html diff --git a/src/wasi.rs b/src/wasi.rs index 10d8ae79b..77bc95312 100644 --- a/src/wasi.rs +++ b/src/wasi.rs @@ -1,9 +1,53 @@ -//! Implementation for WASI +//! Implementation for WASI (preview 1 and 2) +//! +//! `target_env = "p1"` was introduced only in Rust 1.80, so on earlier compiler versions this +//! code will result in a compilation error. use crate::Error; use core::mem::MaybeUninit; -use wasi::random_get; +#[cfg(not(any(target_env = "p1", target_env = "p2")))] +compile_error!( + "Unknown version of WASI (only previews 1 and 2 are supported) \ + or Rust version older than 1.80 was used" +); + +#[cfg(target_env = "p1")] pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - unsafe { random_get(dest.as_mut_ptr().cast::(), dest.len()) } + unsafe { wasi::random_get(dest.as_mut_ptr().cast::(), dest.len()) } .map_err(|e| Error::from_os_error(e.raw().into())) } + +#[cfg(target_env = "p2")] +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { + use core::ptr::copy_nonoverlapping; + use wasi::random::random::get_random_u64; + + let (prefix, chunks, suffix) = unsafe { dest.align_to_mut::>() }; + + // 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(()) +} From fd2de2f7c3f9ffe62ab4efc3553ce2daa55de09a Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 27 Sep 2024 19:53:00 +0300 Subject: [PATCH 030/201] use_file: switch to `futex` on Linux and to `nanosleep` on other targets (#490) All non-Linux targets only open file in the critical section, so we probably can remove all synchronization and replace it with a sleep-based wait loop. On Linux initialization thread may spend a lot of time in the critical section because of `wait_until_rng_ready`. On entropy-starved (and especially virtualized) systems we may spend tens of seconds in it, so we need a proper synchronization between initializing and waiting threads. Luckily, the `futex` API is a great fit in this case and allows us to efficiently handle the synchronization. --- CHANGELOG.md | 9 +- src/linux_android_with_fallback.rs | 8 +- src/use_file.rs | 292 ++++++++++++++++------------- 3 files changed, 173 insertions(+), 136 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc39b075b..b781ac15d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Breaking Changes -- Update MSRV to 1.38 [#425] +- Update MSRV to 1.60 [#472] - Remove support of the `wasm32-wasi` target (use `wasm32-wasip1` or `wasm32-wasip2` instead) [#499] +### Changed +- Switch to `futex` on Linux and to `nanosleep`-based wait loop on other targets + in the `use_file` backend [#490] + ### Added - `wasm32-wasip1` and `wasm32-wasip2` support [#499] -[#425]: https://github.com/rust-random/getrandom/pull/425 +[#472]: https://github.com/rust-random/getrandom/pull/472 +[#490]: https://github.com/rust-random/getrandom/pull/490 [#499]: https://github.com/rust-random/getrandom/pull/499 ## [0.2.15] - 2024-05-06 diff --git a/src/linux_android_with_fallback.rs b/src/linux_android_with_fallback.rs index 98fa15e89..b633faad5 100644 --- a/src/linux_android_with_fallback.rs +++ b/src/linux_android_with_fallback.rs @@ -8,7 +8,13 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { if HAS_GETRANDOM.unsync_init(is_getrandom_available) { linux_android::getrandom_inner(dest) } else { - use_file::getrandom_inner(dest) + // prevent inlining of the fallback implementation + #[inline(never)] + fn inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { + use_file::getrandom_inner(dest) + } + + inner(dest) } } diff --git a/src/use_file.rs b/src/use_file.rs index 4fdbe3d7e..247272dce 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -4,7 +4,6 @@ use crate::{ Error, }; use core::{ - cell::UnsafeCell, ffi::c_void, mem::MaybeUninit, sync::atomic::{AtomicI32, Ordering}, @@ -18,159 +17,186 @@ use core::{ /// - On Haiku and QNX Neutrino they are identical. const FILE_PATH: &[u8] = b"/dev/urandom\0"; -// Do not inline this when it is the fallback implementation, but don't mark it -// `#[cold]` because it is hot when it is actually used. -#[cfg_attr(any(target_os = "android", target_os = "linux"), inline(never))] +// 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); + pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - let fd = get_rng_fd()?; + let mut fd = FD.load(Ordering::Acquire); + if fd == FD_UNINIT || fd == FD_ONGOING_INIT { + fd = open_or_wait()?; + } sys_fill_exact(dest, |buf| unsafe { libc::read(fd, buf.as_mut_ptr().cast::(), buf.len()) }) } -// 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 { - // std::os::fd::{BorrowedFd, OwnedFd} guarantee that -1 is not a valid file descriptor. - const FD_UNINIT: libc::c_int = -1; - - // 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); - - fn get_fd() -> Option { +#[cold] +fn open_or_wait() -> Result { + loop { match FD.load(Ordering::Acquire) { - FD_UNINIT => None, - val => Some(val), + 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), } } - #[cold] - fn get_fd_locked() -> Result { - // This mutex is used to prevent multiple threads from opening file - // descriptors concurrently, which could run into the limit on the - // number of open file descriptors. Our goal is to have no more than one - // file descriptor open, ever. - // - // 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 res = open_fd(); + let val = match res { + Ok(fd) => fd, + Err(_) => FD_UNINIT, + }; + FD.store(val, Ordering::Release); - let fd = open_readonly(FILE_PATH)?; - debug_assert!(fd != FD_UNINIT); - FD.store(fd, 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(); - Ok(fd) - } - - // Use double-checked locking to avoid acquiring the lock if possible. - if let Some(fd) = get_fd() { - Ok(fd) - } else { - get_fd_locked() - } + res } -// 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. -#[cfg(any(target_os = "android", target_os = "linux"))] -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 _guard = DropGuard(|| unsafe { - libc::close(fd); - }); +fn open_fd() -> Result { + #[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) +} - 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), +#[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); } } } -struct Mutex(UnsafeCell); - -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); +#[cfg(any(target_os = "android", target_os = "linux"))] +mod sync { + use super::{Error, FD, FD_ONGOING_INIT}; + use crate::util_libc::{last_os_error, open_readonly}; + + /// 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::(); + 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, + } + }); } -} - -unsafe impl Sync for Mutex {} -struct DropGuard(F); + /// 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); + } -impl Drop for DropGuard { - fn drop(&mut self) { - self.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(); + match err.raw_os_error() { + Some(libc::EINTR) | Some(libc::EAGAIN) => continue, + _ => break Err(err), + } + }; + unsafe { libc::close(fd) }; + res } } From 26b88caf339122539d431cbacc16026870560590 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 4 Oct 2024 20:40:24 +0300 Subject: [PATCH 031/201] wasi: remove dependency on `wasi` v0.11 (#502) Having two `wasi` versions in dependencies causes some annoyances in downstream users, e.g. v0.11 gets show as an "outdated" dependency. The dependency is removed by directly linking `random_get` by following the `wasi` code. --- Cargo.toml | 3 --- src/wasi.rs | 18 ++++++++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 34dbd3a58..2d8baa627 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,9 +21,6 @@ core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" [target.'cfg(unix)'.dependencies] libc = { version = "0.2.154", default-features = false } -[target.'cfg(all(target_arch = "wasm32", target_os = "wasi", target_env = "p1"))'.dependencies] -wasi = { version = "0.11", default-features = false } - [target.'cfg(all(target_arch = "wasm32", target_os = "wasi", target_env = "p2"))'.dependencies] wasi = { version = "0.13", default-features = false } diff --git a/src/wasi.rs b/src/wasi.rs index 77bc95312..db2a800ee 100644 --- a/src/wasi.rs +++ b/src/wasi.rs @@ -13,8 +13,22 @@ compile_error!( #[cfg(target_env = "p1")] pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - unsafe { wasi::random_get(dest.as_mut_ptr().cast::(), dest.len()) } - .map_err(|e| Error::from_os_error(e.raw().into())) + // 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; + } + + // 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. + let ret = unsafe { random_get(dest.as_mut_ptr() as i32, dest.len() as i32) }; + match ret { + 0 => Ok(()), + _ => Err(Error::from_os_error(ret as u32)), + } } #[cfg(target_env = "p2")] From f0d2c3f66fd30f50ea701501f723dbea282232b1 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 7 Oct 2024 17:11:06 +0300 Subject: [PATCH 032/201] Use configuration flags to switch between backends (#504) This PR removes `linux_disable_fallback`, `rdrand`, `js`, `test-in-browser`, and `custom` crate features. As their replacement two new configuration flags are introduced: `getrandom_browser_test` and `getrandom_backend`. The latter can have the following values: `custom`, `rdrand`, `linux_getrandom`, `wasm_js`, `esp_idf`. `getrandom_backend` allows to change default backends which resolves issues like #346 and provides more flexibility to users. For example, it allows to use RDRAND or RDRND (see #494) directly instead of syscall-based interfaces. We previously did not allow such overwrites because of security concerns, but they do not apply in this case since configuration flags used by a project can not be controlled by its upstream dependencies. The `register_custom_getrandom!` macro is removed in favor of explicitly defining the `__getrandom_custom` function. It does not look like the macro was widely used in practice and it's probably easier to explain the `extern fn` approach (especially to embedded developers) than the "magical" registration macro. The new configuration flags also allow a great simplification of our testing code. Finally, ESP-IDF support is no longer enabled by default because of the concerns raised in #397. Users can enable it by enabling the `esp_idf` opt-in backend. Closes #230 Closes #346 Closes #397 Closes #498 --- .github/workflows/tests.yml | 83 ++++++-- .github/workflows/workspace.yml | 18 +- Cargo.toml | 30 ++- src/custom.rs | 95 +-------- src/lib.rs | 337 ++++++++++++++++++-------------- tests/common/mod.rs | 100 ---------- tests/custom.rs | 52 ----- tests/mod.rs | 182 +++++++++++++++++ tests/normal.rs | 11 -- tests/rdrand.rs | 22 --- 10 files changed, 461 insertions(+), 469 deletions(-) delete mode 100644 tests/common/mod.rs delete mode 100644 tests/custom.rs create mode 100644 tests/mod.rs delete mode 100644 tests/normal.rs delete mode 100644 tests/rdrand.rs diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c4e1cf53b..49828c8ee 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,9 +38,8 @@ jobs: toolchain: ${{ matrix.toolchain }} - uses: Swatinem/rust-cache@v2 - run: cargo test - # Make sure enabling the std and custom features don't break anything - - run: cargo test --features=std,custom - - run: cargo test --features=linux_disable_fallback + # Make sure enabling the std feature doesn't break anything + - run: cargo test --features=std - if: ${{ matrix.toolchain == 'nightly' }} run: cargo test --benches @@ -69,6 +68,12 @@ jobs: sudo apt-get install --no-install-recommends ${{ matrix.packages }} - uses: Swatinem/rust-cache@v2 - run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" + run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" + run: cargo test --features=std ios-tests: name: iOS Simulator Test @@ -242,21 +247,27 @@ jobs: wasm-pack --version - uses: Swatinem/rust-cache@v2 - name: Test (Node) - run: wasm-pack test --node --features=js + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" + run: wasm-pack test --node - name: Test (Firefox) - run: wasm-pack test --headless --firefox --features=js,test-in-browser + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test + run: wasm-pack test --headless --firefox - name: Test (Chrome) - run: wasm-pack test --headless --chrome --features=js,test-in-browser + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test + run: wasm-pack test --headless --chrome - name: Test (Edge) if: runner.os == 'Windows' - run: wasm-pack test --headless --chrome --chromedriver $Env:EDGEWEBDRIVER\msedgedriver.exe --features=js,test-in-browser + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test + run: wasm-pack test --headless --chrome --chromedriver $Env:EDGEWEBDRIVER\msedgedriver.exe - name: Test (Safari) if: runner.os == 'macOS' - run: wasm-pack test --headless --safari --features=js,test-in-browser - - name: Test (custom getrandom) - run: wasm-pack test --node --features=custom - - name: Test (JS overrides custom) - run: wasm-pack test --node --features=custom,js + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test + run: wasm-pack test --headless --safari wasm64-tests: name: wasm64 Build/Link @@ -268,10 +279,12 @@ jobs: components: rust-src - uses: Swatinem/rust-cache@v2 - name: Build and Link tests (build-std) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test # This target is Tier 3, so we have to build libstd ourselves. # We currently cannot run these tests because wasm-bindgen-test-runner # does not yet support memory64. - run: cargo test --no-run -Z build-std=std,panic_abort --target=wasm64-unknown-unknown --features=js + run: cargo test --no-run -Z build-std=std,panic_abort --target=wasm64-unknown-unknown wasi-tests: name: WASI Tests @@ -325,24 +338,18 @@ jobs: aarch64-kmc-solid_asp3, armv6k-nintendo-3ds, armv7-sony-vita-newlibeabihf, - riscv32imc-esp-espidf, aarch64-unknown-nto-qnx710, ] + # Supported tier 3 targets with libstd support include: - target: aarch64-unknown-nto-qnx710 features: ["std"] - # Supported tier 3 targets with libstd support - target: x86_64-unknown-openbsd features: ["std"] - target: x86_64-unknown-dragonfly features: ["std"] - target: x86_64-unknown-haiku features: ["std"] - # Unsupported tier 3 targets to test the rdrand feature - - target: x86_64-unknown-uefi - features: ["rdrand"] - - target: x86_64-unknown-l4re-uclibc - features: ["rdrand"] - target: i686-unknown-hurd-gnu features: ["std"] steps: @@ -353,6 +360,38 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: cargo build -Z build-std=${{ contains(matrix.features, 'std') && 'std' || 'core'}} --target=${{ matrix.target }} --features="${{ join(matrix.features, ',') }}" + build-rdrand: + name: RDRAND Build + runs-on: ubuntu-22.04 + strategy: + matrix: + target: [ + x86_64-unknown-uefi, + x86_64-unknown-l4re-uclibc, + ] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly # Required to build libcore + with: + components: rust-src + - uses: Swatinem/rust-cache@v2 + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" + run: cargo build -Z build-std=core --target=${{ matrix.target }} + + build-esp-idf: + name: ESP-IDF Build + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly # Required to build libcore + with: + components: rust-src + - uses: Swatinem/rust-cache@v2 + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="esp_idf" + run: cargo build -Z build-std=core --target=riscv32imc-esp-espidf + build-no-atomics: name: No Atomics Build runs-on: ubuntu-22.04 @@ -362,4 +401,6 @@ jobs: with: targets: riscv32i-unknown-none-elf - uses: Swatinem/rust-cache@v2 - - run: cargo build --features custom --target riscv32i-unknown-none-elf + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom" + run: cargo build --target riscv32i-unknown-none-elf diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index db7b1568f..a230e1c9f 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -27,11 +27,15 @@ jobs: components: clippy,rust-src - name: std feature run: cargo clippy --features std - - name: custom feature - run: cargo clippy -Zbuild-std=core --target riscv32i-unknown-none-elf --features custom + - name: custom backend + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom" + run: cargo clippy -Zbuild-std=core --target riscv32i-unknown-none-elf - name: iOS (apple-other.rs) run: cargo clippy -Zbuild-std=core --target x86_64-apple-ios - name: ESP-IDF (espidf.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="esp_idf" run: cargo clippy -Zbuild-std=core --target riscv32imc-esp-espidf - name: Fuchsia (fuchsia.rs) run: cargo clippy -Zbuild-std=core --target x86_64-unknown-fuchsia @@ -42,9 +46,13 @@ jobs: - name: Hermit (hermit.rs) run: cargo clippy -Zbuild-std=core --target x86_64-unknown-hermit - name: Web WASM (js.rs) - run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown --features js + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" + run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown - name: Linux (linux_android.rs) - run: cargo clippy --target x86_64-unknown-linux-gnu --features linux_disable_fallback + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" + run: cargo clippy --target x86_64-unknown-linux-gnu - name: Linux (linux_android_with_fallback.rs) run: cargo clippy --target x86_64-unknown-linux-gnu - name: NetBSD (netbsd.rs) @@ -93,4 +101,4 @@ jobs: - name: Generate Docs env: RUSTDOCFLAGS: "-Dwarnings --cfg docsrs" - run: cargo doc --no-deps --features custom + run: cargo doc --no-deps --features std diff --git a/Cargo.toml b/Cargo.toml index 2d8baa627..a688779ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,35 +27,27 @@ wasi = { version = "0.13", default-features = false } [target.'cfg(all(windows, not(target_vendor = "win7")))'.dependencies] windows-targets = "0.52" -[target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies] -wasm-bindgen = { version = "0.2.89", default-features = false, optional = true } -js-sys = { version = "0.3", optional = true } -[target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dev-dependencies] +[target.'cfg(all(getrandom_backend = "wasm_js", any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies] +wasm-bindgen = { version = "0.2.89", default-features = false } +js-sys = "0.3" +[target.'cfg(all(getrandom_backend = "wasm_js", getrandom_browser_test, any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dev-dependencies] wasm-bindgen-test = "0.3.39" [features] # Implement std-only traits for getrandom::Error std = [] -# Disable `/dev/urandom` fallback for Linux and Android targets. -# Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). -linux_disable_fallback = [] -# Feature to enable fallback RDRAND-based implementation on x86/x86_64 -rdrand = [] -# Feature to enable JavaScript bindings on wasm*-unknown-unknown -js = ["wasm-bindgen", "js-sys"] -# Feature to enable custom RNG implementations -custom = [] # Unstable feature to support being a libstd dependency rustc-dep-of-std = ["compiler_builtins", "core"] -# Unstable/test-only feature to run wasm-bindgen tests in a browser -test-in-browser = [] -[[test]] -name = "custom" -required-features = ["custom"] +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + 'cfg(getrandom_backend, values("custom", "rdrand", "linux_getrandom", "wasm_js", "esp_idf"))', + 'cfg(getrandom_browser_test)', +] [package.metadata.docs.rs] -features = ["std", "custom"] +features = ["std"] rustdoc-args = ["--cfg", "docsrs"] # workaround for https://github.com/cross-rs/cross/issues/1345 diff --git a/src/custom.rs b/src/custom.rs index 79be7fc26..923b1cf8d 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -1,103 +1,12 @@ //! An implementation which calls out to an externally defined function. -use crate::{util::uninit_slice_fill_zero, Error}; +use crate::Error; use core::{mem::MaybeUninit, 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] -macro_rules! register_custom_getrandom { - ($path:path) => { - // TODO(MSRV 1.37): change to unnamed block - const __GETRANDOM_INTERNAL: () = { - // We use Rust ABI to be safe against potential panics in the passed function. - #[no_mangle] - unsafe fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 { - // Make sure the passed function has the type of getrandom::getrandom - type F = fn(&mut [u8]) -> ::core::result::Result<(), $crate::Error>; - let _: F = $crate::getrandom; - let f: F = $path; - let slice = ::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 [MaybeUninit]) -> Result<(), Error> { extern "Rust" { fn __getrandom_custom(dest: *mut u8, len: usize) -> u32; } - // Previously we always passed a valid, initialized slice to - // `__getrandom_custom`. Ensure `dest` has been initialized for backward - // compatibility with implementations that rely on that (e.g. Rust - // implementations that construct a `&mut [u8]` slice from `dest` and - // `len`). - let dest = uninit_slice_fill_zero(dest); - let ret = unsafe { __getrandom_custom(dest.as_mut_ptr(), dest.len()) }; + let ret = unsafe { __getrandom_custom(dest.as_mut_ptr().cast(), dest.len()) }; match NonZeroU32::new(ret) { None => Ok(()), Some(code) => Err(Error::from(code)), diff --git a/src/lib.rs b/src/lib.rs index 97622ecfb..62c2dab34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,104 +2,88 @@ //! //! # 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 10+ | `*‑windows‑*` | [`ProcessPrng`] -//! | Windows 7 and 8 | `*-win7‑windows‑*` | [`RtlGenRandom`] -//! | macOS | `*‑apple‑darwin` | [`getentropy`][3] +//! | Target | Target Triple | Implementation +//! | ------------------ | ------------------ | -------------- +//! | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` +//! | Windows 10+ | `*‑windows‑*` | [`ProcessPrng`] +//! | Windows 7 and 8 | `*-win7‑windows‑*` | [`RtlGenRandom`] +//! | macOS | `*‑apple‑darwin` | [`getentropy`][3] //! | iOS, tvOS, watchOS | `*‑apple‑ios`, `*-apple-tvos`, `*-apple-watchos` | [`CCRandomGenerateBytes`] -//! | FreeBSD | `*‑freebsd` | [`getrandom`][5] -//! | OpenBSD | `*‑openbsd` | [`getentropy`][7] -//! | NetBSD | `*‑netbsd` | [`getrandom`][16] if available, otherwise [`kern.arandom`][8] -//! | Dragonfly BSD | `*‑dragonfly` | [`getrandom`][9] -//! | Solaris | `*‑solaris` | [`getrandom`][11] (with `GRND_RANDOM`) -//! | illumos | `*‑illumos` | [`getrandom`][12] -//! | Fuchsia OS | `*‑fuchsia` | [`cprng_draw`] -//! | Redox | `*‑redox` | `/dev/urandom` -//! | Haiku | `*‑haiku` | `/dev/urandom` (identical to `/dev/random`) -//! | Hermit | `*-hermit` | [`sys_read_entropy`] -//! | Hurd | `*-hurd-*` | [`getrandom`][17] -//! | SGX | `x86_64‑*‑sgx` | [`RDRAND`] -//! | VxWorks | `*‑wrs‑vxworks‑*` | `randABytes` after checking entropy pool initialization with `randSecure` -//! | ESP-IDF | `*‑espidf` | [`esp_fill_random`] -//! | Emscripten | `*‑emscripten` | [`getentropy`][13] -//! | WASI 0.1 | `wasm32‑wasip1` | [`random_get`] -//! | WASI 0.2 | `wasm32‑wasip2` | [`get-random-u64`] -//! | Web Browser and Node.js | `wasm*‑*‑unknown` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js, see [WebAssembly support] -//! | SOLID | `*-kmc-solid_*` | `SOLID_RNG_SampleRandomBytes` -//! | Nintendo 3DS | `*-nintendo-3ds` | [`getrandom`][18] -//! | PS Vita | `*-vita-*` | [`getentropy`][13] -//! | QNX Neutrino | `*‑nto-qnx*` | [`/dev/urandom`][14] (identical to `/dev/random`) -//! | AIX | `*-ibm-aix` | [`/dev/urandom`][15] +//! | FreeBSD | `*‑freebsd` | [`getrandom`][5] +//! | OpenBSD | `*‑openbsd` | [`getentropy`][7] +//! | NetBSD | `*‑netbsd` | [`getrandom`][16] if available, otherwise [`kern.arandom`][8] +//! | Dragonfly BSD | `*‑dragonfly` | [`getrandom`][9] +//! | Solaris | `*‑solaris` | [`getrandom`][11] (with `GRND_RANDOM`) +//! | illumos | `*‑illumos` | [`getrandom`][12] +//! | Fuchsia OS | `*‑fuchsia` | [`cprng_draw`] +//! | Redox | `*‑redox` | `/dev/urandom` +//! | Haiku | `*‑haiku` | `/dev/urandom` (identical to `/dev/random`) +//! | Hermit | `*-hermit` | [`sys_read_entropy`] +//! | Hurd | `*-hurd-*` | [`getrandom`][17] +//! | SGX | `x86_64‑*‑sgx` | [`RDRAND`] +//! | VxWorks | `*‑wrs‑vxworks‑*` | `randABytes` after checking entropy pool initialization with `randSecure` +//! | Emscripten | `*‑emscripten` | [`getentropy`][13] +//! | WASI 0.1 | `wasm32‑wasip1` | [`random_get`] +//! | WASI 0.2 | `wasm32‑wasip2` | [`get-random-u64`] +//! | SOLID | `*-kmc-solid_*` | `SOLID_RNG_SampleRandomBytes` +//! | Nintendo 3DS | `*-nintendo-3ds` | [`getrandom`][18] +//! | PS Vita | `*-vita-*` | [`getentropy`][13] +//! | QNX Neutrino | `*‑nto-qnx*` | [`/dev/urandom`][14] (identical to `/dev/random`) +//! | AIX | `*-ibm-aix` | [`/dev/urandom`][15] //! //! Pull Requests that add support for new targets to `getrandom` are always welcome. //! -//! ## Unsupported targets +//! ## Opt-in backends //! -//! 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. +//! `getrandom` also provides optional backends which can be enabled using `getrandom_backend` +//! configuration flag: //! -//! 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). +//! | Backend name | Target | Target Triple | Implementation +//! | ----------------- | -------------------- | -------------------- | -------------- +//! | `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). +//! | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction +//! | `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low quality entropy without proper hardware configuration! +//! | `wasm_js` | Web Browser, Node.js | `wasm*‑*‑unknown` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js (see [WebAssembly support]) +//! | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) //! -//! ## `/dev/urandom` fallback on Linux and Android +//! The configuration flag can be enabled either by specifying the `rustflags` field in +//! [`.cargo/config.toml`] (note that it can be done on a per-target basis), or by using +//! `RUSTFLAGS` environment variable: //! -//! On Linux targets the fallback is present only if either `target_env` is `musl`, -//! or `target_arch` is one of the following: `aarch64`, `arm`, `powerpc`, `powerpc64`, -//! `s390x`, `x86`, `x86_64`. Other supported targets [require][platform-support] -//! kernel versions which support `getrandom` system call, so fallback is not needed. -//! -//! On Android targets the fallback is present only for the following `target_arch`es: -//! `aarch64`, `arm`, `x86`, `x86_64`. Other `target_arch`es (e.g. RISC-V) require -//! sufficiently high API levels. +//! ```sh +//! RUSTFLAGS='getrandom_backend="linux_getrandom"' cargo build +//! ``` //! -//! The fallback can be disabled by enabling the `linux_disable_fallback` crate feature. -//! Note that doing so will bump minimum supported Linux kernel version to 3.17 and -//! Android API level to 23 (Marshmallow). +//! Enabling an opt-in backend will replace backend used by default. Doing it for a wrong target +//! (e.g. using `linux_getrandom` while compiling for a Windows target) will result +//! in a compilation error. Be extremely carefull while using opt-in backends, since incorrect +//! configuration may result in vulnerable or in always panicking applications. //! -//! ### RDRAND on x86 +//! Note that using an opt-in backend in a library (e.g. for tests or benchmarks) +//! WILL NOT have any effect on its downstream users. //! -//! *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. +//! [`.cargo/config.toml`]: https://doc.rust-lang.org/cargo/reference/config.html //! //! ### 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). +//! This crate fully supports the [WASI] and [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 should be used (or if JavaScript is available at all). //! -//! Instead, *if the `js` Cargo feature is enabled*, this crate will assume +//! Instead, *if the `wasm_js` backend 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`] toolchain. +//! [described above](#opt-in-backends) using the [`wasm-bindgen`] toolchain. //! -//! To enable the `js` Cargo feature, add the following to the `dependencies` -//! section in your `Cargo.toml` file: +//! To enable the `wasm_js` backend, you can add the following lines to your +//! project's `.cargo/config.toml` file: //! ```toml -//! [dependencies] -//! getrandom = { version = "0.2", features = ["js"] } +//! [target.wasm32-unknown-unknown] +//! rustflags = ['--cfg', 'getrandom_backend="wasm_js"'] //! ``` //! -//! This can be done even if `getrandom` is not a direct dependency. Cargo -//! allows crates to enable features for indirect dependencies. -//! -//! This feature should only be enabled for binary, test, or benchmark crates. -//! Library crates should generally not enable this feature, leaving such a -//! decision to *users* of their library. Also, libraries should not introduce -//! their own `js` features *just* to enable `getrandom`'s `js` feature. -//! -//! This feature has no effect on targets other than `wasm32-unknown-unknown`. -//! //! #### Node.js ES module support //! //! Node.js supports both [CommonJS modules] and [ES modules]. Due to @@ -112,6 +96,42 @@ //! ``` //! This crate will then use the provided `webcrypto` implementation. //! +//! ### Custom backend +//! +//! If this crate does not support your target out of box or you have to use +//! a non-default entropy source, then you can provide a custom implementation. +//! You need to enable the custom backend as described in the [configuration flags] +//! section. Next, you need to define an `extern` function with the following +//! signature: +//! +//! ``` +//! #[no_mangle] +//! unsafe fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 { +//! todo!() +//! } +//! ``` +//! +//! This function ideally should be defined in the root crate of your project, +//! e.g. in your `main.rs`. This function MUST be defined only once for your +//! project, i.e. upstream library crates SHOULD NOT define it outside of +//! tests and benchmarks. Improper configuration of this backend may result +//! in linking errors. +//! +//! The function accepts pointer to buffer which should be filled with random +//! data and length in bytes. Note that the buffer MAY be uninitialized. +//! On success the function should return 0 and fully fill the input buffer, +//! every other return result will be interpreted as an error code. +//! +//! If you are confident that `getrandom` is not used in your project, but +//! it gets pulled nevertheless by one of your dependencies, then you can +//! use the following custom backend which always returns "unsupported" error: +//! ``` +//! #[no_mangle] +//! unsafe fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 { +//! getrandom::Error::UNSUPPORTED.code().get() +//! } +//! ``` +//! //! ### Platform Support //! This crate generally supports the same operating system and platform versions //! that the Rust standard library does. Additional targets may be supported using @@ -122,17 +142,20 @@ //! `getrandom` may create new patch releases (`0.N.x`) that remove support for //! outdated platform versions. //! -//! ### Custom implementations +//! ## `/dev/urandom` fallback on Linux and Android +//! +//! On Linux targets the fallback is present only if either `target_env` is `musl`, +//! or `target_arch` is one of the following: `aarch64`, `arm`, `powerpc`, `powerpc64`, +//! `s390x`, `x86`, `x86_64`. Other supported targets [require][platform-support] +//! kernel versions which support `getrandom` system call, so fallback is not needed. //! -//! 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. +//! On Android targets the fallback is present only for the following `target_arch`es: +//! `aarch64`, `arm`, `x86`, `x86_64`. Other `target_arch`es (e.g. RISC-V) require +//! sufficiently high API levels. //! -//! 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. +//! The fallback can be disabled by enabling the `linux_getrandom` opt-in backend. +//! Note that doing so will bump minimum supported Linux kernel version to 3.17 and +//! Android API level to 23 (Marshmallow). //! //! ## Early boot //! @@ -195,12 +218,16 @@ //! [`random_get`]: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-buf_len-size---errno //! [`get-random-u64`]: https://github.com/WebAssembly/WASI/blob/v0.2.1/wasip2/random/random.wit#L23-L28 //! [WebAssembly support]: #webassembly-support +//! [configuration flags]: #configuration-flags +//! [custom backend]: #custom-backend //! [`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen //! [`module`]: https://rustwasm.github.io/wasm-bindgen/reference/attributes/on-js-imports/module.html //! [CommonJS modules]: https://nodejs.org/api/modules.html //! [ES modules]: https://nodejs.org/api/esm.html //! [`sys_read_entropy`]: https://github.com/hermit-os/kernel/blob/315f58ff5efc81d9bf0618af85a59963ff55f8b1/src/syscalls/entropy.rs#L47-L55 //! [platform-support]: https://doc.rust-lang.org/stable/rustc/platform-support.html +//! [WASI]: https://github.com/CraneStation/wasi +//! [Emscripten]: https://www.hellorust.com/setup/emscripten/ #![doc( html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", @@ -214,20 +241,17 @@ #[macro_use] extern crate cfg_if; -use crate::util::{slice_as_uninit_mut, slice_assume_init_mut}; use core::mem::MaybeUninit; mod error; mod lazy; 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; +use crate::util::{slice_as_uninit_mut, slice_assume_init_mut}; // System-specific implementations. // @@ -237,7 +261,34 @@ pub use crate::error::Error; // The function MUST NOT ever write uninitialized bytes into `dest`, // regardless of what value it returns. cfg_if! { - if #[cfg(any(target_os = "haiku", target_os = "redox", target_os = "nto", target_os = "aix"))] { + if #[cfg(getrandom_backend = "custom")] { + #[path = "custom.rs"] mod imp; + } else if #[cfg(getrandom_backend = "linux_getrandom")] { + #[cfg(not(any(target_os = "android", target_os = "linux")))] + compile_error!("`linux_getrandom` backend can be enabled only for Linux/Android targets!"); + mod util_libc; + #[path = "linux_android.rs"] mod imp; + } else if #[cfg(getrandom_backend = "rdrand")] { + #[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))] + compile_error!("`rdrand` backend can be enabled only for x86 and x86-64 targets!"); + #[path = "rdrand.rs"] mod imp; + } else if #[cfg(getrandom_backend = "wasm_js")] { + #[cfg(not(all( + any(target_arch = "wasm32", target_arch = "wasm64"), + target_os = "unknown", + )))] + compile_error!("`wasm_js` backend can be enabled only on OS-less WASM targets!"); + #[path = "js.rs"] mod imp; + } else if #[cfg(getrandom_backend = "esp_idf")] { + #[cfg(not(target_os = "espidf"))] + compile_error!("`esp_idf` backend can be enabled only for ESP-IDF targets!"); + #[path = "espidf.rs"] mod imp; + } else if #[cfg(any( + target_os = "haiku", + target_os = "redox", + target_os = "nto", + target_os = "aix", + ))] { mod util_libc; #[path = "use_file.rs"] mod imp; } else if #[cfg(any( @@ -259,45 +310,42 @@ cfg_if! { ))] { mod util_libc; #[path = "getrandom.rs"] mod imp; - } else if #[cfg(all( - not(feature = "linux_disable_fallback"), - 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", - ), + } 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", - ), - ) ), + // 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 util_libc; mod use_file; @@ -314,7 +362,12 @@ cfg_if! { #[path = "netbsd.rs"] mod imp; } else if #[cfg(target_os = "fuchsia")] { #[path = "fuchsia.rs"] mod imp; - } else if #[cfg(any(target_os = "ios", target_os = "visionos", target_os = "watchos", target_os = "tvos"))] { + } else if #[cfg(any( + target_os = "ios", + target_os = "visionos", + target_os = "watchos", + target_os = "tvos", + ))] { #[path = "apple-other.rs"] mod imp; } else if #[cfg(all(target_arch = "wasm32", target_os = "wasi"))] { #[path = "wasi.rs"] mod imp; @@ -325,32 +378,24 @@ cfg_if! { #[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(all(windows, target_vendor = "win7"))] { #[path = "windows7.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", - any(target_arch = "wasm32", target_arch = "wasm64"), - target_os = "unknown"))] { - #[path = "js.rs"] mod imp; - } else if #[cfg(feature = "custom")] { - use custom as imp; - } else if #[cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), - target_os = "unknown"))] { + } else if #[cfg(all( + any(target_arch = "wasm32", target_arch = "wasm64"), + target_os = "unknown", + ))] { compile_error!("the wasm*-unknown-unknown targets are not supported by \ - default, you may need to enable the \"js\" feature. \ - For more information see: \ + default, you may need to enable the \"wasm_js\" \ + configuration flag. 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"); + compile_error!("target is not supported. You may need to define \ + a custom backend see: \ + https://docs.rs/getrandom/#custom-backends"); } } diff --git a/tests/common/mod.rs b/tests/common/mod.rs deleted file mode 100644 index 666f7f570..000000000 --- a/tests/common/mod.rs +++ /dev/null @@ -1,100 +0,0 @@ -use super::getrandom_impl; - -#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] -use wasm_bindgen_test::wasm_bindgen_test as test; - -#[cfg(feature = "test-in-browser")] -wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); - -#[test] -fn test_zero() { - // Test that APIs are happy with zero-length requests - getrandom_impl(&mut [0u8; 0]).unwrap(); -} - -// Return the number of bits in which s1 and s2 differ -#[cfg(not(feature = "custom"))] -fn num_diff_bits(s1: &[u8], s2: &[u8]) -> usize { - assert_eq!(s1.len(), s2.len()); - s1.iter() - .zip(s2.iter()) - .map(|(a, b)| (a ^ b).count_ones() as usize) - .sum() -} - -// Tests the quality of calling getrandom on two large buffers -#[test] -#[cfg(not(feature = "custom"))] -fn test_diff() { - let mut v1 = [0u8; 1000]; - getrandom_impl(&mut v1).unwrap(); - - let mut v2 = [0u8; 1000]; - getrandom_impl(&mut v2).unwrap(); - - // Between 3.5 and 4.5 bits per byte should differ. Probability of failure: - // ~ 2^(-94) = 2 * CDF[BinomialDistribution[8000, 0.5], 3500] - let d = num_diff_bits(&v1, &v2); - assert!(d > 3500); - assert!(d < 4500); -} - -// Tests the quality of calling getrandom repeatedly on small buffers -#[test] -#[cfg(not(feature = "custom"))] -fn test_small() { - // For each buffer size, get at least 256 bytes and check that between - // 3 and 5 bits per byte differ. Probability of failure: - // ~ 2^(-91) = 64 * 2 * CDF[BinomialDistribution[8*256, 0.5], 3*256] - for size in 1..=64 { - let mut num_bytes = 0; - let mut diff_bits = 0; - while num_bytes < 256 { - let mut s1 = vec![0u8; size]; - getrandom_impl(&mut s1).unwrap(); - let mut s2 = vec![0u8; size]; - getrandom_impl(&mut s2).unwrap(); - - num_bytes += size; - diff_bits += num_diff_bits(&s1, &s2); - } - assert!(diff_bits > 3 * num_bytes); - assert!(diff_bits < 5 * num_bytes); - } -} - -#[test] -fn test_huge() { - let mut huge = [0u8; 100_000]; - getrandom_impl(&mut huge).unwrap(); -} - -// On WASM, the thread API always fails/panics -#[cfg(not(target_arch = "wasm32"))] -#[test] -fn test_multithreading() { - extern crate std; - use std::{sync::mpsc::channel, thread, vec}; - - let mut txs = vec![]; - for _ in 0..20 { - let (tx, rx) = channel(); - txs.push(tx); - - thread::spawn(move || { - // wait until all the tasks are ready to go. - rx.recv().unwrap(); - let mut v = [0u8; 1000]; - - for _ in 0..100 { - getrandom_impl(&mut v).unwrap(); - thread::yield_now(); - } - }); - } - - // start all the tasks - for tx in txs.iter() { - tx.send(()).unwrap(); - } -} diff --git a/tests/custom.rs b/tests/custom.rs deleted file mode 100644 index 30934e941..000000000 --- a/tests/custom.rs +++ /dev/null @@ -1,52 +0,0 @@ -use core::num::NonZeroU32; -use getrandom::{getrandom, register_custom_getrandom, Error}; -#[cfg(all(target_family = "wasm", target_os = "unknown"))] -use wasm_bindgen_test::wasm_bindgen_test as test; - -const LEN7_CODE: u32 = Error::CUSTOM_START + 7; -// Returns a custom error if input is length 7, otherwise fills with 0x55. -fn mock_rng(buf: &mut [u8]) -> Result<(), Error> { - // `getrandom` guarantees it will not call any implementation if the output - // buffer is empty. - assert!(!buf.is_empty()); - if buf.len() == 7 { - return Err(NonZeroU32::new(LEN7_CODE).unwrap().into()); - } - buf.fill(0x55); - Ok(()) -} - -// Test registering a custom implementation, even on supported platforms. -register_custom_getrandom!(mock_rng); - -// Invoking with an empty buffer should never call the custom implementation. -#[test] -fn custom_empty() { - getrandom(&mut []).unwrap(); -} - -// On a supported platform, make sure the custom implementation isn't used. We -// test on a few common platfroms, rather than duplicating the lib.rs logic. -#[cfg(any( - target_os = "linux", - target_os = "windows", - target_os = "macos", - target_os = "espidf", - target_os = "wasi", - all(target_family = "wasm", target_os = "unknown", feature = "js"), -))] -#[test] -fn custom_not_used() { - getrandom(&mut [0; 7]).unwrap(); -} -// On an unsupported platform, make sure the custom implementation is used. -#[cfg(all(target_family = "wasm", target_os = "unknown", not(feature = "js")))] -#[test] -fn custom_used() { - let err = getrandom(&mut [0; 7]).unwrap_err(); - assert_eq!(err.code().get(), LEN7_CODE); - - let mut buf = [0; 12]; - getrandom(&mut buf).unwrap(); - assert_eq!(buf, [0x55; 12]); -} diff --git a/tests/mod.rs b/tests/mod.rs new file mode 100644 index 000000000..6738c0e13 --- /dev/null +++ b/tests/mod.rs @@ -0,0 +1,182 @@ +use getrandom::getrandom; + +#[cfg(getrandom_browser_test)] +use wasm_bindgen_test::wasm_bindgen_test as test; +#[cfg(getrandom_browser_test)] +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + +#[test] +fn test_zero() { + // Test that APIs are happy with zero-length requests + getrandom(&mut [0u8; 0]).unwrap(); +} + +// Return the number of bits in which s1 and s2 differ +fn num_diff_bits(s1: &[u8], s2: &[u8]) -> usize { + assert_eq!(s1.len(), s2.len()); + s1.iter() + .zip(s2.iter()) + .map(|(a, b)| (a ^ b).count_ones() as usize) + .sum() +} + +// Tests the quality of calling getrandom on two large buffers +#[test] +fn test_diff() { + let mut v1 = [0u8; 1000]; + getrandom(&mut v1).unwrap(); + + let mut v2 = [0u8; 1000]; + getrandom(&mut v2).unwrap(); + + // Between 3.5 and 4.5 bits per byte should differ. Probability of failure: + // ~ 2^(-94) = 2 * CDF[BinomialDistribution[8000, 0.5], 3500] + let d = num_diff_bits(&v1, &v2); + assert!(d > 3500); + assert!(d < 4500); +} + +// Tests the quality of calling getrandom repeatedly on small buffers +#[test] +fn test_small() { + let mut buf1 = [0u8; 64]; + let mut buf2 = [0u8; 64]; + // For each buffer size, get at least 256 bytes and check that between + // 3 and 5 bits per byte differ. Probability of failure: + // ~ 2^(-91) = 64 * 2 * CDF[BinomialDistribution[8*256, 0.5], 3*256] + for size in 1..=64 { + let mut num_bytes = 0; + let mut diff_bits = 0; + while num_bytes < 256 { + let s1 = &mut buf1[..size]; + let s2 = &mut buf2[..size]; + + getrandom(s1).unwrap(); + getrandom(s2).unwrap(); + + num_bytes += size; + diff_bits += num_diff_bits(s1, s2); + } + assert!(diff_bits > 3 * num_bytes); + assert!(diff_bits < 5 * num_bytes); + } +} + +#[test] +fn test_huge() { + let mut huge = [0u8; 100_000]; + getrandom(&mut huge).unwrap(); +} + +#[test] +#[cfg_attr( + target_arch = "wasm32", + ignore = "The thread API always fails/panics on WASM" +)] +fn test_multithreading() { + extern crate std; + use std::{sync::mpsc::channel, thread, vec}; + + let mut txs = vec![]; + for _ in 0..20 { + let (tx, rx) = channel(); + txs.push(tx); + + thread::spawn(move || { + // wait until all the tasks are ready to go. + rx.recv().unwrap(); + let mut v = [0u8; 1000]; + + for _ in 0..100 { + getrandom(&mut v).unwrap(); + thread::yield_now(); + } + }); + } + + // start all the tasks + for tx in txs.iter() { + tx.send(()).unwrap(); + } +} + +#[cfg(getrandom_backend = "custom")] +mod custom { + struct Xoshiro128PlusPlus { + s: [u32; 4], + } + + impl Xoshiro128PlusPlus { + fn new(mut seed: u64) -> Self { + const PHI: u64 = 0x9e3779b97f4a7c15; + let mut s = [0u32; 4]; + for val in s.iter_mut() { + seed = seed.wrapping_add(PHI); + let mut z = seed; + z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9); + z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb); + z = z ^ (z >> 31); + *val = z as u32; + } + Self { s } + } + + fn next_u32(&mut self) -> u32 { + let res = self.s[0] + .wrapping_add(self.s[3]) + .rotate_left(7) + .wrapping_add(self.s[0]); + + let t = self.s[1] << 9; + + self.s[2] ^= self.s[0]; + self.s[3] ^= self.s[1]; + self.s[1] ^= self.s[2]; + self.s[0] ^= self.s[3]; + + self.s[2] ^= t; + + self.s[3] = self.s[3].rotate_left(11); + + res + } + } + + // This implementation uses current timestamp as a PRNG seed. + // + // WARNING: this custom implementation is for testing purposes ONLY! + #[no_mangle] + unsafe fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 { + use std::time::{SystemTime, UNIX_EPOCH}; + + assert_ne!(len, 0); + + if len == 142 { + return getrandom::Error::CUSTOM_START + 142; + } + + let dest_u32 = dest.cast::(); + let ts = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + let mut rng = Xoshiro128PlusPlus::new(ts.as_nanos() as u64); + for i in 0..len / 4 { + let val = rng.next_u32(); + core::ptr::write_unaligned(dest_u32.add(i), val); + } + if len % 4 != 0 { + let start = 4 * (len / 4); + for i in start..len { + let val = rng.next_u32(); + core::ptr::write_unaligned(dest.add(i), val as u8); + } + } + 0 + } + + // Test that enabling the custom feature indeed uses the custom implementation + #[test] + fn test_custom() { + let mut buf = [0u8; 142]; + let res = getrandom::getrandom(&mut buf); + assert!(res.is_err()); + } +} diff --git a/tests/normal.rs b/tests/normal.rs deleted file mode 100644 index 5fff13b38..000000000 --- a/tests/normal.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Don't test on custom wasm32-unknown-unknown -#![cfg(not(all( - target_arch = "wasm32", - target_os = "unknown", - feature = "custom", - not(feature = "js") -)))] - -// Use the normal getrandom implementation on this architecture. -use getrandom::getrandom as getrandom_impl; -mod common; diff --git a/tests/rdrand.rs b/tests/rdrand.rs deleted file mode 100644 index a355c31ee..000000000 --- a/tests/rdrand.rs +++ /dev/null @@ -1,22 +0,0 @@ -// We only test the RDRAND-based RNG source on supported architectures. -#![cfg(any(target_arch = "x86_64", target_arch = "x86"))] - -// rdrand.rs expects to be part of the getrandom main crate, so we need these -// additional imports to get rdrand.rs to compile. -use getrandom::Error; -#[macro_use] -extern crate cfg_if; -#[path = "../src/lazy.rs"] -mod lazy; -#[path = "../src/rdrand.rs"] -mod rdrand; -#[path = "../src/util.rs"] -mod util; - -// The rdrand implementation has the signature of getrandom_uninit(), but our -// tests expect getrandom_impl() to have the signature of getrandom(). -fn getrandom_impl(dest: &mut [u8]) -> Result<(), Error> { - rdrand::getrandom_inner(unsafe { util::slice_as_uninit_mut(dest) })?; - Ok(()) -} -mod common; From 286e48666796b7c901021716a8def8f122b40013 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 9 Oct 2024 16:03:26 +0300 Subject: [PATCH 033/201] Test `getrandom_uninit` (#505) --- tests/mod.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/tests/mod.rs b/tests/mod.rs index 6738c0e13..951b65dcd 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -1,4 +1,5 @@ -use getrandom::getrandom; +use core::mem::MaybeUninit; +use getrandom::{getrandom, getrandom_uninit}; #[cfg(getrandom_browser_test)] use wasm_bindgen_test::wasm_bindgen_test as test; @@ -9,6 +10,8 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); fn test_zero() { // Test that APIs are happy with zero-length requests getrandom(&mut [0u8; 0]).unwrap(); + let res = getrandom_uninit(&mut []).unwrap(); + assert!(res.is_empty()); } // Return the number of bits in which s1 and s2 differ @@ -20,34 +23,51 @@ fn num_diff_bits(s1: &[u8], s2: &[u8]) -> usize { .sum() } +// TODO: use `[const { MaybeUninit::uninit() }; N]` after MSRV is bumped to 1.79+ +// or `MaybeUninit::uninit_array` +fn uninit_vec(n: usize) -> Vec> { + vec![MaybeUninit::uninit(); n] +} + // Tests the quality of calling getrandom on two large buffers #[test] fn test_diff() { - let mut v1 = [0u8; 1000]; + const N: usize = 1000; + let mut v1 = [0u8; N]; + let mut v2 = [0u8; N]; getrandom(&mut v1).unwrap(); - - let mut v2 = [0u8; 1000]; getrandom(&mut v2).unwrap(); + let mut t1 = uninit_vec(N); + let mut t2 = uninit_vec(N); + let r1 = getrandom_uninit(&mut t1).unwrap(); + let r2 = getrandom_uninit(&mut t2).unwrap(); + assert_eq!(r1.len(), N); + assert_eq!(r2.len(), N); + // Between 3.5 and 4.5 bits per byte should differ. Probability of failure: // ~ 2^(-94) = 2 * CDF[BinomialDistribution[8000, 0.5], 3500] - let d = num_diff_bits(&v1, &v2); - assert!(d > 3500); - assert!(d < 4500); + let d1 = num_diff_bits(&v1, &v2); + assert!(d1 > 3500); + assert!(d1 < 4500); + let d2 = num_diff_bits(r1, r2); + assert!(d2 > 3500); + assert!(d2 < 4500); } -// Tests the quality of calling getrandom repeatedly on small buffers #[test] fn test_small() { - let mut buf1 = [0u8; 64]; - let mut buf2 = [0u8; 64]; + const N: usize = 64; // For each buffer size, get at least 256 bytes and check that between // 3 and 5 bits per byte differ. Probability of failure: // ~ 2^(-91) = 64 * 2 * CDF[BinomialDistribution[8*256, 0.5], 3*256] - for size in 1..=64 { + for size in 1..=N { let mut num_bytes = 0; let mut diff_bits = 0; while num_bytes < 256 { + let mut buf1 = [0u8; N]; + let mut buf2 = [0u8; N]; + let s1 = &mut buf1[..size]; let s2 = &mut buf2[..size]; @@ -62,12 +82,50 @@ fn test_small() { } } +// Tests the quality of calling getrandom repeatedly on small buffers +#[test] +fn test_small_uninit() { + const N: usize = 64; + // For each buffer size, get at least 256 bytes and check that between + // 3 and 5 bits per byte differ. Probability of failure: + // ~ 2^(-91) = 64 * 2 * CDF[BinomialDistribution[8*256, 0.5], 3*256] + for size in 1..=N { + let mut num_bytes = 0; + let mut diff_bits = 0; + while num_bytes < 256 { + let mut buf1 = uninit_vec(N); + let mut buf2 = uninit_vec(N); + + let s1 = &mut buf1[..size]; + let s2 = &mut buf2[..size]; + + let r1 = getrandom_uninit(s1).unwrap(); + let r2 = getrandom_uninit(s2).unwrap(); + assert_eq!(r1.len(), size); + assert_eq!(r2.len(), size); + + num_bytes += size; + diff_bits += num_diff_bits(r1, r2); + } + assert!(diff_bits > 3 * num_bytes); + assert!(diff_bits < 5 * num_bytes); + } +} + #[test] fn test_huge() { let mut huge = [0u8; 100_000]; getrandom(&mut huge).unwrap(); } +#[test] +fn test_huge_uninit() { + const N: usize = 100_000; + let mut huge = uninit_vec(N); + let res = getrandom_uninit(&mut huge).unwrap(); + assert_eq!(res.len(), N); +} + #[test] #[cfg_attr( target_arch = "wasm32", From 0f787bc7faee7b782cd98a06833507c47ff0b9c8 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 9 Oct 2024 16:04:52 +0300 Subject: [PATCH 034/201] Test file fallback on Linux (#506) Introduces new `getrandom_test_linux_fallback` configuration flag which forces `is_getrandom_available` to always return `false`. This flag is used in CI to test that file fallback works correctly in the `linux_android_with_fallback` backend. --- .github/workflows/tests.yml | 3 +++ Cargo.toml | 1 + src/linux_android_with_fallback.rs | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 49828c8ee..885e24580 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -71,6 +71,9 @@ jobs: - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback + run: cargo test --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" run: cargo test --features=std diff --git a/Cargo.toml b/Cargo.toml index a688779ee..83e22501f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ level = "warn" check-cfg = [ 'cfg(getrandom_backend, values("custom", "rdrand", "linux_getrandom", "wasm_js", "esp_idf"))', 'cfg(getrandom_browser_test)', + 'cfg(getrandom_test_linux_fallback)', ] [package.metadata.docs.rs] diff --git a/src/linux_android_with_fallback.rs b/src/linux_android_with_fallback.rs index b633faad5..ec7a12166 100644 --- a/src/linux_android_with_fallback.rs +++ b/src/linux_android_with_fallback.rs @@ -19,7 +19,9 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { } fn is_getrandom_available() -> bool { - if linux_android::getrandom_syscall(&mut []) < 0 { + if cfg!(getrandom_test_linux_fallback) { + false + } else if linux_android::getrandom_syscall(&mut []) < 0 { match last_os_error().raw_os_error() { Some(libc::ENOSYS) => false, // No kernel support // The fallback on EPERM is intentionally not done on Android since this workaround From 387248f917f434d537d62a6b48d2f83e79d6b87a Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 9 Oct 2024 16:06:31 +0300 Subject: [PATCH 035/201] Remove `impl From for Error` and `Error::code` (#507) Also adds `Error::{new_custom, new_internal}` methods and changes return type of `__getrandom_custom` to `Result<(), getrandom::Error>`. --- CHANGELOG.md | 3 +++ src/custom.rs | 10 +++------ src/error.rs | 59 +++++++++++++++++++++++---------------------------- src/lib.rs | 10 ++++++--- tests/mod.rs | 8 ++++--- 5 files changed, 44 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b781ac15d..196350e29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Breaking Changes - Update MSRV to 1.60 [#472] - Remove support of the `wasm32-wasi` target (use `wasm32-wasip1` or `wasm32-wasip2` instead) [#499] +- Remove `impl From for Error` and `Error::code` method [#507] ### Changed - Switch to `futex` on Linux and to `nanosleep`-based wait loop on other targets @@ -16,10 +17,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `wasm32-wasip1` and `wasm32-wasip2` support [#499] +- `Error::new_custom` method [#507] [#472]: https://github.com/rust-random/getrandom/pull/472 [#490]: https://github.com/rust-random/getrandom/pull/490 [#499]: https://github.com/rust-random/getrandom/pull/499 +[#507]: https://github.com/rust-random/getrandom/pull/507 ## [0.2.15] - 2024-05-06 ### Added diff --git a/src/custom.rs b/src/custom.rs index 923b1cf8d..fc216e08c 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -1,14 +1,10 @@ //! An implementation which calls out to an externally defined function. use crate::Error; -use core::{mem::MaybeUninit, num::NonZeroU32}; +use core::mem::MaybeUninit; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { extern "Rust" { - fn __getrandom_custom(dest: *mut u8, len: usize) -> u32; - } - let ret = unsafe { __getrandom_custom(dest.as_mut_ptr().cast(), dest.len()) }; - match NonZeroU32::new(ret) { - None => Ok(()), - Some(code) => Err(Error::from(code)), + fn __getrandom_custom(dest: *mut u8, len: usize) -> Result<(), Error>; } + unsafe { __getrandom_custom(dest.as_mut_ptr().cast(), dest.len()) } } diff --git a/src/error.rs b/src/error.rs index 5eff99eb7..1c1584395 100644 --- a/src/error.rs +++ b/src/error.rs @@ -20,44 +20,38 @@ use core::{fmt, num::NonZeroU32}; #[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); + pub const UNSUPPORTED: Error = Self::new_internal(0); /// The platform-specific `errno` returned a non-positive value. - pub const ERRNO_NOT_POSITIVE: Error = internal_error(1); + pub const ERRNO_NOT_POSITIVE: Error = Self::new_internal(1); /// Encountered an unexpected situation which should not happen in practice. - pub const UNEXPECTED: Error = internal_error(2); + pub const UNEXPECTED: Error = Self::new_internal(2); /// Call to [`CCRandomGenerateBytes`](https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html) failed /// on iOS, tvOS, or waatchOS. // TODO: Update this constant name in the next breaking release. - pub const IOS_SEC_RANDOM: Error = internal_error(3); + pub const IOS_SEC_RANDOM: Error = Self::new_internal(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); + pub const WINDOWS_RTL_GEN_RANDOM: Error = Self::new_internal(4); /// RDRAND instruction failed due to a hardware issue. - pub const FAILED_RDRAND: Error = internal_error(5); + pub const FAILED_RDRAND: Error = Self::new_internal(5); /// RDRAND instruction unsupported on this target. - pub const NO_RDRAND: Error = internal_error(6); + pub const NO_RDRAND: Error = Self::new_internal(6); /// The environment does not support the Web Crypto API. - pub const WEB_CRYPTO: Error = internal_error(7); + pub const WEB_CRYPTO: Error = Self::new_internal(7); /// Calling Web Crypto API `crypto.getRandomValues` failed. - pub const WEB_GET_RANDOM_VALUES: Error = internal_error(8); + pub const WEB_GET_RANDOM_VALUES: Error = Self::new_internal(8); /// On VxWorks, call to `randSecure` failed (random number generator is not yet initialized). - pub const VXWORKS_RAND_SECURE: Error = internal_error(11); + pub const VXWORKS_RAND_SECURE: Error = Self::new_internal(11); /// Node.js does not have the `crypto` CommonJS module. - pub const NODE_CRYPTO: Error = internal_error(12); + pub const NODE_CRYPTO: Error = Self::new_internal(12); /// Calling Node.js function `crypto.randomFillSync` failed. - pub const NODE_RANDOM_FILL_SYNC: Error = internal_error(13); + pub const NODE_RANDOM_FILL_SYNC: Error = Self::new_internal(13); /// Called from an ES module on Node.js. This is unsupported, see: /// . - pub const NODE_ES_MODULE: Error = internal_error(14); + pub const NODE_ES_MODULE: Error = Self::new_internal(14); /// Calling Windows ProcessPrng failed. - pub const WINDOWS_PROCESS_PRNG: Error = internal_error(15); + pub const WINDOWS_PROCESS_PRNG: Error = Self::new_internal(15); /// Codes below this point represent OS Errors (i.e. positive i32 values). /// Codes at or above this point, but below [`Error::CUSTOM_START`] are @@ -108,13 +102,18 @@ impl Error { } } - /// 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 + /// 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 a u32. + let code = Error::CUSTOM_START + (n as u32); + Error(unsafe { NonZeroU32::new_unchecked(code) }) + } + + /// Creates a new instance of an `Error` from a particular internal error code. + const fn new_internal(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) }) } } @@ -153,12 +152,6 @@ impl fmt::Display for Error { } } -impl From 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"), diff --git a/src/lib.rs b/src/lib.rs index 62c2dab34..cab0c69e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,8 +105,10 @@ //! signature: //! //! ``` +//! use getrandom::Error; +//! //! #[no_mangle] -//! unsafe fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 { +//! unsafe extern "Rust" fn __getrandom_custom(dest: *mut u8, len: usize) -> Result<(), Error> { //! todo!() //! } //! ``` @@ -126,9 +128,11 @@ //! it gets pulled nevertheless by one of your dependencies, then you can //! use the following custom backend which always returns "unsupported" error: //! ``` +//! use getrandom::Error; +//! //! #[no_mangle] -//! unsafe fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 { -//! getrandom::Error::UNSUPPORTED.code().get() +//! unsafe extern "Rust" fn __getrandom_custom(dest: *mut u8, len: usize) -> Result<(), Error> { +//! Err(Error::UNSUPPORTED) //! } //! ``` //! diff --git a/tests/mod.rs b/tests/mod.rs index 951b65dcd..33083df55 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -160,6 +160,8 @@ fn test_multithreading() { #[cfg(getrandom_backend = "custom")] mod custom { + use getrandom::Error; + struct Xoshiro128PlusPlus { s: [u32; 4], } @@ -204,13 +206,13 @@ mod custom { // // WARNING: this custom implementation is for testing purposes ONLY! #[no_mangle] - unsafe fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 { + unsafe extern "Rust" fn __getrandom_custom(dest: *mut u8, len: usize) -> Result<(), Error> { use std::time::{SystemTime, UNIX_EPOCH}; assert_ne!(len, 0); if len == 142 { - return getrandom::Error::CUSTOM_START + 142; + return Err(Error::new_custom(142)); } let dest_u32 = dest.cast::(); @@ -227,7 +229,7 @@ mod custom { core::ptr::write_unaligned(dest.add(i), val as u8); } } - 0 + Ok(()) } // Test that enabling the custom feature indeed uses the custom implementation From 74e2391114d24b08b99b6fcd58040b0a584d5e69 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 9 Oct 2024 16:23:09 +0300 Subject: [PATCH 036/201] Mount the lazy module only when neccecary (#509) --- src/lazy.rs | 2 -- src/lib.rs | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lazy.rs b/src/lazy.rs index 0b4730e65..b191aa6d7 100644 --- a/src/lazy.rs +++ b/src/lazy.rs @@ -1,6 +1,4 @@ //! Helpers built around pointer-sized atomics. -#![cfg(target_has_atomic = "ptr")] -#![allow(dead_code)] use core::sync::atomic::{AtomicUsize, Ordering}; // This structure represents a lazily initialized static usize value. Useful diff --git a/src/lib.rs b/src/lib.rs index cab0c69e0..07d4be226 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -248,7 +248,6 @@ extern crate cfg_if; use core::mem::MaybeUninit; mod error; -mod lazy; mod util; #[cfg(feature = "std")] @@ -275,6 +274,8 @@ cfg_if! { } else if #[cfg(getrandom_backend = "rdrand")] { #[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))] compile_error!("`rdrand` backend can be enabled only for x86 and x86-64 targets!"); + + mod lazy; #[path = "rdrand.rs"] mod imp; } else if #[cfg(getrandom_backend = "wasm_js")] { #[cfg(not(all( @@ -351,6 +352,7 @@ cfg_if! { ), ) ))] { + mod lazy; mod util_libc; mod use_file; mod linux_android; @@ -387,6 +389,7 @@ cfg_if! { } else if #[cfg(windows)] { #[path = "windows.rs"] mod imp; } else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] { + mod lazy; #[path = "rdrand.rs"] mod imp; } else if #[cfg(all( any(target_arch = "wasm32", target_arch = "wasm64"), From 09145a648da90a6f804dbaf8f5a4c08fdf80052f Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 10 Oct 2024 05:08:25 +0300 Subject: [PATCH 037/201] Replace `as` casts with safer conversions (#510) --- .clippy.toml | 1 - .github/workflows/workspace.yml | 2 +- src/error.rs | 18 +++++++----------- src/hermit.rs | 21 ++++++++++----------- src/js.rs | 12 ++++++++---- src/lib.rs | 15 +++++++++++++++ src/linux_android.rs | 12 ++++++++---- src/netbsd.rs | 16 ++++------------ src/util_libc.rs | 5 ++++- src/vxworks.rs | 7 ++++++- src/wasi.rs | 8 +++++++- src/windows7.rs | 3 ++- 12 files changed, 72 insertions(+), 48 deletions(-) delete mode 100644 .clippy.toml diff --git a/.clippy.toml b/.clippy.toml deleted file mode 100644 index 13f202e9e..000000000 --- a/.clippy.toml +++ /dev/null @@ -1 +0,0 @@ -msrv = "1.60" diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index a230e1c9f..13dba99ab 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -23,7 +23,7 @@ jobs: # Fixed Nigthly version is used to prevent # CI failures which are not relevant to PR changes # on introduction of new Clippy lints. - toolchain: nightly-2024-09-04 + toolchain: nightly-2024-10-08 components: clippy,rust-src - name: std feature run: cargo clippy --features std diff --git a/src/error.rs b/src/error.rs index 1c1584395..d0299267c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -88,18 +88,14 @@ impl Error { /// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error #[inline] pub fn raw_os_error(self) -> Option { - 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), + i32::try_from(self.0.get()).ok().map(|errno| { + // On SOLID, negate the error code again to obtain the original error code. + if cfg!(target_os = "solid_asp3") { + -errno + } else { + errno } - } else { - None - } + }) } /// Creates a new instance of an `Error` from a particular custom error code. diff --git a/src/hermit.rs b/src/hermit.rs index c869372a7..9dc9d8bd9 100644 --- a/src/hermit.rs +++ b/src/hermit.rs @@ -9,18 +9,17 @@ extern "C" { pub fn getrandom_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { while !dest.is_empty() { let res = unsafe { sys_read_entropy(dest.as_mut_ptr().cast::(), dest.len(), 0) }; - // Positive `isize`s can be safely casted to `usize` - if res > 0 && (res as usize) <= dest.len() { - dest = &mut dest[res as usize..]; - } else { - let err = if res < 0 { - u32::try_from(res.unsigned_abs()) + 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 err = u32::try_from(code.unsigned_abs()) .ok() - .map_or(Error::UNEXPECTED, Error::from_os_error) - } else { - Error::UNEXPECTED - }; - return Err(err); + .map_or(Error::UNEXPECTED, Error::from_os_error); + return Err(err); + } } } Ok(()) diff --git a/src/js.rs b/src/js.rs index bec31ee5a..65f63a1ae 100644 --- a/src/js.rs +++ b/src/js.rs @@ -9,7 +9,7 @@ use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; // Size of our temporary Uint8Array buffer used with WebCrypto methods // Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues -const WEB_CRYPTO_BUFFER_SIZE: usize = 256; +const WEB_CRYPTO_BUFFER_SIZE: u16 = 256; // Node.js's crypto.randomFillSync requires the size to be less than 2**31. const NODE_MAX_BUFFER_SIZE: usize = (1 << 31) - 1; @@ -50,10 +50,14 @@ pub(crate) fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> RngSource::Web(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(WEB_CRYPTO_BUFFER_SIZE) { + for chunk in dest.chunks_mut(WEB_CRYPTO_BUFFER_SIZE.into()) { + let chunk_len: u32 = chunk + .len() + .try_into() + .expect("chunk length is bounded by WEB_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); + let sub_buf = buf.subarray(0, chunk_len); if crypto.get_random_values(&sub_buf).is_err() { return Err(Error::WEB_GET_RANDOM_VALUES); @@ -95,7 +99,7 @@ fn getrandom_init() -> Result { }, }; - let buf = Uint8Array::new_with_length(WEB_CRYPTO_BUFFER_SIZE as u32); + let buf = Uint8Array::new_with_length(WEB_CRYPTO_BUFFER_SIZE.into()); Ok(RngSource::Web(crypto, buf)) } diff --git a/src/lib.rs b/src/lib.rs index 07d4be226..5cc409417 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -241,6 +241,21 @@ #![no_std] #![warn(rust_2018_idioms, unused_lifetimes, missing_docs)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![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; diff --git a/src/linux_android.rs b/src/linux_android.rs index 7c1fede4c..401d3dfc1 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -6,14 +6,18 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { util_libc::sys_fill_exact(dest, getrandom_syscall) } -// Also used by linux_android_with_fallback to check if the syscall is available. pub fn getrandom_syscall(buf: &mut [MaybeUninit]) -> libc::ssize_t { - unsafe { + let res: libc::c_long = unsafe { libc::syscall( libc::SYS_getrandom, buf.as_mut_ptr().cast::(), buf.len(), 0, - ) as libc::ssize_t - } + ) + }; + + const _: () = + assert!(core::mem::size_of::() == core::mem::size_of::()); + res.try_into() + .expect("c_long to ssize_t conversion is lossless") } diff --git a/src/netbsd.rs b/src/netbsd.rs index 2842617b6..93469ee97 100644 --- a/src/netbsd.rs +++ b/src/netbsd.rs @@ -19,26 +19,18 @@ unsafe extern "C" fn polyfill_using_kern_arand( ) -> libc::ssize_t { debug_assert_eq!(flags, 0); - static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND]; + 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() as libc::c_uint, - buf, - &mut len, - ptr::null(), - 0, - ) - }; + let ret = unsafe { libc::sysctl(MIB.as_ptr(), MIB_LEN, buf, &mut len, ptr::null(), 0) }; if ret == -1 { -1 } else { - len as libc::ssize_t + libc::ssize_t::try_from(len).expect("len is bounded by 256") } } diff --git a/src/util_libc.rs b/src/util_libc.rs index 7708bfcc8..4b33b8cd7 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -56,7 +56,10 @@ pub fn sys_fill_exact( while !buf.is_empty() { let res = sys_fill(buf); match res { - res if res > 0 => buf = buf.get_mut(res as usize..).ok_or(Error::UNEXPECTED)?, + 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. diff --git a/src/vxworks.rs b/src/vxworks.rs index 7f0613d2e..58b6c9621 100644 --- a/src/vxworks.rs +++ b/src/vxworks.rs @@ -25,7 +25,12 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // 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 ret = unsafe { libc::randABytes(chunk.as_mut_ptr().cast::(), chunk.len() as i32) }; + 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(last_os_error()); } diff --git a/src/wasi.rs b/src/wasi.rs index db2a800ee..9df9bf26f 100644 --- a/src/wasi.rs +++ b/src/wasi.rs @@ -24,10 +24,16 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // 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(()), - _ => Err(Error::from_os_error(ret as u32)), + code => { + let err = u32::try_from(code) + .map(Error::from_os_error) + .unwrap_or(Error::UNEXPECTED); + Err(err) + } } } diff --git a/src/windows7.rs b/src/windows7.rs index 6714f66b3..667bbf26b 100644 --- a/src/windows7.rs +++ b/src/windows7.rs @@ -27,7 +27,8 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> 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 ret = unsafe { RtlGenRandom(chunk.as_mut_ptr().cast::(), chunk.len() as u32) }; + 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::(), chunk_len) }; if ret != TRUE { return Err(Error::WINDOWS_RTL_GEN_RANDOM); } From c060d6548b52424e5ee8a28dfc08490cdc4931fc Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 11 Oct 2024 03:03:25 +0300 Subject: [PATCH 038/201] Fix wasm64 CI job (#511) --- .github/workflows/tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 885e24580..469925b71 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -272,8 +272,8 @@ jobs: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test run: wasm-pack test --headless --safari - wasm64-tests: - name: wasm64 Build/Link + wasm64-build: + name: Wasm64 Build runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -283,7 +283,7 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Build and Link tests (build-std) env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" # This target is Tier 3, so we have to build libstd ourselves. # We currently cannot run these tests because wasm-bindgen-test-runner # does not yet support memory64. From 74ea595cae32cd2e5914dbafc27b030cddece3b1 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 11 Oct 2024 19:03:34 +0300 Subject: [PATCH 039/201] Add AArch64 RNDR register backend (#512) AArch64 platforms from version Armv8.4 onwards may implement FEAT_RNG. FEAT_RNG introduces the RNDR (and RNDRRS) register, reading from which returns a random number. Add support for using the RNDR register as a backend for getrandom. The implementation is added as `rdrnd` opt-in backend. Currently, runtime detection of FEAT_RNG relies on the Linux Kernel's MRS emulation, on other targets users have to either enable the `std` crate feature, or the `rand` target feature at compile time. --- .github/workflows/tests.yml | 23 +++++++ .github/workflows/workspace.yml | 4 ++ Cargo.toml | 2 +- src/error.rs | 41 +++++++----- src/lib.rs | 6 +- src/rndr.rs | 111 ++++++++++++++++++++++++++++++++ 6 files changed, 168 insertions(+), 19 deletions(-) create mode 100644 src/rndr.rs diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 469925b71..100275774 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -382,6 +382,29 @@ jobs: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" run: cargo build -Z build-std=core --target=${{ matrix.target }} + build-rndr: + name: RNDR Build + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: aarch64-unknown-linux-gnu, aarch64-apple-darwin + - uses: Swatinem/rust-cache@v2 + - name: RNDR enabled at compile time (Linux) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" -C target-feature=+rand + run: cargo build --target=aarch64-unknown-linux-gnu + - name: Runtime RNDR detection without std (Linux) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" + run: cargo build --target=aarch64-unknown-linux-gnu + - name: Runtime RNDR detection with std (macOS) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" + run: cargo build --target=aarch64-unknown-linux-gnu --features std + build-esp-idf: name: ESP-IDF Build runs-on: ubuntu-22.04 diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 13dba99ab..80e4b6ef2 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -59,6 +59,10 @@ jobs: run: cargo clippy -Zbuild-std=core --target x86_64-unknown-netbsd - name: Fortranix SGX (rdrand.rs) run: cargo clippy -Zbuild-std=core --target x86_64-fortanix-unknown-sgx + - name: RNDR (rndr.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" + run: cargo clippy -Zbuild-std=core --target aarch64-unknown-linux-gnu - name: Solaris (solaris.rs) run: cargo clippy -Zbuild-std=core --target x86_64-pc-solaris - name: SOLID (solid.rs) diff --git a/Cargo.toml b/Cargo.toml index 83e22501f..88ce56371 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ rustc-dep-of-std = ["compiler_builtins", "core"] [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(getrandom_backend, values("custom", "rdrand", "linux_getrandom", "wasm_js", "esp_idf"))', + 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "wasm_js", "esp_idf"))', 'cfg(getrandom_browser_test)', 'cfg(getrandom_test_linux_fallback)', ] diff --git a/src/error.rs b/src/error.rs index d0299267c..b27ef26b4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -52,6 +52,10 @@ impl Error { pub const NODE_ES_MODULE: Error = Self::new_internal(14); /// Calling Windows ProcessPrng failed. pub const WINDOWS_PROCESS_PRNG: Error = Self::new_internal(15); + /// RNDR register read failed due to a hardware issue. + pub const RNDR_FAILURE: Error = Self::new_internal(16); + /// RNDR register is not supported on this target. + pub const RNDR_NOT_AVAILABLE: Error = Self::new_internal(17); /// Codes below this point represent OS Errors (i.e. positive i32 values). /// Codes at or above this point, but below [`Error::CUSTOM_START`] are @@ -149,23 +153,26 @@ impl fmt::Display for Error { } 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::UNEXPECTED => Some("unexpected situation"), - 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("Calling Web API crypto.getRandomValues failed"), - Error::VXWORKS_RAND_SECURE => Some("randSecure: VxWorks RNG module is not initialized"), - Error::NODE_CRYPTO => Some("Node.js crypto CommonJS module is unavailable"), - Error::NODE_RANDOM_FILL_SYNC => Some("Calling Node.js API crypto.randomFillSync failed"), - Error::NODE_ES_MODULE => Some("Node.js ES modules are not directly supported, see https://docs.rs/getrandom#nodejs-es-module-support"), - Error::WINDOWS_PROCESS_PRNG => Some("ProcessPrng: Windows system function failure"), - _ => None, - } + let desc = match error { + Error::UNSUPPORTED => "getrandom: this target is not supported", + Error::ERRNO_NOT_POSITIVE => "errno: did not return a positive value", + Error::UNEXPECTED => "unexpected situation", + Error::IOS_SEC_RANDOM => "SecRandomCopyBytes: iOS Security framework failure", + Error::WINDOWS_RTL_GEN_RANDOM => "RtlGenRandom: Windows system function failure", + Error::FAILED_RDRAND => "RDRAND: failed multiple times: CPU issue likely", + Error::NO_RDRAND => "RDRAND: instruction not supported", + Error::WEB_CRYPTO => "Web Crypto API is unavailable", + Error::WEB_GET_RANDOM_VALUES => "Calling Web API crypto.getRandomValues failed", + Error::VXWORKS_RAND_SECURE => "randSecure: VxWorks RNG module is not initialized", + Error::NODE_CRYPTO => "Node.js crypto CommonJS module is unavailable", + Error::NODE_RANDOM_FILL_SYNC => "Calling Node.js API crypto.randomFillSync failed", + Error::NODE_ES_MODULE => "Node.js ES modules are not directly supported, see https://docs.rs/getrandom#nodejs-es-module-support", + Error::WINDOWS_PROCESS_PRNG => "ProcessPrng: Windows system function failure", + Error::RNDR_FAILURE => "RNDR: Could not generate a random number", + Error::RNDR_NOT_AVAILABLE => "RNDR: Register not supported", + _ => return None, + }; + Some(desc) } #[cfg(test)] diff --git a/src/lib.rs b/src/lib.rs index 5cc409417..e2084d964 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,7 @@ //! | ----------------- | -------------------- | -------------------- | -------------- //! | `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). //! | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction +//! | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register //! | `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low quality entropy without proper hardware configuration! //! | `wasm_js` | Web Browser, Node.js | `wasm*‑*‑unknown` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js (see [WebAssembly support]) //! | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) @@ -51,7 +52,7 @@ //! `RUSTFLAGS` environment variable: //! //! ```sh -//! RUSTFLAGS='getrandom_backend="linux_getrandom"' cargo build +//! RUSTFLAGS='--cfg getrandom_backend="linux_getrandom"' cargo build //! ``` //! //! Enabling an opt-in backend will replace backend used by default. Doing it for a wrong target @@ -215,6 +216,7 @@ //! [`RtlGenRandom`]: https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom //! [`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 +//! [`RNDR`]: https://developer.arm.com/documentation/ddi0601/2024-06/AArch64-Registers/RNDR--Random-Number //! [`CCRandomGenerateBytes`]: https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html //! [`cprng_draw`]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw //! [`crypto.randomFillSync`]: https://nodejs.org/api/crypto.html#cryptorandomfillsyncbuffer-offset-size @@ -292,6 +294,8 @@ cfg_if! { mod lazy; #[path = "rdrand.rs"] mod imp; + } else if #[cfg(getrandom_backend = "rndr")] { + #[path = "rndr.rs"] mod imp; } else if #[cfg(getrandom_backend = "wasm_js")] { #[cfg(not(all( any(target_arch = "wasm32", target_arch = "wasm64"), diff --git a/src/rndr.rs b/src/rndr.rs new file mode 100644 index 000000000..f27d9d288 --- /dev/null +++ b/src/rndr.rs @@ -0,0 +1,111 @@ +//! 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 + +#[cfg(not(target_arch = "aarch64"))] +compile_error!("the `rndr` backend can be enabled only for AArch64 targets!"); + +use crate::{util::slice_as_uninit, Error}; +use core::arch::asm; +use core::mem::{size_of, MaybeUninit}; + +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 { + 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]) -> Option<()> { + let mut chunks = dest.chunks_exact_mut(size_of::()); + 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(()) +} + +fn is_rndr_available() -> bool { + cfg_if::cfg_if! { + if #[cfg(target_feature = "rand")] { + true + } 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 + } + + #[path = "../src/lazy.rs"] mod lazy; + static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new(); + RNDR_GOOD.unsync_init(mrs_check) + } else if #[cfg(feature = "std")] { + extern crate std; + #[path = "../src/lazy.rs"] mod lazy; + static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new(); + RNDR_GOOD.unsync_init(|| std::arch::is_aarch64_feature_detected!("rand")) + } 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." + ); + } + } +} + +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { + if is_rndr_available() { + // SAFETY: after this point, we know the `rand` target feature is enabled + unsafe { rndr_fill(dest).ok_or(Error::RNDR_FAILURE) } + } else { + Err(Error::RNDR_NOT_AVAILABLE) + } +} From 038e96ec9f9d43500fac267edc42879ff2f57b7b Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 11 Oct 2024 19:53:44 +0300 Subject: [PATCH 040/201] Tweak opt-in backends (#513) Move `compile_error!`s from lib.rs into opt-in backend modules. Rename `js.rs` to `wasm_js.rs` and `espidf.rs` to `esp_idf.rs` for consistency with backend names. --- .github/workflows/workspace.yml | 2 +- src/{espidf.rs => esp_idf.rs} | 3 +++ src/lib.rs | 16 ++-------------- src/linux_android.rs | 3 +++ src/rdrand.rs | 3 +++ src/rndr.rs | 12 ++++++------ src/{js.rs => wasm_js.rs} | 6 ++++++ 7 files changed, 24 insertions(+), 21 deletions(-) rename src/{espidf.rs => esp_idf.rs} (87%) rename src/{js.rs => wasm_js.rs} (97%) diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 80e4b6ef2..86cdadc96 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -45,7 +45,7 @@ jobs: run: cargo clippy -Zbuild-std=core --target x86_64-unknown-freebsd - name: Hermit (hermit.rs) run: cargo clippy -Zbuild-std=core --target x86_64-unknown-hermit - - name: Web WASM (js.rs) + - name: Web WASM (wasm_js.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown diff --git a/src/espidf.rs b/src/esp_idf.rs similarity index 87% rename from src/espidf.rs rename to src/esp_idf.rs index 7da5ca88e..75e81aafc 100644 --- a/src/espidf.rs +++ b/src/esp_idf.rs @@ -2,6 +2,9 @@ use crate::Error; use core::{ffi::c_void, mem::MaybeUninit}; +#[cfg(not(target_os = "espidf"))] +compile_error!("`esp_idf` backend can be enabled only for ESP-IDF targets!"); + extern "C" { fn esp_fill_random(buf: *mut c_void, len: usize) -> u32; } diff --git a/src/lib.rs b/src/lib.rs index e2084d964..005c7a758 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -284,29 +284,17 @@ cfg_if! { if #[cfg(getrandom_backend = "custom")] { #[path = "custom.rs"] mod imp; } else if #[cfg(getrandom_backend = "linux_getrandom")] { - #[cfg(not(any(target_os = "android", target_os = "linux")))] - compile_error!("`linux_getrandom` backend can be enabled only for Linux/Android targets!"); mod util_libc; #[path = "linux_android.rs"] mod imp; } else if #[cfg(getrandom_backend = "rdrand")] { - #[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))] - compile_error!("`rdrand` backend can be enabled only for x86 and x86-64 targets!"); - mod lazy; #[path = "rdrand.rs"] mod imp; } else if #[cfg(getrandom_backend = "rndr")] { #[path = "rndr.rs"] mod imp; } else if #[cfg(getrandom_backend = "wasm_js")] { - #[cfg(not(all( - any(target_arch = "wasm32", target_arch = "wasm64"), - target_os = "unknown", - )))] - compile_error!("`wasm_js` backend can be enabled only on OS-less WASM targets!"); - #[path = "js.rs"] mod imp; + #[path = "wasm_js.rs"] mod imp; } else if #[cfg(getrandom_backend = "esp_idf")] { - #[cfg(not(target_os = "espidf"))] - compile_error!("`esp_idf` backend can be enabled only for ESP-IDF targets!"); - #[path = "espidf.rs"] mod imp; + #[path = "esp_idf.rs"] mod imp; } else if #[cfg(any( target_os = "haiku", target_os = "redox", diff --git a/src/linux_android.rs b/src/linux_android.rs index 401d3dfc1..35c368a51 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -2,6 +2,9 @@ use crate::{util_libc, Error}; use core::mem::MaybeUninit; +#[cfg(not(any(target_os = "android", target_os = "linux")))] +compile_error!("`linux_getrandom` backend can be enabled only for Linux/Android targets!"); + pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { util_libc::sys_fill_exact(dest, getrandom_syscall) } diff --git a/src/rdrand.rs b/src/rdrand.rs index f4c593bdf..68f9878c5 100644 --- a/src/rdrand.rs +++ b/src/rdrand.rs @@ -2,6 +2,9 @@ use crate::{lazy::LazyBool, util::slice_as_uninit, Error}; use core::mem::{size_of, MaybeUninit}; +#[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; diff --git a/src/rndr.rs b/src/rndr.rs index f27d9d288..c670b53f1 100644 --- a/src/rndr.rs +++ b/src/rndr.rs @@ -1,14 +1,14 @@ //! 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 - -#[cfg(not(target_arch = "aarch64"))] -compile_error!("the `rndr` backend can be enabled only 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, 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 diff --git a/src/js.rs b/src/wasm_js.rs similarity index 97% rename from src/js.rs rename to src/wasm_js.rs index 65f63a1ae..026fa9acc 100644 --- a/src/js.rs +++ b/src/wasm_js.rs @@ -4,6 +4,12 @@ use crate::Error; extern crate std; use std::{mem::MaybeUninit, thread_local}; +#[cfg(not(all( + any(target_arch = "wasm32", target_arch = "wasm64"), + target_os = "unknown", +)))] +compile_error!("`wasm_js` backend can be enabled only for OS-less WASM targets!"); + use js_sys::{global, Function, Uint8Array}; use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; From 7db82805bd22c75e97261df649fb391e1bc505db Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 11 Oct 2024 20:18:31 +0300 Subject: [PATCH 041/201] Update CHANGELOG (#514) Tweak the breaking changes section and add entries for #415, #440, #442, #448, #504, and #512. --- CHANGELOG.md | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 196350e29..a68b3be95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,21 +8,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Breaking Changes - Update MSRV to 1.60 [#472] -- Remove support of the `wasm32-wasi` target (use `wasm32-wasip1` or `wasm32-wasip2` instead) [#499] -- Remove `impl From for Error` and `Error::code` method [#507] + +#### Removed +- `wasm32-wasi` target support (use `wasm32-wasip1` or `wasm32-wasip2` instead) [#499] +- `linux_disable_fallback`, `rdrand`, `js`, `test-in-browser`, and `custom` crate features + in favor of configuration flags [#504] +- `register_custom_getrandom!` macro [#504] +- Implementation of `From` for `Error` and `Error::code` method [#507] ### Changed -- Switch to `futex` on Linux and to `nanosleep`-based wait loop on other targets - in the `use_file` backend [#490] +- Use `ProcessPrng` on Windows 10 and up, and use RtlGenRandom on older legacy Windows versions [#415] +- Do not use locale-specific `strerror_r` for retrieving error code descriptions [#440] +- Avoid assuming usize is the native word size in the `rdrand` backend [#442] +- Do not read from `errno` when `libc` did not indicate error on Solaris [#448] +- Switch from `libpthread`'s mutex to `futex` on Linux and to `nanosleep`-based wait loop + on other targets in the `use_file` backend [#490] ### Added - `wasm32-wasip1` and `wasm32-wasip2` support [#499] +- `getrandom_backend` configuration flag for selection of opt-in backends [#504] - `Error::new_custom` method [#507] +- AArch64 RNDR register opt-in backend [#512] +[#415]: https://github.com/rust-random/getrandom/pull/415 +[#440]: https://github.com/rust-random/getrandom/pull/440 +[#442]: https://github.com/rust-random/getrandom/pull/442 +[#448]: https://github.com/rust-random/getrandom/pull/448 [#472]: https://github.com/rust-random/getrandom/pull/472 [#490]: https://github.com/rust-random/getrandom/pull/490 [#499]: https://github.com/rust-random/getrandom/pull/499 +[#504]: https://github.com/rust-random/getrandom/pull/504 [#507]: https://github.com/rust-random/getrandom/pull/507 +[#512]: https://github.com/rust-random/getrandom/pull/512 ## [0.2.15] - 2024-05-06 ### Added From 140876b94315807474546fcb65b9903c0e6bfe4a Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 14 Oct 2024 20:16:25 +0300 Subject: [PATCH 042/201] ci: enforce that `getrandom` does not contain potential panics (#515) The check is done by compiling `cdylib` which exposes `getrandom_uninit` and checking that the result does not contain any strings with "panic". For now CI only checks `linux_android_with_fallback`, `linux_android`, `rdrand`, `wasi`, and `getentropy` backends. Other backend checks could be added in future PRs. --- .github/workflows/nopanic.yaml | 72 ++++++++++++++++++++++++++++++++++ nopanic_check/Cargo.toml | 16 ++++++++ nopanic_check/src/lib.rs | 18 +++++++++ src/lib.rs | 9 +++++ 4 files changed, 115 insertions(+) create mode 100644 .github/workflows/nopanic.yaml create mode 100644 nopanic_check/Cargo.toml create mode 100644 nopanic_check/src/lib.rs diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml new file mode 100644 index 000000000..a4c24173c --- /dev/null +++ b/.github/workflows/nopanic.yaml @@ -0,0 +1,72 @@ +name: No panic + +on: + push: + branches: master + pull_request: + branches: master + +permissions: + contents: read + +defaults: + run: + working-directory: nopanic_check + +env: + RUSTFLAGS: "-Dwarnings" + +jobs: + linux: + name: Linux + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + # We need Nightly for the rust-std component for wasm32-wasip2 + toolchain: nightly-2024-10-14 + targets: wasm32-wasip1, wasm32-wasip2 + + - name: Build (linux_android_with_fallback.rs) + run: cargo build --release + - name: Check (linux_android_with_fallback.rs) + run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + + - name: Build (linux_android.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" + run: cargo build --release + - name: Check (linux_android.rs) + run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + + - name: Build (rdrand.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" + run: cargo build --release + - name: Check (rdrand.rs) + run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + + - name: Build (wasi.rs, preview 1) + run: cargo build --release --target wasm32-wasip1 + - name: Check (wasi.rs, preview 1) + run: ret=$(grep panic target/wasm32-wasip1/release/getrandom_wrapper.wasm; echo $?); [ $ret -eq 1 ] + + - name: Build (wasi.rs, preview 2) + run: cargo build --release --target wasm32-wasip2 + - name: Check (wasi.rs, preview 2) + run: ret=$(grep panic target/wasm32-wasip2/release/getrandom_wrapper.wasm; echo $?); [ $ret -eq 1 ] + + macos: + name: macOS + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + + - name: Build (getentropy.rs) + run: cargo build --release + - name: Check (getentropy.rs) + run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] diff --git a/nopanic_check/Cargo.toml b/nopanic_check/Cargo.toml new file mode 100644 index 000000000..11b510248 --- /dev/null +++ b/nopanic_check/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "nopanic_check" +description = "Helper crate for checking that getrandom implementation does not contain potential panics" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +name = "getrandom_wrapper" +crate-type = ["cdylib"] + +[dependencies] +getrandom = { path = ".." } + +[profile.release] +panic = "abort" diff --git a/nopanic_check/src/lib.rs b/nopanic_check/src/lib.rs new file mode 100644 index 000000000..0c0a7a0d8 --- /dev/null +++ b/nopanic_check/src/lib.rs @@ -0,0 +1,18 @@ +// WASI preview 2 requires enabled std +#![cfg_attr(not(all(target_arch = "wasm32", target_env = "p2")), no_std)] + +#[cfg(not(any(test, all(target_arch = "wasm32", target_env = "p2"))))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + extern "C" { + fn panic_nonexistent() -> !; + } + unsafe { panic_nonexistent() } +} + +#[no_mangle] +pub extern "C" fn getrandom_wrapper(buf_ptr: *mut u8, buf_len: usize) -> u32 { + let buf = unsafe { core::slice::from_raw_parts_mut(buf_ptr.cast(), buf_len) }; + let res = getrandom::getrandom_uninit(buf).map(|_| ()); + unsafe { core::mem::transmute(res) } +} diff --git a/src/lib.rs b/src/lib.rs index 005c7a758..67a4addc8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -195,6 +195,15 @@ //! on every call to `getrandom`, hence after the first successful call one //! can be reasonably confident that no errors will occur. //! +//! ## Panic handling +//! +//! We strive to eliminate all potential panics from our implementation. +//! In other words, when compiled with enabled optimizations, generated +//! binary code for `getrandom` functions should not contain any panic +//! branches. Even if platform misbiheaves and returns an unexpected +//! result, our code should correctly handle it and return an error like +//! [`Error::UNEXPECTED`]. +//! //! [1]: https://manned.org/getrandom.2 //! [2]: https://manned.org/urandom.4 //! [3]: https://www.unix.com/man-page/mojave/2/getentropy/ From 5d007eb7ed3f4fb78d510d267d2518968937c267 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 14 Oct 2024 20:39:43 +0300 Subject: [PATCH 043/201] ci: add no-panic check for the custom backend (#517) --- .github/workflows/nopanic.yaml | 7 +++++++ nopanic_check/Cargo.toml | 6 ++++++ nopanic_check/src/lib.rs | 12 ++++++++++++ 3 files changed, 25 insertions(+) diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index a4c24173c..a5bd6e025 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -47,6 +47,13 @@ jobs: - name: Check (rdrand.rs) run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + - name: Build (custom.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom" + run: cargo build --release + - name: Check (custom.rs) + run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + - name: Build (wasi.rs, preview 1) run: cargo build --release --target wasm32-wasip1 - name: Check (wasi.rs, preview 1) diff --git a/nopanic_check/Cargo.toml b/nopanic_check/Cargo.toml index 11b510248..f8c21c68a 100644 --- a/nopanic_check/Cargo.toml +++ b/nopanic_check/Cargo.toml @@ -14,3 +14,9 @@ getrandom = { path = ".." } [profile.release] panic = "abort" + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + 'cfg(getrandom_backend, values("custom"))', +] diff --git a/nopanic_check/src/lib.rs b/nopanic_check/src/lib.rs index 0c0a7a0d8..af2c8ee33 100644 --- a/nopanic_check/src/lib.rs +++ b/nopanic_check/src/lib.rs @@ -16,3 +16,15 @@ pub extern "C" fn getrandom_wrapper(buf_ptr: *mut u8, buf_len: usize) -> u32 { let res = getrandom::getrandom_uninit(buf).map(|_| ()); unsafe { core::mem::transmute(res) } } + +#[cfg(getrandom_backend = "custom")] +#[no_mangle] +unsafe extern "Rust" fn __getrandom_custom( + dest: *mut u8, + len: usize, +) -> Result<(), getrandom::Error> { + for i in 0..len { + core::ptr::write(dest.add(i), i as u8); + } + Ok(()) +} From 1c029c8d2004bd869334657858fb462192f6b024 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 16 Oct 2024 05:01:11 +0300 Subject: [PATCH 044/201] ci: add cross-based nopanic job (#518) Add cross-based no-panic checks for rndr, netbsd, getrandom, and solaris backends. Temporarily disable solaris and netbsd checks because they trigger the grep check. --- .github/workflows/nopanic.yaml | 137 +++++++++++++++++++++------------ nopanic_check/Cargo.toml | 2 + 2 files changed, 88 insertions(+), 51 deletions(-) diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index a5bd6e025..7329a1cf9 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -21,59 +21,94 @@ jobs: name: Linux runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master - with: - # We need Nightly for the rust-std component for wasm32-wasip2 - toolchain: nightly-2024-10-14 - targets: wasm32-wasip1, wasm32-wasip2 - - - name: Build (linux_android_with_fallback.rs) - run: cargo build --release - - name: Check (linux_android_with_fallback.rs) - run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] - - - name: Build (linux_android.rs) - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" - run: cargo build --release - - name: Check (linux_android.rs) - run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] - - - name: Build (rdrand.rs) - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" - run: cargo build --release - - name: Check (rdrand.rs) - run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] - - - name: Build (custom.rs) - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom" - run: cargo build --release - - name: Check (custom.rs) - run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] - - - name: Build (wasi.rs, preview 1) - run: cargo build --release --target wasm32-wasip1 - - name: Check (wasi.rs, preview 1) - run: ret=$(grep panic target/wasm32-wasip1/release/getrandom_wrapper.wasm; echo $?); [ $ret -eq 1 ] - - - name: Build (wasi.rs, preview 2) - run: cargo build --release --target wasm32-wasip2 - - name: Check (wasi.rs, preview 2) - run: ret=$(grep panic target/wasm32-wasip2/release/getrandom_wrapper.wasm; echo $?); [ $ret -eq 1 ] + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + # We need Nightly for the rust-std component for wasm32-wasip2 + toolchain: nightly-2024-10-14 + targets: wasm32-wasip1, wasm32-wasip2 + + - name: Build (linux_android_with_fallback.rs) + run: cargo build --release + - name: Check (linux_android_with_fallback.rs) + run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + + - name: Build (linux_android.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" + run: cargo build --release + - name: Check (linux_android.rs) + run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + + - name: Build (rdrand.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" + run: cargo build --release + - name: Check (rdrand.rs) + run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + + - name: Build (custom.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom" + run: cargo build --release + - name: Check (custom.rs) + run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + + - name: Build (wasi.rs, preview 1) + run: cargo build --release --target wasm32-wasip1 + - name: Check (wasi.rs, preview 1) + run: ret=$(grep panic target/wasm32-wasip1/release/getrandom_wrapper.wasm; echo $?); [ $ret -eq 1 ] + + - name: Build (wasi.rs, preview 2) + run: cargo build --release --target wasm32-wasip2 + - name: Check (wasi.rs, preview 2) + run: ret=$(grep panic target/wasm32-wasip2/release/getrandom_wrapper.wasm; echo $?); [ $ret -eq 1 ] + + cross: + name: Cross + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + components: rust-src + targets: aarch64-unknown-linux-gnu,x86_64-unknown-netbsd,x86_64-unknown-freebsd,x86_64-pc-solaris + - name: Install cross + run: cargo install cross --git https://github.com/cross-rs/cross + + - name: Build (rndr.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" + run: cross build --release --target=aarch64-unknown-linux-gnu + - name: Check (rndr.rs) + run: ret=$(grep panic target/aarch64-unknown-linux-gnu/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + + - name: Build (getrandom.rs) + run: cross build --release --target=x86_64-unknown-freebsd + - name: Check (getrandom.rs) + run: ret=$(grep panic target/x86_64-unknown-freebsd/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + + # - name: Build (netbsd.rs) + # run: cross build --release --target=x86_64-unknown-netbsd + # - name: Check (netbsd.rs) + # run: ret=$(grep panic target/x86_64-unknown-netbsd/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + + # - name: Build (solaris.rs) + # run: cross build --release --target=x86_64-pc-solaris + # - name: Check (solaris.rs) + # run: ret=$(grep panic target/x86_64-pc-solaris/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] macos: name: macOS runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: stable - - - name: Build (getentropy.rs) - run: cargo build --release - - name: Check (getentropy.rs) - run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + + - name: Build (getentropy.rs) + run: cargo build --release + - name: Check (getentropy.rs) + run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] diff --git a/nopanic_check/Cargo.toml b/nopanic_check/Cargo.toml index f8c21c68a..764dbde0d 100644 --- a/nopanic_check/Cargo.toml +++ b/nopanic_check/Cargo.toml @@ -5,6 +5,8 @@ version = "0.1.0" edition = "2021" publish = false +[workspace] + [lib] name = "getrandom_wrapper" crate-type = ["cdylib"] From ce35c6704bffbbacec2e5034a945d9c372cf46bf Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 16 Oct 2024 05:33:54 +0300 Subject: [PATCH 045/201] netbsd: fix potential panic (#519) The code was assuming that syscall returns either -1 or provided length. Fix code to account for potential bad return results. --- .github/workflows/nopanic.yaml | 9 +++++---- src/netbsd.rs | 9 +++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index 7329a1cf9..798e15df9 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -74,6 +74,7 @@ jobs: toolchain: stable components: rust-src targets: aarch64-unknown-linux-gnu,x86_64-unknown-netbsd,x86_64-unknown-freebsd,x86_64-pc-solaris + # TODO: use pre-compiled cross after a new (post-0.2.5) release - name: Install cross run: cargo install cross --git https://github.com/cross-rs/cross @@ -89,10 +90,10 @@ jobs: - name: Check (getrandom.rs) run: ret=$(grep panic target/x86_64-unknown-freebsd/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] - # - name: Build (netbsd.rs) - # run: cross build --release --target=x86_64-unknown-netbsd - # - name: Check (netbsd.rs) - # run: ret=$(grep panic target/x86_64-unknown-netbsd/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + - name: Build (netbsd.rs) + run: cross build --release --target=x86_64-unknown-netbsd + - name: Check (netbsd.rs) + run: ret=$(grep panic target/x86_64-unknown-netbsd/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] # - name: Build (solaris.rs) # run: cross build --release --target=x86_64-pc-solaris diff --git a/src/netbsd.rs b/src/netbsd.rs index 93469ee97..10cb2e54a 100644 --- a/src/netbsd.rs +++ b/src/netbsd.rs @@ -25,12 +25,17 @@ unsafe extern "C" fn polyfill_using_kern_arand( // 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 expected_ret = libc::c_int::try_from(len).expect("len is bounded by 256"); let ret = unsafe { libc::sysctl(MIB.as_ptr(), MIB_LEN, buf, &mut len, ptr::null(), 0) }; - if ret == -1 { + + if ret == expected_ret { + libc::ssize_t::try_from(ret).expect("len is bounded by 256") + } else if ret == -1 { -1 } else { - libc::ssize_t::try_from(len).expect("len is bounded by 256") + // Zero return result will be converted into `Error::UNEXPECTED` by `sys_fill_exact` + 0 } } From 9aab00c62284ba6e83266f8d30b54d35a06a0601 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 16 Oct 2024 08:26:25 +0300 Subject: [PATCH 046/201] Add `linux_rustix` opt-in backend (#520) This backend can be useful for `libc`-free applications and libraries. It's also used by default on `*-unknown-linux-none` targets. --- .github/workflows/nopanic.yaml | 8 ++++++ .github/workflows/tests.yml | 3 +++ .github/workflows/workspace.yml | 4 +++ CHANGELOG.md | 4 ++- Cargo.toml | 45 ++++++++++++++++++++++++++++++--- src/lib.rs | 8 ++++-- src/linux_rustix.rs | 30 ++++++++++++++++++++++ 7 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 src/linux_rustix.rs diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index 798e15df9..048e06909 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -40,6 +40,14 @@ jobs: - name: Check (linux_android.rs) run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + # TODO: re-enable after https://github.com/bytecodealliance/rustix/pull/1184 is released + # - name: Build (linux_rustix.rs) + # env: + # RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" + # run: cargo build --release + # - name: Check (linux_rustix.rs) + # run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + - name: Build (rdrand.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 100275774..d02dcdb8b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -71,6 +71,9 @@ jobs: - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" + run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback run: cargo test --features=std diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 86cdadc96..8da81c65e 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -53,6 +53,10 @@ jobs: env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo clippy --target x86_64-unknown-linux-gnu + - name: Linux (linux_rustix.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" + run: cargo clippy --target x86_64-unknown-linux-gnu - name: Linux (linux_android_with_fallback.rs) run: cargo clippy --target x86_64-unknown-linux-gnu - name: NetBSD (netbsd.rs) diff --git a/CHANGELOG.md b/CHANGELOG.md index a68b3be95..f63dc37fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `wasm32-wasip1` and `wasm32-wasip2` support [#499] - `getrandom_backend` configuration flag for selection of opt-in backends [#504] - `Error::new_custom` method [#507] -- AArch64 RNDR register opt-in backend [#512] +- `rndr` opt-in backend [#512] +- `linux_rustix` opt-in backend [#520] [#415]: https://github.com/rust-random/getrandom/pull/415 [#440]: https://github.com/rust-random/getrandom/pull/440 @@ -40,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#504]: https://github.com/rust-random/getrandom/pull/504 [#507]: https://github.com/rust-random/getrandom/pull/507 [#512]: https://github.com/rust-random/getrandom/pull/512 +[#520]: https://github.com/rust-random/getrandom/pull/520 ## [0.2.15] - 2024-05-06 ### Added diff --git a/Cargo.toml b/Cargo.toml index 88ce56371..b2fb74ef8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,23 +18,60 @@ cfg-if = "1" compiler_builtins = { version = "0.1", optional = true } core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" } -[target.'cfg(unix)'.dependencies] +# linux_android / linux_android_with_fallback +[target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(target_env = "", getrandom_backend = "linux_rustix", getrandom_backend = "custom"))))'.dependencies] libc = { version = "0.2.154", default-features = false } +# linux_rustix +[target.'cfg(all(any(target_os = "linux", target_os = "android"), any(target_env = "", getrandom_backend = "linux_rustix")))'.dependencies] +rustix = { version = "0.38", default-features = false, features = ["rand"] } + +# apple-other +[target.'cfg(any(target_os = "ios", target_os = "visionos", target_os = "watchos", target_os = "tvos"))'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# getentropy +[target.'cfg(any(target_os = "macos", target_os = "openbsd", target_os = "vita", target_os = "emscripten"))'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# getrandom +[target.'cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "hurd", target_os = "illumos", all(target_os = "horizon", target_arch = "arm")))'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# netbsd +[target.'cfg(target_os = "netbsd")'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# solaris +[target.'cfg(target_os = "solaris")'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# use_file +[target.'cfg(any(target_os = "haiku", target_os = "redox", target_os = "nto", target_os = "aix"))'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# vxworks +[target.'cfg(target_os = "vxworks")'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# wasi (0.2 only) [target.'cfg(all(target_arch = "wasm32", target_os = "wasi", target_env = "p2"))'.dependencies] wasi = { version = "0.13", default-features = false } +# windows7 [target.'cfg(all(windows, not(target_vendor = "win7")))'.dependencies] windows-targets = "0.52" +# wasm_js [target.'cfg(all(getrandom_backend = "wasm_js", any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies] wasm-bindgen = { version = "0.2.89", default-features = false } js-sys = "0.3" -[target.'cfg(all(getrandom_backend = "wasm_js", getrandom_browser_test, any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dev-dependencies] +[target.'cfg(all(getrandom_backend = "wasm_js", getrandom_browser_test, target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies] wasm-bindgen-test = "0.3.39" [features] -# Implement std-only traits for getrandom::Error +# Implement std::error::Error for getrandom::Error and +# use std to retrieve OS error descriptions std = [] # Unstable feature to support being a libstd dependency rustc-dep-of-std = ["compiler_builtins", "core"] @@ -42,7 +79,7 @@ rustc-dep-of-std = ["compiler_builtins", "core"] [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "wasm_js", "esp_idf"))', + 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "linux_rustix", "wasm_js", "esp_idf"))', 'cfg(getrandom_browser_test)', 'cfg(getrandom_test_linux_fallback)', ] diff --git a/src/lib.rs b/src/lib.rs index 67a4addc8..d0e84c7a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,14 +6,14 @@ //! | ------------------ | ------------------ | -------------- //! | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` //! | Windows 10+ | `*‑windows‑*` | [`ProcessPrng`] -//! | Windows 7 and 8 | `*-win7‑windows‑*` | [`RtlGenRandom`] +//! | Windows 7, 8 | `*-win7‑windows‑*` | [`RtlGenRandom`] //! | macOS | `*‑apple‑darwin` | [`getentropy`][3] //! | iOS, tvOS, watchOS | `*‑apple‑ios`, `*-apple-tvos`, `*-apple-watchos` | [`CCRandomGenerateBytes`] //! | FreeBSD | `*‑freebsd` | [`getrandom`][5] //! | OpenBSD | `*‑openbsd` | [`getentropy`][7] //! | NetBSD | `*‑netbsd` | [`getrandom`][16] if available, otherwise [`kern.arandom`][8] //! | Dragonfly BSD | `*‑dragonfly` | [`getrandom`][9] -//! | Solaris | `*‑solaris` | [`getrandom`][11] (with `GRND_RANDOM`) +//! | Solaris | `*‑solaris` | [`getrandom`][11] with `GRND_RANDOM` //! | illumos | `*‑illumos` | [`getrandom`][12] //! | Fuchsia OS | `*‑fuchsia` | [`cprng_draw`] //! | Redox | `*‑redox` | `/dev/urandom` @@ -41,6 +41,7 @@ //! | Backend name | Target | Target Triple | Implementation //! | ----------------- | -------------------- | -------------------- | -------------- //! | `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). +//! | `linux_rustix` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses [`rustix`] instead of `libc`. //! | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction //! | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register //! | `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low quality entropy without proper hardware configuration! @@ -243,6 +244,7 @@ //! [platform-support]: https://doc.rust-lang.org/stable/rustc/platform-support.html //! [WASI]: https://github.com/CraneStation/wasi //! [Emscripten]: https://www.hellorust.com/setup/emscripten/ +//! [`rustix`]: https://docs.rs/rustix #![doc( html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", @@ -295,6 +297,8 @@ cfg_if! { } else if #[cfg(getrandom_backend = "linux_getrandom")] { mod util_libc; #[path = "linux_android.rs"] mod imp; + } else if #[cfg(getrandom_backend = "linux_rustix")] { + #[path = "linux_rustix.rs"] mod imp; } else if #[cfg(getrandom_backend = "rdrand")] { mod lazy; #[path = "rdrand.rs"] mod imp; diff --git a/src/linux_rustix.rs b/src/linux_rustix.rs new file mode 100644 index 000000000..a286b20ce --- /dev/null +++ b/src/linux_rustix.rs @@ -0,0 +1,30 @@ +//! Implementation for Linux / Android without `/dev/urandom` fallback +use crate::{Error, MaybeUninit}; +use rustix::rand::{getrandom_uninit, GetRandomFlags}; + +#[cfg(not(any(target_os = "android", target_os = "linux")))] +compile_error!("`linux_rustix` backend can be enabled only for Linux/Android targets!"); + +pub fn getrandom_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { + loop { + let res = getrandom_uninit(dest, GetRandomFlags::empty()).map(|(res, _)| res.len()); + match res { + Ok(0) => return Err(Error::UNEXPECTED), + Ok(res_len) => { + dest = dest.get_mut(res_len..).ok_or(Error::UNEXPECTED)?; + if dest.is_empty() { + return Ok(()); + } + } + Err(rustix::io::Errno::INTR) => continue, + Err(err) => { + let code = err + .raw_os_error() + .wrapping_neg() + .try_into() + .map_err(|_| Error::UNEXPECTED)?; + return Err(Error::from_os_error(code)); + } + } + } +} From f6222159632ada89d7fd87e36f229f164de724ff Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 16 Oct 2024 09:52:59 +0300 Subject: [PATCH 047/201] Add memory sanitizer support (#521) Add new `getrandom_sanitize` flag which enables unpoisoning of buffer passed to `getrandom_uninit`. --- .github/workflows/tests.yml | 14 ++++++++++++++ CHANGELOG.md | 2 ++ Cargo.toml | 1 + src/lib.rs | 27 ++++++++++++++++++++++++++- 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d02dcdb8b..1f1c320fc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -159,6 +159,20 @@ jobs: - run: cargo test --target=x86_64-win7-windows-msvc -Z build-std --features=std - run: cargo test --target=i686-win7-windows-msvc -Z build-std --features=std + sanitizer-test: + name: Sanitizer Test + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: nightly-2024-10-08 + components: rust-src + - env: + RUSTFLAGS: -Dwarnings -Zsanitizer=memory --cfg getrandom_sanitize + # `--all-targets` is used to skip doc tests which currently fail linking + run: cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu --all-targets + cross-tests: name: Cross Test runs-on: ubuntu-22.04 diff --git a/CHANGELOG.md b/CHANGELOG.md index f63dc37fa..74971dbe3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Error::new_custom` method [#507] - `rndr` opt-in backend [#512] - `linux_rustix` opt-in backend [#520] +- Memory sanitizer support gated behind `getrandom_sanitize` configuration flag [#521] [#415]: https://github.com/rust-random/getrandom/pull/415 [#440]: https://github.com/rust-random/getrandom/pull/440 @@ -42,6 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#507]: https://github.com/rust-random/getrandom/pull/507 [#512]: https://github.com/rust-random/getrandom/pull/512 [#520]: https://github.com/rust-random/getrandom/pull/520 +[#521]: https://github.com/rust-random/getrandom/pull/521 ## [0.2.15] - 2024-05-06 ### Added diff --git a/Cargo.toml b/Cargo.toml index b2fb74ef8..01bd81f88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,6 +80,7 @@ rustc-dep-of-std = ["compiler_builtins", "core"] level = "warn" check-cfg = [ 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "linux_rustix", "wasm_js", "esp_idf"))', + 'cfg(getrandom_sanitize)', 'cfg(getrandom_browser_test)', 'cfg(getrandom_test_linux_fallback)', ] diff --git a/src/lib.rs b/src/lib.rs index d0e84c7a9..7c3cec237 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -205,6 +205,17 @@ //! result, our code should correctly handle it and return an error like //! [`Error::UNEXPECTED`]. //! +//! ## Sanitizer support +//! +//! If your code uses `getrandom_uninit` and you use memory sanitizer +//! (i.e. `-Zsanitizer=memory`), then you need to pass `getrandom_sanitize` +//! configuration flag for `getrandom_uninit` to unpoison destination buffer. +//! +//! For example, it can be done like this (requires Nightly compiler): +//! ```text +//! RUSTFLAGS="-Zsanitizer=memory --cfg getrandom_sanitize" cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu +//! ``` +//! //! [1]: https://manned.org/getrandom.2 //! [2]: https://manned.org/urandom.4 //! [3]: https://www.unix.com/man-page/mojave/2/getentropy/ @@ -254,6 +265,7 @@ #![no_std] #![warn(rust_2018_idioms, unused_lifetimes, missing_docs)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(getrandom_sanitize, feature(cfg_sanitize))] #![deny( clippy::cast_lossless, clippy::cast_possible_truncation, @@ -474,7 +486,20 @@ pub fn getrandom_uninit(dest: &mut [MaybeUninit]) -> Result<&mut [u8], Error if !dest.is_empty() { imp::getrandom_inner(dest)?; } + + #[cfg(getrandom_sanitize)] + #[cfg(sanitize = "memory")] + extern "C" { + fn __msan_unpoison(a: *mut core::ffi::c_void, size: usize); + } + // SAFETY: `dest` has been fully initialized by `imp::getrandom_inner` // since it returned `Ok`. - Ok(unsafe { slice_assume_init_mut(dest) }) + Ok(unsafe { + #[cfg(getrandom_sanitize)] + #[cfg(sanitize = "memory")] + __msan_unpoison(dest.as_mut_ptr().cast(), dest.len()); + + slice_assume_init_mut(dest) + }) } From 869a4f0388338d41513436fc3e2d71a5c6b93dbc Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 16 Oct 2024 10:48:41 +0300 Subject: [PATCH 048/201] linux_android: use `libc::getrandom` (#508) Use of `libc::getrandom` will automatically give us optimizations like vDSO (#503) and can help with testing of fallback logic (#289). It was also requested in #285. In that discussion we decided against using this approach, but in the light of the vDSO optimization it may be worth to reconsider it. In `linux_android_with_fallback` use of `libc::syscall` is replaced by `dlsym`-based code similar to what we use in the `netbsd` backend. --- src/lib.rs | 2 - src/linux_android.rs | 20 +----- src/linux_android_with_fallback.rs | 99 +++++++++++++++++++++--------- 3 files changed, 74 insertions(+), 47 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7c3cec237..386e5906e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -384,10 +384,8 @@ cfg_if! { ), ) ))] { - mod lazy; mod util_libc; mod use_file; - mod linux_android; #[path = "linux_android_with_fallback.rs"] mod imp; } else if #[cfg(any(target_os = "android", target_os = "linux"))] { mod util_libc; diff --git a/src/linux_android.rs b/src/linux_android.rs index 35c368a51..548401b2c 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -6,21 +6,7 @@ use core::mem::MaybeUninit; compile_error!("`linux_getrandom` backend can be enabled only for Linux/Android targets!"); pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - util_libc::sys_fill_exact(dest, getrandom_syscall) -} - -pub fn getrandom_syscall(buf: &mut [MaybeUninit]) -> libc::ssize_t { - let res: libc::c_long = unsafe { - libc::syscall( - libc::SYS_getrandom, - buf.as_mut_ptr().cast::(), - buf.len(), - 0, - ) - }; - - const _: () = - assert!(core::mem::size_of::() == core::mem::size_of::()); - res.try_into() - .expect("c_long to ssize_t conversion is lossless") + util_libc::sys_fill_exact(dest, |buf| unsafe { + libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) + }) } diff --git a/src/linux_android_with_fallback.rs b/src/linux_android_with_fallback.rs index ec7a12166..dd401caac 100644 --- a/src/linux_android_with_fallback.rs +++ b/src/linux_android_with_fallback.rs @@ -1,37 +1,80 @@ //! Implementation for Linux / Android with `/dev/urandom` fallback -use crate::{lazy::LazyBool, linux_android, use_file, util_libc::last_os_error, Error}; -use core::mem::MaybeUninit; +use crate::{use_file, util_libc, Error}; +use core::{ + ffi::c_void, + mem::{self, MaybeUninit}, + ptr::{self, NonNull}, + sync::atomic::{AtomicPtr, Ordering}, +}; -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - // getrandom(2) was introduced in Linux 3.17 - static HAS_GETRANDOM: LazyBool = LazyBool::new(); - if HAS_GETRANDOM.unsync_init(is_getrandom_available) { - linux_android::getrandom_inner(dest) - } else { - // prevent inlining of the fallback implementation - #[inline(never)] - fn inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - use_file::getrandom_inner(dest) +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 = unsafe { NonNull::new_unchecked(usize::MAX as *mut c_void) }; + +static GETRANDOM_FN: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + +#[cold] +fn init() -> NonNull { + static NAME: &[u8] = b"getrandom\0"; + let name_ptr = NAME.as_ptr().cast::(); + let raw_ptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) }; + let res_ptr = match NonNull::new(raw_ptr) { + Some(fptr) => { + let getrandom_fn = unsafe { mem::transmute::, GetRandomFn>(fptr) }; + let dangling_ptr = 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, + }; - inner(dest) - } + GETRANDOM_FN.store(res_ptr.as_ptr(), Ordering::Release); + res_ptr } -fn is_getrandom_available() -> bool { - if cfg!(getrandom_test_linux_fallback) { - false - } else if linux_android::getrandom_syscall(&mut []) < 0 { - match last_os_error().raw_os_error() { - Some(libc::ENOSYS) => false, // 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) => false, // Blocked by seccomp - _ => true, - } +// prevent inlining of the fallback implementation +#[inline(never)] +fn use_file_fallback(dest: &mut [MaybeUninit]) -> Result<(), Error> { + use_file::getrandom_inner(dest) +} + +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> 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 { - true + // note: `transume` is currently the only way to convert pointer into function reference + let getrandom_fn = unsafe { mem::transmute::, GetRandomFn>(fptr) }; + util_libc::sys_fill_exact(dest, |buf| unsafe { + getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0) + }) } } From bce46e2753976e775c510d0485bf5127324c583a Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 16 Oct 2024 12:24:10 +0300 Subject: [PATCH 049/201] use_file: remove EAGAIN check (#522) `poll` can return EAGAIN only on "some other UNIX systems", so we can remove its check for Linux-specific code. --- CHANGELOG.md | 2 ++ src/use_file.rs | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74971dbe3..71c8b4e60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Do not read from `errno` when `libc` did not indicate error on Solaris [#448] - Switch from `libpthread`'s mutex to `futex` on Linux and to `nanosleep`-based wait loop on other targets in the `use_file` backend [#490] +- Do not retry on `EAGAIN` while polling `/dev/random` on Linux [#522] ### Added - `wasm32-wasip1` and `wasm32-wasip2` support [#499] @@ -44,6 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#512]: https://github.com/rust-random/getrandom/pull/512 [#520]: https://github.com/rust-random/getrandom/pull/520 [#521]: https://github.com/rust-random/getrandom/pull/521 +[#522]: https://github.com/rust-random/getrandom/pull/522 ## [0.2.15] - 2024-05-06 ### Added diff --git a/src/use_file.rs b/src/use_file.rs index 247272dce..a9fceb8a6 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -191,8 +191,10 @@ mod sync { 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) | Some(libc::EAGAIN) => continue, + Some(libc::EINTR) => continue, _ => break Err(err), } }; From bafc6e0d54d1b541e1b023fda1af6e85665eadcf Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 16 Oct 2024 12:45:49 +0300 Subject: [PATCH 050/201] Move `open_readonly` function to `use_file` (#523) --- src/use_file.rs | 31 ++++++++++++++++++++++++++++--- src/util_libc.rs | 41 ++++++++--------------------------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/use_file.rs b/src/use_file.rs index a9fceb8a6..ff6b22366 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -1,6 +1,6 @@ //! Implementations that just need to read from a file use crate::{ - util_libc::{open_readonly, sys_fill_exact}, + util_libc::{last_os_error, sys_fill_exact}, Error, }; use core::{ @@ -47,6 +47,32 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { }) } +/// 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 { + assert!(path.iter().any(|&b| b == 0)); + loop { + let fd = unsafe { + libc::open( + path.as_ptr().cast::(), + 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); + } + } +} + #[cold] fn open_or_wait() -> Result { loop { @@ -116,8 +142,7 @@ mod sync { #[cfg(any(target_os = "android", target_os = "linux"))] mod sync { - use super::{Error, FD, FD_ONGOING_INIT}; - use crate::util_libc::{last_os_error, open_readonly}; + use super::{last_os_error, open_readonly, Error, FD, FD_ONGOING_INIT}; /// Wait for atomic `FD` to change value from `FD_ONGOING_INIT` to something else. /// diff --git a/src/util_libc.rs b/src/util_libc.rs index 4b33b8cd7..2f6185958 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -1,4 +1,3 @@ -#![allow(dead_code)] use crate::Error; use core::mem::MaybeUninit; @@ -34,7 +33,7 @@ cfg_if! { } } -pub fn last_os_error() -> Error { +pub(crate) fn last_os_error() -> Error { let errno: libc::c_int = unsafe { get_errno() }; // c_int-to-u32 conversion is lossless for nonnegative values if they are the same size. @@ -46,10 +45,13 @@ pub fn last_os_error() -> Error { } } -// 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( +/// 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], sys_fill: impl Fn(&mut [MaybeUninit]) -> libc::ssize_t, ) -> Result<(), Error> { @@ -75,30 +77,3 @@ pub fn sys_fill_exact( } Ok(()) } - -/// 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 -#[inline(always)] -pub fn open_readonly(path: &[u8]) -> Result { - assert!(path.iter().any(|&b| b == 0)); - loop { - let fd = unsafe { - libc::open( - path.as_ptr().cast::(), - 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); - } - } -} From 203e3c38199c0355b58507d4f66e2ce9cd0cdfd3 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 16 Oct 2024 17:55:29 +0300 Subject: [PATCH 051/201] ci: add nopanic check for apple-other (#524) --- .github/workflows/nopanic.yaml | 15 ++++++++++++--- nopanic_check/Cargo.toml | 1 + src/apple-other.rs | 21 +++++---------------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index 048e06909..140004aaa 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -27,6 +27,7 @@ jobs: # We need Nightly for the rust-std component for wasm32-wasip2 toolchain: nightly-2024-10-14 targets: wasm32-wasip1, wasm32-wasip2 + - uses: Swatinem/rust-cache@v2 - name: Build (linux_android_with_fallback.rs) run: cargo build --release @@ -82,6 +83,7 @@ jobs: toolchain: stable components: rust-src targets: aarch64-unknown-linux-gnu,x86_64-unknown-netbsd,x86_64-unknown-freebsd,x86_64-pc-solaris + - uses: Swatinem/rust-cache@v2 # TODO: use pre-compiled cross after a new (post-0.2.5) release - name: Install cross run: cargo install cross --git https://github.com/cross-rs/cross @@ -110,14 +112,21 @@ jobs: macos: name: macOS - runs-on: ubuntu-latest + runs-on: macos-14 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: toolchain: stable + targets: aarch64-apple-ios + - uses: Swatinem/rust-cache@v2 - name: Build (getentropy.rs) - run: cargo build --release + run: cargo build --release --target=aarch64-apple-darwin - name: Check (getentropy.rs) - run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + run: ret=$(grep -c panic target/aarch64-apple-darwin/release/libgetrandom_wrapper.dylib); (( $ret == 1)) + + - name: Build (apple-other.rs) + run: cargo build --release --target=aarch64-apple-ios + - name: Check (apple-other.rs) + run: ret=$(grep -c panic target/aarch64-apple-ios/release/libgetrandom_wrapper.dylib); (( $ret == 1)) diff --git a/nopanic_check/Cargo.toml b/nopanic_check/Cargo.toml index 764dbde0d..de5774991 100644 --- a/nopanic_check/Cargo.toml +++ b/nopanic_check/Cargo.toml @@ -16,6 +16,7 @@ getrandom = { path = ".." } [profile.release] panic = "abort" +strip = true [lints.rust.unexpected_cfgs] level = "warn" diff --git a/src/apple-other.rs b/src/apple-other.rs index e54b4cb27..6c761494b 100644 --- a/src/apple-other.rs +++ b/src/apple-other.rs @@ -2,23 +2,12 @@ use crate::Error; use core::{ffi::c_void, mem::MaybeUninit}; -// libsystem contains the libc of Darwin, and every binary ends up linked against it either way. This -// makes it a more lightweight choice compared to `Security.framework`. -extern "C" { - // This RNG uses a thread-local CSPRNG to provide data, which is seeded by the operating system's root CSPRNG. - // Its the best option after `getentropy` on modern Darwin-based platforms that also avoids the - // high startup costs and linking of Security.framework. - // - // While its just an implementation detail, `Security.framework` just calls into this anyway. - fn CCRandomGenerateBytes(bytes: *mut c_void, size: usize) -> i32; -} - pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - let ret = unsafe { CCRandomGenerateBytes(dest.as_mut_ptr().cast::(), dest.len()) }; - // kCCSuccess (from CommonCryptoError.h) is always zero. - if ret != 0 { - Err(Error::IOS_SEC_RANDOM) - } else { + let dst_ptr = dest.as_mut_ptr().cast::(); + let ret = unsafe { libc::CCRandomGenerateBytes(dst_ptr, dest.len()) }; + if ret == libc::kCCSuccess { Ok(()) + } else { + Err(Error::IOS_SEC_RANDOM) } } From 136291f2570d60c4d6cd8973d34a81b4088da0e7 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 16 Oct 2024 19:49:18 +0300 Subject: [PATCH 052/201] ci: tweak nopanic.yaml (#525) --- .github/workflows/nopanic.yaml | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index 140004aaa..68a69ed70 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -32,14 +32,14 @@ jobs: - name: Build (linux_android_with_fallback.rs) run: cargo build --release - name: Check (linux_android_with_fallback.rs) - run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) - name: Build (linux_android.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo build --release - name: Check (linux_android.rs) - run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) # TODO: re-enable after https://github.com/bytecodealliance/rustix/pull/1184 is released # - name: Build (linux_rustix.rs) @@ -47,31 +47,31 @@ jobs: # RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" # run: cargo build --release # - name: Check (linux_rustix.rs) - # run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + # run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) - name: Build (rdrand.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" run: cargo build --release - name: Check (rdrand.rs) - run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) - name: Build (custom.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom" run: cargo build --release - name: Check (custom.rs) - run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) - name: Build (wasi.rs, preview 1) run: cargo build --release --target wasm32-wasip1 - name: Check (wasi.rs, preview 1) - run: ret=$(grep panic target/wasm32-wasip1/release/getrandom_wrapper.wasm; echo $?); [ $ret -eq 1 ] + run: (exit $( grep -c panic target/wasm32-wasip1/release/getrandom_wrapper.wasm )) - name: Build (wasi.rs, preview 2) run: cargo build --release --target wasm32-wasip2 - name: Check (wasi.rs, preview 2) - run: ret=$(grep panic target/wasm32-wasip2/release/getrandom_wrapper.wasm; echo $?); [ $ret -eq 1 ] + run: (exit $( grep -c panic target/wasm32-wasip2/release/getrandom_wrapper.wasm )) cross: name: Cross @@ -86,29 +86,29 @@ jobs: - uses: Swatinem/rust-cache@v2 # TODO: use pre-compiled cross after a new (post-0.2.5) release - name: Install cross - run: cargo install cross --git https://github.com/cross-rs/cross + run: cargo install cross --force --git https://github.com/cross-rs/cross - name: Build (rndr.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" run: cross build --release --target=aarch64-unknown-linux-gnu - name: Check (rndr.rs) - run: ret=$(grep panic target/aarch64-unknown-linux-gnu/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + run: (exit $( grep -c panic target/aarch64-unknown-linux-gnu/release/libgetrandom_wrapper.so )) - name: Build (getrandom.rs) run: cross build --release --target=x86_64-unknown-freebsd - name: Check (getrandom.rs) - run: ret=$(grep panic target/x86_64-unknown-freebsd/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + run: (exit $( grep -c panic target/x86_64-unknown-freebsd/release/libgetrandom_wrapper.so )) - name: Build (netbsd.rs) run: cross build --release --target=x86_64-unknown-netbsd - name: Check (netbsd.rs) - run: ret=$(grep panic target/x86_64-unknown-netbsd/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + run: (exit $( grep -c panic target/x86_64-unknown-netbsd/release/libgetrandom_wrapper.so )) # - name: Build (solaris.rs) # run: cross build --release --target=x86_64-pc-solaris # - name: Check (solaris.rs) - # run: ret=$(grep panic target/x86_64-pc-solaris/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + # run: (exit $( grep -c panic target/x86_64-pc-solaris/release/libgetrandom_wrapper.so )) macos: name: macOS @@ -121,12 +121,9 @@ jobs: targets: aarch64-apple-ios - uses: Swatinem/rust-cache@v2 + # We do not need the grep check since linker fails + # if `panic_nonexistent` can not be eliminated - name: Build (getentropy.rs) run: cargo build --release --target=aarch64-apple-darwin - - name: Check (getentropy.rs) - run: ret=$(grep -c panic target/aarch64-apple-darwin/release/libgetrandom_wrapper.dylib); (( $ret == 1)) - - name: Build (apple-other.rs) run: cargo build --release --target=aarch64-apple-ios - - name: Check (apple-other.rs) - run: ret=$(grep -c panic target/aarch64-apple-ios/release/libgetrandom_wrapper.dylib); (( $ret == 1)) From b0555772545473fbb7e3bdbfbab74a7b8d9d5c76 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 17 Oct 2024 22:16:28 +0300 Subject: [PATCH 053/201] ci: add nopanic check for windows (#526) --- .github/workflows/nopanic.yaml | 12 ++++++++++++ nopanic_check/Cargo.toml | 1 + 2 files changed, 13 insertions(+) diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index 68a69ed70..ef61b216d 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -127,3 +127,15 @@ jobs: run: cargo build --release --target=aarch64-apple-darwin - name: Build (apple-other.rs) run: cargo build --release --target=aarch64-apple-ios + + windows: + name: Windows + runs-on: windows-2022 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: nightly-2024-10-14 + components: rust-src + - run: cargo build --release + - run: cargo build --release --target=x86_64-win7-windows-msvc -Zbuild-std="std,panic_abort" diff --git a/nopanic_check/Cargo.toml b/nopanic_check/Cargo.toml index de5774991..0b838eaa2 100644 --- a/nopanic_check/Cargo.toml +++ b/nopanic_check/Cargo.toml @@ -17,6 +17,7 @@ getrandom = { path = ".." } [profile.release] panic = "abort" strip = true +lto = "fat" [lints.rust.unexpected_cfgs] level = "warn" From f0bf800aaef194ca081dc3c1ed398aaa021e715b Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 17 Oct 2024 22:28:05 +0300 Subject: [PATCH 054/201] ci: enable nopanic check for Solaris (#527) This check now works thanks to LTO enabled in #526. --- .github/workflows/nopanic.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index ef61b216d..e88a47c59 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -105,10 +105,10 @@ jobs: - name: Check (netbsd.rs) run: (exit $( grep -c panic target/x86_64-unknown-netbsd/release/libgetrandom_wrapper.so )) - # - name: Build (solaris.rs) - # run: cross build --release --target=x86_64-pc-solaris - # - name: Check (solaris.rs) - # run: (exit $( grep -c panic target/x86_64-pc-solaris/release/libgetrandom_wrapper.so )) + - name: Build (solaris.rs) + run: cross build --release --target=x86_64-pc-solaris + - name: Check (solaris.rs) + run: (exit $( grep -c panic target/x86_64-pc-solaris/release/libgetrandom_wrapper.so )) macos: name: macOS From 60544382ce4323a85f4231a4bdfbb547638ea8eb Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 18 Oct 2024 17:07:45 +0300 Subject: [PATCH 055/201] ci: use VM to test BSD targets (#528) Add CI jobs for FreeBSD, OpenBSD, and NetBSD. Solaris is not tested because it lacks pre-compiled host tools. DragonflyBSD job is currently disabled because cargo fails to update crates.io index. --- .github/workflows/tests.yml | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1f1c320fc..9a6b42f8f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -216,6 +216,64 @@ jobs: - run: sudo xcode-select -switch /Applications/Xcode_15.2.app - run: cargo test --no-run --target=aarch64-apple-visionos -Zbuild-std --features=std + freebsd: + name: FreeBSD VM Test + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Test in FreeBSD + uses: vmactions/freebsd-vm@v1 + with: + envs: 'RUSTFLAGS' + usesh: true + prepare: | + pkg install -y rust + run: cargo test + + openbsd: + name: OpenBSD VM Test + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Test in OpenBSD + uses: vmactions/openbsd-vm@v1 + with: + envs: 'RUSTFLAGS' + usesh: true + prepare: | + pkg_add rust + run: cargo test + + netbsd: + name: NetBSD VM Test + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Test in NetBSD + uses: vmactions/netbsd-vm@v1 + with: + envs: 'RUSTFLAGS' + usesh: true + prepare: | + /usr/sbin/pkg_add rust + run: cargo test + + # This job currently fails: + # https://github.com/rust-random/getrandom/actions/runs/11405005618/job/31735653874?pr=528 + # dragonflybsd: + # name: DragonflyBSD VM Test + # runs-on: ubuntu-22.04 + # steps: + # - uses: actions/checkout@v4 + # - name: Test in DragonflyBSD + # uses: vmactions/dragonflybsd-vm@v1 + # with: + # envs: 'RUSTFLAGS' + # usesh: true + # prepare: | + # pkg install -y rust + # run: cargo test + cross-link: name: Cross Build/Link runs-on: ubuntu-22.04 From 3f8e95ec1a63b4971c717f9d49ded9f0f65b2cad Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 18 Oct 2024 21:26:09 +0300 Subject: [PATCH 056/201] ci: use Rust 1.82 for WASI tests (#529) --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9a6b42f8f..bef1f09fc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -371,7 +371,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: - toolchain: nightly # TODO: Use stable after 1.82 is released as stable + toolchain: 1.82 targets: wasm32-wasip1,wasm32-wasip2 - name: Install Wasmtime run: | From 41817c7fbd3bbfae427ee17a682249b0ffb0b04e Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 20 Oct 2024 09:46:20 +0300 Subject: [PATCH 057/201] ci: add comment about backends which do not have nopanic checks (#530) Also switch rust toolchain from Nightly to Stable in the nopanic's linux job. --- .github/workflows/nopanic.yaml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index e88a47c59..ffc749f7c 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -1,3 +1,12 @@ +# This CI config checks that getrandom's backend implementation +# do not contain potential panics. +# +# It is unclear how to implement a no-panic check for esp_idf, fuchsia, +# vxworks, hermit, and solid backends, so we do not check them here, +# but they still should be panic-free. We do not check wasm_js backend +# since glue code generated by wasm-bindgen contains potential panics, +# so resulting WASM files inevitably contain potential panics for any +# code which non-trivially interacts with the JS enviroment. name: No panic on: @@ -24,8 +33,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: - # We need Nightly for the rust-std component for wasm32-wasip2 - toolchain: nightly-2024-10-14 + toolchain: stable targets: wasm32-wasip1, wasm32-wasip2 - uses: Swatinem/rust-cache@v2 From 573f855bbf31a12d3801b5d00221bcde2297e534 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 20 Oct 2024 10:05:16 +0300 Subject: [PATCH 058/201] Rename `__getrandom_custom` to `__getrandom_v03_custom` (#531) This is done to prevent potential conflicts between getrandom v0.2 and v0.3 in the case when users rely on a custom backend and have both versions in their dependency tree. --- nopanic_check/src/lib.rs | 2 +- src/custom.rs | 4 ++-- src/lib.rs | 10 ++++++++-- tests/mod.rs | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/nopanic_check/src/lib.rs b/nopanic_check/src/lib.rs index af2c8ee33..37c4d28e8 100644 --- a/nopanic_check/src/lib.rs +++ b/nopanic_check/src/lib.rs @@ -19,7 +19,7 @@ pub extern "C" fn getrandom_wrapper(buf_ptr: *mut u8, buf_len: usize) -> u32 { #[cfg(getrandom_backend = "custom")] #[no_mangle] -unsafe extern "Rust" fn __getrandom_custom( +unsafe extern "Rust" fn __getrandom_v03_custom( dest: *mut u8, len: usize, ) -> Result<(), getrandom::Error> { diff --git a/src/custom.rs b/src/custom.rs index fc216e08c..c3e94349a 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -4,7 +4,7 @@ use core::mem::MaybeUninit; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { extern "Rust" { - fn __getrandom_custom(dest: *mut u8, len: usize) -> Result<(), Error>; + fn __getrandom_v03_custom(dest: *mut u8, len: usize) -> Result<(), Error>; } - unsafe { __getrandom_custom(dest.as_mut_ptr().cast(), dest.len()) } + unsafe { __getrandom_v03_custom(dest.as_mut_ptr().cast(), dest.len()) } } diff --git a/src/lib.rs b/src/lib.rs index 386e5906e..0a2b2a31e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -110,7 +110,10 @@ //! use getrandom::Error; //! //! #[no_mangle] -//! unsafe extern "Rust" fn __getrandom_custom(dest: *mut u8, len: usize) -> Result<(), Error> { +//! unsafe extern "Rust" fn __getrandom_v03_custom( +//! dest: *mut u8, +//! len: usize, +//! ) -> Result<(), Error> { //! todo!() //! } //! ``` @@ -133,7 +136,10 @@ //! use getrandom::Error; //! //! #[no_mangle] -//! unsafe extern "Rust" fn __getrandom_custom(dest: *mut u8, len: usize) -> Result<(), Error> { +//! unsafe extern "Rust" fn __getrandom_v03_custom( +//! dest: *mut u8, +//! len: usize, +//! ) -> Result<(), Error> { //! Err(Error::UNSUPPORTED) //! } //! ``` diff --git a/tests/mod.rs b/tests/mod.rs index 33083df55..47bc1b27e 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -206,7 +206,7 @@ mod custom { // // WARNING: this custom implementation is for testing purposes ONLY! #[no_mangle] - unsafe extern "Rust" fn __getrandom_custom(dest: *mut u8, len: usize) -> Result<(), Error> { + unsafe extern "Rust" fn __getrandom_v03_custom(dest: *mut u8, len: usize) -> Result<(), Error> { use std::time::{SystemTime, UNIX_EPOCH}; assert_ne!(len, 0); From 350df46548382c77ae5631197bbc7ba8074c6b07 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 21 Oct 2024 15:22:29 +0300 Subject: [PATCH 059/201] Rename `getrandom(_uninit)` to `fill(_uninit)` (#532) The new names are shorter and easier to understand (i.e. compare `getrandom::fill` vs `getrandom::getrandom`). --- CHANGELOG.md | 6 ++++- README.md | 2 +- benches/buffer.rs | 18 ++++++------- nopanic_check/src/lib.rs | 2 +- src/apple-other.rs | 2 +- src/custom.rs | 2 +- src/esp_idf.rs | 2 +- src/fuchsia.rs | 2 +- src/getentropy.rs | 2 +- src/getrandom.rs | 2 +- src/hermit.rs | 2 +- src/lib.rs | 43 ++++++++++++++++++------------ src/linux_android.rs | 2 +- src/linux_android_with_fallback.rs | 4 +-- src/linux_rustix.rs | 2 +- src/netbsd.rs | 2 +- src/rdrand.rs | 2 +- src/rndr.rs | 2 +- src/solaris.rs | 2 +- src/solid.rs | 2 +- src/use_file.rs | 2 +- src/vxworks.rs | 2 +- src/wasi.rs | 4 +-- src/wasm_js.rs | 2 +- src/windows.rs | 2 +- src/windows7.rs | 2 +- tests/mod.rs | 30 ++++++++++----------- 27 files changed, 80 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71c8b4e60..2383f6c57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Breaking Changes -- Update MSRV to 1.60 [#472] + +#### Changed +- Bump MSRV to 1.60 [#472] +- Rename `getrandom` and `getrandom_uninit` functions to `fill` and `fill_uninit` respectively [#532] #### Removed - `wasm32-wasi` target support (use `wasm32-wasip1` or `wasm32-wasip2` instead) [#499] @@ -46,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#520]: https://github.com/rust-random/getrandom/pull/520 [#521]: https://github.com/rust-random/getrandom/pull/521 [#522]: https://github.com/rust-random/getrandom/pull/522 +[#532]: https://github.com/rust-random/getrandom/pull/532 ## [0.2.15] - 2024-05-06 ### Added diff --git a/README.md b/README.md index ef8a6ce25..7393dbe90 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Then invoke the `getrandom` function: ```rust fn get_random_buf() -> Result<[u8; 32], getrandom::Error> { let mut buf = [0u8; 32]; - getrandom::getrandom(&mut buf)?; + getrandom::fill(&mut buf)?; Ok(buf) } ``` diff --git a/benches/buffer.rs b/benches/buffer.rs index 303bc3e47..2899a3f75 100644 --- a/benches/buffer.rs +++ b/benches/buffer.rs @@ -5,17 +5,17 @@ use std::mem::MaybeUninit; // Call getrandom on a zero-initialized stack buffer #[inline(always)] -fn bench_getrandom() { +fn bench_fill() { let mut buf = [0u8; N]; - getrandom::getrandom(&mut buf).unwrap(); + getrandom::fill(&mut buf).unwrap(); test::black_box(&buf[..]); } -// Call getrandom_uninit on an uninitialized stack buffer +// Call fill_uninit on an uninitialized stack buffer #[inline(always)] -fn bench_getrandom_uninit() { +fn bench_fill_uninit() { let mut uninit = [MaybeUninit::uninit(); N]; - let buf: &[u8] = getrandom::getrandom_uninit(&mut uninit).unwrap(); + let buf: &[u8] = getrandom::fill_uninit(&mut uninit).unwrap(); test::black_box(buf); } @@ -30,20 +30,20 @@ macro_rules! bench { ( $name:ident, $size:expr ) => { pub mod $name { #[bench] - pub fn bench_getrandom(b: &mut test::Bencher) { + pub fn bench_fill(b: &mut test::Bencher) { #[inline(never)] fn inner() { - super::bench_getrandom::<{ $size }>() + super::bench_fill::<{ $size }>() } b.bytes = $size as u64; b.iter(inner); } #[bench] - pub fn bench_getrandom_uninit(b: &mut test::Bencher) { + pub fn bench_fill_uninit(b: &mut test::Bencher) { #[inline(never)] fn inner() { - super::bench_getrandom_uninit::<{ $size }>() + super::bench_fill_uninit::<{ $size }>() } b.bytes = $size as u64; diff --git a/nopanic_check/src/lib.rs b/nopanic_check/src/lib.rs index 37c4d28e8..9a6a02b90 100644 --- a/nopanic_check/src/lib.rs +++ b/nopanic_check/src/lib.rs @@ -13,7 +13,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { #[no_mangle] pub extern "C" fn getrandom_wrapper(buf_ptr: *mut u8, buf_len: usize) -> u32 { let buf = unsafe { core::slice::from_raw_parts_mut(buf_ptr.cast(), buf_len) }; - let res = getrandom::getrandom_uninit(buf).map(|_| ()); + let res = getrandom::fill_uninit(buf).map(|_| ()); unsafe { core::mem::transmute(res) } } diff --git a/src/apple-other.rs b/src/apple-other.rs index 6c761494b..1990523fa 100644 --- a/src/apple-other.rs +++ b/src/apple-other.rs @@ -2,7 +2,7 @@ use crate::Error; use core::{ffi::c_void, mem::MaybeUninit}; -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let dst_ptr = dest.as_mut_ptr().cast::(); let ret = unsafe { libc::CCRandomGenerateBytes(dst_ptr, dest.len()) }; if ret == libc::kCCSuccess { diff --git a/src/custom.rs b/src/custom.rs index c3e94349a..e97d32931 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -2,7 +2,7 @@ use crate::Error; use core::mem::MaybeUninit; -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { extern "Rust" { fn __getrandom_v03_custom(dest: *mut u8, len: usize) -> Result<(), Error>; } diff --git a/src/esp_idf.rs b/src/esp_idf.rs index 75e81aafc..2df7b9aae 100644 --- a/src/esp_idf.rs +++ b/src/esp_idf.rs @@ -9,7 +9,7 @@ extern "C" { fn esp_fill_random(buf: *mut c_void, len: usize) -> u32; } -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> 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 diff --git a/src/fuchsia.rs b/src/fuchsia.rs index 22ae77961..b8e6de860 100644 --- a/src/fuchsia.rs +++ b/src/fuchsia.rs @@ -7,7 +7,7 @@ extern "C" { fn zx_cprng_draw(buffer: *mut u8, length: usize); } -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { unsafe { zx_cprng_draw(dest.as_mut_ptr().cast::(), dest.len()) } Ok(()) } diff --git a/src/getentropy.rs b/src/getentropy.rs index eee47403d..78c797e1a 100644 --- a/src/getentropy.rs +++ b/src/getentropy.rs @@ -10,7 +10,7 @@ use crate::{util_libc::last_os_error, Error}; use core::{ffi::c_void, mem::MaybeUninit}; -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { for chunk in dest.chunks_mut(256) { let ret = unsafe { libc::getentropy(chunk.as_mut_ptr().cast::(), chunk.len()) }; if ret != 0 { diff --git a/src/getrandom.rs b/src/getrandom.rs index 88c077c6d..e0f463de3 100644 --- a/src/getrandom.rs +++ b/src/getrandom.rs @@ -18,7 +18,7 @@ use crate::{util_libc::sys_fill_exact, Error}; use core::{ffi::c_void, mem::MaybeUninit}; -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { sys_fill_exact(dest, |buf| unsafe { libc::getrandom(buf.as_mut_ptr().cast::(), buf.len(), 0) }) diff --git a/src/hermit.rs b/src/hermit.rs index 9dc9d8bd9..594b330b2 100644 --- a/src/hermit.rs +++ b/src/hermit.rs @@ -6,7 +6,7 @@ extern "C" { fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize; } -pub fn getrandom_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { while !dest.is_empty() { let res = unsafe { sys_read_entropy(dest.as_mut_ptr().cast::(), dest.len(), 0) }; match res { diff --git a/src/lib.rs b/src/lib.rs index 0a2b2a31e..d2e5855a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -213,9 +213,9 @@ //! //! ## Sanitizer support //! -//! If your code uses `getrandom_uninit` and you use memory sanitizer +//! If your code uses [`fill_uninit`] and you use memory sanitizer //! (i.e. `-Zsanitizer=memory`), then you need to pass `getrandom_sanitize` -//! configuration flag for `getrandom_uninit` to unpoison destination buffer. +//! configuration flag for `fill_uninit` to unpoison destination buffer. //! //! For example, it can be done like this (requires Nightly compiler): //! ```text @@ -304,8 +304,8 @@ use crate::util::{slice_as_uninit_mut, slice_assume_init_mut}; // System-specific implementations. // -// These should all provide getrandom_inner with the signature -// `fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error>`. +// These should all provide fill_inner with the signature +// `fn fill_inner(dest: &mut [MaybeUninit]) -> 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. @@ -442,8 +442,7 @@ cfg_if! { } } -/// Fill `dest` with random bytes from the system's preferred random number -/// source. +/// 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 @@ -455,17 +454,27 @@ cfg_if! { /// 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 getrandom(dest: &mut [u8]) -> Result<(), Error> { - // SAFETY: The `&mut MaybeUninit<_>` reference doesn't escape, and - // `getrandom_uninit` guarantees it will never de-initialize any part of - // `dest`. - getrandom_uninit(unsafe { slice_as_uninit_mut(dest) })?; +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 { slice_as_uninit_mut(dest) })?; Ok(()) } -/// Version of the `getrandom` function which fills `dest` with random bytes -/// returns a mutable reference to those bytes. +/// 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. @@ -482,13 +491,13 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> { /// #![feature(maybe_uninit_uninit_array)] /// # fn main() -> Result<(), getrandom::Error> { /// let mut buf = core::mem::MaybeUninit::uninit_array::<1024>(); -/// let buf: &mut [u8] = getrandom::getrandom_uninit(&mut buf)?; +/// let buf: &mut [u8] = getrandom::fill_uninit(&mut buf)?; /// # Ok(()) } /// ``` #[inline] -pub fn getrandom_uninit(dest: &mut [MaybeUninit]) -> Result<&mut [u8], Error> { +pub fn fill_uninit(dest: &mut [MaybeUninit]) -> Result<&mut [u8], Error> { if !dest.is_empty() { - imp::getrandom_inner(dest)?; + imp::fill_inner(dest)?; } #[cfg(getrandom_sanitize)] @@ -497,7 +506,7 @@ pub fn getrandom_uninit(dest: &mut [MaybeUninit]) -> Result<&mut [u8], Error fn __msan_unpoison(a: *mut core::ffi::c_void, size: usize); } - // SAFETY: `dest` has been fully initialized by `imp::getrandom_inner` + // SAFETY: `dest` has been fully initialized by `imp::fill_inner` // since it returned `Ok`. Ok(unsafe { #[cfg(getrandom_sanitize)] diff --git a/src/linux_android.rs b/src/linux_android.rs index 548401b2c..a4dd4e26a 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -5,7 +5,7 @@ use core::mem::MaybeUninit; #[cfg(not(any(target_os = "android", target_os = "linux")))] compile_error!("`linux_getrandom` backend can be enabled only for Linux/Android targets!"); -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { util_libc::sys_fill_exact(dest, |buf| unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }) diff --git a/src/linux_android_with_fallback.rs b/src/linux_android_with_fallback.rs index dd401caac..53570d2f4 100644 --- a/src/linux_android_with_fallback.rs +++ b/src/linux_android_with_fallback.rs @@ -52,10 +52,10 @@ fn init() -> NonNull { // prevent inlining of the fallback implementation #[inline(never)] fn use_file_fallback(dest: &mut [MaybeUninit]) -> Result<(), Error> { - use_file::getrandom_inner(dest) + use_file::fill_inner(dest) } -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> 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 diff --git a/src/linux_rustix.rs b/src/linux_rustix.rs index a286b20ce..4fef33818 100644 --- a/src/linux_rustix.rs +++ b/src/linux_rustix.rs @@ -5,7 +5,7 @@ use rustix::rand::{getrandom_uninit, GetRandomFlags}; #[cfg(not(any(target_os = "android", target_os = "linux")))] compile_error!("`linux_rustix` backend can be enabled only for Linux/Android targets!"); -pub fn getrandom_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { loop { let res = getrandom_uninit(dest, GetRandomFlags::empty()).map(|(res, _)| res.len()); match res { diff --git a/src/netbsd.rs b/src/netbsd.rs index 10cb2e54a..a96d353f0 100644 --- a/src/netbsd.rs +++ b/src/netbsd.rs @@ -57,7 +57,7 @@ fn init() -> *mut c_void { ptr } -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> 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 diff --git a/src/rdrand.rs b/src/rdrand.rs index 68f9878c5..2f2aed145 100644 --- a/src/rdrand.rs +++ b/src/rdrand.rs @@ -96,7 +96,7 @@ fn is_rdrand_good() -> bool { unsafe { self_test() } } -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { static RDRAND_GOOD: LazyBool = LazyBool::new(); if !RDRAND_GOOD.unsync_init(is_rdrand_good) { return Err(Error::NO_RDRAND); diff --git a/src/rndr.rs b/src/rndr.rs index c670b53f1..573fa9a41 100644 --- a/src/rndr.rs +++ b/src/rndr.rs @@ -101,7 +101,7 @@ fn is_rndr_available() -> bool { } } -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { if is_rndr_available() { // SAFETY: after this point, we know the `rand` target feature is enabled unsafe { rndr_fill(dest).ok_or(Error::RNDR_FAILURE) } diff --git a/src/solaris.rs b/src/solaris.rs index 203000b01..f2470e8a8 100644 --- a/src/solaris.rs +++ b/src/solaris.rs @@ -17,7 +17,7 @@ use core::{ffi::c_void, mem::MaybeUninit}; const MAX_BYTES: usize = 1024; -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { for chunk in dest.chunks_mut(MAX_BYTES) { let ptr = chunk.as_mut_ptr().cast::(); let ret = unsafe { libc::getrandom(ptr, chunk.len(), libc::GRND_RANDOM) }; diff --git a/src/solid.rs b/src/solid.rs index 36f51caab..50bbe47ee 100644 --- a/src/solid.rs +++ b/src/solid.rs @@ -6,7 +6,7 @@ extern "C" { pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> i32; } -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let ret = unsafe { SOLID_RNG_SampleRandomBytes(dest.as_mut_ptr().cast::(), dest.len()) }; if ret >= 0 { Ok(()) diff --git a/src/use_file.rs b/src/use_file.rs index ff6b22366..453775729 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -37,7 +37,7 @@ const FD_ONGOING_INIT: libc::c_int = -2; // `Ordering::Acquire` to synchronize with it. static FD: AtomicI32 = AtomicI32::new(FD_UNINIT); -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let mut fd = FD.load(Ordering::Acquire); if fd == FD_UNINIT || fd == FD_ONGOING_INIT { fd = open_or_wait()?; diff --git a/src/vxworks.rs b/src/vxworks.rs index 58b6c9621..6d8a4bf95 100644 --- a/src/vxworks.rs +++ b/src/vxworks.rs @@ -6,7 +6,7 @@ use core::{ sync::atomic::{AtomicBool, Ordering::Relaxed}, }; -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { static RNG_INIT: AtomicBool = AtomicBool::new(false); while !RNG_INIT.load(Relaxed) { let ret = unsafe { libc::randSecure() }; diff --git a/src/wasi.rs b/src/wasi.rs index 9df9bf26f..a1ecf0047 100644 --- a/src/wasi.rs +++ b/src/wasi.rs @@ -12,7 +12,7 @@ compile_error!( ); #[cfg(target_env = "p1")] -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // 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")] @@ -38,7 +38,7 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { } #[cfg(target_env = "p2")] -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { use core::ptr::copy_nonoverlapping; use wasi::random::random::get_random_u64; diff --git a/src/wasm_js.rs b/src/wasm_js.rs index 026fa9acc..da70d5ad7 100644 --- a/src/wasm_js.rs +++ b/src/wasm_js.rs @@ -30,7 +30,7 @@ thread_local!( static RNG_SOURCE: Result = getrandom_init(); ); -pub(crate) fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub(crate) fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { RNG_SOURCE.with(|result| { let source = result.as_ref().map_err(|&e| e)?; diff --git a/src/windows.rs b/src/windows.rs index e44c42926..642206e71 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -31,7 +31,7 @@ windows_targets::link!("bcryptprimitives.dll" "system" fn ProcessPrng(pbdata: *m pub type BOOL = i32; pub const TRUE: BOOL = 1i32; -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // ProcessPrng should always return TRUE, but we check just in case. match unsafe { ProcessPrng(dest.as_mut_ptr().cast::(), dest.len()) } { TRUE => Ok(()), diff --git a/src/windows7.rs b/src/windows7.rs index 667bbf26b..573ac8810 100644 --- a/src/windows7.rs +++ b/src/windows7.rs @@ -23,7 +23,7 @@ extern "system" { type BOOLEAN = u8; const TRUE: BOOLEAN = 1u8; -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> 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) { diff --git a/tests/mod.rs b/tests/mod.rs index 47bc1b27e..58e229514 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -1,5 +1,5 @@ use core::mem::MaybeUninit; -use getrandom::{getrandom, getrandom_uninit}; +use getrandom::{fill, fill_uninit}; #[cfg(getrandom_browser_test)] use wasm_bindgen_test::wasm_bindgen_test as test; @@ -9,8 +9,8 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); #[test] fn test_zero() { // Test that APIs are happy with zero-length requests - getrandom(&mut [0u8; 0]).unwrap(); - let res = getrandom_uninit(&mut []).unwrap(); + fill(&mut [0u8; 0]).unwrap(); + let res = fill_uninit(&mut []).unwrap(); assert!(res.is_empty()); } @@ -35,13 +35,13 @@ fn test_diff() { const N: usize = 1000; let mut v1 = [0u8; N]; let mut v2 = [0u8; N]; - getrandom(&mut v1).unwrap(); - getrandom(&mut v2).unwrap(); + fill(&mut v1).unwrap(); + fill(&mut v2).unwrap(); let mut t1 = uninit_vec(N); let mut t2 = uninit_vec(N); - let r1 = getrandom_uninit(&mut t1).unwrap(); - let r2 = getrandom_uninit(&mut t2).unwrap(); + let r1 = fill_uninit(&mut t1).unwrap(); + let r2 = fill_uninit(&mut t2).unwrap(); assert_eq!(r1.len(), N); assert_eq!(r2.len(), N); @@ -71,8 +71,8 @@ fn test_small() { let s1 = &mut buf1[..size]; let s2 = &mut buf2[..size]; - getrandom(s1).unwrap(); - getrandom(s2).unwrap(); + fill(s1).unwrap(); + fill(s2).unwrap(); num_bytes += size; diff_bits += num_diff_bits(s1, s2); @@ -99,8 +99,8 @@ fn test_small_uninit() { let s1 = &mut buf1[..size]; let s2 = &mut buf2[..size]; - let r1 = getrandom_uninit(s1).unwrap(); - let r2 = getrandom_uninit(s2).unwrap(); + let r1 = fill_uninit(s1).unwrap(); + let r2 = fill_uninit(s2).unwrap(); assert_eq!(r1.len(), size); assert_eq!(r2.len(), size); @@ -115,14 +115,14 @@ fn test_small_uninit() { #[test] fn test_huge() { let mut huge = [0u8; 100_000]; - getrandom(&mut huge).unwrap(); + fill(&mut huge).unwrap(); } #[test] fn test_huge_uninit() { const N: usize = 100_000; let mut huge = uninit_vec(N); - let res = getrandom_uninit(&mut huge).unwrap(); + let res = fill_uninit(&mut huge).unwrap(); assert_eq!(res.len(), N); } @@ -146,7 +146,7 @@ fn test_multithreading() { let mut v = [0u8; 1000]; for _ in 0..100 { - getrandom(&mut v).unwrap(); + fill(&mut v).unwrap(); thread::yield_now(); } }); @@ -236,7 +236,7 @@ mod custom { #[test] fn test_custom() { let mut buf = [0u8; 142]; - let res = getrandom::getrandom(&mut buf); + let res = getrandom::fill(&mut buf); assert!(res.is_err()); } } From 5c7a1978873472feb4d06b8fc31fd8265d7f89f2 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 21 Oct 2024 15:50:48 +0300 Subject: [PATCH 060/201] Unify crate docs and README (#533) --- README.md | 312 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/lib.rs | 270 +--------------------------------------------- 2 files changed, 290 insertions(+), 292 deletions(-) diff --git a/README.md b/README.md index 7393dbe90..1e04afb1c 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,10 @@ -# getrandom +# getrandom: (operating) system's random number generator [![Build Status]][GitHub Actions] [![Crate]][crates.io] [![Documentation]][docs.rs] [![Dependency Status]][deps.rs] [![Downloads]][crates.io] [![License]][LICENSE-MIT] -[GitHub Actions]: https://github.com/rust-random/getrandom/actions?query=workflow:Tests+branch:master -[Build Status]: https://github.com/rust-random/getrandom/actions/workflows/tests.yml/badge.svg?branch=master -[crates.io]: https://crates.io/crates/getrandom -[Crate]: https://img.shields.io/crates/v/getrandom -[docs.rs]: https://docs.rs/getrandom -[Documentation]: https://docs.rs/getrandom/badge.svg -[deps.rs]: https://deps.rs/repo/github/rust-random/getrandom -[Dependency Status]: https://deps.rs/repo/github/rust-random/getrandom/status.svg -[Downloads]: https://img.shields.io/crates/d/getrandom -[LICENSE-MIT]: https://raw.githubusercontent.com/rust-random/getrandom/master/LICENSE-MIT -[License]: https://img.shields.io/crates/l/getrandom - +`getrandom` is a Rust library for retrieving random data from (operating) system sources. -A Rust library for retrieving random data from (operating) system sources. It is -assumed that the system always provides high-quality cryptographically secure random +It is assumed that the system always provides high-quality cryptographically secure random data, ideally backed by hardware entropy sources. This crate derives its name from Linux's `getrandom` function, but is cross-platform, roughly supporting the same set of platforms as Rust's `std` lib. @@ -35,7 +23,7 @@ Add this to your `Cargo.toml`: getrandom = "0.2" ``` -Then invoke the `getrandom` function: +Then invoke the `fill` function: ```rust fn get_random_buf() -> Result<[u8; 32], getrandom::Error> { @@ -45,22 +33,231 @@ fn get_random_buf() -> Result<[u8; 32], getrandom::Error> { } ``` -For more information about supported targets, entropy sources, `no_std` targets, -crate features, WASM support and Custom RNGs see the -[`getrandom` documentation](https://docs.rs/getrandom/latest) and -[`getrandom::Error` documentation](https://docs.rs/getrandom/latest/getrandom/struct.Error.html). +## Supported targets -## Minimum Supported Rust Version +| Target | Target Triple | Implementation +| ------------------ | ------------------ | -------------- +| Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` +| Windows 10+ | `*‑windows‑*` | [`ProcessPrng`] +| Windows 7, 8 | `*-win7‑windows‑*` | [`RtlGenRandom`] +| macOS | `*‑apple‑darwin` | [`getentropy`][3] +| iOS, tvOS, watchOS | `*‑apple‑{ios,tvos,watchos}` | [`CCRandomGenerateBytes`] +| FreeBSD | `*‑freebsd` | [`getrandom`][5] +| OpenBSD | `*‑openbsd` | [`getentropy`][7] +| NetBSD | `*‑netbsd` | [`getrandom`][16] if available, otherwise [`kern.arandom`][8] +| Dragonfly BSD | `*‑dragonfly` | [`getrandom`][9] +| Solaris | `*‑solaris` | [`getrandom`][11] with `GRND_RANDOM` +| illumos | `*‑illumos` | [`getrandom`][12] +| Fuchsia OS | `*‑fuchsia` | [`cprng_draw`] +| Redox | `*‑redox` | `/dev/urandom` +| Haiku | `*‑haiku` | `/dev/urandom` (identical to `/dev/random`) +| Hermit | `*-hermit` | [`sys_read_entropy`] +| Hurd | `*-hurd-*` | [`getrandom`][17] +| SGX | `x86_64‑*‑sgx` | [`RDRAND`] +| VxWorks | `*‑wrs‑vxworks‑*` | `randABytes` after checking entropy pool initialization with `randSecure` +| Emscripten | `*‑emscripten` | [`getentropy`][13] +| WASI 0.1 | `wasm32‑wasip1` | [`random_get`] +| WASI 0.2 | `wasm32‑wasip2` | [`get-random-u64`] +| SOLID | `*-kmc-solid_*` | `SOLID_RNG_SampleRandomBytes` +| Nintendo 3DS | `*-nintendo-3ds` | [`getrandom`][18] +| PS Vita | `*-vita-*` | [`getentropy`][13] +| QNX Neutrino | `*‑nto-qnx*` | [`/dev/urandom`][14] (identical to `/dev/random`) +| AIX | `*-ibm-aix` | [`/dev/urandom`][15] -This crate requires Rust 1.60.0 or later. +Pull Requests that add support for new targets to `getrandom` are always welcome. + +### Opt-in backends + +`getrandom` also provides optional backends which can be enabled using `getrandom_backend` +configuration flag: + +| Backend name | Target | Target Triple | Implementation +| ----------------- | -------------------- | -------------------- | -------------- +| `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). +| `linux_rustix` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses [`rustix`] instead of `libc`. +| `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction +| `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register +| `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low quality entropy without proper hardware configuration! +| `wasm_js` | Web Browser, Node.js | `wasm*‑*‑unknown` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js (see [WebAssembly support]) +| `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) + +The configuration flag can be enabled either by specifying the `rustflags` field in +[`.cargo/config.toml`] (note that it can be done on a per-target basis), or by using +`RUSTFLAGS` environment variable: + +```sh +RUSTFLAGS='--cfg getrandom_backend="linux_getrandom"' cargo build +``` + +Enabling an opt-in backend will replace backend used by default. Doing it for a wrong target +(e.g. using `linux_getrandom` while compiling for a Windows target) will result +in a compilation error. Be extremely carefull while using opt-in backends, since incorrect +configuration may result in vulnerable or in always panicking applications. + +Note that using an opt-in backend in a library (e.g. for tests or benchmarks) +WILL NOT have any effect on its downstream users. + +[`.cargo/config.toml`]: https://doc.rust-lang.org/cargo/reference/config.html + +### WebAssembly support + +This crate fully supports the [WASI] and [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 should be used (or if JavaScript is available at all). + +Instead, *if the `wasm_js` backend 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](#opt-in-backends) using the [`wasm-bindgen`] toolchain. + +To enable the `wasm_js` backend, you can add the following lines to your +project's `.cargo/config.toml` file: +```toml +[target.wasm32-unknown-unknown] +rustflags = ['--cfg', 'getrandom_backend="wasm_js"'] +``` + +#### Node.js ES module support + +Node.js supports both [CommonJS modules] and [ES modules]. Due to +limitations in wasm-bindgen's [`module`] support, we cannot directly +support ES Modules running on Node.js. However, on Node v15 and later, the +module author can add a simple shim to support the Web Cryptography API: +```js +import { webcrypto } from 'node:crypto' +globalThis.crypto = webcrypto +``` +This crate will then use the provided `webcrypto` implementation. + +### Custom backend + +If this crate does not support your target out of box or you have to use +a non-default entropy source, then you can provide a custom implementation. +You need to enable the custom backend as described in the [configuration flags] +section. Next, you need to define an `extern` function with the following +signature: + +```rust +use getrandom::Error; + +#[no_mangle] +unsafe extern "Rust" fn __getrandom_v03_custom( + dest: *mut u8, + len: usize, +) -> Result<(), Error> { + todo!() +} +``` + +This function ideally should be defined in the root crate of your project, +e.g. in your `main.rs`. This function MUST be defined only once for your +project, i.e. upstream library crates SHOULD NOT define it outside of +tests and benchmarks. Improper configuration of this backend may result +in linking errors. + +The function accepts pointer to buffer which should be filled with random +data and length in bytes. Note that the buffer MAY be uninitialized. +On success the function should return 0 and fully fill the input buffer, +every other return result will be interpreted as an error code. + +If you are confident that `getrandom` is not used in your project, but +it gets pulled nevertheless by one of your dependencies, then you can +use the following custom backend which always returns "unsupported" error: +```rust +use getrandom::Error; + +#[no_mangle] +unsafe extern "Rust" fn __getrandom_v03_custom( + dest: *mut u8, + len: usize, +) -> Result<(), Error> { + Err(Error::UNSUPPORTED) +} +``` + +### Platform Support +This crate generally supports the same operating system and platform versions +that the Rust standard library does. Additional targets may be supported using +pluggable custom implementations. + +This means that as Rust drops support for old versions of operating systems +(such as old Linux kernel versions, Android API levels, etc) in stable releases, +`getrandom` may create new patch releases (`0.N.x`) that remove support for +outdated platform versions. + +### `/dev/urandom` fallback on Linux and Android + +On Linux targets the fallback is present only if either `target_env` is `musl`, +or `target_arch` is one of the following: `aarch64`, `arm`, `powerpc`, `powerpc64`, +`s390x`, `x86`, `x86_64`. Other supported targets [require][platform-support] +kernel versions which support `getrandom` system call, so fallback is not needed. + +On Android targets the fallback is present only for the following `target_arch`es: +`aarch64`, `arm`, `x86`, `x86_64`. Other `target_arch`es (e.g. RISC-V) require +sufficiently high API levels. + +The fallback can be disabled by enabling the `linux_getrandom` opt-in backend. +Note that doing so will bump minimum supported Linux kernel version to 3.17 and +Android API level to 23 (Marshmallow). + +### Early boot -## Platform Support +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. -This crate generally supports the same operating system and platform versions that the Rust standard library does. -Additional targets may be supported using pluggable custom implementations. +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. -This means that as Rust drops support for old versions of operating systems (such as old Linux kernel versions, Android API levels, etc) -in stable releases, `getrandom` may create new patch releases (`0.N.x`) that remove support for outdated platform versions. +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. + +On OpenBSD, this kind of entropy accounting isn't available, and on +NetBSD, blocking on it is discouraged. On these platforms, nonblocking +interfaces are used, even when reliable entropy may not be available. +On the platforms where it is used, the reliability of entropy accounting +itself isn't free from controversy. This library provides randomness +sourced according to the platform's best practices, but each platform has +its own limits on the grade of randomness it can promise in environments +with few sources of entropy. + +## Error handling + +We always choose failure over returning known 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. + +## Panic handling + +We strive to eliminate all potential panics from our implementation. +In other words, when compiled with enabled optimizations, generated +binary code for `getrandom` functions should not contain any panic +branches. Even if platform misbiheaves and returns an unexpected +result, our code should correctly handle it and return an error like +[`Error::UNEXPECTED`]. + +## Sanitizer support + +If your code uses [`fill_uninit`] and you use memory sanitizer +(i.e. `-Zsanitizer=memory`), then you need to pass `getrandom_sanitize` +configuration flag for `fill_uninit` to unpoison destination buffer. + +For example, it can be done like this (requires Nightly compiler): +```sh +RUSTFLAGS="-Zsanitizer=memory --cfg getrandom_sanitize" cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu +``` + +## Minimum Supported Rust Version + +This crate requires Rust 1.60.0 or later. ## License @@ -77,5 +274,66 @@ Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. +[//]: # (badges) + +[GitHub Actions]: https://github.com/rust-random/getrandom/actions?query=workflow:Tests+branch:master +[Build Status]: https://github.com/rust-random/getrandom/actions/workflows/tests.yml/badge.svg?branch=master +[crates.io]: https://crates.io/crates/getrandom +[Crate]: https://img.shields.io/crates/v/getrandom +[docs.rs]: https://docs.rs/getrandom +[Documentation]: https://docs.rs/getrandom/badge.svg +[deps.rs]: https://deps.rs/repo/github/rust-random/getrandom +[Dependency Status]: https://deps.rs/repo/github/rust-random/getrandom/status.svg +[Downloads]: https://img.shields.io/crates/d/getrandom +[License]: https://img.shields.io/crates/l/getrandom + +[//]: # (supported targets) + +[1]: https://manned.org/getrandom.2 +[2]: https://manned.org/urandom.4 +[3]: https://www.unix.com/man-page/mojave/2/getentropy/ +[4]: https://www.unix.com/man-page/mojave/4/urandom/ +[5]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable +[7]: https://man.openbsd.org/getentropy.2 +[8]: https://man.netbsd.org/sysctl.7 +[9]: https://leaf.dragonflybsd.org/cgi/web-man?command=getrandom +[11]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html +[12]: https://illumos.org/man/2/getrandom +[13]: https://github.com/emscripten-core/emscripten/pull/12240 +[14]: https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.utilities/topic/r/random.html +[15]: https://www.ibm.com/docs/en/aix/7.3?topic=files-random-urandom-devices +[16]: https://man.netbsd.org/getrandom.2 +[17]: https://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getrandom +[18]: https://github.com/rust3ds/shim-3ds/commit/b01d2568836dea2a65d05d662f8e5f805c64389d + +[`ProcessPrng`]: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng +[`RtlGenRandom`]: https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom +[`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 +[`RNDR`]: https://developer.arm.com/documentation/ddi0601/2024-06/AArch64-Registers/RNDR--Random-Number +[`CCRandomGenerateBytes`]: https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html +[`cprng_draw`]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw +[`crypto.randomFillSync`]: https://nodejs.org/api/crypto.html#cryptorandomfillsyncbuffer-offset-size +[`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/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-buf_len-size---errno +[`get-random-u64`]: https://github.com/WebAssembly/WASI/blob/v0.2.1/wasip2/random/random.wit#L23-L28 +[WebAssembly support]: #webassembly-support +[configuration flags]: #configuration-flags +[custom backend]: #custom-backend +[`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen +[`module`]: https://rustwasm.github.io/wasm-bindgen/reference/attributes/on-js-imports/module.html +[CommonJS modules]: https://nodejs.org/api/modules.html +[ES modules]: https://nodejs.org/api/esm.html +[`sys_read_entropy`]: https://github.com/hermit-os/kernel/blob/315f58ff5efc81d9bf0618af85a59963ff55f8b1/src/syscalls/entropy.rs#L47-L55 +[platform-support]: https://doc.rust-lang.org/stable/rustc/platform-support.html +[WASI]: https://github.com/CraneStation/wasi +[Emscripten]: https://www.hellorust.com/setup/emscripten/ +[`rustix`]: https://docs.rs/rustix + +[//]: # (licenses) + [LICENSE-APACHE]: https://github.com/rust-random/getrandom/blob/master/LICENSE-APACHE [LICENSE-MIT]: https://github.com/rust-random/getrandom/blob/master/LICENSE-MIT + +[`Error::UNEXPECTED`]: https://docs.rs/getrandom/latest/getrandom/struct.Error.html#associatedconstant.UNEXPECTED +[`fill_uninit`]: https://docs.rs/getrandom/latest/getrandom/fn.fill_uninit.html diff --git a/src/lib.rs b/src/lib.rs index d2e5855a4..bc7b35701 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,274 +1,14 @@ -//! 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 10+ | `*‑windows‑*` | [`ProcessPrng`] -//! | Windows 7, 8 | `*-win7‑windows‑*` | [`RtlGenRandom`] -//! | macOS | `*‑apple‑darwin` | [`getentropy`][3] -//! | iOS, tvOS, watchOS | `*‑apple‑ios`, `*-apple-tvos`, `*-apple-watchos` | [`CCRandomGenerateBytes`] -//! | FreeBSD | `*‑freebsd` | [`getrandom`][5] -//! | OpenBSD | `*‑openbsd` | [`getentropy`][7] -//! | NetBSD | `*‑netbsd` | [`getrandom`][16] if available, otherwise [`kern.arandom`][8] -//! | Dragonfly BSD | `*‑dragonfly` | [`getrandom`][9] -//! | Solaris | `*‑solaris` | [`getrandom`][11] with `GRND_RANDOM` -//! | illumos | `*‑illumos` | [`getrandom`][12] -//! | Fuchsia OS | `*‑fuchsia` | [`cprng_draw`] -//! | Redox | `*‑redox` | `/dev/urandom` -//! | Haiku | `*‑haiku` | `/dev/urandom` (identical to `/dev/random`) -//! | Hermit | `*-hermit` | [`sys_read_entropy`] -//! | Hurd | `*-hurd-*` | [`getrandom`][17] -//! | SGX | `x86_64‑*‑sgx` | [`RDRAND`] -//! | VxWorks | `*‑wrs‑vxworks‑*` | `randABytes` after checking entropy pool initialization with `randSecure` -//! | Emscripten | `*‑emscripten` | [`getentropy`][13] -//! | WASI 0.1 | `wasm32‑wasip1` | [`random_get`] -//! | WASI 0.2 | `wasm32‑wasip2` | [`get-random-u64`] -//! | SOLID | `*-kmc-solid_*` | `SOLID_RNG_SampleRandomBytes` -//! | Nintendo 3DS | `*-nintendo-3ds` | [`getrandom`][18] -//! | PS Vita | `*-vita-*` | [`getentropy`][13] -//! | QNX Neutrino | `*‑nto-qnx*` | [`/dev/urandom`][14] (identical to `/dev/random`) -//! | AIX | `*-ibm-aix` | [`/dev/urandom`][15] -//! -//! Pull Requests that add support for new targets to `getrandom` are always welcome. -//! -//! ## Opt-in backends -//! -//! `getrandom` also provides optional backends which can be enabled using `getrandom_backend` -//! configuration flag: -//! -//! | Backend name | Target | Target Triple | Implementation -//! | ----------------- | -------------------- | -------------------- | -------------- -//! | `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). -//! | `linux_rustix` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses [`rustix`] instead of `libc`. -//! | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction -//! | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register -//! | `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low quality entropy without proper hardware configuration! -//! | `wasm_js` | Web Browser, Node.js | `wasm*‑*‑unknown` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js (see [WebAssembly support]) -//! | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) -//! -//! The configuration flag can be enabled either by specifying the `rustflags` field in -//! [`.cargo/config.toml`] (note that it can be done on a per-target basis), or by using -//! `RUSTFLAGS` environment variable: -//! -//! ```sh -//! RUSTFLAGS='--cfg getrandom_backend="linux_getrandom"' cargo build -//! ``` -//! -//! Enabling an opt-in backend will replace backend used by default. Doing it for a wrong target -//! (e.g. using `linux_getrandom` while compiling for a Windows target) will result -//! in a compilation error. Be extremely carefull while using opt-in backends, since incorrect -//! configuration may result in vulnerable or in always panicking applications. -//! -//! Note that using an opt-in backend in a library (e.g. for tests or benchmarks) -//! WILL NOT have any effect on its downstream users. -//! -//! [`.cargo/config.toml`]: https://doc.rust-lang.org/cargo/reference/config.html -//! -//! ### WebAssembly support -//! -//! This crate fully supports the [WASI] and [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 should be used (or if JavaScript is available at all). -//! -//! Instead, *if the `wasm_js` backend 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](#opt-in-backends) using the [`wasm-bindgen`] toolchain. -//! -//! To enable the `wasm_js` backend, you can add the following lines to your -//! project's `.cargo/config.toml` file: -//! ```toml -//! [target.wasm32-unknown-unknown] -//! rustflags = ['--cfg', 'getrandom_backend="wasm_js"'] -//! ``` -//! -//! #### Node.js ES module support -//! -//! Node.js supports both [CommonJS modules] and [ES modules]. Due to -//! limitations in wasm-bindgen's [`module`] support, we cannot directly -//! support ES Modules running on Node.js. However, on Node v15 and later, the -//! module author can add a simple shim to support the Web Cryptography API: -//! ```js -//! import { webcrypto } from 'node:crypto' -//! globalThis.crypto = webcrypto -//! ``` -//! This crate will then use the provided `webcrypto` implementation. -//! -//! ### Custom backend -//! -//! If this crate does not support your target out of box or you have to use -//! a non-default entropy source, then you can provide a custom implementation. -//! You need to enable the custom backend as described in the [configuration flags] -//! section. Next, you need to define an `extern` function with the following -//! signature: -//! -//! ``` -//! use getrandom::Error; -//! -//! #[no_mangle] -//! unsafe extern "Rust" fn __getrandom_v03_custom( -//! dest: *mut u8, -//! len: usize, -//! ) -> Result<(), Error> { -//! todo!() -//! } -//! ``` -//! -//! This function ideally should be defined in the root crate of your project, -//! e.g. in your `main.rs`. This function MUST be defined only once for your -//! project, i.e. upstream library crates SHOULD NOT define it outside of -//! tests and benchmarks. Improper configuration of this backend may result -//! in linking errors. -//! -//! The function accepts pointer to buffer which should be filled with random -//! data and length in bytes. Note that the buffer MAY be uninitialized. -//! On success the function should return 0 and fully fill the input buffer, -//! every other return result will be interpreted as an error code. -//! -//! If you are confident that `getrandom` is not used in your project, but -//! it gets pulled nevertheless by one of your dependencies, then you can -//! use the following custom backend which always returns "unsupported" error: -//! ``` -//! use getrandom::Error; -//! -//! #[no_mangle] -//! unsafe extern "Rust" fn __getrandom_v03_custom( -//! dest: *mut u8, -//! len: usize, -//! ) -> Result<(), Error> { -//! Err(Error::UNSUPPORTED) -//! } -//! ``` -//! -//! ### Platform Support -//! This crate generally supports the same operating system and platform versions -//! that the Rust standard library does. Additional targets may be supported using -//! pluggable custom implementations. -//! -//! This means that as Rust drops support for old versions of operating systems -//! (such as old Linux kernel versions, Android API levels, etc) in stable releases, -//! `getrandom` may create new patch releases (`0.N.x`) that remove support for -//! outdated platform versions. -//! -//! ## `/dev/urandom` fallback on Linux and Android -//! -//! On Linux targets the fallback is present only if either `target_env` is `musl`, -//! or `target_arch` is one of the following: `aarch64`, `arm`, `powerpc`, `powerpc64`, -//! `s390x`, `x86`, `x86_64`. Other supported targets [require][platform-support] -//! kernel versions which support `getrandom` system call, so fallback is not needed. -//! -//! On Android targets the fallback is present only for the following `target_arch`es: -//! `aarch64`, `arm`, `x86`, `x86_64`. Other `target_arch`es (e.g. RISC-V) require -//! sufficiently high API levels. -//! -//! The fallback can be disabled by enabling the `linux_getrandom` opt-in backend. -//! Note that doing so will bump minimum supported Linux kernel version to 3.17 and -//! Android API level to 23 (Marshmallow). -//! -//! ## 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. -//! -//! On OpenBSD, this kind of entropy accounting isn't available, and on -//! NetBSD, blocking on it is discouraged. On these platforms, nonblocking -//! interfaces are used, even when reliable entropy may not be available. -//! On the platforms where it is used, the reliability of entropy accounting -//! itself isn't free from controversy. This library provides randomness -//! sourced according to the platform's best practices, but each platform has -//! its own limits on the grade of randomness it can promise in environments -//! with few sources of entropy. -//! -//! ## Error handling -//! -//! We always choose failure over returning known 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. -//! -//! ## Panic handling -//! -//! We strive to eliminate all potential panics from our implementation. -//! In other words, when compiled with enabled optimizations, generated -//! binary code for `getrandom` functions should not contain any panic -//! branches. Even if platform misbiheaves and returns an unexpected -//! result, our code should correctly handle it and return an error like -//! [`Error::UNEXPECTED`]. -//! -//! ## Sanitizer support -//! -//! If your code uses [`fill_uninit`] and you use memory sanitizer -//! (i.e. `-Zsanitizer=memory`), then you need to pass `getrandom_sanitize` -//! configuration flag for `fill_uninit` to unpoison destination buffer. -//! -//! For example, it can be done like this (requires Nightly compiler): -//! ```text -//! RUSTFLAGS="-Zsanitizer=memory --cfg getrandom_sanitize" cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu -//! ``` -//! -//! [1]: https://manned.org/getrandom.2 -//! [2]: https://manned.org/urandom.4 -//! [3]: https://www.unix.com/man-page/mojave/2/getentropy/ -//! [4]: https://www.unix.com/man-page/mojave/4/urandom/ -//! [5]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable -//! [7]: https://man.openbsd.org/getentropy.2 -//! [8]: https://man.netbsd.org/sysctl.7 -//! [9]: https://leaf.dragonflybsd.org/cgi/web-man?command=getrandom -//! [11]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html -//! [12]: https://illumos.org/man/2/getrandom -//! [13]: https://github.com/emscripten-core/emscripten/pull/12240 -//! [14]: https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.utilities/topic/r/random.html -//! [15]: https://www.ibm.com/docs/en/aix/7.3?topic=files-random-urandom-devices -//! [16]: https://man.netbsd.org/getrandom.2 -//! [17]: https://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getrandom -//! [18]: https://github.com/rust3ds/shim-3ds/commit/b01d2568836dea2a65d05d662f8e5f805c64389d -//! -//! [`ProcessPrng`]: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng -//! [`RtlGenRandom`]: https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom -//! [`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 -//! [`RNDR`]: https://developer.arm.com/documentation/ddi0601/2024-06/AArch64-Registers/RNDR--Random-Number -//! [`CCRandomGenerateBytes`]: https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html -//! [`cprng_draw`]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw -//! [`crypto.randomFillSync`]: https://nodejs.org/api/crypto.html#cryptorandomfillsyncbuffer-offset-size -//! [`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/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-buf_len-size---errno -//! [`get-random-u64`]: https://github.com/WebAssembly/WASI/blob/v0.2.1/wasip2/random/random.wit#L23-L28 -//! [WebAssembly support]: #webassembly-support -//! [configuration flags]: #configuration-flags -//! [custom backend]: #custom-backend -//! [`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen -//! [`module`]: https://rustwasm.github.io/wasm-bindgen/reference/attributes/on-js-imports/module.html -//! [CommonJS modules]: https://nodejs.org/api/modules.html -//! [ES modules]: https://nodejs.org/api/esm.html -//! [`sys_read_entropy`]: https://github.com/hermit-os/kernel/blob/315f58ff5efc81d9bf0618af85a59963ff55f8b1/src/syscalls/entropy.rs#L47-L55 -//! [platform-support]: https://doc.rust-lang.org/stable/rustc/platform-support.html -//! [WASI]: https://github.com/CraneStation/wasi -//! [Emscripten]: https://www.hellorust.com/setup/emscripten/ -//! [`rustix`]: https://docs.rs/rustix +// 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", html_root_url = "https://docs.rs/getrandom/0.2.15" )] -#![no_std] +#![doc = include_str!("../README.md")] #![warn(rust_2018_idioms, unused_lifetimes, missing_docs)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(getrandom_sanitize, feature(cfg_sanitize))] From 01ccda57beb145a20b508cb51419a2d6ae551cb9 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 21 Oct 2024 16:40:36 +0300 Subject: [PATCH 061/201] Minor README tweaks (#534) --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1e04afb1c..5c403f78b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ -# getrandom: (operating) system's random number generator +# getrandom: system's random number generator -[![Build Status]][GitHub Actions] [![Crate]][crates.io] [![Documentation]][docs.rs] [![Dependency Status]][deps.rs] [![Downloads]][crates.io] [![License]][LICENSE-MIT] +[![Build Status]][GitHub Actions] +[![Crate]][crates.io] +[![Documentation]][docs.rs] +[![Dependency Status]][deps.rs] +[![Downloads]][crates.io] +[![License]][LICENSE-MIT] `getrandom` is a Rust library for retrieving random data from (operating) system sources. @@ -252,7 +257,8 @@ configuration flag for `fill_uninit` to unpoison destination buffer. For example, it can be done like this (requires Nightly compiler): ```sh -RUSTFLAGS="-Zsanitizer=memory --cfg getrandom_sanitize" cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu +RUSTFLAGS="-Zsanitizer=memory --cfg getrandom_sanitize" \ + cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu ``` ## Minimum Supported Rust Version From 83e53377b381c832cd0531db8e431bffdafc0b45 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 23 Oct 2024 17:32:13 +0300 Subject: [PATCH 062/201] readme: minor text improvements (#535) --- README.md | 92 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 5c403f78b..2c7699223 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,12 @@ `getrandom` is a Rust library for retrieving random data from (operating) system sources. -It is assumed that the system always provides high-quality cryptographically secure random -data, ideally backed by hardware entropy sources. This crate derives its name -from Linux's `getrandom` function, but is cross-platform, roughly supporting -the same set of platforms as Rust's `std` lib. +It is assumed that the system always provides high-quality, cryptographically secure random +data, ideally backed by hardware entropy sources. This crate derives its name from +the Linux `getrandom` syscall but is cross-platform, roughly supporting the same set +of platforms as Rust's `std` library. -This is a low-level API. Most users should prefer using high-level random-number +This is a low-level API. Most users should prefer using a higher-level random-number library like [`rand`]. [`rand`]: https://crates.io/crates/rand @@ -73,8 +73,8 @@ Pull Requests that add support for new targets to `getrandom` are always welcome ### Opt-in backends -`getrandom` also provides optional backends which can be enabled using `getrandom_backend` -configuration flag: +`getrandom` also provides optional (opt-in) backends, which allow users to customize the source +of randomness based on their specific needs: | Backend name | Target | Target Triple | Implementation | ----------------- | -------------------- | -------------------- | -------------- @@ -82,22 +82,24 @@ configuration flag: | `linux_rustix` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses [`rustix`] instead of `libc`. | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register -| `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low quality entropy without proper hardware configuration! +| `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low-quality entropy without proper hardware configuration! | `wasm_js` | Web Browser, Node.js | `wasm*‑*‑unknown` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js (see [WebAssembly support]) | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) -The configuration flag can be enabled either by specifying the `rustflags` field in +Opt-in backends can be enabled using the `getrandom_backend` configuration flag. +The flag can be set either by specifying the `rustflags` field in [`.cargo/config.toml`] (note that it can be done on a per-target basis), or by using -`RUSTFLAGS` environment variable: +the `RUSTFLAGS` environment variable: ```sh RUSTFLAGS='--cfg getrandom_backend="linux_getrandom"' cargo build ``` -Enabling an opt-in backend will replace backend used by default. Doing it for a wrong target -(e.g. using `linux_getrandom` while compiling for a Windows target) will result -in a compilation error. Be extremely carefull while using opt-in backends, since incorrect -configuration may result in vulnerable or in always panicking applications. +Enabling an opt-in backend will replace the backend used by default. Doing this for +an incorrect target (e.g. using `linux_getrandom` while compiling for a Windows target) +will result in a compilation error. Be extremely careful while using opt-in backends, +as incorrect configuration may result in vulnerable applications or applications +that always panic. Note that using an opt-in backend in a library (e.g. for tests or benchmarks) WILL NOT have any effect on its downstream users. @@ -138,7 +140,7 @@ This crate will then use the provided `webcrypto` implementation. ### Custom backend -If this crate does not support your target out of box or you have to use +If this crate does not support your target out of the box or you have to use a non-default entropy source, then you can provide a custom implementation. You need to enable the custom backend as described in the [configuration flags] section. Next, you need to define an `extern` function with the following @@ -156,20 +158,20 @@ unsafe extern "Rust" fn __getrandom_v03_custom( } ``` -This function ideally should be defined in the root crate of your project, +This function should, ideally, be defined in the root crate of your project, e.g. in your `main.rs`. This function MUST be defined only once for your project, i.e. upstream library crates SHOULD NOT define it outside of tests and benchmarks. Improper configuration of this backend may result in linking errors. -The function accepts pointer to buffer which should be filled with random -data and length in bytes. Note that the buffer MAY be uninitialized. -On success the function should return 0 and fully fill the input buffer, -every other return result will be interpreted as an error code. +The function accepts a pointer to a buffer that should be filled with random +data and its length in bytes. Note that the buffer MAY be uninitialized. +On success, the function should return `Ok(())` and fully fill the input buffer; +otherwise, it should return an error value. If you are confident that `getrandom` is not used in your project, but it gets pulled nevertheless by one of your dependencies, then you can -use the following custom backend which always returns "unsupported" error: +use the following custom backend, which always returns the "unsupported" error: ```rust use getrandom::Error; @@ -183,29 +185,30 @@ unsafe extern "Rust" fn __getrandom_v03_custom( ``` ### Platform Support + This crate generally supports the same operating system and platform versions that the Rust standard library does. Additional targets may be supported using -pluggable custom implementations. +the opt-in custom backend. This means that as Rust drops support for old versions of operating systems -(such as old Linux kernel versions, Android API levels, etc) in stable releases, -`getrandom` may create new patch releases (`0.N.x`) that remove support for +(such as old Linux kernel versions, Android API levels, etc.) in stable releases, +`getrandom` may create new patch releases that remove support for outdated platform versions. ### `/dev/urandom` fallback on Linux and Android -On Linux targets the fallback is present only if either `target_env` is `musl`, -or `target_arch` is one of the following: `aarch64`, `arm`, `powerpc`, `powerpc64`, -`s390x`, `x86`, `x86_64`. Other supported targets [require][platform-support] -kernel versions which support `getrandom` system call, so fallback is not needed. +On Linux targets, the `/dev/urandom` fallback is present only if either `target_env` +is `musl`, or `target_arch` is one of the following: `aarch64`, `arm`, `powerpc`, +`powerpc64`, `s390x`, `x86`, `x86_64`. Other supported targets [require][platform-support] +kernel versions that support the `getrandom` system call, so the fallback is not needed. On Android targets the fallback is present only for the following `target_arch`es: `aarch64`, `arm`, `x86`, `x86_64`. Other `target_arch`es (e.g. RISC-V) require sufficiently high API levels. The fallback can be disabled by enabling the `linux_getrandom` opt-in backend. -Note that doing so will bump minimum supported Linux kernel version to 3.17 and -Android API level to 23 (Marshmallow). +Note that doing so will bump minimum supported Linux kernel version to 3.17 +and Android API level to 23 (Marshmallow). ### Early boot @@ -234,28 +237,29 @@ with few sources of entropy. ## Error handling -We always choose failure over returning known 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. +We always prioritize failure over returning known insecure "random" bytes. +Generally, on supported platforms, failure is highly unlikely, though not +impossible. If an error does occur, it is likely that it will occur +on every call to `getrandom`. Therefore, after the first successful call, +one can be reasonably confident that no errors will occur. ## Panic handling -We strive to eliminate all potential panics from our implementation. -In other words, when compiled with enabled optimizations, generated -binary code for `getrandom` functions should not contain any panic -branches. Even if platform misbiheaves and returns an unexpected -result, our code should correctly handle it and return an error like +We strive to eliminate all potential panics from our backend implementations. +In other words, when compiled with optimizations enabled, the generated +binary code for `getrandom` functions should not contain any panic branches. +Even if the platform misbehaves and returns an unexpected result, +our code should correctly handle it and return an error, e.g. [`Error::UNEXPECTED`]. ## Sanitizer support -If your code uses [`fill_uninit`] and you use memory sanitizer -(i.e. `-Zsanitizer=memory`), then you need to pass `getrandom_sanitize` -configuration flag for `fill_uninit` to unpoison destination buffer. +If your code uses [`fill_uninit`] and you enable memory sanitization +(i.e. `-Zsanitizer=memory`), you need to pass the `getrandom_sanitize` +configuration flag to enable unpoisoning of the destination buffer +filled by `fill_uninit`. -For example, it can be done like this (requires Nightly compiler): +For example, this can be done as follows (requires a Nightly compiler): ```sh RUSTFLAGS="-Zsanitizer=memory --cfg getrandom_sanitize" \ cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu From 3fd08723defa279badc0ff3df7d7436125ff3d00 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 28 Oct 2024 17:37:29 +0300 Subject: [PATCH 063/201] Enable nopanic check for `linux_rustix` (#536) The `linux_rustix` opt-in backend should be panic-free since rustix v0.38.38. --- .github/workflows/nopanic.yaml | 13 ++++++------- Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index ffc749f7c..dc8b1d4be 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -49,13 +49,12 @@ jobs: - name: Check (linux_android.rs) run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) - # TODO: re-enable after https://github.com/bytecodealliance/rustix/pull/1184 is released - # - name: Build (linux_rustix.rs) - # env: - # RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" - # run: cargo build --release - # - name: Check (linux_rustix.rs) - # run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) + - name: Build (linux_rustix.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" + run: cargo build --release + - name: Check (linux_rustix.rs) + run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) - name: Build (rdrand.rs) env: diff --git a/Cargo.toml b/Cargo.toml index 01bd81f88..94fdda607 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ libc = { version = "0.2.154", default-features = false } # linux_rustix [target.'cfg(all(any(target_os = "linux", target_os = "android"), any(target_env = "", getrandom_backend = "linux_rustix")))'.dependencies] -rustix = { version = "0.38", default-features = false, features = ["rand"] } +rustix = { version = "0.38.38", default-features = false, features = ["rand"] } # apple-other [target.'cfg(any(target_os = "ios", target_os = "visionos", target_os = "watchos", target_os = "tvos"))'.dependencies] From 5bf25bcd39df95b8651448d56d44ec378c782003 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 28 Oct 2024 17:53:53 +0300 Subject: [PATCH 064/201] readme: minor tweaks (#537) --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2c7699223..984ffd7d3 100644 --- a/README.md +++ b/README.md @@ -21,20 +21,20 @@ library like [`rand`]. ## Usage -Add this to your `Cargo.toml`: +Add the `getrandom` dependency to your `Cargo.toml` file: ```toml [dependencies] -getrandom = "0.2" +getrandom = "0.3" ``` -Then invoke the `fill` function: +Then invoke the `fill` function on a byte buffer to fill it with random data: ```rust -fn get_random_buf() -> Result<[u8; 32], getrandom::Error> { - let mut buf = [0u8; 32]; +fn get_random_u128() -> Result { + let mut buf = [0u8; 16]; getrandom::fill(&mut buf)?; - Ok(buf) + Ok(u128::from_ne_bytes(buf)) } ``` @@ -259,7 +259,7 @@ If your code uses [`fill_uninit`] and you enable memory sanitization configuration flag to enable unpoisoning of the destination buffer filled by `fill_uninit`. -For example, this can be done as follows (requires a Nightly compiler): +For example, it can be done as follows (requires a Nightly compiler): ```sh RUSTFLAGS="-Zsanitizer=memory --cfg getrandom_sanitize" \ cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu From 0bfe592f0e80c3c6575e4aebed11c19ce9aeb715 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 28 Oct 2024 19:05:27 +0300 Subject: [PATCH 065/201] Move backend implementations to `src/backends/` (#538) This makes it easier to get list of existing backends. It also makes lib.rs and the backends `cfg_if` a bit less cluttered. --- src/backends.rs | 152 ++++++++++++++++++ .../apple_other.rs} | 0 src/{ => backends}/custom.rs | 0 src/{ => backends}/esp_idf.rs | 0 src/{ => backends}/fuchsia.rs | 0 src/{ => backends}/getentropy.rs | 7 +- src/{ => backends}/getrandom.rs | 7 +- src/{ => backends}/hermit.rs | 0 src/{ => backends}/linux_android.rs | 5 +- .../linux_android_with_fallback.rs | 4 +- src/{ => backends}/linux_rustix.rs | 0 src/{ => backends}/netbsd.rs | 7 +- src/{ => backends}/rdrand.rs | 7 +- src/{ => backends}/rndr.rs | 4 +- src/{ => backends}/solaris.rs | 12 +- src/{ => backends}/solid.rs | 0 src/{ => backends}/use_file.rs | 14 +- src/{ => backends}/vxworks.rs | 7 +- src/{ => backends}/wasi.rs | 0 src/{ => backends}/wasm_js.rs | 2 +- src/{ => backends}/windows.rs | 0 src/{ => backends}/windows7.rs | 0 src/{error_impls.rs => error_std_impls.rs} | 0 src/lib.rs | 150 +---------------- 24 files changed, 208 insertions(+), 170 deletions(-) create mode 100644 src/backends.rs rename src/{apple-other.rs => backends/apple_other.rs} (100%) rename src/{ => backends}/custom.rs (100%) rename src/{ => backends}/esp_idf.rs (100%) rename src/{ => backends}/fuchsia.rs (100%) rename src/{ => backends}/getentropy.rs (82%) rename src/{ => backends}/getrandom.rs (88%) rename src/{ => backends}/hermit.rs (100%) rename src/{ => backends}/linux_android.rs (87%) rename src/{ => backends}/linux_android_with_fallback.rs (98%) rename src/{ => backends}/linux_rustix.rs (100%) rename src/{ => backends}/netbsd.rs (95%) rename src/{ => backends}/rdrand.rs (96%) rename src/{ => backends}/rndr.rs (97%) rename src/{ => backends}/solaris.rs (83%) rename src/{ => backends}/solid.rs (100%) rename src/{ => backends}/use_file.rs (97%) rename src/{ => backends}/vxworks.rs (91%) rename src/{ => backends}/wasi.rs (100%) rename src/{ => backends}/wasm_js.rs (98%) rename src/{ => backends}/windows.rs (100%) rename src/{ => backends}/windows7.rs (100%) rename src/{error_impls.rs => error_std_impls.rs} (100%) diff --git a/src/backends.rs b/src/backends.rs new file mode 100644 index 000000000..7ed94cf3e --- /dev/null +++ b/src/backends.rs @@ -0,0 +1,152 @@ +//! System-specific implementations. +//! +//! This module should provide `fill_inner` with the signature +//! `fn fill_inner(dest: &mut [MaybeUninit]) -> 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 linux_android; + pub use linux_android::*; + } else if #[cfg(getrandom_backend = "linux_rustix")] { + mod linux_rustix; + pub use linux_rustix::*; + } 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 = "wasm_js")] { + mod wasm_js; + pub use wasm_js::*; + } else if #[cfg(getrandom_backend = "esp_idf")] { + 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( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "hurd", + target_os = "illumos", + // 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(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"))] { + mod linux_android; + pub use linux_android::*; + } 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"))] { + mod wasi; + pub use wasi::*; + } 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, target_vendor = "win7"))] { + 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( + any(target_arch = "wasm32", target_arch = "wasm64"), + target_os = "unknown", + ))] { + compile_error!("the wasm*-unknown-unknown targets are not supported by \ + default, you may need to enable the \"wasm_js\" \ + configuration flag. For more information see: \ + https://docs.rs/getrandom/#webassembly-support"); + } else { + compile_error!("target is not supported. You may need to define \ + a custom backend see: \ + https://docs.rs/getrandom/#custom-backends"); + } +} diff --git a/src/apple-other.rs b/src/backends/apple_other.rs similarity index 100% rename from src/apple-other.rs rename to src/backends/apple_other.rs diff --git a/src/custom.rs b/src/backends/custom.rs similarity index 100% rename from src/custom.rs rename to src/backends/custom.rs diff --git a/src/esp_idf.rs b/src/backends/esp_idf.rs similarity index 100% rename from src/esp_idf.rs rename to src/backends/esp_idf.rs diff --git a/src/fuchsia.rs b/src/backends/fuchsia.rs similarity index 100% rename from src/fuchsia.rs rename to src/backends/fuchsia.rs diff --git a/src/getentropy.rs b/src/backends/getentropy.rs similarity index 82% rename from src/getentropy.rs rename to src/backends/getentropy.rs index 78c797e1a..c93c6ccf6 100644 --- a/src/getentropy.rs +++ b/src/backends/getentropy.rs @@ -7,14 +7,17 @@ //! - vita newlib since Dec 2021 //! //! For these targets, we use getentropy(2) because getrandom(2) doesn't exist. -use crate::{util_libc::last_os_error, Error}; +use crate::Error; use core::{ffi::c_void, mem::MaybeUninit}; +#[path = "../util_libc.rs"] +mod util_libc; + pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { for chunk in dest.chunks_mut(256) { let ret = unsafe { libc::getentropy(chunk.as_mut_ptr().cast::(), chunk.len()) }; if ret != 0 { - return Err(last_os_error()); + return Err(util_libc::last_os_error()); } } Ok(()) diff --git a/src/getrandom.rs b/src/backends/getrandom.rs similarity index 88% rename from src/getrandom.rs rename to src/backends/getrandom.rs index e0f463de3..298059c28 100644 --- a/src/getrandom.rs +++ b/src/backends/getrandom.rs @@ -15,11 +15,14 @@ //! 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::{util_libc::sys_fill_exact, Error}; +use crate::Error; use core::{ffi::c_void, mem::MaybeUninit}; +#[path = "../util_libc.rs"] +mod util_libc; + pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - sys_fill_exact(dest, |buf| unsafe { + util_libc::sys_fill_exact(dest, |buf| unsafe { libc::getrandom(buf.as_mut_ptr().cast::(), buf.len(), 0) }) } diff --git a/src/hermit.rs b/src/backends/hermit.rs similarity index 100% rename from src/hermit.rs rename to src/backends/hermit.rs diff --git a/src/linux_android.rs b/src/backends/linux_android.rs similarity index 87% rename from src/linux_android.rs rename to src/backends/linux_android.rs index a4dd4e26a..cc59b0b16 100644 --- a/src/linux_android.rs +++ b/src/backends/linux_android.rs @@ -1,7 +1,10 @@ //! Implementation for Linux / Android without `/dev/urandom` fallback -use crate::{util_libc, Error}; +use crate::Error; use core::mem::MaybeUninit; +#[path = "../util_libc.rs"] +mod util_libc; + #[cfg(not(any(target_os = "android", target_os = "linux")))] compile_error!("`linux_getrandom` backend can be enabled only for Linux/Android targets!"); diff --git a/src/linux_android_with_fallback.rs b/src/backends/linux_android_with_fallback.rs similarity index 98% rename from src/linux_android_with_fallback.rs rename to src/backends/linux_android_with_fallback.rs index 53570d2f4..4e3ea98c4 100644 --- a/src/linux_android_with_fallback.rs +++ b/src/backends/linux_android_with_fallback.rs @@ -1,11 +1,13 @@ //! Implementation for Linux / Android with `/dev/urandom` fallback -use crate::{use_file, util_libc, Error}; +use super::use_file; +use crate::Error; use core::{ ffi::c_void, mem::{self, MaybeUninit}, ptr::{self, NonNull}, sync::atomic::{AtomicPtr, Ordering}, }; +use use_file::util_libc; type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) -> libc::ssize_t; diff --git a/src/linux_rustix.rs b/src/backends/linux_rustix.rs similarity index 100% rename from src/linux_rustix.rs rename to src/backends/linux_rustix.rs diff --git a/src/netbsd.rs b/src/backends/netbsd.rs similarity index 95% rename from src/netbsd.rs rename to src/backends/netbsd.rs index a96d353f0..ddb697361 100644 --- a/src/netbsd.rs +++ b/src/backends/netbsd.rs @@ -3,7 +3,7 @@ //! `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::{util_libc::sys_fill_exact, Error}; +use crate::Error; use core::{ cmp, ffi::c_void, @@ -12,6 +12,9 @@ use core::{ sync::atomic::{AtomicPtr, Ordering}, }; +#[path = "../util_libc.rs"] +mod util_libc; + unsafe extern "C" fn polyfill_using_kern_arand( buf: *mut c_void, buflen: libc::size_t, @@ -69,7 +72,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { fptr = init(); } let fptr = unsafe { mem::transmute::<*mut c_void, GetRandomFn>(fptr) }; - sys_fill_exact(dest, |buf| unsafe { + util_libc::sys_fill_exact(dest, |buf| unsafe { fptr(buf.as_mut_ptr().cast::(), buf.len(), 0) }) } diff --git a/src/rdrand.rs b/src/backends/rdrand.rs similarity index 96% rename from src/rdrand.rs rename to src/backends/rdrand.rs index 2f2aed145..0a278b9ac 100644 --- a/src/rdrand.rs +++ b/src/backends/rdrand.rs @@ -1,7 +1,10 @@ //! RDRAND backend for x86(-64) targets -use crate::{lazy::LazyBool, util::slice_as_uninit, Error}; +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!"); @@ -97,7 +100,7 @@ fn is_rdrand_good() -> bool { } pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - static RDRAND_GOOD: LazyBool = LazyBool::new(); + static RDRAND_GOOD: lazy::LazyBool = lazy::LazyBool::new(); if !RDRAND_GOOD.unsync_init(is_rdrand_good) { return Err(Error::NO_RDRAND); } diff --git a/src/rndr.rs b/src/backends/rndr.rs similarity index 97% rename from src/rndr.rs rename to src/backends/rndr.rs index 573fa9a41..b6805b20e 100644 --- a/src/rndr.rs +++ b/src/backends/rndr.rs @@ -84,12 +84,12 @@ fn is_rndr_available() -> bool { (id_aa64isar0 >> 60) & 0xf >= 1 } - #[path = "../src/lazy.rs"] mod lazy; + #[path = "../lazy.rs"] mod lazy; static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new(); RNDR_GOOD.unsync_init(mrs_check) } else if #[cfg(feature = "std")] { extern crate std; - #[path = "../src/lazy.rs"] mod lazy; + #[path = "../lazy.rs"] mod lazy; static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new(); RNDR_GOOD.unsync_init(|| std::arch::is_aarch64_feature_detected!("rand")) } else { diff --git a/src/solaris.rs b/src/backends/solaris.rs similarity index 83% rename from src/solaris.rs rename to src/backends/solaris.rs index f2470e8a8..a9a26804b 100644 --- a/src/solaris.rs +++ b/src/backends/solaris.rs @@ -12,9 +12,12 @@ //! 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::{util_libc::last_os_error, Error}; +use crate::Error; use core::{ffi::c_void, mem::MaybeUninit}; +#[path = "../util_libc.rs"] +mod util_libc; + const MAX_BYTES: usize = 1024; pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { @@ -24,8 +27,11 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // 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) { - Ok(ret) if ret == chunk.len() => {} // Good. Keep going. - Ok(0) => return Err(last_os_error()), // The syscall failed. + // 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), } } diff --git a/src/solid.rs b/src/backends/solid.rs similarity index 100% rename from src/solid.rs rename to src/backends/solid.rs diff --git a/src/use_file.rs b/src/backends/use_file.rs similarity index 97% rename from src/use_file.rs rename to src/backends/use_file.rs index 453775729..86dfb48c3 100644 --- a/src/use_file.rs +++ b/src/backends/use_file.rs @@ -1,14 +1,14 @@ //! Implementations that just need to read from a file -use crate::{ - util_libc::{last_os_error, sys_fill_exact}, - Error, -}; +use crate::Error; use core::{ ffi::c_void, mem::MaybeUninit, sync::atomic::{AtomicI32, Ordering}, }; +#[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". @@ -42,7 +42,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { if fd == FD_UNINIT || fd == FD_ONGOING_INIT { fd = open_or_wait()?; } - sys_fill_exact(dest, |buf| unsafe { + util_libc::sys_fill_exact(dest, |buf| unsafe { libc::read(fd, buf.as_mut_ptr().cast::(), buf.len()) }) } @@ -65,7 +65,7 @@ fn open_readonly(path: &[u8]) -> Result { if fd >= 0 { return Ok(fd); } - let err = last_os_error(); + 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); @@ -142,7 +142,7 @@ mod sync { #[cfg(any(target_os = "android", target_os = "linux"))] mod sync { - use super::{last_os_error, open_readonly, Error, FD, FD_ONGOING_INIT}; + 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. /// diff --git a/src/vxworks.rs b/src/backends/vxworks.rs similarity index 91% rename from src/vxworks.rs rename to src/backends/vxworks.rs index 6d8a4bf95..d595d17b9 100644 --- a/src/vxworks.rs +++ b/src/backends/vxworks.rs @@ -1,11 +1,14 @@ //! Implementation for VxWorks -use crate::{util_libc::last_os_error, Error}; +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 fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { static RNG_INIT: AtomicBool = AtomicBool::new(false); while !RNG_INIT.load(Relaxed) { @@ -32,7 +35,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let p: *mut libc::c_uchar = chunk.as_mut_ptr().cast(); let ret = unsafe { libc::randABytes(p, chunk_len) }; if ret != 0 { - return Err(last_os_error()); + return Err(util_libc::last_os_error()); } } Ok(()) diff --git a/src/wasi.rs b/src/backends/wasi.rs similarity index 100% rename from src/wasi.rs rename to src/backends/wasi.rs diff --git a/src/wasm_js.rs b/src/backends/wasm_js.rs similarity index 98% rename from src/wasm_js.rs rename to src/backends/wasm_js.rs index da70d5ad7..5cdca578d 100644 --- a/src/wasm_js.rs +++ b/src/backends/wasm_js.rs @@ -30,7 +30,7 @@ thread_local!( static RNG_SOURCE: Result = getrandom_init(); ); -pub(crate) fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { RNG_SOURCE.with(|result| { let source = result.as_ref().map_err(|&e| e)?; diff --git a/src/windows.rs b/src/backends/windows.rs similarity index 100% rename from src/windows.rs rename to src/backends/windows.rs diff --git a/src/windows7.rs b/src/backends/windows7.rs similarity index 100% rename from src/windows7.rs rename to src/backends/windows7.rs diff --git a/src/error_impls.rs b/src/error_std_impls.rs similarity index 100% rename from src/error_impls.rs rename to src/error_std_impls.rs diff --git a/src/lib.rs b/src/lib.rs index bc7b35701..b0034588d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,154 +33,14 @@ extern crate cfg_if; use core::mem::MaybeUninit; +mod backends; mod error; mod util; #[cfg(feature = "std")] -mod error_impls; +mod error_std_impls; pub use crate::error::Error; -use crate::util::{slice_as_uninit_mut, slice_assume_init_mut}; - -// System-specific implementations. -// -// These should all provide fill_inner with the signature -// `fn fill_inner(dest: &mut [MaybeUninit]) -> 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")] { - #[path = "custom.rs"] mod imp; - } else if #[cfg(getrandom_backend = "linux_getrandom")] { - mod util_libc; - #[path = "linux_android.rs"] mod imp; - } else if #[cfg(getrandom_backend = "linux_rustix")] { - #[path = "linux_rustix.rs"] mod imp; - } else if #[cfg(getrandom_backend = "rdrand")] { - mod lazy; - #[path = "rdrand.rs"] mod imp; - } else if #[cfg(getrandom_backend = "rndr")] { - #[path = "rndr.rs"] mod imp; - } else if #[cfg(getrandom_backend = "wasm_js")] { - #[path = "wasm_js.rs"] mod imp; - } else if #[cfg(getrandom_backend = "esp_idf")] { - #[path = "esp_idf.rs"] mod imp; - } else if #[cfg(any( - target_os = "haiku", - target_os = "redox", - target_os = "nto", - target_os = "aix", - ))] { - mod util_libc; - #[path = "use_file.rs"] mod imp; - } else if #[cfg(any( - target_os = "macos", - target_os = "openbsd", - target_os = "vita", - target_os = "emscripten", - ))] { - mod util_libc; - #[path = "getentropy.rs"] mod imp; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "hurd", - target_os = "illumos", - // 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 util_libc; - #[path = "getrandom.rs"] mod imp; - } 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 util_libc; - mod use_file; - #[path = "linux_android_with_fallback.rs"] mod imp; - } else if #[cfg(any(target_os = "android", target_os = "linux"))] { - mod util_libc; - #[path = "linux_android.rs"] mod imp; - } else if #[cfg(target_os = "solaris")] { - mod util_libc; - #[path = "solaris.rs"] mod imp; - } else if #[cfg(target_os = "netbsd")] { - mod util_libc; - #[path = "netbsd.rs"] mod imp; - } else if #[cfg(target_os = "fuchsia")] { - #[path = "fuchsia.rs"] mod imp; - } else if #[cfg(any( - target_os = "ios", - target_os = "visionos", - target_os = "watchos", - target_os = "tvos", - ))] { - #[path = "apple-other.rs"] mod imp; - } else if #[cfg(all(target_arch = "wasm32", target_os = "wasi"))] { - #[path = "wasi.rs"] mod imp; - } else if #[cfg(target_os = "hermit")] { - #[path = "hermit.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(all(windows, target_vendor = "win7"))] { - #[path = "windows7.rs"] mod imp; - } else if #[cfg(windows)] { - #[path = "windows.rs"] mod imp; - } else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] { - mod lazy; - #[path = "rdrand.rs"] mod imp; - } else if #[cfg(all( - any(target_arch = "wasm32", target_arch = "wasm64"), - target_os = "unknown", - ))] { - compile_error!("the wasm*-unknown-unknown targets are not supported by \ - default, you may need to enable the \"wasm_js\" \ - configuration flag. For more information see: \ - https://docs.rs/getrandom/#webassembly-support"); - } else { - compile_error!("target is not supported. You may need to define \ - a custom backend see: \ - https://docs.rs/getrandom/#custom-backends"); - } -} /// Fill `dest` with random bytes from the system's preferred random number source. /// @@ -208,7 +68,7 @@ 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 { slice_as_uninit_mut(dest) })?; + fill_uninit(unsafe { util::slice_as_uninit_mut(dest) })?; Ok(()) } @@ -237,7 +97,7 @@ pub fn fill(dest: &mut [u8]) -> Result<(), Error> { #[inline] pub fn fill_uninit(dest: &mut [MaybeUninit]) -> Result<&mut [u8], Error> { if !dest.is_empty() { - imp::fill_inner(dest)?; + backends::fill_inner(dest)?; } #[cfg(getrandom_sanitize)] @@ -253,6 +113,6 @@ pub fn fill_uninit(dest: &mut [MaybeUninit]) -> Result<&mut [u8], Error> { #[cfg(sanitize = "memory")] __msan_unpoison(dest.as_mut_ptr().cast(), dest.len()); - slice_assume_init_mut(dest) + util::slice_assume_init_mut(dest) }) } From 4bbf71d4f363ec6b7193413dcacdf21fc37c3a2e Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 28 Oct 2024 19:17:47 +0300 Subject: [PATCH 066/201] ci: move build jobs into a separate workflow (#539) This results in nicer CI job names, e.g. `Test / Tier 1` and `Build / Tier 2`. --- .github/workflows/build.yml | 196 +++++++++++++++++++++++++++++++ .github/workflows/tests.yml | 223 ++++-------------------------------- 2 files changed, 218 insertions(+), 201 deletions(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..9bdb1b5ef --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,196 @@ +name: Build + +on: + push: + branches: master + pull_request: + branches: master + schedule: + - cron: "0 12 * * 1" + +permissions: + contents: read + +env: + CARGO_INCREMENTAL: 0 + RUSTFLAGS: "-Dwarnings" + +jobs: + macos: + name: Apple Other + # visionOS requires Xcode 15.2+, which is only available on the arm64 runners. + runs-on: macos-14 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + with: + targets: aarch64-apple-darwin, aarch64-apple-ios + components: rust-src + - uses: Swatinem/rust-cache@v2 + - run: cargo test --no-run --target=aarch64-apple-darwin --features=std + - run: cargo test --no-run --target=aarch64-apple-ios --features=std + - run: cargo test --no-run --target=aarch64-apple-tvos -Zbuild-std --features=std + - run: cargo test --no-run --target=aarch64-apple-watchos -Zbuild-std --features=std + # visionOS requires Xcode 15.2+, GitHub Actions defaults to an older version. + - run: sudo xcode-select -switch /Applications/Xcode_15.2.app + - run: cargo test --no-run --target=aarch64-apple-visionos -Zbuild-std --features=std + + cross: + name: Cross + runs-on: ubuntu-22.04 + strategy: + matrix: + target: [ + sparcv9-sun-solaris, + x86_64-unknown-illumos, + x86_64-unknown-freebsd, + x86_64-unknown-netbsd, + ] + steps: + - uses: actions/checkout@v4 + - name: Install precompiled cross + run: | + VERSION=v0.2.5 + URL=https://github.com/cross-rs/cross/releases/download/${VERSION}/cross-x86_64-unknown-linux-gnu.tar.gz + wget -O - $URL | tar -xz -C ~/.cargo/bin + cross --version + - name: Build Tests + run: cross test --no-run --target=${{ matrix.target }} --features=std + + wasm64: + name: Wasm64 + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly # Need to build libstd + with: + components: rust-src + - uses: Swatinem/rust-cache@v2 + - name: Build and Link tests (build-std) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" + # This target is Tier 3, so we have to build libstd ourselves. + # We currently cannot run these tests because wasm-bindgen-test-runner + # does not yet support memory64. + run: cargo test --no-run -Z build-std=std,panic_abort --target=wasm64-unknown-unknown + + tier2: + name: Tier 2 + runs-on: ubuntu-22.04 + strategy: + matrix: + target: [ + x86_64-unknown-fuchsia, + x86_64-unknown-redox, + x86_64-fortanix-unknown-sgx, + ] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + - uses: Swatinem/rust-cache@v2 + - name: Build + run: cargo build --target=${{ matrix.target }} --features=std + + tier3: + name: Tier 3 + runs-on: ubuntu-22.04 + strategy: + matrix: + # Supported tier 3 targets without libstd support + target: [ + x86_64-unknown-hermit, + x86_64-wrs-vxworks, + aarch64-kmc-solid_asp3, + armv6k-nintendo-3ds, + armv7-sony-vita-newlibeabihf, + aarch64-unknown-nto-qnx710, + ] + # Supported tier 3 targets with libstd support + include: + - target: aarch64-unknown-nto-qnx710 + features: ["std"] + - target: x86_64-unknown-openbsd + features: ["std"] + - target: x86_64-unknown-dragonfly + features: ["std"] + - target: x86_64-unknown-haiku + features: ["std"] + - target: i686-unknown-hurd-gnu + features: ["std"] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly # Required to build libcore + with: + components: rust-src + - uses: Swatinem/rust-cache@v2 + - run: cargo build -Z build-std=${{ contains(matrix.features, 'std') && 'std' || 'core'}} --target=${{ matrix.target }} --features="${{ join(matrix.features, ',') }}" + + rdrand: + name: RDRAND + runs-on: ubuntu-22.04 + strategy: + matrix: + target: [ + x86_64-unknown-uefi, + x86_64-unknown-l4re-uclibc, + ] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly # Required to build libcore + with: + components: rust-src + - uses: Swatinem/rust-cache@v2 + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" + run: cargo build -Z build-std=core --target=${{ matrix.target }} + + rndr: + name: RNDR + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: aarch64-unknown-linux-gnu, aarch64-apple-darwin + - uses: Swatinem/rust-cache@v2 + - name: RNDR enabled at compile time (Linux) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" -C target-feature=+rand + run: cargo build --target=aarch64-unknown-linux-gnu + - name: Runtime RNDR detection without std (Linux) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" + run: cargo build --target=aarch64-unknown-linux-gnu + - name: Runtime RNDR detection with std (macOS) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" + run: cargo build --target=aarch64-unknown-linux-gnu --features std + + esp-idf: + name: ESP-IDF + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly # Required to build libcore + with: + components: rust-src + - uses: Swatinem/rust-cache@v2 + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="esp_idf" + run: cargo build -Z build-std=core --target=riscv32imc-esp-espidf + + no-atomics: + name: No Atomics + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + targets: riscv32i-unknown-none-elf + - uses: Swatinem/rust-cache@v2 + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom" + run: cargo build --target riscv32i-unknown-none-elf diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bef1f09fc..7f683c291 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,4 +1,4 @@ -name: Tests +name: Test on: push: @@ -16,8 +16,8 @@ env: RUSTFLAGS: "-Dwarnings" jobs: - main-tests: - name: Tier 1 Test + tier1: + name: Tier 1 runs-on: ${{ matrix.os }} strategy: matrix: @@ -43,8 +43,8 @@ jobs: - if: ${{ matrix.toolchain == 'nightly' }} run: cargo test --benches - linux-tests: - name: Linux Test + linux: + name: Linux runs-on: ubuntu-22.04 strategy: matrix: @@ -81,8 +81,8 @@ jobs: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" run: cargo test --features=std - ios-tests: - name: iOS Simulator Test + ios: + name: iOS Simulator runs-on: ${{ matrix.os }} strategy: matrix: @@ -127,8 +127,8 @@ jobs: - name: Run tests run: cargo dinghy -p ${{ matrix.ios_platform }} -d ${{ env.device }} test - windows-tests: - name: Windows Test + windows: + name: Windows runs-on: windows-2022 strategy: matrix: @@ -146,7 +146,7 @@ jobs: - run: cargo test --features=std windows7: - name: Test Windows 7 impl on Windows 10 + name: Windows 7 (on Windows 10) runs-on: windows-2022 steps: - uses: actions/checkout@v4 @@ -159,8 +159,8 @@ jobs: - run: cargo test --target=x86_64-win7-windows-msvc -Z build-std --features=std - run: cargo test --target=i686-win7-windows-msvc -Z build-std --features=std - sanitizer-test: - name: Sanitizer Test + sanitizer: + name: Sanitizer runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -173,8 +173,8 @@ jobs: # `--all-targets` is used to skip doc tests which currently fail linking run: cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu --all-targets - cross-tests: - name: Cross Test + cross: + name: Cross runs-on: ubuntu-22.04 strategy: matrix: @@ -197,27 +197,8 @@ jobs: - name: Test run: cross test --no-fail-fast --target=${{ matrix.target }} --features=std - macos-link: - name: macOS ARM64 Build/Link - # visionOS requires Xcode 15.2+, which is only available on the arm64 runners. - runs-on: macos-14 - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly - with: - targets: aarch64-apple-darwin, aarch64-apple-ios - components: rust-src - - uses: Swatinem/rust-cache@v2 - - run: cargo test --no-run --target=aarch64-apple-darwin --features=std - - run: cargo test --no-run --target=aarch64-apple-ios --features=std - - run: cargo test --no-run --target=aarch64-apple-tvos -Zbuild-std --features=std - - run: cargo test --no-run --target=aarch64-apple-watchos -Zbuild-std --features=std - # visionOS requires Xcode 15.2+, GitHub Actions defaults to an older version. - - run: sudo xcode-select -switch /Applications/Xcode_15.2.app - - run: cargo test --no-run --target=aarch64-apple-visionos -Zbuild-std --features=std - freebsd: - name: FreeBSD VM Test + name: FreeBSD VM runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -231,7 +212,7 @@ jobs: run: cargo test openbsd: - name: OpenBSD VM Test + name: OpenBSD VM runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -245,7 +226,7 @@ jobs: run: cargo test netbsd: - name: NetBSD VM Test + name: NetBSD VM runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -261,7 +242,7 @@ jobs: # This job currently fails: # https://github.com/rust-random/getrandom/actions/runs/11405005618/job/31735653874?pr=528 # dragonflybsd: - # name: DragonflyBSD VM Test + # name: DragonflyBSD VM # runs-on: ubuntu-22.04 # steps: # - uses: actions/checkout@v4 @@ -274,30 +255,8 @@ jobs: # pkg install -y rust # run: cargo test - cross-link: - name: Cross Build/Link - runs-on: ubuntu-22.04 - strategy: - matrix: - target: [ - sparcv9-sun-solaris, - x86_64-unknown-illumos, - x86_64-unknown-freebsd, - x86_64-unknown-netbsd, - ] - steps: - - uses: actions/checkout@v4 - - name: Install precompiled cross - run: | - VERSION=v0.2.5 - URL=https://github.com/cross-rs/cross/releases/download/${VERSION}/cross-x86_64-unknown-linux-gnu.tar.gz - wget -O - $URL | tar -xz -C ~/.cargo/bin - cross --version - - name: Build Tests - run: cross test --no-run --target=${{ matrix.target }} --features=std - - web-tests: - name: Web Test + web: + name: Web strategy: fail-fast: false matrix: @@ -347,25 +306,8 @@ jobs: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test run: wasm-pack test --headless --safari - wasm64-build: - name: Wasm64 Build - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly # Need to build libstd - with: - components: rust-src - - uses: Swatinem/rust-cache@v2 - - name: Build and Link tests (build-std) - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - # This target is Tier 3, so we have to build libstd ourselves. - # We currently cannot run these tests because wasm-bindgen-test-runner - # does not yet support memory64. - run: cargo test --no-run -Z build-std=std,panic_abort --target=wasm64-unknown-unknown - - wasi-tests: - name: WASI Tests + wasi: + name: WASI runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -384,124 +326,3 @@ jobs: run: cargo test --target wasm32-wasip1 - name: WASI 0.2 Test run: cargo test --target wasm32-wasip2 - - build-tier2: - name: Tier 2 Build - runs-on: ubuntu-22.04 - strategy: - matrix: - target: [ - x86_64-unknown-fuchsia, - x86_64-unknown-redox, - x86_64-fortanix-unknown-sgx, - ] - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - with: - targets: ${{ matrix.target }} - - uses: Swatinem/rust-cache@v2 - - name: Build - run: cargo build --target=${{ matrix.target }} --features=std - - build-tier3: - name: Tier 3 Build - runs-on: ubuntu-22.04 - strategy: - matrix: - # Supported tier 3 targets without libstd support - target: [ - x86_64-unknown-hermit, - x86_64-wrs-vxworks, - aarch64-kmc-solid_asp3, - armv6k-nintendo-3ds, - armv7-sony-vita-newlibeabihf, - aarch64-unknown-nto-qnx710, - ] - # Supported tier 3 targets with libstd support - include: - - target: aarch64-unknown-nto-qnx710 - features: ["std"] - - target: x86_64-unknown-openbsd - features: ["std"] - - target: x86_64-unknown-dragonfly - features: ["std"] - - target: x86_64-unknown-haiku - features: ["std"] - - target: i686-unknown-hurd-gnu - features: ["std"] - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly # Required to build libcore - with: - components: rust-src - - uses: Swatinem/rust-cache@v2 - - run: cargo build -Z build-std=${{ contains(matrix.features, 'std') && 'std' || 'core'}} --target=${{ matrix.target }} --features="${{ join(matrix.features, ',') }}" - - build-rdrand: - name: RDRAND Build - runs-on: ubuntu-22.04 - strategy: - matrix: - target: [ - x86_64-unknown-uefi, - x86_64-unknown-l4re-uclibc, - ] - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly # Required to build libcore - with: - components: rust-src - - uses: Swatinem/rust-cache@v2 - - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" - run: cargo build -Z build-std=core --target=${{ matrix.target }} - - build-rndr: - name: RNDR Build - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: stable - targets: aarch64-unknown-linux-gnu, aarch64-apple-darwin - - uses: Swatinem/rust-cache@v2 - - name: RNDR enabled at compile time (Linux) - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" -C target-feature=+rand - run: cargo build --target=aarch64-unknown-linux-gnu - - name: Runtime RNDR detection without std (Linux) - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" - run: cargo build --target=aarch64-unknown-linux-gnu - - name: Runtime RNDR detection with std (macOS) - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" - run: cargo build --target=aarch64-unknown-linux-gnu --features std - - build-esp-idf: - name: ESP-IDF Build - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly # Required to build libcore - with: - components: rust-src - - uses: Swatinem/rust-cache@v2 - - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="esp_idf" - run: cargo build -Z build-std=core --target=riscv32imc-esp-espidf - - build-no-atomics: - name: No Atomics Build - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - with: - targets: riscv32i-unknown-none-elf - - uses: Swatinem/rust-cache@v2 - - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom" - run: cargo build --target riscv32i-unknown-none-elf From 1fc27b1ce278f5b79c62fab20a6cf6a3d8996e69 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 28 Oct 2024 19:34:04 +0300 Subject: [PATCH 067/201] ci: remove macos-12 jobs (#540) `macOS 12` workers are in the process of deprecation and will be eventually removed, see https://github.com/actions/runner-images/issues/10721. --- .github/workflows/tests.yml | 53 +++++-------------------------------- 1 file changed, 7 insertions(+), 46 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7f683c291..4daf23f56 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -25,9 +25,6 @@ jobs: toolchain: [nightly, beta, stable, "1.60"] # Only Test macOS on stable to reduce macOS CI jobs include: - # x86_64-apple-darwin. - - os: macos-12 - toolchain: stable # aarch64-apple-darwin. - os: macos-14 toolchain: stable @@ -83,27 +80,13 @@ jobs: ios: name: iOS Simulator - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-12, macos-14] - # Only test on stable to reduce macOS CI jobs - toolchain: [stable] - include: - # The Aarch64 device simulator doesn't seem to work on an x86-64 host - # and the x86_64 device simulator doesn't seem to work on an Aarch64 - # host, at least within GitHub Actions. - - os: macos-12 - target: x86_64-apple-ios - ios_platform: auto-ios-x86_64 - - os: macos-14 - target: aarch64-apple-ios-sim - ios_platform: auto-ios-aarch64-sim + runs-on: macos-14 steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@master with: - targets: ${{ matrix.target }} + toolchain: stable + targets: aarch64-apple-ios-sim - name: Install precompiled cargo-dinghy run: | VERSION=0.7.2 @@ -125,7 +108,7 @@ jobs: echo "device=$SIM_ID" >> $GITHUB_ENV - uses: Swatinem/rust-cache@v2 - name: Run tests - run: cargo dinghy -p ${{ matrix.ios_platform }} -d ${{ env.device }} test + run: cargo dinghy -p auto-ios-aarch64-sim -d ${{ env.device }} test windows: name: Windows @@ -257,19 +240,7 @@ jobs: web: name: Web - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-22.04 - host: x86_64-unknown-linux-musl - - os: macos-12 - host: x86_64-apple-darwin - # We get spurious failures on Windows, see: - # https://github.com/rust-random/getrandom/issues/400 - # - os: windows-2022 - # host: x86_64-pc-windows-msvc - runs-on: ${{ matrix.os }} + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable @@ -279,7 +250,7 @@ jobs: shell: bash run: | VERSION=v0.12.1 - URL=https://github.com/rustwasm/wasm-pack/releases/download/${VERSION}/wasm-pack-${VERSION}-${{ matrix.host }}.tar.gz + URL=https://github.com/rustwasm/wasm-pack/releases/download/${VERSION}/wasm-pack-${VERSION}-x86_64-unknown-linux-musl.tar.gz wget -O - $URL | tar -xz --strip-components=1 -C ~/.cargo/bin wasm-pack --version - uses: Swatinem/rust-cache@v2 @@ -295,16 +266,6 @@ jobs: env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test run: wasm-pack test --headless --chrome - - name: Test (Edge) - if: runner.os == 'Windows' - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test - run: wasm-pack test --headless --chrome --chromedriver $Env:EDGEWEBDRIVER\msedgedriver.exe - - name: Test (Safari) - if: runner.os == 'macOS' - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test - run: wasm-pack test --headless --safari wasi: name: WASI From 2ce1f0bddc2a1f69fe5270788f501bec3f227efb Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 21 Nov 2024 18:42:28 +0300 Subject: [PATCH 068/201] Bump MSRV to 1.63 (#542) This follows the MSRV bump in `libc`: https://github.com/rust-lang/libc/pull/4040 --- .github/workflows/tests.yml | 2 +- Cargo.toml | 2 +- README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4daf23f56..890e133c4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: os: [ubuntu-22.04, windows-2022] - toolchain: [nightly, beta, stable, "1.60"] + toolchain: [nightly, beta, stable, "1.63"] # Only Test macOS on stable to reduce macOS CI jobs include: # aarch64-apple-darwin. diff --git a/Cargo.toml b/Cargo.toml index 94fdda607..2886268ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "getrandom" version = "0.2.15" # Also update html_root_url in lib.rs when bumping this edition = "2021" -rust-version = "1.60" # Sync .clippy.toml, tests.yml, and README.md. +rust-version = "1.63" # Sync tests.yml and README.md. authors = ["The Rand Project Developers"] license = "MIT OR Apache-2.0" description = "A small cross-platform library for retrieving random data from system source" diff --git a/README.md b/README.md index 984ffd7d3..63d393962 100644 --- a/README.md +++ b/README.md @@ -267,7 +267,7 @@ RUSTFLAGS="-Zsanitizer=memory --cfg getrandom_sanitize" \ ## Minimum Supported Rust Version -This crate requires Rust 1.60.0 or later. +This crate requires Rust 1.63 or later. ## License From e144b1bc446d0ee28b809aed6a06ac8f1a39c088 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 25 Nov 2024 13:22:45 +0300 Subject: [PATCH 069/201] ci: do not test std feature in tier 3 builds (#543) Rust CI does not test `std` build for tier 3 targets, which means that breakage can go unnoticed for a long time (see rust-lang/rust#123032 and rust-lang/rust#133401). This results in unrelated CI breakages on our side. Additionally, removes OpenBSD from the tier3 build-only job since we test this target properly using VM. --- .github/workflows/build.yml | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9bdb1b5ef..87b5fe7f4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -98,34 +98,24 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - # Supported tier 3 targets without libstd support target: [ - x86_64-unknown-hermit, - x86_64-wrs-vxworks, aarch64-kmc-solid_asp3, + aarch64-unknown-nto-qnx710, armv6k-nintendo-3ds, armv7-sony-vita-newlibeabihf, - aarch64-unknown-nto-qnx710, + i686-unknown-hurd-gnu, + x86_64-unknown-hermit, + x86_64-wrs-vxworks, + x86_64-unknown-dragonfly, + x86_64-unknown-haiku, ] - # Supported tier 3 targets with libstd support - include: - - target: aarch64-unknown-nto-qnx710 - features: ["std"] - - target: x86_64-unknown-openbsd - features: ["std"] - - target: x86_64-unknown-dragonfly - features: ["std"] - - target: x86_64-unknown-haiku - features: ["std"] - - target: i686-unknown-hurd-gnu - features: ["std"] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly # Required to build libcore with: components: rust-src - uses: Swatinem/rust-cache@v2 - - run: cargo build -Z build-std=${{ contains(matrix.features, 'std') && 'std' || 'core'}} --target=${{ matrix.target }} --features="${{ join(matrix.features, ',') }}" + - run: cargo build -Z build-std=core --target=${{ matrix.target }} rdrand: name: RDRAND From e694075dfe3fabb45af40a711ac4b5719c43a293 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 26 Nov 2024 16:38:43 +0300 Subject: [PATCH 070/201] Add functions to generate random `u32` and `u64` values (#544) These functions can be helpful for seed generation and implementation of `OsRng`. Additionally, some backends (Hermit, RDRAND, RNDR, WASI p2) can directly generate random `u32`/`u64` values. Relying on the byte API may be less efficient in these cases. Using `u32` and `u64` as function names may seem problematic, but based on the `fasrand` experience, it works well in practice, provided that users reference them as `getrandom::u32/u64` without importing them directly. --- src/backends.rs | 16 ++++- src/backends/apple_other.rs | 2 + src/backends/custom.rs | 2 + src/backends/esp_idf.rs | 2 + src/backends/fuchsia.rs | 2 + src/backends/getentropy.rs | 2 + src/backends/getrandom.rs | 2 + src/backends/hermit.rs | 26 ++++++++ src/backends/linux_android.rs | 2 + src/backends/linux_android_with_fallback.rs | 2 + src/backends/linux_rustix.rs | 2 + src/backends/netbsd.rs | 2 + src/backends/rdrand.rs | 61 ++++++++++++++--- src/backends/rndr.rs | 25 ++++++- src/backends/solaris.rs | 2 + src/backends/solid.rs | 2 + src/backends/use_file.rs | 3 + src/backends/vxworks.rs | 2 + src/backends/wasi.rs | 73 --------------------- src/backends/wasi_p1.rs | 30 +++++++++ src/backends/wasi_p2.rs | 47 +++++++++++++ src/backends/wasm_js.rs | 2 + src/backends/windows.rs | 2 + src/backends/windows7.rs | 2 + src/lib.rs | 28 ++++++++ src/util.rs | 36 +++++++++- tests/mod.rs | 67 +++++++++++++++++-- 27 files changed, 353 insertions(+), 91 deletions(-) delete mode 100644 src/backends/wasi.rs create mode 100644 src/backends/wasi_p1.rs create mode 100644 src/backends/wasi_p2.rs diff --git a/src/backends.rs b/src/backends.rs index 7ed94cf3e..d5164173d 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -116,8 +116,20 @@ cfg_if! { mod apple_other; pub use apple_other::*; } else if #[cfg(all(target_arch = "wasm32", target_os = "wasi"))] { - mod wasi; - pub use 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::*; diff --git a/src/backends/apple_other.rs b/src/backends/apple_other.rs index 1990523fa..127a31e3c 100644 --- a/src/backends/apple_other.rs +++ b/src/backends/apple_other.rs @@ -2,6 +2,8 @@ use crate::Error; use core::{ffi::c_void, mem::MaybeUninit}; +pub use crate::util::{inner_u32, inner_u64}; + pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let dst_ptr = dest.as_mut_ptr().cast::(); let ret = unsafe { libc::CCRandomGenerateBytes(dst_ptr, dest.len()) }; diff --git a/src/backends/custom.rs b/src/backends/custom.rs index e97d32931..0c4829466 100644 --- a/src/backends/custom.rs +++ b/src/backends/custom.rs @@ -2,6 +2,8 @@ use crate::Error; use core::mem::MaybeUninit; +pub use crate::util::{inner_u32, inner_u64}; + pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { extern "Rust" { fn __getrandom_v03_custom(dest: *mut u8, len: usize) -> Result<(), Error>; diff --git a/src/backends/esp_idf.rs b/src/backends/esp_idf.rs index 2df7b9aae..0f0ff7f49 100644 --- a/src/backends/esp_idf.rs +++ b/src/backends/esp_idf.rs @@ -2,6 +2,8 @@ use crate::Error; use core::{ffi::c_void, mem::MaybeUninit}; +pub use crate::util::{inner_u32, inner_u64}; + #[cfg(not(target_os = "espidf"))] compile_error!("`esp_idf` backend can be enabled only for ESP-IDF targets!"); diff --git a/src/backends/fuchsia.rs b/src/backends/fuchsia.rs index b8e6de860..5edd210dc 100644 --- a/src/backends/fuchsia.rs +++ b/src/backends/fuchsia.rs @@ -2,6 +2,8 @@ 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); diff --git a/src/backends/getentropy.rs b/src/backends/getentropy.rs index c93c6ccf6..e0b2d34c1 100644 --- a/src/backends/getentropy.rs +++ b/src/backends/getentropy.rs @@ -10,6 +10,8 @@ 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; diff --git a/src/backends/getrandom.rs b/src/backends/getrandom.rs index 298059c28..a00829f7c 100644 --- a/src/backends/getrandom.rs +++ b/src/backends/getrandom.rs @@ -18,6 +18,8 @@ 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; diff --git a/src/backends/hermit.rs b/src/backends/hermit.rs index 594b330b2..11bfbf271 100644 --- a/src/backends/hermit.rs +++ b/src/backends/hermit.rs @@ -4,6 +4,32 @@ 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; +} + +pub fn inner_u32() -> Result { + 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), + } +} + +pub fn inner_u64() -> Result { + 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), + } } pub fn fill_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { diff --git a/src/backends/linux_android.rs b/src/backends/linux_android.rs index cc59b0b16..6c0b66ae8 100644 --- a/src/backends/linux_android.rs +++ b/src/backends/linux_android.rs @@ -2,6 +2,8 @@ use crate::Error; use core::mem::MaybeUninit; +pub use crate::util::{inner_u32, inner_u64}; + #[path = "../util_libc.rs"] mod util_libc; diff --git a/src/backends/linux_android_with_fallback.rs b/src/backends/linux_android_with_fallback.rs index 4e3ea98c4..cdfff9809 100644 --- a/src/backends/linux_android_with_fallback.rs +++ b/src/backends/linux_android_with_fallback.rs @@ -9,6 +9,8 @@ use core::{ }; 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, diff --git a/src/backends/linux_rustix.rs b/src/backends/linux_rustix.rs index 4fef33818..d3bcce3e5 100644 --- a/src/backends/linux_rustix.rs +++ b/src/backends/linux_rustix.rs @@ -2,6 +2,8 @@ use crate::{Error, MaybeUninit}; use rustix::rand::{getrandom_uninit, GetRandomFlags}; +pub use crate::util::{inner_u32, inner_u64}; + #[cfg(not(any(target_os = "android", target_os = "linux")))] compile_error!("`linux_rustix` backend can be enabled only for Linux/Android targets!"); diff --git a/src/backends/netbsd.rs b/src/backends/netbsd.rs index ddb697361..0e3268ef4 100644 --- a/src/backends/netbsd.rs +++ b/src/backends/netbsd.rs @@ -12,6 +12,8 @@ use core::{ sync::atomic::{AtomicPtr, Ordering}, }; +pub use crate::util::{inner_u32, inner_u64}; + #[path = "../util_libc.rs"] mod util_libc; diff --git a/src/backends/rdrand.rs b/src/backends/rdrand.rs index 0a278b9ac..19fa97baf 100644 --- a/src/backends/rdrand.rs +++ b/src/backends/rdrand.rs @@ -20,6 +20,8 @@ cfg_if! { } } +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 Developer’s Manual" - Volume 1 - Section 7.3.17.1. @@ -99,15 +101,6 @@ fn is_rdrand_good() -> bool { unsafe { self_test() } } -pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - static RDRAND_GOOD: lazy::LazyBool = lazy::LazyBool::new(); - 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) -} - // TODO: make this function safe when we have feature(target_feature_11) #[target_feature(enable = "rdrand")] unsafe fn rdrand_exact(dest: &mut [MaybeUninit]) -> Option<()> { @@ -127,3 +120,53 @@ unsafe fn rdrand_exact(dest: &mut [MaybeUninit]) -> Option<()> { } Some(()) } + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "rdrand")] +unsafe fn rdrand_u32() -> Option { + rdrand().map(crate::util::truncate) +} + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "rdrand")] +unsafe fn rdrand_u64() -> Option { + rdrand() +} + +#[cfg(target_arch = "x86")] +#[target_feature(enable = "rdrand")] +unsafe fn rdrand_u32() -> Option { + rdrand() +} + +#[cfg(target_arch = "x86")] +#[target_feature(enable = "rdrand")] +unsafe fn rdrand_u64() -> Option { + let a = rdrand()?; + let b = rdrand()?; + Some((u64::from(a) << 32) || u64::from(b)) +} + +pub fn inner_u32() -> Result { + 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) +} + +pub fn inner_u64() -> Result { + 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) +} + +pub fn fill_inner(dest: &mut [MaybeUninit]) -> 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) +} diff --git a/src/backends/rndr.rs b/src/backends/rndr.rs index b6805b20e..bd2878f00 100644 --- a/src/backends/rndr.rs +++ b/src/backends/rndr.rs @@ -2,7 +2,10 @@ //! //! 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, Error}; +use crate::{ + util::{slice_as_uninit, truncate}, + Error, +}; use core::arch::asm; use core::mem::{size_of, MaybeUninit}; @@ -101,6 +104,26 @@ fn is_rndr_available() -> bool { } } +pub fn inner_u32() -> Result { + if is_rndr_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) + } else { + Err(Error::RNDR_NOT_AVAILABLE) + } +} + +pub fn inner_u64() -> Result { + if is_rndr_available() { + // SAFETY: after this point, we know the `rand` target feature is enabled + let res = unsafe { rndr() }; + res.ok_or(Error::RNDR_FAILURE) + } else { + Err(Error::RNDR_NOT_AVAILABLE) + } +} + pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { if is_rndr_available() { // SAFETY: after this point, we know the `rand` target feature is enabled diff --git a/src/backends/solaris.rs b/src/backends/solaris.rs index a9a26804b..ea5344fcf 100644 --- a/src/backends/solaris.rs +++ b/src/backends/solaris.rs @@ -15,6 +15,8 @@ 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; diff --git a/src/backends/solid.rs b/src/backends/solid.rs index 50bbe47ee..6699e6869 100644 --- a/src/backends/solid.rs +++ b/src/backends/solid.rs @@ -2,6 +2,8 @@ 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; } diff --git a/src/backends/use_file.rs b/src/backends/use_file.rs index 86dfb48c3..ef12fca1b 100644 --- a/src/backends/use_file.rs +++ b/src/backends/use_file.rs @@ -6,6 +6,9 @@ use core::{ 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; diff --git a/src/backends/vxworks.rs b/src/backends/vxworks.rs index d595d17b9..51b7580ea 100644 --- a/src/backends/vxworks.rs +++ b/src/backends/vxworks.rs @@ -9,6 +9,8 @@ use core::{ #[path = "../util_libc.rs"] mod util_libc; +pub use crate::util::{inner_u32, inner_u64}; + pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { static RNG_INIT: AtomicBool = AtomicBool::new(false); while !RNG_INIT.load(Relaxed) { diff --git a/src/backends/wasi.rs b/src/backends/wasi.rs deleted file mode 100644 index a1ecf0047..000000000 --- a/src/backends/wasi.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Implementation for WASI (preview 1 and 2) -//! -//! `target_env = "p1"` was introduced only in Rust 1.80, so on earlier compiler versions this -//! code will result in a compilation error. -use crate::Error; -use core::mem::MaybeUninit; - -#[cfg(not(any(target_env = "p1", target_env = "p2")))] -compile_error!( - "Unknown version of WASI (only previews 1 and 2 are supported) \ - or Rust version older than 1.80 was used" -); - -#[cfg(target_env = "p1")] -pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - // 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; - } - - // 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(()), - code => { - let err = u32::try_from(code) - .map(Error::from_os_error) - .unwrap_or(Error::UNEXPECTED); - Err(err) - } - } -} - -#[cfg(target_env = "p2")] -pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - use core::ptr::copy_nonoverlapping; - use wasi::random::random::get_random_u64; - - let (prefix, chunks, suffix) = unsafe { dest.align_to_mut::>() }; - - // 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(()) -} diff --git a/src/backends/wasi_p1.rs b/src/backends/wasi_p1.rs new file mode 100644 index 000000000..6eefdee61 --- /dev/null +++ b/src/backends/wasi_p1.rs @@ -0,0 +1,30 @@ +//! 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; +} + +pub fn fill_inner(dest: &mut [MaybeUninit]) -> 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(()), + code => { + let err = u32::try_from(code) + .map(Error::from_os_error) + .unwrap_or(Error::UNEXPECTED); + Err(err) + } + } +} diff --git a/src/backends/wasi_p2.rs b/src/backends/wasi_p2.rs new file mode 100644 index 000000000..9d5d601d7 --- /dev/null +++ b/src/backends/wasi_p2.rs @@ -0,0 +1,47 @@ +//! Implementation for WASI Preview 2. +use crate::Error; +use core::mem::MaybeUninit; +use wasi::random::random::get_random_u64; + +pub fn inner_u32() -> Result { + let val = get_random_u64(); + Ok(crate::util::truncate(val)) +} + +pub fn inner_u64() -> Result { + Ok(get_random_u64()) +} + +pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { + use core::ptr::copy_nonoverlapping; + use wasi::random::random::get_random_u64; + + let (prefix, chunks, suffix) = unsafe { dest.align_to_mut::>() }; + + // 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(()) +} diff --git a/src/backends/wasm_js.rs b/src/backends/wasm_js.rs index 5cdca578d..de2b4333e 100644 --- a/src/backends/wasm_js.rs +++ b/src/backends/wasm_js.rs @@ -4,6 +4,8 @@ use crate::Error; extern crate std; use std::{mem::MaybeUninit, thread_local}; +pub use crate::util::{inner_u32, inner_u64}; + #[cfg(not(all( any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown", diff --git a/src/backends/windows.rs b/src/backends/windows.rs index 642206e71..6c8e46b1a 100644 --- a/src/backends/windows.rs +++ b/src/backends/windows.rs @@ -23,6 +23,8 @@ 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 the windows-targets // crate to link to it. diff --git a/src/backends/windows7.rs b/src/backends/windows7.rs index 573ac8810..2546719eb 100644 --- a/src/backends/windows7.rs +++ b/src/backends/windows7.rs @@ -12,6 +12,8 @@ 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")] diff --git a/src/lib.rs b/src/lib.rs index b0034588d..930b94529 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,3 +116,31 @@ pub fn fill_uninit(dest: &mut [MaybeUninit]) -> Result<&mut [u8], Error> { 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 { + 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 { + backends::inner_u64() +} diff --git a/src/util.rs b/src/util.rs index 9eeba9a7f..4a55b0a50 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,6 @@ #![allow(dead_code)] -use core::{mem::MaybeUninit, ptr}; +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 @@ -46,3 +47,36 @@ fn ptr_from_mut(r: &mut T) -> *mut T { fn ptr_from_ref(r: &T) -> *const T { r } + +/// Default implementation of `inner_u32` on top of `fill_uninit` +pub fn inner_u32() -> Result { + let mut res = MaybeUninit::::uninit(); + // SAFETY: the created slice has the same size as `res` + let dst = unsafe { + let p: *mut MaybeUninit = res.as_mut_ptr().cast(); + slice::from_raw_parts_mut(p, core::mem::size_of::()) + }; + 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` +pub fn inner_u64() -> Result { + let mut res = MaybeUninit::::uninit(); + // SAFETY: the created slice has the same size as `res` + let dst = unsafe { + let p: *mut MaybeUninit = res.as_mut_ptr().cast(); + slice::from_raw_parts_mut(p, core::mem::size_of::()) + }; + 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") +} diff --git a/tests/mod.rs b/tests/mod.rs index 58e229514..204ec6539 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -14,13 +14,32 @@ fn test_zero() { assert!(res.is_empty()); } +trait DiffBits: Sized { + fn diff_bits(ab: (&Self, &Self)) -> usize; +} + +impl DiffBits for u8 { + fn diff_bits((a, b): (&Self, &Self)) -> usize { + (a ^ b).count_ones() as usize + } +} + +impl DiffBits for u32 { + fn diff_bits((a, b): (&Self, &Self)) -> usize { + (a ^ b).count_ones() as usize + } +} + +impl DiffBits for u64 { + fn diff_bits((a, b): (&Self, &Self)) -> usize { + (a ^ b).count_ones() as usize + } +} + // Return the number of bits in which s1 and s2 differ -fn num_diff_bits(s1: &[u8], s2: &[u8]) -> usize { +fn num_diff_bits(s1: &[T], s2: &[T]) -> usize { assert_eq!(s1.len(), s2.len()); - s1.iter() - .zip(s2.iter()) - .map(|(a, b)| (a ^ b).count_ones() as usize) - .sum() + s1.iter().zip(s2.iter()).map(T::diff_bits).sum() } // TODO: use `[const { MaybeUninit::uninit() }; N]` after MSRV is bumped to 1.79+ @@ -55,6 +74,44 @@ fn test_diff() { assert!(d2 < 4500); } +#[test] +fn test_diff_u32() { + const N: usize = 1000 / 4; + let mut v1 = [0u32; N]; + let mut v2 = [0u32; N]; + for v in v1.iter_mut() { + *v = getrandom::u32().unwrap(); + } + for v in v2.iter_mut() { + *v = getrandom::u32().unwrap(); + } + + // Between 3.5 and 4.5 bits per byte should differ. Probability of failure: + // ~ 2^(-94) = 2 * CDF[BinomialDistribution[8000, 0.5], 3500] + let d1 = num_diff_bits(&v1, &v2); + assert!(d1 > 3500); + assert!(d1 < 4500); +} + +#[test] +fn test_diff_u64() { + const N: usize = 1000 / 8; + let mut v1 = [0u64; N]; + let mut v2 = [0u64; N]; + for v in v1.iter_mut() { + *v = getrandom::u64().unwrap(); + } + for v in v2.iter_mut() { + *v = getrandom::u64().unwrap(); + } + + // Between 3.5 and 4.5 bits per byte should differ. Probability of failure: + // ~ 2^(-94) = 2 * CDF[BinomialDistribution[8000, 0.5], 3500] + let d1 = num_diff_bits(&v1, &v2); + assert!(d1 > 3500); + assert!(d1 < 4500); +} + #[test] fn test_small() { const N: usize = 64; From e1943e44e9de59ca7e1481720cf5a1bfb1037036 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 29 Nov 2024 15:45:14 +0300 Subject: [PATCH 071/201] ci: disable visionos build and fix cross installation (#548) --- .github/workflows/build.yml | 3 ++- .github/workflows/nopanic.yaml | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 87b5fe7f4..b97c4f7cf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,7 +33,8 @@ jobs: - run: cargo test --no-run --target=aarch64-apple-watchos -Zbuild-std --features=std # visionOS requires Xcode 15.2+, GitHub Actions defaults to an older version. - run: sudo xcode-select -switch /Applications/Xcode_15.2.app - - run: cargo test --no-run --target=aarch64-apple-visionos -Zbuild-std --features=std + # std is broken on visionOS right now + #- run: cargo test --no-run --target=aarch64-apple-visionos -Zbuild-std --features=std cross: name: Cross diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index dc8b1d4be..24c89efbb 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -93,6 +93,9 @@ jobs: - uses: Swatinem/rust-cache@v2 # TODO: use pre-compiled cross after a new (post-0.2.5) release - name: Install cross + env: + # Allow compiler warnings during cross installation + RUSTFLAGS: run: cargo install cross --force --git https://github.com/cross-rs/cross - name: Build (rndr.rs) From a5bc5fe4ec1854d6d8fc0fd5df9126d062d54f22 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 29 Nov 2024 15:55:46 +0300 Subject: [PATCH 072/201] Release v0.3.0-rc.0 (#547) --- CHANGELOG.md | 6 ++++-- Cargo.toml | 2 +- src/lib.rs | 3 +-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2383f6c57..c01987b18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Breaking Changes #### Changed -- Bump MSRV to 1.60 [#472] +- Bump MSRV to 1.63 [#542] - Rename `getrandom` and `getrandom_uninit` functions to `fill` and `fill_uninit` respectively [#532] #### Removed @@ -35,12 +35,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `rndr` opt-in backend [#512] - `linux_rustix` opt-in backend [#520] - Memory sanitizer support gated behind `getrandom_sanitize` configuration flag [#521] +- `u32` and `u64` functions for generating random values of the respective type [#544] [#415]: https://github.com/rust-random/getrandom/pull/415 [#440]: https://github.com/rust-random/getrandom/pull/440 [#442]: https://github.com/rust-random/getrandom/pull/442 [#448]: https://github.com/rust-random/getrandom/pull/448 -[#472]: https://github.com/rust-random/getrandom/pull/472 [#490]: https://github.com/rust-random/getrandom/pull/490 [#499]: https://github.com/rust-random/getrandom/pull/499 [#504]: https://github.com/rust-random/getrandom/pull/504 @@ -50,6 +50,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#521]: https://github.com/rust-random/getrandom/pull/521 [#522]: https://github.com/rust-random/getrandom/pull/522 [#532]: https://github.com/rust-random/getrandom/pull/532 +[#542]: https://github.com/rust-random/getrandom/pull/542 +[#544]: https://github.com/rust-random/getrandom/pull/544 ## [0.2.15] - 2024-05-06 ### Added diff --git a/Cargo.toml b/Cargo.toml index 2886268ef..559ca05e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "getrandom" -version = "0.2.15" # Also update html_root_url in lib.rs when bumping this +version = "0.3.0-rc.0" edition = "2021" rust-version = "1.63" # Sync tests.yml and README.md. authors = ["The Rand Project Developers"] diff --git a/src/lib.rs b/src/lib.rs index 930b94529..5b0f47fd8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,8 +5,7 @@ #![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", - html_root_url = "https://docs.rs/getrandom/0.2.15" + html_favicon_url = "https://www.rust-lang.org/favicon.ico" )] #![doc = include_str!("../README.md")] #![warn(rust_2018_idioms, unused_lifetimes, missing_docs)] From d2ddafb9700477f90013421330d1e648ed30590c Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 29 Nov 2024 18:47:00 +0300 Subject: [PATCH 073/201] Improve docs for the custom backend (#550) --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index 63d393962..b1bfdfbe1 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,31 @@ data and its length in bytes. Note that the buffer MAY be uninitialized. On success, the function should return `Ok(())` and fully fill the input buffer; otherwise, it should return an error value. +While wrapping functions which work with byte slices you should fully initialize +the buffer before passing it to the function: +```rust +use getrandom::Error; + +fn my_entropy_source(buf: &mut [u8]) -> Result<(), getrandom::Error> { + // ... + Ok(()) +} + +#[no_mangle] +unsafe extern "Rust" fn __getrandom_v03_custom( + dest: *mut u8, + len: usize, +) -> Result<(), Error> { + let buf = unsafe { + // fill the buffer with zeros + core::ptr::write_bytes(dest, 0, len); + // create mutable byte slice + core::slice::from_raw_parts_mut(dest, len) + }; + my_entropy_source(buf) +} +``` + If you are confident that `getrandom` is not used in your project, but it gets pulled nevertheless by one of your dependencies, then you can use the following custom backend, which always returns the "unsupported" error: From 69b353693647e10cdaec325248cc984b6480163e Mon Sep 17 00:00:00 2001 From: daxpedda Date: Fri, 29 Nov 2024 19:05:26 +0100 Subject: [PATCH 074/201] Remove faulty support for `wasm64-unknown-unknown` (#551) This removes the previously in #303 added support for `wasm64-unknown-unknown`. `wasm-bindgen` does in fact not support the Memory64 proposal. The reason it still compiled is that `wasm-bindgen` emits panicking stubs for any target it doesn't support. However, during runtime this would have failed. --- .github/workflows/build.yml | 17 ----------------- Cargo.toml | 2 +- README.md | 18 +++++++++--------- src/backends.rs | 6 +++--- src/backends/wasm_js.rs | 5 +---- 5 files changed, 14 insertions(+), 34 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b97c4f7cf..1d7a060e5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -58,23 +58,6 @@ jobs: - name: Build Tests run: cross test --no-run --target=${{ matrix.target }} --features=std - wasm64: - name: Wasm64 - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly # Need to build libstd - with: - components: rust-src - - uses: Swatinem/rust-cache@v2 - - name: Build and Link tests (build-std) - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - # This target is Tier 3, so we have to build libstd ourselves. - # We currently cannot run these tests because wasm-bindgen-test-runner - # does not yet support memory64. - run: cargo test --no-run -Z build-std=std,panic_abort --target=wasm64-unknown-unknown - tier2: name: Tier 2 runs-on: ubuntu-22.04 diff --git a/Cargo.toml b/Cargo.toml index 559ca05e9..3b779eae3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ wasi = { version = "0.13", default-features = false } windows-targets = "0.52" # wasm_js -[target.'cfg(all(getrandom_backend = "wasm_js", any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies] +[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", target_os = "unknown"))'.dependencies] wasm-bindgen = { version = "0.2.89", default-features = false } js-sys = "0.3" [target.'cfg(all(getrandom_backend = "wasm_js", getrandom_browser_test, target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies] diff --git a/README.md b/README.md index b1bfdfbe1..d145c2fe1 100644 --- a/README.md +++ b/README.md @@ -76,15 +76,15 @@ Pull Requests that add support for new targets to `getrandom` are always welcome `getrandom` also provides optional (opt-in) backends, which allow users to customize the source of randomness based on their specific needs: -| Backend name | Target | Target Triple | Implementation -| ----------------- | -------------------- | -------------------- | -------------- -| `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). -| `linux_rustix` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses [`rustix`] instead of `libc`. -| `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction -| `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register -| `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low-quality entropy without proper hardware configuration! -| `wasm_js` | Web Browser, Node.js | `wasm*‑*‑unknown` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js (see [WebAssembly support]) -| `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) +| Backend name | Target | Target Triple | Implementation +| ----------------- | -------------------- | ------------------------ | -------------- +| `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). +| `linux_rustix` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses [`rustix`] instead of `libc`. +| `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction +| `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register +| `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low-quality entropy without proper hardware configuration! +| `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js (see [WebAssembly support]) +| `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) Opt-in backends can be enabled using the `getrandom_backend` configuration flag. The flag can be set either by specifying the `rustflags` field in diff --git a/src/backends.rs b/src/backends.rs index d5164173d..a744a2295 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -149,11 +149,11 @@ cfg_if! { mod rdrand; pub use rdrand::*; } else if #[cfg(all( - any(target_arch = "wasm32", target_arch = "wasm64"), + target_arch = "wasm32", target_os = "unknown", ))] { - compile_error!("the wasm*-unknown-unknown targets are not supported by \ - default, you may need to enable the \"wasm_js\" \ + compile_error!("the wasm32-unknown-unknown targets are not supported \ + by default, you may need to enable the \"wasm_js\" \ configuration flag. For more information see: \ https://docs.rs/getrandom/#webassembly-support"); } else { diff --git a/src/backends/wasm_js.rs b/src/backends/wasm_js.rs index de2b4333e..c0182b824 100644 --- a/src/backends/wasm_js.rs +++ b/src/backends/wasm_js.rs @@ -6,10 +6,7 @@ use std::{mem::MaybeUninit, thread_local}; pub use crate::util::{inner_u32, inner_u64}; -#[cfg(not(all( - any(target_arch = "wasm32", target_arch = "wasm64"), - target_os = "unknown", -)))] +#[cfg(not(all(target_arch = "wasm32", target_os = "unknown",)))] compile_error!("`wasm_js` backend can be enabled only for OS-less WASM targets!"); use js_sys::{global, Function, Uint8Array}; From c697b5c1c7f850c8b6e68492874c633d43762bbc Mon Sep 17 00:00:00 2001 From: daxpedda Date: Mon, 2 Dec 2024 14:48:14 +0100 Subject: [PATCH 075/201] Run Wasm tests in workers as well (#552) This change runs Wasm tests in workers as well. - Fix Node tests not actually running any tests. It was already broken because of an interaction with the latest Rust version and an old Node.js version. - Test dedicated, shared and service worker by using the newly added environment variables: https://github.com/rustwasm/wasm-bindgen/pull/4295. --- .github/workflows/tests.yml | 28 ++++++++++++++++++++++------ Cargo.toml | 2 +- tests/mod.rs | 8 +++++--- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 890e133c4..ece1117c8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -240,16 +240,14 @@ jobs: web: name: Web - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - - run: choco install wget - if: runner.os == 'Windows' - name: Install precompiled wasm-pack shell: bash run: | - VERSION=v0.12.1 + VERSION=v0.13.1 URL=https://github.com/rustwasm/wasm-pack/releases/download/${VERSION}/wasm-pack-${VERSION}-x86_64-unknown-linux-musl.tar.gz wget -O - $URL | tar -xz --strip-components=1 -C ~/.cargo/bin wasm-pack --version @@ -260,11 +258,29 @@ jobs: run: wasm-pack test --node - name: Test (Firefox) env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test + WASM_BINDGEN_USE_BROWSER: 1 + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" run: wasm-pack test --headless --firefox - name: Test (Chrome) env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test + WASM_BINDGEN_USE_BROWSER: 1 + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" + run: wasm-pack test --headless --chrome + - name: Test (dedicated worker) + env: + WASM_BINDGEN_USE_DEDICATED_WORKER: 1 + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" + run: wasm-pack test --headless --firefox + - name: Test (shared worker) + env: + WASM_BINDGEN_USE_SHARED_WORKER: 1 + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" + run: wasm-pack test --headless --firefox + - name: Test (service worker) + env: + WASM_BINDGEN_USE_SERVICE_WORKER: 1 + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" + # Firefox doesn't support module service workers and therefor can't import scripts run: wasm-pack test --headless --chrome wasi: diff --git a/Cargo.toml b/Cargo.toml index 3b779eae3..16e47a4ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,7 @@ windows-targets = "0.52" [target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", target_os = "unknown"))'.dependencies] wasm-bindgen = { version = "0.2.89", default-features = false } js-sys = "0.3" -[target.'cfg(all(getrandom_backend = "wasm_js", getrandom_browser_test, target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies] +[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies] wasm-bindgen-test = "0.3.39" [features] diff --git a/tests/mod.rs b/tests/mod.rs index 204ec6539..c972e768b 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -1,10 +1,12 @@ use core::mem::MaybeUninit; use getrandom::{fill, fill_uninit}; -#[cfg(getrandom_browser_test)] +#[cfg(all( + getrandom_backend = "wasm_js", + target_arch = "wasm32", + target_os = "unknown" +))] use wasm_bindgen_test::wasm_bindgen_test as test; -#[cfg(getrandom_browser_test)] -wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); #[test] fn test_zero() { From cddf8612597929a0e60b1100554458ba11a42b83 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 2 Dec 2024 17:14:22 +0300 Subject: [PATCH 076/201] ci: use Ubuntu 24.04 (#553) Also moves x32 into a separate build-only job because the tests fail to link on Ubuntu 24.04. --- .github/workflows/build.yml | 46 ++++++++++++++++++++++++++++----- .github/workflows/nopanic.yaml | 4 +-- .github/workflows/tests.yml | 36 +++++++++----------------- .github/workflows/workspace.yml | 6 ++--- 4 files changed, 56 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1d7a060e5..41c6a4bfe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,7 +38,7 @@ jobs: cross: name: Cross - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: target: [ @@ -60,7 +60,7 @@ jobs: tier2: name: Tier 2 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: target: [ @@ -79,7 +79,7 @@ jobs: tier3: name: Tier 3 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: target: [ @@ -101,9 +101,41 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: cargo build -Z build-std=core --target=${{ matrix.target }} + # Ubuntu does not support running x32 binaries: + # https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1994516/comments/21 + linux-x32: + name: Linux x32 + runs-on: ubuntu-24.04 + strategy: + matrix: + target: [x86_64-unknown-linux-gnux32] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + - name: Install libc and libgcc + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends libc6-dev-x32 libx32gcc-11-dev + - uses: Swatinem/rust-cache@v2 + - run: cargo build --target=${{ matrix.target }} --features=std + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" + run: cargo build --target=${{ matrix.target }} --features=std + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" + run: cargo build --target=${{ matrix.target }} --features=std + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback + run: cargo build --features=std + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" + run: cargo build --features=std + rdrand: name: RDRAND - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: target: [ @@ -122,7 +154,7 @@ jobs: rndr: name: RNDR - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master @@ -145,7 +177,7 @@ jobs: esp-idf: name: ESP-IDF - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly # Required to build libcore @@ -158,7 +190,7 @@ jobs: no-atomics: name: No Atomics - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index 24c89efbb..f9821a1db 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -28,7 +28,7 @@ env: jobs: linux: name: Linux - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master @@ -82,7 +82,7 @@ jobs: cross: name: Cross - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ece1117c8..e96ad130d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,7 +21,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04, windows-2022] + os: [ubuntu-24.04, windows-2022] toolchain: [nightly, beta, stable, "1.63"] # Only Test macOS on stable to reduce macOS CI jobs include: @@ -42,35 +42,23 @@ jobs: linux: name: Linux - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: target: [x86_64-unknown-linux-musl, i686-unknown-linux-musl] - include: - - target: i686-unknown-linux-gnu - packages: libc6-dev-i386 lib32gcc-11-dev - - target: x86_64-unknown-linux-gnux32 - packages: libc6-dev-x32 libx32gcc-11-dev - # TODO: Find a Linux image/runner with CONFIG_X86_X32_ABI set - cargo_test_opts: --no-run steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} - - name: Install libc and libgcc - if: matrix.packages - run: | - sudo apt-get update - sudo apt-get install --no-install-recommends ${{ matrix.packages }} - uses: Swatinem/rust-cache@v2 - - run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std + - run: cargo test --target=${{ matrix.target }} --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" - run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std + run: cargo test --target=${{ matrix.target }} --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" - run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std + run: cargo test --target=${{ matrix.target }} --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback run: cargo test --features=std @@ -144,7 +132,7 @@ jobs: sanitizer: name: Sanitizer - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master @@ -158,7 +146,7 @@ jobs: cross: name: Cross - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: target: [ @@ -182,7 +170,7 @@ jobs: freebsd: name: FreeBSD VM - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Test in FreeBSD @@ -196,7 +184,7 @@ jobs: openbsd: name: OpenBSD VM - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Test in OpenBSD @@ -210,7 +198,7 @@ jobs: netbsd: name: NetBSD VM - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Test in NetBSD @@ -226,7 +214,7 @@ jobs: # https://github.com/rust-random/getrandom/actions/runs/11405005618/job/31735653874?pr=528 # dragonflybsd: # name: DragonflyBSD VM - # runs-on: ubuntu-22.04 + # runs-on: ubuntu-24.04 # steps: # - uses: actions/checkout@v4 # - name: Test in DragonflyBSD @@ -285,7 +273,7 @@ jobs: wasi: name: WASI - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 8da81c65e..2653984d8 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -12,7 +12,7 @@ permissions: jobs: clippy: name: Clippy - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: RUSTFLAGS: "-Dwarnings" steps: @@ -86,7 +86,7 @@ jobs: fmt: name: rustfmt - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable @@ -98,7 +98,7 @@ jobs: check-doc: name: rustdoc - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master From 584926ef40fd69a6c4b64dd7acca997e5c16330b Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 4 Dec 2024 16:48:15 +0300 Subject: [PATCH 077/201] wasm_js: remove IE 11 workaround (#554) Internet Explorer is superseded by Edge (which has 3-5% usage share) and effectively no longer supported. Citing Wikipedia: >For SAC versions of Windows 10, Internet Explorer 11 support ended on June 15, 2022, Internet Explorer was permanently disabled on February 14, 2023, and any remaining icons or shortcuts were due to be removed on June 13, 2023. Technically, it's still supported on LTSC, but Microsoft discourages the use of LTSC editions outside of "special-purpose devices" that perform a fixed function and thus do not require new user experience features, so I think we can ignore it. --- CHANGELOG.md | 2 ++ src/backends/wasm_js.rs | 40 +++++++++++++++++----------------------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c01987b18..01de288e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 in favor of configuration flags [#504] - `register_custom_getrandom!` macro [#504] - Implementation of `From` for `Error` and `Error::code` method [#507] +- Internet Explorer 11 support [#554] ### Changed - Use `ProcessPrng` on Windows 10 and up, and use RtlGenRandom on older legacy Windows versions [#415] @@ -52,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#532]: https://github.com/rust-random/getrandom/pull/532 [#542]: https://github.com/rust-random/getrandom/pull/542 [#544]: https://github.com/rust-random/getrandom/pull/544 +[#554]: https://github.com/rust-random/getrandom/pull/554 ## [0.2.15] - 2024-05-06 ### Added diff --git a/src/backends/wasm_js.rs b/src/backends/wasm_js.rs index c0182b824..15a4e66bb 100644 --- a/src/backends/wasm_js.rs +++ b/src/backends/wasm_js.rs @@ -83,29 +83,23 @@ fn getrandom_init() -> Result { // Get the Web Crypto interface if we are in a browser, Web Worker, Deno, // or another environment that supports the Web Cryptography API. This // also allows for user-provided polyfills in unsupported environments. - let crypto = match global.crypto() { - // Standard Web Crypto interface - c if c.is_object() => c, - // Node.js CommonJS Crypto module - _ if is_node(&global) => { - // If module.require isn't a valid function, we are in an ES module. - match Module::require_fn().and_then(JsCast::dyn_into::) { - Ok(require_fn) => match require_fn.call1(&global, &JsValue::from_str("crypto")) { - Ok(n) => return Ok(RngSource::Node(n.unchecked_into())), - Err(_) => return Err(Error::NODE_CRYPTO), - }, - Err(_) => return Err(Error::NODE_ES_MODULE), - } - } - // IE 11 Workaround - _ => match global.ms_crypto() { - c if c.is_object() => c, - _ => return Err(Error::WEB_CRYPTO), - }, - }; - - let buf = Uint8Array::new_with_length(WEB_CRYPTO_BUFFER_SIZE.into()); - Ok(RngSource::Web(crypto, buf)) + let crypto = global.crypto(); + if crypto.is_object() { + let buf = Uint8Array::new_with_length(WEB_CRYPTO_BUFFER_SIZE.into()); + Ok(RngSource::Web(crypto, buf)) + } else if is_node(&global) { + // If module.require isn't a valid function, we are in an ES module. + let require_fn = Module::require_fn() + .and_then(JsCast::dyn_into::) + .map_err(|_| Error::NODE_ES_MODULE)?; + let n = require_fn + .call1(&global, &JsValue::from_str("crypto")) + .map_err(|_| Error::NODE_CRYPTO)? + .unchecked_into(); + Ok(RngSource::Node(n)) + } else { + Err(Error::WEB_CRYPTO) + } } // Taken from https://www.npmjs.com/package/browser-or-node From cee3bf13e24f43161ae499eb33b4dbe63ca43117 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 4 Dec 2024 18:03:51 +0300 Subject: [PATCH 078/201] netbsd: fix fallback and test it using configuration flag (#555) Fixes bug in the NetBSD fallback code based on `KERN_ARND`. `sysctl` returns either 0 or -1, while the code assumed that on success it returns number of bytes filled. Adds the `getrandom_test_netbsd_fallback` configuration flag, which forces the NetBSD backend to use the `KERN_ARND` fallback, and tweaks CI to use the flag. --- .github/workflows/tests.yml | 4 +++- CHANGELOG.md | 4 ++++ Cargo.toml | 1 + src/backends/netbsd.rs | 14 +++++--------- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e96ad130d..6e92dae04 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -208,7 +208,9 @@ jobs: usesh: true prepare: | /usr/sbin/pkg_add rust - run: cargo test + run: | + cargo test + RUSTFLAGS="--cfg getrandom_test_netbsd_fallback -D warnings" cargo test # This job currently fails: # https://github.com/rust-random/getrandom/actions/runs/11405005618/job/31735653874?pr=528 diff --git a/CHANGELOG.md b/CHANGELOG.md index 01de288e6..ce4cebbc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Memory sanitizer support gated behind `getrandom_sanitize` configuration flag [#521] - `u32` and `u64` functions for generating random values of the respective type [#544] +### Fixed +- NetBSD fallback code based on `KERN_ARND` [#555] + [#415]: https://github.com/rust-random/getrandom/pull/415 [#440]: https://github.com/rust-random/getrandom/pull/440 [#442]: https://github.com/rust-random/getrandom/pull/442 @@ -54,6 +57,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#542]: https://github.com/rust-random/getrandom/pull/542 [#544]: https://github.com/rust-random/getrandom/pull/544 [#554]: https://github.com/rust-random/getrandom/pull/554 +[#555]: https://github.com/rust-random/getrandom/pull/555 ## [0.2.15] - 2024-05-06 ### Added diff --git a/Cargo.toml b/Cargo.toml index 16e47a4ba..28b48a64c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,6 +83,7 @@ check-cfg = [ 'cfg(getrandom_sanitize)', 'cfg(getrandom_browser_test)', 'cfg(getrandom_test_linux_fallback)', + 'cfg(getrandom_test_netbsd_fallback)', ] [package.metadata.docs.rs] diff --git a/src/backends/netbsd.rs b/src/backends/netbsd.rs index 0e3268ef4..57fa91a00 100644 --- a/src/backends/netbsd.rs +++ b/src/backends/netbsd.rs @@ -30,17 +30,13 @@ unsafe extern "C" fn polyfill_using_kern_arand( // 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 expected_ret = libc::c_int::try_from(len).expect("len is bounded by 256"); - let ret = unsafe { libc::sysctl(MIB.as_ptr(), MIB_LEN, buf, &mut len, ptr::null(), 0) }; - if ret == expected_ret { - libc::ssize_t::try_from(ret).expect("len is bounded by 256") - } else if ret == -1 { - -1 - } else { + 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 + _ => 0, } } @@ -53,7 +49,7 @@ fn init() -> *mut c_void { static NAME: &[u8] = b"getrandom\0"; let name_ptr = NAME.as_ptr().cast::(); let mut ptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) }; - if ptr.is_null() { + 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; From 96ed30eaf48d7b205b1b0d9058234f27e44a028d Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 4 Dec 2024 18:15:01 +0300 Subject: [PATCH 079/201] ci: do not build FreeBSD and NetBSD in the cross job (#556) The targets are already tested using VM jobs. --- .github/workflows/build.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 41c6a4bfe..6cd162104 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,8 +44,6 @@ jobs: target: [ sparcv9-sun-solaris, x86_64-unknown-illumos, - x86_64-unknown-freebsd, - x86_64-unknown-netbsd, ] steps: - uses: actions/checkout@v4 From 5fbfd2e8aea75d67dec475d1080c3c7d952611f4 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 5 Dec 2024 02:49:19 +0300 Subject: [PATCH 080/201] wasm_js: remove the separate codepath for Node.js and TLS caching (#557) Acquire of "global" objects is relatively cheap (adds ~40 ns of overhead), so it make sense to do it on each call instead of trying to cache objects in a TLS variable. Additionally, removes the separate codepath for Node.js since it fully supports the Web Crypto API since v19 (released 2022-10-18). --- CHANGELOG.md | 5 +- Cargo.toml | 11 ++- README.md | 24 +----- src/backends.rs | 2 +- src/backends/wasm_js.rs | 157 ++++++++-------------------------------- src/error.rs | 16 +--- 6 files changed, 46 insertions(+), 169 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce4cebbc9..36cabb352 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Switch from `libpthread`'s mutex to `futex` on Linux and to `nanosleep`-based wait loop on other targets in the `use_file` backend [#490] - Do not retry on `EAGAIN` while polling `/dev/random` on Linux [#522] - +- Remove separate codepath for Node.js in the `wasm_js` backend (bumps minimum supported Node.js + version to v19) [#557] + ### Added - `wasm32-wasip1` and `wasm32-wasip2` support [#499] - `getrandom_backend` configuration flag for selection of opt-in backends [#504] @@ -58,6 +60,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#544]: https://github.com/rust-random/getrandom/pull/544 [#554]: https://github.com/rust-random/getrandom/pull/554 [#555]: https://github.com/rust-random/getrandom/pull/555 +[#557]: https://github.com/rust-random/getrandom/pull/557 ## [0.2.15] - 2024-05-06 ### Added diff --git a/Cargo.toml b/Cargo.toml index 28b48a64c..875a7fd07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,11 +63,11 @@ wasi = { version = "0.13", default-features = false } windows-targets = "0.52" # wasm_js -[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", target_os = "unknown"))'.dependencies] -wasm-bindgen = { version = "0.2.89", default-features = false } -js-sys = "0.3" -[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies] -wasm-bindgen-test = "0.3.39" +[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dependencies] +wasm-bindgen = { version = "0.2.96", default-features = false } +js-sys = "0.3.73" +[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dev-dependencies] +wasm-bindgen-test = "0.3" [features] # Implement std::error::Error for getrandom::Error and @@ -81,7 +81,6 @@ level = "warn" check-cfg = [ 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "linux_rustix", "wasm_js", "esp_idf"))', 'cfg(getrandom_sanitize)', - 'cfg(getrandom_browser_test)', 'cfg(getrandom_test_linux_fallback)', 'cfg(getrandom_test_netbsd_fallback)', ] diff --git a/README.md b/README.md index d145c2fe1..ebd1b76aa 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ of randomness based on their specific needs: | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register | `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low-quality entropy without proper hardware configuration! -| `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js (see [WebAssembly support]) +| `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown`, `wasm32v1-none` | [`Crypto.getRandomValues`] | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) Opt-in backends can be enabled using the `getrandom_backend` configuration flag. @@ -115,9 +115,9 @@ which JavaScript interface should be used (or if JavaScript is available at all) Instead, *if the `wasm_js` backend 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](#opt-in-backends) using the [`wasm-bindgen`] toolchain. +call the appropriate Web Crypto methods [described above](#opt-in-backends) using +the [`wasm-bindgen`] toolchain. Both web browser (main window and Web Workers) +and Node.js (v19 or later) environments are supported. To enable the `wasm_js` backend, you can add the following lines to your project's `.cargo/config.toml` file: @@ -126,18 +126,6 @@ project's `.cargo/config.toml` file: rustflags = ['--cfg', 'getrandom_backend="wasm_js"'] ``` -#### Node.js ES module support - -Node.js supports both [CommonJS modules] and [ES modules]. Due to -limitations in wasm-bindgen's [`module`] support, we cannot directly -support ES Modules running on Node.js. However, on Node v15 and later, the -module author can add a simple shim to support the Web Cryptography API: -```js -import { webcrypto } from 'node:crypto' -globalThis.crypto = webcrypto -``` -This crate will then use the provided `webcrypto` implementation. - ### Custom backend If this crate does not support your target out of the box or you have to use @@ -348,17 +336,13 @@ dual licensed as above, without any additional terms or conditions. [`RNDR`]: https://developer.arm.com/documentation/ddi0601/2024-06/AArch64-Registers/RNDR--Random-Number [`CCRandomGenerateBytes`]: https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html [`cprng_draw`]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw -[`crypto.randomFillSync`]: https://nodejs.org/api/crypto.html#cryptorandomfillsyncbuffer-offset-size [`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/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-buf_len-size---errno [`get-random-u64`]: https://github.com/WebAssembly/WASI/blob/v0.2.1/wasip2/random/random.wit#L23-L28 -[WebAssembly support]: #webassembly-support [configuration flags]: #configuration-flags [custom backend]: #custom-backend [`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen [`module`]: https://rustwasm.github.io/wasm-bindgen/reference/attributes/on-js-imports/module.html -[CommonJS modules]: https://nodejs.org/api/modules.html -[ES modules]: https://nodejs.org/api/esm.html [`sys_read_entropy`]: https://github.com/hermit-os/kernel/blob/315f58ff5efc81d9bf0618af85a59963ff55f8b1/src/syscalls/entropy.rs#L47-L55 [platform-support]: https://doc.rust-lang.org/stable/rustc/platform-support.html [WASI]: https://github.com/CraneStation/wasi diff --git a/src/backends.rs b/src/backends.rs index a744a2295..f7b720f58 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -150,7 +150,7 @@ cfg_if! { pub use rdrand::*; } else if #[cfg(all( target_arch = "wasm32", - target_os = "unknown", + any(target_os = "unknown", target_os = "none") ))] { compile_error!("the wasm32-unknown-unknown targets are not supported \ by default, you may need to enable the \"wasm_js\" \ diff --git a/src/backends/wasm_js.rs b/src/backends/wasm_js.rs index 15a4e66bb..7753daf98 100644 --- a/src/backends/wasm_js.rs +++ b/src/backends/wasm_js.rs @@ -1,158 +1,59 @@ //! Implementation for WASM based on Web and Node.js use crate::Error; - -extern crate std; -use std::{mem::MaybeUninit, thread_local}; +use core::mem::MaybeUninit; pub use crate::util::{inner_u32, inner_u64}; -#[cfg(not(all(target_arch = "wasm32", target_os = "unknown",)))] +#[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 js_sys::{global, Function, Uint8Array}; +use js_sys::{global, Uint8Array}; use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; // Size of our temporary Uint8Array buffer used with WebCrypto methods // Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues -const WEB_CRYPTO_BUFFER_SIZE: u16 = 256; -// Node.js's crypto.randomFillSync requires the size to be less than 2**31. -const NODE_MAX_BUFFER_SIZE: usize = (1 << 31) - 1; - -enum RngSource { - Node(NodeCrypto), - Web(WebCrypto, 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 = getrandom_init(); -); +const CRYPTO_BUFFER_SIZE: u16 = 256; pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - RNG_SOURCE.with(|result| { - let source = result.as_ref().map_err(|&e| e)?; - - match source { - RngSource::Node(n) => { - for chunk in dest.chunks_mut(NODE_MAX_BUFFER_SIZE) { - // SAFETY: chunk is never used directly, the memory is only - // modified via the Uint8Array view, which is passed - // directly to JavaScript. Also, crypto.randomFillSync does - // not resize the buffer. We know the length is less than - // u32::MAX because of the chunking above. - // Note that this uses the fact that JavaScript doesn't - // have a notion of "uninitialized memory", this is purely - // a Rust/C/C++ concept. - let res = n.random_fill_sync(unsafe { - Uint8Array::view_mut_raw(chunk.as_mut_ptr().cast::(), chunk.len()) - }); - if res.is_err() { - return Err(Error::NODE_RANDOM_FILL_SYNC); - } - } - } - RngSource::Web(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(WEB_CRYPTO_BUFFER_SIZE.into()) { - let chunk_len: u32 = chunk - .len() - .try_into() - .expect("chunk length is bounded by WEB_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); - - if crypto.get_random_values(&sub_buf).is_err() { - return Err(Error::WEB_GET_RANDOM_VALUES); - } - - // SAFETY: `sub_buf`'s length is the same length as `chunk` - unsafe { sub_buf.raw_copy_to_ptr(chunk.as_mut_ptr().cast::()) }; - } - } - }; - Ok(()) - }) -} - -fn getrandom_init() -> Result { let global: Global = global().unchecked_into(); - - // Get the Web Crypto interface if we are in a browser, Web Worker, Deno, - // or another environment that supports the Web Cryptography API. This - // also allows for user-provided polyfills in unsupported environments. let crypto = global.crypto(); - if crypto.is_object() { - let buf = Uint8Array::new_with_length(WEB_CRYPTO_BUFFER_SIZE.into()); - Ok(RngSource::Web(crypto, buf)) - } else if is_node(&global) { - // If module.require isn't a valid function, we are in an ES module. - let require_fn = Module::require_fn() - .and_then(JsCast::dyn_into::) - .map_err(|_| Error::NODE_ES_MODULE)?; - let n = require_fn - .call1(&global, &JsValue::from_str("crypto")) - .map_err(|_| Error::NODE_CRYPTO)? - .unchecked_into(); - Ok(RngSource::Node(n)) - } else { - Err(Error::WEB_CRYPTO) + + if !crypto.is_object() { + return Err(Error::WEB_CRYPTO); } -} -// 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(); + // getRandomValues does not work with all types of WASM memory, + // so we initially write to browser memory to avoid exceptions. + let buf = Uint8Array::new_with_length(CRYPTO_BUFFER_SIZE.into()); + for chunk in dest.chunks_mut(CRYPTO_BUFFER_SIZE.into()) { + let chunk_len: u32 = chunk + .len() + .try_into() + .expect("chunk length is bounded by 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); + + if crypto.get_random_values(&sub_buf).is_err() { + return Err(Error::WEB_GET_RANDOM_VALUES); } + + // SAFETY: `sub_buf`'s length is the same length as `chunk` + unsafe { sub_buf.raw_copy_to_ptr(chunk.as_mut_ptr().cast::()) }; } - false + Ok(()) } #[wasm_bindgen] extern "C" { // Return type of js_sys::global() type Global; - // Web Crypto API: Crypto interface (https://www.w3.org/TR/WebCryptoAPI/) - type WebCrypto; - // Getters for the WebCrypto API + type Crypto; + // Getters for the Crypto API #[wasm_bindgen(method, getter)] - fn crypto(this: &Global) -> WebCrypto; - #[wasm_bindgen(method, getter, js_name = msCrypto)] - fn ms_crypto(this: &Global) -> WebCrypto; + fn crypto(this: &Global) -> Crypto; // Crypto.getRandomValues() #[wasm_bindgen(method, js_name = getRandomValues, catch)] - fn get_random_values(this: &WebCrypto, buf: &Uint8Array) -> Result<(), JsValue>; - - // Node JS crypto module (https://nodejs.org/api/crypto.html) - type NodeCrypto; - // crypto.randomFillSync() - #[wasm_bindgen(method, js_name = randomFillSync, catch)] - fn random_fill_sync(this: &NodeCrypto, buf: Uint8Array) -> Result<(), JsValue>; - - // Ideally, we would just use `fn require(s: &str)` here. However, doing - // this causes a Webpack warning. So we instead return the function itself - // and manually invoke it using call1. This also lets us to check that the - // function actually exists, allowing for better error messages. See: - // https://github.com/rust-random/getrandom/issues/224 - // https://github.com/rust-random/getrandom/issues/256 - type Module; - #[wasm_bindgen(getter, static_method_of = Module, js_class = module, js_name = require, catch)] - fn require_fn() -> Result; - - // 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; + fn get_random_values(this: &Crypto, buf: &Uint8Array) -> Result<(), JsValue>; } diff --git a/src/error.rs b/src/error.rs index b27ef26b4..0f486c7b7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -43,19 +43,12 @@ impl Error { pub const WEB_GET_RANDOM_VALUES: Error = Self::new_internal(8); /// On VxWorks, call to `randSecure` failed (random number generator is not yet initialized). pub const VXWORKS_RAND_SECURE: Error = Self::new_internal(11); - /// Node.js does not have the `crypto` CommonJS module. - pub const NODE_CRYPTO: Error = Self::new_internal(12); - /// Calling Node.js function `crypto.randomFillSync` failed. - pub const NODE_RANDOM_FILL_SYNC: Error = Self::new_internal(13); - /// Called from an ES module on Node.js. This is unsupported, see: - /// . - pub const NODE_ES_MODULE: Error = Self::new_internal(14); /// Calling Windows ProcessPrng failed. - pub const WINDOWS_PROCESS_PRNG: Error = Self::new_internal(15); + pub const WINDOWS_PROCESS_PRNG: Error = Self::new_internal(12); /// RNDR register read failed due to a hardware issue. - pub const RNDR_FAILURE: Error = Self::new_internal(16); + pub const RNDR_FAILURE: Error = Self::new_internal(13); /// RNDR register is not supported on this target. - pub const RNDR_NOT_AVAILABLE: Error = Self::new_internal(17); + pub const RNDR_NOT_AVAILABLE: Error = Self::new_internal(14); /// Codes below this point represent OS Errors (i.e. positive i32 values). /// Codes at or above this point, but below [`Error::CUSTOM_START`] are @@ -164,9 +157,6 @@ fn internal_desc(error: Error) -> Option<&'static str> { Error::WEB_CRYPTO => "Web Crypto API is unavailable", Error::WEB_GET_RANDOM_VALUES => "Calling Web API crypto.getRandomValues failed", Error::VXWORKS_RAND_SECURE => "randSecure: VxWorks RNG module is not initialized", - Error::NODE_CRYPTO => "Node.js crypto CommonJS module is unavailable", - Error::NODE_RANDOM_FILL_SYNC => "Calling Node.js API crypto.randomFillSync failed", - Error::NODE_ES_MODULE => "Node.js ES modules are not directly supported, see https://docs.rs/getrandom#nodejs-es-module-support", Error::WINDOWS_PROCESS_PRNG => "ProcessPrng: Windows system function failure", Error::RNDR_FAILURE => "RNDR: Could not generate a random number", Error::RNDR_NOT_AVAILABLE => "RNDR: Register not supported", From ae0c807161da3007a9703c9da81b174097dc0994 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Thu, 5 Dec 2024 22:15:33 +0100 Subject: [PATCH 081/201] Add `no_std` support for Web (#560) In #557 we forgot to port the `no_std` support from #541. This also adds running Clippy for `wasm32v1-none`. --- .github/workflows/build.yml | 34 ++++++++++++++++++++++++++++++++++ .github/workflows/tests.yml | 12 ++++++------ Cargo.toml | 2 +- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6cd162104..cb7ffe34d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -131,6 +131,40 @@ jobs: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" run: cargo build --features=std + web: + name: ${{ matrix.target.description }} ${{ matrix.feature.description }} ${{ matrix.atomic.description }} + runs-on: ubuntu-24.04 + env: + RUSTFLAGS: --cfg getrandom_backend="wasm_js" ${{ matrix.atomic.flags }} + strategy: + fail-fast: false + matrix: + target: [ + { description: Web, target: wasm32-unknown-unknown }, + { description: WasmV1, target: wasm32v1-none }, + ] + feature: [ + { description: no_std, feature: "", build-std: "core,alloc", std: false }, + { feature: --features std, build-std: "panic_abort,std", std: true }, + ] + atomic: [ + { flags: "" }, + { description: with Atomics, flags: "-Ctarget-feature=+atomics,bulk-memory" }, + ] + exclude: + - target: { target: wasm32v1-none } + feature: { std: true } + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + targets: ${{ matrix.target.target }} + toolchain: nightly-2024-10-24 + components: rust-src + - uses: Swatinem/rust-cache@v2 + - name: Build + run: cargo build --target ${{ matrix.target.target }} ${{ matrix.feature.feature }} -Zbuild-std=${{ matrix.feature.build-std }} + rdrand: name: RDRAND runs-on: ubuntu-24.04 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6e92dae04..045a6bb94 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -245,33 +245,33 @@ jobs: - name: Test (Node) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --node + run: wasm-pack test --node -- --features std - name: Test (Firefox) env: WASM_BINDGEN_USE_BROWSER: 1 RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --headless --firefox + run: wasm-pack test --headless --firefox -- --features std - name: Test (Chrome) env: WASM_BINDGEN_USE_BROWSER: 1 RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --headless --chrome + run: wasm-pack test --headless --chrome -- --features std - name: Test (dedicated worker) env: WASM_BINDGEN_USE_DEDICATED_WORKER: 1 RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --headless --firefox + run: wasm-pack test --headless --firefox -- --features std - name: Test (shared worker) env: WASM_BINDGEN_USE_SHARED_WORKER: 1 RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --headless --firefox + run: wasm-pack test --headless --firefox -- --features std - name: Test (service worker) env: WASM_BINDGEN_USE_SERVICE_WORKER: 1 RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" # Firefox doesn't support module service workers and therefor can't import scripts - run: wasm-pack test --headless --chrome + run: wasm-pack test --headless --chrome -- --features std wasi: name: WASI diff --git a/Cargo.toml b/Cargo.toml index 875a7fd07..6e7f30d4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,7 @@ windows-targets = "0.52" # wasm_js [target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dependencies] wasm-bindgen = { version = "0.2.96", default-features = false } -js-sys = "0.3.73" +js-sys = { version = "0.3.73", default-features = false } [target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dev-dependencies] wasm-bindgen-test = "0.3" From 30a7f1fd9427be672da3d750327b5136504584b3 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Mon, 9 Dec 2024 16:51:19 +0100 Subject: [PATCH 082/201] Web optimizations (#559) As discussed in #541. This PR adds the following improvements: - Caching of the global `Crypto` object. - Detecting if our Wasm memory is based on a `SharedArrayBuffer`. If not, we can copy bytes directly into our memory instead of having to go through JS. This saves allocating the buffer in JS and copying the bytes into Wasm memory. This is also the most common path. `SharedArrayBuffer` requires `target_feature = "atomics"`, which is unstable and requires Rust nightly. See https://github.com/rust-random/getrandom/pull/559#issuecomment-2525342760 for full context. - The atomic path only creates a sub-array when necessary, potentially saving another FFI call. - The atomic path will now allocate an `Uint8Array` with the minimum amount of bytes necessary instead of a fixed size. - The maximum chunk size for the non-atomic path and the maximum `Uint8Array` size for the atomic paths have been increased to 65536 bytes: the maximum allowed buffer size for `Crypto.getRandomValues()`. All in all this should give a performance improvement of ~5% to ~500% depending on the amount of requested bytes and which path is taken. See https://github.com/rust-random/getrandom/pull/559#discussion_r1874542668 for some benchmark results. This spawned a bunch of improvements and fixes in `wasm-bindgen` that are being used here: - https://github.com/rustwasm/wasm-bindgen/pull/4315 - https://github.com/rustwasm/wasm-bindgen/pull/4316 - https://github.com/rustwasm/wasm-bindgen/pull/4318 - https://github.com/rustwasm/wasm-bindgen/pull/4319 - https://github.com/rustwasm/wasm-bindgen/pull/4340 --- .github/workflows/tests.yml | 48 ++++++++++++++++++-------- .github/workflows/workspace.yml | 4 +++ Cargo.toml | 5 +-- src/backends/wasm_js.rs | 60 +++++++++++++++++++-------------- src/error.rs | 3 -- 5 files changed, 75 insertions(+), 45 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 045a6bb94..ae4910ea5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -229,11 +229,31 @@ jobs: # run: cargo test web: - name: Web + name: ${{ matrix.rust.description }} runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + rust: + - { + description: Web, + version: stable, + flags: -Dwarnings --cfg getrandom_backend="wasm_js", + args: --features=std, + } + - { + description: Web with Atomics, + version: nightly, + components: rust-src, + flags: '-Dwarnings --cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory', + args: '--features=std -Zbuild-std=panic_abort,std', + } steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust.version }} + components: ${{ matrix.rust.components }} - name: Install precompiled wasm-pack shell: bash run: | @@ -244,34 +264,34 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Test (Node) env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --node -- --features std + RUSTFLAGS: ${{ matrix.rust.flags }} + run: wasm-pack test --node -- ${{ matrix.rust.args }} - name: Test (Firefox) env: WASM_BINDGEN_USE_BROWSER: 1 - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --headless --firefox -- --features std + RUSTFLAGS: ${{ matrix.rust.flags }} + run: wasm-pack test --headless --firefox -- ${{ matrix.rust.args }} - name: Test (Chrome) env: WASM_BINDGEN_USE_BROWSER: 1 - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --headless --chrome -- --features std + RUSTFLAGS: ${{ matrix.rust.flags }} + run: wasm-pack test --headless --chrome -- ${{ matrix.rust.args }} - name: Test (dedicated worker) env: WASM_BINDGEN_USE_DEDICATED_WORKER: 1 - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --headless --firefox -- --features std + RUSTFLAGS: ${{ matrix.rust.flags }} + run: wasm-pack test --headless --firefox -- ${{ matrix.rust.args }} - name: Test (shared worker) env: WASM_BINDGEN_USE_SHARED_WORKER: 1 - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: wasm-pack test --headless --firefox -- --features std + RUSTFLAGS: ${{ matrix.rust.flags }} + run: wasm-pack test --headless --firefox -- ${{ matrix.rust.args }} - name: Test (service worker) env: WASM_BINDGEN_USE_SERVICE_WORKER: 1 - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" + RUSTFLAGS: ${{ matrix.rust.flags }} # Firefox doesn't support module service workers and therefor can't import scripts - run: wasm-pack test --headless --chrome -- --features std + run: wasm-pack test --headless --chrome -- ${{ matrix.rust.args }} wasi: name: WASI diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 2653984d8..7f62034a1 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -49,6 +49,10 @@ jobs: env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown + - name: Web WASM with atomics (wasm_js.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory + run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown - name: Linux (linux_android.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" diff --git a/Cargo.toml b/Cargo.toml index 6e7f30d4f..05ff4b1b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,8 +64,9 @@ windows-targets = "0.52" # wasm_js [target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dependencies] -wasm-bindgen = { version = "0.2.96", default-features = false } -js-sys = { version = "0.3.73", default-features = false } +wasm-bindgen = { version = "0.2.98", default-features = false } +[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none"), target_feature = "atomics"))'.dependencies] +js-sys = { version = "0.3.75", default-features = false } [target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dev-dependencies] wasm-bindgen-test = "0.3" diff --git a/src/backends/wasm_js.rs b/src/backends/wasm_js.rs index 7753daf98..8556f7680 100644 --- a/src/backends/wasm_js.rs +++ b/src/backends/wasm_js.rs @@ -7,35 +7,46 @@ 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 js_sys::{global, Uint8Array}; -use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; +use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; -// Size of our temporary Uint8Array buffer used with WebCrypto methods -// Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues -const CRYPTO_BUFFER_SIZE: u16 = 256; +// 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"))] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - let global: Global = global().unchecked_into(); - let crypto = global.crypto(); - - if !crypto.is_object() { - return Err(Error::WEB_CRYPTO); + 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]) -> Result<(), Error> { // getRandomValues does not work with all types of WASM memory, // so we initially write to browser memory to avoid exceptions. - let buf = Uint8Array::new_with_length(CRYPTO_BUFFER_SIZE.into()); - for chunk in dest.chunks_mut(CRYPTO_BUFFER_SIZE.into()) { - let chunk_len: u32 = chunk + 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 CRYPTO_BUFFER_SIZE"); + .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 = buf.subarray(0, chunk_len); + let sub_buf = if chunk_len == buf_len_u32 { + &buf + } else { + &buf.subarray(0, chunk_len) + }; - if crypto.get_random_values(&sub_buf).is_err() { - return Err(Error::WEB_GET_RANDOM_VALUES); + if get_random_values(sub_buf).is_err() { + return Err(Error::WEB_CRYPTO); } // SAFETY: `sub_buf`'s length is the same length as `chunk` @@ -46,14 +57,11 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { #[wasm_bindgen] extern "C" { - // Return type of js_sys::global() - type Global; - // Web Crypto API: Crypto interface (https://www.w3.org/TR/WebCryptoAPI/) - type Crypto; - // Getters for the Crypto API - #[wasm_bindgen(method, getter)] - fn crypto(this: &Global) -> Crypto; // Crypto.getRandomValues() - #[wasm_bindgen(method, js_name = getRandomValues, catch)] - fn get_random_values(this: &Crypto, buf: &Uint8Array) -> Result<(), JsValue>; + #[cfg(not(target_feature = "atomics"))] + #[wasm_bindgen(js_namespace = ["globalThis", "crypto"], js_name = getRandomValues, catch)] + fn get_random_values(buf: &mut [MaybeUninit]) -> 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>; } diff --git a/src/error.rs b/src/error.rs index 0f486c7b7..0c60f9294 100644 --- a/src/error.rs +++ b/src/error.rs @@ -39,8 +39,6 @@ impl Error { pub const NO_RDRAND: Error = Self::new_internal(6); /// The environment does not support the Web Crypto API. pub const WEB_CRYPTO: Error = Self::new_internal(7); - /// Calling Web Crypto API `crypto.getRandomValues` failed. - pub const WEB_GET_RANDOM_VALUES: Error = Self::new_internal(8); /// On VxWorks, call to `randSecure` failed (random number generator is not yet initialized). pub const VXWORKS_RAND_SECURE: Error = Self::new_internal(11); /// Calling Windows ProcessPrng failed. @@ -155,7 +153,6 @@ fn internal_desc(error: Error) -> Option<&'static str> { Error::FAILED_RDRAND => "RDRAND: failed multiple times: CPU issue likely", Error::NO_RDRAND => "RDRAND: instruction not supported", Error::WEB_CRYPTO => "Web Crypto API is unavailable", - Error::WEB_GET_RANDOM_VALUES => "Calling Web API crypto.getRandomValues failed", Error::VXWORKS_RAND_SECURE => "randSecure: VxWorks RNG module is not initialized", Error::WINDOWS_PROCESS_PRNG => "ProcessPrng: Windows system function failure", Error::RNDR_FAILURE => "RNDR: Could not generate a random number", From 83bef1213e872df4466ea3d6392920f420cdd2a3 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 11 Dec 2024 10:59:20 +0300 Subject: [PATCH 083/201] Make target-specific errors private (#562) The main reason for existence of the target-specific errors is nicer error descriptions. Users arguably should not match on those error constants since our inner implementation may change together with possible error codes (for example, like with `IOS_SEC_RANDOM`). Marking the error constants as private we get flexibility to change error codes and names. Additionally, the `internal_desc` change reduces generated binary size since compiler no longer has to include irrelevant error descriptions. Ideally the target-specific error descriptions would be defined in the relevant modules, but I couldn't find a good way to do it, so, unfortunately, I had to partially duplicate backend `cfg`s in `internal_desc`. --- src/backends/apple_other.rs | 7 ++- src/backends/rdrand.rs | 7 +++ src/backends/rndr.rs | 7 +++ src/backends/vxworks.rs | 5 +++ src/backends/wasm_js.rs | 5 +++ src/backends/windows.rs | 5 +++ src/backends/windows7.rs | 5 +++ src/error.rs | 86 +++++++++++++++++++------------------ 8 files changed, 84 insertions(+), 43 deletions(-) diff --git a/src/backends/apple_other.rs b/src/backends/apple_other.rs index 127a31e3c..a8c0a24d6 100644 --- a/src/backends/apple_other.rs +++ b/src/backends/apple_other.rs @@ -10,6 +10,11 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { if ret == libc::kCCSuccess { Ok(()) } else { - Err(Error::IOS_SEC_RANDOM) + Err(Error::IOS_RANDOM_GEN) } } + +impl Error { + /// Call to `CCRandomGenerateBytes` failed. + pub(crate) const IOS_RANDOM_GEN: Error = Self::new_internal(10); +} diff --git a/src/backends/rdrand.rs b/src/backends/rdrand.rs index 19fa97baf..67dc71296 100644 --- a/src/backends/rdrand.rs +++ b/src/backends/rdrand.rs @@ -170,3 +170,10 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // 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); +} diff --git a/src/backends/rndr.rs b/src/backends/rndr.rs index bd2878f00..7db903555 100644 --- a/src/backends/rndr.rs +++ b/src/backends/rndr.rs @@ -132,3 +132,10 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { Err(Error::RNDR_NOT_AVAILABLE) } } + +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); +} diff --git a/src/backends/vxworks.rs b/src/backends/vxworks.rs index 51b7580ea..f03ab1844 100644 --- a/src/backends/vxworks.rs +++ b/src/backends/vxworks.rs @@ -42,3 +42,8 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), 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); +} diff --git a/src/backends/wasm_js.rs b/src/backends/wasm_js.rs index 8556f7680..c49436523 100644 --- a/src/backends/wasm_js.rs +++ b/src/backends/wasm_js.rs @@ -65,3 +65,8 @@ extern "C" { #[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); +} diff --git a/src/backends/windows.rs b/src/backends/windows.rs index 6c8e46b1a..764359437 100644 --- a/src/backends/windows.rs +++ b/src/backends/windows.rs @@ -40,3 +40,8 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { _ => Err(Error::WINDOWS_PROCESS_PRNG), } } + +impl Error { + /// Calling Windows ProcessPrng failed. + pub(crate) const WINDOWS_PROCESS_PRNG: Error = Self::new_internal(10); +} diff --git a/src/backends/windows7.rs b/src/backends/windows7.rs index 2546719eb..5b3c86c9c 100644 --- a/src/backends/windows7.rs +++ b/src/backends/windows7.rs @@ -37,3 +37,8 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { } 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); +} diff --git a/src/error.rs b/src/error.rs index 0c60f9294..7449fed3c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -27,26 +27,6 @@ impl Error { 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); - /// Call to [`CCRandomGenerateBytes`](https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html) failed - /// on iOS, tvOS, or waatchOS. - // TODO: Update this constant name in the next breaking release. - pub const IOS_SEC_RANDOM: Error = Self::new_internal(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 = Self::new_internal(4); - /// RDRAND instruction failed due to a hardware issue. - pub const FAILED_RDRAND: Error = Self::new_internal(5); - /// RDRAND instruction unsupported on this target. - pub const NO_RDRAND: Error = Self::new_internal(6); - /// The environment does not support the Web Crypto API. - pub const WEB_CRYPTO: Error = Self::new_internal(7); - /// On VxWorks, call to `randSecure` failed (random number generator is not yet initialized). - pub const VXWORKS_RAND_SECURE: Error = Self::new_internal(11); - /// Calling Windows ProcessPrng failed. - pub const WINDOWS_PROCESS_PRNG: Error = Self::new_internal(12); - /// RNDR register read failed due to a hardware issue. - pub const RNDR_FAILURE: Error = Self::new_internal(13); - /// RNDR register is not supported on this target. - pub const RNDR_NOT_AVAILABLE: Error = Self::new_internal(14); /// Codes below this point represent OS Errors (i.e. positive i32 values). /// Codes at or above this point, but below [`Error::CUSTOM_START`] are @@ -101,11 +81,52 @@ impl Error { } /// Creates a new instance of an `Error` from a particular internal error code. - const fn new_internal(n: u16) -> Error { + pub(crate) const fn new_internal(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) }) } + + 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, not(target_vendor = "win7")))] + Error::WINDOWS_PROCESS_PRNG => "ProcessPrng: Windows system function failure", + #[cfg(all(windows, target_vendor = "win7"))] + Error::WINDOWS_RTL_GEN_RANDOM => "RtlGenRandom: Windows system function failure", + #[cfg(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 { @@ -115,7 +136,7 @@ impl fmt::Debug for 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) = internal_desc(*self) { + } else if let Some(desc) = self.internal_desc() { dbg.field("internal_code", &self.0.get()); dbg.field("description", &desc); } else { @@ -135,7 +156,7 @@ impl fmt::Display for Error { write!(f, "OS Error: {}", errno) } } - } else if let Some(desc) = internal_desc(*self) { + } else if let Some(desc) = self.internal_desc() { f.write_str(desc) } else { write!(f, "Unknown Error: {}", self.0.get()) @@ -143,25 +164,6 @@ impl fmt::Display for Error { } } -fn internal_desc(error: Error) -> Option<&'static str> { - let desc = match error { - Error::UNSUPPORTED => "getrandom: this target is not supported", - Error::ERRNO_NOT_POSITIVE => "errno: did not return a positive value", - Error::UNEXPECTED => "unexpected situation", - Error::IOS_SEC_RANDOM => "SecRandomCopyBytes: iOS Security framework failure", - Error::WINDOWS_RTL_GEN_RANDOM => "RtlGenRandom: Windows system function failure", - Error::FAILED_RDRAND => "RDRAND: failed multiple times: CPU issue likely", - Error::NO_RDRAND => "RDRAND: instruction not supported", - Error::WEB_CRYPTO => "Web Crypto API is unavailable", - Error::VXWORKS_RAND_SECURE => "randSecure: VxWorks RNG module is not initialized", - Error::WINDOWS_PROCESS_PRNG => "ProcessPrng: Windows system function failure", - Error::RNDR_FAILURE => "RNDR: Could not generate a random number", - Error::RNDR_NOT_AVAILABLE => "RNDR: Register not supported", - _ => return None, - }; - Some(desc) -} - #[cfg(test)] mod tests { use super::Error; From 3425cf4565f051f8e24583ba4528179e67837fd2 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 12 Dec 2024 23:43:18 -0800 Subject: [PATCH 084/201] Use dep: style features for rustc-dep-of-std (#564) This prevents this crate from having features `compiler_builtins` and `core`. I didn't initially add this because it requires an MSRV of 1.60, but our MSRV is 1.63 now, so this is OK. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 05ff4b1b4..f3d3a7206 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,7 +75,7 @@ wasm-bindgen-test = "0.3" # use std to retrieve OS error descriptions std = [] # Unstable feature to support being a libstd dependency -rustc-dep-of-std = ["compiler_builtins", "core"] +rustc-dep-of-std = ["dep:compiler_builtins", "dep:core"] [lints.rust.unexpected_cfgs] level = "warn" From 12c9f809f59ca20c534b8759cd8632268674a2ad Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 17 Dec 2024 12:02:03 +0300 Subject: [PATCH 085/201] Remove explicit docsrs configuration flag from docs.rs metadata (#565) The flag is passed automatically for all docs.rs builds. See: https://github.com/rust-lang/docs.rs/pull/2390 --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f3d3a7206..e8c00a582 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,7 +88,6 @@ check-cfg = [ [package.metadata.docs.rs] features = ["std"] -rustdoc-args = ["--cfg", "docsrs"] # workaround for https://github.com/cross-rs/cross/issues/1345 [package.metadata.cross.target.x86_64-unknown-netbsd] From 9195c09493f259f1fa6d3aafa52218c1ab657771 Mon Sep 17 00:00:00 2001 From: usamoi Date: Wed, 18 Dec 2024 20:21:03 +0800 Subject: [PATCH 086/201] fix compilation on uefi (with std feature enabled) or i686 (#566) --- .github/workflows/build.yml | 1 + src/backends/rdrand.rs | 2 +- src/error.rs | 4 ++-- src/error_std_impls.rs | 5 +++++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cb7ffe34d..759f84143 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -173,6 +173,7 @@ jobs: target: [ x86_64-unknown-uefi, x86_64-unknown-l4re-uclibc, + i686-unknown-uefi, ] steps: - uses: actions/checkout@v4 diff --git a/src/backends/rdrand.rs b/src/backends/rdrand.rs index 67dc71296..347786a55 100644 --- a/src/backends/rdrand.rs +++ b/src/backends/rdrand.rs @@ -144,7 +144,7 @@ unsafe fn rdrand_u32() -> Option { unsafe fn rdrand_u64() -> Option { let a = rdrand()?; let b = rdrand()?; - Some((u64::from(a) << 32) || u64::from(b)) + Some((u64::from(a) << 32) | u64::from(b)) } pub fn inner_u32() -> Result { diff --git a/src/error.rs b/src/error.rs index 7449fed3c..125051eee 100644 --- a/src/error.rs +++ b/src/error.rs @@ -134,7 +134,7 @@ impl fmt::Debug for Error { let mut dbg = f.debug_struct("Error"); if let Some(errno) = self.raw_os_error() { dbg.field("os_error", &errno); - #[cfg(feature = "std")] + #[cfg(all(feature = "std", not(target_os = "uefi")))] 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()); @@ -150,7 +150,7 @@ 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")] { + if #[cfg(all(feature = "std", not(target_os = "uefi")))] { std::io::Error::from_raw_os_error(errno).fmt(f) } else { write!(f, "OS Error: {}", errno) diff --git a/src/error_std_impls.rs b/src/error_std_impls.rs index 2c326012c..569165e38 100644 --- a/src/error_std_impls.rs +++ b/src/error_std_impls.rs @@ -5,10 +5,15 @@ use std::io; impl From for io::Error { fn from(err: Error) -> Self { + #[cfg(not(target_os = "uefi"))] match err.raw_os_error() { Some(errno) => io::Error::from_raw_os_error(errno), None => io::Error::new(io::ErrorKind::Other, err), } + #[cfg(target_os = "uefi")] + { + io::Error::new(io::ErrorKind::Other, err) + } } } From e27f6ecc031eee76feb6d9a4522503f1923129c0 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 18 Dec 2024 15:39:11 +0300 Subject: [PATCH 087/201] ci: test UEFI with `std` (#567) Additionally disables build for `x86_64-unknown-l4re-uclibc` since its `std` is currently broken. --- .github/workflows/build.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 759f84143..4a251776f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -165,14 +165,13 @@ jobs: - name: Build run: cargo build --target ${{ matrix.target.target }} ${{ matrix.feature.feature }} -Zbuild-std=${{ matrix.feature.build-std }} - rdrand: - name: RDRAND + rdrand-uefi: + name: RDRAND UEFI runs-on: ubuntu-24.04 strategy: matrix: target: [ x86_64-unknown-uefi, - x86_64-unknown-l4re-uclibc, i686-unknown-uefi, ] steps: @@ -184,6 +183,9 @@ jobs: - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" run: cargo build -Z build-std=core --target=${{ matrix.target }} + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" + run: cargo build -Z build-std=std --target=${{ matrix.target }} --features std rndr: name: RNDR From dc89211bcac956025de0a4cf02da49ba29064ffa Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 19 Dec 2024 00:28:03 +0300 Subject: [PATCH 088/201] Allow `Error::raw_os_error` to return non-`i32` codes (#569) This allows us to remove some UEFI-specific exceptions from the code. This PR only partially resolves #568 since we still use `NonZeroU32` on UEFI targets, but it should be sufficient to future-proof ourselves for the v0.3 release. --- src/error.rs | 41 ++++++++++++++++++++++++++++------------- src/error_std_impls.rs | 5 ----- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/error.rs b/src/error.rs index 125051eee..4004af578 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,6 +3,16 @@ extern crate std; use core::{fmt, num::NonZeroU32}; +// 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")] { + type RawOsError = usize; + } else { + type RawOsError = i32; + } +); + /// A small and `no_std` compatible error type /// /// The [`Error::raw_os_error()`] will indicate if the error is from the OS, and @@ -57,20 +67,25 @@ impl Error { /// 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. + /// that it works in `no_std` contexts. On most targets this method returns + /// `Option`, 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 { - i32::try_from(self.0.get()).ok().map(|errno| { - // On SOLID, negate the error code again to obtain the original error code. - if cfg!(target_os = "solid_asp3") { - -errno - } else { - errno - } - }) + pub fn raw_os_error(self) -> Option { + let code = self.0.get(); + if code >= Self::INTERNAL_START { + return None; + } + let errno = RawOsError::try_from(code).ok()?; + #[cfg(target_os = "solid_asp3")] + let errno = -errno; + Some(errno) } /// Creates a new instance of an `Error` from a particular custom error code. @@ -134,7 +149,7 @@ impl fmt::Debug for Error { let mut dbg = f.debug_struct("Error"); if let Some(errno) = self.raw_os_error() { dbg.field("os_error", &errno); - #[cfg(all(feature = "std", not(target_os = "uefi")))] + #[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()); @@ -150,7 +165,7 @@ 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(all(feature = "std", not(target_os = "uefi")))] { + if #[cfg(feature = "std")] { std::io::Error::from_raw_os_error(errno).fmt(f) } else { write!(f, "OS Error: {}", errno) diff --git a/src/error_std_impls.rs b/src/error_std_impls.rs index 569165e38..2c326012c 100644 --- a/src/error_std_impls.rs +++ b/src/error_std_impls.rs @@ -5,15 +5,10 @@ use std::io; impl From for io::Error { fn from(err: Error) -> Self { - #[cfg(not(target_os = "uefi"))] match err.raw_os_error() { Some(errno) => io::Error::from_raw_os_error(errno), None => io::Error::new(io::ErrorKind::Other, err), } - #[cfg(target_os = "uefi")] - { - io::Error::new(io::ErrorKind::Other, err) - } } } From 9b902af17175fc5bc7ed4ee835376622691ae7f1 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Wed, 18 Dec 2024 14:36:13 -0800 Subject: [PATCH 089/201] Detect use of MemorySanitizer without using Nightly-only features (#571) This allows msan detection to "just-work" whenever someone passes `-Zsanitizer=memory`. Users no longer need to do any `getrandom`-specific configuration. This will also continue working once https://github.com/rust-lang/rust/issues/123615 is merged, which stabilizes some sanitizers (but not MemorySanitizer). This is the approch taken by other low-level crates: - [`parking_lot_core`](https://github.com/Amanieu/parking_lot/blob/ca920b31312839013b4455aba1d53a4aede21b2f/core/build.rs) - [`crossbeam-utils`](https://github.com/crossbeam-rs/crossbeam/blob/00283fb1818174c25b02d7f1c883c5e19f8506a4/crossbeam-utils/build.rs#L42) The only downside is that this adds a build-script, but it's as small as possible, doesn't seem to impact build times, and is only a temporary workaround. --------- Signed-off-by: Joe Richey --- .github/workflows/tests.yml | 6 +++--- CHANGELOG.md | 3 ++- Cargo.toml | 2 +- README.md | 13 ++++++------- build.rs | 9 +++++++++ src/lib.rs | 7 ++----- 6 files changed, 23 insertions(+), 17 deletions(-) create mode 100644 build.rs diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ae4910ea5..673fd3703 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -140,9 +140,9 @@ jobs: toolchain: nightly-2024-10-08 components: rust-src - env: - RUSTFLAGS: -Dwarnings -Zsanitizer=memory --cfg getrandom_sanitize - # `--all-targets` is used to skip doc tests which currently fail linking - run: cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu --all-targets + RUSTFLAGS: -Dwarnings -Zsanitizer=memory + RUSTDOCFLAGS: -Dwarnings -Zsanitizer=memory + run: cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu cross: name: Cross diff --git a/CHANGELOG.md b/CHANGELOG.md index 36cabb352..afdefce2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Error::new_custom` method [#507] - `rndr` opt-in backend [#512] - `linux_rustix` opt-in backend [#520] -- Memory sanitizer support gated behind `getrandom_sanitize` configuration flag [#521] +- Automatic MemorySanitizer support [#521] [#571] - `u32` and `u64` functions for generating random values of the respective type [#544] ### Fixed @@ -61,6 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#554]: https://github.com/rust-random/getrandom/pull/554 [#555]: https://github.com/rust-random/getrandom/pull/555 [#557]: https://github.com/rust-random/getrandom/pull/557 +[#571]: https://github.com/rust-random/getrandom/pull/571 ## [0.2.15] - 2024-05-06 ### Added diff --git a/Cargo.toml b/Cargo.toml index e8c00a582..57fe2274c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,7 +81,7 @@ rustc-dep-of-std = ["dep:compiler_builtins", "dep:core"] level = "warn" check-cfg = [ 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "linux_rustix", "wasm_js", "esp_idf"))', - 'cfg(getrandom_sanitize)', + 'cfg(getrandom_msan)', 'cfg(getrandom_test_linux_fallback)', 'cfg(getrandom_test_netbsd_fallback)', ] diff --git a/README.md b/README.md index ebd1b76aa..7ece9ecf2 100644 --- a/README.md +++ b/README.md @@ -267,15 +267,14 @@ our code should correctly handle it and return an error, e.g. ## Sanitizer support -If your code uses [`fill_uninit`] and you enable memory sanitization -(i.e. `-Zsanitizer=memory`), you need to pass the `getrandom_sanitize` -configuration flag to enable unpoisoning of the destination buffer -filled by `fill_uninit`. +If your code uses [`fill_uninit`] and you enable +[MemorySanitizer](https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html#memorysanitizer) +(i.e. `-Zsanitizer=memory`), we will automatically handle unpoisoning +of the destination buffer filled by `fill_uninit`. -For example, it can be done as follows (requires a Nightly compiler): +You can run sanitizer tests for your crate dependent on `getrandom` like this: ```sh -RUSTFLAGS="-Zsanitizer=memory --cfg getrandom_sanitize" \ - cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu +RUSTFLAGS="-Zsanitizer=memory" cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu ``` ## Minimum Supported Rust Version diff --git a/build.rs b/build.rs new file mode 100644 index 000000000..15d419191 --- /dev/null +++ b/build.rs @@ -0,0 +1,9 @@ +// Automatically detect cfg(sanitize = "memory") even if cfg(sanitize) isn't +// supported. Build scripts get cfg() info, even if the cfg is unstable. +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + let santizers = std::env::var("CARGO_CFG_SANITIZE").unwrap_or_default(); + if santizers.contains("memory") { + println!("cargo:rustc-cfg=getrandom_msan"); + } +} diff --git a/src/lib.rs b/src/lib.rs index 5b0f47fd8..2ac0ad0ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ #![doc = include_str!("../README.md")] #![warn(rust_2018_idioms, unused_lifetimes, missing_docs)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] -#![cfg_attr(getrandom_sanitize, feature(cfg_sanitize))] #![deny( clippy::cast_lossless, clippy::cast_possible_truncation, @@ -99,8 +98,7 @@ pub fn fill_uninit(dest: &mut [MaybeUninit]) -> Result<&mut [u8], Error> { backends::fill_inner(dest)?; } - #[cfg(getrandom_sanitize)] - #[cfg(sanitize = "memory")] + #[cfg(getrandom_msan)] extern "C" { fn __msan_unpoison(a: *mut core::ffi::c_void, size: usize); } @@ -108,8 +106,7 @@ pub fn fill_uninit(dest: &mut [MaybeUninit]) -> Result<&mut [u8], Error> { // SAFETY: `dest` has been fully initialized by `imp::fill_inner` // since it returned `Ok`. Ok(unsafe { - #[cfg(getrandom_sanitize)] - #[cfg(sanitize = "memory")] + #[cfg(getrandom_msan)] __msan_unpoison(dest.as_mut_ptr().cast(), dest.len()); util::slice_assume_init_mut(dest) From 5ac8d75fea096bdf43ae1385c5d6955834d097ab Mon Sep 17 00:00:00 2001 From: Luka Teras Date: Thu, 2 Jan 2025 21:33:21 -0300 Subject: [PATCH 090/201] Remove the link to PS Vita `getentropy` from the README (#576) Currently, PS Vita entry in the README links to the Emscripten issue tracker, likely by mistake. This pull request unlinks `getentropy` in the PS Vita entry. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7ece9ecf2..ce6f0f09e 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ fn get_random_u128() -> Result { | WASI 0.2 | `wasm32‑wasip2` | [`get-random-u64`] | SOLID | `*-kmc-solid_*` | `SOLID_RNG_SampleRandomBytes` | Nintendo 3DS | `*-nintendo-3ds` | [`getrandom`][18] -| PS Vita | `*-vita-*` | [`getentropy`][13] +| PS Vita | `*-vita-*` | `getentropy` | QNX Neutrino | `*‑nto-qnx*` | [`/dev/urandom`][14] (identical to `/dev/random`) | AIX | `*-ibm-aix` | [`/dev/urandom`][15] From d337f1ab0d0d551bdf05ab039a3fa82116dd6ffa Mon Sep 17 00:00:00 2001 From: Jose Quintana <1700322+joseluisq@users.noreply.github.com> Date: Fri, 3 Jan 2025 01:34:19 +0100 Subject: [PATCH 091/201] Fix broken link for NetBSD 9.2 base source used by cross workaround (#575) Recently NetBSD 9.2 source was archived affecting the `base.tar.xz` link used by the `libexecinfo.so` **cross** workaround (https://github.com/cross-rs/cross/issues/1345). This small patch prefers `NetBSD 9.3` as it is the latest `9.x`. - https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.2/amd64/binary/sets/base.tar.xz (broken) - https://archive.netbsd.org/pub/NetBSD-archive/NetBSD-9.2/amd64/binary/sets/base.tar.xz (archived) - https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.3/amd64/binary/sets/base.tar.xz (new) Additionally, I added a `-f, --fail` to curl to fail in case a `4xx` or greater happens again. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 57fe2274c..5d26c72f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,7 +93,7 @@ features = ["std"] [package.metadata.cross.target.x86_64-unknown-netbsd] pre-build = [ "mkdir -p /tmp/netbsd", - "curl https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.2/amd64/binary/sets/base.tar.xz -O", + "curl -fO https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.3/amd64/binary/sets/base.tar.xz", "tar -C /tmp/netbsd -xJf base.tar.xz", "cp /tmp/netbsd/usr/lib/libexecinfo.so /usr/local/x86_64-unknown-netbsd/lib", "rm base.tar.xz", From f39e8ea693673e09c348d848fce5a8321d1caca3 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 3 Jan 2025 03:54:35 +0300 Subject: [PATCH 092/201] Remove `linux_rustix` opt-in backend (#573) As suggested [here](https://github.com/rust-random/getrandom/pull/572#pullrequestreview-2521131415) it may be worth to remove `linux_rustix` from the v0.3.0 release. We probably will either return it in v0.3.1, or will introduce a different `linux_raw` opt-in backend (see #572). --- .github/workflows/build.yml | 3 --- .github/workflows/nopanic.yaml | 7 ------- .github/workflows/tests.yml | 3 --- .github/workflows/workspace.yml | 4 ---- CHANGELOG.md | 2 -- Cargo.toml | 8 ++------ README.md | 2 -- src/backends.rs | 3 --- src/backends/linux_rustix.rs | 32 -------------------------------- 9 files changed, 2 insertions(+), 62 deletions(-) delete mode 100644 src/backends/linux_rustix.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4a251776f..4dfc57032 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -121,9 +121,6 @@ jobs: - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo build --target=${{ matrix.target }} --features=std - - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" - run: cargo build --target=${{ matrix.target }} --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback run: cargo build --features=std diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index f9821a1db..5b5734a07 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -49,13 +49,6 @@ jobs: - name: Check (linux_android.rs) run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) - - name: Build (linux_rustix.rs) - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" - run: cargo build --release - - name: Check (linux_rustix.rs) - run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) - - name: Build (rdrand.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 673fd3703..2be4cf9a7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -56,9 +56,6 @@ jobs: - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo test --target=${{ matrix.target }} --features=std - - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" - run: cargo test --target=${{ matrix.target }} --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback run: cargo test --features=std diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 7f62034a1..f57b91c40 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -57,10 +57,6 @@ jobs: env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo clippy --target x86_64-unknown-linux-gnu - - name: Linux (linux_rustix.rs) - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" - run: cargo clippy --target x86_64-unknown-linux-gnu - name: Linux (linux_android_with_fallback.rs) run: cargo clippy --target x86_64-unknown-linux-gnu - name: NetBSD (netbsd.rs) diff --git a/CHANGELOG.md b/CHANGELOG.md index afdefce2a..c3765a23f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `getrandom_backend` configuration flag for selection of opt-in backends [#504] - `Error::new_custom` method [#507] - `rndr` opt-in backend [#512] -- `linux_rustix` opt-in backend [#520] - Automatic MemorySanitizer support [#521] [#571] - `u32` and `u64` functions for generating random values of the respective type [#544] @@ -52,7 +51,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#504]: https://github.com/rust-random/getrandom/pull/504 [#507]: https://github.com/rust-random/getrandom/pull/507 [#512]: https://github.com/rust-random/getrandom/pull/512 -[#520]: https://github.com/rust-random/getrandom/pull/520 [#521]: https://github.com/rust-random/getrandom/pull/521 [#522]: https://github.com/rust-random/getrandom/pull/522 [#532]: https://github.com/rust-random/getrandom/pull/532 diff --git a/Cargo.toml b/Cargo.toml index 5d26c72f6..15a95dc27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,13 +19,9 @@ compiler_builtins = { version = "0.1", optional = true } core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" } # linux_android / linux_android_with_fallback -[target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(target_env = "", getrandom_backend = "linux_rustix", getrandom_backend = "custom"))))'.dependencies] +[target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(target_env = "", getrandom_backend = "custom"))))'.dependencies] libc = { version = "0.2.154", default-features = false } -# linux_rustix -[target.'cfg(all(any(target_os = "linux", target_os = "android"), any(target_env = "", getrandom_backend = "linux_rustix")))'.dependencies] -rustix = { version = "0.38.38", default-features = false, features = ["rand"] } - # apple-other [target.'cfg(any(target_os = "ios", target_os = "visionos", target_os = "watchos", target_os = "tvos"))'.dependencies] libc = { version = "0.2.154", default-features = false } @@ -80,7 +76,7 @@ rustc-dep-of-std = ["dep:compiler_builtins", "dep:core"] [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "linux_rustix", "wasm_js", "esp_idf"))', + 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "wasm_js", "esp_idf"))', 'cfg(getrandom_msan)', 'cfg(getrandom_test_linux_fallback)', 'cfg(getrandom_test_netbsd_fallback)', diff --git a/README.md b/README.md index ce6f0f09e..e63869a06 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,6 @@ of randomness based on their specific needs: | Backend name | Target | Target Triple | Implementation | ----------------- | -------------------- | ------------------------ | -------------- | `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). -| `linux_rustix` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses [`rustix`] instead of `libc`. | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register | `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low-quality entropy without proper hardware configuration! @@ -346,7 +345,6 @@ dual licensed as above, without any additional terms or conditions. [platform-support]: https://doc.rust-lang.org/stable/rustc/platform-support.html [WASI]: https://github.com/CraneStation/wasi [Emscripten]: https://www.hellorust.com/setup/emscripten/ -[`rustix`]: https://docs.rs/rustix [//]: # (licenses) diff --git a/src/backends.rs b/src/backends.rs index f7b720f58..900911fb3 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -13,9 +13,6 @@ cfg_if! { } else if #[cfg(getrandom_backend = "linux_getrandom")] { mod linux_android; pub use linux_android::*; - } else if #[cfg(getrandom_backend = "linux_rustix")] { - mod linux_rustix; - pub use linux_rustix::*; } else if #[cfg(getrandom_backend = "rdrand")] { mod rdrand; pub use rdrand::*; diff --git a/src/backends/linux_rustix.rs b/src/backends/linux_rustix.rs deleted file mode 100644 index d3bcce3e5..000000000 --- a/src/backends/linux_rustix.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Implementation for Linux / Android without `/dev/urandom` fallback -use crate::{Error, MaybeUninit}; -use rustix::rand::{getrandom_uninit, GetRandomFlags}; - -pub use crate::util::{inner_u32, inner_u64}; - -#[cfg(not(any(target_os = "android", target_os = "linux")))] -compile_error!("`linux_rustix` backend can be enabled only for Linux/Android targets!"); - -pub fn fill_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { - loop { - let res = getrandom_uninit(dest, GetRandomFlags::empty()).map(|(res, _)| res.len()); - match res { - Ok(0) => return Err(Error::UNEXPECTED), - Ok(res_len) => { - dest = dest.get_mut(res_len..).ok_or(Error::UNEXPECTED)?; - if dest.is_empty() { - return Ok(()); - } - } - Err(rustix::io::Errno::INTR) => continue, - Err(err) => { - let code = err - .raw_os_error() - .wrapping_neg() - .try_into() - .map_err(|_| Error::UNEXPECTED)?; - return Err(Error::from_os_error(code)); - } - } - } -} From a9edccf72ce3a54c877c1240ea548628ab15403c Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 3 Jan 2025 05:21:15 +0300 Subject: [PATCH 093/201] ci: disable NetBSD VM test job (#578) The job fails after VM image update, see https://github.com/vmactions/netbsd-vm/issues/14 --- .github/workflows/tests.yml | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2be4cf9a7..d07470017 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -193,21 +193,23 @@ jobs: pkg_add rust run: cargo test - netbsd: - name: NetBSD VM - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v4 - - name: Test in NetBSD - uses: vmactions/netbsd-vm@v1 - with: - envs: 'RUSTFLAGS' - usesh: true - prepare: | - /usr/sbin/pkg_add rust - run: | - cargo test - RUSTFLAGS="--cfg getrandom_test_netbsd_fallback -D warnings" cargo test + # Rust installation currently fails: + # https://github.com/rust-random/getrandom/actions/runs/12590976993/job/35093395247 + # netbsd: + # name: NetBSD VM + # runs-on: ubuntu-24.04 + # steps: + # - uses: actions/checkout@v4 + # - name: Test in NetBSD + # uses: vmactions/netbsd-vm@v1 + # with: + # envs: 'RUSTFLAGS' + # usesh: true + # prepare: | + # /usr/sbin/pkg_add rust + # run: | + # cargo test + # RUSTFLAGS="--cfg getrandom_test_netbsd_fallback -D warnings" cargo test # This job currently fails: # https://github.com/rust-random/getrandom/actions/runs/11405005618/job/31735653874?pr=528 From 9fb4a9a2481018e4ab58d597ecd167a609033149 Mon Sep 17 00:00:00 2001 From: Luka Teras Date: Thu, 2 Jan 2025 23:28:44 -0300 Subject: [PATCH 094/201] Add a link to PS Vita `getentropy` to the README (#577) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e63869a06..f34890900 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ fn get_random_u128() -> Result { | WASI 0.2 | `wasm32‑wasip2` | [`get-random-u64`] | SOLID | `*-kmc-solid_*` | `SOLID_RNG_SampleRandomBytes` | Nintendo 3DS | `*-nintendo-3ds` | [`getrandom`][18] -| PS Vita | `*-vita-*` | `getentropy` +| PS Vita | `*-vita-*` | [`getentropy`][19] | QNX Neutrino | `*‑nto-qnx*` | [`/dev/urandom`][14] (identical to `/dev/random`) | AIX | `*-ibm-aix` | [`/dev/urandom`][15] @@ -326,6 +326,7 @@ dual licensed as above, without any additional terms or conditions. [16]: https://man.netbsd.org/getrandom.2 [17]: https://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getrandom [18]: https://github.com/rust3ds/shim-3ds/commit/b01d2568836dea2a65d05d662f8e5f805c64389d +[19]: https://github.com/vitasdk/newlib/blob/2d869fe47aaf02b8e52d04e9a2b79d5b210fd016/newlib/libc/sys/vita/getentropy.c [`ProcessPrng`]: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng [`RtlGenRandom`]: https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom From 9f20e28392a32def691f692badf4fd31e6570d0f Mon Sep 17 00:00:00 2001 From: silverstillisntgold Date: Sun, 12 Jan 2025 04:39:18 -0500 Subject: [PATCH 095/201] Remove unnecessary error branch of ProcessPrng (#579) ProcessPrng is guaranteed to never fail during runtime, so there's no need to handle that case. Also found that windows_targets declares all extern functions as pub, so wrapped the link! macro in a local module to prevent it from being accessible outside of windows.rs. --- src/backends/windows.rs | 29 ++++++++++++++--------------- src/error.rs | 2 -- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/backends/windows.rs b/src/backends/windows.rs index 764359437..e6e12e185 100644 --- a/src/backends/windows.rs +++ b/src/backends/windows.rs @@ -1,7 +1,7 @@ //! Implementation for Windows 10 and later //! //! On Windows 10 and later, ProcessPrng "is the primary interface to the -//! user-mode per-processer PRNGs" and only requires bcryptprimitives.dll, +//! 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) @@ -28,20 +28,19 @@ 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 the windows-targets // crate to link to it. -windows_targets::link!("bcryptprimitives.dll" "system" fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL); -#[allow(clippy::upper_case_acronyms)] -pub type BOOL = i32; -pub const TRUE: BOOL = 1i32; +// +// TODO(MSRV 1.71): Migrate to linking as raw-dylib directly. +// https://github.com/joboet/rust/blob/5c1c72572479afe98734d5f78fa862abe662c41a/library/std/src/sys/pal/windows/c.rs#L119 +// https://github.com/microsoft/windows-rs/blob/0.60.0/crates/libs/targets/src/lib.rs +windows_targets::link!("bcryptprimitives.dll" "system" fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> i32); pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - // ProcessPrng should always return TRUE, but we check just in case. - match unsafe { ProcessPrng(dest.as_mut_ptr().cast::(), dest.len()) } { - TRUE => Ok(()), - _ => Err(Error::WINDOWS_PROCESS_PRNG), - } -} - -impl Error { - /// Calling Windows ProcessPrng failed. - pub(crate) const WINDOWS_PROCESS_PRNG: Error = Self::new_internal(10); + let result = unsafe { ProcessPrng(dest.as_mut_ptr().cast::(), 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 == 1); + Ok(()) } diff --git a/src/error.rs b/src/error.rs index 4004af578..e82b5e3a5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -114,8 +114,6 @@ impl Error { target_os = "tvos", ))] Error::IOS_RANDOM_GEN => "SecRandomCopyBytes: iOS Security framework failure", - #[cfg(all(windows, not(target_vendor = "win7")))] - Error::WINDOWS_PROCESS_PRNG => "ProcessPrng: Windows system function failure", #[cfg(all(windows, target_vendor = "win7"))] Error::WINDOWS_RTL_GEN_RANDOM => "RtlGenRandom: Windows system function failure", #[cfg(getrandom_backend = "wasm_js")] From 2648e60c5d27979f45043e379b1af7bee5e300a9 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 13 Jan 2025 06:43:54 -0800 Subject: [PATCH 096/201] ESP-IDF: Enable unconditionally (#583) After reviewing the updated ESP-IDF random documentation: - https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/random.html - https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf#rng Given that ESP-IDF provides binding of `getrandom`/`getentropy` to `esp_fill_random`, it's clear they intend for cryptographic libraries (such as their fork of WolfSSL) to use them. Furthermore, it seems like the only time the Hardware RNG would lack sufficient entropy is during early boot, so I added a section to our "Early boot" documentation noting this issue. Also note that Rust's standard library unconditionally supports ESP-IDF for both hash seed generation and generating cryptographic random bytes, see https://github.com/rust-lang/rust/blob/62bf38fa600f4beb878d61c537837729d4ee689e/library/std/src/sys/random/espidf.rs#L7 I don't think there's a good reason to deviate from the standard library here. --- .github/workflows/build.yml | 14 +------------- Cargo.toml | 2 +- README.md | 13 +++++++++++-- src/backends.rs | 2 +- src/backends/esp_idf.rs | 3 --- 5 files changed, 14 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4dfc57032..83a4d72ee 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -86,6 +86,7 @@ jobs: armv6k-nintendo-3ds, armv7-sony-vita-newlibeabihf, i686-unknown-hurd-gnu, + riscv32imc-esp-espidf, x86_64-unknown-hermit, x86_64-wrs-vxworks, x86_64-unknown-dragonfly, @@ -207,19 +208,6 @@ jobs: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" run: cargo build --target=aarch64-unknown-linux-gnu --features std - esp-idf: - name: ESP-IDF - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly # Required to build libcore - with: - components: rust-src - - uses: Swatinem/rust-cache@v2 - - env: - RUSTFLAGS: -Dwarnings --cfg getrandom_backend="esp_idf" - run: cargo build -Z build-std=core --target=riscv32imc-esp-espidf - no-atomics: name: No Atomics runs-on: ubuntu-24.04 diff --git a/Cargo.toml b/Cargo.toml index 15a95dc27..45b17780e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,7 +76,7 @@ rustc-dep-of-std = ["dep:compiler_builtins", "dep:core"] [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "wasm_js", "esp_idf"))', + 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "wasm_js"))', 'cfg(getrandom_msan)', 'cfg(getrandom_test_linux_fallback)', 'cfg(getrandom_test_netbsd_fallback)', diff --git a/README.md b/README.md index f34890900..ea3b8b01a 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ fn get_random_u128() -> Result { | WASI 0.2 | `wasm32‑wasip2` | [`get-random-u64`] | SOLID | `*-kmc-solid_*` | `SOLID_RNG_SampleRandomBytes` | Nintendo 3DS | `*-nintendo-3ds` | [`getrandom`][18] +| ESP-IDF | `*‑espidf` | [`esp_fill_random`] WARNING: see "Early Boot" section below | PS Vita | `*-vita-*` | [`getentropy`][19] | QNX Neutrino | `*‑nto-qnx*` | [`/dev/urandom`][14] (identical to `/dev/random`) | AIX | `*-ibm-aix` | [`/dev/urandom`][15] @@ -81,7 +82,6 @@ of randomness based on their specific needs: | `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register -| `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low-quality entropy without proper hardware configuration! | `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown`, `wasm32v1-none` | [`Crypto.getRandomValues`] | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) @@ -247,6 +247,13 @@ sourced according to the platform's best practices, but each platform has its own limits on the grade of randomness it can promise in environments with few sources of entropy. +On ESP-IDF, if `esp_fill_random` is used before enabling WiFi, BT, or the +voltage noise entropy source (SAR ADC), the Hardware RNG will only be seeded +via RC_FAST_CLK. This can occur during early boot unless +`bootloader_random_enable()` is called. For more information see the +[ESP-IDF RNG Docs][esp-idf-rng] or the +[RNG section of the ESP32 Technical Reference Manual][esp-trng-docs]. + ## Error handling We always prioritize failure over returning known insecure "random" bytes. @@ -335,7 +342,9 @@ dual licensed as above, without any additional terms or conditions. [`RNDR`]: https://developer.arm.com/documentation/ddi0601/2024-06/AArch64-Registers/RNDR--Random-Number [`CCRandomGenerateBytes`]: https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html [`cprng_draw`]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw -[`esp_fill_random`]: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html#_CPPv415esp_fill_randomPv6size_t +[`esp_fill_random`]: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/random.html#functions +[esp-idf-rng]: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/random.html +[esp-trng-docs]: https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf#rng [`random_get`]: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-buf_len-size---errno [`get-random-u64`]: https://github.com/WebAssembly/WASI/blob/v0.2.1/wasip2/random/random.wit#L23-L28 [configuration flags]: #configuration-flags diff --git a/src/backends.rs b/src/backends.rs index 900911fb3..921b7779b 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -22,7 +22,7 @@ cfg_if! { } else if #[cfg(getrandom_backend = "wasm_js")] { mod wasm_js; pub use wasm_js::*; - } else if #[cfg(getrandom_backend = "esp_idf")] { + } else if #[cfg(target_os = "espidf")] { mod esp_idf; pub use esp_idf::*; } else if #[cfg(any( diff --git a/src/backends/esp_idf.rs b/src/backends/esp_idf.rs index 0f0ff7f49..7ee391ab1 100644 --- a/src/backends/esp_idf.rs +++ b/src/backends/esp_idf.rs @@ -4,9 +4,6 @@ use core::{ffi::c_void, mem::MaybeUninit}; pub use crate::util::{inner_u32, inner_u64}; -#[cfg(not(target_os = "espidf"))] -compile_error!("`esp_idf` backend can be enabled only for ESP-IDF targets!"); - extern "C" { fn esp_fill_random(buf: *mut c_void, len: usize) -> u32; } From 6be40128a7c19bac658c6e85e808a6b5eadfd6b2 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Tue, 14 Jan 2025 11:10:21 +0100 Subject: [PATCH 097/201] Web: use safe method to copy to `MaybeUninit` (#584) This removes the last `unsafe` call in the Web implementation. See [`Uint8Array::copy_to_uninit`](https://docs.rs/js-sys/0.3.77/js_sys/struct.Uint8Array.html#method.copy_to_uninit). --- Cargo.toml | 2 +- src/backends/wasm_js.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 45b17780e..de8866a64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,7 @@ windows-targets = "0.52" [target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dependencies] wasm-bindgen = { version = "0.2.98", default-features = false } [target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none"), target_feature = "atomics"))'.dependencies] -js-sys = { version = "0.3.75", default-features = false } +js-sys = { version = "0.3.77", default-features = false } [target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dev-dependencies] wasm-bindgen-test = "0.3" diff --git a/src/backends/wasm_js.rs b/src/backends/wasm_js.rs index c49436523..fe8f1a6ed 100644 --- a/src/backends/wasm_js.rs +++ b/src/backends/wasm_js.rs @@ -49,8 +49,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { return Err(Error::WEB_CRYPTO); } - // SAFETY: `sub_buf`'s length is the same length as `chunk` - unsafe { sub_buf.raw_copy_to_ptr(chunk.as_mut_ptr().cast::()) }; + sub_buf.copy_to_uninit(chunk); } Ok(()) } From 7cde98b9770eaefe1bcf6194f7ac55ce28d9b53e Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 24 Jan 2025 12:03:27 +0000 Subject: [PATCH 098/201] Add `wasm_js` feature flag (#574) --- .github/workflows/build.yml | 4 ++-- .github/workflows/tests.yml | 6 +++--- .github/workflows/workspace.yml | 4 ++-- Cargo.toml | 29 +++++++++++++++++------------ README.md | 25 +++++++++++++------------ src/backends.rs | 32 +++++++++++++++++++++----------- src/error.rs | 2 +- tests/mod.rs | 6 +----- 8 files changed, 60 insertions(+), 48 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 83a4d72ee..707ac3625 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -142,8 +142,8 @@ jobs: { description: WasmV1, target: wasm32v1-none }, ] feature: [ - { description: no_std, feature: "", build-std: "core,alloc", std: false }, - { feature: --features std, build-std: "panic_abort,std", std: true }, + { description: no_std, feature: "--features wasm_js", build-std: "core,alloc", std: false }, + { feature: "--features wasm_js,std", build-std: "panic_abort,std", std: true }, ] atomic: [ { flags: "" }, diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d07470017..28b91ab93 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -237,15 +237,15 @@ jobs: - { description: Web, version: stable, - flags: -Dwarnings --cfg getrandom_backend="wasm_js", - args: --features=std, + flags: '-Dwarnings --cfg getrandom_backend="wasm_js"', + args: '--features=std,wasm_js', } - { description: Web with Atomics, version: nightly, components: rust-src, flags: '-Dwarnings --cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory', - args: '--features=std -Zbuild-std=panic_abort,std', + args: '--features=std,wasm_js -Zbuild-std=panic_abort,std', } steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index f57b91c40..14b37dd9b 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -48,11 +48,11 @@ jobs: - name: Web WASM (wasm_js.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" - run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown + run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown --features wasm_js - name: Web WASM with atomics (wasm_js.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory - run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown + run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown --features wasm_js - name: Linux (linux_android.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" diff --git a/Cargo.toml b/Cargo.toml index de8866a64..8e6d0e6af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,18 @@ repository = "https://github.com/rust-random/getrandom" categories = ["os", "no-std"] exclude = [".*"] +[features] +# Implement std::error::Error for getrandom::Error and +# use std to retrieve OS error descriptions +std = [] +# Unstable feature to support being a libstd dependency +rustc-dep-of-std = ["dep:compiler_builtins", "dep:core"] + +# Optional backend: wasm_js +# This flag enables the backend but does not select it. To use the backend, use +# this flag *and* set getrandom_backend=wasm_js (see README). +wasm_js = ["dep:wasm-bindgen", "dep:js-sys"] + [dependencies] cfg-if = "1" @@ -59,20 +71,13 @@ wasi = { version = "0.13", default-features = false } windows-targets = "0.52" # wasm_js -[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dependencies] -wasm-bindgen = { version = "0.2.98", default-features = false } -[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none"), target_feature = "atomics"))'.dependencies] -js-sys = { version = "0.3.77", default-features = false } -[target.'cfg(all(getrandom_backend = "wasm_js", target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dev-dependencies] +[target.'cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dependencies] +wasm-bindgen = { version = "0.2.98", default-features = false, optional = true } +[target.'cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"), target_feature = "atomics"))'.dependencies] +js-sys = { version = "0.3.77", default-features = false, optional = true } +[target.'cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dev-dependencies] wasm-bindgen-test = "0.3" -[features] -# Implement std::error::Error for getrandom::Error and -# use std to retrieve OS error descriptions -std = [] -# Unstable feature to support being a libstd dependency -rustc-dep-of-std = ["dep:compiler_builtins", "dep:core"] - [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ diff --git a/README.md b/README.md index ea3b8b01a..0007634c9 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ of randomness based on their specific needs: | `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register -| `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown`, `wasm32v1-none` | [`Crypto.getRandomValues`] +| `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown`, `wasm32v1-none` | [`Crypto.getRandomValues`]. Requires feature `wasm_js` ([see below](#webassembly-support)). | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) Opt-in backends can be enabled using the `getrandom_backend` configuration flag. @@ -112,18 +112,19 @@ 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 should be used (or if JavaScript is available at all). -Instead, *if the `wasm_js` backend is enabled*, this crate will assume -that you are building for an environment containing JavaScript, and will -call the appropriate Web Crypto methods [described above](#opt-in-backends) using -the [`wasm-bindgen`] toolchain. Both web browser (main window and Web Workers) -and Node.js (v19 or later) environments are supported. +To enable `getrandom`'s functionality on `wasm32-unknown-unknown` using the Web +Crypto methods [described above](#opt-in-backends) via [`wasm-bindgen`], do +*both* of the following: -To enable the `wasm_js` backend, you can add the following lines to your -project's `.cargo/config.toml` file: -```toml -[target.wasm32-unknown-unknown] -rustflags = ['--cfg', 'getrandom_backend="wasm_js"'] -``` +- Use the `wasm_js` feature flag, i.e. + `getrandom = { version = "0.3", features = ["wasm_js"] }`. + On its own, this only makes the backend available. (As a side effect this + will make your `Cargo.lock` significantly larger if you are not already + using [`wasm-bindgen`], but otherwise enabling this feature is harmless.) +- Set `RUSTFLAGS='--cfg getrandom_backend="wasm_js"'` ([see above](#opt-in-backends)). + +This backend supports both web browsers (main window and Web Workers) +and Node.js (v19 or later) environments. ### Custom backend diff --git a/src/backends.rs b/src/backends.rs index 921b7779b..1509af115 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -19,9 +19,19 @@ cfg_if! { } else if #[cfg(getrandom_backend = "rndr")] { mod rndr; pub use rndr::*; - } else if #[cfg(getrandom_backend = "wasm_js")] { - mod wasm_js; - pub use wasm_js::*; + } 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!( + "The \"wasm_js\" backend requires the `wasm_js` feature \ + for `getrandom`. For more information see: \ + https://docs.rs/getrandom/#webassembly-support" + ); + } + } } else if #[cfg(target_os = "espidf")] { mod esp_idf; pub use esp_idf::*; @@ -145,14 +155,14 @@ cfg_if! { } 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!("the wasm32-unknown-unknown targets are not supported \ - by default, you may need to enable the \"wasm_js\" \ - configuration flag. For more information see: \ - https://docs.rs/getrandom/#webassembly-support"); + } else if #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))] { + compile_error!( + "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/#webassembly-support" + ); } else { compile_error!("target is not supported. You may need to define \ a custom backend see: \ diff --git a/src/error.rs b/src/error.rs index e82b5e3a5..ccbe78373 100644 --- a/src/error.rs +++ b/src/error.rs @@ -116,7 +116,7 @@ impl Error { 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(getrandom_backend = "wasm_js")] + #[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", diff --git a/tests/mod.rs b/tests/mod.rs index c972e768b..9f1e63387 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -1,11 +1,7 @@ use core::mem::MaybeUninit; use getrandom::{fill, fill_uninit}; -#[cfg(all( - getrandom_backend = "wasm_js", - target_arch = "wasm32", - target_os = "unknown" -))] +#[cfg(all(feature = "wasm_js", target_arch = "wasm32", target_os = "unknown"))] use wasm_bindgen_test::wasm_bindgen_test as test; #[test] From 3d0c01c35231b40f58b49f4455797c85c2e8c042 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 24 Jan 2025 15:25:39 +0300 Subject: [PATCH 099/201] ci: disable broken Solaris and Emscripten cross jobs (#585) --- .github/workflows/build.yml | 4 +++- .github/workflows/tests.yml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 707ac3625..34e50985c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,7 +42,9 @@ jobs: strategy: matrix: target: [ - sparcv9-sun-solaris, + # This target is currently broken: + # https://github.com/rust-random/getrandom/actions/runs/12949235456/job/36119544880 + # sparcv9-sun-solaris, x86_64-unknown-illumos, ] steps: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 28b91ab93..f28ef7791 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -152,7 +152,9 @@ jobs: # See: https://github.com/cross-rs/cross/issues/1222 # aarch64-linux-android, powerpc-unknown-linux-gnu, - wasm32-unknown-emscripten, + # This target is currently broken: + # https://github.com/rust-random/getrandom/actions/runs/12949235459/job/36119546920 + #wasm32-unknown-emscripten, ] steps: - uses: actions/checkout@v4 From 5e62ce9fadb401539a08b329e4cbd98cc6393f60 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 24 Jan 2025 15:40:57 +0300 Subject: [PATCH 100/201] rndr: minor tweaks (#586) The most notable change is that `is_aarch64_feature_detected!` now takes precedence over `asm!`-based detection. --- src/backends/rndr.rs | 53 ++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/backends/rndr.rs b/src/backends/rndr.rs index 7db903555..fa24a0972 100644 --- a/src/backends/rndr.rs +++ b/src/backends/rndr.rs @@ -60,10 +60,21 @@ unsafe fn rndr_fill(dest: &mut [MaybeUninit]) -> Option<()> { 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(target_feature = "rand")] { - true + 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 /// @@ -87,14 +98,7 @@ fn is_rndr_available() -> bool { (id_aa64isar0 >> 60) & 0xf >= 1 } - #[path = "../lazy.rs"] mod lazy; - static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new(); RNDR_GOOD.unsync_init(mrs_check) - } else if #[cfg(feature = "std")] { - extern crate std; - #[path = "../lazy.rs"] mod lazy; - static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new(); - RNDR_GOOD.unsync_init(|| std::arch::is_aarch64_feature_detected!("rand")) } else { compile_error!( "RNDR `no_std` runtime detection is currently supported only on Linux targets. \ @@ -105,32 +109,29 @@ fn is_rndr_available() -> bool { } pub fn inner_u32() -> Result { - if is_rndr_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) - } else { - Err(Error::RNDR_NOT_AVAILABLE) + 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) } pub fn inner_u64() -> Result { - if is_rndr_available() { - // SAFETY: after this point, we know the `rand` target feature is enabled - let res = unsafe { rndr() }; - res.ok_or(Error::RNDR_FAILURE) - } else { - Err(Error::RNDR_NOT_AVAILABLE) + 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) } pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - if is_rndr_available() { - // SAFETY: after this point, we know the `rand` target feature is enabled - unsafe { rndr_fill(dest).ok_or(Error::RNDR_FAILURE) } - } else { - Err(Error::RNDR_NOT_AVAILABLE) + 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 { From d5683740ef9cd2d0ebfed73f2a629c0ebb47b5e8 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sat, 25 Jan 2025 04:30:15 +0300 Subject: [PATCH 101/201] Release v0.3.0 (#563) Close #433 TODO: update release date before merge --- CHANGELOG.md | 19 ++++++++++++++----- Cargo.toml | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3765a23f..0237b0d8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.3.0] - 2024-12-16 ### Breaking Changes @@ -19,17 +19,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `register_custom_getrandom!` macro [#504] - Implementation of `From` for `Error` and `Error::code` method [#507] - Internet Explorer 11 support [#554] +- Target-specific assocciated `Error` constants [#562] ### Changed -- Use `ProcessPrng` on Windows 10 and up, and use RtlGenRandom on older legacy Windows versions [#415] +- Use `ProcessPrng` on Windows 10 and up, and use `RtlGenRandom` on older Windows versions [#415] - Do not use locale-specific `strerror_r` for retrieving error code descriptions [#440] -- Avoid assuming usize is the native word size in the `rdrand` backend [#442] +- Avoid assuming `usize` is the native word size in the `rdrand` backend [#442] - Do not read from `errno` when `libc` did not indicate error on Solaris [#448] - Switch from `libpthread`'s mutex to `futex` on Linux and to `nanosleep`-based wait loop on other targets in the `use_file` backend [#490] - Do not retry on `EAGAIN` while polling `/dev/random` on Linux [#522] -- Remove separate codepath for Node.js in the `wasm_js` backend (bumps minimum supported Node.js - version to v19) [#557] +- Remove separate codepath for Node.js in the `wasm_js` backend + (bumps minimum supported Node.js version to v19) [#557] +- Use `js_namespace` in the `wasm_js` backend [#559] ### Added - `wasm32-wasip1` and `wasm32-wasip2` support [#499] @@ -38,6 +40,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `rndr` opt-in backend [#512] - Automatic MemorySanitizer support [#521] [#571] - `u32` and `u64` functions for generating random values of the respective type [#544] +- `wasm32v1-none` support in the `wasm_js` backend [#560] +- `wasm_js` crate feature which allows users to enable the `wasm_js` opt-in backend [#574] ### Fixed - NetBSD fallback code based on `KERN_ARND` [#555] @@ -59,7 +63,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#554]: https://github.com/rust-random/getrandom/pull/554 [#555]: https://github.com/rust-random/getrandom/pull/555 [#557]: https://github.com/rust-random/getrandom/pull/557 +[#559]: https://github.com/rust-random/getrandom/pull/559 +[#560]: https://github.com/rust-random/getrandom/pull/560 +[#562]: https://github.com/rust-random/getrandom/pull/562 [#571]: https://github.com/rust-random/getrandom/pull/571 +[#574]: https://github.com/rust-random/getrandom/pull/574 ## [0.2.15] - 2024-05-06 ### Added @@ -511,6 +519,7 @@ Publish initial implementation. ## [0.0.0] - 2019-01-19 Publish an empty template library. +[0.3.0]: https://github.com/rust-random/getrandom/compare/v0.2.15...v0.3.0 [0.2.15]: https://github.com/rust-random/getrandom/compare/v0.2.14...v0.2.15 [0.2.14]: https://github.com/rust-random/getrandom/compare/v0.2.13...v0.2.14 [0.2.13]: https://github.com/rust-random/getrandom/compare/v0.2.12...v0.2.13 diff --git a/Cargo.toml b/Cargo.toml index 8e6d0e6af..9d130e327 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "getrandom" -version = "0.3.0-rc.0" +version = "0.3.0" edition = "2021" rust-version = "1.63" # Sync tests.yml and README.md. authors = ["The Rand Project Developers"] From e38855c69882c2c1ff7438f9292512a0b91275fe Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sat, 25 Jan 2025 14:22:07 +0300 Subject: [PATCH 102/201] Fix release date for v0.3.0 (#587) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0237b0d8d..d094d1b77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.3.0] - 2024-12-16 +## [0.3.0] - 2025-01-25 ### Breaking Changes From aa9636349418ffa58bca6e2884d1bbc63fa1d2fa Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Sat, 25 Jan 2025 03:28:07 -0800 Subject: [PATCH 103/201] Add benchmarks for u32/u64 functions. (#582) This allows us to see the effect of any specicalized implementations for `getrandom::u32` or `getrandom::u64`. As expected, on Linux (which just uses the default implementation in `utils.rs`) there is no change: ``` test bench_u32 ... bench: 196.50 ns/iter (+/- 4.85) = 20 MB/s test bench_u32_via_fill ... bench: 198.25 ns/iter (+/- 1.78) = 20 MB/s test bench_u64 ... bench: 196.95 ns/iter (+/- 2.99) = 40 MB/s test bench_u64_via_fill ... bench: 197.62 ns/iter (+/- 2.24) = 40 MB/s ``` but when using the `rdrand` backend (which is specialized), there is a mesurable difference. ``` test bench_u32 ... bench: 16.84 ns/iter (+/- 0.09) = 250 MB/s test bench_u32_via_fill ... bench: 18.40 ns/iter (+/- 0.28) = 222 MB/s test bench_u64 ... bench: 16.62 ns/iter (+/- 0.06) = 500 MB/s test bench_u64_via_fill ... bench: 17.70 ns/iter (+/- 0.08) = 470 MB/s ``` --- benches/buffer.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/benches/buffer.rs b/benches/buffer.rs index 2899a3f75..0063a453a 100644 --- a/benches/buffer.rs +++ b/benches/buffer.rs @@ -1,7 +1,10 @@ #![feature(test, maybe_uninit_uninit_array_transpose)] extern crate test; -use std::mem::MaybeUninit; +use std::{ + mem::{size_of, MaybeUninit}, + slice, +}; // Call getrandom on a zero-initialized stack buffer #[inline(always)] @@ -19,6 +22,53 @@ fn bench_fill_uninit() { test::black_box(buf); } +#[bench] +pub fn bench_u32(b: &mut test::Bencher) { + #[inline(never)] + fn inner() -> u32 { + getrandom::u32().unwrap() + } + b.bytes = 4; + b.iter(inner); +} +#[bench] +pub fn bench_u32_via_fill(b: &mut test::Bencher) { + #[inline(never)] + fn inner() -> u32 { + let mut res = MaybeUninit::::uninit(); + let dst: &mut [MaybeUninit] = + unsafe { slice::from_raw_parts_mut(res.as_mut_ptr().cast(), size_of::()) }; + getrandom::fill_uninit(dst).unwrap(); + unsafe { res.assume_init() } + } + b.bytes = 4; + b.iter(inner); +} + +#[bench] +pub fn bench_u64(b: &mut test::Bencher) { + #[inline(never)] + fn inner() -> u64 { + getrandom::u64().unwrap() + } + b.bytes = 8; + b.iter(inner); +} + +#[bench] +pub fn bench_u64_via_fill(b: &mut test::Bencher) { + #[inline(never)] + fn inner() -> u64 { + let mut res = MaybeUninit::::uninit(); + let dst: &mut [MaybeUninit] = + unsafe { slice::from_raw_parts_mut(res.as_mut_ptr().cast(), size_of::()) }; + getrandom::fill_uninit(dst).unwrap(); + unsafe { res.assume_init() } + } + b.bytes = 8; + b.iter(inner); +} + // We benchmark using #[inline(never)] "inner" functions for two reasons: // - Avoiding inlining reduces a source of variance when running benchmarks. // - It is _much_ easier to get the assembly or IR for the inner loop. From ac379dacbfbcbcc14747a0e014d84d6f24c8140b Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 28 Jan 2025 04:10:59 +0900 Subject: [PATCH 104/201] Fix build error on Android (#588) --- .github/workflows/build.yml | 1 + .github/workflows/tests.yml | 3 +++ Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 34e50985c..204da8074 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,6 +64,7 @@ jobs: strategy: matrix: target: [ + aarch64-linux-android, x86_64-unknown-fuchsia, x86_64-unknown-redox, x86_64-fortanix-unknown-sgx, diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f28ef7791..4ba01e80b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -55,12 +55,15 @@ jobs: - run: cargo test --target=${{ matrix.target }} --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" + RUSTDOCFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo test --target=${{ matrix.target }} --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback + RUSTDOCFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback run: cargo test --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" + RUSTDOCFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" run: cargo test --features=std ios: diff --git a/Cargo.toml b/Cargo.toml index 9d130e327..f2785eb83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ compiler_builtins = { version = "0.1", optional = true } core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" } # linux_android / linux_android_with_fallback -[target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(target_env = "", getrandom_backend = "custom"))))'.dependencies] +[target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(getrandom_backend = "custom", getrandom_backend = "rdrand", getrandom_backend = "rndr"))))'.dependencies] libc = { version = "0.2.154", default-features = false } # apple-other From 2bb39598632af0097426815487f5b33b07edacbc Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 28 Jan 2025 04:14:18 +0300 Subject: [PATCH 105/201] Release v0.3.1 (#589) ### Fixed - Build error on Android [#588] [#588]: https://github.com/rust-random/getrandom/pull/588 --- CHANGELOG.md | 7 +++++++ Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d094d1b77..96dba8236 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.1] - 2025-01-28 + +### Fixed +- Build error on Android [#588] + +[#588]: https://github.com/rust-random/getrandom/pull/588 + ## [0.3.0] - 2025-01-25 ### Breaking Changes diff --git a/Cargo.toml b/Cargo.toml index f2785eb83..bf7e06dfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "getrandom" -version = "0.3.0" +version = "0.3.1" edition = "2021" rust-version = "1.63" # Sync tests.yml and README.md. authors = ["The Rand Project Developers"] From f6ddd517a1a6c6d6d8ec473d905848310f05c6d4 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 28 Jan 2025 18:50:40 +0300 Subject: [PATCH 106/201] Add .cargo/config.toml example (#591) --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0007634c9..a3f2dce08 100644 --- a/README.md +++ b/README.md @@ -86,9 +86,14 @@ of randomness based on their specific needs: | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) Opt-in backends can be enabled using the `getrandom_backend` configuration flag. -The flag can be set either by specifying the `rustflags` field in -[`.cargo/config.toml`] (note that it can be done on a per-target basis), or by using -the `RUSTFLAGS` environment variable: +The flag can be set either by specifying the `rustflags` field in [`.cargo/config.toml`]: +```toml +# It's recommended to set the flag on a per-target basis: +[target.wasm32-unknown-unknown] +rustflags = ['--cfg', 'getrandom_backend="wasm_js"'] +``` + +Or by using the `RUSTFLAGS` environment variable: ```sh RUSTFLAGS='--cfg getrandom_backend="linux_getrandom"' cargo build From 9dac11ca3584d7b57b93e78a7676827da3bd1e95 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 29 Jan 2025 06:10:48 +0300 Subject: [PATCH 107/201] Update `windows-targets` to v0.53 (#593) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bf7e06dfe..8b23c5d3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,7 +68,7 @@ wasi = { version = "0.13", default-features = false } # windows7 [target.'cfg(all(windows, not(target_vendor = "win7")))'.dependencies] -windows-targets = "0.52" +windows-targets = "0.53" # wasm_js [target.'cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dependencies] From 7385d1348954b100044843bbd661faa0f19459f7 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 29 Jan 2025 06:17:08 +0300 Subject: [PATCH 108/201] Update `wasi` to v0.14 (#594) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8b23c5d3d..ee22ce15e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,7 +64,7 @@ libc = { version = "0.2.154", default-features = false } # wasi (0.2 only) [target.'cfg(all(target_arch = "wasm32", target_os = "wasi", target_env = "p2"))'.dependencies] -wasi = { version = "0.13", default-features = false } +wasi = { version = "0.14", default-features = false } # windows7 [target.'cfg(all(windows, not(target_vendor = "win7")))'.dependencies] From e4dcbbc7025993f5a08a659c7f0b660e93eaf8c6 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 31 Jan 2025 00:17:52 +0300 Subject: [PATCH 109/201] Update WASI and Emscripten links (#597) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a3f2dce08..79082409a 100644 --- a/README.md +++ b/README.md @@ -359,8 +359,8 @@ dual licensed as above, without any additional terms or conditions. [`module`]: https://rustwasm.github.io/wasm-bindgen/reference/attributes/on-js-imports/module.html [`sys_read_entropy`]: https://github.com/hermit-os/kernel/blob/315f58ff5efc81d9bf0618af85a59963ff55f8b1/src/syscalls/entropy.rs#L47-L55 [platform-support]: https://doc.rust-lang.org/stable/rustc/platform-support.html -[WASI]: https://github.com/CraneStation/wasi -[Emscripten]: https://www.hellorust.com/setup/emscripten/ +[WASI]: https://github.com/WebAssembly/WASI +[Emscripten]: https://emscripten.org [//]: # (licenses) From ce3b017fdee0233c6ecd61e68b96a84bf6f911bf Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 2 Feb 2025 01:04:19 +0300 Subject: [PATCH 110/201] Add `#[inline]` attribute to the inner functions (#596) --- src/backends/apple_other.rs | 1 + src/backends/custom.rs | 1 + src/backends/esp_idf.rs | 1 + src/backends/fuchsia.rs | 1 + src/backends/getentropy.rs | 1 + src/backends/getrandom.rs | 1 + src/backends/hermit.rs | 3 +++ src/backends/linux_android.rs | 1 + src/backends/linux_android_with_fallback.rs | 4 ++- src/backends/netbsd.rs | 2 ++ src/backends/rdrand.rs | 3 +++ src/backends/rndr.rs | 3 +++ src/backends/solaris.rs | 1 + src/backends/solid.rs | 1 + src/backends/use_file.rs | 2 ++ src/backends/vxworks.rs | 29 ++++++++++++--------- src/backends/wasi_p1.rs | 1 + src/backends/wasi_p2.rs | 3 +++ src/backends/wasm_js.rs | 1 + src/backends/windows.rs | 1 + src/backends/windows7.rs | 1 + src/util.rs | 2 ++ 22 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/backends/apple_other.rs b/src/backends/apple_other.rs index a8c0a24d6..c7b51c0e0 100644 --- a/src/backends/apple_other.rs +++ b/src/backends/apple_other.rs @@ -4,6 +4,7 @@ use core::{ffi::c_void, mem::MaybeUninit}; pub use crate::util::{inner_u32, inner_u64}; +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let dst_ptr = dest.as_mut_ptr().cast::(); let ret = unsafe { libc::CCRandomGenerateBytes(dst_ptr, dest.len()) }; diff --git a/src/backends/custom.rs b/src/backends/custom.rs index 0c4829466..c505481ad 100644 --- a/src/backends/custom.rs +++ b/src/backends/custom.rs @@ -4,6 +4,7 @@ use core::mem::MaybeUninit; pub use crate::util::{inner_u32, inner_u64}; +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { extern "Rust" { fn __getrandom_v03_custom(dest: *mut u8, len: usize) -> Result<(), Error>; diff --git a/src/backends/esp_idf.rs b/src/backends/esp_idf.rs index 7ee391ab1..4d1689dc7 100644 --- a/src/backends/esp_idf.rs +++ b/src/backends/esp_idf.rs @@ -8,6 +8,7 @@ extern "C" { fn esp_fill_random(buf: *mut c_void, len: usize) -> u32; } +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> 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: diff --git a/src/backends/fuchsia.rs b/src/backends/fuchsia.rs index 5edd210dc..b5f1ade54 100644 --- a/src/backends/fuchsia.rs +++ b/src/backends/fuchsia.rs @@ -9,6 +9,7 @@ extern "C" { fn zx_cprng_draw(buffer: *mut u8, length: usize); } +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { unsafe { zx_cprng_draw(dest.as_mut_ptr().cast::(), dest.len()) } Ok(()) diff --git a/src/backends/getentropy.rs b/src/backends/getentropy.rs index e0b2d34c1..ed181f019 100644 --- a/src/backends/getentropy.rs +++ b/src/backends/getentropy.rs @@ -15,6 +15,7 @@ pub use crate::util::{inner_u32, inner_u64}; #[path = "../util_libc.rs"] mod util_libc; +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { for chunk in dest.chunks_mut(256) { let ret = unsafe { libc::getentropy(chunk.as_mut_ptr().cast::(), chunk.len()) }; diff --git a/src/backends/getrandom.rs b/src/backends/getrandom.rs index a00829f7c..4a7b96b01 100644 --- a/src/backends/getrandom.rs +++ b/src/backends/getrandom.rs @@ -23,6 +23,7 @@ pub use crate::util::{inner_u32, inner_u64}; #[path = "../util_libc.rs"] mod util_libc; +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { util_libc::sys_fill_exact(dest, |buf| unsafe { libc::getrandom(buf.as_mut_ptr().cast::(), buf.len(), 0) diff --git a/src/backends/hermit.rs b/src/backends/hermit.rs index 11bfbf271..0c0e3a6d8 100644 --- a/src/backends/hermit.rs +++ b/src/backends/hermit.rs @@ -12,6 +12,7 @@ extern "C" { fn sys_secure_rand64(value: *mut u64) -> i32; } +#[inline] pub fn inner_u32() -> Result { let mut res = MaybeUninit::uninit(); let ret = unsafe { sys_secure_rand32(res.as_mut_ptr()) }; @@ -22,6 +23,7 @@ pub fn inner_u32() -> Result { } } +#[inline] pub fn inner_u64() -> Result { let mut res = MaybeUninit::uninit(); let ret = unsafe { sys_secure_rand64(res.as_mut_ptr()) }; @@ -32,6 +34,7 @@ pub fn inner_u64() -> Result { } } +#[inline] pub fn fill_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { while !dest.is_empty() { let res = unsafe { sys_read_entropy(dest.as_mut_ptr().cast::(), dest.len(), 0) }; diff --git a/src/backends/linux_android.rs b/src/backends/linux_android.rs index 6c0b66ae8..58b4fe80b 100644 --- a/src/backends/linux_android.rs +++ b/src/backends/linux_android.rs @@ -10,6 +10,7 @@ mod util_libc; #[cfg(not(any(target_os = "android", target_os = "linux")))] compile_error!("`linux_getrandom` backend can be enabled only for Linux/Android targets!"); +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { util_libc::sys_fill_exact(dest, |buf| unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) diff --git a/src/backends/linux_android_with_fallback.rs b/src/backends/linux_android_with_fallback.rs index cdfff9809..33dabd2ef 100644 --- a/src/backends/linux_android_with_fallback.rs +++ b/src/backends/linux_android_with_fallback.rs @@ -20,6 +20,7 @@ const NOT_AVAILABLE: NonNull = unsafe { NonNull::new_unchecked(usize::MA static GETRANDOM_FN: AtomicPtr = AtomicPtr::new(ptr::null_mut()); #[cold] +#[inline(never)] fn init() -> NonNull { static NAME: &[u8] = b"getrandom\0"; let name_ptr = NAME.as_ptr().cast::(); @@ -59,6 +60,7 @@ fn use_file_fallback(dest: &mut [MaybeUninit]) -> Result<(), Error> { use_file::fill_inner(dest) } +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> 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` @@ -75,7 +77,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { if fptr == NOT_AVAILABLE { use_file_fallback(dest) } else { - // note: `transume` is currently the only way to convert pointer into function reference + // note: `transmute` is currently the only way to convert a pointer into a function reference let getrandom_fn = unsafe { mem::transmute::, GetRandomFn>(fptr) }; util_libc::sys_fill_exact(dest, |buf| unsafe { getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0) diff --git a/src/backends/netbsd.rs b/src/backends/netbsd.rs index 57fa91a00..f228a8b13 100644 --- a/src/backends/netbsd.rs +++ b/src/backends/netbsd.rs @@ -45,6 +45,7 @@ type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) static GETRANDOM: AtomicPtr = 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::(); @@ -58,6 +59,7 @@ fn init() -> *mut c_void { ptr } +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> 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` diff --git a/src/backends/rdrand.rs b/src/backends/rdrand.rs index 347786a55..609fcc386 100644 --- a/src/backends/rdrand.rs +++ b/src/backends/rdrand.rs @@ -147,6 +147,7 @@ unsafe fn rdrand_u64() -> Option { Some((u64::from(a) << 32) | u64::from(b)) } +#[inline] pub fn inner_u32() -> Result { if !RDRAND_GOOD.unsync_init(is_rdrand_good) { return Err(Error::NO_RDRAND); @@ -155,6 +156,7 @@ pub fn inner_u32() -> Result { unsafe { rdrand_u32() }.ok_or(Error::FAILED_RDRAND) } +#[inline] pub fn inner_u64() -> Result { if !RDRAND_GOOD.unsync_init(is_rdrand_good) { return Err(Error::NO_RDRAND); @@ -163,6 +165,7 @@ pub fn inner_u64() -> Result { unsafe { rdrand_u64() }.ok_or(Error::FAILED_RDRAND) } +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { if !RDRAND_GOOD.unsync_init(is_rdrand_good) { return Err(Error::NO_RDRAND); diff --git a/src/backends/rndr.rs b/src/backends/rndr.rs index fa24a0972..eea741a2d 100644 --- a/src/backends/rndr.rs +++ b/src/backends/rndr.rs @@ -108,6 +108,7 @@ fn is_rndr_available() -> bool { } } +#[inline] pub fn inner_u32() -> Result { if !is_rndr_available() { return Err(Error::RNDR_NOT_AVAILABLE); @@ -117,6 +118,7 @@ pub fn inner_u32() -> Result { res.map(truncate).ok_or(Error::RNDR_FAILURE) } +#[inline] pub fn inner_u64() -> Result { if !is_rndr_available() { return Err(Error::RNDR_NOT_AVAILABLE); @@ -126,6 +128,7 @@ pub fn inner_u64() -> Result { res.ok_or(Error::RNDR_FAILURE) } +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { if !is_rndr_available() { return Err(Error::RNDR_NOT_AVAILABLE); diff --git a/src/backends/solaris.rs b/src/backends/solaris.rs index ea5344fcf..c27f91a5f 100644 --- a/src/backends/solaris.rs +++ b/src/backends/solaris.rs @@ -22,6 +22,7 @@ mod util_libc; const MAX_BYTES: usize = 1024; +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { for chunk in dest.chunks_mut(MAX_BYTES) { let ptr = chunk.as_mut_ptr().cast::(); diff --git a/src/backends/solid.rs b/src/backends/solid.rs index 6699e6869..c4222a7fb 100644 --- a/src/backends/solid.rs +++ b/src/backends/solid.rs @@ -8,6 +8,7 @@ extern "C" { pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> i32; } +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let ret = unsafe { SOLID_RNG_SampleRandomBytes(dest.as_mut_ptr().cast::(), dest.len()) }; if ret >= 0 { diff --git a/src/backends/use_file.rs b/src/backends/use_file.rs index ef12fca1b..43d60b508 100644 --- a/src/backends/use_file.rs +++ b/src/backends/use_file.rs @@ -40,6 +40,7 @@ const FD_ONGOING_INIT: libc::c_int = -2; // `Ordering::Acquire` to synchronize with it. static FD: AtomicI32 = AtomicI32::new(FD_UNINIT); +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let mut fd = FD.load(Ordering::Acquire); if fd == FD_UNINIT || fd == FD_ONGOING_INIT { @@ -77,6 +78,7 @@ fn open_readonly(path: &[u8]) -> Result { } #[cold] +#[inline(never)] fn open_or_wait() -> Result { loop { match FD.load(Ordering::Acquire) { diff --git a/src/backends/vxworks.rs b/src/backends/vxworks.rs index f03ab1844..5f5e6773b 100644 --- a/src/backends/vxworks.rs +++ b/src/backends/vxworks.rs @@ -11,20 +11,25 @@ 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]) -> Result<(), Error> { - static RNG_INIT: AtomicBool = AtomicBool::new(false); while !RNG_INIT.load(Relaxed) { - let ret = unsafe { libc::randSecure() }; - match ret.cmp(&0) { - Greater => { - RNG_INIT.store(true, Relaxed); - break; - } - Equal => unsafe { - libc::usleep(10); - }, - Less => return Err(Error::VXWORKS_RAND_SECURE), - } + init()?; } // Prevent overflow of i32 diff --git a/src/backends/wasi_p1.rs b/src/backends/wasi_p1.rs index 6eefdee61..424b7f96d 100644 --- a/src/backends/wasi_p1.rs +++ b/src/backends/wasi_p1.rs @@ -11,6 +11,7 @@ extern "C" { fn random_get(arg0: i32, arg1: i32) -> i32; } +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> 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 diff --git a/src/backends/wasi_p2.rs b/src/backends/wasi_p2.rs index 9d5d601d7..63bd2d7cb 100644 --- a/src/backends/wasi_p2.rs +++ b/src/backends/wasi_p2.rs @@ -3,15 +3,18 @@ use crate::Error; use core::mem::MaybeUninit; use wasi::random::random::get_random_u64; +#[inline] pub fn inner_u32() -> Result { let val = get_random_u64(); Ok(crate::util::truncate(val)) } +#[inline] pub fn inner_u64() -> Result { Ok(get_random_u64()) } +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { use core::ptr::copy_nonoverlapping; use wasi::random::random::get_random_u64; diff --git a/src/backends/wasm_js.rs b/src/backends/wasm_js.rs index fe8f1a6ed..1320d9fc4 100644 --- a/src/backends/wasm_js.rs +++ b/src/backends/wasm_js.rs @@ -14,6 +14,7 @@ use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; const MAX_BUFFER_SIZE: usize = 65536; #[cfg(not(target_feature = "atomics"))] +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { for chunk in dest.chunks_mut(MAX_BUFFER_SIZE) { if get_random_values(chunk).is_err() { diff --git a/src/backends/windows.rs b/src/backends/windows.rs index e6e12e185..2ab7beadb 100644 --- a/src/backends/windows.rs +++ b/src/backends/windows.rs @@ -34,6 +34,7 @@ pub use crate::util::{inner_u32, inner_u64}; // https://github.com/microsoft/windows-rs/blob/0.60.0/crates/libs/targets/src/lib.rs windows_targets::link!("bcryptprimitives.dll" "system" fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> i32); +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let result = unsafe { ProcessPrng(dest.as_mut_ptr().cast::(), dest.len()) }; // Since Windows 10, calls to the user-mode RNG are guaranteed to never diff --git a/src/backends/windows7.rs b/src/backends/windows7.rs index 5b3c86c9c..8a353a9f8 100644 --- a/src/backends/windows7.rs +++ b/src/backends/windows7.rs @@ -25,6 +25,7 @@ extern "system" { type BOOLEAN = u8; const TRUE: BOOLEAN = 1u8; +#[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // Prevent overflow of u32 let chunk_size = usize::try_from(i32::MAX).expect("Windows does not support 16-bit targets"); diff --git a/src/util.rs b/src/util.rs index 4a55b0a50..d42c26e75 100644 --- a/src/util.rs +++ b/src/util.rs @@ -49,6 +49,7 @@ fn ptr_from_ref(r: &T) -> *const T { } /// Default implementation of `inner_u32` on top of `fill_uninit` +#[inline] pub fn inner_u32() -> Result { let mut res = MaybeUninit::::uninit(); // SAFETY: the created slice has the same size as `res` @@ -63,6 +64,7 @@ pub fn inner_u32() -> Result { } /// Default implementation of `inner_u64` on top of `fill_uninit` +#[inline] pub fn inner_u64() -> Result { let mut res = MaybeUninit::::uninit(); // SAFETY: the created slice has the same size as `res` From 3ba857b2da654f14e88939dda945cb0f19fc5899 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 5 Feb 2025 11:33:13 -0500 Subject: [PATCH 111/201] Remove `linux_android.rs` and use `getrandom.rs` instead (#603) --- .github/workflows/nopanic.yaml | 9 ++------- .github/workflows/workspace.yml | 4 +--- Cargo.toml | 2 +- src/backends.rs | 31 +++++++++++++++---------------- src/backends/getrandom.rs | 4 ++-- src/backends/linux_android.rs | 18 ------------------ 6 files changed, 21 insertions(+), 47 deletions(-) delete mode 100644 src/backends/linux_android.rs diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index 5b5734a07..41e9f7647 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -42,11 +42,11 @@ jobs: - name: Check (linux_android_with_fallback.rs) run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) - - name: Build (linux_android.rs) + - name: Build (getrandom.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo build --release - - name: Check (linux_android.rs) + - name: Check (getrandom.rs) run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) - name: Build (rdrand.rs) @@ -98,11 +98,6 @@ jobs: - name: Check (rndr.rs) run: (exit $( grep -c panic target/aarch64-unknown-linux-gnu/release/libgetrandom_wrapper.so )) - - name: Build (getrandom.rs) - run: cross build --release --target=x86_64-unknown-freebsd - - name: Check (getrandom.rs) - run: (exit $( grep -c panic target/x86_64-unknown-freebsd/release/libgetrandom_wrapper.so )) - - name: Build (netbsd.rs) run: cross build --release --target=x86_64-unknown-netbsd - name: Check (netbsd.rs) diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 14b37dd9b..f1e44b42d 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -41,8 +41,6 @@ jobs: run: cargo clippy -Zbuild-std=core --target x86_64-unknown-fuchsia - name: OpenBSD (getentropy.rs) run: cargo clippy -Zbuild-std=core --target x86_64-unknown-openbsd - - name: FreeBSD (getrandom.rs) - run: cargo clippy -Zbuild-std=core --target x86_64-unknown-freebsd - name: Hermit (hermit.rs) run: cargo clippy -Zbuild-std=core --target x86_64-unknown-hermit - name: Web WASM (wasm_js.rs) @@ -53,7 +51,7 @@ jobs: env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown --features wasm_js - - name: Linux (linux_android.rs) + - name: Linux (getrandom.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo clippy --target x86_64-unknown-linux-gnu diff --git a/Cargo.toml b/Cargo.toml index ee22ce15e..2942d31e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ cfg-if = "1" compiler_builtins = { version = "0.1", optional = true } core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" } -# linux_android / linux_android_with_fallback +# getrandom / linux_android_with_fallback [target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(getrandom_backend = "custom", getrandom_backend = "rdrand", getrandom_backend = "rndr"))))'.dependencies] libc = { version = "0.2.154", default-features = false } diff --git a/src/backends.rs b/src/backends.rs index 1509af115..3b98a61da 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -11,8 +11,8 @@ cfg_if! { mod custom; pub use custom::*; } else if #[cfg(getrandom_backend = "linux_getrandom")] { - mod linux_android; - pub use linux_android::*; + mod getrandom; + pub use getrandom::*; } else if #[cfg(getrandom_backend = "rdrand")] { mod rdrand; pub use rdrand::*; @@ -51,17 +51,6 @@ cfg_if! { ))] { mod getentropy; pub use getentropy::*; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "hurd", - target_os = "illumos", - // 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(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 @@ -102,9 +91,19 @@ cfg_if! { mod use_file; mod linux_android_with_fallback; pub use linux_android_with_fallback::*; - } else if #[cfg(any(target_os = "android", target_os = "linux"))] { - mod linux_android; - pub use linux_android::*; + } else if #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "hurd", + target_os = "illumos", + // 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::*; diff --git a/src/backends/getrandom.rs b/src/backends/getrandom.rs index 4a7b96b01..27d5a1f5d 100644 --- a/src/backends/getrandom.rs +++ b/src/backends/getrandom.rs @@ -16,7 +16,7 @@ //! nothing. On illumos, the default pool is used to implement getentropy(2), //! so we assume it is acceptable here. use crate::Error; -use core::{ffi::c_void, mem::MaybeUninit}; +use core::mem::MaybeUninit; pub use crate::util::{inner_u32, inner_u64}; @@ -26,6 +26,6 @@ mod util_libc; #[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { util_libc::sys_fill_exact(dest, |buf| unsafe { - libc::getrandom(buf.as_mut_ptr().cast::(), buf.len(), 0) + libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }) } diff --git a/src/backends/linux_android.rs b/src/backends/linux_android.rs deleted file mode 100644 index 58b4fe80b..000000000 --- a/src/backends/linux_android.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Implementation for Linux / Android without `/dev/urandom` fallback -use crate::Error; -use core::mem::MaybeUninit; - -pub use crate::util::{inner_u32, inner_u64}; - -#[path = "../util_libc.rs"] -mod util_libc; - -#[cfg(not(any(target_os = "android", target_os = "linux")))] -compile_error!("`linux_getrandom` backend can be enabled only for Linux/Android targets!"); - -#[inline] -pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - util_libc::sys_fill_exact(dest, |buf| unsafe { - libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) - }) -} From b75db5cede302bc9734f5bf2b9048a6e05c7f11e Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 12 Feb 2025 18:28:34 +0300 Subject: [PATCH 112/201] linux_android_with_fallback: do not use dlsym on MUSL targets (#602) --- src/backends/linux_android_with_fallback.rs | 30 ++++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/backends/linux_android_with_fallback.rs b/src/backends/linux_android_with_fallback.rs index 33dabd2ef..379237c6b 100644 --- a/src/backends/linux_android_with_fallback.rs +++ b/src/backends/linux_android_with_fallback.rs @@ -3,8 +3,8 @@ use super::use_file; use crate::Error; use core::{ ffi::c_void, - mem::{self, MaybeUninit}, - ptr::{self, NonNull}, + mem::{transmute, MaybeUninit}, + ptr::NonNull, sync::atomic::{AtomicPtr, Ordering}, }; use use_file::util_libc; @@ -17,18 +17,28 @@ type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) /// or not supported by kernel. const NOT_AVAILABLE: NonNull = unsafe { NonNull::new_unchecked(usize::MAX as *mut c_void) }; -static GETRANDOM_FN: AtomicPtr = AtomicPtr::new(ptr::null_mut()); +static GETRANDOM_FN: AtomicPtr = AtomicPtr::new(core::ptr::null_mut()); #[cold] #[inline(never)] fn init() -> NonNull { - static NAME: &[u8] = b"getrandom\0"; - let name_ptr = NAME.as_ptr().cast::(); - let raw_ptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) }; + // 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::(); + unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) } + }; + #[cfg(target_env = "musl")] + let raw_ptr = { + let fptr: GetRandomFn = libc::getrandom; + unsafe { transmute::(fptr) } + }; + let res_ptr = match NonNull::new(raw_ptr) { Some(fptr) => { - let getrandom_fn = unsafe { mem::transmute::, GetRandomFn>(fptr) }; - let dangling_ptr = ptr::NonNull::dangling().as_ptr(); + let getrandom_fn = unsafe { transmute::, 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) { @@ -54,7 +64,7 @@ fn init() -> NonNull { res_ptr } -// prevent inlining of the fallback implementation +// Prevent inlining of the fallback implementation #[inline(never)] fn use_file_fallback(dest: &mut [MaybeUninit]) -> Result<(), Error> { use_file::fill_inner(dest) @@ -78,7 +88,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { use_file_fallback(dest) } else { // note: `transmute` is currently the only way to convert a pointer into a function reference - let getrandom_fn = unsafe { mem::transmute::, GetRandomFn>(fptr) }; + let getrandom_fn = unsafe { transmute::, GetRandomFn>(fptr) }; util_libc::sys_fill_exact(dest, |buf| unsafe { getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0) }) From 074b15bc1ca993a8043513746feb52c56da479d4 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 12 Feb 2025 18:50:01 +0300 Subject: [PATCH 113/201] linux_android_with_fallback: add cfg to test that fallback is not triggered (#605) The test is needed to prevent potential regressions like #600. --- .github/workflows/tests.yml | 4 ++++ Cargo.toml | 1 + src/backends/linux_android_with_fallback.rs | 5 +++++ 3 files changed, 10 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4ba01e80b..5363968fa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -61,6 +61,10 @@ jobs: RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback RUSTDOCFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback run: cargo test --features=std + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_without_fallback + RUSTDOCFLAGS: -Dwarnings --cfg getrandom_test_linux_without_fallback + run: cargo test --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" RUSTDOCFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" diff --git a/Cargo.toml b/Cargo.toml index 2942d31e3..2441555b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,6 +84,7 @@ check-cfg = [ 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "wasm_js"))', 'cfg(getrandom_msan)', 'cfg(getrandom_test_linux_fallback)', + 'cfg(getrandom_test_linux_without_fallback)', 'cfg(getrandom_test_netbsd_fallback)', ] diff --git a/src/backends/linux_android_with_fallback.rs b/src/backends/linux_android_with_fallback.rs index 379237c6b..2ad8f0a46 100644 --- a/src/backends/linux_android_with_fallback.rs +++ b/src/backends/linux_android_with_fallback.rs @@ -60,6 +60,11 @@ fn init() -> NonNull { 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 } From 89df461267277f45a84bdcbcca10339f1eb3e8c5 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 12 Feb 2025 19:39:16 +0300 Subject: [PATCH 114/201] Commit Cargo.lock (#595) This should improve CI times a bit since it allows cargo to skip update of the crates.io index. --- .github/workflows/lock_upd.yml | 31 +++ .gitignore | 6 +- Cargo.lock | 423 +++++++++++++++++++++++++++++++++ 3 files changed, 456 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/lock_upd.yml create mode 100644 Cargo.lock diff --git a/.github/workflows/lock_upd.yml b/.github/workflows/lock_upd.yml new file mode 100644 index 000000000..e2f2a06b2 --- /dev/null +++ b/.github/workflows/lock_upd.yml @@ -0,0 +1,31 @@ +name: Update Cargo.lock + +on: + schedule: + # Run every Sunday at 00:00 UTC + - cron: '0 0 * * 0' + +permissions: + contents: read + pull-requests: write + +jobs: + update-cargo-lock: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + - name: Update dependencies + run: cargo update + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + title: "Update Cargo.lock" + commit-message: "Update Cargo.lock" + base: master + branch: update-cargo-lock + path: Cargo.lock diff --git a/.gitignore b/.gitignore index 435eeeee4..51778e4a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ /target **/*.rs.bk -Cargo.lock -*.ts -*.js -*.wasm +nopanic_check/Cargo.lock +nopanic_check/target/ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000..c8ba52e67 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,423 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "cc" +version = "1.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "compiler_builtins" +version = "0.1.146" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97117b1434b79833f39a5fabdf82f890bd98c1988334dea1cb67f7e627fa311" + +[[package]] +name = "getrandom" +version = "0.3.1" +dependencies = [ + "cfg-if", + "compiler_builtins", + "js-sys", + "libc", + "rustc-std-workspace-core", + "wasi", + "wasm-bindgen", + "wasm-bindgen-test", + "windows-targets 0.53.0", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.168" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" + +[[package]] +name = "log" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" + +[[package]] +name = "minicov" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" +dependencies = [ + "cc", + "walkdir", +] + +[[package]] +name = "once_cell" +version = "1.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc-std-workspace-core" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.14.1+wasi-0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad7df608df60a1c33e247881838b0f809512086e3e3bb1c18323b77eeb1f844e" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" +dependencies = [ + "js-sys", + "minicov", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] From d4c304162171bcd57e2d31e8688288a24baf3910 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 17 Feb 2025 08:23:48 +0300 Subject: [PATCH 115/201] ci: fix update-cargo-lock (#607) --- .github/workflows/lock_upd.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/lock_upd.yml b/.github/workflows/lock_upd.yml index e2f2a06b2..ef086f8f6 100644 --- a/.github/workflows/lock_upd.yml +++ b/.github/workflows/lock_upd.yml @@ -28,4 +28,3 @@ jobs: commit-message: "Update Cargo.lock" base: master branch: update-cargo-lock - path: Cargo.lock From 491d9d4a9cb965216a4e303c6d898635812ed723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Tue, 25 Feb 2025 14:54:51 +0300 Subject: [PATCH 116/201] Update license year --- LICENSE-MIT | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE-MIT b/LICENSE-MIT index 8ca28a1a0..e54440a9e 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2018-2024 The rust-random Project Developers +Copyright (c) 2018-2025 The rust-random Project Developers Copyright (c) 2014 The Rust Project Developers Permission is hereby granted, free of charge, to any From cf1f37e747ec1d55be61a8180ffa6ea241015b0c Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 3 Mar 2025 14:26:18 +0300 Subject: [PATCH 117/201] windows: always use `RtlGenRandom` on pre-1.78 Rust versions (#610) This PR adds detection of Rust compiler version in the build script while compiling the crate for Windows targets. If the version is smaller than 1.78, then we switch to the `windows7` backend for all Windows targets. This is necessary because on those older versions we can not disambiguate between win7 and win10 based on the target triplet. --- CHANGELOG.md | 9 +++++++++ Cargo.toml | 3 ++- README.md | 2 +- build.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++-- src/backends.rs | 2 +- 5 files changed, 63 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96dba8236..f27fdbefa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.2] - UNRELEASED + +### Changed +- Always use `RtlGenRandom` on Windows targets when compiling with pre-1.78 Rust [#610] + +[#610]: https://github.com/rust-random/getrandom/pull/610 + ## [0.3.1] - 2025-01-28 ### Fixed @@ -526,6 +533,8 @@ Publish initial implementation. ## [0.0.0] - 2019-01-19 Publish an empty template library. +[0.3.2]: https://github.com/rust-random/getrandom/compare/v0.3.0...v0.3.2 +[0.3.1]: https://github.com/rust-random/getrandom/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/rust-random/getrandom/compare/v0.2.15...v0.3.0 [0.2.15]: https://github.com/rust-random/getrandom/compare/v0.2.14...v0.2.15 [0.2.14]: https://github.com/rust-random/getrandom/compare/v0.2.13...v0.2.14 diff --git a/Cargo.toml b/Cargo.toml index 2441555b1..a5fb2dbe7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ libc = { version = "0.2.154", default-features = false } wasi = { version = "0.14", default-features = false } # windows7 -[target.'cfg(all(windows, not(target_vendor = "win7")))'.dependencies] +[target.'cfg(all(windows, not(target_vendor = "win7"), not(getrandom_windows_legacy)))'.dependencies] windows-targets = "0.53" # wasm_js @@ -83,6 +83,7 @@ level = "warn" check-cfg = [ 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "wasm_js"))', 'cfg(getrandom_msan)', + 'cfg(getrandom_windows_legacy)', 'cfg(getrandom_test_linux_fallback)', 'cfg(getrandom_test_linux_without_fallback)', 'cfg(getrandom_test_netbsd_fallback)', diff --git a/README.md b/README.md index 79082409a..6fb9b00e3 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ fn get_random_u128() -> Result { | Target | Target Triple | Implementation | ------------------ | ------------------ | -------------- | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` -| Windows 10+ | `*‑windows‑*` | [`ProcessPrng`] +| Windows 10+ | `*‑windows‑*` | [`ProcessPrng`] on Rust 1.78+, [`RtlGenRandom`] otherwise | Windows 7, 8 | `*-win7‑windows‑*` | [`RtlGenRandom`] | macOS | `*‑apple‑darwin` | [`getentropy`][3] | iOS, tvOS, watchOS | `*‑apple‑{ios,tvos,watchos}` | [`CCRandomGenerateBytes`] diff --git a/build.rs b/build.rs index 15d419191..ea9baaaaa 100644 --- a/build.rs +++ b/build.rs @@ -1,9 +1,57 @@ -// Automatically detect cfg(sanitize = "memory") even if cfg(sanitize) isn't -// supported. Build scripts get cfg() info, even if the cfg is unstable. +use std::{env, ffi::OsString, process::Command}; + +/// Tries to get the minor version of the Rust compiler in use. +/// If it fails for any reason, returns `None`. +/// +/// Based on the `rustc_version` crate. +fn rustc_minor_version() -> Option { + let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); + let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER").filter(|w| !w.is_empty()) { + let mut cmd = Command::new(wrapper); + cmd.arg(rustc); + cmd + } else { + Command::new(rustc) + }; + + let out = cmd.arg("-vV").output().ok()?; + + if !out.status.success() { + return None; + } + + let stdout = std::str::from_utf8(&out.stdout).ok()?; + + // Assumes that the first line contains "rustc 1.xx.0-channel (abcdef 2025-01-01)" + // where "xx" is the minor version which we want to extract + let mut lines = stdout.lines(); + let first_line = lines.next()?; + let minor_ver_str = first_line.split(".").nth(1)?; + minor_ver_str.parse().ok() +} + fn main() { + // Automatically detect cfg(sanitize = "memory") even if cfg(sanitize) isn't + // supported. Build scripts get cfg() info, even if the cfg is unstable. println!("cargo:rerun-if-changed=build.rs"); let santizers = std::env::var("CARGO_CFG_SANITIZE").unwrap_or_default(); if santizers.contains("memory") { println!("cargo:rustc-cfg=getrandom_msan"); } + + // Use `RtlGenRandom` on older compiler versions since win7 targets + // were introduced only in Rust 1.78 + let target_family = env::var_os("CARGO_CFG_TARGET_FAMILY").and_then(|f| f.into_string().ok()); + if target_family.as_deref() == Some("windows") { + /// Minor version of the Rust compiler in which win7 targets were inroduced + const WIN7_INTRODUCED_MINOR_VER: u64 = 78; + + match rustc_minor_version() { + Some(minor_ver) if minor_ver < WIN7_INTRODUCED_MINOR_VER => { + println!("cargo:rustc-cfg=getrandom_windows_legacy"); + } + None => println!("cargo:warning=Couldn't detect minor version of the Rust compiler"), + _ => {} + } + } } diff --git a/src/backends.rs b/src/backends.rs index 3b98a61da..f97059c47 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -145,7 +145,7 @@ cfg_if! { } else if #[cfg(target_os = "solid_asp3")] { mod solid; pub use solid::*; - } else if #[cfg(all(windows, target_vendor = "win7"))] { + } else if #[cfg(all(windows, any(target_vendor = "win7", getrandom_windows_legacy)))] { mod windows7; pub use windows7::*; } else if #[cfg(windows)] { From 3be979be4e72c4b1134d6b3642c0bd90ab361e28 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 3 Mar 2025 14:26:58 +0300 Subject: [PATCH 118/201] Add `linux_raw` opt-in backend (#572) This PR replaces the `linux_rustix` opt-in backend introduced in #520 with `linux_raw` opt-in backend based raw syscalls implemented using `asm!`. It noticeably reduces dependency footprint of the crate (see concerns raised in #433). Unfortunately, it means that we have to implement the raw syscalls ourselves. This PR implements `linux_raw` support only for target arches with stable `asm!`. Nightly-only support for other targets can be added in later PRs. --- .github/workflows/build.yml | 26 ++++++ .github/workflows/nopanic.yaml | 7 ++ .github/workflows/tests.yml | 4 + .github/workflows/workspace.yml | 4 + Cargo.toml | 4 +- README.md | 10 +++ src/backends.rs | 3 + src/backends/linux_raw.rs | 139 ++++++++++++++++++++++++++++++++ 8 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 src/backends/linux_raw.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 204da8074..6ad2c4c2f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -132,6 +132,32 @@ jobs: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" run: cargo build --features=std + linux-raw: + name: Build Raw Linux + runs-on: ubuntu-24.04 + strategy: + matrix: + target: [ + arm-unknown-linux-gnueabihf, + aarch64-unknown-linux-gnu, + loongarch64-unknown-linux-gnu, + riscv32gc-unknown-linux-gnu, + riscv64gc-unknown-linux-gnu, + s390x-unknown-linux-gnu, + i686-unknown-linux-gnu, + x86_64-unknown-linux-gnu, + x86_64-unknown-linux-gnux32, + ] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: nightly-2025-02-15 + components: rust-src + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw" + run: cargo build -Zbuild-std=core --target=${{ matrix.target }} + web: name: ${{ matrix.target.description }} ${{ matrix.feature.description }} ${{ matrix.atomic.description }} runs-on: ubuntu-24.04 diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index 41e9f7647..7ad20ce04 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -49,6 +49,13 @@ jobs: - name: Check (getrandom.rs) run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) + - name: Build (linux_raw.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw" + run: cargo build --release + - name: Check (linux_raw.rs) + run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so )) + - name: Build (rdrand.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5363968fa..84b148b41 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -57,6 +57,10 @@ jobs: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" RUSTDOCFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo test --target=${{ matrix.target }} --features=std + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw" + RUSTDOCFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw" + run: cargo test --target=${{ matrix.target }} --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback RUSTDOCFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index f1e44b42d..29c0d5ab5 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -57,6 +57,10 @@ jobs: run: cargo clippy --target x86_64-unknown-linux-gnu - name: Linux (linux_android_with_fallback.rs) run: cargo clippy --target x86_64-unknown-linux-gnu + - name: Linux (linux_raw.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw" + run: cargo clippy --target x86_64-unknown-linux-gnu - name: NetBSD (netbsd.rs) run: cargo clippy -Zbuild-std=core --target x86_64-unknown-netbsd - name: Fortranix SGX (rdrand.rs) diff --git a/Cargo.toml b/Cargo.toml index a5fb2dbe7..4df70e688 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ compiler_builtins = { version = "0.1", optional = true } core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" } # getrandom / linux_android_with_fallback -[target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(getrandom_backend = "custom", getrandom_backend = "rdrand", getrandom_backend = "rndr"))))'.dependencies] +[target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(getrandom_backend = "custom", getrandom_backend = "linux_raw", getrandom_backend = "rdrand", getrandom_backend = "rndr"))))'.dependencies] libc = { version = "0.2.154", default-features = false } # apple-other @@ -81,7 +81,7 @@ wasm-bindgen-test = "0.3" [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "wasm_js"))', + 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "linux_raw", "wasm_js"))', 'cfg(getrandom_msan)', 'cfg(getrandom_windows_legacy)', 'cfg(getrandom_test_linux_fallback)', diff --git a/README.md b/README.md index 6fb9b00e3..9c85b62ad 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ of randomness based on their specific needs: | Backend name | Target | Target Triple | Implementation | ----------------- | -------------------- | ------------------------ | -------------- | `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). +| `linux_raw` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses raw `asm!`-based syscalls instead of `libc`. | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register | `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown`, `wasm32v1-none` | [`Crypto.getRandomValues`]. Requires feature `wasm_js` ([see below](#webassembly-support)). @@ -110,6 +111,15 @@ WILL NOT have any effect on its downstream users. [`.cargo/config.toml`]: https://doc.rust-lang.org/cargo/reference/config.html +### Raw Linux syscall support + +Currently the `linux_raw` backend supports only targets with stabilized `asm!` macro, +i.e. `arm`, `aarch64`, `loongarch64`, `riscv32`, `riscv64`, `s390x`, `x86`, and `x86_64`. + +Note that the raw syscall backend may be slower than backends based on `libc::getrandom`, +e.g. it does not implement vDSO optimizations and on `x86` it uses the infamously slow +`int 0x80` instruction to perform syscall. + ### WebAssembly support This crate fully supports the [WASI] and [Emscripten] targets. However, diff --git a/src/backends.rs b/src/backends.rs index f97059c47..b2ac5102a 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -13,6 +13,9 @@ cfg_if! { } 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::*; diff --git a/src/backends/linux_raw.rs b/src/backends/linux_raw.rs new file mode 100644 index 000000000..a601f07b8 --- /dev/null +++ b/src/backends/linux_raw.rs @@ -0,0 +1,139 @@ +//! 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]) -> 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: u32 = ret + .wrapping_neg() + .try_into() + .map_err(|_| Error::UNEXPECTED)?; + return Err(Error::from_os_error(code)); + } + } + } +} From 0ce3de13c2a56c34ff4a81ad91afa93119e86c64 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 3 Mar 2025 14:40:55 +0300 Subject: [PATCH 119/201] Add previously merged PRs to changelog (#612) --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f27fdbefa..bd2ff582a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.3.2] - UNRELEASED +### Added +- `linux_raw` opt-in backend [#572] +- `.cargo/config.toml` example in the crate-level docs [#591] +- `getrandom_test_linux_without_fallback` configuration flag to test that file fallback + is not triggered in the `linux_android_with_fallback` backend [#605] + ### Changed +- Update `windows-targets` dependency to v0.53 [#593] +- Update `wasi` dependency to v0.14 [#594] +- Add `#[inline]` attribute to the inner functions [#596] +- Update WASI and Emscripten links in the crate-level docs [#597] +- Do not use `dlsym` on MUSL targets in the `linux_android_with_fallback` backend [#602] +- Remove `linux_android.rs` and use `getrandom.rs` instead [#603] - Always use `RtlGenRandom` on Windows targets when compiling with pre-1.78 Rust [#610] +[#572]: https://github.com/rust-random/getrandom/pull/572 +[#591]: https://github.com/rust-random/getrandom/pull/591 +[#593]: https://github.com/rust-random/getrandom/pull/593 +[#594]: https://github.com/rust-random/getrandom/pull/594 +[#596]: https://github.com/rust-random/getrandom/pull/596 +[#597]: https://github.com/rust-random/getrandom/pull/597 +[#602]: https://github.com/rust-random/getrandom/pull/602 +[#603]: https://github.com/rust-random/getrandom/pull/603 +[#605]: https://github.com/rust-random/getrandom/pull/605 [#610]: https://github.com/rust-random/getrandom/pull/610 ## [0.3.1] - 2025-01-28 From 0428d50979c5c4cb6b6c867470f0969c2f6cb81e Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 3 Mar 2025 15:48:47 +0300 Subject: [PATCH 120/201] Add `efi_rng` opt-in backend (#570) The implementation is based on the [`std` code][0]. I am not sure why we need the try loop over protocol handles instead of just getting the first handle, but I decided to just follow `std` here. [0]: https://github.com/rust-lang/rust/blob/master/library/std/src/sys/random/uefi.rs Because the backend requires access to `BootServices` it has to rely on the unstable `uefi_std` feature. We could alternatively use the `uefi` crate, but it would tie the backend to the `uefi` crate environment, which is probably not desirable. `TEMP_EFI_ERROR` is used as a temporary solution and will be fixed in a separate PR. --- .github/workflows/build.yml | 20 +++++ .github/workflows/workspace.yml | 4 + CHANGELOG.md | 2 + Cargo.lock | 47 +++++++----- Cargo.toml | 6 +- README.md | 2 + src/backends.rs | 3 + src/backends/efi_rng.rs | 125 ++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 9 files changed, 189 insertions(+), 21 deletions(-) create mode 100644 src/backends/efi_rng.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6ad2c4c2f..ed9788d84 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -192,6 +192,26 @@ jobs: - name: Build run: cargo build --target ${{ matrix.target.target }} ${{ matrix.feature.feature }} -Zbuild-std=${{ matrix.feature.build-std }} + efi-rng: + name: UEFI RNG Protocol + runs-on: ubuntu-24.04 + strategy: + matrix: + target: [ + aarch64-unknown-uefi, + x86_64-unknown-uefi, + i686-unknown-uefi, + ] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly # Required to build libstd + with: + components: rust-src + - uses: Swatinem/rust-cache@v2 + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="efi_rng" + run: cargo build -Z build-std=std --target=${{ matrix.target }} --features std + rdrand-uefi: name: RDRAND UEFI runs-on: ubuntu-24.04 diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 29c0d5ab5..9f379b187 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -69,6 +69,10 @@ jobs: env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rndr" run: cargo clippy -Zbuild-std=core --target aarch64-unknown-linux-gnu + - name: EFI RNG (efi_rng.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="efi_rng" + run: cargo clippy -Zbuild-std=std --target x86_64-unknown-uefi - name: Solaris (solaris.rs) run: cargo clippy -Zbuild-std=core --target x86_64-pc-solaris - name: SOLID (solid.rs) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd2ff582a..3e5af794d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.3.2] - UNRELEASED ### Added +- `efi_rng` opt-in backend [#570] - `linux_raw` opt-in backend [#572] - `.cargo/config.toml` example in the crate-level docs [#591] - `getrandom_test_linux_without_fallback` configuration flag to test that file fallback @@ -21,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove `linux_android.rs` and use `getrandom.rs` instead [#603] - Always use `RtlGenRandom` on Windows targets when compiling with pre-1.78 Rust [#610] +[#570]: https://github.com/rust-random/getrandom/pull/570 [#572]: https://github.com/rust-random/getrandom/pull/572 [#591]: https://github.com/rust-random/getrandom/pull/591 [#593]: https://github.com/rust-random/getrandom/pull/593 diff --git a/Cargo.lock b/Cargo.lock index c8ba52e67..c83e51555 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "bitflags" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "bumpalo" @@ -16,9 +16,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.13" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ "shlex", ] @@ -31,9 +31,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "compiler_builtins" -version = "0.1.146" +version = "0.1.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97117b1434b79833f39a5fabdf82f890bd98c1988334dea1cb67f7e627fa311" +checksum = "5c42734e0ccf0d9f953165770593a75306f0b24dda1aa03f115c70748726dbca" [[package]] name = "getrandom" @@ -43,6 +43,7 @@ dependencies = [ "compiler_builtins", "js-sys", "libc", + "r-efi", "rustc-std-workspace-core", "wasi", "wasm-bindgen", @@ -62,15 +63,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.168" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "log" -version = "0.4.25" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "minicov" @@ -90,22 +91,28 @@ checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rustc-std-workspace-core" version = "1.0.1" @@ -129,9 +136,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "syn" -version = "2.0.98" +version = "2.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" dependencies = [ "proc-macro2", "quote", @@ -140,9 +147,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" [[package]] name = "walkdir" @@ -156,9 +163,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.14.1+wasi-0.2.3" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad7df608df60a1c33e247881838b0f809512086e3e3bb1c18323b77eeb1f844e" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] diff --git a/Cargo.toml b/Cargo.toml index 4df70e688..4298ea0bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,10 @@ libc = { version = "0.2.154", default-features = false } [target.'cfg(any(target_os = "ios", target_os = "visionos", target_os = "watchos", target_os = "tvos"))'.dependencies] libc = { version = "0.2.154", default-features = false } +# efi_rng +[target.'cfg(all(target_os = "uefi", getrandom_backend = "efi_rng"))'.dependencies] +r-efi = { version = "5.1", default-features = false } + # getentropy [target.'cfg(any(target_os = "macos", target_os = "openbsd", target_os = "vita", target_os = "emscripten"))'.dependencies] libc = { version = "0.2.154", default-features = false } @@ -81,7 +85,7 @@ wasm-bindgen-test = "0.3" [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "linux_raw", "wasm_js"))', + 'cfg(getrandom_backend, values("custom", "efi_rng", "rdrand", "rndr", "linux_getrandom", "linux_raw", "wasm_js"))', 'cfg(getrandom_msan)', 'cfg(getrandom_windows_legacy)', 'cfg(getrandom_test_linux_fallback)', diff --git a/README.md b/README.md index 9c85b62ad..1c6cb3e8c 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ of randomness based on their specific needs: | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register | `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown`, `wasm32v1-none` | [`Crypto.getRandomValues`]. Requires feature `wasm_js` ([see below](#webassembly-support)). +| `efi_rng` | UEFI | `*-unknown‑uefi` | [`EFI_RNG_PROTOCOL`] with `EFI_RNG_ALGORITHM_RAW` (requires `std` and Nigthly compiler) | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) Opt-in backends can be enabled using the `getrandom_backend` configuration flag. @@ -361,6 +362,7 @@ dual licensed as above, without any additional terms or conditions. [`esp_fill_random`]: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/random.html#functions [esp-idf-rng]: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/random.html [esp-trng-docs]: https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf#rng +[`EFI_RNG_PROTOCOL`]: https://uefi.org/specs/UEFI/2.10/37_Secure_Technologies.html#efi-rng-protocol [`random_get`]: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-buf_len-size---errno [`get-random-u64`]: https://github.com/WebAssembly/WASI/blob/v0.2.1/wasip2/random/random.wit#L23-L28 [configuration flags]: #configuration-flags diff --git a/src/backends.rs b/src/backends.rs index b2ac5102a..82141a2bb 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -22,6 +22,9 @@ cfg_if! { } 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")] { diff --git a/src/backends/efi_rng.rs b/src/backends/efi_rng.rs new file mode 100644 index 000000000..5c642a3bb --- /dev/null +++ b/src/backends/efi_rng.rs @@ -0,0 +1,125 @@ +//! 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 = AtomicPtr::new(null_mut()); + +#[cold] +#[inline(never)] +fn init() -> Result, Error> { + const HANDLE_SIZE: usize = size_of::(); + + let boot_services = std::os::uefi::env::boot_services() + .ok_or(Error::BOOT_SERVICES_UNAVAILABLE)? + .cast::(); + + 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::TEMP_EFI_ERROR); + } + + 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]) -> 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::(), + ) + }; + + if ret.is_error() { + Err(Error::TEMP_EFI_ERROR) + } 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); + pub(crate) const TEMP_EFI_ERROR: Error = Self::new_internal(12); +} diff --git a/src/lib.rs b/src/lib.rs index 2ac0ad0ba..51c494e17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ #![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, From 76ed428dadd7cc8be4f04d495a22806e86e7749e Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 3 Mar 2025 15:59:46 +0300 Subject: [PATCH 121/201] Fix `clippy::manual_contains` (#613) --- src/backends/use_file.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/use_file.rs b/src/backends/use_file.rs index 43d60b508..7b48d4338 100644 --- a/src/backends/use_file.rs +++ b/src/backends/use_file.rs @@ -58,7 +58,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // 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 { - assert!(path.iter().any(|&b| b == 0)); + assert!(path.contains(&0)); loop { let fd = unsafe { libc::open( From 564dca556fe75ea5090f120613ff901d8486558a Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 6 Mar 2025 22:33:08 -0800 Subject: [PATCH 122/201] ci: try to fix Update Cargo.lock job (#615) We need more permission. Also does some other minor cleanup and allows us to run the workflow manually, so I can make sure it works. --- .github/workflows/lock_upd.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/lock_upd.yml b/.github/workflows/lock_upd.yml index ef086f8f6..4f1b9ba5a 100644 --- a/.github/workflows/lock_upd.yml +++ b/.github/workflows/lock_upd.yml @@ -1,12 +1,15 @@ name: Update Cargo.lock on: + # Allow manually running the update + workflow_dispatch: + # Run every Sunday at 00:00 UTC schedule: - # Run every Sunday at 00:00 UTC - cron: '0 0 * * 0' +# We need permissions to commit code and open a pull request permissions: - contents: read + contents: write pull-requests: write jobs: @@ -14,15 +17,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: stable + - uses: dtolnay/rust-toolchain@stable - name: Update dependencies run: cargo update - name: Create Pull Request uses: peter-evans/create-pull-request@v7 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: title: "Update Cargo.lock" commit-message: "Update Cargo.lock" From f2ede81baddfab37b4d46e9057e9315b0ebea171 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 7 Mar 2025 12:37:18 +0300 Subject: [PATCH 123/201] Tweak `Error` representation (#614) On UEFI targets `Error` is now represented as `NonZeroUsize` and on other targets as `NonZeroI32`. In the former case OS errors have the highest bit set to 1, while in the latter case OS errors are represented as negative integers. Additionally, this PR removes `Error::INTERNAL_START` and `Error::CUSTOM_START` associated constants since the constants are no longer relevant and the inner representation is an internal detail. This is technically a breaking change, but I highly doubt that downstream users rely on them since they can not be used for anything useful, so we can consider it as a "fix" of unintentionally exported constants. --- CHANGELOG.md | 7 ++- src/backends/efi_rng.rs | 5 +- src/backends/hermit.rs | 6 +- src/backends/linux_raw.rs | 7 +-- src/backends/solid.rs | 4 +- src/backends/wasi_p1.rs | 7 +-- src/error.rs | 120 ++++++++++++++++++++++---------------- src/util_libc.rs | 16 ++--- 8 files changed, 94 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e5af794d..16fdb3710 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Do not use `dlsym` on MUSL targets in the `linux_android_with_fallback` backend [#602] - Remove `linux_android.rs` and use `getrandom.rs` instead [#603] - Always use `RtlGenRandom` on Windows targets when compiling with pre-1.78 Rust [#610] +- Internal representation of the `Error` type [#614] + +### Removed +- `Error::INTERNAL_START` and `Error::CUSTOM_START` associated constants [#614] [#570]: https://github.com/rust-random/getrandom/pull/570 [#572]: https://github.com/rust-random/getrandom/pull/572 @@ -33,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#603]: https://github.com/rust-random/getrandom/pull/603 [#605]: https://github.com/rust-random/getrandom/pull/605 [#610]: https://github.com/rust-random/getrandom/pull/610 +[#614]: https://github.com/rust-random/getrandom/pull/614 ## [0.3.1] - 2025-01-28 @@ -556,7 +561,7 @@ Publish initial implementation. ## [0.0.0] - 2019-01-19 Publish an empty template library. -[0.3.2]: https://github.com/rust-random/getrandom/compare/v0.3.0...v0.3.2 +[0.3.2]: https://github.com/rust-random/getrandom/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/rust-random/getrandom/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/rust-random/getrandom/compare/v0.2.15...v0.3.0 [0.2.15]: https://github.com/rust-random/getrandom/compare/v0.2.14...v0.2.15 diff --git a/src/backends/efi_rng.rs b/src/backends/efi_rng.rs index 5c642a3bb..768c8cc8c 100644 --- a/src/backends/efi_rng.rs +++ b/src/backends/efi_rng.rs @@ -43,7 +43,7 @@ fn init() -> Result, Error> { }; if ret.is_error() { - return Err(Error::TEMP_EFI_ERROR); + return Err(Error::from_uefi_code(ret.as_usize())); } let handles_len = buf_size / HANDLE_SIZE; @@ -112,7 +112,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { }; if ret.is_error() { - Err(Error::TEMP_EFI_ERROR) + Err(Error::from_uefi_code(ret.as_usize())) } else { Ok(()) } @@ -121,5 +121,4 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { impl Error { pub(crate) const BOOT_SERVICES_UNAVAILABLE: Error = Self::new_internal(10); pub(crate) const NO_RNG_HANDLE: Error = Self::new_internal(11); - pub(crate) const TEMP_EFI_ERROR: Error = Self::new_internal(12); } diff --git a/src/backends/hermit.rs b/src/backends/hermit.rs index 0c0e3a6d8..34d7cdbb9 100644 --- a/src/backends/hermit.rs +++ b/src/backends/hermit.rs @@ -44,10 +44,8 @@ pub fn fill_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { dest = dest.get_mut(len..).ok_or(Error::UNEXPECTED)?; } code => { - let err = u32::try_from(code.unsigned_abs()) - .ok() - .map_or(Error::UNEXPECTED, Error::from_os_error); - return Err(err); + let code = i32::try_from(code).map_err(|_| Error::UNEXPECTED)?; + return Err(Error::from_neg_error_code(code)); } } } diff --git a/src/backends/linux_raw.rs b/src/backends/linux_raw.rs index a601f07b8..4a59eef00 100644 --- a/src/backends/linux_raw.rs +++ b/src/backends/linux_raw.rs @@ -128,11 +128,8 @@ pub fn fill_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { } Err(_) if ret == EINTR => continue, Err(_) => { - let code: u32 = ret - .wrapping_neg() - .try_into() - .map_err(|_| Error::UNEXPECTED)?; - return Err(Error::from_os_error(code)); + let code = i32::try_from(ret).map_err(|_| Error::UNEXPECTED)?; + return Err(Error::from_neg_error_code(code)); } } } diff --git a/src/backends/solid.rs b/src/backends/solid.rs index c4222a7fb..caa773f81 100644 --- a/src/backends/solid.rs +++ b/src/backends/solid.rs @@ -14,8 +14,6 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { 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(Error::from_os_error(ret.unsigned_abs())) + Err(Error::from_neg_error_code(ret)) } } diff --git a/src/backends/wasi_p1.rs b/src/backends/wasi_p1.rs index 424b7f96d..76dbc6d0a 100644 --- a/src/backends/wasi_p1.rs +++ b/src/backends/wasi_p1.rs @@ -21,11 +21,6 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let ret = unsafe { random_get(dest.as_mut_ptr() as i32, dest.len() as i32) }; match ret { 0 => Ok(()), - code => { - let err = u32::try_from(code) - .map(Error::from_os_error) - .unwrap_or(Error::UNEXPECTED); - Err(err) - } + code => Err(Error::from_neg_error_code(code)), } } diff --git a/src/error.rs b/src/error.rs index ccbe78373..13f3121f6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,15 +1,20 @@ #[cfg(feature = "std")] extern crate std; -use core::{fmt, num::NonZeroU32}; +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; } ); @@ -19,16 +24,16 @@ cfg_if::cfg_if!( /// 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`](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(NonZeroU32); +pub struct Error(NonZeroRawOsError); impl Error { /// This target/platform is not supported by `getrandom`. @@ -38,29 +43,32 @@ impl Error { /// Encountered an unexpected situation which should not happen in practice. pub const UNEXPECTED: Error = Self::new_internal(2); - /// 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; + /// 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; - /// 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); + /// 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 a particular OS error code. - /// - /// This method is analogous to [`std::io::Error::from_raw_os_error()`][1], - /// except that it works in `no_std` contexts and `code` will be - /// replaced with `Error::UNEXPECTED` if it isn't in the range - /// `1..Error::INTERNAL_START`. Thus, for the result `r`, - /// `r == Self::UNEXPECTED || r.raw_os_error().unsigned_abs() == code`. - /// - /// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.from_raw_os_error + /// Creates a new instance of an `Error` from an UEFI error code. + #[cfg(target_os = "uefi")] #[allow(dead_code)] - pub(super) fn from_os_error(code: u32) -> Self { - match NonZeroU32::new(code) { - Some(code) if code.get() < Self::INTERNAL_START => Self(code), - _ => Self::UNEXPECTED, + 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 } } @@ -79,27 +87,53 @@ impl Error { #[inline] pub fn raw_os_error(self) -> Option { let code = self.0.get(); - if code >= Self::INTERNAL_START { - return None; + + // 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) + } } - let errno = RawOsError::try_from(code).ok()?; - #[cfg(target_os = "solid_asp3")] - let errno = -errno; - Some(errno) } /// 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 a u32. - let code = Error::CUSTOM_START + (n as u32); - Error(unsafe { NonZeroU32::new_unchecked(code) }) + // 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 a u32. - let code = Error::INTERNAL_START + (n as u32); - Error(unsafe { NonZeroU32::new_unchecked(code) }) + // 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> { @@ -176,15 +210,3 @@ impl fmt::Display for Error { } } } - -#[cfg(test)] -mod tests { - use super::Error; - use core::mem::size_of; - - #[test] - fn test_size() { - assert_eq!(size_of::(), 4); - assert_eq!(size_of::>(), 4); - } -} diff --git a/src/util_libc.rs b/src/util_libc.rs index 2f6185958..800030139 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -34,14 +34,16 @@ cfg_if! { } pub(crate) fn last_os_error() -> Error { - let errno: libc::c_int = unsafe { get_errno() }; + // We assume that on all targets which use the `util_libc` module `c_int` is equal to `i32` + let errno: i32 = unsafe { get_errno() }; - // c_int-to-u32 conversion is lossless for nonnegative values if they are the same size. - const _: () = assert!(core::mem::size_of::() == core::mem::size_of::()); - - match u32::try_from(errno) { - Ok(code) if code != 0 => Error::from_os_error(code), - _ => Error::ERRNO_NOT_POSITIVE, + 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 } } From d3175f3f182174d54ab5f3b9c483b7fc23abe85e Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 7 Mar 2025 14:28:43 +0300 Subject: [PATCH 124/201] ci: replace `lock_upd` job with Dependabot (#619) With the added config we should get from Dependabot at most daily PRs on breaking change releases of our direct upstream dependencies and at most weekly PRs for Cargo.lock updates. --- .github/dependabot.yml | 19 +++++++++++++++++++ .github/workflows/lock_upd.yml | 29 ----------------------------- 2 files changed, 19 insertions(+), 29 deletions(-) create mode 100644 .github/dependabot.yml delete mode 100644 .github/workflows/lock_upd.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..5d9402757 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,19 @@ +version: 2 +updates: +- package-ecosystem: cargo + directory: "/" + versioning-strategy: increase-if-necessary + schedule: + interval: daily + open-pull-requests-limit: 10 +- package-ecosystem: cargo + directory: "/" + versioning-strategy: lockfile-only + schedule: + interval: weekly + open-pull-requests-limit: 10 +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 diff --git a/.github/workflows/lock_upd.yml b/.github/workflows/lock_upd.yml deleted file mode 100644 index 4f1b9ba5a..000000000 --- a/.github/workflows/lock_upd.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Update Cargo.lock - -on: - # Allow manually running the update - workflow_dispatch: - # Run every Sunday at 00:00 UTC - schedule: - - cron: '0 0 * * 0' - -# We need permissions to commit code and open a pull request -permissions: - contents: write - pull-requests: write - -jobs: - update-cargo-lock: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - name: Update dependencies - run: cargo update - - name: Create Pull Request - uses: peter-evans/create-pull-request@v7 - with: - title: "Update Cargo.lock" - commit-message: "Update Cargo.lock" - base: master - branch: update-cargo-lock From 2eb358466c175dee46a67e29ed511f926cdfd560 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 7 Mar 2025 14:34:51 +0300 Subject: [PATCH 125/201] ci: fix Dependabot config (#620) Unfortunately, we can not have two separate "jobs" for bumping direct dependencies and for updating Cargo.lock. The old config results in the following error: >Update configs must have a unique combination of 'package-ecosystem', 'directory', and 'target-branch'. Ecosystem 'cargo' has overlapping directories. --- .github/dependabot.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5d9402757..9a4eb3e23 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,11 +1,5 @@ version: 2 updates: -- package-ecosystem: cargo - directory: "/" - versioning-strategy: increase-if-necessary - schedule: - interval: daily - open-pull-requests-limit: 10 - package-ecosystem: cargo directory: "/" versioning-strategy: lockfile-only From e591030c48a8a06d5c1710ed3244e0ef2a66c0b5 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 7 Mar 2025 14:52:19 +0300 Subject: [PATCH 126/201] ci: tweak Dependabot config (#623) --- .github/dependabot.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9a4eb3e23..80dfb4a97 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,12 +2,16 @@ version: 2 updates: - package-ecosystem: cargo directory: "/" - versioning-strategy: lockfile-only + versioning-strategy: increase-if-necessary + allow: + - dependency-type: "all" schedule: interval: weekly - open-pull-requests-limit: 10 + groups: + all-deps: + patterns: + - "*" - package-ecosystem: "github-actions" directory: "/" schedule: interval: weekly - open-pull-requests-limit: 10 From 3b1605888f867e17c5106ea7ca91b612cb0096aa Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 7 Mar 2025 14:59:07 +0300 Subject: [PATCH 127/201] ci: fix Dependabot config (#624) It looks like Cargo does not support the `increase-if-necessary` versioning strategy. --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 80dfb4a97..b42e381cf 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,7 +2,7 @@ version: 2 updates: - package-ecosystem: cargo directory: "/" - versioning-strategy: increase-if-necessary + versioning-strategy: lockfile-only allow: - dependency-type: "all" schedule: From 05c0c41f5dbcb6b52fadbfdf10d16cef8ba97465 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Mar 2025 15:05:52 +0300 Subject: [PATCH 128/201] Update Cargo.lock (#625) --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c83e51555..93df7a712 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,9 +31,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "compiler_builtins" -version = "0.1.150" +version = "0.1.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c42734e0ccf0d9f953165770593a75306f0b24dda1aa03f115c70748726dbca" +checksum = "abc30f1766d387c35f2405e586d3e7a88230dc728ff78cd1d0bc59ae0b63154b" [[package]] name = "getrandom" @@ -63,9 +63,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.169" +version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" [[package]] name = "log" @@ -147,9 +147,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "walkdir" From b160ef612568c4aeaf749d6311bc99e2fe7e12bc Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Sat, 8 Mar 2025 19:53:24 -0800 Subject: [PATCH 129/201] Use "raw-dylib" for non-win7 Windows Targets (#627) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we only use the standard Windows backend on Windows 1.78 or later, we can just use `kind = "raw-dylib"` to link to `bcryptprimitives.dll`. This eliminates the `windows-targets` dependency and reduces the `--target=all` dependancy graph for `getrandom` to: ``` └── getrandom v0.3.1 ├── cfg-if v1.0.0 ├── libc v0.2.170 ├── r-efi v5.2.0 └── wasi v0.14.2+wasi-0.2.4 └── wit-bindgen-rt v0.39.0 └── bitflags v2.9.0 ``` Signed-off-by: Joe Richey --- CHANGELOG.md | 5 ++- Cargo.lock | 83 +++++------------------------------------ Cargo.toml | 4 -- build.rs | 2 +- src/backends/windows.rs | 30 +++++++++++---- 5 files changed, 35 insertions(+), 89 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16fdb3710..acfa3719d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 is not triggered in the `linux_android_with_fallback` backend [#605] ### Changed -- Update `windows-targets` dependency to v0.53 [#593] +- Remove `windows-targets` dependency and use [`raw-dylib`] directly [#627] - Update `wasi` dependency to v0.14 [#594] - Add `#[inline]` attribute to the inner functions [#596] - Update WASI and Emscripten links in the crate-level docs [#597] @@ -29,7 +29,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#570]: https://github.com/rust-random/getrandom/pull/570 [#572]: https://github.com/rust-random/getrandom/pull/572 [#591]: https://github.com/rust-random/getrandom/pull/591 -[#593]: https://github.com/rust-random/getrandom/pull/593 [#594]: https://github.com/rust-random/getrandom/pull/594 [#596]: https://github.com/rust-random/getrandom/pull/596 [#597]: https://github.com/rust-random/getrandom/pull/597 @@ -38,6 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#605]: https://github.com/rust-random/getrandom/pull/605 [#610]: https://github.com/rust-random/getrandom/pull/610 [#614]: https://github.com/rust-random/getrandom/pull/614 +[#627]: https://github.com/rust-random/getrandom/pull/627 +[`raw-dylib`]: https://doc.rust-lang.org/reference/items/external-blocks.html?highlight=link#dylib-versus-raw-dylib ## [0.3.1] - 2025-01-28 diff --git a/Cargo.lock b/Cargo.lock index 93df7a712..91a0cb2e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,7 +48,6 @@ dependencies = [ "wasi", "wasm-bindgen", "wasm-bindgen-test", - "windows-targets 0.53.0", ] [[package]] @@ -289,7 +288,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -298,30 +297,14 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -330,96 +313,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "wit-bindgen-rt" version = "0.39.0" diff --git a/Cargo.toml b/Cargo.toml index 4298ea0bc..abd0d79b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,10 +70,6 @@ libc = { version = "0.2.154", default-features = false } [target.'cfg(all(target_arch = "wasm32", target_os = "wasi", target_env = "p2"))'.dependencies] wasi = { version = "0.14", default-features = false } -# windows7 -[target.'cfg(all(windows, not(target_vendor = "win7"), not(getrandom_windows_legacy)))'.dependencies] -windows-targets = "0.53" - # wasm_js [target.'cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dependencies] wasm-bindgen = { version = "0.2.98", default-features = false, optional = true } diff --git a/build.rs b/build.rs index ea9baaaaa..14aaf0c80 100644 --- a/build.rs +++ b/build.rs @@ -40,7 +40,7 @@ fn main() { } // Use `RtlGenRandom` on older compiler versions since win7 targets - // were introduced only in Rust 1.78 + // TODO(MSRV 1.78): Remove this check let target_family = env::var_os("CARGO_CFG_TARGET_FAMILY").and_then(|f| f.into_string().ok()); if target_family.as_deref() == Some("windows") { /// Minor version of the Rust compiler in which win7 targets were inroduced diff --git a/src/backends/windows.rs b/src/backends/windows.rs index 2ab7beadb..b5cd504fe 100644 --- a/src/backends/windows.rs +++ b/src/backends/windows.rs @@ -26,13 +26,27 @@ 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 the windows-targets -// crate to link to it. -// -// TODO(MSRV 1.71): Migrate to linking as raw-dylib directly. -// https://github.com/joboet/rust/blob/5c1c72572479afe98734d5f78fa862abe662c41a/library/std/src/sys/pal/windows/c.rs#L119 -// https://github.com/microsoft/windows-rs/blob/0.60.0/crates/libs/targets/src/lib.rs -windows_targets::link!("bcryptprimitives.dll" "system" fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> i32); +// 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]) -> Result<(), Error> { @@ -42,6 +56,6 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // 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 == 1); + debug_assert!(result == TRUE); Ok(()) } From 526aff14f4c02aea4fcf9b7fccc02a11eac9e502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Sun, 9 Mar 2025 15:35:11 +0800 Subject: [PATCH 130/201] Add cygwin support (#626) Need https://github.com/rust-lang/rust/pull/137621 to test. --------- Co-authored-by: Joe Richey --- .github/workflows/build.yml | 3 +++ CHANGELOG.md | 2 ++ Cargo.toml | 3 ++- README.md | 2 ++ src/backends.rs | 1 + src/util_libc.rs | 2 +- 6 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ed9788d84..d0c2feb7a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -94,6 +94,9 @@ jobs: x86_64-wrs-vxworks, x86_64-unknown-dragonfly, x86_64-unknown-haiku, + # TODO: once libc support for cygwin is released + # https://github.com/rust-lang/libc/pull/4308 + # x86_64-pc-cygwin, ] steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index acfa3719d..b53ccd03f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `.cargo/config.toml` example in the crate-level docs [#591] - `getrandom_test_linux_without_fallback` configuration flag to test that file fallback is not triggered in the `linux_android_with_fallback` backend [#605] +- Cygwin support [#626] ### Changed - Remove `windows-targets` dependency and use [`raw-dylib`] directly [#627] @@ -37,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#605]: https://github.com/rust-random/getrandom/pull/605 [#610]: https://github.com/rust-random/getrandom/pull/610 [#614]: https://github.com/rust-random/getrandom/pull/614 +[#626]: https://github.com/rust-random/getrandom/pull/626 [#627]: https://github.com/rust-random/getrandom/pull/627 [`raw-dylib`]: https://doc.rust-lang.org/reference/items/external-blocks.html?highlight=link#dylib-versus-raw-dylib diff --git a/Cargo.toml b/Cargo.toml index abd0d79b5..e55cbb89f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ r-efi = { version = "5.1", default-features = false } libc = { version = "0.2.154", default-features = false } # getrandom -[target.'cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "hurd", target_os = "illumos", all(target_os = "horizon", target_arch = "arm")))'.dependencies] +[target.'cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "hurd", target_os = "illumos", target_os = "cygwin", all(target_os = "horizon", target_arch = "arm")))'.dependencies] libc = { version = "0.2.154", default-features = false } # netbsd @@ -87,6 +87,7 @@ check-cfg = [ 'cfg(getrandom_test_linux_fallback)', 'cfg(getrandom_test_linux_without_fallback)', 'cfg(getrandom_test_netbsd_fallback)', + 'cfg(target_os, values("cygwin"))', # TODO(MSRV 1.86): Remove this. ] [package.metadata.docs.rs] diff --git a/README.md b/README.md index 1c6cb3e8c..125daa087 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ fn get_random_u128() -> Result { | PS Vita | `*-vita-*` | [`getentropy`][19] | QNX Neutrino | `*‑nto-qnx*` | [`/dev/urandom`][14] (identical to `/dev/random`) | AIX | `*-ibm-aix` | [`/dev/urandom`][15] +| Cygwin | `*-cygwin` | [`getrandom`][20] (based on [`RtlGenRandom`]) Pull Requests that add support for new targets to `getrandom` are always welcome. @@ -351,6 +352,7 @@ dual licensed as above, without any additional terms or conditions. [17]: https://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getrandom [18]: https://github.com/rust3ds/shim-3ds/commit/b01d2568836dea2a65d05d662f8e5f805c64389d [19]: https://github.com/vitasdk/newlib/blob/2d869fe47aaf02b8e52d04e9a2b79d5b210fd016/newlib/libc/sys/vita/getentropy.c +[20]: https://github.com/cygwin/cygwin/blob/main/winsup/cygwin/libc/getentropy.cc [`ProcessPrng`]: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng [`RtlGenRandom`]: https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom diff --git a/src/backends.rs b/src/backends.rs index 82141a2bb..adf8a0d02 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -104,6 +104,7 @@ cfg_if! { 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"), diff --git a/src/util_libc.rs b/src/util_libc.rs index 800030139..24c53c0c9 100644 --- a/src/util_libc.rs +++ b/src/util_libc.rs @@ -2,7 +2,7 @@ use crate::Error; use core::mem::MaybeUninit; cfg_if! { - if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] { + 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; From a13ad84f89221199c8e046046675f15189f83dea Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 9 Mar 2025 20:46:38 +0300 Subject: [PATCH 131/201] Add built-in support for `*-linux-none` targets (#618) --- .github/workflows/build.yml | 1 + CHANGELOG.md | 2 ++ Cargo.toml | 2 +- src/backends.rs | 3 +++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d0c2feb7a..79dba1d04 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -94,6 +94,7 @@ jobs: x86_64-wrs-vxworks, x86_64-unknown-dragonfly, x86_64-unknown-haiku, + x86_64-unknown-linux-none, # TODO: once libc support for cygwin is released # https://github.com/rust-lang/libc/pull/4308 # x86_64-pc-cygwin, diff --git a/CHANGELOG.md b/CHANGELOG.md index b53ccd03f..05489ada0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `.cargo/config.toml` example in the crate-level docs [#591] - `getrandom_test_linux_without_fallback` configuration flag to test that file fallback is not triggered in the `linux_android_with_fallback` backend [#605] +- Built-in support for `*-linux-none` targets [#618] - Cygwin support [#626] ### Changed @@ -38,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#605]: https://github.com/rust-random/getrandom/pull/605 [#610]: https://github.com/rust-random/getrandom/pull/610 [#614]: https://github.com/rust-random/getrandom/pull/614 +[#618]: https://github.com/rust-random/getrandom/pull/618 [#626]: https://github.com/rust-random/getrandom/pull/626 [#627]: https://github.com/rust-random/getrandom/pull/627 [`raw-dylib`]: https://doc.rust-lang.org/reference/items/external-blocks.html?highlight=link#dylib-versus-raw-dylib diff --git a/Cargo.toml b/Cargo.toml index e55cbb89f..19fbc31c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ compiler_builtins = { version = "0.1", optional = true } core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" } # getrandom / linux_android_with_fallback -[target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(getrandom_backend = "custom", getrandom_backend = "linux_raw", getrandom_backend = "rdrand", getrandom_backend = "rndr"))))'.dependencies] +[target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(all(target_os = "linux", target_env = ""), getrandom_backend = "custom", getrandom_backend = "linux_raw", getrandom_backend = "rdrand", getrandom_backend = "rndr"))))'.dependencies] libc = { version = "0.2.154", default-features = false } # apple-other diff --git a/src/backends.rs b/src/backends.rs index adf8a0d02..a07cea2a3 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -38,6 +38,9 @@ cfg_if! { ); } } + } 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::*; From 5b9e58d84340c0576d9014f49e5930f5df755ac3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 21:02:41 +0300 Subject: [PATCH 132/201] build(deps): bump the all-deps group with 2 updates (#629) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 91a0cb2e1..0eed3e1c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,9 +84,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" [[package]] name = "proc-macro2" @@ -135,9 +135,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "syn" -version = "2.0.99" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", From 3a9172299b5c36791c60d3037355d5dec5fce439 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 18 Mar 2025 00:51:01 +0300 Subject: [PATCH 133/201] Release v0.3.2 (#617) ### Added - `efi_rng` opt-in backend [#570] - `linux_raw` opt-in backend [#572] - `.cargo/config.toml` example in the crate-level docs [#591] - `getrandom_test_linux_without_fallback` configuration flag to test that file fallback is not triggered in the `linux_android_with_fallback` backend [#605] - Built-in support for `*-linux-none` targets [#618] - Cygwin support [#626] ### Changed - Update `wasi` dependency to v0.14 [#594] - Add `#[inline]` attribute to the inner functions [#596] - Update WASI and Emscripten links in the crate-level docs [#597] - Do not use `dlsym` on MUSL targets in the `linux_android_with_fallback` backend [#602] - Remove `linux_android.rs` and use `getrandom.rs` instead [#603] - Always use `RtlGenRandom` on Windows targets when compiling with pre-1.78 Rust [#610] - Internal representation of the `Error` type [#614] - Remove `windows-targets` dependency and use [`raw-dylib`] directly [#627] ### Removed - `Error::INTERNAL_START` and `Error::CUSTOM_START` associated constants [#614] [#570]: https://github.com/rust-random/getrandom/pull/570 [#572]: https://github.com/rust-random/getrandom/pull/572 [#591]: https://github.com/rust-random/getrandom/pull/591 [#594]: https://github.com/rust-random/getrandom/pull/594 [#596]: https://github.com/rust-random/getrandom/pull/596 [#597]: https://github.com/rust-random/getrandom/pull/597 [#602]: https://github.com/rust-random/getrandom/pull/602 [#603]: https://github.com/rust-random/getrandom/pull/603 [#605]: https://github.com/rust-random/getrandom/pull/605 [#610]: https://github.com/rust-random/getrandom/pull/610 [#614]: https://github.com/rust-random/getrandom/pull/614 [#618]: https://github.com/rust-random/getrandom/pull/618 [#626]: https://github.com/rust-random/getrandom/pull/626 [#627]: https://github.com/rust-random/getrandom/pull/627 [`raw-dylib`]: https://doc.rust-lang.org/reference/items/external-blocks.html?highlight=link#dylib-versus-raw-dylib --- CHANGELOG.md | 4 ++-- Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05489ada0..9e6f2991b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.3.2] - UNRELEASED +## [0.3.2] - 2025-03-17 ### Added - `efi_rng` opt-in backend [#570] @@ -16,7 +16,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Cygwin support [#626] ### Changed -- Remove `windows-targets` dependency and use [`raw-dylib`] directly [#627] - Update `wasi` dependency to v0.14 [#594] - Add `#[inline]` attribute to the inner functions [#596] - Update WASI and Emscripten links in the crate-level docs [#597] @@ -24,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove `linux_android.rs` and use `getrandom.rs` instead [#603] - Always use `RtlGenRandom` on Windows targets when compiling with pre-1.78 Rust [#610] - Internal representation of the `Error` type [#614] +- Remove `windows-targets` dependency and use [`raw-dylib`] directly [#627] ### Removed - `Error::INTERNAL_START` and `Error::CUSTOM_START` associated constants [#614] diff --git a/Cargo.lock b/Cargo.lock index 0eed3e1c1..12e3551eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,7 +37,7 @@ checksum = "abc30f1766d387c35f2405e586d3e7a88230dc728ff78cd1d0bc59ae0b63154b" [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.2" dependencies = [ "cfg-if", "compiler_builtins", diff --git a/Cargo.toml b/Cargo.toml index 19fbc31c8..41b7a676d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "getrandom" -version = "0.3.1" +version = "0.3.2" edition = "2021" rust-version = "1.63" # Sync tests.yml and README.md. authors = ["The Rand Project Developers"] From 64118598f5d7b99dc0ad023f6f963d472f21f091 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 20 Mar 2025 18:26:30 +0300 Subject: [PATCH 134/201] Fix typo in `compile_error!` doc link (#632) --- src/backends.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/backends.rs b/src/backends.rs index a07cea2a3..c8e7d1c38 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -173,8 +173,9 @@ cfg_if! { https://docs.rs/getrandom/#webassembly-support" ); } else { - compile_error!("target is not supported. You may need to define \ - a custom backend see: \ - https://docs.rs/getrandom/#custom-backends"); + compile_error!( + "target is not supported. You may need to define a custom backend see: \ + https://docs.rs/getrandom/#custom-backend" + ); } } From db162168c91dc535e26e1e5da7974afbf41ed77a Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 21 Mar 2025 15:51:46 +0300 Subject: [PATCH 135/201] readme: fix invalid "configuration flags" link (#634) --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 125daa087..a0407d978 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ is not automatically supported since, from the target name alone, we cannot dedu which JavaScript interface should be used (or if JavaScript is available at all). To enable `getrandom`'s functionality on `wasm32-unknown-unknown` using the Web -Crypto methods [described above](#opt-in-backends) via [`wasm-bindgen`], do +Crypto methods [described above][opt-in] via [`wasm-bindgen`], do *both* of the following: - Use the `wasm_js` feature flag, i.e. @@ -138,7 +138,7 @@ Crypto methods [described above](#opt-in-backends) via [`wasm-bindgen`], do On its own, this only makes the backend available. (As a side effect this will make your `Cargo.lock` significantly larger if you are not already using [`wasm-bindgen`], but otherwise enabling this feature is harmless.) -- Set `RUSTFLAGS='--cfg getrandom_backend="wasm_js"'` ([see above](#opt-in-backends)). +- Set `RUSTFLAGS='--cfg getrandom_backend="wasm_js"'` ([see above][opt-in]). This backend supports both web browsers (main window and Web Workers) and Node.js (v19 or later) environments. @@ -147,9 +147,10 @@ and Node.js (v19 or later) environments. If this crate does not support your target out of the box or you have to use a non-default entropy source, then you can provide a custom implementation. -You need to enable the custom backend as described in the [configuration flags] -section. Next, you need to define an `extern` function with the following -signature: +You need to enable the custom backend as described in the +[opt-in backends][opt-in] section. + +Next, you need to define an `extern` function with the following signature: ```rust use getrandom::Error; @@ -375,6 +376,7 @@ dual licensed as above, without any additional terms or conditions. [platform-support]: https://doc.rust-lang.org/stable/rustc/platform-support.html [WASI]: https://github.com/WebAssembly/WASI [Emscripten]: https://emscripten.org +[opt-in]: #opt-in-backends [//]: # (licenses) From a6993bd59ffd6dc595b617dd2ea2419bcd8cb65c Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 21 Mar 2025 22:47:35 +0300 Subject: [PATCH 136/201] Add warnings for `wasm_js` (#635) --- Cargo.toml | 2 ++ README.md | 3 +++ 2 files changed, 5 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 41b7a676d..19c8ee526 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,8 @@ rustc-dep-of-std = ["dep:compiler_builtins", "dep:core"] # Optional backend: wasm_js # This flag enables the backend but does not select it. To use the backend, use # this flag *and* set getrandom_backend=wasm_js (see README). +# WARNING: It is highly recommended to enable this feature only for binary crates and tests, +# i.e. avoid unconditionally enabling it in library crates. wasm_js = ["dep:wasm-bindgen", "dep:js-sys"] [dependencies] diff --git a/README.md b/README.md index a0407d978..858247e64 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,9 @@ Crypto methods [described above][opt-in] via [`wasm-bindgen`], do This backend supports both web browsers (main window and Web Workers) and Node.js (v19 or later) environments. +WARNING: It is highly recommended to enable the `wasm_js` feature only for +binary crates and tests, i.e. avoid unconditionally enabling it in library crates. + ### Custom backend If this crate does not support your target out of the box or you have to use From 4f4057e59fd64cafadacd1a38839450a28765215 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 21:14:41 +0300 Subject: [PATCH 137/201] Update Cargo.lock (#637) --- Cargo.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12e3551eb..2299aaa1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.16" +version = "1.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" dependencies = [ "shlex", ] @@ -31,9 +31,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "compiler_builtins" -version = "0.1.151" +version = "0.1.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abc30f1766d387c35f2405e586d3e7a88230dc728ff78cd1d0bc59ae0b63154b" +checksum = "2153cf213eb259361567720ce55f6446f17acd0ccca87fb6dc05360578228a58" [[package]] name = "getrandom" @@ -62,15 +62,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.170" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "minicov" @@ -84,9 +84,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.0" +version = "1.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" [[package]] name = "proc-macro2" @@ -99,9 +99,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] From 34be1f9a24b08e766df8a967e4ef045840d0f91d Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 27 Mar 2025 03:34:08 +0300 Subject: [PATCH 138/201] ci: enable backtrace in tests (#640) This would give use more information from panicking tests, e.g. https://github.com/rust-lang/rust/issues/138984. --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 84b148b41..5eb194b48 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,6 +13,7 @@ permissions: env: CARGO_INCREMENTAL: 0 + RUST_BACKTRACE: 1 RUSTFLAGS: "-Dwarnings" jobs: From e56d4a19d3354e8a61d505e962d6d8da23534a7f Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 27 Mar 2025 17:25:25 +0300 Subject: [PATCH 139/201] Add crate version to docs.rs links used in `compile_error!`s (#639) --- CHANGELOG.md | 12 ++++++++++++ src/backends.rs | 18 +++++++++--------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e6f2991b..f706e194a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.3] - UNRELEASED + +### Changed +- Doc improvements [#632] [#634] [#635] +- Add crate version to docs.rs links used in `compile_error!`s [#639] + +[#632]: https://github.com/rust-random/getrandom/pull/632 +[#634]: https://github.com/rust-random/getrandom/pull/634 +[#635]: https://github.com/rust-random/getrandom/pull/635 +[#639]: https://github.com/rust-random/getrandom/pull/639 + ## [0.3.2] - 2025-03-17 ### Added @@ -566,6 +577,7 @@ Publish initial implementation. ## [0.0.0] - 2019-01-19 Publish an empty template library. +[0.3.3]: https://github.com/rust-random/getrandom/compare/v0.3.2...v0.3.3 [0.3.2]: https://github.com/rust-random/getrandom/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/rust-random/getrandom/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/rust-random/getrandom/compare/v0.2.15...v0.3.0 diff --git a/src/backends.rs b/src/backends.rs index c8e7d1c38..2c539df26 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -31,11 +31,11 @@ cfg_if! { mod wasm_js; pub use wasm_js::*; } else { - compile_error!( + compile_error!(concat!( "The \"wasm_js\" backend requires the `wasm_js` feature \ for `getrandom`. For more information see: \ - https://docs.rs/getrandom/#webassembly-support" - ); + https://docs.rs/getrandom/", env!("CARGO_PKG_VERSION"), "/#webassembly-support" + )); } } } else if #[cfg(all(target_os = "linux", target_env = ""))] { @@ -165,17 +165,17 @@ cfg_if! { mod rdrand; pub use rdrand::*; } else if #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))] { - compile_error!( + 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/#webassembly-support" - ); + https://docs.rs/getrandom/", env!("CARGO_PKG_VERSION"), "/#webassembly-support" + )); } else { - compile_error!( + compile_error!(concat!( "target is not supported. You may need to define a custom backend see: \ - https://docs.rs/getrandom/#custom-backend" - ); + https://docs.rs/getrandom/", env!("CARGO_PKG_VERSION"), "/#custom-backend" + )); } } From 05bf124591e7a51e1ab4798aa28dbc509c0641df Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 27 Mar 2025 17:54:07 +0300 Subject: [PATCH 140/201] ci: temporarily allow warnings in the `web` job (#642) Relevant `wasm-bindgen` issue: https://github.com/rustwasm/wasm-bindgen/issues/4463 --- .github/workflows/tests.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5eb194b48..b0605e044 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -248,17 +248,19 @@ jobs: fail-fast: false matrix: rust: + # Temporarily allow warnings (i.e. remove `-Dwarnings`) until `wasm-bindgen` fixes the bug: + # https://github.com/rustwasm/wasm-bindgen/issues/4463 - { description: Web, version: stable, - flags: '-Dwarnings --cfg getrandom_backend="wasm_js"', + flags: '--cfg getrandom_backend="wasm_js"', args: '--features=std,wasm_js', } - { description: Web with Atomics, version: nightly, components: rust-src, - flags: '-Dwarnings --cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory', + flags: '--cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory', args: '--features=std,wasm_js -Zbuild-std=panic_abort,std', } steps: From 58d768d1533bd33af3cf18b79ac5d0f5d8f2c598 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 27 Mar 2025 19:08:51 +0300 Subject: [PATCH 141/201] Use `cargo dinghy` v0.8.0 (#643) --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b0605e044..93f620e0d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -86,7 +86,7 @@ jobs: targets: aarch64-apple-ios-sim - name: Install precompiled cargo-dinghy run: | - VERSION=0.7.2 + VERSION=0.8.0 URL="https://github.com/sonos/dinghy/releases/download/${VERSION}/cargo-dinghy-macos-${VERSION}.tgz" wget -O - $URL | tar -xz --strip-components=1 -C ~/.cargo/bin - name: Check cargo-dinghy version. From a41d4f9dc0a93a39e4816906df10de8c5eba247b Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 27 Mar 2025 19:09:04 +0300 Subject: [PATCH 142/201] readme: fix CI badge link (#644) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 858247e64..b0e17d477 100644 --- a/README.md +++ b/README.md @@ -326,7 +326,7 @@ dual licensed as above, without any additional terms or conditions. [//]: # (badges) -[GitHub Actions]: https://github.com/rust-random/getrandom/actions?query=workflow:Tests+branch:master +[GitHub Actions]: https://github.com/rust-random/getrandom/actions?query=branch:master [Build Status]: https://github.com/rust-random/getrandom/actions/workflows/tests.yml/badge.svg?branch=master [crates.io]: https://crates.io/crates/getrandom [Crate]: https://img.shields.io/crates/v/getrandom From 6b7ce54a28e4b3d6301198bf44287f6591433542 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 20:19:48 +0300 Subject: [PATCH 143/201] Update Cargo.lock (#645) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2299aaa1e..4c2d54aa3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,9 +84,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "proc-macro2" From 70fe4d798dbae182456890417a5f9b5f4a0d590e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 21:08:12 +0300 Subject: [PATCH 144/201] Update Cargo.lock (#646) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c2d54aa3..9c459ad7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.17" +version = "1.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" dependencies = [ "shlex", ] From d2e34c541157be3945e3cb9ec136211a0e8a5d3a Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 13 Apr 2025 06:32:45 +0300 Subject: [PATCH 145/201] ci: re-enable NetBSD VM job (#647) --- .github/workflows/tests.yml | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 93f620e0d..3708113ce 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -207,23 +207,21 @@ jobs: pkg_add rust run: cargo test - # Rust installation currently fails: - # https://github.com/rust-random/getrandom/actions/runs/12590976993/job/35093395247 - # netbsd: - # name: NetBSD VM - # runs-on: ubuntu-24.04 - # steps: - # - uses: actions/checkout@v4 - # - name: Test in NetBSD - # uses: vmactions/netbsd-vm@v1 - # with: - # envs: 'RUSTFLAGS' - # usesh: true - # prepare: | - # /usr/sbin/pkg_add rust - # run: | - # cargo test - # RUSTFLAGS="--cfg getrandom_test_netbsd_fallback -D warnings" cargo test + netbsd: + name: NetBSD VM + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - name: Test in NetBSD + uses: vmactions/netbsd-vm@v1 + with: + envs: 'RUSTFLAGS' + usesh: true + prepare: | + /usr/sbin/pkg_add rust + run: | + cargo test + RUSTFLAGS="--cfg getrandom_test_netbsd_fallback -D warnings" cargo test # This job currently fails: # https://github.com/rust-random/getrandom/actions/runs/11405005618/job/31735653874?pr=528 From eff129c4179f17c46c930f4f8af027425c7f659a Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 13 Apr 2025 07:13:10 +0300 Subject: [PATCH 146/201] ci: remove DragonFly BSD VM job (#648) --- .github/workflows/tests.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3708113ce..077c7740a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -223,22 +223,6 @@ jobs: cargo test RUSTFLAGS="--cfg getrandom_test_netbsd_fallback -D warnings" cargo test - # This job currently fails: - # https://github.com/rust-random/getrandom/actions/runs/11405005618/job/31735653874?pr=528 - # dragonflybsd: - # name: DragonflyBSD VM - # runs-on: ubuntu-24.04 - # steps: - # - uses: actions/checkout@v4 - # - name: Test in DragonflyBSD - # uses: vmactions/dragonflybsd-vm@v1 - # with: - # envs: 'RUSTFLAGS' - # usesh: true - # prepare: | - # pkg install -y rust - # run: cargo test - web: name: ${{ matrix.rust.description }} runs-on: ubuntu-24.04 From 27a48b2c3660899fb637c26541ee06f476fe25e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 20:34:36 -0700 Subject: [PATCH 147/201] build(deps): bump the all-deps group with 2 updates (#649) Bumps the all-deps group with 2 updates: [compiler_builtins](https://github.com/rust-lang/compiler-builtins) and [cc](https://github.com/rust-lang/cc-rs). Updates `compiler_builtins` from 0.1.152 to 0.1.153
Release notes

Sourced from compiler_builtins's releases.

compiler_builtins-v0.1.153

Other

  • Remove a mention of force-soft-float in build.rs
  • Revert "Disable f16 on AArch64 without the neon feature"
  • Skip No More!
  • avoid out-of-bounds accesses (#799)
Commits
  • 9978a8b chore: release v0.1.153
  • cd6f4f6 Update the libm submodule
  • c887852 Remove a mention of force-soft-float in build.rs
  • 1901c41 Revert "Disable f16 on AArch64 without the neon feature"
  • f1b9055 avr: Skip No More!
  • 4df7a8d copy_misaligned_words: avoid out-of-bounds accesses (#799)
  • 974d721 Clean up icount benchmarks
  • e49ff02 Add benchmarks using iai-callgrind
  • See full diff in compare view

Updates `cc` from 1.2.18 to 1.2.19
Release notes

Sourced from cc's releases.

cc-v1.2.19

Other

  • Fix musl compilation: Add musl as a prefix fallback (#1455)
Changelog

Sourced from cc's changelog.

1.2.19 - 2025-04-11

Other

  • Fix musl compilation: Add musl as a prefix fallback (#1455)
Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c459ad7d..160762e25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.18" +version = "1.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" dependencies = [ "shlex", ] @@ -31,9 +31,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "compiler_builtins" -version = "0.1.152" +version = "0.1.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2153cf213eb259361567720ce55f6446f17acd0ccca87fb6dc05360578228a58" +checksum = "926ef6a360c15a911023352fd6969c51605d70495406f735beb1ca0257448e59" [[package]] name = "getrandom" From aaff261f72fd2be75ef312f944ff4abe4dae259e Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 17 Apr 2025 18:41:09 +0400 Subject: [PATCH 148/201] changelog: fix v0.3.3 link (#650) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f706e194a..936b07330 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -577,7 +577,7 @@ Publish initial implementation. ## [0.0.0] - 2019-01-19 Publish an empty template library. -[0.3.3]: https://github.com/rust-random/getrandom/compare/v0.3.2...v0.3.3 +[0.3.3]: https://github.com/rust-random/getrandom/compare/v0.3.2...HEAD [0.3.2]: https://github.com/rust-random/getrandom/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/rust-random/getrandom/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/rust-random/getrandom/compare/v0.2.15...v0.3.0 From 07b0c124299e82f602754b1e64952d621ce21044 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Apr 2025 21:13:17 +0400 Subject: [PATCH 149/201] Update Cargo.lock (#652) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 160762e25..7851c122e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,9 +31,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "compiler_builtins" -version = "0.1.153" +version = "0.1.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926ef6a360c15a911023352fd6969c51605d70495406f735beb1ca0257448e59" +checksum = "341e0830ca6170a4fcf02e92e57daf4b6f10142d48da32a547023867a6c8b35e" [[package]] name = "getrandom" @@ -90,9 +90,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] From 189dcb350b15dc97221181a6d01094754558e84e Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 22 Apr 2025 23:40:22 +0400 Subject: [PATCH 150/201] Add changelog entry for v0.2.16 (#657) --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 936b07330..8fa88b593 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -127,6 +127,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#571]: https://github.com/rust-random/getrandom/pull/571 [#574]: https://github.com/rust-random/getrandom/pull/574 +## [0.2.16] - 2025-04-22 +### Added +- Cygwin support (backport of [#626]) [#654] + +[#654]: https://github.com/rust-random/getrandom/pull/654 + ## [0.2.15] - 2024-05-06 ### Added - Apple visionOS support [#410] @@ -581,6 +587,7 @@ Publish an empty template library. [0.3.2]: https://github.com/rust-random/getrandom/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/rust-random/getrandom/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/rust-random/getrandom/compare/v0.2.15...v0.3.0 +[0.2.16]: https://github.com/rust-random/getrandom/compare/v0.2.16...v0.2.16 [0.2.15]: https://github.com/rust-random/getrandom/compare/v0.2.14...v0.2.15 [0.2.14]: https://github.com/rust-random/getrandom/compare/v0.2.13...v0.2.14 [0.2.13]: https://github.com/rust-random/getrandom/compare/v0.2.12...v0.2.13 From 68aecab25f0307030bcc90ebbab5adfa4be3eea6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Apr 2025 21:17:55 +0300 Subject: [PATCH 151/201] Update Cargo.lock (#659) --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7851c122e..eb972017a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.19" +version = "1.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" dependencies = [ "shlex", ] @@ -31,9 +31,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "compiler_builtins" -version = "0.1.155" +version = "0.1.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "341e0830ca6170a4fcf02e92e57daf4b6f10142d48da32a547023867a6c8b35e" +checksum = "c1ffbd2789fe5bb95b96a2e22cbe3128239dc46ff0374e0d38e9f102062d7055" [[package]] name = "getrandom" @@ -135,9 +135,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", From f0ff6e257631fbe2b16d2a46ca02292acf83c9f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 11:26:54 -0700 Subject: [PATCH 152/201] build(deps): bump the all-deps group with 2 updates (#662) Bumps the all-deps group with 2 updates: [compiler_builtins](https://github.com/rust-lang/compiler-builtins) and [cc](https://github.com/rust-lang/cc-rs). Updates `compiler_builtins` from 0.1.156 to 0.1.157
Release notes

Sourced from compiler_builtins's releases.

compiler_builtins-v0.1.157

Other

  • Use runtime feature detection for fma routines on x86
Commits
  • 257dd48 chore: release
  • a2f6440 Use runtime feature detection for fma routines on x86
  • 6e4255a Rename the i686 module to x86
  • f83962e update-api-list: Match subdirectories within arch
  • 725484e fmaf: Add a test case from a MinGW failure
  • 7ccb126 builtins-test: Remove no_mangle from eh_personality
  • f456aa8 Refactor the fma modules
  • 91963f5 Move fma implementations to mod generic
  • 99b4c19 Resolve unnecessary_transmutes lints
  • fdbefb3 Warn on unsafe_op_in_unsafe_fn by default
  • Additional commits viewable in compare view

Updates `cc` from 1.2.20 to 1.2.21
Release notes

Sourced from cc's releases.

cc-v1.2.21

Other

  • Fix wasm32-unknown-unknown by passing -c (#1424)
Changelog

Sourced from cc's changelog.

1.2.21 - 2025-05-02

Other

  • Fix wasm32-unknown-unknown by passing -c (#1424)
Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb972017a..0b0d7501f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.20" +version = "1.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" +checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" dependencies = [ "shlex", ] @@ -31,9 +31,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "compiler_builtins" -version = "0.1.156" +version = "0.1.157" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ffbd2789fe5bb95b96a2e22cbe3128239dc46ff0374e0d38e9f102062d7055" +checksum = "74f103f5a97b25e3ed7134dee586e90bbb0496b33ba41816f0e7274e5bb73b50" [[package]] name = "getrandom" From 74e53dabeb9359e63e9be7d6cf0eb468a64523d5 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 6 May 2025 15:12:14 +0000 Subject: [PATCH 153/201] Fix error handling in WASI p1 (#661) --- CHANGELOG.md | 4 ++++ src/backends/wasi_p1.rs | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fa88b593..799261b78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Doc improvements [#632] [#634] [#635] - Add crate version to docs.rs links used in `compile_error!`s [#639] +## Fixed +- Error handling in WASI p1 [#661] + [#632]: https://github.com/rust-random/getrandom/pull/632 [#634]: https://github.com/rust-random/getrandom/pull/634 [#635]: https://github.com/rust-random/getrandom/pull/635 [#639]: https://github.com/rust-random/getrandom/pull/639 +[#661]: https://github.com/rust-random/getrandom/pull/661 ## [0.3.2] - 2025-03-17 diff --git a/src/backends/wasi_p1.rs b/src/backends/wasi_p1.rs index 76dbc6d0a..25b5ca3b7 100644 --- a/src/backends/wasi_p1.rs +++ b/src/backends/wasi_p1.rs @@ -11,6 +11,10 @@ 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]) -> Result<(), Error> { // Based on the wasi code: @@ -21,6 +25,8 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let ret = unsafe { random_get(dest.as_mut_ptr() as i32, dest.len() as i32) }; match ret { 0 => Ok(()), - code => Err(Error::from_neg_error_code(code)), + // 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), } } From 4804becaf5916517edec1b812bb6514569ae471c Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 9 May 2025 12:42:10 +0300 Subject: [PATCH 154/201] Release v0.3.3 (#663) ### Changed - Doc improvements [#632] [#634] [#635] - Add crate version to docs.rs links used in `compile_error!`s [#639] ## Fixed - Error handling in WASI p1 [#661] [#632]: https://github.com/rust-random/getrandom/pull/632 [#634]: https://github.com/rust-random/getrandom/pull/634 [#635]: https://github.com/rust-random/getrandom/pull/635 [#639]: https://github.com/rust-random/getrandom/pull/639 [#661]: https://github.com/rust-random/getrandom/pull/661 --- CHANGELOG.md | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 799261b78..fbfe1d6db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.3.3] - UNRELEASED +## [0.3.3] - 2025-05-09 ### Changed - Doc improvements [#632] [#634] [#635] @@ -587,11 +587,11 @@ Publish initial implementation. ## [0.0.0] - 2019-01-19 Publish an empty template library. -[0.3.3]: https://github.com/rust-random/getrandom/compare/v0.3.2...HEAD +[0.3.3]: https://github.com/rust-random/getrandom/compare/v0.3.2...v0.3.3 [0.3.2]: https://github.com/rust-random/getrandom/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/rust-random/getrandom/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/rust-random/getrandom/compare/v0.2.15...v0.3.0 -[0.2.16]: https://github.com/rust-random/getrandom/compare/v0.2.16...v0.2.16 +[0.2.16]: https://github.com/rust-random/getrandom/compare/v0.2.15...v0.2.16 [0.2.15]: https://github.com/rust-random/getrandom/compare/v0.2.14...v0.2.15 [0.2.14]: https://github.com/rust-random/getrandom/compare/v0.2.13...v0.2.14 [0.2.13]: https://github.com/rust-random/getrandom/compare/v0.2.12...v0.2.13 @@ -607,7 +607,7 @@ Publish an empty template library. [0.2.3]: https://github.com/rust-random/getrandom/compare/v0.2.2...v0.2.3 [0.2.2]: https://github.com/rust-random/getrandom/compare/v0.2.1...v0.2.2 [0.2.1]: https://github.com/rust-random/getrandom/compare/v0.2.0...v0.2.1 -[0.2.0]: https://github.com/rust-random/getrandom/compare/v0.1.15...v0.2.0 +[0.2.0]: https://github.com/rust-random/getrandom/compare/v0.1.16...v0.2.0 [0.1.16]: https://github.com/rust-random/getrandom/compare/v0.1.15...v0.1.16 [0.1.15]: https://github.com/rust-random/getrandom/compare/v0.1.14...v0.1.15 [0.1.14]: https://github.com/rust-random/getrandom/compare/v0.1.13...v0.1.14 diff --git a/Cargo.toml b/Cargo.toml index 19c8ee526..371bc817b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "getrandom" -version = "0.3.2" +version = "0.3.3" edition = "2021" rust-version = "1.63" # Sync tests.yml and README.md. authors = ["The Rand Project Developers"] From 82396406b28f23ba86e3e511d34a4f5dab0fda08 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 9 May 2025 02:52:27 -0700 Subject: [PATCH 155/201] Update Cargo.lock with updated version (#664) This release (instead of #663) will be what we tag as v0.3.3 Signed-off-by: Joe Richey --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 0b0d7501f..c27e9a5b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,7 +37,7 @@ checksum = "74f103f5a97b25e3ed7134dee586e90bbb0496b33ba41816f0e7274e5bb73b50" [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" dependencies = [ "cfg-if", "compiler_builtins", From 35e17e577cb52e01831baa367a8900a3ec542592 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 23:47:05 +0300 Subject: [PATCH 156/201] Update Cargo.lock (#665) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c27e9a5b8..cd0dece9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.21" +version = "1.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" +checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" dependencies = [ "shlex", ] @@ -31,9 +31,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "compiler_builtins" -version = "0.1.157" +version = "0.1.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f103f5a97b25e3ed7134dee586e90bbb0496b33ba41816f0e7274e5bb73b50" +checksum = "448068da8f2326b2a0472353cb401dd8795a89c007ef30fff90f50706e862e72" [[package]] name = "getrandom" From 9583603e5e5c0992f8270d3475fdd67f8e43984f Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 19 May 2025 03:23:43 -0700 Subject: [PATCH 157/201] Fix Web CI (#668) - Re-enable Warnings for web tests - Add `RUSTDOCFLAGS` when using custom backends - Replace broken PowerPC target with RISC-V target --- .github/workflows/tests.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 077c7740a..8132b61eb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -163,7 +163,10 @@ jobs: # TODO: add Android tests back when the cross cuts a new release. # See: https://github.com/cross-rs/cross/issues/1222 # aarch64-linux-android, - powerpc-unknown-linux-gnu, + # This target is currently broken: + # https://github.com/rust-random/getrandom/actions/runs/15109500597/job/42465556156 + #powerpc-unknown-linux-gnu, + riscv64gc-unknown-linux-gnu, # This target is currently broken: # https://github.com/rust-random/getrandom/actions/runs/12949235459/job/36119546920 #wasm32-unknown-emscripten, @@ -230,19 +233,17 @@ jobs: fail-fast: false matrix: rust: - # Temporarily allow warnings (i.e. remove `-Dwarnings`) until `wasm-bindgen` fixes the bug: - # https://github.com/rustwasm/wasm-bindgen/issues/4463 - { description: Web, version: stable, - flags: '--cfg getrandom_backend="wasm_js"', + flags: '-Dwarnings --cfg getrandom_backend="wasm_js"', args: '--features=std,wasm_js', } - { description: Web with Atomics, version: nightly, components: rust-src, - flags: '--cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory', + flags: '-Dwarnings --cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory', args: '--features=std,wasm_js -Zbuild-std=panic_abort,std', } steps: @@ -262,31 +263,37 @@ jobs: - name: Test (Node) env: RUSTFLAGS: ${{ matrix.rust.flags }} + RUSTDOCFLAGS: ${{ matrix.rust.flags }} run: wasm-pack test --node -- ${{ matrix.rust.args }} - name: Test (Firefox) env: WASM_BINDGEN_USE_BROWSER: 1 RUSTFLAGS: ${{ matrix.rust.flags }} + RUSTDOCFLAGS: ${{ matrix.rust.flags }} run: wasm-pack test --headless --firefox -- ${{ matrix.rust.args }} - name: Test (Chrome) env: WASM_BINDGEN_USE_BROWSER: 1 RUSTFLAGS: ${{ matrix.rust.flags }} + RUSTDOCFLAGS: ${{ matrix.rust.flags }} run: wasm-pack test --headless --chrome -- ${{ matrix.rust.args }} - name: Test (dedicated worker) env: WASM_BINDGEN_USE_DEDICATED_WORKER: 1 RUSTFLAGS: ${{ matrix.rust.flags }} + RUSTDOCFLAGS: ${{ matrix.rust.flags }} run: wasm-pack test --headless --firefox -- ${{ matrix.rust.args }} - name: Test (shared worker) env: WASM_BINDGEN_USE_SHARED_WORKER: 1 RUSTFLAGS: ${{ matrix.rust.flags }} + RUSTDOCFLAGS: ${{ matrix.rust.flags }} run: wasm-pack test --headless --firefox -- ${{ matrix.rust.args }} - name: Test (service worker) env: WASM_BINDGEN_USE_SERVICE_WORKER: 1 RUSTFLAGS: ${{ matrix.rust.flags }} + RUSTDOCFLAGS: ${{ matrix.rust.flags }} # Firefox doesn't support module service workers and therefor can't import scripts run: wasm-pack test --headless --chrome -- ${{ matrix.rust.args }} From d4302b45a43c86d8dbfb77e28d39aaf158b4388f Mon Sep 17 00:00:00 2001 From: David Sherret Date: Mon, 19 May 2025 12:45:54 -0400 Subject: [PATCH 158/201] Add `unsupported` opt-in backend (#667) The backend always returns `Err(Error::UNSUPPORTED)`. --- .github/workflows/build.yml | 13 +++++++++++++ CHANGELOG.md | 8 ++++++++ Cargo.toml | 2 +- README.md | 22 +++++++++------------- src/backends.rs | 3 +++ src/backends/unsupported.rs | 9 +++++++++ 6 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 src/backends/unsupported.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 79dba1d04..53144945e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -273,3 +273,16 @@ jobs: - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom" run: cargo build --target riscv32i-unknown-none-elf + + unsupported: + name: Runtime error + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + targets: wasm32-unknown-unknown + - uses: Swatinem/rust-cache@v2 + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="unsupported" + run: cargo build --target wasm32-unknown-unknown diff --git a/CHANGELOG.md b/CHANGELOG.md index fbfe1d6db..f51c2b59b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.4] - UNRELEASED + +### Added +- `unsupported` opt-in backend [#667] + +[#667]: https://github.com/rust-random/getrandom/pull/667 + ## [0.3.3] - 2025-05-09 ### Changed @@ -587,6 +594,7 @@ Publish initial implementation. ## [0.0.0] - 2019-01-19 Publish an empty template library. +[0.3.4]: https://github.com/rust-random/getrandom/compare/v0.3.3...HEAD [0.3.3]: https://github.com/rust-random/getrandom/compare/v0.3.2...v0.3.3 [0.3.2]: https://github.com/rust-random/getrandom/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/rust-random/getrandom/compare/v0.3.0...v0.3.1 diff --git a/Cargo.toml b/Cargo.toml index 371bc817b..4a982ee7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,7 +83,7 @@ wasm-bindgen-test = "0.3" [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(getrandom_backend, values("custom", "efi_rng", "rdrand", "rndr", "linux_getrandom", "linux_raw", "wasm_js"))', + 'cfg(getrandom_backend, values("custom", "efi_rng", "rdrand", "rndr", "linux_getrandom", "linux_raw", "wasm_js", "unsupported"))', 'cfg(getrandom_msan)', 'cfg(getrandom_windows_legacy)', 'cfg(getrandom_test_linux_fallback)', diff --git a/README.md b/README.md index b0e17d477..293eb88a1 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ of randomness based on their specific needs: | `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown`, `wasm32v1-none` | [`Crypto.getRandomValues`]. Requires feature `wasm_js` ([see below](#webassembly-support)). | `efi_rng` | UEFI | `*-unknown‑uefi` | [`EFI_RNG_PROTOCOL`] with `EFI_RNG_ALGORITHM_RAW` (requires `std` and Nigthly compiler) | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) +| `unsupported` | All targets | `*` | Always returns `Err(Error::UNSUPPORTED)` (see [unsupported backend]) Opt-in backends can be enabled using the `getrandom_backend` configuration flag. The flag can be set either by specifying the `rustflags` field in [`.cargo/config.toml`]: @@ -203,20 +204,14 @@ unsafe extern "Rust" fn __getrandom_v03_custom( } ``` -If you are confident that `getrandom` is not used in your project, but -it gets pulled nevertheless by one of your dependencies, then you can -use the following custom backend, which always returns the "unsupported" error: -```rust -use getrandom::Error; +### Unsupported backend -#[no_mangle] -unsafe extern "Rust" fn __getrandom_v03_custom( - dest: *mut u8, - len: usize, -) -> Result<(), Error> { - Err(Error::UNSUPPORTED) -} -``` +In some rare scenarios, you might be compiling this crate for an unsupported +target (e.g. `wasm32-unknown-unknown`), but this crate's functionality +is not actually used by your code. If you are confident that `getrandom` is +not used in your project, but it gets pulled nevertheless by one of your +dependencies, then you can enable the `unsupported` backend, which always +returns `Err(Error::UNSUPPORTED)`. ### Platform Support @@ -373,6 +368,7 @@ dual licensed as above, without any additional terms or conditions. [`get-random-u64`]: https://github.com/WebAssembly/WASI/blob/v0.2.1/wasip2/random/random.wit#L23-L28 [configuration flags]: #configuration-flags [custom backend]: #custom-backend +[unsupported backend]: #unsupported-backend [`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen [`module`]: https://rustwasm.github.io/wasm-bindgen/reference/attributes/on-js-imports/module.html [`sys_read_entropy`]: https://github.com/hermit-os/kernel/blob/315f58ff5efc81d9bf0618af85a59963ff55f8b1/src/syscalls/entropy.rs#L47-L55 diff --git a/src/backends.rs b/src/backends.rs index 2c539df26..dbe934565 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -38,6 +38,9 @@ cfg_if! { )); } } + } else if #[cfg(getrandom_backend = "unsupported")] { + mod unsupported; + pub use unsupported::*; } else if #[cfg(all(target_os = "linux", target_env = ""))] { mod linux_raw; pub use linux_raw::*; diff --git a/src/backends/unsupported.rs b/src/backends/unsupported.rs new file mode 100644 index 000000000..4ea381fc4 --- /dev/null +++ b/src/backends/unsupported.rs @@ -0,0 +1,9 @@ +//! Implementation that errors at runtime. +use crate::Error; +use core::mem::MaybeUninit; + +pub use crate::util::{inner_u32, inner_u64}; + +pub fn fill_inner(_dest: &mut [MaybeUninit]) -> Result<(), Error> { + Err(Error::UNSUPPORTED) +} From 2cf460252aaa897453801965e3e7c1cbf301d04d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 20:01:43 +0300 Subject: [PATCH 159/201] Update Cargo.lock (#669) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd0dece9e..565926899 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bumpalo" @@ -16,9 +16,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.22" +version = "1.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" +checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" dependencies = [ "shlex", ] From aecbb3af3377089490525ccba128ede233e7b365 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 May 2025 20:26:13 +0300 Subject: [PATCH 160/201] Update Cargo.lock (#673) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 565926899..365634fc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.23" +version = "1.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" +checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" dependencies = [ "shlex", ] From c5b35fd9ab718a6f700d428729f54d7694a4446c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Jun 2025 20:00:21 +0300 Subject: [PATCH 161/201] Update Cargo.lock (#676) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 365634fc0..b3925295b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.24" +version = "1.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" +checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" dependencies = [ "shlex", ] @@ -31,9 +31,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "compiler_builtins" -version = "0.1.159" +version = "0.1.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "448068da8f2326b2a0472353cb401dd8795a89c007ef30fff90f50706e862e72" +checksum = "6376049cfa92c0aa8b9ac95fae22184b981c658208d4ed8a1dc553cd83612895" [[package]] name = "getrandom" From c346aac01c0524cd4316608eb9c631dccc4c3103 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Tue, 3 Jun 2025 11:53:57 -0700 Subject: [PATCH 162/201] CI: Update Rust Nightly to a very recent version (#679) Address a Nightly Clippy complaint and update to the nightly-2025-06-01 toolchain. This allows us to validate upcoming changes. This will help with filing issues against rust-lang/rust for recent Nightly releases that affect us. --- .github/workflows/build.yml | 4 ++-- .github/workflows/nopanic.yaml | 2 +- .github/workflows/tests.yml | 4 ++-- .github/workflows/workspace.yml | 4 ++-- src/error.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 53144945e..bf51e6ea5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -156,7 +156,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: - toolchain: nightly-2025-02-15 + toolchain: nightly-2025-06-01 components: rust-src - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw" @@ -190,7 +190,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: targets: ${{ matrix.target.target }} - toolchain: nightly-2024-10-24 + toolchain: nightly-2025-06-01 components: rust-src - uses: Swatinem/rust-cache@v2 - name: Build diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index 7ad20ce04..23ab7ca53 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -140,7 +140,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: - toolchain: nightly-2024-10-14 + toolchain: nightly-2025-06-01 components: rust-src - run: cargo build --release - run: cargo build --release --target=x86_64-win7-windows-msvc -Zbuild-std="std,panic_abort" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8132b61eb..58b8ec65f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -133,7 +133,7 @@ jobs: # Win7 targets are Tier3, so pin a nightly where libstd builds. - uses: dtolnay/rust-toolchain@master with: - toolchain: nightly-2024-05-20 + toolchain: nightly-2025-06-01 components: rust-src - uses: Swatinem/rust-cache@v2 - run: cargo test --target=x86_64-win7-windows-msvc -Z build-std --features=std @@ -146,7 +146,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: - toolchain: nightly-2024-10-08 + toolchain: nightly-2025-06-01 components: rust-src - env: RUSTFLAGS: -Dwarnings -Zsanitizer=memory diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 9f379b187..9ab4e4dae 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -23,7 +23,7 @@ jobs: # Fixed Nigthly version is used to prevent # CI failures which are not relevant to PR changes # on introduction of new Clippy lints. - toolchain: nightly-2024-10-08 + toolchain: nightly-2025-06-01 components: clippy,rust-src - name: std feature run: cargo clippy --features std @@ -110,7 +110,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: # We need Nightly for doc_auto_cfg - toolchain: nightly-2024-09-04 + toolchain: nightly-2025-06-01 - uses: Swatinem/rust-cache@v2 - name: Generate Docs env: diff --git a/src/error.rs b/src/error.rs index 13f3121f6..284533d10 100644 --- a/src/error.rs +++ b/src/error.rs @@ -200,7 +200,7 @@ impl fmt::Display for Error { if #[cfg(feature = "std")] { std::io::Error::from_raw_os_error(errno).fmt(f) } else { - write!(f, "OS Error: {}", errno) + write!(f, "OS Error: {errno}") } } } else if let Some(desc) = self.internal_desc() { From ecd4881770265b056a204e1b7e047f899480d478 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Tue, 3 Jun 2025 12:05:52 -0700 Subject: [PATCH 163/201] CI: Test w/ Memory Sanitizer on AArch64 Linux (#680) --- .github/workflows/tests.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 58b8ec65f..d61bee13a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -139,8 +139,24 @@ jobs: - run: cargo test --target=x86_64-win7-windows-msvc -Z build-std --features=std - run: cargo test --target=i686-win7-windows-msvc -Z build-std --features=std - sanitizer: - name: Sanitizer + sanitizer-linux-aarch64: + name: Sanitizer Linux AArch64 + # MemorySanitizer won't run in QEMU so we can't run it in cross: + # https://github.com/llvm/llvm-project/issues/65144 + runs-on: ubuntu-24.04-arm + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: nightly-2025-06-01 + components: rust-src + - env: + RUSTFLAGS: -Dwarnings -Zsanitizer=memory + RUSTDOCFLAGS: -Dwarnings -Zsanitizer=memory + run: cargo test -Zbuild-std --target=aarch64-unknown-linux-gnu + + sanitizer-linux-x86_64: + name: Sanitizer Linux x86_64 runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 From 5f6d231a76bca3e6c9ce55340f0da4477d851aab Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Wed, 4 Jun 2025 07:17:00 -0700 Subject: [PATCH 164/201] CI: Test all backends using Memory Sanitizer on Linux AArch64/x86_64 (#682) --- .github/workflows/tests.yml | 70 ++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d61bee13a..bedcd3284 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -139,35 +139,65 @@ jobs: - run: cargo test --target=x86_64-win7-windows-msvc -Z build-std --features=std - run: cargo test --target=i686-win7-windows-msvc -Z build-std --features=std - sanitizer-linux-aarch64: - name: Sanitizer Linux AArch64 - # MemorySanitizer won't run in QEMU so we can't run it in cross: - # https://github.com/llvm/llvm-project/issues/65144 - runs-on: ubuntu-24.04-arm - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: nightly-2025-06-01 - components: rust-src - - env: - RUSTFLAGS: -Dwarnings -Zsanitizer=memory - RUSTDOCFLAGS: -Dwarnings -Zsanitizer=memory - run: cargo test -Zbuild-std --target=aarch64-unknown-linux-gnu + sanitizer-linux: + name: Sanitizer Linux + runs-on: ${{ matrix.runner }} + strategy: + matrix: + arch: [ + "aarch64", + "x86_64", + ] + include: + # MemorySanitizer won't run in QEMU so we can't run it in cross: + # https://github.com/llvm/llvm-project/issues/65144 + - arch: aarch64 + runner: ubuntu-24.04-arm - sanitizer-linux-x86_64: - name: Sanitizer Linux x86_64 - runs-on: ubuntu-24.04 + - arch: x86_64 + runner: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: toolchain: nightly-2025-06-01 components: rust-src - - env: + - name: default configuration + env: RUSTFLAGS: -Dwarnings -Zsanitizer=memory RUSTDOCFLAGS: -Dwarnings -Zsanitizer=memory - run: cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu + run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + - name: --cfg getrandom_backend="linux_getrandom" + env: + RUSTFLAGS: --cfg getrandom_backend="linux_getrandom" -Dwarnings -Zsanitizer=memory + RUSTDOCFLAGS: --cfg getrandom_backend="linux_getrandom" -Dwarnings -Zsanitizer=memory + run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + - name: --cfg getrandom_backend="linux_raw" + env: + RUSTFLAGS: --cfg getrandom_backend="linux_raw" -Dwarnings -Zsanitizer=memory + RUSTDOCFLAGS: --cfg getrandom_backend="linux_raw" -Dwarnings -Zsanitizer=memory + run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + - name: --cfg getrandom_backend="linux_fallback" + env: + RUSTFLAGS: --cfg getrandom_backend="linux_fallback" -Dwarnings -Zsanitizer=memory + RUSTDOCFLAGS: --cfg getrandom_backend="linux_fallback" -Dwarnings -Zsanitizer=memory + run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + - if: ${{ matrix.arch == 'x86_64' }} + name: --cfg getrandom_backend="rdrand" + env: + RUSTFLAGS: --cfg getrandom_backend="rdrand" -Dwarnings -Zsanitizer=memory + RUSTDOCFLAGS: --cfg getrandom_backend="rdrand" -Dwarnings -Zsanitizer=memory + run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + - name: --cfg getrandom_test_linux_fallback + env: + RUSTFLAGS: --cfg getrandom_test_linux_fallback -Dwarnings -Zsanitizer=memory + RUSTDOCFLAGS: --cfg getrandom_test_linux_fallback -Dwarnings -Zsanitizer=memory + run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + - name: --cfg getrandom_test_linux_without_fallback + env: + RUSTFLAGS: --cfg getrandom_test_linux_without_fallback -Dwarnings -Zsanitizer=memory + RUSTDOCFLAGS: --cfg getrandom_test_linux_without_fallback -Dwarnings -Zsanitizer=memory + run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu cross: name: Cross From 79ee57a52becbd37b3ddeb7d4da97397fac6b19d Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Wed, 4 Jun 2025 07:18:17 -0700 Subject: [PATCH 165/201] Implement Memory Sanitizer unpoisoning more precisely. (#678) Avoid masking bugs in backends that return `Ok` without writing the entire output buffer. For built-in backends, this makes MSAN useful for validating the correctness of the control flow of each backend. For custom backends in particular, this makes MSAN useful for validating that a custom backend actually filled the entire output buffer when it returned `Ok`. When MSAN is enabled, this is a breaking change for a custom backend that is implemented in a way that avoids built-in unpoisoning provided by Rust/libc/MSAN.. Since MSAN support is unstable in Rust anyway, I think this is acceptable breakage. As a side effect, this minimizes the number of configurations that reference the `__msan_unpoison` symbol unnecessarily. --- src/backends.rs | 9 +++- src/backends/getrandom.rs | 10 +++- src/backends/linux_android_with_fallback.rs | 6 ++- src/backends/linux_raw.rs | 5 +- src/backends/sanitizer.rs | 59 +++++++++++++++++++++ src/lib.rs | 7 +-- 6 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 src/backends/sanitizer.rs diff --git a/src/backends.rs b/src/backends.rs index dbe934565..bf0381d26 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -2,7 +2,8 @@ //! //! This module should provide `fill_inner` with the signature //! `fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error>`. -//! The function MUST fully initialize `dest` when `Ok(())` is returned. +//! The function MUST fully initialize `dest` when `Ok(())` is returned; +//! the function may need to use `sanitizer::unpoison` as well. //! The function MUST NOT ever write uninitialized bytes into `dest`, //! regardless of what value it returns. @@ -12,9 +13,11 @@ cfg_if! { pub use custom::*; } else if #[cfg(getrandom_backend = "linux_getrandom")] { mod getrandom; + mod sanitizer; pub use getrandom::*; } else if #[cfg(getrandom_backend = "linux_raw")] { mod linux_raw; + mod sanitizer; pub use linux_raw::*; } else if #[cfg(getrandom_backend = "rdrand")] { mod rdrand; @@ -43,6 +46,7 @@ cfg_if! { pub use unsupported::*; } else if #[cfg(all(target_os = "linux", target_env = ""))] { mod linux_raw; + mod sanitizer; pub use linux_raw::*; } else if #[cfg(target_os = "espidf")] { mod esp_idf; @@ -102,6 +106,7 @@ cfg_if! { ))] { mod use_file; mod linux_android_with_fallback; + mod sanitizer; pub use linux_android_with_fallback::*; } else if #[cfg(any( target_os = "android", @@ -116,6 +121,8 @@ cfg_if! { all(target_os = "horizon", target_arch = "arm"), ))] { mod getrandom; + #[cfg(any(target_os = "android", target_os = "linux"))] + mod sanitizer; pub use getrandom::*; } else if #[cfg(target_os = "solaris")] { mod solaris; diff --git a/src/backends/getrandom.rs b/src/backends/getrandom.rs index 27d5a1f5d..f3c33c3cb 100644 --- a/src/backends/getrandom.rs +++ b/src/backends/getrandom.rs @@ -26,6 +26,14 @@ mod util_libc; #[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { util_libc::sys_fill_exact(dest, |buf| unsafe { - libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) + let ret = libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0); + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this. + unsafe { + super::sanitizer::unpoison_linux_getrandom_result(buf, ret); + } + + ret }) } diff --git a/src/backends/linux_android_with_fallback.rs b/src/backends/linux_android_with_fallback.rs index 2ad8f0a46..6c9dd0653 100644 --- a/src/backends/linux_android_with_fallback.rs +++ b/src/backends/linux_android_with_fallback.rs @@ -1,5 +1,5 @@ //! Implementation for Linux / Android with `/dev/urandom` fallback -use super::use_file; +use super::{sanitizer, use_file}; use crate::Error; use core::{ ffi::c_void, @@ -95,7 +95,9 @@ pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // note: `transmute` is currently the only way to convert a pointer into a function reference let getrandom_fn = unsafe { transmute::, GetRandomFn>(fptr) }; util_libc::sys_fill_exact(dest, |buf| unsafe { - getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0) + let ret = getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0); + sanitizer::unpoison_linux_getrandom_result(buf, ret); + ret }) } } diff --git a/src/backends/linux_raw.rs b/src/backends/linux_raw.rs index 4a59eef00..f199e201a 100644 --- a/src/backends/linux_raw.rs +++ b/src/backends/linux_raw.rs @@ -1,7 +1,7 @@ //! Implementation for Linux / Android using `asm!`-based syscalls. -use crate::{Error, MaybeUninit}; - +use super::sanitizer; pub use crate::util::{inner_u32, inner_u64}; +use crate::{Error, MaybeUninit}; #[cfg(not(any(target_os = "android", target_os = "linux")))] compile_error!("`linux_raw` backend can be enabled only for Linux/Android targets!"); @@ -118,6 +118,7 @@ pub fn fill_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { loop { let ret = unsafe { getrandom_syscall(dest.as_mut_ptr().cast(), dest.len(), 0) }; + unsafe { sanitizer::unpoison_linux_getrandom_result(dest, ret) }; match usize::try_from(ret) { Ok(0) => return Err(Error::UNEXPECTED), Ok(len) => { diff --git a/src/backends/sanitizer.rs b/src/backends/sanitizer.rs new file mode 100644 index 000000000..0e074d43e --- /dev/null +++ b/src/backends/sanitizer.rs @@ -0,0 +1,59 @@ +use core::mem::MaybeUninit; + +/// Unpoisons `buf` if MSAN support is enabled. +/// +/// Most backends do not need to unpoison their output. Rust language- and +/// library- provided functionality unpoisons automatically. Similarly, libc +/// either natively supports MSAN and/or MSAN hooks libc-provided functions +/// to unpoison outputs on success. Only when all of these things are +/// bypassed do we need to do it ourselves. +/// +/// The call to unpoison should be done as close to the write as possible. +/// For example, if the backend partially fills the output buffer in chunks, +/// each chunk should be unpoisoned individually. This way, the correctness of +/// the chunking logic can be validated (in part) using MSAN. +pub unsafe fn unpoison(buf: &mut [MaybeUninit]) { + cfg_if! { + if #[cfg(getrandom_msan)] { + extern "C" { + fn __msan_unpoison(a: *mut core::ffi::c_void, size: usize); + } + let a = buf.as_mut_ptr().cast(); + let size = buf.len(); + #[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this. + unsafe { + __msan_unpoison(a, size); + } + } else { + let _ = buf; + } + } +} + +/// Interprets the result of the `getrandom` syscall of Linux, unpoisoning any +/// written part of `buf`. +/// +/// `buf` must be the output buffer that was originally passed to the `getrandom` +/// syscall. +/// +/// `ret` must be the result returned by `getrandom`. If `ret` is negative or +/// larger than the length of `buf` then nothing is done. +/// +/// Memory Sanitizer only intercepts `getrandom` on this condition (from its +/// source code): +/// ```c +/// #define SANITIZER_INTERCEPT_GETRANDOM \ +/// ((SI_LINUX && __GLIBC_PREREQ(2, 25)) || SI_FREEBSD || SI_SOLARIS) +/// ``` +/// So, effectively, we have to assume that it is never intercepted on Linux. +#[cfg(any(target_os = "android", target_os = "linux"))] +pub unsafe fn unpoison_linux_getrandom_result(buf: &mut [MaybeUninit], ret: isize) { + if let Ok(bytes_written) = usize::try_from(ret) { + if let Some(written) = buf.get_mut(..bytes_written) { + #[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this. + unsafe { + unpoison(written) + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 51c494e17..8ffd4c989 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,12 +106,7 @@ pub fn fill_uninit(dest: &mut [MaybeUninit]) -> Result<&mut [u8], Error> { // 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) - }) + Ok(unsafe { util::slice_assume_init_mut(dest) }) } /// Get random `u32` from the system's preferred random number source. From 5f7a91020fb75435dfe063a0c231010c9163f32a Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 4 Jun 2025 17:27:50 +0300 Subject: [PATCH 166/201] ci: simplifiy matrix for `sanitizer-linux` job (#683) --- .github/workflows/tests.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bedcd3284..94d604045 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -144,16 +144,11 @@ jobs: runs-on: ${{ matrix.runner }} strategy: matrix: - arch: [ - "aarch64", - "x86_64", - ] include: # MemorySanitizer won't run in QEMU so we can't run it in cross: # https://github.com/llvm/llvm-project/issues/65144 - arch: aarch64 runner: ubuntu-24.04-arm - - arch: x86_64 runner: ubuntu-24.04 steps: From cdf3a46438a4a0e71f593ddf3bd10697385545d5 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 9 Jun 2025 05:10:07 -0700 Subject: [PATCH 167/201] build.rs: Address `clippy::single_char_pattern` (#686) --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 14aaf0c80..b87d2e55d 100644 --- a/build.rs +++ b/build.rs @@ -26,7 +26,7 @@ fn rustc_minor_version() -> Option { // where "xx" is the minor version which we want to extract let mut lines = stdout.lines(); let first_line = lines.next()?; - let minor_ver_str = first_line.split(".").nth(1)?; + let minor_ver_str = first_line.split('.').nth(1)?; minor_ver_str.parse().ok() } From 5ad8384900372e22679534472a3c00b97356d469 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 9 Jun 2025 16:35:51 +0300 Subject: [PATCH 168/201] linux_raw: inline `__NR_getrandom` into ARM assembly (#688) `asm_const` was stabilized only in Rust 1.82, so inlining the constant relaxes MSRV for the `linux_raw` backend on ARM targets. --- CHANGELOG.md | 4 ++++ src/backends/linux_raw.rs | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f51c2b59b..4de0a4b37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.3.4] - UNRELEASED +### Changed +- Relax MSRV for the `linux_raw` opt-in backend on ARM targets [#688] + ### Added - `unsupported` opt-in backend [#667] [#667]: https://github.com/rust-random/getrandom/pull/667 +[#688]: https://github.com/rust-random/getrandom/pull/688 ## [0.3.3] - 2025-05-09 diff --git a/src/backends/linux_raw.rs b/src/backends/linux_raw.rs index f199e201a..6b6af91ef 100644 --- a/src/backends/linux_raw.rs +++ b/src/backends/linux_raw.rs @@ -13,7 +13,6 @@ unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize { // 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. @@ -22,10 +21,10 @@ unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize { // bother with it. core::arch::asm!( "mov {tmp}, r7", - "mov r7, {nr}", + // TODO(MSRV-1.82): replace with `nr = const __NR_getrandom,` + "mov r7, #384", "svc 0", "mov r7, {tmp}", - nr = const __NR_getrandom, tmp = out(reg) _, inlateout("r0") buf => r0, in("r1") buflen, From 32924016dc9a776ac3f75e464c6f4fd247f1c89b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 19:53:45 +0300 Subject: [PATCH 169/201] Update Cargo.lock (#689) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b3925295b..b212f9689 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,15 +10,15 @@ checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "cc" -version = "1.2.25" +version = "1.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" +checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" dependencies = [ "shlex", ] From e500436f46d123e6ddf1e9c98961050ca4fb58af Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 9 Jun 2025 13:13:43 -0700 Subject: [PATCH 170/201] linux_raw: clarify x86_64 syscall numbers (#687) The source code didn't mention the x32 ABI by name. Give `__X32_SYSCALL_BIT` its rightful name so readers can understand what we're doing. Explain why we're not using `cfg(target_abi)`. For other ILP32 ABIs, it seems like they use the same syscall numbers. --- src/backends/linux_raw.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/backends/linux_raw.rs b/src/backends/linux_raw.rs index 6b6af91ef..508409002 100644 --- a/src/backends/linux_raw.rs +++ b/src/backends/linux_raw.rs @@ -13,6 +13,7 @@ unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize { // Based on `rustix` and `linux-raw-sys` code. cfg_if! { if #[cfg(target_arch = "arm")] { + // TODO(MSRV-1.78): Also check `target_abi = "eabi"`. // 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. @@ -32,6 +33,11 @@ unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize { options(nostack, preserves_flags) ); } else if #[cfg(target_arch = "aarch64")] { + // TODO(MSRV-1.78): Also check `any(target_abi = "", target_abi = "ilp32")` above. + // According the the ILP32 patch for the kernel that hasn't yet + // been merged into the mainline, "AARCH64/ILP32 ABI uses standard + // syscall table [...] with the exceptions listed below," where + // getrandom is not mentioned as an exception. const __NR_getrandom: u32 = 278; core::arch::asm!( "svc 0", @@ -42,6 +48,7 @@ unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize { options(nostack, preserves_flags) ); } else if #[cfg(target_arch = "loongarch64")] { + // TODO(MSRV-1.78): Also check `any(target_abi = "", target_abi = "ilp32")` above. const __NR_getrandom: u32 = 278; core::arch::asm!( "syscall 0", @@ -86,10 +93,10 @@ unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize { 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; + // TODO(MSRV-1.78): Add `any(target_abi = "", target_abi = "x32")` above. + const __X32_SYSCALL_BIT: u32 = 0x40000000; + const OFFSET: u32 = if cfg!(target_pointer_width = "32") { __X32_SYSCALL_BIT } else { 0 }; + const __NR_getrandom: u32 = OFFSET + 318; core::arch::asm!( "syscall", From 1c359b57b7ad2915ede9cfd9883b0abecb0cf13c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 21:05:09 +0300 Subject: [PATCH 171/201] Update Cargo.lock (#690) --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b212f9689..cd6128edc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,18 +16,18 @@ checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "cc" -version = "1.2.26" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "compiler_builtins" @@ -62,9 +62,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.171" +version = "0.2.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" [[package]] name = "log" @@ -135,9 +135,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "syn" -version = "2.0.101" +version = "2.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" dependencies = [ "proc-macro2", "quote", From 5fe2780e266fe7bf933432438c12b4743b8dee06 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 17 Jun 2025 17:24:19 +0300 Subject: [PATCH 172/201] ci: add typos job (#692) --- .github/workflows/workspace.yml | 6 ++++++ .typos.toml | 7 +++++++ CHANGELOG.md | 4 ++-- README.md | 2 +- src/backends/use_file.rs | 2 +- src/backends/windows7.rs | 2 +- 6 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 .typos.toml diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 9ab4e4dae..4182dfc05 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -116,3 +116,9 @@ jobs: env: RUSTDOCFLAGS: "-Dwarnings --cfg docsrs" run: cargo doc --no-deps --features std + + typos: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: crate-ci/typos@v1 diff --git a/.typos.toml b/.typos.toml new file mode 100644 index 000000000..89bf65dff --- /dev/null +++ b/.typos.toml @@ -0,0 +1,7 @@ +[files] +extend-exclude = [ + ".git/" +] + +[default.extend-words] +"nto" = "nto" diff --git a/CHANGELOG.md b/CHANGELOG.md index 4de0a4b37..4619a7319 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -92,7 +92,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `register_custom_getrandom!` macro [#504] - Implementation of `From` for `Error` and `Error::code` method [#507] - Internet Explorer 11 support [#554] -- Target-specific assocciated `Error` constants [#562] +- Target-specific associated `Error` constants [#562] ### Changed - Use `ProcessPrng` on Windows 10 and up, and use `RtlGenRandom` on older Windows versions [#415] @@ -240,7 +240,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Update MSRV to 1.36 [#291] - Use getentropy on Emscripten [#307] -- Solaris: consistantly use `/dev/random` source [#310] +- Solaris: consistently use `/dev/random` source [#310] - Move 3ds selection above rdrand/js/custom fallback [#312] - Remove buffer zeroing from Node.js implementation [#315] - Use `open` instead of `open64` [#326] diff --git a/README.md b/README.md index 293eb88a1..17e84860a 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ of randomness based on their specific needs: | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register | `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown`, `wasm32v1-none` | [`Crypto.getRandomValues`]. Requires feature `wasm_js` ([see below](#webassembly-support)). -| `efi_rng` | UEFI | `*-unknown‑uefi` | [`EFI_RNG_PROTOCOL`] with `EFI_RNG_ALGORITHM_RAW` (requires `std` and Nigthly compiler) +| `efi_rng` | UEFI | `*-unknown‑uefi` | [`EFI_RNG_PROTOCOL`] with `EFI_RNG_ALGORITHM_RAW` (requires `std` and Nightly compiler) | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) | `unsupported` | All targets | `*` | Always returns `Err(Error::UNSUPPORTED)` (see [unsupported backend]) diff --git a/src/backends/use_file.rs b/src/backends/use_file.rs index 7b48d4338..071ce930b 100644 --- a/src/backends/use_file.rs +++ b/src/backends/use_file.rs @@ -27,7 +27,7 @@ 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 +// need to use a different atomic type or make other accommodations. The // compiler will let us know if/when that is the case, because the // `FD.store(fd)` would fail to compile. // diff --git a/src/backends/windows7.rs b/src/backends/windows7.rs index 8a353a9f8..cee5f43a4 100644 --- a/src/backends/windows7.rs +++ b/src/backends/windows7.rs @@ -5,7 +5,7 @@ //! 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). +//! that it forces the loading of an additional 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. From aa034a23e3444559c56a596d4b0d7290cd463f12 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 18 Jun 2025 23:40:15 +0300 Subject: [PATCH 173/201] Remove the unstable `rustc-dep-of-std` feature (#694) The feature was initially added for potential use of `getrandom` in `std`. Unfortunately, the proposal did not get traction, so the feature is effectively useless. Before reviving this feature we should resolve #365 at the very least and even with that it's unlikely that `getrandom` will be used by `std` considering the proposals to properly expose entropy sources in `std`. Closes #693 --- CHANGELOG.md | 4 ++++ Cargo.lock | 14 -------------- Cargo.toml | 6 ------ 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4619a7319..d310fb575 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `unsupported` opt-in backend [#667] +### Removed +- Unstable `rustc-dep-of-std` crate feature [#694] + [#667]: https://github.com/rust-random/getrandom/pull/667 [#688]: https://github.com/rust-random/getrandom/pull/688 +[#694]: https://github.com/rust-random/getrandom/pull/694 ## [0.3.3] - 2025-05-09 diff --git a/Cargo.lock b/Cargo.lock index cd6128edc..557be3df9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,22 +29,14 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" -[[package]] -name = "compiler_builtins" -version = "0.1.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6376049cfa92c0aa8b9ac95fae22184b981c658208d4ed8a1dc553cd83612895" - [[package]] name = "getrandom" version = "0.3.3" dependencies = [ "cfg-if", - "compiler_builtins", "js-sys", "libc", "r-efi", - "rustc-std-workspace-core", "wasi", "wasm-bindgen", "wasm-bindgen-test", @@ -112,12 +104,6 @@ version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" -[[package]] -name = "rustc-std-workspace-core" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955" - [[package]] name = "same-file" version = "1.0.6" diff --git a/Cargo.toml b/Cargo.toml index 4a982ee7c..03b188be7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,6 @@ exclude = [".*"] # Implement std::error::Error for getrandom::Error and # use std to retrieve OS error descriptions std = [] -# Unstable feature to support being a libstd dependency -rustc-dep-of-std = ["dep:compiler_builtins", "dep:core"] # Optional backend: wasm_js # This flag enables the backend but does not select it. To use the backend, use @@ -28,10 +26,6 @@ wasm_js = ["dep:wasm-bindgen", "dep:js-sys"] [dependencies] cfg-if = "1" -# When built as part of libstd -compiler_builtins = { version = "0.1", optional = true } -core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" } - # getrandom / linux_android_with_fallback [target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(all(target_os = "linux", target_env = ""), getrandom_backend = "custom", getrandom_backend = "linux_raw", getrandom_backend = "rdrand", getrandom_backend = "rndr"))))'.dependencies] libc = { version = "0.2.154", default-features = false } From 5ecab629385174c842b19716e90b0c8896790ddc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 21:21:21 +0300 Subject: [PATCH 174/201] Update Cargo.lock (#695) --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 557be3df9..e67b1f746 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.173" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "log" @@ -100,9 +100,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "same-file" @@ -121,9 +121,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "syn" -version = "2.0.103" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", From f079ded3e2a2f8f4d70f13ee4e9758b172923316 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 22:32:09 +0300 Subject: [PATCH 175/201] Update Cargo.lock (#696) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e67b1f746..9da6147a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bumpalo" -version = "3.18.1" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" From 03ec647de15d5c6c4e891261df7cd9ea5ca7d39d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 23:10:17 +0300 Subject: [PATCH 176/201] Update Cargo.lock (#697) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9da6147a8..cf8a60a7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.27" +version = "1.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" dependencies = [ "shlex", ] From 8f32de2530965d9f935147c79dafdcc79dd3bd30 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Wed, 23 Jul 2025 19:35:39 -0700 Subject: [PATCH 177/201] Use getrandom syscall on riscv32/riscv64 linux (#699) Minimum kernel needed on RISCV is fairly new (4.15+) so we are sure to have getrandom syscall, on glibc there is mimimal ABI kernel to denote it but musl does not have any other way to indicate it, so add it as a condition here to choose getrandom backend for rv32/rv64 on linux when using musl. Signed-off-by: Khem Raj --- src/backends.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/backends.rs b/src/backends.rs index bf0381d26..d7b73cec0 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -100,7 +100,15 @@ cfg_if! { // 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", + all( + target_env = "musl", + not( + any( + target_arch = "riscv64", + target_arch = "riscv32", + ), + ), + ), ), ) ))] { From e5faa412dfdd3227d134560d28a79e81ecb75972 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 21:57:46 +0300 Subject: [PATCH 178/201] Update Cargo.lock (#700) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cf8a60a7b..cb82465d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.29" +version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ "shlex", ] From cf4d9e0ba58f4c6639ec8c5d942be5d4587af1de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 03:16:58 +0300 Subject: [PATCH 179/201] Update Cargo.lock (#702) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb82465d2..7e4701059 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.30" +version = "1.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" dependencies = [ "shlex", ] From c6210f9541df44798378d95c175c4ddfb3bb2138 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 12 Aug 2025 04:35:28 +0300 Subject: [PATCH 180/201] ci: update `cargo dinghy` to v0.8.1 (#705) Temporarily downgrades Rust toolchain in the Dinghy job to 1.88 to work around https://github.com/sonos/dinghy/issues/255 --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 94d604045..9b9cc7094 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -82,11 +82,11 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: - toolchain: stable + toolchain: 1.88.0 targets: aarch64-apple-ios-sim - name: Install precompiled cargo-dinghy run: | - VERSION=0.8.0 + VERSION=0.8.1 URL="https://github.com/sonos/dinghy/releases/download/${VERSION}/cargo-dinghy-macos-${VERSION}.tgz" wget -O - $URL | tar -xz --strip-components=1 -C ~/.cargo/bin - name: Check cargo-dinghy version. From 8bface79a5ca68f0007e11ed654ca06846272625 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 04:42:16 +0300 Subject: [PATCH 181/201] build(deps): bump actions/checkout from 4 to 5 (#704) --- .github/workflows/build.yml | 24 ++++++++++++------------ .github/workflows/nopanic.yaml | 8 ++++---- .github/workflows/tests.yml | 24 ++++++++++++------------ .github/workflows/workspace.yml | 8 ++++---- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bf51e6ea5..a84ca684f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,7 @@ jobs: # visionOS requires Xcode 15.2+, which is only available on the arm64 runners. runs-on: macos-14 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@nightly with: targets: aarch64-apple-darwin, aarch64-apple-ios @@ -48,7 +48,7 @@ jobs: x86_64-unknown-illumos, ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install precompiled cross run: | VERSION=v0.2.5 @@ -70,7 +70,7 @@ jobs: x86_64-fortanix-unknown-sgx, ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} @@ -100,7 +100,7 @@ jobs: # x86_64-pc-cygwin, ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@nightly # Required to build libcore with: components: rust-src @@ -116,7 +116,7 @@ jobs: matrix: target: [x86_64-unknown-linux-gnux32] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} @@ -153,7 +153,7 @@ jobs: x86_64-unknown-linux-gnux32, ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: nightly-2025-06-01 @@ -186,7 +186,7 @@ jobs: - target: { target: wasm32v1-none } feature: { std: true } steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: targets: ${{ matrix.target.target }} @@ -207,7 +207,7 @@ jobs: i686-unknown-uefi, ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@nightly # Required to build libstd with: components: rust-src @@ -226,7 +226,7 @@ jobs: i686-unknown-uefi, ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@nightly # Required to build libcore with: components: rust-src @@ -242,7 +242,7 @@ jobs: name: RNDR runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: stable @@ -265,7 +265,7 @@ jobs: name: No Atomics runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable with: targets: riscv32i-unknown-none-elf @@ -278,7 +278,7 @@ jobs: name: Runtime error runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable with: targets: wasm32-unknown-unknown diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index 23ab7ca53..c4907c10f 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -30,7 +30,7 @@ jobs: name: Linux runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: stable @@ -84,7 +84,7 @@ jobs: name: Cross runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: stable @@ -119,7 +119,7 @@ jobs: name: macOS runs-on: macos-14 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: stable @@ -137,7 +137,7 @@ jobs: name: Windows runs-on: windows-2022 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: nightly-2025-06-01 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9b9cc7094..4fc5c880a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -30,7 +30,7 @@ jobs: - os: macos-14 toolchain: stable steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.toolchain }} @@ -48,7 +48,7 @@ jobs: matrix: target: [x86_64-unknown-linux-musl, i686-unknown-linux-musl] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} @@ -79,7 +79,7 @@ jobs: name: iOS Simulator runs-on: macos-14 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: 1.88.0 @@ -118,7 +118,7 @@ jobs: stable-i686-msvc, ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.toolchain }} @@ -129,7 +129,7 @@ jobs: name: Windows 7 (on Windows 10) runs-on: windows-2022 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 # Win7 targets are Tier3, so pin a nightly where libstd builds. - uses: dtolnay/rust-toolchain@master with: @@ -152,7 +152,7 @@ jobs: - arch: x86_64 runner: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: nightly-2025-06-01 @@ -213,7 +213,7 @@ jobs: #wasm32-unknown-emscripten, ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install precompiled cross run: | VERSION=v0.2.5 @@ -227,7 +227,7 @@ jobs: name: FreeBSD VM runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Test in FreeBSD uses: vmactions/freebsd-vm@v1 with: @@ -241,7 +241,7 @@ jobs: name: OpenBSD VM runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Test in OpenBSD uses: vmactions/openbsd-vm@v1 with: @@ -255,7 +255,7 @@ jobs: name: NetBSD VM runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Test in NetBSD uses: vmactions/netbsd-vm@v1 with: @@ -288,7 +288,7 @@ jobs: args: '--features=std,wasm_js -Zbuild-std=panic_abort,std', } steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust.version }} @@ -342,7 +342,7 @@ jobs: name: WASI runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: 1.82 diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 4182dfc05..d6ba854a1 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -16,7 +16,7 @@ jobs: env: RUSTFLAGS: "-Dwarnings" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: # We need Nightly for -Zbuild-std. @@ -94,7 +94,7 @@ jobs: name: rustfmt runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt @@ -106,7 +106,7 @@ jobs: name: rustdoc runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: # We need Nightly for doc_auto_cfg @@ -120,5 +120,5 @@ jobs: typos: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: crate-ci/typos@v1 From eddc81a79ec33f2878f74aafe9dc36fbbac5e1b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 04:55:09 +0300 Subject: [PATCH 182/201] Update Cargo.lock (#703) --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e4701059..2090d30f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.31" +version = "1.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" +checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" dependencies = [ "shlex", ] @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.174" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "log" @@ -82,9 +82,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1" dependencies = [ "unicode-ident", ] From 8edf6e4be124a92676cfc6eab269ef08c6215cfe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 13:17:33 +0300 Subject: [PATCH 183/201] Update Cargo.lock (#706) --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2090d30f8..465546d56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" [[package]] name = "bumpalo" @@ -16,9 +16,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.32" +version = "1.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" +checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f" dependencies = [ "shlex", ] @@ -82,9 +82,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "proc-macro2" -version = "1.0.97" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -121,9 +121,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", From d962137e21348ec5ae6c039e72a0f2161c1411ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:20:25 +0300 Subject: [PATCH 184/201] Update Cargo.lock (#709) --- Cargo.lock | 63 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 465546d56..74b78e178 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "bitflags" -version = "2.9.2" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" +checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" [[package]] name = "bumpalo" @@ -16,18 +16,18 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.33" +version = "1.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f" +checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" dependencies = [ "shlex", ] [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "getrandom" @@ -261,28 +261,35 @@ dependencies = [ [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ "windows-sys", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.52.6" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link", "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", @@ -295,51 +302,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] name = "windows_aarch64_msvc" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_i686_gnu" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" [[package]] name = "windows_i686_gnullvm" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[package]] name = "windows_i686_msvc" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] name = "windows_x86_64_gnu" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[package]] name = "windows_x86_64_msvc" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "wit-bindgen-rt" From 6dd8296e8191a1ac1f062e648bc557af5025dbc0 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sat, 30 Aug 2025 19:36:50 +0300 Subject: [PATCH 185/201] linux_raw: fix comment typo (#711) --- src/backends/linux_raw.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/linux_raw.rs b/src/backends/linux_raw.rs index 508409002..2a74e5852 100644 --- a/src/backends/linux_raw.rs +++ b/src/backends/linux_raw.rs @@ -34,7 +34,7 @@ unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize { ); } else if #[cfg(target_arch = "aarch64")] { // TODO(MSRV-1.78): Also check `any(target_abi = "", target_abi = "ilp32")` above. - // According the the ILP32 patch for the kernel that hasn't yet + // According to the ILP32 patch for the kernel that hasn't yet // been merged into the mainline, "AARCH64/ILP32 ABI uses standard // syscall table [...] with the exceptions listed below," where // getrandom is not mentioned as an exception. From 78ef61a0e7a5dc876da0b496998464630a4c0bf0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 14:01:10 +0300 Subject: [PATCH 186/201] Update Cargo.lock (#712) --- Cargo.lock | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74b78e178..ba41eb96d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "bitflags" -version = "2.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" - [[package]] name = "bumpalo" version = "3.19.0" @@ -16,10 +10,11 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.34" +version = "1.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" +checksum = "590f9024a68a8c40351881787f1934dc11afd69090f5edb6831464694d836ea3" dependencies = [ + "find-msvc-tools", "shlex", ] @@ -29,6 +24,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +[[package]] +name = "find-msvc-tools" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e178e4fba8a2726903f6ba98a6d221e76f9c12c650d5dc0e6afdc50677b49650" + [[package]] name = "getrandom" version = "0.3.3" @@ -148,11 +149,11 @@ dependencies = [ [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.14.3+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -349,10 +350,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] +checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" From 0951329f9a45eb0f8d98a565cf84188210ff67bb Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 8 Sep 2025 22:13:37 +0300 Subject: [PATCH 187/201] ci: disable NetBSD job (#714) --- .github/workflows/tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4fc5c880a..60027c95d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -254,6 +254,9 @@ jobs: netbsd: name: NetBSD VM runs-on: ubuntu-24.04 + # The job is currently broken: + # https://github.com/rust-random/getrandom/actions/runs/17557903310/job/49871767957 + if: false steps: - uses: actions/checkout@v5 - name: Test in NetBSD From 0b9c42e8627c5f28779ef4558da5f04d809dd7f9 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 8 Sep 2025 22:29:24 +0300 Subject: [PATCH 188/201] Update Cargo.lock (#715) --- Cargo.lock | 138 ++++++++++++++--------------------------------------- 1 file changed, 37 insertions(+), 101 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba41eb96d..da027edd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.35" +version = "1.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "590f9024a68a8c40351881787f1934dc11afd69090f5edb6831464694d836ea3" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" dependencies = [ "find-msvc-tools", "shlex", @@ -26,9 +26,9 @@ checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "find-msvc-tools" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e178e4fba8a2726903f6ba98a6d221e76f9c12c650d5dc0e6afdc50677b49650" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" [[package]] name = "getrandom" @@ -45,9 +45,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" dependencies = [ "once_cell", "wasm-bindgen", @@ -61,9 +61,9 @@ checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "minicov" @@ -149,29 +149,30 @@ dependencies = [ [[package]] name = "wasi" -version = "0.14.3+wasi-0.2.4" +version = "0.14.4+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" +checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" dependencies = [ "cfg-if", "once_cell", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" dependencies = [ "bumpalo", "log", @@ -183,9 +184,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" dependencies = [ "cfg-if", "js-sys", @@ -196,9 +197,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -206,9 +207,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" dependencies = [ "proc-macro2", "quote", @@ -219,18 +220,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-bindgen-test" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" +checksum = "80cc7f8a4114fdaa0c58383caf973fc126cf004eba25c9dc639bccd3880d55ad" dependencies = [ "js-sys", "minicov", @@ -241,9 +242,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" +checksum = "c5ada2ab788d46d4bda04c9d567702a79c8ced14f51f221646a16ed39d0e6a5d" dependencies = [ "proc-macro2", "quote", @@ -252,9 +253,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" dependencies = [ "js-sys", "wasm-bindgen", @@ -262,95 +263,30 @@ dependencies = [ [[package]] name = "winapi-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ "windows-sys", ] [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" [[package]] name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.53.3" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" dependencies = [ "windows-link", - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "wit-bindgen" -version = "0.45.0" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" From 6134f6b377f14d6e07e2fbf54adb4003bbce8705 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 15 Sep 2025 20:58:47 +0300 Subject: [PATCH 189/201] ci: update Nighly version for the Clippy job (#718) --- .github/workflows/workspace.yml | 2 +- src/backends/windows.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index d6ba854a1..857578fdb 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -23,7 +23,7 @@ jobs: # Fixed Nigthly version is used to prevent # CI failures which are not relevant to PR changes # on introduction of new Clippy lints. - toolchain: nightly-2025-06-01 + toolchain: nightly-2025-09-15 components: clippy,rust-src - name: std feature run: cargo clippy --features std diff --git a/src/backends/windows.rs b/src/backends/windows.rs index b5cd504fe..b1e10e7fc 100644 --- a/src/backends/windows.rs +++ b/src/backends/windows.rs @@ -44,7 +44,7 @@ pub use crate::util::{inner_u32, inner_u64}; extern "system" { fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL; } -#[allow(clippy::upper_case_acronyms)] +#[allow(clippy::upper_case_acronyms, clippy::incompatible_msrv)] type BOOL = core::ffi::c_int; // MSRV 1.64, similarly OK for this backend. const TRUE: BOOL = 1; From cf9d5dfabf7dd9b29339a93ad944d1c63109335a Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 16 Sep 2025 11:16:28 +0300 Subject: [PATCH 190/201] Replace `wasi` crate with `wasip2` (#721) The recent releases of `wasi` simply re-export contents of `wasip2`. --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 4 ++-- src/backends/wasi_p2.rs | 7 ++----- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index da027edd1..5fa470407 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.36" +version = "1.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" +checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44" dependencies = [ "find-msvc-tools", "shlex", @@ -38,7 +38,7 @@ dependencies = [ "js-sys", "libc", "r-efi", - "wasi", + "wasip2", "wasm-bindgen", "wasm-bindgen-test", ] @@ -133,9 +133,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "walkdir" @@ -148,10 +148,10 @@ dependencies = [ ] [[package]] -name = "wasi" -version = "0.14.4+wasi-0.2.4" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] @@ -287,6 +287,6 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" diff --git a/Cargo.toml b/Cargo.toml index 03b188be7..33322a04a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,9 +62,9 @@ libc = { version = "0.2.154", default-features = false } [target.'cfg(target_os = "vxworks")'.dependencies] libc = { version = "0.2.154", default-features = false } -# wasi (0.2 only) +# wasi_p2 [target.'cfg(all(target_arch = "wasm32", target_os = "wasi", target_env = "p2"))'.dependencies] -wasi = { version = "0.14", default-features = false } +wasip2 = { version = "1", default-features = false } # wasm_js [target.'cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))'.dependencies] diff --git a/src/backends/wasi_p2.rs b/src/backends/wasi_p2.rs index 63bd2d7cb..d16fdff99 100644 --- a/src/backends/wasi_p2.rs +++ b/src/backends/wasi_p2.rs @@ -1,7 +1,7 @@ //! Implementation for WASI Preview 2. use crate::Error; -use core::mem::MaybeUninit; -use wasi::random::random::get_random_u64; +use core::{mem::MaybeUninit, ptr::copy_nonoverlapping}; +use wasip2::random::random::get_random_u64; #[inline] pub fn inner_u32() -> Result { @@ -16,9 +16,6 @@ pub fn inner_u64() -> Result { #[inline] pub fn fill_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - use core::ptr::copy_nonoverlapping; - use wasi::random::random::get_random_u64; - let (prefix, chunks, suffix) = unsafe { dest.align_to_mut::>() }; // We use `get_random_u64` instead of `get_random_bytes` because the latter creates From 3cddf083282a56a941bc3784b0356901385f6285 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 19:36:28 +0300 Subject: [PATCH 191/201] Update Cargo.lock (#727) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5fa470407..fcf0c441a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.37" +version = "1.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" dependencies = [ "find-msvc-tools", "shlex", @@ -26,9 +26,9 @@ checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "find-msvc-tools" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" [[package]] name = "getrandom" From 3983e0fbec37516bd5e1b32eb4bdacb612f36f8b Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 23 Sep 2025 14:43:21 +0300 Subject: [PATCH 192/201] Add `windows_legacy` opt-in backend (#724) Some users may prefer to use the legacy Windows backend (e.g. see #723), so I think it's worth to introduce a documented configuration flag for it and replace the undocumented `getrandom_windows_legacy` flag. --- CHANGELOG.md | 14 +++++-- Cargo.lock | 40 +++++++++---------- Cargo.toml | 3 +- README.md | 1 + build.rs | 2 +- src/backends.rs | 9 +++-- .../{windows7.rs => windows_legacy.rs} | 3 ++ 7 files changed, 43 insertions(+), 29 deletions(-) rename src/backends/{windows7.rs => windows_legacy.rs} (94%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d310fb575..799dc407a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,18 +6,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.3.4] - UNRELEASED -### Changed -- Relax MSRV for the `linux_raw` opt-in backend on ARM targets [#688] - ### Added - `unsupported` opt-in backend [#667] +- `windows_legacy` opt-in backend [#724] + +### Changed +- Implement Memory Sanitizer unpoisoning more precisely [#678] +- Relax MSRV for the `linux_raw` opt-in backend on ARM targets [#688] +- Use `getrandom` syscall on all RISC-V Linux targets [#699] +- Replaced `wasi` dependency with `wasip2` [#721] ### Removed - Unstable `rustc-dep-of-std` crate feature [#694] [#667]: https://github.com/rust-random/getrandom/pull/667 +[#678]: https://github.com/rust-random/getrandom/pull/678 [#688]: https://github.com/rust-random/getrandom/pull/688 [#694]: https://github.com/rust-random/getrandom/pull/694 +[#699]: https://github.com/rust-random/getrandom/pull/699 +[#721]: https://github.com/rust-random/getrandom/pull/721 +[#724]: https://github.com/rust-random/getrandom/pull/724 ## [0.3.3] - 2025-05-09 diff --git a/Cargo.lock b/Cargo.lock index fcf0c441a..589df9fa8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,9 +45,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.78" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" dependencies = [ "once_cell", "wasm-bindgen", @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" dependencies = [ "cfg-if", "once_cell", @@ -170,9 +170,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" dependencies = [ "bumpalo", "log", @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.51" +version = "0.4.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" +checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67" dependencies = [ "cfg-if", "js-sys", @@ -197,9 +197,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -207,9 +207,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" dependencies = [ "proc-macro2", "quote", @@ -220,18 +220,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-bindgen-test" -version = "0.3.51" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80cc7f8a4114fdaa0c58383caf973fc126cf004eba25c9dc639bccd3880d55ad" +checksum = "aee0a0f5343de9221a0d233b04520ed8dc2e6728dce180b1dcd9288ec9d9fa3c" dependencies = [ "js-sys", "minicov", @@ -242,9 +242,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.51" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ada2ab788d46d4bda04c9d567702a79c8ced14f51f221646a16ed39d0e6a5d" +checksum = "a369369e4360c2884c3168d22bded735c43cccae97bbc147586d4b480edd138d" dependencies = [ "proc-macro2", "quote", @@ -253,9 +253,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.78" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" +checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 33322a04a..27f3532fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,9 +77,8 @@ wasm-bindgen-test = "0.3" [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(getrandom_backend, values("custom", "efi_rng", "rdrand", "rndr", "linux_getrandom", "linux_raw", "wasm_js", "unsupported"))', + 'cfg(getrandom_backend, values("custom", "efi_rng", "rdrand", "rndr", "linux_getrandom", "linux_raw", "wasm_js", "windows_legacy", "unsupported"))', 'cfg(getrandom_msan)', - 'cfg(getrandom_windows_legacy)', 'cfg(getrandom_test_linux_fallback)', 'cfg(getrandom_test_linux_without_fallback)', 'cfg(getrandom_test_netbsd_fallback)', diff --git a/README.md b/README.md index 17e84860a..9866302a1 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ of randomness based on their specific needs: | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register | `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown`, `wasm32v1-none` | [`Crypto.getRandomValues`]. Requires feature `wasm_js` ([see below](#webassembly-support)). | `efi_rng` | UEFI | `*-unknown‑uefi` | [`EFI_RNG_PROTOCOL`] with `EFI_RNG_ALGORITHM_RAW` (requires `std` and Nightly compiler) +| `windows_legacy` | Windows | `*-windows-*` | [`RtlGenRandom`] | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) | `unsupported` | All targets | `*` | Always returns `Err(Error::UNSUPPORTED)` (see [unsupported backend]) diff --git a/build.rs b/build.rs index b87d2e55d..a35ad61be 100644 --- a/build.rs +++ b/build.rs @@ -48,7 +48,7 @@ fn main() { match rustc_minor_version() { Some(minor_ver) if minor_ver < WIN7_INTRODUCED_MINOR_VER => { - println!("cargo:rustc-cfg=getrandom_windows_legacy"); + println!("cargo:rustc-cfg=getrandom_backend=\"windows_legacy\""); } None => println!("cargo:warning=Couldn't detect minor version of the Rust compiler"), _ => {} diff --git a/src/backends.rs b/src/backends.rs index d7b73cec0..8f64824c1 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -28,6 +28,9 @@ cfg_if! { } else if #[cfg(getrandom_backend = "efi_rng")] { mod efi_rng; pub use efi_rng::*; + } else if #[cfg(getrandom_backend = "windows_legacy")] { + mod windows_legacy; + pub use windows_legacy::*; } else if #[cfg(all(getrandom_backend = "wasm_js"))] { cfg_if! { if #[cfg(feature = "wasm_js")] { @@ -173,9 +176,9 @@ cfg_if! { } 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(all(windows, target_vendor = "win7"))] { + mod windows_legacy; + pub use windows_legacy::*; } else if #[cfg(windows)] { mod windows; pub use windows::*; diff --git a/src/backends/windows7.rs b/src/backends/windows_legacy.rs similarity index 94% rename from src/backends/windows7.rs rename to src/backends/windows_legacy.rs index cee5f43a4..4b3f09278 100644 --- a/src/backends/windows7.rs +++ b/src/backends/windows_legacy.rs @@ -14,6 +14,9 @@ use core::{ffi::c_void, mem::MaybeUninit}; pub use crate::util::{inner_u32, inner_u64}; +#[cfg(not(windows))] +compile_error!("`windows_legacy` backend can be enabled only for Windows targets!"); + // 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")] From b6ac385bc4bd20a40a07c94a3be347ac88c19606 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 29 Sep 2025 16:25:51 +0300 Subject: [PATCH 193/201] ci: re-enable NetBSD job (#729) --- .github/workflows/tests.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 60027c95d..4fc5c880a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -254,9 +254,6 @@ jobs: netbsd: name: NetBSD VM runs-on: ubuntu-24.04 - # The job is currently broken: - # https://github.com/rust-random/getrandom/actions/runs/17557903310/job/49871767957 - if: false steps: - uses: actions/checkout@v5 - name: Test in NetBSD From 9b78fcc83ad54d2a0e045090d6fa90b2a4b315c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 22:01:44 +0300 Subject: [PATCH 194/201] Update Cargo.lock (#731) --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 589df9fa8..f6c2f431a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.38" +version = "1.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" dependencies = [ "find-msvc-tools", "shlex", @@ -55,9 +55,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.175" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "log" @@ -92,9 +92,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -278,9 +278,9 @@ checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" dependencies = [ "windows-link", ] From d4cb6a2b29fd87d5c8f624cf9f3be60c5e4c2b9b Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 29 Sep 2025 15:44:32 -0700 Subject: [PATCH 195/201] Update all nightly toolchains to latest nightly Signed-off-by: Joe Richey --- .github/workflows/build.yml | 4 ++-- .github/workflows/nopanic.yaml | 2 +- .github/workflows/tests.yml | 4 ++-- .github/workflows/workspace.yml | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a84ca684f..2d65f5827 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -156,7 +156,7 @@ jobs: - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: - toolchain: nightly-2025-06-01 + toolchain: nightly-2025-09-28 components: rust-src - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw" @@ -190,7 +190,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: targets: ${{ matrix.target.target }} - toolchain: nightly-2025-06-01 + toolchain: nightly-2025-09-28 components: rust-src - uses: Swatinem/rust-cache@v2 - name: Build diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index c4907c10f..5903c2e26 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -140,7 +140,7 @@ jobs: - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: - toolchain: nightly-2025-06-01 + toolchain: nightly-2025-09-28 components: rust-src - run: cargo build --release - run: cargo build --release --target=x86_64-win7-windows-msvc -Zbuild-std="std,panic_abort" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4fc5c880a..dc8f19ca3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -133,7 +133,7 @@ jobs: # Win7 targets are Tier3, so pin a nightly where libstd builds. - uses: dtolnay/rust-toolchain@master with: - toolchain: nightly-2025-06-01 + toolchain: nightly-2025-09-28 components: rust-src - uses: Swatinem/rust-cache@v2 - run: cargo test --target=x86_64-win7-windows-msvc -Z build-std --features=std @@ -155,7 +155,7 @@ jobs: - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: - toolchain: nightly-2025-06-01 + toolchain: nightly-2025-09-28 components: rust-src - name: default configuration env: diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 857578fdb..99b0cbaa6 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -23,7 +23,7 @@ jobs: # Fixed Nigthly version is used to prevent # CI failures which are not relevant to PR changes # on introduction of new Clippy lints. - toolchain: nightly-2025-09-15 + toolchain: nightly-2025-09-28 components: clippy,rust-src - name: std feature run: cargo clippy --features std @@ -110,7 +110,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: # We need Nightly for doc_auto_cfg - toolchain: nightly-2025-06-01 + toolchain: nightly-2025-09-28 - uses: Swatinem/rust-cache@v2 - name: Generate Docs env: From c904801e8bdac1f2b1903f80edeb07a0d4a81b20 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 29 Sep 2025 15:37:40 -0700 Subject: [PATCH 196/201] Change removed doc_auto_cfg feature The `doc_auto_cfg` feature was removed in a recent nightly. We can just switch to `doc_cfg`, and everything still works like before. Signed-off-by: Joe Richey --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 8ffd4c989..adb7e5b7e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ )] #![doc = include_str!("../README.md")] #![warn(rust_2018_idioms, unused_lifetimes, missing_docs)] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(getrandom_backend = "efi_rng", feature(uefi_std))] #![deny( clippy::cast_lossless, From 18d89843981b93032b2a2c6f1e33897075a8d727 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 29 Sep 2025 17:50:34 -0700 Subject: [PATCH 197/201] Don't run doctests with -Zsanitizer=memory Signed-off-by: Joe Richey --- .github/workflows/tests.yml | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dc8f19ca3..df5f0ec0a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -157,42 +157,37 @@ jobs: with: toolchain: nightly-2025-09-28 components: rust-src + # Use --all-targets to skip doctests, which don't work with the -Zsanitizer=memory flag. + # See: https://github.com/rust-lang/rust/issues/134172 - name: default configuration env: RUSTFLAGS: -Dwarnings -Zsanitizer=memory - RUSTDOCFLAGS: -Dwarnings -Zsanitizer=memory - run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + run: cargo test --all-targets -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu - name: --cfg getrandom_backend="linux_getrandom" env: RUSTFLAGS: --cfg getrandom_backend="linux_getrandom" -Dwarnings -Zsanitizer=memory - RUSTDOCFLAGS: --cfg getrandom_backend="linux_getrandom" -Dwarnings -Zsanitizer=memory - run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + run: cargo test --all-targets -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu - name: --cfg getrandom_backend="linux_raw" env: RUSTFLAGS: --cfg getrandom_backend="linux_raw" -Dwarnings -Zsanitizer=memory - RUSTDOCFLAGS: --cfg getrandom_backend="linux_raw" -Dwarnings -Zsanitizer=memory - run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + run: cargo test --all-targets -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu - name: --cfg getrandom_backend="linux_fallback" env: RUSTFLAGS: --cfg getrandom_backend="linux_fallback" -Dwarnings -Zsanitizer=memory - RUSTDOCFLAGS: --cfg getrandom_backend="linux_fallback" -Dwarnings -Zsanitizer=memory - run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + run: cargo test --all-targets -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu - if: ${{ matrix.arch == 'x86_64' }} name: --cfg getrandom_backend="rdrand" env: RUSTFLAGS: --cfg getrandom_backend="rdrand" -Dwarnings -Zsanitizer=memory - RUSTDOCFLAGS: --cfg getrandom_backend="rdrand" -Dwarnings -Zsanitizer=memory - run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + run: cargo test --all-targets -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu - name: --cfg getrandom_test_linux_fallback env: RUSTFLAGS: --cfg getrandom_test_linux_fallback -Dwarnings -Zsanitizer=memory - RUSTDOCFLAGS: --cfg getrandom_test_linux_fallback -Dwarnings -Zsanitizer=memory - run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + run: cargo test --all-targets -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu - name: --cfg getrandom_test_linux_without_fallback env: RUSTFLAGS: --cfg getrandom_test_linux_without_fallback -Dwarnings -Zsanitizer=memory - RUSTDOCFLAGS: --cfg getrandom_test_linux_without_fallback -Dwarnings -Zsanitizer=memory - run: cargo test -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu + run: cargo test --all-targets -Zbuild-std --target=${{ matrix.arch }}-unknown-linux-gnu cross: name: Cross From 1af25102d644c28b3b42521a17f2b65440e28a6f Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 13 Oct 2025 10:06:56 +0100 Subject: [PATCH 198/201] Implement #675: let wasm_js enable the backend by default (#730) Implements #675. Closes #726. Now, when the `wasm_js` feature is enabled and `getrandom_backend` is not specified, this crate will use the `wasm_js` implementation by default (instead of failing to compile). The backend my still be overridden via `getrandom_backend` as with any other platform. --- Cargo.toml | 4 ++-- README.md | 28 +++++++++++++--------------- src/backends.rs | 23 +++++++++++++++-------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 27f3532fd..9d913005e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,8 @@ exclude = [".*"] std = [] # Optional backend: wasm_js -# This flag enables the backend but does not select it. To use the backend, use -# this flag *and* set getrandom_backend=wasm_js (see README). +# This flag enables the wasm_js backend and uses it by default on wasm32 where +# the target_os is unknown. The getrandom_backend cfg may override this. # WARNING: It is highly recommended to enable this feature only for binary crates and tests, # i.e. avoid unconditionally enabling it in library crates. wasm_js = ["dep:wasm-bindgen", "dep:js-sys"] diff --git a/README.md b/README.md index 9866302a1..608849dab 100644 --- a/README.md +++ b/README.md @@ -131,22 +131,20 @@ 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 should be used (or if JavaScript is available at all). -To enable `getrandom`'s functionality on `wasm32-unknown-unknown` using the Web -Crypto methods [described above][opt-in] via [`wasm-bindgen`], do -*both* of the following: - -- Use the `wasm_js` feature flag, i.e. - `getrandom = { version = "0.3", features = ["wasm_js"] }`. - On its own, this only makes the backend available. (As a side effect this - will make your `Cargo.lock` significantly larger if you are not already - using [`wasm-bindgen`], but otherwise enabling this feature is harmless.) -- Set `RUSTFLAGS='--cfg getrandom_backend="wasm_js"'` ([see above][opt-in]). +We do not include support for this target in the default configuration because +our JS backend (supporting web browsers, web workers and Node.js v19 or later) +requires [`wasm-bindgen`], **bloating `Cargo.lock`** and +**potentially breaking builds** on non-web WASM platforms. -This backend supports both web browsers (main window and Web Workers) -and Node.js (v19 or later) environments. - -WARNING: It is highly recommended to enable the `wasm_js` feature only for -binary crates and tests, i.e. avoid unconditionally enabling it in library crates. +To enable `getrandom`'s functionality on `wasm32-unknown-unknown` using the Web +Crypto methods [described above][opt-in] via [`wasm-bindgen`], enable the +`wasm_js` feature flag. Optionally, one can also set +`RUSTFLAGS='--cfg getrandom_backend="wasm_js"'`. + +WARNING: enabling the `wasm_js` feature will bloat `Cargo.lock` on all platforms +(where [`wasm-bindgen`] is not an existing dependency) and is known to cause +build issues on some non-web WASM platforms, even when a different backend is +selected via `getrandom_backend`. ### Custom backend diff --git a/src/backends.rs b/src/backends.rs index 8f64824c1..991d413b5 100644 --- a/src/backends.rs +++ b/src/backends.rs @@ -31,7 +31,7 @@ cfg_if! { } else if #[cfg(getrandom_backend = "windows_legacy")] { mod windows_legacy; pub use windows_legacy::*; - } else if #[cfg(all(getrandom_backend = "wasm_js"))] { + } else if #[cfg(getrandom_backend = "wasm_js")] { cfg_if! { if #[cfg(feature = "wasm_js")] { mod wasm_js; @@ -186,13 +186,20 @@ cfg_if! { 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" - )); + cfg_if! { + if #[cfg(feature = "wasm_js")] { + mod wasm_js; + pub use wasm_js::*; + } else { + 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: \ From ccb0ca9ab039bdf0b1f7b165957f5b0e1b58f541 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 00:43:08 -0700 Subject: [PATCH 199/201] build(deps): bump the all-deps group across 1 directory with 5 updates (#734) Bumps the all-deps group with 4 updates in the / directory: [libc](https://github.com/rust-lang/libc), [cc](https://github.com/rust-lang/cc-rs), [windows-link](https://github.com/microsoft/windows-rs) and [windows-sys](https://github.com/microsoft/windows-rs). Updates `libc` from 0.2.176 to 0.2.177
Release notes

Sourced from libc's releases.

0.2.177

Added

  • Apple: Add TIOCGETA, TIOCSETA, TIOCSETAW, TIOCSETAF constants (#4736)
  • Apple: Add pthread_cond_timedwait_relative_np (#4719)
  • BSDs: Add _CS_PATH constant (#4738)
  • Linux-like: Add SIGEMT for mips* and sparc* architectures (#4730)
  • OpenBSD: Add elf_aux_info (#4729)
  • Redox: Add more sysconf constants (#4728)
  • Windows: Add wcsnlen (#4721)

Changed

  • WASIP2: Invert conditional to include p2 APIs (#4733)
Changelog

Sourced from libc's changelog.

0.2.177 - 2025-10-09

Added

  • Apple: Add TIOCGETA, TIOCSETA, TIOCSETAW, TIOCSETAF constants (#4736)
  • Apple: Add pthread_cond_timedwait_relative_np (#4719)
  • BSDs: Add _CS_PATH constant (#4738)
  • Linux-like: Add SIGEMT for mips* and sparc* architectures (#4730)
  • OpenBSD: Add elf_aux_info (#4729)
  • Redox: Add more sysconf constants (#4728)
  • Windows: Add wcsnlen (#4721)

Changed

  • WASIP2: Invert conditional to include p2 APIs (#4733)
Commits
  • 9f598d2 chore: release libc 0.2.177
  • 329a5e7 Add missing TIOCGETA/TIOCSETA constants for macOS
  • 72a40e2 add pthread_cond_timedwait_relative_np
  • 2914d6f linux_like: add SIGEMT for mips* and sparc*
  • ff2ff25 openbsd add elf_aux_info
  • 4ae44a4 Update semver tests
  • d5737a0 Define _CS_PATH on the BSDs
  • fe277da redox: more sysconf constants
  • bdad426 wasip2: Invert conditional to include p2 APIs
  • 0af069d Windows: add wcsnlen
  • Additional commits viewable in compare view

Updates `cc` from 1.2.39 to 1.2.41
Release notes

Sourced from cc's releases.

cc-v1.2.41

Other

  • Allow using VCToolsVersion to request a specific msvc version (#1589)
  • Regenerate target info (#1592)
  • Regenerate windows sys bindings (#1591)
  • Update windows-bindgen requirement from 0.64 to 0.65 (#1590)
  • Fix get_base_archiver_variant for clang-cl: use --print-search-dirs (#1587)

cc-v1.2.40

Other

  • Reorder changelog and remove duplicate Unreleased section (#1579)
  • Prefer clang if linker-plugin-lto specified (#1573)
  • Fix building for Mac Catalyst (#1577)
  • Improve ESP microcontroller targets (#1574)
Changelog

Sourced from cc's changelog.

1.2.41 - 2025-10-10

Other

  • Allow using VCToolsVersion to request a specific msvc version (#1589)
  • Regenerate target info (#1592)
  • Regenerate windows sys bindings (#1591)
  • Update windows-bindgen requirement from 0.64 to 0.65 (#1590)
  • Fix get_base_archiver_variant for clang-cl: use --print-search-dirs (#1587)

1.2.40 - 2025-10-03

Other

  • Reorder changelog and remove duplicate Unreleased section (#1579)
  • Prefer clang if linker-plugin-lto specified (#1573)
  • Fix building for Mac Catalyst (#1577)
  • Improve ESP microcontroller targets (#1574)
Commits

Updates `find-msvc-tools` from 0.1.2 to 0.1.4
Release notes

Sourced from find-msvc-tools's releases.

find-msvc-tools-v0.1.4

Other

  • Allow using VCToolsVersion to request a specific msvc version (#1589)
  • Regenerate windows sys bindings (#1591)

find-msvc-tools-v0.1.3

Other

  • Regenerate windows sys bindings (#1572)
Commits

Updates `windows-link` from 0.2.0 to 0.2.1
Commits

Updates `windows-sys` from 0.61.1 to 0.61.2
Commits

Most Recent Ignore Conditions Applied to This Pull Request | Dependency Name | Ignore Conditions | | --- | --- | | libc | [>= 0.2.172.a, < 0.2.173] |
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6c2f431a..714a65fcc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.39" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ "find-msvc-tools", "shlex", @@ -26,9 +26,9 @@ checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "getrandom" @@ -55,9 +55,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "log" @@ -272,15 +272,15 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" -version = "0.61.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] From 2d033b76f18aafed9ae10e9c36a1ee596574e15a Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 14 Oct 2025 10:31:06 -0700 Subject: [PATCH 200/201] Release Version v0.3.4 (#735) ## [0.3.4] - 2025-10-14 ### Major change to `wasm_js` backend Now, when the `wasm_js` feature is enabled, the `wasm_js` backend will be used by default. Users of `wasm32-unknown-unknown` targeting JavaScript environments like the Web and Node.js will no longer need to specify: ``` --cfg getrandom_backend="wasm_js" ``` in `RUSTFLAGS` for the crate to compile. They can now simple enable a feature. Note: this should not affect non-JS users of the `wasm32-unknown-unknown` target. Using `--cfg getrandom_backend` will still override the source of randomness _even if_ the `wasm_js` feature is enabled. This includes `--cfg getrandom_backend=custom` and `--cfg getrandom_backend=unsupported`. For more information, see the discussions in [#671], [#675], and [#730]. ### Added - `unsupported` opt-in backend [#667] - `windows_legacy` opt-in backend [#724] ### Changed - Implement Memory Sanitizer unpoisoning more precisely [#678] - Relax MSRV for the `linux_raw` opt-in backend on ARM targets [#688] - Use `getrandom` syscall on all RISC-V Linux targets [#699] - Replaced `wasi` dependency with `wasip2` [#721] - Enable `wasm_js` backend by default if the `wasm_js` feature is enabled [#730] ### Removed - Unstable `rustc-dep-of-std` crate feature [#694] [#667]: https://github.com/rust-random/getrandom/pull/667 [#671]: https://github.com/rust-random/getrandom/issues/671 [#675]: https://github.com/rust-random/getrandom/pull/675 [#678]: https://github.com/rust-random/getrandom/pull/678 [#688]: https://github.com/rust-random/getrandom/pull/688 [#694]: https://github.com/rust-random/getrandom/pull/694 [#699]: https://github.com/rust-random/getrandom/pull/699 [#721]: https://github.com/rust-random/getrandom/pull/721 [#724]: https://github.com/rust-random/getrandom/pull/724 [#730]: https://github.com/rust-random/getrandom/pull/730 --------- Signed-off-by: Joe Richey --- CHANGELOG.md | 25 +++++++++++++++++++++++-- README.md | 7 ++++--- build.rs | 4 ++-- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 799dc407a..9a53965a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.3.4] - UNRELEASED +## [0.3.4] - 2025-10-14 + +### Major change to `wasm_js` backend + +Now, when the `wasm_js` feature is enabled, the `wasm_js` backend will be used +by default. Users of `wasm32-unknown-unknown` targeting JavaScript environments +like the Web and Node.js will no longer need to specify: +``` +--cfg getrandom_backend="wasm_js" +``` +in `RUSTFLAGS` for the crate to compile. They can now simple enable a feature. + +Note: this should not affect non-JS users of the `wasm32-unknown-unknown` +target. Using `--cfg getrandom_backend` will still override the source of +randomness _even if_ the `wasm_js` feature is enabled. This includes +`--cfg getrandom_backend=custom` and `--cfg getrandom_backend=unsupported`. + +For more information, see the discussions in [#671], [#675], and [#730]. ### Added - `unsupported` opt-in backend [#667] @@ -15,17 +32,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Relax MSRV for the `linux_raw` opt-in backend on ARM targets [#688] - Use `getrandom` syscall on all RISC-V Linux targets [#699] - Replaced `wasi` dependency with `wasip2` [#721] +- Enable `wasm_js` backend by default if the `wasm_js` feature is enabled [#730] ### Removed - Unstable `rustc-dep-of-std` crate feature [#694] [#667]: https://github.com/rust-random/getrandom/pull/667 +[#671]: https://github.com/rust-random/getrandom/issues/671 +[#675]: https://github.com/rust-random/getrandom/pull/675 [#678]: https://github.com/rust-random/getrandom/pull/678 [#688]: https://github.com/rust-random/getrandom/pull/688 [#694]: https://github.com/rust-random/getrandom/pull/694 [#699]: https://github.com/rust-random/getrandom/pull/699 [#721]: https://github.com/rust-random/getrandom/pull/721 [#724]: https://github.com/rust-random/getrandom/pull/724 +[#730]: https://github.com/rust-random/getrandom/pull/730 ## [0.3.3] - 2025-05-09 @@ -33,7 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Doc improvements [#632] [#634] [#635] - Add crate version to docs.rs links used in `compile_error!`s [#639] -## Fixed +### Fixed - Error handling in WASI p1 [#661] [#632]: https://github.com/rust-random/getrandom/pull/632 diff --git a/README.md b/README.md index 608849dab..13d4388a2 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ of randomness based on their specific needs: | `linux_raw` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses raw `asm!`-based syscalls instead of `libc`. | `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction | `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register -| `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown`, `wasm32v1-none` | [`Crypto.getRandomValues`]. Requires feature `wasm_js` ([see below](#webassembly-support)). +| `wasm_js` | Web Browser, Node.js | `wasm32‑unknown‑unknown`, `wasm32v1-none` | [`Crypto.getRandomValues`]. Enabled by the `wasm_js` feature ([see below](#webassembly-support)). | `efi_rng` | UEFI | `*-unknown‑uefi` | [`EFI_RNG_PROTOCOL`] with `EFI_RNG_ALGORITHM_RAW` (requires `std` and Nightly compiler) | `windows_legacy` | Windows | `*-windows-*` | [`RtlGenRandom`] | `custom` | All targets | `*` | User-provided custom implementation (see [custom backend]) @@ -138,8 +138,9 @@ requires [`wasm-bindgen`], **bloating `Cargo.lock`** and To enable `getrandom`'s functionality on `wasm32-unknown-unknown` using the Web Crypto methods [described above][opt-in] via [`wasm-bindgen`], enable the -`wasm_js` feature flag. Optionally, one can also set -`RUSTFLAGS='--cfg getrandom_backend="wasm_js"'`. +`wasm_js` feature flag. Setting `RUSTFLAGS='--cfg getrandom_backend="wasm_js"'` +is allowed but is no longer required and does nothing (it was required in a +prior version of this crate). WARNING: enabling the `wasm_js` feature will bloat `Cargo.lock` on all platforms (where [`wasm-bindgen`] is not an existing dependency) and is known to cause diff --git a/build.rs b/build.rs index a35ad61be..28068d977 100644 --- a/build.rs +++ b/build.rs @@ -34,8 +34,8 @@ fn main() { // Automatically detect cfg(sanitize = "memory") even if cfg(sanitize) isn't // supported. Build scripts get cfg() info, even if the cfg is unstable. println!("cargo:rerun-if-changed=build.rs"); - let santizers = std::env::var("CARGO_CFG_SANITIZE").unwrap_or_default(); - if santizers.contains("memory") { + let sanitizers = std::env::var("CARGO_CFG_SANITIZE").unwrap_or_default(); + if sanitizers.contains("memory") { println!("cargo:rustc-cfg=getrandom_msan"); } From 38e4ad38309a85b56eef4fc759535ccfc322ba9a Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 14 Oct 2025 10:45:11 -0700 Subject: [PATCH 201/201] Update version number to v0.3.4 (#736) Forgot this because I'm out of practice. Signed-off-by: Joe Richey --- CHANGELOG.md | 2 +- Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a53965a5..71f9c7ce8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -631,7 +631,7 @@ Publish initial implementation. ## [0.0.0] - 2019-01-19 Publish an empty template library. -[0.3.4]: https://github.com/rust-random/getrandom/compare/v0.3.3...HEAD +[0.3.4]: https://github.com/rust-random/getrandom/compare/v0.3.3...v0.3.4 [0.3.3]: https://github.com/rust-random/getrandom/compare/v0.3.2...v0.3.3 [0.3.2]: https://github.com/rust-random/getrandom/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/rust-random/getrandom/compare/v0.3.0...v0.3.1 diff --git a/Cargo.lock b/Cargo.lock index 714a65fcc..671aa98f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,7 +32,7 @@ checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" dependencies = [ "cfg-if", "js-sys", diff --git a/Cargo.toml b/Cargo.toml index 9d913005e..933b9d9cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "getrandom" -version = "0.3.3" +version = "0.3.4" edition = "2021" rust-version = "1.63" # Sync tests.yml and README.md. authors = ["The Rand Project Developers"]