diff --git a/src/libos/src/fs/dev_fs/dev_random.rs b/src/libos/src/fs/dev_fs/dev_random.rs index 79bc3b6a..56c72027 100644 --- a/src/libos/src/fs/dev_fs/dev_random.rs +++ b/src/libos/src/fs/dev_fs/dev_random.rs @@ -1,12 +1,12 @@ use super::*; -use crate::util::random; +use crate::misc; #[derive(Debug)] pub struct DevRandom; impl INode for DevRandom { fn read_at(&self, offset: usize, buf: &mut [u8]) -> vfs::Result { - random::get_random(buf).map_err(|_| FsError::Again)?; + misc::get_random(buf).map_err(|_| FsError::Again)?; Ok(buf.len()) } diff --git a/src/libos/src/fs/sefs/sgx_uuid_provider.rs b/src/libos/src/fs/sefs/sgx_uuid_provider.rs index 34fd0b39..1ef27f8a 100644 --- a/src/libos/src/fs/sefs/sgx_uuid_provider.rs +++ b/src/libos/src/fs/sefs/sgx_uuid_provider.rs @@ -1,5 +1,5 @@ use super::*; -use crate::util::random; +use crate::misc; use rcore_fs_sefs::dev::{SefsUuid, UuidProvider}; pub struct SgxUuidProvider; @@ -7,7 +7,7 @@ pub struct SgxUuidProvider; impl UuidProvider for SgxUuidProvider { fn generate_uuid(&self) -> SefsUuid { let mut uuid: [u8; 16] = [0u8; 16]; - random::get_random(&mut uuid).expect("failed to get random number"); + misc::get_random(&mut uuid).expect("failed to get random number"); SefsUuid(uuid) } } diff --git a/src/libos/src/misc/mod.rs b/src/libos/src/misc/mod.rs index 5c11ebbf..34923189 100644 --- a/src/libos/src/misc/mod.rs +++ b/src/libos/src/misc/mod.rs @@ -2,10 +2,12 @@ use super::*; #[cfg(feature = "cov")] mod coverage; +mod random; mod rlimit; mod sysinfo; mod uname; +pub use self::random::{do_getrandom, get_random, RandFlags}; pub use self::rlimit::{do_prlimit, resource_t, rlimit_t, ResourceLimits}; pub use self::sysinfo::{do_sysinfo, sysinfo_t}; pub use self::uname::{do_uname, utsname_t}; diff --git a/src/libos/src/util/random.rs b/src/libos/src/misc/random.rs similarity index 52% rename from src/libos/src/util/random.rs rename to src/libos/src/misc/random.rs index d450b147..cf7aa6c8 100644 --- a/src/libos/src/util/random.rs +++ b/src/libos/src/misc/random.rs @@ -1,20 +1,45 @@ use super::*; -use sgx_types::sgx_status_t; +pub fn do_getrandom(rand_buf: &mut [u8], flags: RandFlags) -> Result<()> { + debug!("getrandom: flags: {:?}", flags); + if flags.contains(RandFlags::GRND_NONBLOCK) { + get_random(rand_buf) + } else { + get_random_blocking(rand_buf) + } +} -const MAX_RETRIES: u32 = 50; +bitflags! { + pub struct RandFlags: u32 { + /// Don't block and return EAGAIN instead + const GRND_NONBLOCK = 0x0001; + /// No effect + const GRND_RANDOM = 0x0002; + } +} + +fn get_random_blocking(rand: &mut [u8]) -> Result<()> { + loop { + if get_random(rand).is_ok() { + break; + } + } + Ok(()) +} pub fn get_random(rand: &mut [u8]) -> Result<()> { + use sgx_types::sgx_status_t; extern "C" { fn sgx_read_rand(rand_buf: *mut u8, buf_size: usize) -> sgx_status_t; } + const MAX_TIMES: u32 = 50; if rand.is_empty() { return Ok(()); } // sgx_read_rand() may fail because of HW failure of RDRAND instruction, // add retries to get the random number. - for _ in 0..MAX_RETRIES { + for _ in 0..MAX_TIMES { let status = unsafe { sgx_read_rand(rand.as_mut_ptr(), rand.len()) }; match status { sgx_status_t::SGX_SUCCESS => { diff --git a/src/libos/src/process/do_spawn/init_stack.rs b/src/libos/src/process/do_spawn/init_stack.rs index 9df45f04..e5bdcb47 100644 --- a/src/libos/src/process/do_spawn/init_stack.rs +++ b/src/libos/src/process/do_spawn/init_stack.rs @@ -3,8 +3,8 @@ use std::os::raw::c_char; use std::{mem, ptr}; use super::aux_vec::{AuxKey, AuxVec}; +use crate::misc; use crate::prelude::*; -use crate::util::random; /* * The initial stack of a process looks like below: @@ -152,7 +152,7 @@ impl StackBuf { fn generate_random_on_stack(stack: &StackBuf) -> Result<*const u8> { let rand_val = { let mut rand: [u8; 16] = [0; 16]; - random::get_random(&mut rand)?; + misc::get_random(&mut rand)?; rand }; stack.put_slice(&rand_val) diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 6af77e2a..85bbf3f9 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -34,7 +34,7 @@ use crate::fs::{ Stat, Statfs, }; use crate::interrupt::{do_handle_interrupt, sgx_interrupt_info_t}; -use crate::misc::{resource_t, rlimit_t, sysinfo_t, utsname_t}; +use crate::misc::{resource_t, rlimit_t, sysinfo_t, utsname_t, RandFlags}; use crate::net::{ do_accept, do_accept4, do_bind, do_connect, do_epoll_create, do_epoll_create1, do_epoll_ctl, do_epoll_pwait, do_epoll_wait, do_getpeername, do_getsockname, do_getsockopt, do_listen, @@ -406,7 +406,7 @@ macro_rules! process_syscall_table_with_callback { (SchedGetattr = 315) => handle_unsupported(), (Renameat2 = 316) => handle_unsupported(), (Seccomp = 317) => handle_unsupported(), - (Getrandom = 318) => handle_unsupported(), + (Getrandom = 318) => do_getrandom(buf: *mut u8, len: size_t, flags: u32), (MemfdCreate = 319) => handle_unsupported(), (KexecFileLoad = 320) => handle_unsupported(), (Bpf = 321) => handle_unsupported(), @@ -827,6 +827,20 @@ fn do_sysinfo(info: *mut sysinfo_t) -> Result { Ok(0) } +fn do_getrandom(buf: *mut u8, len: size_t, flags: u32) -> Result { + check_mut_array(buf, len)?; + let checked_len = if len > u32::MAX as usize { + u32::MAX as usize + } else { + len + }; + let rand_buf = unsafe { std::slice::from_raw_parts_mut(buf, checked_len) }; + let flags = RandFlags::from_bits(flags).ok_or_else(|| errno!(EINVAL, "invalid flags"))?; + + misc::do_getrandom(rand_buf, flags)?; + Ok(checked_len as isize) +} + // TODO: handle tz: timezone_t fn do_gettimeofday(tv_u: *mut timeval_t) -> Result { check_mut_ptr(tv_u)?; diff --git a/src/libos/src/util/mod.rs b/src/libos/src/util/mod.rs index 9a58644c..8f6b5404 100644 --- a/src/libos/src/util/mod.rs +++ b/src/libos/src/util/mod.rs @@ -4,7 +4,6 @@ pub mod dirty; pub mod log; pub mod mem_util; pub mod mpx_util; -pub mod random; pub mod resolv_conf_util; pub mod sgx; pub mod sync; diff --git a/src/libos/src/vm/process_vm.rs b/src/libos/src/vm/process_vm.rs index adde03a2..b032cb1a 100644 --- a/src/libos/src/vm/process_vm.rs +++ b/src/libos/src/vm/process_vm.rs @@ -52,10 +52,10 @@ impl<'a, 'b> ProcessVMBuilder<'a, 'b> { return range; } - use crate::util::random; + use crate::misc; trace!("entrophy size = {}", range); let mut random_buf: [u8; 8] = [0u8; 8]; // same length as usize - random::get_random(&mut random_buf).expect("failed to get random number"); + misc::get_random(&mut random_buf).expect("failed to get random number"); let random_num: usize = u64::from_le_bytes(random_buf) as usize; random_num % range } diff --git a/test/Makefile b/test/Makefile index 89f10d91..d169f027 100644 --- a/test/Makefile +++ b/test/Makefile @@ -19,7 +19,7 @@ TESTS ?= env empty hello_world malloc mmap file fs_perms getpid spawn sched pipe truncate readdir mkdir open stat link symlink chmod chown tls pthread system_info resolv_conf rlimit \ server server_epoll unix_socket cout hostfs cpuid rdtsc device sleep exit_group \ ioctl fcntl eventfd emulate_syscall access signal sysinfo prctl rename procfs wait \ - spawn_attribute exec statfs umask pgrp vfork + spawn_attribute exec statfs random umask pgrp vfork # Benchmarks: need to be compiled and run by bench-% target BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput diff --git a/test/random/Makefile b/test/random/Makefile new file mode 100644 index 00000000..9e1b6dec --- /dev/null +++ b/test/random/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/random/main.c b/test/random/main.c new file mode 100644 index 00000000..688dbb9f --- /dev/null +++ b/test/random/main.c @@ -0,0 +1,43 @@ +#include +#include "test.h" + +// ============================================================================ +// Test cases for getrandom +// ============================================================================ + +int test_getrandom() { + unsigned long rand; + + ssize_t len = getrandom(&rand, sizeof(unsigned long), GRND_NONBLOCK); + if (len < 0 || len != sizeof(unsigned long)) { + THROW_ERROR("failed to call getrandom"); + } + printf("generate random value: %lu\n", rand); + + return 0; +} + +int test_getrandom_blocking() { + int rand; + + ssize_t len = getrandom(&rand, sizeof(int), 0); + if (len < 0 || len != sizeof(int)) { + THROW_ERROR("failed to call getrandom"); + } + printf("generate random value: %d\n", rand); + + return 0; +} + +// ============================================================================ +// Test suite +// ============================================================================ + +static test_case_t test_cases[] = { + TEST_CASE(test_getrandom), + TEST_CASE(test_getrandom_blocking), +}; + +int main() { + return test_suite_run(test_cases, ARRAY_SIZE(test_cases)); +}