Skip to content

Commit 528c6f3

Browse files
authored
Auto merge of #35884 - habnabit:freebsd-arc4rand, r=alexcrichton
Use arc4rand(9) on FreeBSD From rust-random/rand#112: >After reading through #30691 it seems that there's general agreement that using OS-provided facilities for seeding rust userland processes is fine as long as it doesn't use too much from libc. FreeBSD's `arc4random_buf(3)` is not only a whole lot of libc code, but also not even currently exposed in the libc crate. Fortunately, the mechanism `arc4random_buf(3)` et al. use for getting entropy from the kernel ([`arc4rand(9)`](https://www.freebsd.org/cgi/man.cgi?query=arc4random&apropos=0&sektion=9&manpath=FreeBSD+10.3-RELEASE&arch=default&format=html)) is exposed via `sysctl(3)` with constants that are already in the libc crate. >I haven't found too much documentation on `KERN_ARND`—it's missing or only briefly described in most of the places that cover sysctl mibs. But, from digging through the kernel source, it appears that the sysctl used in this PR is very close to just calling `arc4rand(9)` directly (with `reseed` set to 0 and no way to change it). I expected [rand](/rust-lang-nursery/rand) to reply quicker, so I tried submitting it there first. It's been a few weeks with no comment, so I don't know the state of it, but maybe someone will see it here and have an opinion. This is basically the same patch. It pains me to duplicate the code but I guess it hasn't been factored out into just one place yet.
2 parents 17a2be8 + 0a70944 commit 528c6f3

File tree

1 file changed

+77
-30
lines changed

1 file changed

+77
-30
lines changed

src/libstd/sys/unix/rand.rs

+77-30
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,31 @@
1010

1111
pub use self::imp::OsRng;
1212

13-
#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
13+
use mem;
14+
15+
fn next_u32(mut fill_buf: &mut FnMut(&mut [u8])) -> u32 {
16+
let mut buf: [u8; 4] = [0; 4];
17+
fill_buf(&mut buf);
18+
unsafe { mem::transmute::<[u8; 4], u32>(buf) }
19+
}
20+
21+
fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 {
22+
let mut buf: [u8; 8] = [0; 8];
23+
fill_buf(&mut buf);
24+
unsafe { mem::transmute::<[u8; 8], u64>(buf) }
25+
}
26+
27+
#[cfg(all(unix,
28+
not(target_os = "ios"),
29+
not(target_os = "openbsd"),
30+
not(target_os = "freebsd")))]
1431
mod imp {
1532
use self::OsRngInner::*;
33+
use super::{next_u32, next_u64};
1634

1735
use fs::File;
1836
use io;
1937
use libc;
20-
use mem;
2138
use rand::Rng;
2239
use rand::reader::ReaderRng;
2340
use sys::os::errno;
@@ -87,18 +104,6 @@ mod imp {
87104
}
88105
}
89106

90-
fn getrandom_next_u32() -> u32 {
91-
let mut buf: [u8; 4] = [0; 4];
92-
getrandom_fill_bytes(&mut buf);
93-
unsafe { mem::transmute::<[u8; 4], u32>(buf) }
94-
}
95-
96-
fn getrandom_next_u64() -> u64 {
97-
let mut buf: [u8; 8] = [0; 8];
98-
getrandom_fill_bytes(&mut buf);
99-
unsafe { mem::transmute::<[u8; 8], u64>(buf) }
100-
}
101-
102107
#[cfg(all(target_os = "linux",
103108
any(target_arch = "x86_64",
104109
target_arch = "x86",
@@ -163,13 +168,13 @@ mod imp {
163168
impl Rng for OsRng {
164169
fn next_u32(&mut self) -> u32 {
165170
match self.inner {
166-
OsGetrandomRng => getrandom_next_u32(),
171+
OsGetrandomRng => next_u32(&mut getrandom_fill_bytes),
167172
OsReaderRng(ref mut rng) => rng.next_u32(),
168173
}
169174
}
170175
fn next_u64(&mut self) -> u64 {
171176
match self.inner {
172-
OsGetrandomRng => getrandom_next_u64(),
177+
OsGetrandomRng => next_u64(&mut getrandom_fill_bytes),
173178
OsReaderRng(ref mut rng) => rng.next_u64(),
174179
}
175180
}
@@ -184,9 +189,10 @@ mod imp {
184189

185190
#[cfg(target_os = "openbsd")]
186191
mod imp {
192+
use super::{next_u32, next_u64};
193+
187194
use io;
188195
use libc;
189-
use mem;
190196
use sys::os::errno;
191197
use rand::Rng;
192198

@@ -205,14 +211,10 @@ mod imp {
205211

206212
impl Rng for OsRng {
207213
fn next_u32(&mut self) -> u32 {
208-
let mut v = [0; 4];
209-
self.fill_bytes(&mut v);
210-
unsafe { mem::transmute(v) }
214+
next_u32(&mut |v| self.fill_bytes(v))
211215
}
212216
fn next_u64(&mut self) -> u64 {
213-
let mut v = [0; 8];
214-
self.fill_bytes(&mut v);
215-
unsafe { mem::transmute(v) }
217+
next_u64(&mut |v| self.fill_bytes(v))
216218
}
217219
fn fill_bytes(&mut self, v: &mut [u8]) {
218220
// getentropy(2) permits a maximum buffer size of 256 bytes
@@ -230,8 +232,9 @@ mod imp {
230232

231233
#[cfg(target_os = "ios")]
232234
mod imp {
235+
use super::{next_u32, next_u64};
236+
233237
use io;
234-
use mem;
235238
use ptr;
236239
use rand::Rng;
237240
use libc::{c_int, size_t};
@@ -265,14 +268,10 @@ mod imp {
265268

266269
impl Rng for OsRng {
267270
fn next_u32(&mut self) -> u32 {
268-
let mut v = [0; 4];
269-
self.fill_bytes(&mut v);
270-
unsafe { mem::transmute(v) }
271+
next_u32(&mut |v| self.fill_bytes(v))
271272
}
272273
fn next_u64(&mut self) -> u64 {
273-
let mut v = [0; 8];
274-
self.fill_bytes(&mut v);
275-
unsafe { mem::transmute(v) }
274+
next_u64(&mut |v| self.fill_bytes(v))
276275
}
277276
fn fill_bytes(&mut self, v: &mut [u8]) {
278277
let ret = unsafe {
@@ -286,3 +285,51 @@ mod imp {
286285
}
287286
}
288287
}
288+
289+
#[cfg(target_os = "freebsd")]
290+
mod imp {
291+
use super::{next_u32, next_u64};
292+
293+
use io;
294+
use libc;
295+
use rand::Rng;
296+
use ptr;
297+
298+
pub struct OsRng {
299+
// dummy field to ensure that this struct cannot be constructed outside
300+
// of this module
301+
_dummy: (),
302+
}
303+
304+
impl OsRng {
305+
/// Create a new `OsRng`.
306+
pub fn new() -> io::Result<OsRng> {
307+
Ok(OsRng { _dummy: () })
308+
}
309+
}
310+
311+
impl Rng for OsRng {
312+
fn next_u32(&mut self) -> u32 {
313+
next_u32(&mut |v| self.fill_bytes(v))
314+
}
315+
fn next_u64(&mut self) -> u64 {
316+
next_u64(&mut |v| self.fill_bytes(v))
317+
}
318+
fn fill_bytes(&mut self, v: &mut [u8]) {
319+
let mib = [libc::CTL_KERN, libc::KERN_ARND];
320+
// kern.arandom permits a maximum buffer size of 256 bytes
321+
for s in v.chunks_mut(256) {
322+
let mut s_len = s.len();
323+
let ret = unsafe {
324+
libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
325+
s.as_mut_ptr() as *mut _, &mut s_len,
326+
ptr::null(), 0)
327+
};
328+
if ret == -1 || s_len != s.len() {
329+
panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
330+
ret, s.len(), s_len);
331+
}
332+
}
333+
}
334+
}
335+
}

0 commit comments

Comments
 (0)