]> git.proxmox.com Git - rustc.git/blame - library/std/src/sys/unix/rand.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / library / std / src / sys / unix / rand.rs
CommitLineData
532ac7d7
XL
1use crate::mem;
2use crate::slice;
9e0c209e 3
abe05a73
XL
4pub fn hashmap_random_keys() -> (u64, u64) {
5 let mut v = (0, 0);
6 unsafe {
60c5eb7d 7 let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, mem::size_of_val(&v));
abe05a73
XL
8 imp::fill_bytes(view);
9 }
e74abb32 10 v
9e0c209e
SL
11}
12
60c5eb7d
XL
13#[cfg(all(
14 unix,
ba9703b0 15 not(target_os = "macos"),
60c5eb7d
XL
16 not(target_os = "ios"),
17 not(target_os = "openbsd"),
18 not(target_os = "freebsd"),
19 not(target_os = "netbsd"),
20 not(target_os = "fuchsia"),
cdc7bbd5
XL
21 not(target_os = "redox"),
22 not(target_os = "vxworks")
60c5eb7d 23))]
1a4d82fc 24mod imp {
532ac7d7
XL
25 use crate::fs::File;
26 use crate::io::Read;
1a4d82fc 27
136023e0
XL
28 #[cfg(any(target_os = "linux", target_os = "android"))]
29 use crate::sys::weak::syscall;
30
abe05a73 31 #[cfg(any(target_os = "linux", target_os = "android"))]
fc512014
XL
32 fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
33 // A weak symbol allows interposition, e.g. for perf measurements that want to
34 // disable randomness for consistency. Otherwise, we'll try a raw syscall.
35 // (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28)
36 syscall! {
37 fn getrandom(
38 buffer: *mut libc::c_void,
39 length: libc::size_t,
40 flags: libc::c_uint
41 ) -> libc::ssize_t
1a4d82fc 42 }
fc512014
XL
43
44 unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) }
1a4d82fc
JJ
45 }
46
abe05a73 47 #[cfg(not(any(target_os = "linux", target_os = "android")))]
60c5eb7d
XL
48 fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool {
49 false
50 }
1a4d82fc 51
b7449926 52 #[cfg(any(target_os = "linux", target_os = "android"))]
abe05a73 53 fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
532ac7d7
XL
54 use crate::sync::atomic::{AtomicBool, Ordering};
55 use crate::sys::os::errno;
b7449926
XL
56
57 static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
58 if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
59 return false;
60 }
61
1a4d82fc 62 let mut read = 0;
9cc50fc6 63 while read < v.len() {
85aaf69f 64 let result = getrandom(&mut v[read..]);
1a4d82fc
JJ
65 if result == -1 {
66 let err = errno() as libc::c_int;
67 if err == libc::EINTR {
68 continue;
48663c56
XL
69 } else if err == libc::ENOSYS || err == libc::EPERM {
70 // Fall back to reading /dev/urandom if `getrandom` is not
71 // supported on the current kernel.
72 //
73 // Also fall back in case it is disabled by something like
74 // seccomp or inside of virtual machines.
b7449926
XL
75 GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
76 return false;
a7813a04 77 } else if err == libc::EAGAIN {
b7449926 78 return false;
1a4d82fc
JJ
79 } else {
80 panic!("unexpected getrandom error: {}", err);
81 }
82 } else {
85aaf69f 83 read += result as usize;
1a4d82fc
JJ
84 }
85 }
b7449926 86 true
1a4d82fc
JJ
87 }
88
abe05a73
XL
89 pub fn fill_bytes(v: &mut [u8]) {
90 // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
91 // meaning it would have blocked because the non-blocking pool (urandom)
b7449926 92 // has not initialized in the kernel yet due to a lack of entropy. The
abe05a73
XL
93 // fallback we do here is to avoid blocking applications which could
94 // depend on this call without ever knowing they do and don't have a
b7449926
XL
95 // work around. The PRNG of /dev/urandom will still be used but over a
96 // possibly predictable entropy pool.
97 if getrandom_fill_bytes(v) {
98 return;
1a4d82fc 99 }
1a4d82fc 100
b7449926
XL
101 // getrandom failed because it is permanently or temporarily (because
102 // of missing entropy) unavailable. Open /dev/urandom, read from it,
103 // and close it again.
104 let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
105 file.read_exact(v).expect("failed to read /dev/urandom")
ba9703b0
XL
106 }
107}
108
109#[cfg(target_os = "macos")]
110mod imp {
111 use crate::fs::File;
112 use crate::io::Read;
113 use crate::sys::os::errno;
136023e0 114 use crate::sys::weak::weak;
ba9703b0
XL
115 use libc::{c_int, c_void, size_t};
116
117 fn getentropy_fill_bytes(v: &mut [u8]) -> bool {
118 weak!(fn getentropy(*mut c_void, size_t) -> c_int);
119
120 getentropy
121 .get()
122 .map(|f| {
123 // getentropy(2) permits a maximum buffer size of 256 bytes
124 for s in v.chunks_mut(256) {
125 let ret = unsafe { f(s.as_mut_ptr() as *mut c_void, s.len()) };
126 if ret == -1 {
127 panic!("unexpected getentropy error: {}", errno());
128 }
129 }
130 true
131 })
132 .unwrap_or(false)
133 }
134
135 pub fn fill_bytes(v: &mut [u8]) {
136 if getentropy_fill_bytes(v) {
137 return;
138 }
139
140 // for older macos which doesn't support getentropy
141 let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
142 file.read_exact(v).expect("failed to read /dev/urandom")
1a4d82fc
JJ
143 }
144}
145
9cc50fc6 146#[cfg(target_os = "openbsd")]
1a4d82fc 147mod imp {
532ac7d7 148 use crate::sys::os::errno;
9cc50fc6 149
abe05a73
XL
150 pub fn fill_bytes(v: &mut [u8]) {
151 // getentropy(2) permits a maximum buffer size of 256 bytes
152 for s in v.chunks_mut(256) {
60c5eb7d 153 let ret = unsafe { libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) };
abe05a73
XL
154 if ret == -1 {
155 panic!("unexpected getentropy error: {}", errno());
9cc50fc6
SL
156 }
157 }
158 }
159}
1a4d82fc 160
48663c56
XL
161// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
162// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
163// from `/dev/random` and which runs on its own thread accessed via GCD.
164// This seems needlessly heavyweight for the purposes of generating two u64s
165// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
166// only used on iOS where direct access to `/dev/urandom` is blocked by the
167// sandbox.
9cc50fc6
SL
168#[cfg(target_os = "ios")]
169mod imp {
532ac7d7
XL
170 use crate::io;
171 use crate::ptr;
e9174d1e 172 use libc::{c_int, size_t};
1a4d82fc 173
e9174d1e 174 enum SecRandom {}
1a4d82fc 175
1a4d82fc 176 #[allow(non_upper_case_globals)]
e9174d1e 177 const kSecRandomDefault: *const SecRandom = ptr::null();
1a4d82fc 178
60c5eb7d
XL
179 extern "C" {
180 fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int;
1a4d82fc
JJ
181 }
182
abe05a73 183 pub fn fill_bytes(v: &mut [u8]) {
60c5eb7d 184 let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) };
abe05a73 185 if ret == -1 {
60c5eb7d 186 panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
1a4d82fc
JJ
187 }
188 }
189}
9e0c209e 190
60c5eb7d 191#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
9e0c209e 192mod imp {
532ac7d7 193 use crate::ptr;
9e0c209e 194
abe05a73
XL
195 pub fn fill_bytes(v: &mut [u8]) {
196 let mib = [libc::CTL_KERN, libc::KERN_ARND];
197 // kern.arandom permits a maximum buffer size of 256 bytes
198 for s in v.chunks_mut(256) {
199 let mut s_len = s.len();
200 let ret = unsafe {
60c5eb7d
XL
201 libc::sysctl(
202 mib.as_ptr(),
203 mib.len() as libc::c_uint,
204 s.as_mut_ptr() as *mut _,
205 &mut s_len,
206 ptr::null(),
207 0,
208 )
abe05a73
XL
209 };
210 if ret == -1 || s_len != s.len() {
60c5eb7d
XL
211 panic!(
212 "kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
213 ret,
214 s.len(),
215 s_len
216 );
9e0c209e
SL
217 }
218 }
219 }
220}
c30ab7b3
SL
221
222#[cfg(target_os = "fuchsia")]
223mod imp {
ea8adc8c 224 #[link(name = "zircon")]
60c5eb7d 225 extern "C" {
8faf50e0 226 fn zx_cprng_draw(buffer: *mut u8, len: usize);
c30ab7b3
SL
227 }
228
abe05a73 229 pub fn fill_bytes(v: &mut [u8]) {
8faf50e0 230 unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
c30ab7b3
SL
231 }
232}
416331ca
XL
233
234#[cfg(target_os = "redox")]
235mod imp {
236 use crate::fs::File;
237 use crate::io::Read;
238
239 pub fn fill_bytes(v: &mut [u8]) {
240 // Open rand:, read from it, and close it again.
241 let mut file = File::open("rand:").expect("failed to open rand:");
242 file.read_exact(v).expect("failed to read rand:")
243 }
244}
cdc7bbd5
XL
245
246#[cfg(target_os = "vxworks")]
247mod imp {
248 use crate::io;
249 use core::sync::atomic::{AtomicBool, Ordering::Relaxed};
250
251 pub fn fill_bytes(v: &mut [u8]) {
252 static RNG_INIT: AtomicBool = AtomicBool::new(false);
253 while !RNG_INIT.load(Relaxed) {
254 let ret = unsafe { libc::randSecure() };
255 if ret < 0 {
256 panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
257 } else if ret > 0 {
258 RNG_INIT.store(true, Relaxed);
259 break;
260 }
261 unsafe { libc::usleep(10) };
262 }
263 let ret = unsafe {
264 libc::randABytes(v.as_mut_ptr() as *mut libc::c_uchar, v.len() as libc::c_int)
265 };
266 if ret < 0 {
267 panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
268 }
269 }
270}