Skip to content
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
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))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cfg_attr is not needed since the module is already gated.

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to use ///-style doc for this module.

//! 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