Skip to main content

strat9_kernel/syscall/
random.rs

1//! Random number generation syscalls: getrandom
2//!
3//! Fills request buffers from the kernel entropy pool, which collects
4//! entropy from interrupt noise (keyboard, timer, storage IRQs) and
5//! RDRAND.  Falls back to RDRAND + jitter if the pool is not yet
6//! seeded during early boot.
7
8use crate::{memory::userslice::UserSliceWrite, syscall::error::SyscallError};
9
10/// GRND_NONBLOCK: return EAGAIN if entropy pool is not yet initialised.
11const GRND_NONBLOCK: u32 = 1;
12/// GRND_RANDOM: use /dev/random quality (same pool, no distinction in this impl).
13const GRND_RANDOM: u32 = 2;
14/// Valid flags mask.
15const GRND_FLAGS_MASK: u32 = GRND_NONBLOCK | GRND_RANDOM;
16
17/// SYS_GETRANDOM (601): Fill a buffer with random bytes.
18///
19/// # Arguments
20/// * `buf`   - Pointer to the userspace buffer
21/// * `len`   - Number of bytes requested
22/// * `flags` - GRND_NONBLOCK (1) and/or GRND_RANDOM (2)
23///
24/// # Returns
25/// * Number of bytes written on success
26/// * -EAGAIN if GRND_NONBLOCK is set and entropy pool is not yet initialised
27/// * -EFAULT if buf pointer is invalid
28/// * -EINVAL if len is 0 or flags are invalid
29///
30/// # POSIX compatibility
31/// POSIX signature: `ssize_t getrandom(void *buf, size_t buflen, unsigned int flags)`
32pub fn sys_getrandom(buf: u64, len: usize, flags: u32) -> Result<u64, SyscallError> {
33    if buf == 0 || len == 0 {
34        return Err(SyscallError::InvalidArgument);
35    }
36
37    if flags & !GRND_FLAGS_MASK != 0 {
38        return Err(SyscallError::InvalidArgument);
39    }
40
41    // If GRND_NONBLOCK is set, check whether the pool has enough entropy.
42    // If not, return EAGAIN immediately instead of spinning.
43    if flags & GRND_NONBLOCK != 0 && !crate::entropy::is_ready() {
44        return Err(SyscallError::Again);
45    }
46
47    // Bound the maximum read to avoid DoS (256 bytes is reasonable for canary/seed)
48    let actual_len = len.min(256);
49    let mut tmp = [0u8; 256];
50
51    // Try the entropy pool first (cryptographically sound).
52    crate::entropy::fill_random(&mut tmp[..actual_len]);
53
54    let user = UserSliceWrite::new(buf, actual_len)?;
55    user.copy_from(&tmp[..actual_len]);
56    Ok(actual_len as u64)
57}