1 | //! Implementations that just need to read from a file |
2 | use crate::{ |
3 | util_libc::{open_readonly, sys_fill_exact}, |
4 | Error, |
5 | }; |
6 | use core::{ |
7 | cell::UnsafeCell, |
8 | mem::MaybeUninit, |
9 | sync::atomic::{AtomicUsize, Ordering::Relaxed}, |
10 | }; |
11 | |
12 | /// For all platforms, we use `/dev/urandom` rather than `/dev/random`. |
13 | /// For more information see the linked man pages in lib.rs. |
14 | /// - On Linux, "/dev/urandom is preferred and sufficient in all use cases". |
15 | /// - On Redox, only /dev/urandom is provided. |
16 | /// - On AIX, /dev/urandom will "provide cryptographically secure output". |
17 | /// - On Haiku and QNX Neutrino they are identical. |
18 | const FILE_PATH: &str = "/dev/urandom \0" ; |
19 | const FD_UNINIT: usize = usize::max_value(); |
20 | |
21 | pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> { |
22 | let fd: i32 = get_rng_fd()?; |
23 | sys_fill_exact(buf:dest, |buf: &mut [MaybeUninit]| unsafe { |
24 | libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, count:buf.len()) |
25 | }) |
26 | } |
27 | |
28 | // Returns the file descriptor for the device file used to retrieve random |
29 | // bytes. The file will be opened exactly once. All subsequent calls will |
30 | // return the same file descriptor. This file descriptor is never closed. |
31 | fn get_rng_fd() -> Result<libc::c_int, Error> { |
32 | static FD: AtomicUsize = AtomicUsize::new(FD_UNINIT); |
33 | fn get_fd() -> Option<libc::c_int> { |
34 | match FD.load(Relaxed) { |
35 | FD_UNINIT => None, |
36 | val => Some(val as libc::c_int), |
37 | } |
38 | } |
39 | |
40 | // Use double-checked locking to avoid acquiring the lock if possible. |
41 | if let Some(fd) = get_fd() { |
42 | return Ok(fd); |
43 | } |
44 | |
45 | // SAFETY: We use the mutex only in this method, and we always unlock it |
46 | // before returning, making sure we don't violate the pthread_mutex_t API. |
47 | static MUTEX: Mutex = Mutex::new(); |
48 | unsafe { MUTEX.lock() }; |
49 | let _guard = DropGuard(|| unsafe { MUTEX.unlock() }); |
50 | |
51 | if let Some(fd) = get_fd() { |
52 | return Ok(fd); |
53 | } |
54 | |
55 | // On Linux, /dev/urandom might return insecure values. |
56 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
57 | wait_until_rng_ready()?; |
58 | |
59 | let fd = unsafe { open_readonly(FILE_PATH)? }; |
60 | // The fd always fits in a usize without conflicting with FD_UNINIT. |
61 | debug_assert!(fd >= 0 && (fd as usize) < FD_UNINIT); |
62 | FD.store(fd as usize, Relaxed); |
63 | |
64 | Ok(fd) |
65 | } |
66 | |
67 | // Succeeds once /dev/urandom is safe to read from |
68 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
69 | fn wait_until_rng_ready() -> Result<(), Error> { |
70 | // Poll /dev/random to make sure it is ok to read from /dev/urandom. |
71 | let fd = unsafe { open_readonly("/dev/random \0" )? }; |
72 | let mut pfd = libc::pollfd { |
73 | fd, |
74 | events: libc::POLLIN, |
75 | revents: 0, |
76 | }; |
77 | let _guard = DropGuard(|| unsafe { |
78 | libc::close(fd); |
79 | }); |
80 | |
81 | loop { |
82 | // A negative timeout means an infinite timeout. |
83 | let res = unsafe { libc::poll(&mut pfd, 1, -1) }; |
84 | if res >= 0 { |
85 | debug_assert_eq!(res, 1); // We only used one fd, and cannot timeout. |
86 | return Ok(()); |
87 | } |
88 | let err = crate::util_libc::last_os_error(); |
89 | match err.raw_os_error() { |
90 | Some(libc::EINTR) | Some(libc::EAGAIN) => continue, |
91 | _ => return Err(err), |
92 | } |
93 | } |
94 | } |
95 | |
96 | struct Mutex(UnsafeCell<libc::pthread_mutex_t>); |
97 | |
98 | impl Mutex { |
99 | const fn new() -> Self { |
100 | Self(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)) |
101 | } |
102 | unsafe fn lock(&self) { |
103 | let r: i32 = libc::pthread_mutex_lock(self.0.get()); |
104 | debug_assert_eq!(r, 0); |
105 | } |
106 | unsafe fn unlock(&self) { |
107 | let r: i32 = libc::pthread_mutex_unlock(self.0.get()); |
108 | debug_assert_eq!(r, 0); |
109 | } |
110 | } |
111 | |
112 | unsafe impl Sync for Mutex {} |
113 | |
114 | struct DropGuard<F: FnMut()>(F); |
115 | |
116 | impl<F: FnMut()> Drop for DropGuard<F> { |
117 | fn drop(&mut self) { |
118 | self.0() |
119 | } |
120 | } |
121 | |