Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace linux_rustix opt-in backend with linux_raw #572

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ jobs:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom"
run: cargo build --target=${{ matrix.target }} --features=std
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix"
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw"
run: cargo build --target=${{ matrix.target }} --features=std
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback
Expand All @@ -131,6 +131,31 @@ jobs:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand"
run: cargo build --features=std

linux-raw:
name: Build Raw Linux
runs-on: ubuntu-24.04
strategy:
matrix:
target: [
arm-unknown-linux-gnueabihf,
aarch64-unknown-linux-gnu,
loongarch64-unknown-linux-gnu,
riscv32gc-unknown-linux-gnu,
riscv64gc-unknown-linux-gnu,
i686-unknown-linux-gnu,
x86_64-unknown-linux-gnu,
x86_64-unknown-linux-gnux32,
]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2024-10-24
components: rust-src
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw"
run: cargo build -Zbuild-std=core --target=${{ matrix.target }}

web:
name: ${{ matrix.target.description }} ${{ matrix.feature.description }} ${{ matrix.atomic.description }}
runs-on: ubuntu-24.04
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/nopanic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ jobs:
- name: Check (linux_android.rs)
run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so ))

- name: Build (linux_rustix.rs)
- name: Build (linux_raw.rs)
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix"
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw"
run: cargo build --release
- name: Check (linux_rustix.rs)
- name: Check (linux_raw.rs)
run: (exit $( grep -c panic target/release/libgetrandom_wrapper.so ))

- name: Build (rdrand.rs)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom"
run: cargo test --target=${{ matrix.target }} --features=std
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix"
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw"
run: cargo test --target=${{ matrix.target }} --features=std
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/workspace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ jobs:
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom"
run: cargo clippy --target x86_64-unknown-linux-gnu
- name: Linux (linux_rustix.rs)
- name: Linux (linux_raw.rs)
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix"
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw"
run: cargo clippy --target x86_64-unknown-linux-gnu
- name: Linux (linux_android_with_fallback.rs)
run: cargo clippy --target x86_64-unknown-linux-gnu
Expand Down
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `getrandom_backend` configuration flag for selection of opt-in backends [#504]
- `Error::new_custom` method [#507]
- `rndr` opt-in backend [#512]
- `linux_rustix` opt-in backend [#520]
- Automatic MemorySanitizer support [#521] [#571]
- `u32` and `u64` functions for generating random values of the respective type [#544]
- `linux_raw` opt-in backend [#572]

### Fixed
- NetBSD fallback code based on `KERN_ARND` [#555]
Expand All @@ -52,7 +52,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#504]: https://github.com/rust-random/getrandom/pull/504
[#507]: https://github.com/rust-random/getrandom/pull/507
[#512]: https://github.com/rust-random/getrandom/pull/512
[#520]: https://github.com/rust-random/getrandom/pull/520
[#521]: https://github.com/rust-random/getrandom/pull/521
[#522]: https://github.com/rust-random/getrandom/pull/522
[#532]: https://github.com/rust-random/getrandom/pull/532
Expand All @@ -62,6 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#555]: https://github.com/rust-random/getrandom/pull/555
[#557]: https://github.com/rust-random/getrandom/pull/557
[#571]: https://github.com/rust-random/getrandom/pull/571
[#572]: https://github.com/rust-random/getrandom/pull/572

## [0.2.15] - 2024-05-06
### Added
Expand Down
6 changes: 1 addition & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ core = { version = "1.0", optional = true, package = "rustc-std-workspace-core"
[target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(target_env = "", getrandom_backend = "linux_rustix", getrandom_backend = "custom"))))'.dependencies]
libc = { version = "0.2.154", default-features = false }

# linux_rustix
[target.'cfg(all(any(target_os = "linux", target_os = "android"), any(target_env = "", getrandom_backend = "linux_rustix")))'.dependencies]
rustix = { version = "0.38.38", default-features = false, features = ["rand"] }

# apple-other
[target.'cfg(any(target_os = "ios", target_os = "visionos", target_os = "watchos", target_os = "tvos"))'.dependencies]
libc = { version = "0.2.154", default-features = false }
Expand Down Expand Up @@ -80,7 +76,7 @@ rustc-dep-of-std = ["dep:compiler_builtins", "dep:core"]
[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = [
'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "linux_rustix", "wasm_js", "esp_idf"))',
'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "linux_raw", "wasm_js", "esp_idf"))',
'cfg(getrandom_msan)',
'cfg(getrandom_test_linux_fallback)',
'cfg(getrandom_test_netbsd_fallback)',
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ of randomness based on their specific needs:
| Backend name | Target | Target Triple | Implementation
| ----------------- | -------------------- | ------------------------ | --------------
| `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).
| `linux_rustix` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses [`rustix`] instead of `libc`.
| `linux_raw` | Linux, Android | `*‑linux‑*` | Same as `linux_getrandom`, but uses raw `asm!`-based syscalls instead of `libc`.
| `rdrand` | x86, x86-64 | `x86_64-*`, `i686-*` | [`RDRAND`] instruction
| `rndr` | AArch64 | `aarch64-*` | [`RNDR`] register
| `esp_idf` | ESP-IDF | `*‑espidf` | [`esp_fill_random`]. WARNING: can return low-quality entropy without proper hardware configuration!
Expand All @@ -106,6 +106,13 @@ WILL NOT have any effect on its downstream users.

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

### Raw Linux syscall support

Currently the `linux_raw` backend supports only targets with stabilized `asm!` macro, i.e. `arm`, `aarch64`, `loongarch64`, `riscv32`, `riscv64`, `x86`, and `x86_64`.

Note that on `x86` we use the famously slow `int 0x80` to perform syscall.
We recommend to avoid `linux_raw` on this target arch.

### WebAssembly support

This crate fully supports the [WASI] and [Emscripten] targets. However,
Expand Down
6 changes: 3 additions & 3 deletions src/backends.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ cfg_if! {
} else if #[cfg(getrandom_backend = "linux_getrandom")] {
mod linux_android;
pub use linux_android::*;
} else if #[cfg(getrandom_backend = "linux_rustix")] {
mod linux_rustix;
pub use linux_rustix::*;
} else if #[cfg(getrandom_backend = "linux_raw")] {
mod linux_raw;
pub use linux_raw::*;
} else if #[cfg(getrandom_backend = "rdrand")] {
mod rdrand;
pub use rdrand::*;
Expand Down
124 changes: 124 additions & 0 deletions src/backends/linux_raw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//! Implementation for Linux / Android using `asm!`-based syscalls.
use crate::{Error, MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

#[cfg(not(any(target_os = "android", target_os = "linux")))]
compile_error!("`linux_raw` backend can be enabled only for Linux/Android targets!");

#[allow(non_upper_case_globals)]
unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize {
let r0;

// Based on `rustix` and `linux-raw-sys` code.
cfg_if! {
if #[cfg(target_arch = "arm")] {
// In thumb-mode, r7 is the frame pointer and is not permitted to be used in
// an inline asm operand, so we have to use a different register and copy it
// into r7 inside the inline asm.
// Theoretically, we could detect thumb mode in the build script, but several
// register moves are cheap enough compared to the syscall cost, so we do not
// bother with it.
core::arch::asm!(
"mov {tmp}, r7",
"mov r7, #384", // __NR_getrandom = 384
"svc 0",
"mov r7, {tmp}",
tmp = out(reg) _,
inlateout("r0") buf => r0,
in("r1") buflen,
in("r2") flags,
options(nostack, preserves_flags)
);
} else if #[cfg(target_arch = "aarch64")] {
const __NR_getrandom: u32 = 278;
core::arch::asm!(
"svc 0",
in("x8") __NR_getrandom,
inlateout("x0") buf => r0,
in("x1") buflen,
in("x2") flags,
options(nostack, preserves_flags)
);
} else if #[cfg(target_arch = "loongarch64")] {
const __NR_getrandom: u32 = 278;
core::arch::asm!(
"syscall 0",
in("$a7") __NR_getrandom,
inlateout("$a0") buf => r0,
in("$a1") buflen,
in("$a2") flags,
options(nostack, preserves_flags)
);
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
const __NR_getrandom: u32 = 278;
core::arch::asm!(
"ecall",
in("a7") __NR_getrandom,
inlateout("a0") buf => r0,
in("a1") buflen,
in("a2") flags,
options(nostack, preserves_flags)
);
} else if #[cfg(target_arch = "x86")] {
const __NR_getrandom: isize = 355;
// `int 0x80` is famously slow, but implementing vDSO is too complex
// and `sysenter`/`syscall` have their own portability issues,
// so we use the simple "legacy" way of doing syscalls.
core::arch::asm!(
"int $$0x80",
inlateout("eax") __NR_getrandom => r0,
in("ebx") buf,
in("ecx") buflen,
in("edx") flags,
options(nostack, preserves_flags)
);
} else if #[cfg(target_arch = "x86_64")] {
#[cfg(target_pointer_width = "64")]
const __NR_getrandom: isize = 318;
#[cfg(target_pointer_width = "32")]
const __NR_getrandom: isize = 1073742142;

core::arch::asm!(
"syscall",
inlateout("rax") __NR_getrandom => r0,
in("rdi") buf,
in("rsi") buflen,
in("rdx") flags,
lateout("rcx") _,
lateout("r11") _,
options(nostack, preserves_flags)
);
} else {
compile_error!("`linux_raw` backend does not support this target arch");
}
}

r0
}

pub fn fill_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// Value of this error code is stable across all target arches.
const EINTR: isize = -4;

loop {
let ret = unsafe { getrandom_syscall(dest.as_mut_ptr().cast(), dest.len(), 0) };
match usize::try_from(ret) {
Ok(0) => return Err(Error::UNEXPECTED),
Ok(len) => {
dest = dest.get_mut(len..).ok_or(Error::UNEXPECTED)?;
if dest.is_empty() {
return Ok(());
}
}
Err(_) if ret == EINTR => continue,
Err(_) => {
let code: u32 = ret
.wrapping_neg()
.try_into()
.map_err(|_| Error::UNEXPECTED)?;
return Err(Error::from_os_error(code));
}
}
}
}
32 changes: 0 additions & 32 deletions src/backends/linux_rustix.rs

This file was deleted.