Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ wasm-bindgen-test = "0.3"
[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = [
'cfg(getrandom_backend, values("custom", "efi_rng", "rdrand", "rndr", "linux_getrandom", "linux_raw", "windows_legacy", "unsupported"))',
'cfg(getrandom_backend, values("custom", "efi_rng", "rdrand", "rndr", "linux_getrandom", "linux_raw", "windows_legacy", "unsupported", "extern_item_impls"))',
'cfg(getrandom_msan)',
'cfg(getrandom_test_linux_fallback)',
'cfg(getrandom_test_linux_without_fallback)',
Expand Down
53 changes: 43 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,17 @@ or `js-sys` on "unknown" WASM targets then it's acceptable to enable this featur
`getrandom` also provides optional (opt-in) backends, which allow users to customize the source
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_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
| `efi_rng` | UEFI | `*-unknown‑uefi` | [`EFI_RNG_PROTOCOL`] with `EFI_RNG_ALGORITHM_RAW` (requires `std` and Nightly compiler)
| `windows_legacy` | Windows | `*-windows-*` | [`RtlGenRandom`]
| `custom` | All targets | `*` | User-provided custom implementation (see [custom backend])
| `unsupported` | All targets | `*` | Always returns `Err(Error::UNSUPPORTED)` (see [unsupported backend])
| 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_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
| `efi_rng` | UEFI | `*-unknown‑uefi` | [`EFI_RNG_PROTOCOL`] with `EFI_RNG_ALGORITHM_RAW` (requires `std` and Nightly compiler)
| `windows_legacy` | Windows | `*-windows-*` | [`RtlGenRandom`]
| `custom` | All targets | `*` | User-provided custom implementation (see [custom backend])
| `unsupported` | All targets | `*` | Always returns `Err(Error::UNSUPPORTED)` (see [unsupported backend])
| `extern_item_impls` | All targets | `*` | User or library provided custom implementation (see [externally implemented interface])

Opt-in backends can be enabled using the `getrandom_backend` configuration flag.
The flag can be set either by specifying the `rustflags` field in [`.cargo/config.toml`]:
Expand Down Expand Up @@ -201,6 +202,37 @@ unsafe extern "Rust" fn __getrandom_v03_custom(
}
```

### Externally Implemented Interface

Using the nightly-only feature [`extern_item_impls`](https://github.com/rust-lang/rust/issues/125418)
it is possible to provide a custom backend for `getrandom`, even to override
an existing first-party implementation. First, enable the `extern_item_impls`
opt-in backend to allow usage of this nightly feature. Then, you may provide
implementations for `fill_uninit`, `u32`, and/or `u64` with an attribute macro
from the `implementation` module.

```rust
use core::mem::MaybeUninit;

#[cfg(getrandom_backend = "extern_item_impls")]
#[getrandom::implementation::fill_uninit]
fn my_fill_uninit_implementation(
dest: &mut [MaybeUninit<u8>]
) -> Result<(), getrandom::Error> {
// ...
Ok(())
}
```

For further details on what a suitable implementation for `fill_uninit` may look
like, see [custom backend].

`getrandom` will provide a default implementation for `u32` and `u64`, but does
not currently provide a default for `fill_uninit`, even if one is normally
available for the current target. If no implementation is available,
a compilation error will be raised with instructions for how to provide
an implementation.

### Unsupported backend

In some rare scenarios, you might be compiling this crate for an unsupported
Expand Down Expand Up @@ -373,6 +405,7 @@ dual licensed as above, without any additional terms or conditions.
[WASI]: https://github.com/WebAssembly/WASI
[Emscripten]: https://emscripten.org
[opt-in]: #opt-in-backends
[externally implemented interface]: #externally-implemented-interface

[//]: # (licenses)

Expand Down
3 changes: 3 additions & 0 deletions src/backends.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ cfg_if! {
} else if #[cfg(getrandom_backend = "unsupported")] {
mod unsupported;
pub use unsupported::*;
} else if #[cfg(getrandom_backend = "extern_item_impls")] {
pub(crate) mod extern_item_impls;
pub use extern_item_impls::*;
} else if #[cfg(all(target_os = "linux", target_env = ""))] {
mod linux_raw;
pub use linux_raw::*;
Expand Down
19 changes: 19 additions & 0 deletions src/backends/extern_item_impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//! An implementation which calls out to an externally defined function.
use crate::Error;
use core::mem::MaybeUninit;

/// Declares this function as an external implementation of [`fill_uninit`](crate::fill_uninit).
#[cfg_attr(getrandom_backend = "extern_item_impls", eii(fill_uninit))]
pub(crate) fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error>;

/// Declares this function as an external implementation of [`u32`](crate::u32).
#[cfg_attr(getrandom_backend = "extern_item_impls", eii(u32))]
pub(crate) fn inner_u32() -> Result<u32, crate::Error> {
crate::util::inner_u32()
}

/// Declares this function as an external implementation of [`u64`](crate::u64).
#[cfg_attr(getrandom_backend = "extern_item_impls", eii(u64))]
pub(crate) fn inner_u64() -> Result<u64, crate::Error> {
crate::util::inner_u64()
}
28 changes: 28 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#![doc = include_str!("../README.md")]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(getrandom_backend = "efi_rng", feature(uefi_std))]
#![cfg_attr(getrandom_backend = "extern_item_impls", feature(extern_item_impls))]

#[macro_use]
extern crate cfg_if;
Expand All @@ -34,6 +35,33 @@ pub use sys_rng::SysRng;

pub use crate::error::{Error, RawOsError};

#[cfg(getrandom_backend = "extern_item_impls")]
pub mod implementation {
//! Provides Externally Implementable Interfaces for the core functionality of this crate.
//! This allows `getrandom` to provide a default implementation and a common interface
//! for all crates to use, while giving users a safe way to override that default where required.
//!
//! Must be enabled via the `extern_item_impls` opt-in backend, as this functionality
//! is currently limited to nightly.
//!
//! # Examples
//!
//! ```rust
//! # use core::mem::MaybeUninit;
//! # #[cfg(getrandom_backend = "extern_item_impls")]
//! #[getrandom::implementation::fill_uninit]
//! fn my_fill_uninit_implementation(
//! dest: &mut [MaybeUninit<u8>]
//! ) -> Result<(), getrandom::Error> {
//! // ...
//! # let _ = dest;
//! # Err(Error::UNSUPPORTED)
//! }
//! ```

pub use crate::backends::extern_item_impls::{fill_uninit, u32, u64};
}

/// Fill `dest` with random bytes from the system's preferred random number source.
///
/// This function returns an error on any failure, including partial reads. We
Expand Down
Loading