From 3685d34d638f8d513665dba52b8bb4c7acb76aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Wed, 16 Oct 2024 06:46:23 +0300 Subject: [PATCH] Add `linux_rustix` opt-in backend --- .github/workflows/nopanic.yaml | 7 +++++++ .github/workflows/tests.yml | 3 +++ .github/workflows/workspace.yml | 4 ++++ Cargo.toml | 7 +++++-- src/lib.rs | 4 ++++ src/linux_rustix.rs | 30 ++++++++++++++++++++++++++++++ 6 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 src/linux_rustix.rs diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index 798e15df..03695a3b 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -40,6 +40,13 @@ jobs: - name: Check (linux_android.rs) run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + - name: Build (linux_rustix.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" + run: cargo build --release + - name: Check (linux_rustix.rs) + run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + - name: Build (rdrand.rs) env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 10027577..d02dcdb8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -71,6 +71,9 @@ jobs: - env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std + - env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" + run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std - env: RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback run: cargo test --features=std diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 86cdadc9..8da81c65 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -53,6 +53,10 @@ jobs: env: RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom" run: cargo clippy --target x86_64-unknown-linux-gnu + - name: Linux (linux_rustix.rs) + env: + RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_rustix" + 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 - name: NetBSD (netbsd.rs) diff --git a/Cargo.toml b/Cargo.toml index 88ce5637..a521e96c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,9 +18,12 @@ cfg-if = "1" compiler_builtins = { version = "0.1", optional = true } core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" } -[target.'cfg(unix)'.dependencies] +[target.'cfg(all(unix, not(getrandom_backend = "linux_rustix")))'.dependencies] libc = { version = "0.2.154", default-features = false } +[target.'cfg(all(getrandom_backend = "linux_rustix", any(target_os = "linux", target_os = "android")))'.dependencies] +rustix = { version = "0.38", default-features = false, features = ["rand"] } + [target.'cfg(all(target_arch = "wasm32", target_os = "wasi", target_env = "p2"))'.dependencies] wasi = { version = "0.13", default-features = false } @@ -42,7 +45,7 @@ rustc-dep-of-std = ["compiler_builtins", "core"] [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "wasm_js", "esp_idf"))', + 'cfg(getrandom_backend, values("custom", "rdrand", "rndr", "linux_getrandom", "linux_rustix", "wasm_js", "esp_idf"))', 'cfg(getrandom_browser_test)', 'cfg(getrandom_test_linux_fallback)', ] diff --git a/src/lib.rs b/src/lib.rs index 67a4addc..2722cac3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,6 +41,7 @@ //! | 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‑*` | [`getrandom`][1] system call using the [`rustix`] crate //! | `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! @@ -243,6 +244,7 @@ //! [platform-support]: https://doc.rust-lang.org/stable/rustc/platform-support.html //! [WASI]: https://github.com/CraneStation/wasi //! [Emscripten]: https://www.hellorust.com/setup/emscripten/ +//! [`rustix`]: https://docs.rs/rustix #![doc( html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", @@ -295,6 +297,8 @@ cfg_if! { } else if #[cfg(getrandom_backend = "linux_getrandom")] { mod util_libc; #[path = "linux_android.rs"] mod imp; + } else if #[cfg(getrandom_backend = "linux_rustix")] { + #[path = "linux_rustix.rs"] mod imp; } else if #[cfg(getrandom_backend = "rdrand")] { mod lazy; #[path = "rdrand.rs"] mod imp; diff --git a/src/linux_rustix.rs b/src/linux_rustix.rs new file mode 100644 index 00000000..30a6496c --- /dev/null +++ b/src/linux_rustix.rs @@ -0,0 +1,30 @@ +//! Implementation for Linux / Android without `/dev/urandom` fallback +use crate::{Error, MaybeUninit}; +use rustix::rand::{getrandom_uninit, GetRandomFlags}; + +#[cfg(not(any(target_os = "android", target_os = "linux")))] +compile_error!("`linux_rustix` backend can be enabled only for Linux/Android targets!"); + +pub fn getrandom_inner(mut dest: &mut [MaybeUninit]) -> Result<(), Error> { + loop { + let res = getrandom_uninit(dest, GetRandomFlags::empty()).map(|(res, _)| res.len()); + match res { + Ok(0) => return Err(Error::UNEXPECTED), + Ok(res_len) => { + dest = dest.get_mut(res_len..).ok_or(Error::UNEXPECTED)?; + if !dest.is_empty() { + return Ok(()); + } + } + Err(rustix::io::Errno::INTR) => continue, + Err(err) => { + let code = err + .raw_os_error() + .wrapping_neg() + .try_into() + .expect("Errno uses u16 internally"); + return Err(Error::from_os_error(code)); + } + } + } +}