Skip to content

Commit

Permalink
Don't leak the file descriptor in rand
Browse files Browse the repository at this point in the history
  • Loading branch information
tbu- committed Aug 29, 2018
1 parent 09a615c commit d6d280b
Showing 1 changed file with 11 additions and 44 deletions.
55 changes: 11 additions & 44 deletions src/libstd/sys/unix/rand.rs
Expand Up @@ -29,23 +29,8 @@ pub fn hashmap_random_keys() -> (u64, u64) {
mod imp {
use fs::File;
use io::Read;
use libc;
use sync::atomic::{AtomicBool, AtomicI32, Ordering};
use sys::os::errno;

static GETRANDOM_URANDOM_FD: AtomicI32 = AtomicI32::new(-1);
#[cfg(any(target_os = "linux", target_os = "android"))]
static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);

#[cfg(any(target_os = "linux", target_os = "android"))]
fn is_getrandom_permanently_unavailable() -> bool {
GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed)
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn is_getrandom_permanently_unavailable() -> bool {
true
}
use libc;

#[cfg(any(target_os = "linux", target_os = "android"))]
fn getrandom(buf: &mut [u8]) -> libc::c_long {
Expand All @@ -59,7 +44,11 @@ mod imp {

#[cfg(any(target_os = "linux", target_os = "android"))]
fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
if is_getrandom_permanently_unavailable() {
use sync::atomic::{AtomicBool, Ordering};
use sys::os::errno;

static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
return false;
}

Expand Down Expand Up @@ -96,33 +85,11 @@ mod imp {
return;
}

// getrandom failed for some reason. If the getrandom call is
// permanently unavailable (OS without getrandom, or OS version without
// getrandom), we'll keep around the fd for /dev/urandom for future
// requests, to avoid re-opening the file on every call.
//
// Otherwise, open /dev/urandom, read from it, and close it again.
use super::super::ext::io::{FromRawFd, IntoRawFd};
let mut fd = GETRANDOM_URANDOM_FD.load(Ordering::Relaxed);
let mut close_fd = false;
if fd == -1 {
if !is_getrandom_permanently_unavailable() {
close_fd = true;
}
let file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
fd = file.into_raw_fd();
// If some other thread also opened /dev/urandom and set the global
// fd already, we close our fd at the end of the function.
if !close_fd && GETRANDOM_URANDOM_FD.compare_and_swap(-1, fd, Ordering::Relaxed) != -1 {
close_fd = true;
}
}
let mut file = unsafe { File::from_raw_fd(fd) };
let res = file.read_exact(v);
if !close_fd {
let _ = file.into_raw_fd();
}
res.expect("failed to read /dev/urandom");
// getrandom failed because it is permanently or temporarily (because
// of missing entropy) unavailable. Open /dev/urandom, read from it,
// and close it again.
let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
file.read_exact(v).expect("failed to read /dev/urandom")
}
}

Expand Down

0 comments on commit d6d280b

Please sign in to comment.