Skip to content

Commit a9719e4

Browse files
committed
linux_android: Use direct syscall instead of libc to support *-none.
Remove the last libc dependency from `linux_android`, as a step towards supporting x86_64-unknown-linux-none.
1 parent 0122c66 commit a9719e4

File tree

6 files changed

+83
-16
lines changed

6 files changed

+83
-16
lines changed

.github/workflows/tests.yml

+2
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,8 @@ jobs:
361361
features: ["rdrand"]
362362
- target: i686-unknown-hurd-gnu
363363
features: ["std"]
364+
- target: x86_64-unknown-linux-none
365+
features: ["rdrand"]
364366
steps:
365367
- uses: actions/checkout@v3
366368
- uses: dtolnay/rust-toolchain@nightly # Required to build libcore

Cargo.toml

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ cfg-if = "1"
1818
compiler_builtins = { version = "0.1", optional = true }
1919
core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" }
2020

21-
[target.'cfg(unix)'.dependencies]
21+
# XXX: Additionally, we don't use libc when feature `linux_disable_fallback` is
22+
# enabled, but we can't express this. In that case, we require libc to be
23+
# available, and we force it to be linked, but we don't actually use anything
24+
# from it.
25+
[target.'cfg(all(unix, not(all(target_arch = "x86_64", target_os = "linux", target_env = ""))))'.dependencies]
2226
libc = { version = "0.2.154", default-features = false }
2327

2428
[target.'cfg(target_os = "wasi")'.dependencies]

src/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ cfg_if! {
295295
// are used in practice to target pre-3.17 kernels.
296296
target_env = "musl",
297297
),
298+
not(target_env = "")
298299
)
299300
),
300301
))] {
@@ -304,8 +305,8 @@ cfg_if! {
304305
mod linux_android;
305306
#[path = "linux_android_with_fallback.rs"] mod imp;
306307
} else if #[cfg(any(target_os = "android", target_os = "linux"))] {
307-
mod util_libc;
308-
#[path = "linux_android.rs"] mod imp;
308+
mod linux_android;
309+
use linux_android as imp;
309310
} else if #[cfg(target_os = "solaris")] {
310311
mod util_libc;
311312
#[path = "solaris.rs"] mod imp;

src/linux_android.rs

+62-12
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,68 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
66
sys_fill_exact(dest, getrandom_syscall)
77
}
88

9+
// The value of `EINTR` is not architecture-specific. It is checked against
10+
// `libc::EINTR` by linux_android_with_fallback.rs.
11+
pub const EINTR: i32 = 4;
12+
913
// Also used by linux_android_with_fallback to check if the syscall is available.
10-
pub fn getrandom_syscall(buf: &mut [MaybeUninit<u8>]) -> Result<usize, Error> {
11-
use crate::util_libc::last_os_error;
14+
cfg_if! {
15+
// Assume Android always has libc available and always go through libc on
16+
// Android to support any future possible restrictions on direct syscall
17+
// access by the Android sandbox.
18+
//
19+
// TODO: Expand inilne assembly to other architectures to avoid depending
20+
// on libc on Linux.
21+
if #[cfg(all(target_os = "linux", target_arch = "x86_64"))] {
22+
type Word = u64;
23+
type IWord = i64;
24+
25+
#[allow(non_upper_case_globals)]
26+
pub const SYS_getrandom: IWord = if cfg!(target_arch = "x86_64") { 318 } else { unimplemented!() };
27+
28+
pub fn getrandom_syscall(buf: &mut [MaybeUninit<u8>]) -> Result<usize, Error> {
29+
const _:() = assert!(core::mem::size_of::<Word>() == core::mem::size_of::<usize>());
30+
31+
let mut ret: IWord;
32+
let flags = 0;
33+
unsafe {
34+
core::arch::asm!(
35+
"syscall",
36+
in("rax") SYS_getrandom,
37+
in("rdi") buf.as_mut_ptr(),
38+
in("rsi") buf.len(),
39+
in("rdx") flags,
40+
lateout("rcx") _,
41+
lateout("r11") _,
42+
lateout("rax") ret,
43+
options(nostack),
44+
);
45+
}
46+
match Word::try_from(ret) {
47+
Ok(written) => {
48+
const _:() = assert!(core::mem::size_of::<Word>() <= core::mem::size_of::<usize>());
49+
Ok(written as usize)
50+
},
51+
Err(_) => {
52+
Err(u32::try_from(ret.unsigned_abs()).map_or(
53+
Error::UNEXPECTED, Error::from_os_error))
54+
}
55+
}
56+
}
57+
} else {
58+
use crate::util_libc::last_os_error;
1259

13-
let ret: libc::c_long = unsafe {
14-
libc::syscall(
15-
libc::SYS_getrandom,
16-
buf.as_mut_ptr().cast::<core::ffi::c_void>(),
17-
buf.len(),
18-
0,
19-
)
20-
};
21-
const _: () = assert!(core::mem::size_of::<libc::c_long>() == core::mem::size_of::<isize>());
22-
usize::try_from(ret as isize).map_err(|_| last_os_error())
60+
pub fn getrandom_syscall(buf: &mut [MaybeUninit<u8>]) -> Result<usize, Error> {
61+
let ret: libc::c_long = unsafe {
62+
libc::syscall(
63+
libc::SYS_getrandom,
64+
buf.as_mut_ptr().cast::<core::ffi::c_void>(),
65+
buf.len(),
66+
0,
67+
)
68+
};
69+
const _:() = assert!(core::mem::size_of::<libc::c_long>() == core::mem::size_of::<isize>());
70+
usize::try_from(ret as isize).map_err(|_| last_os_error())
71+
}
72+
}
2373
}

src/linux_android_with_fallback.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
use crate::{lazy::LazyBool, linux_android, use_file, Error};
33
use core::mem::MaybeUninit;
44

5+
const _: () = assert!(linux_android::EINTR == libc::EINTR);
6+
#[cfg(target_arch = "x86_64")]
7+
const _: () = assert!(linux_android::SYS_getrandom == libc::SYS_getrandom);
8+
59
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
610
// getrandom(2) was introduced in Linux 3.17
711
static HAS_GETRANDOM: LazyBool = LazyBool::new();

src/util_unix.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@ pub fn sys_fill_exact(
99
mut buf: &mut [MaybeUninit<u8>],
1010
sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> Result<usize, Error>,
1111
) -> Result<(), Error> {
12+
// Avoid depending on libc for Linux/Android.
13+
#[cfg(any(target_os = "android", target_os = "linux"))]
14+
use crate::linux_android::EINTR;
15+
#[cfg(not(any(target_os = "android", target_os = "linux")))]
16+
use libc::EINTR;
17+
1218
while !buf.is_empty() {
1319
match sys_fill(buf) {
1420
Ok(res) if res > 0 => buf = buf.get_mut(res as usize..).ok_or(Error::UNEXPECTED)?,
1521
Err(err) => {
1622
// We should try again if the call was interrupted.
17-
if err.raw_os_error() != Some(libc::EINTR) {
23+
if err.raw_os_error() != Some(EINTR) {
1824
return Err(err);
1925
}
2026
}

0 commit comments

Comments
 (0)