diff --git a/src/getentropy.rs b/src/getentropy.rs index 1d35b572..41bab8fe 100644 --- a/src/getentropy.rs +++ b/src/getentropy.rs @@ -1,10 +1,12 @@ -//! Implementation using libc::getentropy +//! Implementation using getentropy(2) //! //! Available since: //! - macOS 10.12 //! - OpenBSD 5.6 //! - Emscripten 2.0.5 //! - vita newlib since Dec 2021 +//! +//! For these targets, we use getentropy(2) because getrandom(2) doesn't exist. use crate::{util_libc::last_os_error, Error}; use core::mem::MaybeUninit; diff --git a/src/getrandom.rs b/src/getrandom.rs index 3b2cde15..bc583653 100644 --- a/src/getrandom.rs +++ b/src/getrandom.rs @@ -1,15 +1,20 @@ -//! Implementation using `libc::getrandom`. +//! Implementation using getrandom(2). //! //! Available since: //! - Linux Kernel 3.17, Glibc 2.25, Musl 1.1.20 //! - Android API level 23 (Marshmallow) //! - NetBSD 10.0 //! - FreeBSD 12.0 -//! - Solaris 11.3 -//! - Illumos since Dec 2018 +//! - illumos since Dec 2018 //! - DragonFly 5.7 //! - Hurd Glibc 2.31 //! - shim-3ds since Feb 2022 +//! +//! For these platforms, we always use the default pool and never set the +//! GRND_RANDOM flag to use the /dev/random pool. On Linux/Android/Hurd, using +//! GRND_RANDOM is not recommended. On NetBSD/FreeBSD/Dragonfly/3ds, it does +//! nothing. On illumos, the default pool is used to implement getentropy(2), +//! so we assume it is acceptable here. use crate::{util_libc::sys_fill_exact, Error}; use core::mem::MaybeUninit; diff --git a/src/lib.rs b/src/lib.rs index c30e95bb..1305f2bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,8 +12,8 @@ //! | OpenBSD | `*‑openbsd` | [`getentropy`][7] //! | NetBSD | `*‑netbsd` | [`getrandom`][16] if available, otherwise [`kern.arandom`][8] //! | Dragonfly BSD | `*‑dragonfly` | [`getrandom`][9] -//! | Solaris | `*‑solaris` | [`getentropy`][11] -//! | Illumos | `*‑illumos` | [`getrandom`][12] +//! | 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`) @@ -173,7 +173,7 @@ //! [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/getentropy-2.html +//! [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 @@ -238,7 +238,6 @@ cfg_if! { } else if #[cfg(any( target_os = "macos", target_os = "openbsd", - target_os = "solaris", target_os = "vita", target_os = "emscripten", ))] { @@ -302,6 +301,9 @@ cfg_if! { } 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; diff --git a/src/solaris.rs b/src/solaris.rs new file mode 100644 index 00000000..761acc6b --- /dev/null +++ b/src/solaris.rs @@ -0,0 +1,28 @@ +//! Solaris implementation using getrandom(2). +//! +//! While getrandom(2) has been available since Solaris 11.3, it has a few +//! quirks not present on other OSes. First, on Solaris 11.3, calls will always +//! fail if bufsz > 1024. Second, it will always either fail or completely fill +//! the buffer (returning bufsz). Finally, "if GRND_RANDOM is not specified +//! then getrandom(2) is always a non blocking call". This _might_ imply that +//! in early-boot scenarios with low entropy, getrandom(2) will not properly +//! block. To be safe, we set GRND_RANDOM, mirroring the man page examples. +//! +//! For more information, see the man page linked in lib.rs and this blog post: +//! https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2 +//! which also explains why this crate should not use getentropy(2). +use crate::{util_libc::last_os_error, Error}; +use core::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 ret = libc::getrandom(ptr, chunk.len(), libc::GRND_RANDOM); + if ret != (chunk.len() as isize) { + return Err(last_os_error()); + } + } + Ok(()) +}