Skip to content

Commit

Permalink
Move backend implementations to src/backends/ (#538)
Browse files Browse the repository at this point in the history
This makes it easier to get list of existing backends.
It also makes lib.rs and the backends `cfg_if` a bit less cluttered.
  • Loading branch information
newpavlov authored Oct 28, 2024
1 parent 5bf25bc commit 0bfe592
Show file tree
Hide file tree
Showing 24 changed files with 208 additions and 170 deletions.
152 changes: 152 additions & 0 deletions src/backends.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
//! System-specific implementations.
//!
//! This module should provide `fill_inner` with the signature
//! `fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error>`.
//! The function MUST fully initialize `dest` when `Ok(())` is returned.
//! The function MUST NOT ever write uninitialized bytes into `dest`,
//! regardless of what value it returns.
cfg_if! {
if #[cfg(getrandom_backend = "custom")] {
mod custom;
pub use custom::*;
} 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 = "rdrand")] {
mod rdrand;
pub use rdrand::*;
} else if #[cfg(getrandom_backend = "rndr")] {
mod rndr;
pub use rndr::*;
} else if #[cfg(getrandom_backend = "wasm_js")] {
mod wasm_js;
pub use wasm_js::*;
} else if #[cfg(getrandom_backend = "esp_idf")] {
mod esp_idf;
pub use esp_idf::*;
} else if #[cfg(any(
target_os = "haiku",
target_os = "redox",
target_os = "nto",
target_os = "aix",
))] {
mod use_file;
pub use use_file::*;
} else if #[cfg(any(
target_os = "macos",
target_os = "openbsd",
target_os = "vita",
target_os = "emscripten",
))] {
mod getentropy;
pub use getentropy::*;
} else if #[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "hurd",
target_os = "illumos",
// Check for target_arch = "arm" to only include the 3DS. Does not
// include the Nintendo Switch (which is target_arch = "aarch64").
all(target_os = "horizon", target_arch = "arm"),
))] {
mod getrandom;
pub use getrandom::*;
} else if #[cfg(any(
// Rust supports Android API level 19 (KitKat) [0] and the next upgrade targets
// level 21 (Lollipop) [1], while `getrandom(2)` was added only in
// level 23 (Marshmallow). Note that it applies only to the "old" `target_arch`es,
// RISC-V Android targets sufficiently new API level, same will apply for potential
// new Android `target_arch`es.
// [0]: https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html
// [1]: https://github.com/rust-lang/rust/pull/120593
all(
target_os = "android",
any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "x86",
target_arch = "x86_64",
),
),
// Only on these `target_arch`es Rust supports Linux kernel versions (3.2+)
// that precede the version (3.17) in which `getrandom(2)` was added:
// https://doc.rust-lang.org/stable/rustc/platform-support.html
all(
target_os = "linux",
any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "s390x",
target_arch = "x86",
target_arch = "x86_64",
// Minimum supported Linux kernel version for MUSL targets
// is not specified explicitly (as of Rust 1.77) and they
// are used in practice to target pre-3.17 kernels.
target_env = "musl",
),
)
))] {
mod use_file;
mod linux_android_with_fallback;
pub use linux_android_with_fallback::*;
} else if #[cfg(any(target_os = "android", target_os = "linux"))] {
mod linux_android;
pub use linux_android::*;
} else if #[cfg(target_os = "solaris")] {
mod solaris;
pub use solaris::*;
} else if #[cfg(target_os = "netbsd")] {
mod netbsd;
pub use netbsd::*;
} else if #[cfg(target_os = "fuchsia")] {
mod fuchsia;
pub use fuchsia::*;
} else if #[cfg(any(
target_os = "ios",
target_os = "visionos",
target_os = "watchos",
target_os = "tvos",
))] {
mod apple_other;
pub use apple_other::*;
} else if #[cfg(all(target_arch = "wasm32", target_os = "wasi"))] {
mod wasi;
pub use wasi::*;
} else if #[cfg(target_os = "hermit")] {
mod hermit;
pub use hermit::*;
} else if #[cfg(target_os = "vxworks")] {
mod vxworks;
pub use vxworks::*;
} else if #[cfg(target_os = "solid_asp3")] {
mod solid;
pub use solid::*;
} else if #[cfg(all(windows, target_vendor = "win7"))] {
mod windows7;
pub use windows7::*;
} else if #[cfg(windows)] {
mod windows;
pub use windows::*;
} else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] {
mod rdrand;
pub use rdrand::*;
} else if #[cfg(all(
any(target_arch = "wasm32", target_arch = "wasm64"),
target_os = "unknown",
))] {
compile_error!("the wasm*-unknown-unknown targets are not supported by \
default, you may need to enable the \"wasm_js\" \
configuration flag. For more information see: \
https://docs.rs/getrandom/#webassembly-support");
} else {
compile_error!("target is not supported. You may need to define \
a custom backend see: \
https://docs.rs/getrandom/#custom-backends");
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
7 changes: 5 additions & 2 deletions src/getentropy.rs → src/backends/getentropy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
//! - vita newlib since Dec 2021
//!
//! For these targets, we use getentropy(2) because getrandom(2) doesn't exist.
use crate::{util_libc::last_os_error, Error};
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

#[path = "../util_libc.rs"]
mod util_libc;

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
for chunk in dest.chunks_mut(256) {
let ret = unsafe { libc::getentropy(chunk.as_mut_ptr().cast::<c_void>(), chunk.len()) };
if ret != 0 {
return Err(last_os_error());
return Err(util_libc::last_os_error());
}
}
Ok(())
Expand Down
7 changes: 5 additions & 2 deletions src/getrandom.rs → src/backends/getrandom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
//! GRND_RANDOM is not recommended. On NetBSD/FreeBSD/Dragonfly/3ds, it does
//! nothing. On illumos, the default pool is used to implement getentropy(2),
//! so we assume it is acceptable here.
use crate::{util_libc::sys_fill_exact, Error};
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

#[path = "../util_libc.rs"]
mod util_libc;

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
sys_fill_exact(dest, |buf| unsafe {
util_libc::sys_fill_exact(dest, |buf| unsafe {
libc::getrandom(buf.as_mut_ptr().cast::<c_void>(), buf.len(), 0)
})
}
File renamed without changes.
5 changes: 4 additions & 1 deletion src/linux_android.rs → src/backends/linux_android.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//! Implementation for Linux / Android without `/dev/urandom` fallback
use crate::{util_libc, Error};
use crate::Error;
use core::mem::MaybeUninit;

#[path = "../util_libc.rs"]
mod util_libc;

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

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
//! Implementation for Linux / Android with `/dev/urandom` fallback
use crate::{use_file, util_libc, Error};
use super::use_file;
use crate::Error;
use core::{
ffi::c_void,
mem::{self, MaybeUninit},
ptr::{self, NonNull},
sync::atomic::{AtomicPtr, Ordering},
};
use use_file::util_libc;

type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) -> libc::ssize_t;

Expand Down
File renamed without changes.
7 changes: 5 additions & 2 deletions src/netbsd.rs → src/backends/netbsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! `getrandom(2)` was introduced in NetBSD 10. To support older versions we
//! implement our own weak linkage to it, and provide a fallback based on the
//! KERN_ARND sysctl.
use crate::{util_libc::sys_fill_exact, Error};
use crate::Error;
use core::{
cmp,
ffi::c_void,
Expand All @@ -12,6 +12,9 @@ use core::{
sync::atomic::{AtomicPtr, Ordering},
};

#[path = "../util_libc.rs"]
mod util_libc;

unsafe extern "C" fn polyfill_using_kern_arand(
buf: *mut c_void,
buflen: libc::size_t,
Expand Down Expand Up @@ -69,7 +72,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
fptr = init();
}
let fptr = unsafe { mem::transmute::<*mut c_void, GetRandomFn>(fptr) };
sys_fill_exact(dest, |buf| unsafe {
util_libc::sys_fill_exact(dest, |buf| unsafe {
fptr(buf.as_mut_ptr().cast::<c_void>(), buf.len(), 0)
})
}
7 changes: 5 additions & 2 deletions src/rdrand.rs → src/backends/rdrand.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//! RDRAND backend for x86(-64) targets
use crate::{lazy::LazyBool, util::slice_as_uninit, Error};
use crate::{util::slice_as_uninit, Error};
use core::mem::{size_of, MaybeUninit};

#[path = "../lazy.rs"]
mod lazy;

#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
compile_error!("`rdrand` backend can be enabled only for x86 and x86-64 targets!");

Expand Down Expand Up @@ -97,7 +100,7 @@ fn is_rdrand_good() -> bool {
}

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
static RDRAND_GOOD: LazyBool = LazyBool::new();
static RDRAND_GOOD: lazy::LazyBool = lazy::LazyBool::new();
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
return Err(Error::NO_RDRAND);
}
Expand Down
4 changes: 2 additions & 2 deletions src/rndr.rs → src/backends/rndr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ fn is_rndr_available() -> bool {
(id_aa64isar0 >> 60) & 0xf >= 1
}

#[path = "../src/lazy.rs"] mod lazy;
#[path = "../lazy.rs"] mod lazy;
static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new();
RNDR_GOOD.unsync_init(mrs_check)
} else if #[cfg(feature = "std")] {
extern crate std;
#[path = "../src/lazy.rs"] mod lazy;
#[path = "../lazy.rs"] mod lazy;
static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new();
RNDR_GOOD.unsync_init(|| std::arch::is_aarch64_feature_detected!("rand"))
} else {
Expand Down
12 changes: 9 additions & 3 deletions src/solaris.rs → src/backends/solaris.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
//! For more information, see the man page linked in lib.rs and this blog post:
//! https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2
//! which also explains why this crate should not use getentropy(2).
use crate::{util_libc::last_os_error, Error};
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

#[path = "../util_libc.rs"]
mod util_libc;

const MAX_BYTES: usize = 1024;

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
Expand All @@ -24,8 +27,11 @@ pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// In case the man page has a typo, we also check for negative ret.
// If getrandom(2) succeeds, it should have completely filled chunk.
match usize::try_from(ret) {
Ok(ret) if ret == chunk.len() => {} // Good. Keep going.
Ok(0) => return Err(last_os_error()), // The syscall failed.
// Good. Keep going.
Ok(ret) if ret == chunk.len() => {}
// The syscall failed.
Ok(0) => return Err(util_libc::last_os_error()),
// All other cases should be impossible.
_ => return Err(Error::UNEXPECTED),
}
}
Expand Down
File renamed without changes.
14 changes: 7 additions & 7 deletions src/use_file.rs → src/backends/use_file.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//! Implementations that just need to read from a file
use crate::{
util_libc::{last_os_error, sys_fill_exact},
Error,
};
use crate::Error;
use core::{
ffi::c_void,
mem::MaybeUninit,
sync::atomic::{AtomicI32, Ordering},
};

#[path = "../util_libc.rs"]
pub(super) mod util_libc;

/// For all platforms, we use `/dev/urandom` rather than `/dev/random`.
/// For more information see the linked man pages in lib.rs.
/// - On Linux, "/dev/urandom is preferred and sufficient in all use cases".
Expand Down Expand Up @@ -42,7 +42,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
if fd == FD_UNINIT || fd == FD_ONGOING_INIT {
fd = open_or_wait()?;
}
sys_fill_exact(dest, |buf| unsafe {
util_libc::sys_fill_exact(dest, |buf| unsafe {
libc::read(fd, buf.as_mut_ptr().cast::<c_void>(), buf.len())
})
}
Expand All @@ -65,7 +65,7 @@ fn open_readonly(path: &[u8]) -> Result<libc::c_int, Error> {
if fd >= 0 {
return Ok(fd);
}
let err = last_os_error();
let err = util_libc::last_os_error();
// We should try again if open() was interrupted.
if err.raw_os_error() != Some(libc::EINTR) {
return Err(err);
Expand Down Expand Up @@ -142,7 +142,7 @@ mod sync {

#[cfg(any(target_os = "android", target_os = "linux"))]
mod sync {
use super::{last_os_error, open_readonly, Error, FD, FD_ONGOING_INIT};
use super::{open_readonly, util_libc::last_os_error, Error, FD, FD_ONGOING_INIT};

/// Wait for atomic `FD` to change value from `FD_ONGOING_INIT` to something else.
///
Expand Down
7 changes: 5 additions & 2 deletions src/vxworks.rs → src/backends/vxworks.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
//! Implementation for VxWorks
use crate::{util_libc::last_os_error, Error};
use crate::Error;
use core::{
cmp::Ordering::{Equal, Greater, Less},
mem::MaybeUninit,
sync::atomic::{AtomicBool, Ordering::Relaxed},
};

#[path = "../util_libc.rs"]
mod util_libc;

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
static RNG_INIT: AtomicBool = AtomicBool::new(false);
while !RNG_INIT.load(Relaxed) {
Expand All @@ -32,7 +35,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
let p: *mut libc::c_uchar = chunk.as_mut_ptr().cast();
let ret = unsafe { libc::randABytes(p, chunk_len) };
if ret != 0 {
return Err(last_os_error());
return Err(util_libc::last_os_error());
}
}
Ok(())
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion src/wasm_js.rs → src/backends/wasm_js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ thread_local!(
static RNG_SOURCE: Result<RngSource, Error> = getrandom_init();
);

pub(crate) fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
RNG_SOURCE.with(|result| {
let source = result.as_ref().map_err(|&e| e)?;

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 0bfe592

Please sign in to comment.