shadow_rs/host/syscall/handler/
random.rs

1use linux_api::errno::Errno;
2use log::*;
3use rand::RngCore;
4use shadow_shim_helper_rs::syscall_types::ForeignPtr;
5
6use crate::host::syscall::handler::{SyscallContext, SyscallHandler};
7use crate::host::syscall::types::ForeignArrayPtr;
8
9impl SyscallHandler {
10    log_syscall!(
11        getrandom,
12        /* rv */ isize,
13        /* buf */ *const std::ffi::c_void,
14        /* count */ usize,
15        /* flags */ std::ffi::c_uint,
16    );
17    pub fn getrandom(
18        ctx: &mut SyscallContext,
19        buf_ptr: ForeignPtr<u8>,
20        count: usize,
21        _flags: std::ffi::c_uint,
22    ) -> Result<isize, Errno> {
23        // We ignore the flags arg, because we use the same random source for both
24        // random and urandom, and it never blocks anyway.
25
26        trace!("Trying to read {count} random bytes.");
27
28        // Get a native-process mem buffer where we can copy the random bytes.
29        let dst_ptr = ForeignArrayPtr::new(buf_ptr, count);
30        let mut memory = ctx.objs.process.memory_borrow_mut();
31        let mut mem_ref = match memory.memory_ref_mut_uninit(dst_ptr) {
32            Ok(m) => m,
33            Err(e) => {
34                warn!("Failed to get memory ref: {e:?}");
35                return Err(Errno::EFAULT);
36            }
37        };
38
39        // Get random bytes using host rng to maintain determinism.
40        let mut rng = ctx.objs.host.random_mut();
41        rng.fill_bytes(&mut mem_ref);
42
43        // We must flush the memory reference to write it back.
44        match mem_ref.flush() {
45            Ok(()) => Ok(isize::try_from(count).unwrap()),
46            Err(e) => {
47                warn!("Failed to flush writes: {e:?}");
48                Err(Errno::EFAULT)
49            }
50        }
51    }
52}