You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

getrandom

Package Overview
Dependencies
Maintainers
0
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

getrandom - cargo Package Compare versions

Comparing version
0.3.4
to
0.4.0-rc.0
+54
src/sys_rng.rs
use crate::Error;
use rand_core::{TryCryptoRng, TryRngCore};
/// A [`TryRngCore`] interface over the system's preferred random number source
///
/// This is a zero-sized struct. It can be freely constructed with just `SysRng`.
///
/// This struct is also available as [`rand::rngs::SysRng`] when using [rand].
///
/// # Usage example
///
/// `SysRng` implements [`TryRngCore`]:
/// ```
/// use getrandom::{rand_core::TryRngCore, SysRng};
///
/// let mut key = [0u8; 32];
/// SysRng.try_fill_bytes(&mut key).unwrap();
/// ```
///
/// Using it as an [`RngCore`] is possible using [`TryRngCore::unwrap_err`]:
/// ```
/// use getrandom::rand_core::{TryRngCore, RngCore};
/// use getrandom::SysRng;
///
/// let mut rng = SysRng.unwrap_err();
/// let random_u64 = rng.next_u64();
/// ```
///
/// [rand]: https://crates.io/crates/rand
/// [`rand::rngs::SysRng`]: https://docs.rs/rand/latest/rand/rngs/struct.SysRng.html
/// [`RngCore`]: rand_core::RngCore
#[derive(Clone, Copy, Debug, Default)]
pub struct SysRng;
impl TryRngCore for SysRng {
type Error = Error;
#[inline]
fn try_next_u32(&mut self) -> Result<u32, Error> {
crate::u32()
}
#[inline]
fn try_next_u64(&mut self) -> Result<u64, Error> {
crate::u64()
}
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
crate::fill(dest)
}
}
impl TryCryptoRng for SysRng {}
cfg_if! {
if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "cygwin"))] {
use libc::__errno as errno_location;
} else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd", target_os = "redox", target_os = "dragonfly"))] {
use libc::__errno_location as errno_location;
} else if #[cfg(target_os = "illumos")] {
use libc::___errno as errno_location;
} else if #[cfg(any(target_os = "macos", target_os = "freebsd"))] {
use libc::__error as errno_location;
} else if #[cfg(target_os = "haiku")] {
use libc::_errnop as errno_location;
} else if #[cfg(target_os = "nto")] {
use libc::__get_errno_ptr as errno_location;
} else if #[cfg(any(all(target_os = "horizon", target_arch = "arm"), target_os = "vita"))] {
unsafe extern "C" {
// Not provided by libc: https://github.com/rust-lang/libc/issues/1995
fn __errno() -> *mut libc::c_int;
}
use __errno as errno_location;
} else if #[cfg(target_os = "aix")] {
use libc::_Errno as errno_location;
} else {
compile_error!("errno_location is not provided for the target");
}
}
pub(crate) fn get_errno() -> libc::c_int {
unsafe { core::ptr::read(errno_location()) }
}
//! Helpers built around pointer-sized atomics.
use core::sync::atomic::{AtomicUsize, Ordering};
// This structure represents a lazily initialized static usize value. Useful
// when it is preferable to just rerun initialization instead of locking.
// unsync_init will invoke an init() function until it succeeds, then return the
// cached value for future calls.
//
// unsync_init supports init() "failing". If the init() method returns UNINIT,
// that value will be returned as normal, but will not be cached.
//
// Users should only depend on the _value_ returned by init() functions.
// Specifically, for the following init() function:
// fn init() -> usize {
// a();
// let v = b();
// c();
// v
// }
// the effects of c() or writes to shared memory will not necessarily be
// observed and additional synchronization methods may be needed.
struct LazyUsize(AtomicUsize);
impl LazyUsize {
// The initialization is not completed.
const UNINIT: usize = usize::MAX;
const fn new() -> Self {
Self(AtomicUsize::new(Self::UNINIT))
}
// Runs the init() function at most once, returning the value of some run of
// init(). Multiple callers can run their init() functions in parallel.
// init() should always return the same value, if it succeeds.
fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize {
#[cold]
fn do_init(this: &LazyUsize, init: impl FnOnce() -> usize) -> usize {
let val = init();
this.0.store(val, Ordering::Relaxed);
val
}
// Relaxed ordering is fine, as we only have a single atomic variable.
let val = self.0.load(Ordering::Relaxed);
if val != Self::UNINIT {
val
} else {
do_init(self, init)
}
}
}
// Identical to LazyUsize except with bool instead of usize.
pub(crate) struct LazyBool(LazyUsize);
impl LazyBool {
pub const fn new() -> Self {
Self(LazyUsize::new())
}
pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool {
self.0.unsync_init(|| usize::from(init())) != 0
}
}
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<u8>]) {
cfg_if! {
if #[cfg(getrandom_msan)] {
unsafe extern "C" {
fn __msan_unpoison(a: *mut core::ffi::c_void, size: usize);
}
let a = buf.as_mut_ptr().cast();
let size = buf.len();
unsafe { __msan_unpoison(a, size) };
} else {
let _ = buf;
}
}
}
use crate::Error;
use core::mem::MaybeUninit;
mod get_errno;
mod sanitizer;
pub(crate) use get_errno::get_errno;
/// 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
pub(crate) fn sys_fill_exact(
mut buf: &mut [MaybeUninit<u8>],
sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> libc::ssize_t,
) -> Result<(), Error> {
while !buf.is_empty() {
let res = sys_fill(buf);
match res {
res if res > 0 => {
let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?;
let (l, r) = buf.split_at_mut_checked(len).ok_or(Error::UNEXPECTED)?;
unsafe { sanitizer::unpoison(l) };
buf = r;
}
-1 => {
let errno = get_errno();
// We should try again if the call was interrupted.
if errno != libc::EINTR {
return Err(Error::from_errno(errno));
}
}
// Negative return codes not equal to -1 should be impossible.
// EOF (ret = 0) should be impossible, as the data we are reading
// should be an infinite stream of random bytes.
_ => return Err(Error::UNEXPECTED),
}
}
Ok(())
}
#![cfg(feature = "sys_rng")]
use getrandom::SysRng;
use getrandom::rand_core::TryRngCore;
#[test]
fn test_sys_rng() {
let x = SysRng.try_next_u64().unwrap();
let y = SysRng.try_next_u64().unwrap();
assert!(x != 0);
assert!(x != y);
}
#[test]
fn test_construction() {
assert!(SysRng.try_next_u64().unwrap() != 0);
}
+1
-1
{
"git": {
"sha1": "38e4ad38309a85b56eef4fc759535ccfc322ba9a"
"sha1": "78536276778a84f92a0ffc712401b581c6bfb354"
},
"path_in_vcs": ""
}

@@ -5,3 +5,3 @@ #![feature(test, maybe_uninit_uninit_array_transpose)]

use std::{
mem::{size_of, MaybeUninit},
mem::{MaybeUninit, size_of},
slice,

@@ -8,0 +8,0 @@ };

@@ -1,33 +0,1 @@

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<u64> {
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() {

@@ -41,18 +9,2 @@ // Automatically detect cfg(sanitize = "memory") even if cfg(sanitize) isn't

}
// Use `RtlGenRandom` on older compiler versions since win7 targets
// 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
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_backend=\"windows_legacy\"");
}
None => println!("cargo:warning=Couldn't detect minor version of the Rust compiler"),
_ => {}
}
}
}
+175
-58
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "async-trait"
version = "0.1.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bumpalo"
version = "3.19.0"
version = "3.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.2.41"
version = "1.2.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7"
checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
dependencies = [

@@ -23,15 +46,15 @@ "find-msvc-tools",

name = "cfg-if"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "find-msvc-tools"
version = "0.1.4"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
[[package]]
name = "getrandom"
version = "0.3.4"
version = "0.4.0-rc.0"
dependencies = [

@@ -42,2 +65,3 @@ "cfg-if",

"r-efi",
"rand_core",
"wasip2",

@@ -49,6 +73,12 @@ "wasm-bindgen",

[[package]]
name = "itoa"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "js-sys"
version = "0.3.80"
version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e"
checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
dependencies = [

@@ -61,17 +91,23 @@ "once_cell",

name = "libc"
version = "0.2.177"
version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
name = "log"
version = "0.4.28"
name = "libm"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "memchr"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "minicov"
version = "0.3.7"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b"
checksum = "4869b6a491569605d66d3952bcdf03df789e5b536e5f0cf7758a7f08a55ae24d"
dependencies = [

@@ -83,2 +119,21 @@ "cc",

[[package]]
name = "nu-ansi-term"
version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
"libm",
]
[[package]]
name = "once_cell"

@@ -90,6 +145,12 @@ version = "1.21.3"

[[package]]
name = "oorandom"
version = "11.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]]
name = "proc-macro2"
version = "1.0.101"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [

@@ -101,5 +162,5 @@ "unicode-ident",

name = "quote"
version = "1.0.41"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [

@@ -116,2 +177,14 @@ "proc-macro2",

[[package]]
name = "rand_core"
version = "0.10.0-rc-3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f66ee92bc15280519ef199a274fe0cafff4245d31bc39aaa31c011ad56cb1f05"
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "same-file"

@@ -126,2 +199,45 @@ version = "1.0.6"

[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "shlex"

@@ -134,5 +250,5 @@ version = "1.3.0"

name = "syn"
version = "2.0.106"
version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [

@@ -146,5 +262,5 @@ "proc-macro2",

name = "unicode-ident"
version = "1.0.19"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"

@@ -172,8 +288,9 @@ [[package]]

name = "wasm-bindgen"
version = "0.2.103"
version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819"
checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",

@@ -184,20 +301,6 @@ "wasm-bindgen-shared",

[[package]]
name = "wasm-bindgen-backend"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.53"
version = "0.4.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67"
checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
dependencies = [

@@ -213,5 +316,5 @@ "cfg-if",

name = "wasm-bindgen-macro"
version = "0.2.103"
version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0"
checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
dependencies = [

@@ -224,10 +327,10 @@ "quote",

name = "wasm-bindgen-macro-support"
version = "0.2.103"
version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32"
checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",

@@ -238,5 +341,5 @@ ]

name = "wasm-bindgen-shared"
version = "0.2.103"
version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf"
checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
dependencies = [

@@ -248,8 +351,16 @@ "unicode-ident",

name = "wasm-bindgen-test"
version = "0.3.53"
version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aee0a0f5343de9221a0d233b04520ed8dc2e6728dce180b1dcd9288ec9d9fa3c"
checksum = "25e90e66d265d3a1efc0e72a54809ab90b9c0c515915c67cdf658689d2c22c6c"
dependencies = [
"async-trait",
"cast",
"js-sys",
"libm",
"minicov",
"nu-ansi-term",
"num-traits",
"oorandom",
"serde",
"serde_json",
"wasm-bindgen",

@@ -262,5 +373,5 @@ "wasm-bindgen-futures",

name = "wasm-bindgen-test-macro"
version = "0.3.53"
version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a369369e4360c2884c3168d22bded735c43cccae97bbc147586d4b480edd138d"
checksum = "7150335716dce6028bead2b848e72f47b45e7b9422f64cccdc23bedca89affc1"
dependencies = [

@@ -274,5 +385,5 @@ "proc-macro2",

name = "web-sys"
version = "0.3.80"
version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc"
checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
dependencies = [

@@ -312,1 +423,7 @@ "js-sys",

checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
[[package]]
name = "zmij"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d6085d62852e35540689d1f97ad663e3971fc19cf5eceab364d62c646ea167"

@@ -13,6 +13,6 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO

[package]
edition = "2021"
rust-version = "1.63"
edition = "2024"
rust-version = "1.85"
name = "getrandom"
version = "0.3.4"
version = "0.4.0-rc.0"
authors = ["The Rand Project Developers"]

@@ -37,3 +37,6 @@ build = "build.rs"

[package.metadata.docs.rs]
features = ["std"]
features = [
"std",
"sys_rng",
]

@@ -52,2 +55,3 @@ [package.metadata.cross.target.x86_64-unknown-netbsd]

std = []
sys_rng = ["dep:rand_core"]
wasm_js = [

@@ -66,2 +70,6 @@ "dep:wasm-bindgen",

[[test]]
name = "sys_rng"
path = "tests/sys_rng.rs"
[[bench]]

@@ -74,2 +82,6 @@ name = "buffer"

[dependencies.rand_core]
version = "0.10.0-rc-3"
optional = true
[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]

@@ -76,0 +88,0 @@ version = "0.2.154"

# Changelog
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/)
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- `RawOsError` type alias [#739]
- `SysRng` behind new feature `sys_rng` [#751]
### Changed
- Use Edition 2024 and MSRV 1.85 [#749]
[#739]: https://github.com/rust-random/getrandom/pull/739
[#749]: https://github.com/rust-random/getrandom/pull/749
[#751]: https://github.com/rust-random/getrandom/pull/751
## [0.3.4] - 2025-10-14

@@ -634,2 +647,3 @@

[Unreleased]: https://github.com/rust-random/getrandom/compare/v0.3.4...master
[0.3.4]: https://github.com/rust-random/getrandom/compare/v0.3.3...v0.3.4

@@ -636,0 +650,0 @@ [0.3.3]: https://github.com/rust-random/getrandom/compare/v0.3.2...v0.3.3

@@ -162,3 +162,3 @@ # getrandom: system's random number generator

#[no_mangle]
#[unsafe(no_mangle)]
unsafe extern "Rust" fn __getrandom_v03_custom(

@@ -193,3 +193,3 @@ dest: *mut u8,

#[no_mangle]
#[unsafe(no_mangle)]
unsafe extern "Rust" fn __getrandom_v03_custom(

@@ -307,3 +307,3 @@ dest: *mut u8,

This crate requires Rust 1.63 or later.
This crate requires Rust 1.85 or later.

@@ -310,0 +310,0 @@ ## License

@@ -16,7 +16,5 @@ //! System-specific implementations.

mod getrandom;
mod sanitizer;
pub use getrandom::*;
} else if #[cfg(getrandom_backend = "linux_raw")] {
mod linux_raw;
mod sanitizer;
pub use linux_raw::*;

@@ -53,3 +51,2 @@ } else if #[cfg(getrandom_backend = "rdrand")] {

mod linux_raw;
mod sanitizer;
pub use linux_raw::*;

@@ -122,3 +119,2 @@ } else if #[cfg(target_os = "espidf")] {

mod linux_android_with_fallback;
mod sanitizer;
pub use linux_android_with_fallback::*;

@@ -138,4 +134,2 @@ } else if #[cfg(any(

mod getrandom;
#[cfg(any(target_os = "android", target_os = "linux"))]
mod sanitizer;
pub use getrandom::*;

@@ -142,0 +136,0 @@ } else if #[cfg(target_os = "solaris")] {

@@ -9,3 +9,3 @@ //! An implementation which calls out to an externally defined function.

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
extern "Rust" {
unsafe extern "Rust" {
fn __getrandom_v03_custom(dest: *mut u8, len: usize) -> Result<(), Error>;

@@ -12,0 +12,0 @@ }

@@ -5,3 +5,3 @@ //! Implementation for UEFI using EFI_RNG_PROTOCOL

mem::MaybeUninit,
ptr::{self, null_mut, NonNull},
ptr::{self, NonNull, null_mut},
sync::atomic::{AtomicPtr, Ordering::Relaxed},

@@ -8,0 +8,0 @@ };

@@ -7,3 +7,3 @@ //! Implementation for ESP-IDF

extern "C" {
unsafe extern "C" {
fn esp_fill_random(buf: *mut c_void, len: usize) -> u32;

@@ -10,0 +10,0 @@ }

@@ -8,3 +8,3 @@ //! Implementation for Fuchsia Zircon

#[link(name = "zircon")]
extern "C" {
unsafe extern "C" {
fn zx_cprng_draw(buffer: *mut u8, length: usize);

@@ -11,0 +11,0 @@ }

@@ -15,4 +15,4 @@ //! Implementation using getentropy(2)

#[path = "../util_libc.rs"]
mod util_libc;
#[path = "../utils/get_errno.rs"]
mod utils;

@@ -24,3 +24,4 @@ #[inline]

if ret != 0 {
return Err(util_libc::last_os_error());
let errno = utils::get_errno();
return Err(Error::from_errno(errno));
}

@@ -27,0 +28,0 @@ }

@@ -23,18 +23,10 @@ //! Implementation using getrandom(2).

#[path = "../util_libc.rs"]
mod util_libc;
#[path = "../utils/sys_fill_exact.rs"]
mod utils;
#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
util_libc::sys_fill_exact(dest, |buf| unsafe {
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
utils::sys_fill_exact(dest, |buf| unsafe {
libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0)
})
}

@@ -5,3 +5,3 @@ //! Implementation for Hermit

extern "C" {
unsafe extern "C" {
fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize;

@@ -8,0 +8,0 @@ // Note that `sys_secure_rand32/64` are implemented using `sys_read_entropy`:

//! Implementation for Linux / Android with `/dev/urandom` fallback
use super::{sanitizer, use_file};
use super::use_file;
use crate::Error;
use core::{
ffi::c_void,
mem::{transmute, MaybeUninit},
mem::{MaybeUninit, transmute},
ptr::NonNull,
sync::atomic::{AtomicPtr, Ordering},
};
use use_file::util_libc;
use use_file::utils;

@@ -47,4 +47,4 @@ pub use crate::util::{inner_u32, inner_u64};

} else if res.is_negative() {
match util_libc::last_os_error().raw_os_error() {
Some(libc::ENOSYS) => NOT_AVAILABLE, // No kernel support
match utils::get_errno() {
libc::ENOSYS => NOT_AVAILABLE, // No kernel support
// The fallback on EPERM is intentionally not done on Android since this workaround

@@ -54,3 +54,3 @@ // seems to be needed only for specific Linux-based products that aren't based

#[cfg(target_os = "linux")]
Some(libc::EPERM) => NOT_AVAILABLE, // Blocked by seccomp
libc::EPERM => NOT_AVAILABLE, // Blocked by seccomp
_ => fptr,

@@ -99,8 +99,6 @@ }

let getrandom_fn = unsafe { transmute::<NonNull<c_void>, GetRandomFn>(fptr) };
util_libc::sys_fill_exact(dest, |buf| unsafe {
let ret = getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0);
sanitizer::unpoison_linux_getrandom_result(buf, ret);
ret
utils::sys_fill_exact(dest, |buf| unsafe {
getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0)
})
}
}
//! Implementation for Linux / Android using `asm!`-based syscalls.
use super::sanitizer;
pub use crate::util::{inner_u32, inner_u64};

@@ -9,2 +8,5 @@ use crate::{Error, MaybeUninit};

#[path = "../utils/sanitizer.rs"]
mod utils;
#[allow(non_upper_case_globals)]

@@ -16,4 +18,7 @@ unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize {

cfg_if! {
if #[cfg(target_arch = "arm")] {
// TODO(MSRV-1.78): Also check `target_abi = "eabi"`.
if #[cfg(all(
target_arch = "arm",
any(target_abi = "eabi", target_abi = "eabihf"),
))] {
const __NR_getrandom: u32 = 384;
// In thumb-mode, r7 is the frame pointer and is not permitted to be used in

@@ -25,16 +30,20 @@ // an inline asm operand, so we have to use a different register and copy it

// bother with it.
core::arch::asm!(
"mov {tmp}, r7",
// TODO(MSRV-1.82): replace with `nr = const __NR_getrandom,`
"mov r7, #384",
"svc 0",
"mov r7, {tmp}",
tmp = out(reg) _,
inlateout("r0") buf => r0,
in("r1") buflen,
in("r2") flags,
options(nostack, preserves_flags)
);
} else if #[cfg(target_arch = "aarch64")] {
// TODO(MSRV-1.78): Also check `any(target_abi = "", target_abi = "ilp32")` above.
unsafe {
core::arch::asm!(
"mov {tmp}, r7",
"mov r7, {nr}",
"svc 0",
"mov r7, {tmp}",
tmp = out(reg) _,
nr = const __NR_getrandom,
inlateout("r0") buf => r0,
in("r1") buflen,
in("r2") flags,
options(nostack, preserves_flags)
);
}
} else if #[cfg(all(
target_arch = "aarch64",
any(target_abi = "", target_abi = "ilp32"),
))] {
// According to the ILP32 patch for the kernel that hasn't yet

@@ -45,41 +54,51 @@ // been merged into the mainline, "AARCH64/ILP32 ABI uses standard

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")] {
// TODO(MSRV-1.78): Also check `any(target_abi = "", target_abi = "ilp32")` above.
unsafe {
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(all(
target_arch = "loongarch64",
any(target_abi = "", target_abi = "ilp32"),
))] {
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)
);
unsafe {
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)
);
unsafe {
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)
);
unsafe {
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")] {

@@ -90,13 +109,17 @@ const __NR_getrandom: u32 = 355;

// 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")] {
// TODO(MSRV-1.78): Add `any(target_abi = "", target_abi = "x32")` above.
unsafe {
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(all(
target_arch = "x86_64",
any(target_abi = "", target_abi = "x32"),
))] {
const __X32_SYSCALL_BIT: u32 = 0x40000000;

@@ -106,13 +129,15 @@ const OFFSET: u32 = if cfg!(target_pointer_width = "32") { __X32_SYSCALL_BIT } else { 0 };

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)
);
unsafe {
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 {

@@ -133,7 +158,8 @@ compile_error!("`linux_raw` backend does not support this target arch");

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) => {
dest = dest.get_mut(len..).ok_or(Error::UNEXPECTED)?;
let (l, r) = dest.split_at_mut_checked(len).ok_or(Error::UNEXPECTED)?;
unsafe { utils::unpoison(l) };
dest = r;
if dest.is_empty() {

@@ -140,0 +166,0 @@ return Ok(());

@@ -17,4 +17,4 @@ //! Implementation for NetBSD

#[path = "../util_libc.rs"]
mod util_libc;
#[path = "../utils/sys_fill_exact.rs"]
mod utils;

@@ -76,5 +76,5 @@ unsafe extern "C" fn polyfill_using_kern_arand(

let fptr = unsafe { mem::transmute::<*mut c_void, GetRandomFn>(fptr) };
util_libc::sys_fill_exact(dest, |buf| unsafe {
utils::sys_fill_exact(dest, |buf| unsafe {
fptr(buf.as_mut_ptr().cast::<c_void>(), buf.len(), 0)
})
}
//! RDRAND backend for x86(-64) targets
use crate::{util::slice_as_uninit, Error};
use core::mem::{size_of, MaybeUninit};
use crate::{Error, util::slice_as_uninit};
use core::mem::{MaybeUninit, size_of};
#[path = "../lazy.rs"]
#[path = "../utils/lazy.rs"]
mod lazy;

@@ -31,6 +31,16 @@

#[target_feature(enable = "rdrand")]
unsafe fn rdrand() -> Option<Word> {
fn rdrand() -> Option<Word> {
for _ in 0..RETRY_LIMIT {
let mut val = 0;
if rdrand_step(&mut val) == 1 {
// SAFETY: this function is safe to call from a `[target_feature(enable
// = "rdrand")]` context (it itself is annotated with
// `target_feature(enable = "rdrand")`) but was marked unsafe until
// https://github.com/rust-lang/stdarch/commit/59864cd which was pulled
// in via https://github.com/rust-lang/rust/commit/f2eb88b which is
// expected to be included in 1.93.0. Since our MSRV is 1.85, we need to
// use unsafe here and suppress the lint.
//
// TODO(MSRV 1.93): remove allow(unused_unsafe) and the unsafe block.
#[allow(unused_unsafe)]
if unsafe { rdrand_step(&mut val) } == 1 {
return Some(val);

@@ -52,5 +62,5 @@ }

#[target_feature(enable = "rdrand")]
unsafe fn self_test() -> bool {
fn self_test() -> bool {
// On AMD, RDRAND returns 0xFF...FF on failure, count it as a collision.
let mut prev = !0; // TODO(MSRV 1.43): Move to usize::MAX
let mut prev = Word::MAX;
let mut fails = 0;

@@ -72,2 +82,5 @@ for _ in 0..8 {

// check that leaf 1 is supported before using it.
//
// TODO(MSRV 1.94): remove allow(unused_unsafe) and the unsafe blocks for `__cpuid`.
#[allow(unused_unsafe)]
let cpuid0 = unsafe { arch::__cpuid(0) };

@@ -77,2 +90,3 @@ if cpuid0.eax < 1 {

}
#[allow(unused_unsafe)]
let cpuid1 = unsafe { arch::__cpuid(1) };

@@ -108,5 +122,4 @@

// TODO: make this function safe when we have feature(target_feature_11)
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_exact(dest: &mut [MaybeUninit<u8>]) -> Option<()> {
fn rdrand_exact(dest: &mut [MaybeUninit<u8>]) -> Option<()> {
// We use chunks_exact_mut instead of chunks_mut as it allows almost all

@@ -131,3 +144,3 @@ // calls to memcpy to be elided by the compiler.

#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u32() -> Option<u32> {
fn rdrand_u32() -> Option<u32> {
rdrand().map(crate::util::truncate)

@@ -138,3 +151,3 @@ }

#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u64() -> Option<u64> {
fn rdrand_u64() -> Option<u64> {
rdrand()

@@ -145,3 +158,3 @@ }

#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u32() -> Option<u32> {
fn rdrand_u32() -> Option<u32> {
rdrand()

@@ -152,3 +165,3 @@ }

#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u64() -> Option<u64> {
fn rdrand_u64() -> Option<u64> {
let a = rdrand()?;

@@ -155,0 +168,0 @@ let b = rdrand()?;

@@ -6,7 +6,7 @@ //! RNDR register backend for aarch64 targets

use crate::{
Error,
util::{slice_as_uninit, truncate},
Error,
};
use core::arch::asm;
use core::mem::{size_of, MaybeUninit};
use core::mem::{MaybeUninit, size_of};

@@ -31,8 +31,10 @@ #[cfg(not(target_arch = "aarch64"))]

// 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,
);
unsafe {
asm!(
"mrs {x}, RNDR",
"mrs {nzcv}, NZCV",
x = out(reg) x,
nzcv = out(reg) nzcv,
);
}

@@ -52,3 +54,3 @@ // If the hardware returns a genuine random number, PSTATE.NZCV is set to 0b0000

for chunk in chunks.by_ref() {
let src = rndr()?.to_ne_bytes();
let src = unsafe { rndr() }?.to_ne_bytes();
chunk.copy_from_slice(slice_as_uninit(&src));

@@ -60,3 +62,3 @@ }

if n > 0 {
let src = rndr()?.to_ne_bytes();
let src = unsafe { rndr() }?.to_ne_bytes();
tail.copy_from_slice(slice_as_uninit(&src[..n]));

@@ -74,3 +76,3 @@ }

fn is_rndr_available() -> bool {
#[path = "../lazy.rs"]
#[path = "../utils/lazy.rs"]
mod lazy;

@@ -77,0 +79,0 @@ static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new();

@@ -17,8 +17,6 @@ //! Solaris implementation using getrandom(2).

use core::{ffi::c_void, mem::MaybeUninit};
use libc::___errno as errno_location;
pub use crate::util::{inner_u32, inner_u64};
#[path = "../util_libc.rs"]
mod util_libc;
const MAX_BYTES: usize = 1024;

@@ -37,3 +35,6 @@

// The syscall failed.
Ok(0) => return Err(util_libc::last_os_error()),
Ok(0) => {
let errno = unsafe { core::ptr::read(errno_location()) };
return Err(Error::from_errno(errno));
}
// All other cases should be impossible.

@@ -40,0 +41,0 @@ _ => return Err(Error::UNEXPECTED),

@@ -7,3 +7,3 @@ //! Implementation for SOLID

extern "C" {
unsafe extern "C" {
pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> i32;

@@ -10,0 +10,0 @@ }

//! Implementations that just need to read from a file
use crate::Error;
use core::{
ffi::c_void,
ffi::{CStr, c_void},
mem::MaybeUninit,

@@ -12,4 +12,4 @@ sync::atomic::{AtomicI32, Ordering},

#[path = "../util_libc.rs"]
pub(super) mod util_libc;
#[path = "../utils/sys_fill_exact.rs"]
pub(super) mod utils;

@@ -22,3 +22,3 @@ /// For all platforms, we use `/dev/urandom` rather than `/dev/random`.

/// - On Haiku and QNX Neutrino they are identical.
const FILE_PATH: &[u8] = b"/dev/urandom\0";
const FILE_PATH: &CStr = c"/dev/urandom";

@@ -51,3 +51,3 @@ // File descriptor is a "nonnegative integer", so we can safely use negative sentinel values.

}
util_libc::sys_fill_exact(dest, |buf| unsafe {
utils::sys_fill_exact(dest, |buf| unsafe {
libc::read(fd, buf.as_mut_ptr().cast::<c_void>(), buf.len())

@@ -58,23 +58,12 @@ })

/// Open a file in read-only mode.
///
/// # Panics
/// If `path` does not contain any zeros.
// TODO: Move `path` to `CStr` and use `CStr::from_bytes_until_nul` (MSRV 1.69)
// or C-string literals (MSRV 1.77) for statics
fn open_readonly(path: &[u8]) -> Result<libc::c_int, Error> {
assert!(path.contains(&0));
fn open_readonly(path: &CStr) -> Result<libc::c_int, Error> {
loop {
let fd = unsafe {
libc::open(
path.as_ptr().cast::<libc::c_char>(),
libc::O_RDONLY | libc::O_CLOEXEC,
)
};
let fd = unsafe { libc::open(path.as_ptr(), libc::O_RDONLY | libc::O_CLOEXEC) };
if fd >= 0 {
return Ok(fd);
}
let err = util_libc::last_os_error();
let errno = utils::get_errno();
// We should try again if open() was interrupted.
if err.raw_os_error() != Some(libc::EINTR) {
return Err(err);
if errno != libc::EINTR {
return Err(Error::from_errno(errno));
}

@@ -154,3 +143,3 @@ }

mod sync {
use super::{open_readonly, util_libc::last_os_error, Error, FD, FD_ONGOING_INIT};
use super::{Error, FD, FD_ONGOING_INIT, open_readonly, utils};

@@ -171,3 +160,3 @@ /// Wait for atomic `FD` to change value from `FD_ONGOING_INIT` to something else.

0 => true,
-1 => last_os_error().raw_os_error() == Some(libc::EAGAIN),
-1 => utils::get_errno() == libc::EAGAIN,
_ => false,

@@ -214,3 +203,3 @@ }

pub(super) fn wait_until_rng_ready() -> Result<(), Error> {
let fd = open_readonly(b"/dev/random\0")?;
let fd = open_readonly(c"/dev/random")?;
let mut pfd = libc::pollfd {

@@ -230,8 +219,8 @@ fd,

}
let err = last_os_error();
let errno = utils::get_errno();
// Assuming that `poll` is called correctly,
// on Linux it can return only EINTR and ENOMEM errors.
match err.raw_os_error() {
Some(libc::EINTR) => continue,
_ => break Err(err),
match errno {
libc::EINTR => continue,
_ => break Err(Error::from_errno(errno)),
}

@@ -238,0 +227,0 @@ };

@@ -9,5 +9,2 @@ //! Implementation for VxWorks

#[path = "../util_libc.rs"]
mod util_libc;
pub use crate::util::{inner_u32, inner_u64};

@@ -46,3 +43,4 @@

if ret != 0 {
return Err(util_libc::last_os_error());
let errno = unsafe { libc::errnoGet() };
return Err(Error::from_errno(errno));
}

@@ -49,0 +47,0 @@ }

@@ -10,3 +10,3 @@ //! Implementation for WASI Preview 1

#[link(wasm_import_module = "wasi_snapshot_preview1")]
extern "C" {
unsafe extern "C" {
fn random_get(arg0: i32, arg1: i32) -> i32;

@@ -13,0 +13,0 @@ }

@@ -59,3 +59,3 @@ //! Implementation for WASM based on Web and Node.js

#[wasm_bindgen]
extern "C" {
unsafe extern "C" {
// Crypto.getRandomValues()

@@ -62,0 +62,0 @@ #[cfg(not(target_feature = "atomics"))]

@@ -23,3 +23,3 @@ //! Legacy implementation for Windows XP and later

#[link(name = "advapi32")]
extern "system" {
unsafe extern "system" {
#[link_name = "SystemFunction036"]

@@ -26,0 +26,0 @@ fn RtlGenRandom(randombuffer: *mut c_void, randombufferlength: u32) -> BOOLEAN;

@@ -29,5 +29,3 @@ //! Implementation for Windows 10 and later

// Binding to the Windows.Win32.Security.Cryptography.ProcessPrng API. As
// bcryptprimitives.dll lacks an import library, we use "raw-dylib". This
// was added in Rust 1.65 for x86_64/aarch64 and in Rust 1.71 for x86.
// We don't need MSRV 1.71, as we only use this backend on Rust 1.78 and later.
// bcryptprimitives.dll lacks an import library, we use "raw-dylib".
#[cfg_attr(

@@ -45,7 +43,7 @@ target_arch = "x86",

)]
extern "system" {
unsafe extern "system" {
fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
}
#[allow(clippy::upper_case_acronyms, clippy::incompatible_msrv)]
type BOOL = core::ffi::c_int; // MSRV 1.64, similarly OK for this backend.
#[expect(clippy::upper_case_acronyms)]
type BOOL = core::ffi::c_int;
const TRUE: BOOL = 1;

@@ -56,9 +54,7 @@

let result = unsafe { ProcessPrng(dest.as_mut_ptr().cast::<u8>(), dest.len()) };
// Since Windows 10, calls to the user-mode RNG are guaranteed to never
// fail during runtime (rare windows W); `ProcessPrng` will only ever
// return 1 (which is how windows represents TRUE).
// See the bottom of page 6 of the aforementioned Windows RNG
// whitepaper for more information.
// `ProcessPrng` is documented to always return TRUE. All potential errors are handled
// during loading of `BCryptPrimitive.dll`. See the "Process base PRNG" section
// in the aforementioned Windows RNG whitepaper for more information.
debug_assert!(result == TRUE);
Ok(())
}

@@ -10,7 +10,5 @@ extern crate std;

Some(errno) => io::Error::from_raw_os_error(errno),
None => io::Error::new(io::ErrorKind::Other, err),
None => io::Error::other(err),
}
}
}
impl std::error::Error for Error {}

@@ -6,4 +6,2 @@ #[cfg(feature = "std")]

// This private alias mirrors `std::io::RawOsError`:
// https://doc.rust-lang.org/std/io/type.RawOsError.html)
cfg_if::cfg_if!(

@@ -13,7 +11,18 @@ if #[cfg(target_os = "uefi")] {

// https://uefi.org/specs/UEFI/2.10/Apx_D_Status_Codes.html
type RawOsError = usize;
/// Raw error code.
///
/// This alias mirrors unstable [`std::io::RawOsError`].
///
/// [`std::io::RawOsError`]: https://doc.rust-lang.org/std/io/type.RawOsError.html
pub type RawOsError = usize;
type NonZeroRawOsError = core::num::NonZeroUsize;
const UEFI_ERROR_FLAG: RawOsError = 1 << (RawOsError::BITS - 1);
} else {
type RawOsError = i32;
/// Raw error code.
///
/// This alias mirrors unstable [`std::io::RawOsError`].
///
/// [`std::io::RawOsError`]: https://doc.rust-lang.org/std/io/type.RawOsError.html
pub type RawOsError = i32;
type NonZeroRawOsError = core::num::NonZeroI32;

@@ -53,5 +62,23 @@ }

/// Creates a new instance of an `Error` from a negative error code.
/// Creates a new `Error` instance from a positive error code.
///
/// Returns [`Error::ERRNO_NOT_POSITIVE`] for zero and negative error codes.
#[cfg(not(target_os = "uefi"))]
#[allow(dead_code)]
pub(super) fn from_errno(errno: i32) -> Self {
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
}
}
/// Creates a new `Error` instance from a negative error code.
///
/// Returns [`Error::UNEXPECTED`] for zero and positive error codes.
#[cfg(not(target_os = "uefi"))]
#[allow(dead_code)]
pub(super) fn from_neg_error_code(code: RawOsError) -> Self {

@@ -182,2 +209,4 @@ if code < 0 {

impl core::error::Error for Error {}
impl fmt::Debug for Error {

@@ -184,0 +213,0 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

@@ -42,4 +42,13 @@ // Overwrite links to crate items with intra-crate links

pub use crate::error::Error;
/// `rand_core` adapter
#[cfg(feature = "sys_rng")]
mod sys_rng;
#[cfg(feature = "sys_rng")]
pub use rand_core;
#[cfg(feature = "sys_rng")]
pub use sys_rng::SysRng;
pub use crate::error::{Error, RawOsError};
/// Fill `dest` with random bytes from the system's preferred random number source.

@@ -104,3 +113,3 @@ ///

#[cfg(getrandom_msan)]
extern "C" {
unsafe extern "C" {
fn __msan_unpoison(a: *mut core::ffi::c_void, size: usize);

@@ -107,0 +116,0 @@ }

@@ -9,5 +9,4 @@ #![allow(dead_code)]

#[inline(always)]
#[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this.
pub unsafe fn slice_assume_init_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T] {
let ptr = ptr_from_mut::<[MaybeUninit<T>]>(slice) as *mut [T];
let ptr = ptr::from_mut(slice) as *mut [T];
// SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`.

@@ -25,3 +24,3 @@ unsafe { &mut *ptr }

pub fn slice_as_uninit<T>(slice: &[T]) -> &[MaybeUninit<T>] {
let ptr = ptr_from_ref::<[T]>(slice) as *const [MaybeUninit<T>];
let ptr = ptr::from_ref(slice) as *const [MaybeUninit<T>];
// SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`.

@@ -36,5 +35,4 @@ unsafe { &*ptr }

#[inline(always)]
#[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this.
pub unsafe fn slice_as_uninit_mut<T>(slice: &mut [T]) -> &mut [MaybeUninit<T>] {
let ptr = ptr_from_mut::<[T]>(slice) as *mut [MaybeUninit<T>];
let ptr = ptr::from_mut(slice) as *mut [MaybeUninit<T>];
// SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`.

@@ -44,12 +42,2 @@ unsafe { &mut *ptr }

// TODO: MSRV(1.76.0): Replace with `core::ptr::from_mut`.
fn ptr_from_mut<T: ?Sized>(r: &mut T) -> *mut T {
r
}
// TODO: MSRV(1.76.0): Replace with `core::ptr::from_ref`.
fn ptr_from_ref<T: ?Sized>(r: &T) -> *const T {
r
}
/// Default implementation of `inner_u32` on top of `fill_uninit`

@@ -56,0 +44,0 @@ #[inline]

@@ -43,8 +43,2 @@ use core::mem::MaybeUninit;

// TODO: use `[const { MaybeUninit::uninit() }; N]` after MSRV is bumped to 1.79+
// or `MaybeUninit::uninit_array`
fn uninit_vec(n: usize) -> Vec<MaybeUninit<u8>> {
vec![MaybeUninit::uninit(); n]
}
// Tests the quality of calling getrandom on two large buffers

@@ -59,4 +53,4 @@ #[test]

let mut t1 = uninit_vec(N);
let mut t2 = uninit_vec(N);
let mut t1 = [MaybeUninit::uninit(); N];
let mut t2 = [MaybeUninit::uninit(); N];
let r1 = fill_uninit(&mut t1).unwrap();

@@ -153,4 +147,4 @@ let r2 = fill_uninit(&mut t2).unwrap();

while num_bytes < 256 {
let mut buf1 = uninit_vec(N);
let mut buf2 = uninit_vec(N);
let mut buf1 = [MaybeUninit::uninit(); N];
let mut buf2 = [MaybeUninit::uninit(); N];

@@ -182,3 +176,3 @@ let s1 = &mut buf1[..size];

const N: usize = 100_000;
let mut huge = uninit_vec(N);
let mut huge = [MaybeUninit::uninit(); N];
let res = fill_uninit(&mut huge).unwrap();

@@ -267,3 +261,4 @@ assert_eq!(res.len(), N);

// WARNING: this custom implementation is for testing purposes ONLY!
#[no_mangle]
#[unsafe(no_mangle)]
unsafe extern "Rust" fn __getrandom_v03_custom(dest: *mut u8, len: usize) -> Result<(), Error> {

@@ -283,3 +278,3 @@ use std::time::{SystemTime, UNIX_EPOCH};

let val = rng.next_u32();
core::ptr::write_unaligned(dest_u32.add(i), val);
unsafe { core::ptr::write_unaligned(dest_u32.add(i), val) };
}

@@ -290,3 +285,3 @@ if len % 4 != 0 {

let val = rng.next_u32();
core::ptr::write_unaligned(dest.add(i), val as u8);
unsafe { core::ptr::write_unaligned(dest.add(i), val as u8) };
}

@@ -293,0 +288,0 @@ }

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<u8>]) {
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<u8>], 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)
}
}
}
}
//! Helpers built around pointer-sized atomics.
use core::sync::atomic::{AtomicUsize, Ordering};
// This structure represents a lazily initialized static usize value. Useful
// when it is preferable to just rerun initialization instead of locking.
// unsync_init will invoke an init() function until it succeeds, then return the
// cached value for future calls.
//
// unsync_init supports init() "failing". If the init() method returns UNINIT,
// that value will be returned as normal, but will not be cached.
//
// Users should only depend on the _value_ returned by init() functions.
// Specifically, for the following init() function:
// fn init() -> usize {
// a();
// let v = b();
// c();
// v
// }
// the effects of c() or writes to shared memory will not necessarily be
// observed and additional synchronization methods may be needed.
struct LazyUsize(AtomicUsize);
impl LazyUsize {
// The initialization is not completed.
const UNINIT: usize = usize::MAX;
const fn new() -> Self {
Self(AtomicUsize::new(Self::UNINIT))
}
// Runs the init() function at most once, returning the value of some run of
// init(). Multiple callers can run their init() functions in parallel.
// init() should always return the same value, if it succeeds.
fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize {
#[cold]
fn do_init(this: &LazyUsize, init: impl FnOnce() -> usize) -> usize {
let val = init();
this.0.store(val, Ordering::Relaxed);
val
}
// Relaxed ordering is fine, as we only have a single atomic variable.
let val = self.0.load(Ordering::Relaxed);
if val != Self::UNINIT {
val
} else {
do_init(self, init)
}
}
}
// Identical to LazyUsize except with bool instead of usize.
pub(crate) struct LazyBool(LazyUsize);
impl LazyBool {
pub const fn new() -> Self {
Self(LazyUsize::new())
}
pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool {
self.0.unsync_init(|| usize::from(init())) != 0
}
}
use crate::Error;
use core::mem::MaybeUninit;
cfg_if! {
if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "cygwin"))] {
use libc::__errno as errno_location;
} else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd", target_os = "redox", target_os = "dragonfly"))] {
use libc::__errno_location as errno_location;
} else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] {
use libc::___errno as errno_location;
} else if #[cfg(any(target_os = "macos", target_os = "freebsd"))] {
use libc::__error as errno_location;
} else if #[cfg(target_os = "haiku")] {
use libc::_errnop as errno_location;
} else if #[cfg(target_os = "nto")] {
use libc::__get_errno_ptr as errno_location;
} else if #[cfg(any(all(target_os = "horizon", target_arch = "arm"), target_os = "vita"))] {
extern "C" {
// Not provided by libc: https://github.com/rust-lang/libc/issues/1995
fn __errno() -> *mut libc::c_int;
}
use __errno as errno_location;
} else if #[cfg(target_os = "aix")] {
use libc::_Errno as errno_location;
}
}
cfg_if! {
if #[cfg(target_os = "vxworks")] {
use libc::errnoGet as get_errno;
} else {
unsafe fn get_errno() -> libc::c_int { *errno_location() }
}
}
pub(crate) fn last_os_error() -> Error {
// We assume that on all targets which use the `util_libc` module `c_int` is equal to `i32`
let errno: i32 = unsafe { get_errno() };
if errno > 0 {
let code = errno
.checked_neg()
.expect("Positive number can be always negated");
Error::from_neg_error_code(code)
} else {
Error::ERRNO_NOT_POSITIVE
}
}
/// Fill a buffer by repeatedly invoking `sys_fill`.
///
/// The `sys_fill` function:
/// - should return -1 and set errno on failure
/// - should return the number of bytes written on success
#[allow(dead_code)]
pub(crate) fn sys_fill_exact(
mut buf: &mut [MaybeUninit<u8>],
sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> libc::ssize_t,
) -> Result<(), Error> {
while !buf.is_empty() {
let res = sys_fill(buf);
match res {
res if res > 0 => {
let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?;
buf = buf.get_mut(len..).ok_or(Error::UNEXPECTED)?;
}
-1 => {
let err = last_os_error();
// We should try again if the call was interrupted.
if err.raw_os_error() != Some(libc::EINTR) {
return Err(err);
}
}
// Negative return codes not equal to -1 should be impossible.
// EOF (ret = 0) should be impossible, as the data we are reading
// should be an infinite stream of random bytes.
_ => return Err(Error::UNEXPECTED),
}
}
Ok(())
}

Sorry, the diff of this file is not supported yet