Skip to content

Commit ca5c981

Browse files
committed
Replace linux_rustix opt-in backend with linux_raw
1 parent 9b902af commit ca5c981

File tree

9 files changed

+168
-48
lines changed

9 files changed

+168
-48
lines changed

.github/workflows/build.yml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ jobs:
122122
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom"
123123
run: cargo build --target=${{ matrix.target }} --features=std
124124
- env:
125-
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix"
125+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw"
126126
run: cargo build --target=${{ matrix.target }} --features=std
127127
- env:
128128
RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback
@@ -131,6 +131,30 @@ jobs:
131131
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand"
132132
run: cargo build --features=std
133133

134+
linux-raw:
135+
name: Build Raw Linux
136+
runs-on: ubuntu-24.04
137+
strategy:
138+
matrix:
139+
target: [
140+
arm-unknown-linux-gnueabihf,
141+
aarch64-unknown-linux-gnu,
142+
loongarch64-unknown-linux-gnu,
143+
riscv32gc-unknown-linux-gnu,
144+
riscv64gc-unknown-linux-gnu,
145+
i686-unknown-linux-gnu,
146+
x86_64-unknown-linux-gnu,
147+
x86_64-unknown-linux-gnux32,
148+
]
149+
steps:
150+
- uses: actions/checkout@v4
151+
- uses: dtolnay/rust-toolchain@nightly
152+
with:
153+
targets: ${{ matrix.target }}
154+
- env:
155+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw"
156+
run: cargo build -Zbuild-std=core --target=${{ matrix.target }}
157+
134158
web:
135159
name: ${{ matrix.target.description }} ${{ matrix.feature.description }} ${{ matrix.atomic.description }}
136160
runs-on: ubuntu-24.04

.github/workflows/nopanic.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ jobs:
4949
- name: Check (linux_android.rs)
5050
run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so ))
5151

52-
- name: Build (linux_rustix.rs)
52+
- name: Build (linux_raw.rs)
5353
env:
54-
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix"
54+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw"
5555
run: cargo build --release
56-
- name: Check (linux_rustix.rs)
56+
- name: Check (linux_raw.rs)
5757
run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so ))
5858

5959
- name: Build (rdrand.rs)

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ jobs:
5757
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom"
5858
run: cargo test --target=${{ matrix.target }} --features=std
5959
- env:
60-
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix"
60+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw"
6161
run: cargo test --target=${{ matrix.target }} --features=std
6262
- env:
6363
RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback

.github/workflows/workspace.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ jobs:
5757
env:
5858
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom"
5959
run: cargo clippy --target x86_64-unknown-linux-gnu
60-
- name: Linux (linux_rustix.rs)
60+
- name: Linux (linux_raw.rs)
6161
env:
62-
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix"
62+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw"
6363
run: cargo clippy --target x86_64-unknown-linux-gnu
6464
- name: Linux (linux_android_with_fallback.rs)
6565
run: cargo clippy --target x86_64-unknown-linux-gnu

Cargo.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@ core = { version = "1.0", optional = true, package = "rustc-std-workspace-core"
2222
[target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(target_env = "", getrandom_backend = "linux_rustix", getrandom_backend = "custom"))))'.dependencies]
2323
libc = { version = "0.2.154", default-features = false }
2424

25-
# linux_rustix
26-
[target.'cfg(all(any(target_os = "linux", target_os = "android"), any(target_env = "", getrandom_backend = "linux_rustix")))'.dependencies]
27-
rustix = { version = "0.38.38", default-features = false, features = ["rand"] }
28-
2925
# apple-other
3026
[target.'cfg(any(target_os = "ios", target_os = "visionos", target_os = "watchos", target_os = "tvos"))'.dependencies]
3127
libc = { version = "0.2.154", default-features = false }
@@ -80,7 +76,7 @@ rustc-dep-of-std = ["dep:compiler_builtins", "dep:core"]
8076
[lints.rust.unexpected_cfgs]
8177
level = "warn"
8278
check-cfg = [
83-
'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "linux_rustix", "wasm_js", "esp_idf"))',
79+
'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "linux_raw", "wasm_js", "esp_idf"))',
8480
'cfg(getrandom_msan)',
8581
'cfg(getrandom_test_linux_fallback)',
8682
'cfg(getrandom_test_netbsd_fallback)',

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ of randomness based on their specific needs:
7979
| Backend name | Target | Target Triple | Implementation
8080
| ----------------- | -------------------- | ------------------------ | --------------
8181
| `linux_getrandom` | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call (without `/dev/urandom` fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow).
82-
| `linux_rustix` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses [`rustix`] instead of `libc`.
82+
| `linux_raw` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses raw `asm!`-based syscalls instead of `libc`.
8383
| `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction
8484
| `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register
8585
| `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low-quality entropy without proper hardware configuration!
@@ -106,6 +106,13 @@ WILL NOT have any effect on its downstream users.
106106

107107
[`.cargo/config.toml`]: https://doc.rust-lang.org/cargo/reference/config.html
108108

109+
### Raw Linux syscall support
110+
111+
Currently the `linux_raw` backend supports only targets with stabilized `asm!` macro, i.e. `arm`, `aarch64`, `loongarch64`, `riscv32`, `riscv64`, `x86`, and `x86_64`.
112+
113+
Note that on `x86` we use the famously slow `int 0x80` to perform syscall.
114+
We recommend to avoid `linux_raw` on this target arch.
115+
109116
### WebAssembly support
110117

111118
This crate fully supports the [WASI] and [Emscripten] targets. However,

src/backends.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ cfg_if! {
1313
} else if #[cfg(getrandom_backend = "linux_getrandom")] {
1414
mod linux_android;
1515
pub use linux_android::*;
16-
} else if #[cfg(getrandom_backend = "linux_rustix")] {
17-
mod linux_rustix;
18-
pub use linux_rustix::*;
16+
} else if #[cfg(getrandom_backend = "linux_raw")] {
17+
mod linux_raw;
18+
pub use linux_raw::*;
1919
} else if #[cfg(getrandom_backend = "rdrand")] {
2020
mod rdrand;
2121
pub use rdrand::*;

src/backends/linux_raw.rs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
//! Implementation for Linux / Android without `/dev/urandom` fallback
2+
use crate::{Error, MaybeUninit};
3+
// use rustix::rand::{getrandom_uninit, GetRandomFlags};
4+
5+
pub use crate::util::{inner_u32, inner_u64};
6+
7+
#[cfg(not(any(target_os = "android", target_os = "linux")))]
8+
compile_error!("`linux_raw` backend can be enabled only for Linux/Android targets!");
9+
10+
#[allow(non_upper_case_globals)]
11+
unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize {
12+
let r0;
13+
14+
// Based on `rustix` and `linux-raw-sys` code.
15+
cfg_if! {
16+
if #[cfg(target_arch = "arm")] {
17+
// In thumb-mode, r7 is the frame pointer and is not permitted to be used in
18+
// an inline asm operand, so we have to use a different register and copy it
19+
// into r7 inside the inline asm.
20+
// Theoretically, we could detect thumb mode in the build script, but several
21+
// register moves are cheap enough compared to the syscall cost, so we do not
22+
// bother with it.
23+
core::arch::asm!(
24+
"mov {tmp}, r7",
25+
"mov r7, #384", // __NR_getrandom = 384
26+
"svc 0",
27+
"mov r7, {tmp}",
28+
tmp = out(reg) _,
29+
inlateout("r0") buf => r0,
30+
in("r1") buflen,
31+
in("r2") flags,
32+
options(nostack, preserves_flags)
33+
);
34+
} else if #[cfg(target_arch = "aarch64")] {
35+
const __NR_getrandom: u32 = 278;
36+
core::arch::asm!(
37+
"svc 0",
38+
in("x8") __NR_getrandom,
39+
inlateout("x0") buf => r0,
40+
in("x1") buflen,
41+
in("x2") flags,
42+
options(nostack, preserves_flags)
43+
);
44+
} else if #[cfg(target_arch = "loongarch64")] {
45+
const __NR_getrandom: u32 = 278;
46+
core::arch::asm!(
47+
"syscall 0",
48+
in("$a7") __NR_getrandom,
49+
inlateout("$a0") buf => r0,
50+
in("$a1") buflen,
51+
in("$a2") flags,
52+
options(nostack, preserves_flags)
53+
);
54+
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
55+
const __NR_getrandom: u32 = 278;
56+
core::arch::asm!(
57+
"ecall",
58+
in("a7") __NR_getrandom,
59+
inlateout("a0") buf => r0,
60+
in("a1") buflen,
61+
in("a2") flags,
62+
options(nostack, preserves_flags)
63+
);
64+
} else if #[cfg(target_arch = "x86")] {
65+
const __NR_getrandom: isize = 355;
66+
// `int 0x80` is famously slow, but implementing vDSO is too complex
67+
// and `sysenter`/`syscall` have their own portability issues,
68+
// so we use the simple "legacy" way of doing syscalls.
69+
core::arch::asm!(
70+
"int $$0x80",
71+
inlateout("eax") __NR_getrandom => r0,
72+
in("ebx") buf,
73+
in("ecx") buflen,
74+
in("edx") flags,
75+
options(nostack, preserves_flags)
76+
);
77+
} else if #[cfg(target_arch = "x86_64")] {
78+
#[cfg(target_pointer_width = "64")]
79+
const __NR_getrandom: isize = 318;
80+
#[cfg(target_pointer_width = "32")]
81+
const __NR_getrandom: isize = 1073742142;
82+
83+
core::arch::asm!(
84+
"syscall",
85+
inlateout("rax") __NR_getrandom => r0,
86+
in("rdi") buf,
87+
in("rsi") buflen,
88+
in("rdx") flags,
89+
lateout("rcx") _,
90+
lateout("r11") _,
91+
options(nostack, preserves_flags)
92+
);
93+
} else {
94+
compile_error!("`linux_raw` backend does not support this target arch");
95+
}
96+
}
97+
98+
r0
99+
}
100+
101+
pub fn fill_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
102+
// Value of this error code is stable across all target arches.
103+
const EINTR: isize = -4;
104+
105+
loop {
106+
let ret = unsafe { getrandom_syscall(dest.as_mut_ptr().cast(), dest.len(), 0) };
107+
match usize::try_from(ret) {
108+
Ok(0) => return Err(Error::UNEXPECTED),
109+
Ok(len) => {
110+
dest = dest.get_mut(len..).ok_or(Error::UNEXPECTED)?;
111+
if dest.is_empty() {
112+
return Ok(());
113+
}
114+
}
115+
Err(_) if ret == EINTR => continue,
116+
Err(_) => {
117+
let code: u32 = ret
118+
.wrapping_neg()
119+
.try_into()
120+
.map_err(|_| Error::UNEXPECTED)?;
121+
return Err(Error::from_os_error(code));
122+
}
123+
}
124+
}
125+
}

src/backends/linux_rustix.rs

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)