From 495fefd20f69d2503ba58fb6181e5c067b2cbe97 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 2 May 2024 00:31:50 -0700 Subject: [PATCH 1/2] Unconditionally use libc::getrandom on Illumos and Solaris Also removes the use of `GRND_RANDOM`, which appears to be based on outdated staements about the RNGs. For Solaris, see [this blog post](https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2). For Illumos, the algorithms are less clear, but I don't see a clear reason to continue using `GRND_RANDOM`. I updated the documentation in `getrandom.rs` to full document this decision and to have a common place listing when `getrandom(2)` became avalible on each platform. I also updated the main lib.rs docs to point to the correct man pages. Note that Solaris 11.3 has a maximum buffer length of 1024 bytes, while Illumos doesn't have this sort of issue. Signed-off-by: Joe Richey --- src/getrandom.rs | 40 +++++++++++++++++++++++++++++++++++++--- src/lib.rs | 14 +++++++------- src/solaris_illumos.rs | 41 ----------------------------------------- src/use_file.rs | 16 +--------------- 4 files changed, 45 insertions(+), 66 deletions(-) delete mode 100644 src/solaris_illumos.rs diff --git a/src/getrandom.rs b/src/getrandom.rs index 38100384..70c118e8 100644 --- a/src/getrandom.rs +++ b/src/getrandom.rs @@ -1,9 +1,43 @@ //! Implementation using libc::getrandom +//! +//! 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 +//! - DragonFly 5.7 +//! - Hurd Glibc 2.31 +//! - shim-3ds since Feb 2022 +//! +//! For all platforms, we use the default randomness source (the one used +//! by /dev/urandom) rather than the /dev/random (GRND_RANDOM) source. For +//! more information see the linked man pages in lib.rs. +//! - On Linux, "/dev/urandom is preferred and sufficient in all use cases". +//! - On NetBSD, "there is no reason to ever use" GRND_RANDOM. +//! - On Illumos, the default source is used for getentropy() and the like: +//! https://github.com/illumos/illumos-gate/blob/89cf0c2ce8a47dcf555bb1596f9034f07b9467fa/usr/src/lib/libc/port/gen/getentropy.c#L33 +//! - On Solaris, both sources use FIPS 140-2 / NIST SP-900-90A DRBGs, see: +//! https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2 +//! - On Redox, only /dev/urandom is provided. +//! - On AIX, /dev/urandom will "provide cryptographically secure output". +//! - On Haiku, QNX Neutrino, DragonFly, and FreeBSD, they are identical. use crate::{util_libc::sys_fill_exact, Error}; use core::mem::MaybeUninit; +// On Solaris 11.3, getrandom() will fail if bufsz > 1024 (bufsz > 133120 on Solaris 11.4). +// This issue is not present in Illumos's implementation of getrandom(). +#[cfg(target_os = "solaris")] +const MAX_BYTES: usize = 1024; +#[cfg(not(target_os = "solaris"))] +const MAX_BYTES: usize = usize::MAX; + 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) - }) + for chunk in dest.chunks_mut(MAX_BYTES) { + sys_fill_exact(chunk, |buf| unsafe { + libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0) + })?; + } + Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 6823041f..d2666f15 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,8 @@ //! | OpenBSD | `*‑openbsd` | [`getentropy`][7] //! | NetBSD | `*‑netbsd` | [`getrandom`][16] if available, otherwise [`kern.arandom`][8] //! | Dragonfly BSD | `*‑dragonfly` | [`getrandom`][9] -//! | Solaris, illumos | `*‑solaris`, `*‑illumos` | [`getrandom`][11] if available, otherwise [`/dev/random`][12] +//! | Solaris | `*‑solaris` | [`getrandom`][11] +//! | Illumos | `*‑illumos` | [`getrandom`][12] //! | Fuchsia OS | `*‑fuchsia` | [`cprng_draw`] //! | Redox | `*‑redox` | `/dev/urandom` //! | Haiku | `*‑haiku` | `/dev/urandom` (identical to `/dev/random`) @@ -25,7 +26,7 @@ //! | WASI | `wasm32‑wasi` | [`random_get`] //! | 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 | `armv6k-nintendo-3ds` | [`getrandom`][1] +//! | 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] @@ -177,12 +178,13 @@ //! [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://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.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 //! //! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom //! [`Crypto.getRandomValues`]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues @@ -249,6 +251,8 @@ cfg_if! { target_os = "dragonfly", target_os = "freebsd", target_os = "hurd", + target_os = "illumos", + target_os = "solaris", // 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"), @@ -302,10 +306,6 @@ cfg_if! { } else if #[cfg(any(target_os = "android", target_os = "linux"))] { mod util_libc; #[path = "linux_android.rs"] mod imp; - } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] { - mod util_libc; - mod use_file; - #[path = "solaris_illumos.rs"] mod imp; } else if #[cfg(target_os = "netbsd")] { mod util_libc; #[path = "netbsd.rs"] mod imp; diff --git a/src/solaris_illumos.rs b/src/solaris_illumos.rs deleted file mode 100644 index fbc23943..00000000 --- a/src/solaris_illumos.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! Implementation for the Solaris family -//! -//! `/dev/random` uses the Hash_DRBG with SHA512 algorithm from NIST SP 800-90A. -//! `/dev/urandom` uses the FIPS 186-2 algorithm, which is considered less -//! secure. We choose to read from `/dev/random` (and use GRND_RANDOM). -//! -//! Solaris 11.3 and late-2018 illumos added the getrandom(2) libc function. -//! To make sure we can compile on both Solaris and its derivatives, as well as -//! function, we check for the existence of getrandom(2) in libc by calling -//! libc::dlsym. -use crate::{ - use_file, - util_libc::{sys_fill_exact, Weak}, - Error, -}; -use core::mem::{self, MaybeUninit}; - -static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") }; -type GetRandomFn = - unsafe extern "C" fn(*mut libc::c_void, libc::size_t, libc::c_uint) -> libc::ssize_t; - -pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - if let Some(fptr) = GETRANDOM.ptr() { - let func: GetRandomFn = unsafe { mem::transmute(fptr) }; - // 256 bytes is the lowest common denominator across all the Solaris - // derived platforms for atomically obtaining random data. - for chunk in dest.chunks_mut(256) { - sys_fill_exact(chunk, |buf| unsafe { - // A cast is needed for the flags as libc uses the wrong type. - func( - buf.as_mut_ptr() as *mut libc::c_void, - buf.len(), - libc::GRND_RANDOM as libc::c_uint, - ) - })? - } - Ok(()) - } else { - use_file::getrandom_inner(dest) - } -} diff --git a/src/use_file.rs b/src/use_file.rs index 333325b5..cf2082ed 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -9,21 +9,7 @@ use core::{ sync::atomic::{AtomicUsize, Ordering::Relaxed}, }; -// We prefer using /dev/urandom and only use /dev/random if the OS -// documentation indicates that /dev/urandom is insecure. -// On Solaris/Illumos, see src/solaris_illumos.rs -// On Dragonfly, Haiku, and QNX Neutrino the devices are identical. -#[cfg(any(target_os = "solaris", target_os = "illumos"))] -const FILE_PATH: &str = "/dev/random\0"; -#[cfg(any( - target_os = "aix", - target_os = "android", - target_os = "linux", - target_os = "redox", - target_os = "dragonfly", - target_os = "haiku", - target_os = "nto", -))] +// We always use /dev/urandom, see the comment in getrandom.rs. const FILE_PATH: &str = "/dev/urandom\0"; const FD_UNINIT: usize = usize::max_value(); From e535bc83e12f54ea95bca5da8784e62a91f853ec 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: Fri, 3 May 2024 17:01:56 +0300 Subject: [PATCH 2/2] Switch Solaris to getentropy --- src/getrandom.rs | 31 ++++--------------------------- src/lib.rs | 10 +++------- src/use_file.rs | 7 ++++++- 3 files changed, 13 insertions(+), 35 deletions(-) diff --git a/src/getrandom.rs b/src/getrandom.rs index 70c118e8..3b2cde15 100644 --- a/src/getrandom.rs +++ b/src/getrandom.rs @@ -1,4 +1,4 @@ -//! Implementation using libc::getrandom +//! Implementation using `libc::getrandom`. //! //! Available since: //! - Linux Kernel 3.17, Glibc 2.25, Musl 1.1.20 @@ -10,34 +10,11 @@ //! - DragonFly 5.7 //! - Hurd Glibc 2.31 //! - shim-3ds since Feb 2022 -//! -//! For all platforms, we use the default randomness source (the one used -//! by /dev/urandom) rather than the /dev/random (GRND_RANDOM) source. For -//! more information see the linked man pages in lib.rs. -//! - On Linux, "/dev/urandom is preferred and sufficient in all use cases". -//! - On NetBSD, "there is no reason to ever use" GRND_RANDOM. -//! - On Illumos, the default source is used for getentropy() and the like: -//! https://github.com/illumos/illumos-gate/blob/89cf0c2ce8a47dcf555bb1596f9034f07b9467fa/usr/src/lib/libc/port/gen/getentropy.c#L33 -//! - On Solaris, both sources use FIPS 140-2 / NIST SP-900-90A DRBGs, see: -//! https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2 -//! - On Redox, only /dev/urandom is provided. -//! - On AIX, /dev/urandom will "provide cryptographically secure output". -//! - On Haiku, QNX Neutrino, DragonFly, and FreeBSD, they are identical. use crate::{util_libc::sys_fill_exact, Error}; use core::mem::MaybeUninit; -// On Solaris 11.3, getrandom() will fail if bufsz > 1024 (bufsz > 133120 on Solaris 11.4). -// This issue is not present in Illumos's implementation of getrandom(). -#[cfg(target_os = "solaris")] -const MAX_BYTES: usize = 1024; -#[cfg(not(target_os = "solaris"))] -const MAX_BYTES: usize = usize::MAX; - pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - for chunk in dest.chunks_mut(MAX_BYTES) { - sys_fill_exact(chunk, |buf| unsafe { - libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0) - })?; - } - Ok(()) + sys_fill_exact(dest, |buf| unsafe { + libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0) + }) } diff --git a/src/lib.rs b/src/lib.rs index d2666f15..c30e95bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ //! | OpenBSD | `*‑openbsd` | [`getentropy`][7] //! | NetBSD | `*‑netbsd` | [`getrandom`][16] if available, otherwise [`kern.arandom`][8] //! | Dragonfly BSD | `*‑dragonfly` | [`getrandom`][9] -//! | Solaris | `*‑solaris` | [`getrandom`][11] +//! | Solaris | `*‑solaris` | [`getentropy`][11] //! | Illumos | `*‑illumos` | [`getrandom`][12] //! | Fuchsia OS | `*‑fuchsia` | [`cprng_draw`] //! | Redox | `*‑redox` | `/dev/urandom` @@ -31,10 +31,6 @@ //! | QNX Neutrino | `*‑nto-qnx*` | [`/dev/urandom`][14] (identical to `/dev/random`) //! | AIX | `*-ibm-aix` | [`/dev/urandom`][15] //! -//! There is no blanket implementation on `unix` targets that reads from -//! `/dev/urandom`. This ensures all supported targets are using the recommended -//! interface and respect maximum buffer sizes. -//! //! Pull Requests that add support for new targets to `getrandom` are always welcome. //! //! ## Unsupported targets @@ -177,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/getrandom-2.html +//! [11]: https://docs.oracle.com/cd/E88353_01/html/E37841/getentropy-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 @@ -242,6 +238,7 @@ cfg_if! { } else if #[cfg(any( target_os = "macos", target_os = "openbsd", + target_os = "solaris", target_os = "vita", target_os = "emscripten", ))] { @@ -252,7 +249,6 @@ cfg_if! { target_os = "freebsd", target_os = "hurd", target_os = "illumos", - target_os = "solaris", // 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/use_file.rs b/src/use_file.rs index cf2082ed..bd643ae5 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -9,7 +9,12 @@ use core::{ sync::atomic::{AtomicUsize, Ordering::Relaxed}, }; -// We always use /dev/urandom, see the comment in getrandom.rs. +/// For all platforms, we use `/dev/urandom` rather than `/dev/random`. +/// For more information see the linked man pages in lib.rs. +/// - On Linux, "/dev/urandom is preferred and sufficient in all use cases". +/// - On Redox, only /dev/urandom is provided. +/// - On AIX, /dev/urandom will "provide cryptographically secure output". +/// - On Haiku and QNX Neutrino they are identical. const FILE_PATH: &str = "/dev/urandom\0"; const FD_UNINIT: usize = usize::max_value();