Skip to content

Commit 229d870

Browse files
authored
Use libc::getrandom on Solaris and update docs. (#420)
#417 used `getentropy(2)` on Solaris, but after looking at [the blog post introducing `getrandom()` and `getentropy()`](https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2), it seems like we should prefer using `getrandom` based on this quote: > On Solaris the output of getentropy(2) is entropy and should not be used where randomness is needed, in particular it must not be used where an IV or nonce is needed when calling a cryptographic operation. It is intended only for seeding a user space RBG (Random Bit Generator) system. More specifically the data returned by getentropy(2) has not had the required FIPS 140-2 processing for the DRBG applied to it. I also updated some of the documentation explaining: - Why we use `getentropy(2)` - Why we only set `GRND_RANDOM` on Solaris Signed-off-by: Joe Richey <[email protected]>
1 parent 924c88d commit 229d870

File tree

4 files changed

+51
-8
lines changed

4 files changed

+51
-8
lines changed

src/getentropy.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
//! Implementation using libc::getentropy
1+
//! Implementation using getentropy(2)
22
//!
33
//! Available since:
44
//! - macOS 10.12
55
//! - OpenBSD 5.6
66
//! - Emscripten 2.0.5
77
//! - vita newlib since Dec 2021
8+
//!
9+
//! For these targets, we use getentropy(2) because getrandom(2) doesn't exist.
810
use crate::{util_libc::last_os_error, Error};
911
use core::mem::MaybeUninit;
1012

src/getrandom.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
1-
//! Implementation using `libc::getrandom`.
1+
//! Implementation using getrandom(2).
22
//!
33
//! Available since:
44
//! - Linux Kernel 3.17, Glibc 2.25, Musl 1.1.20
55
//! - Android API level 23 (Marshmallow)
66
//! - NetBSD 10.0
77
//! - FreeBSD 12.0
8-
//! - Solaris 11.3
9-
//! - Illumos since Dec 2018
8+
//! - illumos since Dec 2018
109
//! - DragonFly 5.7
1110
//! - Hurd Glibc 2.31
1211
//! - shim-3ds since Feb 2022
12+
//!
13+
//! For these platforms, we always use the default pool and never set the
14+
//! GRND_RANDOM flag to use the /dev/random pool. On Linux/Android/Hurd, using
15+
//! GRND_RANDOM is not recommended. On NetBSD/FreeBSD/Dragonfly/3ds, it does
16+
//! nothing. On illumos, the default pool is used to implement getentropy(2),
17+
//! so we assume it is acceptable here.
1318
use crate::{util_libc::sys_fill_exact, Error};
1419
use core::mem::MaybeUninit;
1520

src/lib.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
//! | OpenBSD | `*‑openbsd` | [`getentropy`][7]
1313
//! | NetBSD | `*‑netbsd` | [`getrandom`][16] if available, otherwise [`kern.arandom`][8]
1414
//! | Dragonfly BSD | `*‑dragonfly` | [`getrandom`][9]
15-
//! | Solaris | `*‑solaris` | [`getentropy`][11]
16-
//! | Illumos | `*‑illumos` | [`getrandom`][12]
15+
//! | Solaris | `*‑solaris` | [`getrandom`][11] (with `GRND_RANDOM`)
16+
//! | illumos | `*‑illumos` | [`getrandom`][12]
1717
//! | Fuchsia OS | `*‑fuchsia` | [`cprng_draw`]
1818
//! | Redox | `*‑redox` | `/dev/urandom`
1919
//! | Haiku | `*‑haiku` | `/dev/urandom` (identical to `/dev/random`)
@@ -173,7 +173,7 @@
173173
//! [7]: https://man.openbsd.org/getentropy.2
174174
//! [8]: https://man.netbsd.org/sysctl.7
175175
//! [9]: https://leaf.dragonflybsd.org/cgi/web-man?command=getrandom
176-
//! [11]: https://docs.oracle.com/cd/E88353_01/html/E37841/getentropy-2.html
176+
//! [11]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
177177
//! [12]: https://illumos.org/man/2/getrandom
178178
//! [13]: https://github.com/emscripten-core/emscripten/pull/12240
179179
//! [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! {
238238
} else if #[cfg(any(
239239
target_os = "macos",
240240
target_os = "openbsd",
241-
target_os = "solaris",
242241
target_os = "vita",
243242
target_os = "emscripten",
244243
))] {
@@ -302,6 +301,9 @@ cfg_if! {
302301
} else if #[cfg(any(target_os = "android", target_os = "linux"))] {
303302
mod util_libc;
304303
#[path = "linux_android.rs"] mod imp;
304+
} else if #[cfg(target_os = "solaris")] {
305+
mod util_libc;
306+
#[path = "solaris.rs"] mod imp;
305307
} else if #[cfg(target_os = "netbsd")] {
306308
mod util_libc;
307309
#[path = "netbsd.rs"] mod imp;

src/solaris.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//! Solaris implementation using getrandom(2).
2+
//!
3+
//! While getrandom(2) has been available since Solaris 11.3, it has a few
4+
//! quirks not present on other OSes. First, on Solaris 11.3, calls will always
5+
//! fail if bufsz > 1024. Second, it will always either fail or completely fill
6+
//! the buffer (returning bufsz). Third, error is indicated by returning 0,
7+
//! rather than by returning -1. Finally, "if GRND_RANDOM is not specified
8+
//! then getrandom(2) is always a non blocking call". This _might_ imply that
9+
//! in early-boot scenarios with low entropy, getrandom(2) will not properly
10+
//! block. To be safe, we set GRND_RANDOM, mirroring the man page examples.
11+
//!
12+
//! For more information, see the man page linked in lib.rs and this blog post:
13+
//! https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2
14+
//! which also explains why this crate should not use getentropy(2).
15+
use crate::{util_libc::last_os_error, Error};
16+
use core::mem::MaybeUninit;
17+
18+
const MAX_BYTES: usize = 1024;
19+
20+
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
21+
for chunk in dest.chunks_mut(MAX_BYTES) {
22+
let ptr = chunk.as_mut_ptr() as *mut libc::c_void;
23+
let ret = unsafe { libc::getrandom(ptr, chunk.len(), libc::GRND_RANDOM) };
24+
// In case the man page has a typo, we also check for negative ret.
25+
if ret <= 0 {
26+
return Err(last_os_error());
27+
}
28+
// If getrandom(2) succeeds, it should have completely filled chunk.
29+
if (ret as usize) != chunk.len() {
30+
return Err(Error::UNEXPECTED);
31+
}
32+
}
33+
Ok(())
34+
}

0 commit comments

Comments
 (0)