From 7a15f026f2666a16255904879028acdd5513c766 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 5 Nov 2020 12:38:09 -0800 Subject: [PATCH 1/3] 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. --- library/std/src/sys/unix/rand.rs | 15 ++++++++++++--- library/std/src/sys/unix/weak.rs | 21 +++++++++++++++++++-- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index eed6fbf13b7d2..b563011913cff 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -25,10 +25,19 @@ mod imp { use crate::io::Read; #[cfg(any(target_os = "linux", target_os = "android"))] - fn getrandom(buf: &mut [u8]) -> libc::c_long { - unsafe { - libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK) + fn getrandom(buf: &mut [u8]) -> libc::ssize_t { + // A weak symbol allows interposition, e.g. for perf measurements that want to + // disable randomness for consistency. Otherwise, we'll try a raw syscall. + // (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28) + weak_syscall! { + fn getrandom( + buffer: *mut libc::c_void, + length: libc::size_t, + flags: libc::c_uint + ) -> libc::ssize_t } + + unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) } } #[cfg(not(any(target_os = "linux", target_os = "android")))] diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs index f4b33a00f7c85..3aa43858b9257 100644 --- a/library/std/src/sys/unix/weak.rs +++ b/library/std/src/sys/unix/weak.rs @@ -66,7 +66,7 @@ unsafe fn fetch(name: &str) -> usize { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize } -#[cfg(not(target_os = "linux"))] +#[cfg(not(any(target_os = "linux", target_os = "android")))] macro_rules! syscall { (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( unsafe fn $name($($arg_name: $t),*) -> $ret { @@ -84,7 +84,7 @@ macro_rules! syscall { ) } -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "android"))] macro_rules! syscall { (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( unsafe fn $name($($arg_name:$t),*) -> $ret { @@ -99,3 +99,20 @@ macro_rules! syscall { } ) } + +/// Use a weak symbol from libc when possible, allowing `LD_PRELOAD` interposition, +/// but if it's not found just use a raw syscall. +#[cfg(any(target_os = "linux", target_os = "android"))] +macro_rules! weak_syscall { + (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + unsafe fn $name($($arg_name:$t),*) -> $ret { + weak! { fn $name($($t),*) -> $ret } + if let Some(fun) = $name.get() { + fun($($arg_name),*) + } else { + syscall! { fn $name($($arg_name:$t),*) -> $ret } + $name($($arg_name),*) + } + } + ) +} From a035626eb53e88956680398f5fda821ca0e6bd97 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 5 Nov 2020 14:08:42 -0800 Subject: [PATCH 2/3] Try weak symbols for all linux syscall! wrappers --- library/std/src/sys/unix/rand.rs | 2 +- library/std/src/sys/unix/weak.rs | 23 +++++++---------------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index b563011913cff..38ddb41700c4b 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -29,7 +29,7 @@ mod imp { // A weak symbol allows interposition, e.g. for perf measurements that want to // disable randomness for consistency. Otherwise, we'll try a raw syscall. // (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28) - weak_syscall! { + syscall! { fn getrandom( buffer: *mut libc::c_void, length: libc::size_t, diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs index 3aa43858b9257..6251c3147300a 100644 --- a/library/std/src/sys/unix/weak.rs +++ b/library/std/src/sys/unix/weak.rs @@ -92,26 +92,17 @@ macro_rules! syscall { // (not paths). use libc::*; - syscall( - concat_idents!(SYS_, $name), - $($arg_name as c_long),* - ) as $ret - } - ) -} - -/// Use a weak symbol from libc when possible, allowing `LD_PRELOAD` interposition, -/// but if it's not found just use a raw syscall. -#[cfg(any(target_os = "linux", target_os = "android"))] -macro_rules! weak_syscall { - (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( - unsafe fn $name($($arg_name:$t),*) -> $ret { weak! { fn $name($($t),*) -> $ret } + + // Use a weak symbol from libc when possible, allowing `LD_PRELOAD` + // interposition, but if it's not found just use a raw syscall. if let Some(fun) = $name.get() { fun($($arg_name),*) } else { - syscall! { fn $name($($arg_name:$t),*) -> $ret } - $name($($arg_name),*) + syscall( + concat_idents!(SYS_, $name), + $($arg_name as c_long),* + ) as $ret } } ) From cd22381daa7f23bf20a739ac35c95ff77921d9a0 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 5 Nov 2020 14:09:28 -0800 Subject: [PATCH 3/3] Use syscall! for copy_file_range too --- library/std/src/sys/unix/kernel_copy.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index ac2fcfcb53f72..1dc16ef099367 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -445,15 +445,15 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> // We store the availability in a global to avoid unnecessary syscalls static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true); - unsafe fn copy_file_range( - fd_in: libc::c_int, - off_in: *mut libc::loff_t, - fd_out: libc::c_int, - off_out: *mut libc::loff_t, - len: libc::size_t, - flags: libc::c_uint, - ) -> libc::c_long { - libc::syscall(libc::SYS_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags) + syscall! { + fn copy_file_range( + fd_in: libc::c_int, + off_in: *mut libc::loff_t, + fd_out: libc::c_int, + off_out: *mut libc::loff_t, + len: libc::size_t, + flags: libc::c_uint + ) -> libc::ssize_t } let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed);