Skip to content

Commit 7a15f02

Browse files
committed
linux: try to use libc getrandom to allow interposition
We'll try to use a weak `getrandom` symbol first, because that allows things like `LD_PRELOAD` interposition. For example, perf measurements might want to disable randomness to get reproducible results. If the weak symbol is not found, we fall back to a raw `SYS_getrandom` call.
1 parent f5230fb commit 7a15f02

File tree

2 files changed

+31
-5
lines changed

2 files changed

+31
-5
lines changed

library/std/src/sys/unix/rand.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,19 @@ mod imp {
2525
use crate::io::Read;
2626

2727
#[cfg(any(target_os = "linux", target_os = "android"))]
28-
fn getrandom(buf: &mut [u8]) -> libc::c_long {
29-
unsafe {
30-
libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
28+
fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
29+
// A weak symbol allows interposition, e.g. for perf measurements that want to
30+
// disable randomness for consistency. Otherwise, we'll try a raw syscall.
31+
// (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28)
32+
weak_syscall! {
33+
fn getrandom(
34+
buffer: *mut libc::c_void,
35+
length: libc::size_t,
36+
flags: libc::c_uint
37+
) -> libc::ssize_t
3138
}
39+
40+
unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) }
3241
}
3342

3443
#[cfg(not(any(target_os = "linux", target_os = "android")))]

library/std/src/sys/unix/weak.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ unsafe fn fetch(name: &str) -> usize {
6666
libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
6767
}
6868

69-
#[cfg(not(target_os = "linux"))]
69+
#[cfg(not(any(target_os = "linux", target_os = "android")))]
7070
macro_rules! syscall {
7171
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
7272
unsafe fn $name($($arg_name: $t),*) -> $ret {
@@ -84,7 +84,7 @@ macro_rules! syscall {
8484
)
8585
}
8686

87-
#[cfg(target_os = "linux")]
87+
#[cfg(any(target_os = "linux", target_os = "android"))]
8888
macro_rules! syscall {
8989
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
9090
unsafe fn $name($($arg_name:$t),*) -> $ret {
@@ -99,3 +99,20 @@ macro_rules! syscall {
9999
}
100100
)
101101
}
102+
103+
/// Use a weak symbol from libc when possible, allowing `LD_PRELOAD` interposition,
104+
/// but if it's not found just use a raw syscall.
105+
#[cfg(any(target_os = "linux", target_os = "android"))]
106+
macro_rules! weak_syscall {
107+
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
108+
unsafe fn $name($($arg_name:$t),*) -> $ret {
109+
weak! { fn $name($($t),*) -> $ret }
110+
if let Some(fun) = $name.get() {
111+
fun($($arg_name),*)
112+
} else {
113+
syscall! { fn $name($($arg_name:$t),*) -> $ret }
114+
$name($($arg_name),*)
115+
}
116+
}
117+
)
118+
}

0 commit comments

Comments
 (0)