| Joel Galenson | 4be0c6d | 2020-07-07 13:20:14 -0700 | [diff] [blame] | 1 | // Copyright 2018 Developers of the Rand project. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| 4 | // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| 5 | // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your |
| 6 | // option. This file may not be copied, modified, or distributed |
| 7 | // except according to those terms. |
| 8 | |
| 9 | //! Implementation for the Solaris family |
| 10 | //! |
| 11 | //! Read from `/dev/random`, with chunks of limited size (256 bytes). |
| 12 | //! `/dev/random` uses the Hash_DRBG with SHA512 algorithm from NIST SP 800-90A. |
| 13 | //! `/dev/urandom` uses the FIPS 186-2 algorithm, which is considered less |
| 14 | //! secure. We choose to read from `/dev/random`. |
| 15 | //! |
| 16 | //! Since Solaris 11.3 and mid-2015 illumos, the `getrandom` syscall is available. |
| 17 | //! To make sure we can compile on both Solaris and its derivatives, as well as |
| 18 | //! function, we check for the existence of getrandom(2) in libc by calling |
| 19 | //! libc::dlsym. |
| 20 | use crate::util_libc::{sys_fill_exact, Weak}; |
| 21 | use crate::{use_file, Error}; |
| 22 | use core::mem; |
| 23 | |
| 24 | #[cfg(target_os = "illumos")] |
| 25 | type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t; |
| 26 | #[cfg(target_os = "solaris")] |
| 27 | type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::c_int; |
| 28 | |
| 29 | pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { |
| 30 | static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") }; |
| 31 | if let Some(fptr) = GETRANDOM.ptr() { |
| 32 | let func: GetRandomFn = unsafe { mem::transmute(fptr) }; |
| 33 | // 256 bytes is the lowest common denominator across all the Solaris |
| 34 | // derived platforms for atomically obtaining random data. |
| 35 | for chunk in dest.chunks_mut(256) { |
| 36 | sys_fill_exact(chunk, |buf| unsafe { |
| 37 | func(buf.as_mut_ptr(), buf.len(), 0) as libc::ssize_t |
| 38 | })? |
| 39 | } |
| 40 | Ok(()) |
| 41 | } else { |
| 42 | use_file::getrandom_inner(dest) |
| 43 | } |
| 44 | } |