Skip to content

Commit d0302a5

Browse files
committed
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.
1 parent 0a18857 commit d0302a5

File tree

1 file changed

+50
-16
lines changed

1 file changed

+50
-16
lines changed

src/linux_android.rs

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,6 @@ thread_local!(
2727
static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
2828
);
2929

30-
fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {
31-
let ret = unsafe {
32-
libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), 0)
33-
};
34-
if ret < 0 || (ret as usize) != dest.len() {
35-
error!("Linux getrandom syscall failed with return value {}", ret);
36-
return Err(io::Error::last_os_error());
37-
}
38-
Ok(())
39-
}
40-
4130
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
4231
RNG_SOURCE.with(|f| {
4332
use_init(f,
@@ -56,7 +45,11 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
5645
Ok(s)
5746
}, |f| {
5847
match f {
59-
RngSource::GetRandom => syscall_getrandom(dest),
48+
RngSource::GetRandom => {
49+
sys_fill_exact(dest, |buf| unsafe {
50+
getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0)
51+
})
52+
},
6053
RngSource::Device(f) => f.read_exact(dest),
6154
}.map_err(From::from)
6255
})
@@ -70,10 +63,17 @@ fn is_getrandom_available() -> bool {
7063
static AVAILABLE: AtomicBool = AtomicBool::new(false);
7164

7265
CHECKER.call_once(|| {
73-
let mut buf: [u8; 0] = [];
74-
let available = match syscall_getrandom(&mut buf) {
75-
Ok(()) => true,
76-
Err(err) => err.raw_os_error() != Some(libc::ENOSYS),
66+
let available = {
67+
let res = unsafe { getrandom(core::ptr::null_mut(), 0, libc::GRND_NONBLOCK) };
68+
if res < 0 {
69+
match io::Error::last_os_error().raw_os_error() {
70+
Some(libc::ENOSYS) => false, // No kernel support
71+
Some(libc::EPERM) => false, // Blocked by seccomp
72+
_ => true,
73+
}
74+
} else {
75+
true
76+
}
7777
};
7878
AVAILABLE.store(available, Ordering::Relaxed);
7979
});
@@ -83,3 +83,37 @@ fn is_getrandom_available() -> bool {
8383

8484
#[inline(always)]
8585
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }
86+
87+
// Fill a buffer by repeatedly invoking a system call. The `sys_fill` function:
88+
// - should return -1 and set errno on failure
89+
// - should return the number of bytes written on success
90+
//
91+
// From src/util_libc.rs 65660e00
92+
fn sys_fill_exact(
93+
mut buf: &mut [u8],
94+
sys_fill: impl Fn(&mut [u8]) -> libc::ssize_t,
95+
) -> Result<(), io::Error> {
96+
while !buf.is_empty() {
97+
let res = sys_fill(buf);
98+
if res < 0 {
99+
let err = io::Error::last_os_error();
100+
// We should try again if the call was interrupted.
101+
if err.raw_os_error() != Some(libc::EINTR) {
102+
return Err(err.into());
103+
}
104+
} else {
105+
// We don't check for EOF (ret = 0) as the data we are reading
106+
// should be an infinite stream of random bytes.
107+
buf = &mut buf[(res as usize)..];
108+
}
109+
}
110+
Ok(())
111+
}
112+
113+
unsafe fn getrandom(
114+
buf: *mut libc::c_void,
115+
buflen: libc::size_t,
116+
flags: libc::c_uint,
117+
) -> libc::ssize_t {
118+
libc::syscall(libc::SYS_getrandom, buf, buflen, flags) as libc::ssize_t
119+
}

0 commit comments

Comments
 (0)