From 92776975ebff133b9bf17292be53316280f2e413 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 08:16:53 +0300 Subject: [PATCH] Add `linux_rustix` opt-in backend --- .github/workflows/nopanic.yaml | 8 ++++++ .github/workflows/tests.yml | 3 +++ .github/workflows/workspace.yml | 4 +++ CHANGELOG.md | 4 ++- Cargo.toml | 45 ++++++++++++++++++++++++++++++--- src/lib.rs | 8 ++++-- src/linux_rustix.rs | 30 ++++++++++++++++++++++ 7 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 src/linux_rustix.rs diff --git a/.github/workflows/nopanic.yaml b/.github/workflows/nopanic.yaml index 798e15df..048e0690 100644 --- a/.github/workflows/nopanic.yaml +++ b/.github/workflows/nopanic.yaml @@ -40,6 +40,14 @@ jobs: - name: Check (linux_android.rs) run: ret=$(grep panic target/release/libgetrandom_wrapper.so; echo $?); [ $ret -eq 1 ] + # TODO: re-enable after https://github.com/bytecodealliance/rustix/pull/1184 is released + # - 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/CHANGELOG.md b/CHANGELOG.md index a68b3be9..f63dc37f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `wasm32-wasip1` and `wasm32-wasip2` support [#499] - `getrandom_backend` configuration flag for selection of opt-in backends [#504] - `Error::new_custom` method [#507] -- AArch64 RNDR register opt-in backend [#512] +- `rndr` opt-in backend [#512] +- `linux_rustix` opt-in backend [#520] [#415]: https://github.com/rust-random/getrandom/pull/415 [#440]: https://github.com/rust-random/getrandom/pull/440 @@ -40,6 +41,7 @@ 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 ## [0.2.15] - 2024-05-06 ### Added diff --git a/Cargo.toml b/Cargo.toml index 88ce5637..b2fb74ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,23 +18,60 @@ 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] +# linux_android / linux_android_with_fallback +[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", 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 } + +# getentropy +[target.'cfg(any(target_os = "macos", target_os = "openbsd", target_os = "vita", target_os = "emscripten"))'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# getrandom +[target.'cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "hurd", target_os = "illumos", all(target_os = "horizon", target_arch = "arm")))'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# netbsd +[target.'cfg(target_os = "netbsd")'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# solaris +[target.'cfg(target_os = "solaris")'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# use_file +[target.'cfg(any(target_os = "haiku", target_os = "redox", target_os = "nto", target_os = "aix"))'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# vxworks +[target.'cfg(target_os = "vxworks")'.dependencies] +libc = { version = "0.2.154", default-features = false } + +# wasi (0.2 only) [target.'cfg(all(target_arch = "wasm32", target_os = "wasi", target_env = "p2"))'.dependencies] wasi = { version = "0.13", default-features = false } +# windows7 [target.'cfg(all(windows, not(target_vendor = "win7")))'.dependencies] windows-targets = "0.52" +# wasm_js [target.'cfg(all(getrandom_backend = "wasm_js", any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies] wasm-bindgen = { version = "0.2.89", default-features = false } js-sys = "0.3" -[target.'cfg(all(getrandom_backend = "wasm_js", getrandom_browser_test, any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dev-dependencies] +[target.'cfg(all(getrandom_backend = "wasm_js", getrandom_browser_test, target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies] wasm-bindgen-test = "0.3.39" [features] -# Implement std-only traits for getrandom::Error +# Implement std::error::Error for getrandom::Error and +# use std to retrieve OS error descriptions std = [] # Unstable feature to support being a libstd dependency rustc-dep-of-std = ["compiler_builtins", "core"] @@ -42,7 +79,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..d0e84c7a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,14 +6,14 @@ //! | ------------------ | ------------------ | -------------- //! | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` //! | Windows 10+ | `*‑windows‑*` | [`ProcessPrng`] -//! | Windows 7 and 8 | `*-win7‑windows‑*` | [`RtlGenRandom`] +//! | Windows 7, 8 | `*-win7‑windows‑*` | [`RtlGenRandom`] //! | macOS | `*‑apple‑darwin` | [`getentropy`][3] //! | iOS, tvOS, watchOS | `*‑apple‑ios`, `*-apple-tvos`, `*-apple-watchos` | [`CCRandomGenerateBytes`] //! | FreeBSD | `*‑freebsd` | [`getrandom`][5] //! | OpenBSD | `*‑openbsd` | [`getentropy`][7] //! | NetBSD | `*‑netbsd` | [`getrandom`][16] if available, otherwise [`kern.arandom`][8] //! | Dragonfly BSD | `*‑dragonfly` | [`getrandom`][9] -//! | Solaris | `*‑solaris` | [`getrandom`][11] (with `GRND_RANDOM`) +//! | Solaris | `*‑solaris` | [`getrandom`][11] with `GRND_RANDOM` //! | illumos | `*‑illumos` | [`getrandom`][12] //! | Fuchsia OS | `*‑fuchsia` | [`cprng_draw`] //! | Redox | `*‑redox` | `/dev/urandom` @@ -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‑*` | Same as `linux_getrandom`, but uses [`rustix`] 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! @@ -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..a286b20c --- /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() + .map_err(|_| Error::UNEXPECTED)?; + return Err(Error::from_os_error(code)); + } + } + } +}