Skip to content

Commit df0b03f

Browse files
Aaron1011froydnj
authored andcommitted
Explicitly specify types to arguments of 'libc::syscall' (rust-random#74)
The 'libc::syscall' function uses varargs - as a result, its arguments are completely untyped. THe user must ensure that it is called with the proper types for the targeted syscall - otherwise, the calling convention might cause arguments to be put into the wrong registers. This commit explicitly casts the arguments to 'libc::syscall' to the proper type for the 'getrandom' syscall. This ensures that the correct types for the target platform will always be used, instead of relying on the types used happening to match those required by the target platform. This particular commit is a backport of 6716ad0, with the addition of `sys_fill_exact` from master (originally committed in 65660e0) to make the backport more obviously correct. # Conflicts: # src/linux_android.rs
1 parent e02e946 commit df0b03f

File tree

1 file changed

+44
-24
lines changed

1 file changed

+44
-24
lines changed

src/linux_android.rs

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,48 +14,68 @@ use core::num::NonZeroU32;
1414
use lazy_static::lazy_static;
1515
use std::io;
1616

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-
3117
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
3218
lazy_static! {
3319
static ref HAS_GETRANDOM: bool = is_getrandom_available();
3420
}
3521
match *HAS_GETRANDOM {
3622
true => {
37-
let mut start = 0;
38-
while start < dest.len() {
39-
start += syscall_getrandom(&mut dest[start..], true)?;
40-
}
41-
Ok(())
42-
}
23+
sys_fill_exact(dest, |buf| unsafe {
24+
getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0)
25+
})
26+
},
4327
false => use_file::getrandom_inner(dest),
4428
}
4529
}
4630

4731
fn is_getrandom_available() -> bool {
48-
match syscall_getrandom(&mut [], false) {
49-
Err(err) => match err.raw_os_error() {
32+
let res = unsafe { getrandom(core::ptr::null_mut(), 0, libc::GRND_NONBLOCK) };
33+
if res < 0 {
34+
match io::Error::last_os_error().raw_os_error() {
5035
Some(libc::ENOSYS) => false, // No kernel support
5136
Some(libc::EPERM) => false, // Blocked by seccomp
5237
_ => true,
53-
},
54-
Ok(_) => true,
38+
}
39+
} else {
40+
true
5541
}
5642
}
5743

5844
#[inline(always)]
5945
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
6046
None
6147
}
48+
49+
// Fill a buffer by repeatedly invoking a system call. The `sys_fill` function:
50+
// - should return -1 and set errno on failure
51+
// - should return the number of bytes written on success
52+
//
53+
// From src/util_libc.rs 65660e00
54+
fn sys_fill_exact(
55+
mut buf: &mut [u8],
56+
sys_fill: impl Fn(&mut [u8]) -> libc::ssize_t,
57+
) -> Result<(), Error> {
58+
while !buf.is_empty() {
59+
let res = sys_fill(buf);
60+
if res < 0 {
61+
let err = io::Error::last_os_error();
62+
// We should try again if the call was interrupted.
63+
if err.raw_os_error() != Some(libc::EINTR) {
64+
return Err(err.into());
65+
}
66+
} else {
67+
// We don't check for EOF (ret = 0) as the data we are reading
68+
// should be an infinite stream of random bytes.
69+
buf = &mut buf[(res as usize)..];
70+
}
71+
}
72+
Ok(())
73+
}
74+
75+
unsafe fn getrandom(
76+
buf: *mut libc::c_void,
77+
buflen: libc::size_t,
78+
flags: libc::c_uint,
79+
) -> libc::ssize_t {
80+
libc::syscall(libc::SYS_getrandom, buf, buflen, flags) as libc::ssize_t
81+
}

0 commit comments

Comments
 (0)