Skip to content

Commit 3c8df25

Browse files
committed
Linux/Android: Read a byte from /dev/random instead of polling it.
See the added comment for details.
1 parent 40e873d commit 3c8df25

File tree

1 file changed

+24
-20
lines changed

1 file changed

+24
-20
lines changed

src/use_file.rs

+24-20
Original file line numberDiff line numberDiff line change
@@ -68,30 +68,34 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
6868
// Succeeds once /dev/urandom is safe to read from
6969
#[cfg(any(target_os = "android", target_os = "linux"))]
7070
fn wait_until_rng_ready() -> Result<(), Error> {
71-
// Poll /dev/random to make sure it is ok to read from /dev/urandom.
71+
// Read a byte from /dev/random to make sure it is ok to read from
72+
// /dev/urandom. reading a byte instead of polling is more compatible with
73+
// sandboxes that disallow `poll()` but which allow reading /dev/random,
74+
// e.g. sandboxes that assume that `poll()` is for network I/O. This way,
75+
// fewer applications will have to insert pre-sandbox-initialization logic.
76+
// Often (blocking) file I/O is not allowed in such early phases of an
77+
// application for performance and/or security reasons.
78+
//
79+
// It is hard to write a sandbox policy to support `libc::poll()` because
80+
// it may be invoked as `SYS_POLL`, `SYS_PPOLL`, or even `SYS_SELECT`,
81+
// depending on the libc implementation (e.g. glibc vs musl), libc version,
82+
// potentially the kernel version at runtime, and/or the target
83+
// architecture.
84+
//
85+
// BoringSSL and libstd don't try to protect against insecure output from
86+
// `/dev/urandom'; they don't open `/dev/random` at all.
87+
//
88+
// OpenSSL uses `libc::select()` unless the `dev/random` file descriptor
89+
// is too large; if it is too large then it does what we do here.
90+
7291
let fd = open_readonly(b"/dev/random\0")?;
73-
let mut pfd = libc::pollfd {
74-
fd,
75-
events: libc::POLLIN,
76-
revents: 0,
77-
};
7892
let _guard = DropGuard(|| unsafe {
7993
libc::close(fd);
8094
});
81-
82-
loop {
83-
// A negative timeout means an infinite timeout.
84-
let res = unsafe { libc::poll(&mut pfd, 1, -1) };
85-
if res >= 0 {
86-
debug_assert_eq!(res, 1); // We only used one fd, and cannot timeout.
87-
return Ok(());
88-
}
89-
let err = crate::util_libc::last_os_error();
90-
match err.raw_os_error() {
91-
Some(libc::EINTR) | Some(libc::EAGAIN) => continue,
92-
_ => return Err(err),
93-
}
94-
}
95+
let mut dummy: [MaybeUninit<u8>; 1] = [MaybeUninit::uninit()];
96+
sys_fill_exact(&mut dummy, |buf| unsafe {
97+
libc::read(fd, buf.as_mut_ptr().cast::<c_void>(), buf.len())
98+
})
9599
}
96100

97101
struct Mutex(UnsafeCell<libc::pthread_mutex_t>);

0 commit comments

Comments
 (0)