Skip to content

Commit 32b221f

Browse files
committed
Add fill_exact helper function
1 parent 1705b40 commit 32b221f

File tree

4 files changed

+41
-43
lines changed

4 files changed

+41
-43
lines changed

src/freebsd.rs

+6-11
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,12 @@
77
// except according to those terms.
88

99
//! Implementation for FreeBSD
10-
extern crate std;
11-
10+
use crate::util_libc::fill_exact;
1211
use crate::Error;
1312
use core::num::NonZeroU32;
1413
use core::ptr;
15-
use std::io;
1614

17-
fn kern_arnd(buf: &mut [u8]) -> Result<usize, Error> {
15+
fn kern_arnd(buf: &mut [u8]) -> libc::ssize_t {
1816
static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND];
1917
let mut len = buf.len();
2018
let ret = unsafe {
@@ -29,17 +27,14 @@ fn kern_arnd(buf: &mut [u8]) -> Result<usize, Error> {
2927
};
3028
if ret == -1 {
3129
error!("freebsd: kern.arandom syscall failed");
32-
return Err(io::Error::last_os_error().into());
30+
-1
31+
} else {
32+
len as libc::ssize_t
3333
}
34-
Ok(len)
3534
}
3635

3736
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
38-
let mut start = 0;
39-
while start < dest.len() {
40-
start += kern_arnd(&mut dest[start..])?;
41-
}
42-
Ok(())
37+
fill_exact(dest, kern_arnd)
4338
}
4439

4540
#[inline(always)]

src/linux_android.rs

+10-23
Original file line numberDiff line numberDiff line change
@@ -10,45 +10,32 @@
1010
extern crate std;
1111

1212
use crate::util::LazyBool;
13+
use crate::util_libc::fill_exact;
1314
use crate::{use_file, Error};
1415
use core::num::NonZeroU32;
1516
use std::io;
1617

17-
fn syscall_getrandom(dest: &mut [u8], block: bool) -> Result<usize, io::Error> {
18-
let flags = if block { 0 } else { libc::GRND_NONBLOCK };
19-
let ret = unsafe { libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), flags) };
20-
if ret < 0 {
21-
let err = io::Error::last_os_error();
22-
if err.raw_os_error() == Some(libc::EINTR) {
23-
return Ok(0); // Call was interrupted, try again
24-
}
25-
error!("Linux getrandom syscall failed with return value {}", ret);
26-
return Err(err);
27-
}
28-
Ok(ret as usize)
29-
}
30-
3118
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
3219
static HAS_GETRANDOM: LazyBool = LazyBool::new();
3320
if HAS_GETRANDOM.unsync_init(is_getrandom_available) {
34-
let mut start = 0;
35-
while start < dest.len() {
36-
start += syscall_getrandom(&mut dest[start..], true)?;
37-
}
38-
Ok(())
21+
fill_exact(dest, |buf| unsafe {
22+
libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), 0) as libc::ssize_t
23+
})
3924
} else {
4025
use_file::getrandom_inner(dest)
4126
}
4227
}
4328

4429
fn is_getrandom_available() -> bool {
45-
match syscall_getrandom(&mut [], false) {
46-
Err(err) => match err.raw_os_error() {
30+
let res = unsafe { libc::syscall(libc::SYS_getrandom, 0, 0, libc::GRND_NONBLOCK) };
31+
if res < 0 {
32+
match io::Error::last_os_error().raw_os_error() {
4733
Some(libc::ENOSYS) => false, // No kernel support
4834
Some(libc::EPERM) => false, // Blocked by seccomp
4935
_ => true,
50-
},
51-
Ok(_) => true,
36+
}
37+
} else {
38+
true
5239
}
5340
}
5441

src/solaris_illumos.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,10 @@
1717
//! To make sure we can compile on both Solaris and its derivatives, as well as
1818
//! function, we check for the existance of getrandom(2) in libc by calling
1919
//! libc::dlsym.
20-
extern crate std;
21-
22-
use crate::util_libc::Weak;
20+
use crate::util_libc::{fill_exact, Weak};
2321
use crate::{use_file, Error};
2422
use core::mem;
2523
use core::num::NonZeroU32;
26-
use std::io;
2724

2825
#[cfg(target_os = "illumos")]
2926
type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t;
@@ -37,11 +34,9 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
3734
// 256 bytes is the lowest common denominator across all the Solaris
3835
// derived platforms for atomically obtaining random data.
3936
for chunk in dest.chunks_mut(256) {
40-
let ret = unsafe { func(chunk.as_mut_ptr(), chunk.len(), 0) };
41-
if ret != chunk.len() as _ {
42-
error!("getrandom syscall failed with ret={}", ret);
43-
return Err(io::Error::last_os_error().into());
44-
}
37+
fill_exact(chunk, |buf| unsafe {
38+
func(buf.as_mut_ptr(), buf.len(), 0) as libc::ssize_t
39+
})?
4540
}
4641
Ok(())
4742
} else {

src/util_libc.rs

+21
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,30 @@
55
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
8+
extern crate std;
89

910
use crate::util::LazyUsize;
11+
use crate::Error;
1012
use core::ptr::NonNull;
13+
use std::io;
14+
15+
pub fn fill_exact(mut buf: &mut [u8], f: impl Fn(&mut [u8]) -> libc::ssize_t) -> Result<(), Error> {
16+
while !buf.is_empty() {
17+
let res = f(buf);
18+
if res < 0 {
19+
let err = io::Error::last_os_error();
20+
// We should try again if the call was interrupted.
21+
if err.raw_os_error() != Some(libc::EINTR) {
22+
return Err(err.into());
23+
}
24+
} else {
25+
// We don't check for EOF (ret = 0) as the data we are reading
26+
// should be an infinite stream of random bytes.
27+
buf = &mut buf[(res as usize)..];
28+
}
29+
}
30+
Ok(())
31+
}
1132

1233
// A "weak" binding to a C function that may or may not be present at runtime.
1334
// Used for supporting newer OS features while still building on older systems.

0 commit comments

Comments
 (0)