Skip to content

Commit c4538e2

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. This requires bumping the MSRV to 1.59.
1 parent 308ee2b commit c4538e2

8 files changed

+92
-21
lines changed

.clippy.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
msrv = "1.57"
1+
msrv = "1.59"

.github/workflows/tests.yml

+5-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
strategy:
4545
matrix:
4646
os: [ubuntu-22.04, windows-2022]
47-
toolchain: [nightly, beta, stable, 1.57]
47+
toolchain: [nightly, beta, stable, 1.59]
4848
# Only Test macOS on stable to reduce macOS CI jobs
4949
include:
5050
# x86_64-apple-darwin.
@@ -61,6 +61,8 @@ jobs:
6161
- uses: Swatinem/rust-cache@v2
6262
- run: cargo test
6363
- run: cargo test --features=std
64+
# This is assumed to be the same code path as x86_64-*-linux-none, since
65+
# we don't/can't run tests for that target yet.
6466
- run: cargo test --features=linux_disable_fallback
6567
- run: cargo test --features=custom # custom should do nothing here
6668
- if: ${{ matrix.toolchain == 'nightly' }}
@@ -361,6 +363,8 @@ jobs:
361363
features: ["rdrand"]
362364
- target: i686-unknown-hurd-gnu
363365
features: ["std"]
366+
- target: x86_64-unknown-linux-none
367+
features: ["rdrand"]
364368
steps:
365369
- uses: actions/checkout@v3
366370
- uses: dtolnay/rust-toolchain@nightly # Required to build libcore

Cargo.toml

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "getrandom"
33
version = "0.2.15" # Also update html_root_url in lib.rs when bumping this
44
edition = "2021"
5-
rust-version = "1.57" # Sync .clippy.toml, tests.yml, and README.md.
5+
rust-version = "1.59" # Sync .clippy.toml, tests.yml, and README.md.
66
authors = ["The Rand Project Developers"]
77
license = "MIT OR Apache-2.0"
88
description = "A small cross-platform library for retrieving random data from system source"
@@ -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 on `x86_64-*-linux-*`, but we can't express this. In that case, we
23+
# require libc to be built, and we force it to be linked, but we don't actually
24+
# use anything 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]

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ crate features, WASM support and Custom RNGs see the
5252

5353
## Minimum Supported Rust Version
5454

55-
This crate requires Rust 1.57.0 or later.
55+
This crate requires Rust 1.59.0 or later.
5656

5757
## Platform Support
5858

src/lib.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,10 @@ cfg_if! {
259259
mod util_libc;
260260
#[path = "getrandom.rs"] mod imp;
261261
} else if #[cfg(all(
262-
not(feature = "linux_disable_fallback"),
262+
// Always treat feature="linux_disable_fallback" identically to
263+
// target_env="" to ensure the code paths are the same. This is
264+
// important because we can't run tests for target_env="" (yet).
265+
not(any(feature = "linux_disable_fallback", target_env="")),
263266
any(
264267
// Rust supports Android API level 19 (KitKat) [0] and the next upgrade targets
265268
// level 21 (Lollipop) [1], while `getrandom(2)` was added only in
@@ -304,8 +307,8 @@ cfg_if! {
304307
mod linux_android;
305308
#[path = "linux_android_with_fallback.rs"] mod imp;
306309
} else if #[cfg(any(target_os = "android", target_os = "linux"))] {
307-
mod util_libc;
308-
#[path = "linux_android.rs"] mod imp;
310+
mod linux_android;
311+
use linux_android as imp;
309312
} else if #[cfg(target_os = "solaris")] {
310313
mod util_libc;
311314
#[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..).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)