Fix long buffer issues (#33)

This commit is contained in:
Joseph Richey 2019-06-14 11:13:44 -07:00 committed by Artyom Pavlov
parent bcad3fb877
commit ac7a5426b9
2 changed files with 25 additions and 14 deletions

View File

@ -28,16 +28,20 @@ thread_local!(
static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);
fn syscall_getrandom(dest: &mut [u8], block: bool) -> Result<(), io::Error> {
fn syscall_getrandom(dest: &mut [u8], block: bool) -> Result<usize, io::Error> {
let flags = if block { 0 } else { libc::GRND_NONBLOCK };
let ret = unsafe {
libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), flags)
};
if ret < 0 || (ret as usize) != dest.len() {
if ret < 0 {
let err = io::Error::last_os_error();
if err.raw_os_error() == Some(libc::EINTR) {
return Ok(0); // Call was interrupted, try again
}
error!("Linux getrandom syscall failed with return value {}", ret);
return Err(io::Error::last_os_error());
return Err(err);
}
Ok(())
Ok(ret as usize)
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
@ -58,9 +62,15 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
Ok(s)
}, |f| {
match f {
RngSource::GetRandom => syscall_getrandom(dest, true),
RngSource::Device(f) => f.read_exact(dest),
}.map_err(From::from)
RngSource::GetRandom => {
let mut start = 0;
while start < dest.len() {
start += syscall_getrandom(&mut dest[start..], true)?;
}
Ok(())
}
RngSource::Device(f) => f.read_exact(dest).map_err(From::from),
}
})
})
}
@ -74,7 +84,7 @@ fn is_getrandom_available() -> bool {
CHECKER.call_once(|| {
let mut buf: [u8; 0] = [];
let available = match syscall_getrandom(&mut buf, false) {
Ok(()) => true,
Ok(_) => true,
Err(err) => err.raw_os_error() != Some(libc::ENOSYS),
};
AVAILABLE.store(available, Ordering::Relaxed);

View File

@ -17,12 +17,13 @@ use core::num::NonZeroU32;
use crate::Error;
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
let ret = unsafe {
RtlGenRandom(dest.as_mut_ptr() as PVOID, dest.len() as ULONG)
};
if ret == 0 {
error!("RtlGenRandom call failed");
return Err(io::Error::last_os_error().into());
// Prevent overflow of ULONG
for chunk in dest.chunks_mut(ULONG::max_value() as usize) {
let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr() as PVOID, chunk.len() as ULONG) };
if ret == 0 {
error!("RtlGenRandom call failed");
return Err(io::Error::last_os_error().into());
}
}
Ok(())
}