diff --git a/build.rs b/build.rs index b81e2177..d3dac9c7 100644 --- a/build.rs +++ b/build.rs @@ -25,12 +25,16 @@ const INCLUDED_FUNCTIONS: &[&str] = &[ "_copy_from_user", "alloc_chrdev_region", "unregister_chrdev_region", + "wait_for_random_bytes", + "get_random_bytes", + "rng_is_initialized", ]; const INCLUDED_VARS: &[&str] = &[ "EINVAL", "ENOMEM", "ESPIPE", "EFAULT", + "EAGAIN", "__this_module", "FS_REQUIRES_DEV", "FS_BINARY_MOUNTDATA", diff --git a/src/bindings_helper.h b/src/bindings_helper.h index df0e387d..fd8ba5e8 100644 --- a/src/bindings_helper.h +++ b/src/bindings_helper.h @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include diff --git a/src/error.rs b/src/error.rs index 98081bcd..40b48d3e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,6 +10,7 @@ impl Error { pub const ENOMEM: Self = Error(-(bindings::ENOMEM as i32)); pub const EFAULT: Self = Error(-(bindings::EFAULT as i32)); pub const ESPIPE: Self = Error(-(bindings::ESPIPE as i32)); + pub const EAGAIN: Self = Error(-(bindings::EAGAIN as i32)); pub fn from_kernel_errno(errno: c_types::c_int) -> Error { Error(errno) diff --git a/src/lib.rs b/src/lib.rs index f9595036..e0ee4ccd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ mod error; pub mod file_operations; pub mod filesystem; pub mod printk; +pub mod random; pub mod sysctl; mod types; pub mod user_ptr; diff --git a/src/random.rs b/src/random.rs new file mode 100644 index 00000000..256da341 --- /dev/null +++ b/src/random.rs @@ -0,0 +1,28 @@ +use core::convert::TryInto; + +use crate::{bindings, error}; + +/// Fills `dest` with random bytes generated from the kernel's CSPRNG. Ensures +/// that the CSPRNG has been seeded before generating any random bytes, and +/// will block until it's ready. +pub fn getrandom(dest: &mut [u8]) -> error::KernelResult<()> { + let res = unsafe { bindings::wait_for_random_bytes() }; + if res != 0 { + return Err(error::Error::from_kernel_errno(res)); + } + + unsafe { + // TODO: convert `unwrap` to proper error handling + bindings::get_random_bytes(dest.as_mut_ptr(), dest.len().try_into().unwrap()); + } + Ok(()) +} + +/// Fills `dest` with random bytes generated from the kernel's CSPRNG. If the +/// CSPRNG is not yet seeded, returns an `Err(EAGAIN)` immediately. +pub fn getrandom_nonblock(dest: &mut [u8]) -> error::KernelResult<()> { + if !unsafe { bindings::rng_is_initialized() } { + return Err(error::Error::EAGAIN); + } + getrandom(dest) +}