From 8686322afbc32d590abb1767aab7b0e55c4ca581 Mon Sep 17 00:00:00 2001 From: "Tate, Hongliang Tian" Date: Fri, 19 Jul 2019 12:30:15 +0000 Subject: [PATCH] Add /dev/zero, /dev/random, /dev/urandom, and /dev/arandom --- src/libos/src/fs/{null.rs => dev_null.rs} | 44 +++++------ src/libos/src/fs/dev_random.rs | 84 +++++++++++++++++++++ src/libos/src/fs/dev_zero.rs | 65 ++++++++++++++++ src/libos/src/fs/mod.rs | 16 +++- test/Makefile | 5 +- test/device/Makefile | 5 ++ test/device/main.c | 91 +++++++++++++++++++++++ 7 files changed, 283 insertions(+), 27 deletions(-) rename src/libos/src/fs/{null.rs => dev_null.rs} (65%) create mode 100644 src/libos/src/fs/dev_random.rs create mode 100644 src/libos/src/fs/dev_zero.rs create mode 100644 test/device/Makefile create mode 100644 test/device/main.c diff --git a/src/libos/src/fs/null.rs b/src/libos/src/fs/dev_null.rs similarity index 65% rename from src/libos/src/fs/null.rs rename to src/libos/src/fs/dev_null.rs index 18382360..6a3498d9 100644 --- a/src/libos/src/fs/null.rs +++ b/src/libos/src/fs/dev_null.rs @@ -1,35 +1,35 @@ use super::*; #[derive(Debug)] -pub struct NullFile; - -impl File for NullFile { - fn read(&self, _buf: &mut [u8]) -> Result { - unimplemented!() - } +pub struct DevNull; +impl File for DevNull { fn write(&self, _buf: &[u8]) -> Result { - Ok(0) - } - - fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { - unimplemented!() + Ok(_buf.len()) } fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { - unimplemented!() - } - - fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { - unimplemented!() + Ok(_buf.len()) } fn writev(&self, bufs: &[&[u8]]) -> Result { - unimplemented!() + Ok(bufs.iter().map(|buf| buf.len()).sum()) + } + + fn read(&self, _buf: &mut [u8]) -> Result { + errno!(EINVAL, "device not support reads") + } + + fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { + errno!(EINVAL, "device not support reads") + } + + fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { + errno!(EINVAL, "device not support reads") } fn seek(&self, pos: SeekFrom) -> Result { - unimplemented!() + errno!(EINVAL, "device not support seeks") } fn metadata(&self) -> Result { @@ -37,19 +37,19 @@ impl File for NullFile { } fn set_len(&self, len: u64) -> Result<(), Error> { - unimplemented!() + errno!(EINVAL, "device not support resizing") } fn sync_all(&self) -> Result<(), Error> { - unimplemented!() + Ok(()) } fn sync_data(&self) -> Result<(), Error> { - unimplemented!() + Ok(()) } fn read_entry(&self) -> Result { - unimplemented!() + errno!(ENOTDIR, "device is not a directory") } fn as_any(&self) -> &Any { diff --git a/src/libos/src/fs/dev_random.rs b/src/libos/src/fs/dev_random.rs new file mode 100644 index 00000000..d5de4ac2 --- /dev/null +++ b/src/libos/src/fs/dev_random.rs @@ -0,0 +1,84 @@ +use super::*; + +#[derive(Debug)] +pub struct DevRandom; + +extern "C" { + fn sgx_read_rand(rand_buf: *mut u8, buf_size: usize) -> sgx_status_t; +} + +impl File for DevRandom { + fn read(&self, _buf: &mut [u8]) -> Result { + let buf = _buf.as_mut_ptr(); + let size = _buf.len(); + let status = unsafe { sgx_read_rand(buf, size) }; + if status != sgx_status_t::SGX_SUCCESS { + return errno!(EAGAIN, "failed to get random number from sgx"); + } + Ok(size) + } + + fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { + self.read(_buf) + } + + fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { + let mut total_nbytes = 0; + for buf in bufs { + match self.read(buf) { + Ok(this_nbytes) => { + total_nbytes += this_nbytes; + } + Err(e) => { + if total_nbytes > 0 { + break + } + else { + return Err(e); + } + } + } + } + Ok(total_nbytes) + } + + fn write(&self, _buf: &[u8]) -> Result { + errno!(EINVAL, "device not support writes") + } + + fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { + errno!(EINVAL, "device not support writes") + } + + fn writev(&self, bufs: &[&[u8]]) -> Result { + errno!(EINVAL, "device not support writes") + } + + fn seek(&self, pos: SeekFrom) -> Result { + errno!(EINVAL, "device not support seeks") + } + + fn metadata(&self) -> Result { + unimplemented!() + } + + fn set_len(&self, len: u64) -> Result<(), Error> { + errno!(EINVAL, "device not support resizing") + } + + fn sync_all(&self) -> Result<(), Error> { + Ok(()) + } + + fn sync_data(&self) -> Result<(), Error> { + Ok(()) + } + + fn read_entry(&self) -> Result { + errno!(ENOTDIR, "device is not a directory") + } + + fn as_any(&self) -> &Any { + self + } +} diff --git a/src/libos/src/fs/dev_zero.rs b/src/libos/src/fs/dev_zero.rs new file mode 100644 index 00000000..db7bcc70 --- /dev/null +++ b/src/libos/src/fs/dev_zero.rs @@ -0,0 +1,65 @@ +use super::*; + +#[derive(Debug)] +pub struct DevZero; + +impl File for DevZero { + fn read(&self, _buf: &mut [u8]) -> Result { + for b in _buf.iter_mut() { + *b = 0; + } + Ok(_buf.len()) + } + + fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { + self.read(_buf) + } + + fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { + let mut total_nbytes = 0; + for buf in bufs { + total_nbytes += self.read(buf)?; + } + Ok(total_nbytes) + } + + fn write(&self, _buf: &[u8]) -> Result { + errno!(EINVAL, "device not support writes") + } + + fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { + errno!(EINVAL, "device not support writes") + } + + fn writev(&self, bufs: &[&[u8]]) -> Result { + errno!(EINVAL, "device not support writes") + } + + fn seek(&self, pos: SeekFrom) -> Result { + errno!(EINVAL, "device not support seeks") + } + + fn metadata(&self) -> Result { + unimplemented!() + } + + fn set_len(&self, len: u64) -> Result<(), Error> { + errno!(EINVAL, "device not support resizing") + } + + fn sync_all(&self) -> Result<(), Error> { + Ok(()) + } + + fn sync_data(&self) -> Result<(), Error> { + Ok(()) + } + + fn read_entry(&self) -> Result { + errno!(ENOTDIR, "device is not a directory") + } + + fn as_any(&self) -> &Any { + self + } +} diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index c42df998..e1ebe1e7 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -12,7 +12,9 @@ pub use self::file_table::{FileDesc, FileTable}; use self::inode_file::OpenOptions; pub use self::inode_file::{INodeExt, INodeFile, ROOT_INODE}; pub use self::io_multiplexing::*; -use self::null::NullFile; +use self::dev_null::DevNull; +use self::dev_zero::DevZero; +use self::dev_random::DevRandom; pub use self::pipe::Pipe; pub use self::socket_file::{AsSocket, SocketFile}; pub use self::unix_socket::{AsUnixSocket, UnixSocketFile}; @@ -25,7 +27,9 @@ mod file_table; mod hostfs; mod inode_file; mod io_multiplexing; -mod null; +mod dev_null; +mod dev_zero; +mod dev_random; mod pipe; mod sgx_impl; mod socket_file; @@ -410,7 +414,13 @@ impl Process { /// Open a file on the process. But DO NOT add it to file table. pub fn open_file(&self, path: &str, flags: OpenFlags, mode: u32) -> Result, Error> { if path == "/dev/null" { - return Ok(Box::new(NullFile)); + return Ok(Box::new(DevNull)); + } + if path == "/dev/zero" { + return Ok(Box::new(DevZero)); + } + if path == "/dev/random" || path == "/dev/urandom" || path == "/dev/arandom" { + return Ok(Box::new(DevRandom)); } let inode = if flags.contains(OpenFlags::CREATE) { let (dir_path, file_name) = split_path(&path); diff --git a/test/Makefile b/test/Makefile index c59f0aae..930bfda1 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,8 +4,9 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../) # Dependencies: need to be compiled but not to run by any Makefile target TEST_DEPS := dev_null # Tests: need to be compiled and run by test-% target -#TESTS := empty argv hello_world malloc mmap file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server server_epoll unix_socket cout hostfs cpuid rdtsc -TESTS := hello_world file readdir mkdir link hostfs +TESTS := empty argv hello_world malloc mmap file getpid spawn pipe time \ + truncate readdir mkdir link tls pthread uname rlimit client server \ + server_epoll unix_socket cout hostfs cpuid rdtsc device # Benchmarks: need to be compiled and run by bench-% target BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput diff --git a/test/device/Makefile b/test/device/Makefile new file mode 100644 index 00000000..9e1b6dec --- /dev/null +++ b/test/device/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/device/main.c b/test/device/main.c new file mode 100644 index 00000000..a8a49b03 --- /dev/null +++ b/test/device/main.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include "test.h" + +// ============================================================================ +// Test utilities +// ============================================================================ + +static int check_file_readable(const char* filename) { + int fd; + char buf[512] = {0}; + int len; + if ((fd = open(filename, O_RDONLY)) < 0) { + throw_error("failed to open the file"); + } + if ((len = read(fd, buf, sizeof(buf))) != sizeof(buf)) { + throw_error("failed to read the file"); + } + close(fd); + return 0; +} + +static int check_file_writable(const char* filename) { + int fd; + char buf[512] = {0}; + int len; + if ((fd = open(filename, O_WRONLY)) < 0) { + throw_error("failed to open the file"); + } + if ((len = write(fd, buf, sizeof(buf))) != sizeof(buf)) { + throw_error("failed to read the file"); + } + close(fd); + return 0; +} + +// ============================================================================ +// Test cases for /dev/random, /dev/urandom, /dev/ +// ============================================================================ + +int test_dev_null() { + if (check_file_writable("/dev/null")) { + throw_error("failed to write to /dev/null"); + } + return 0; +} + +int test_dev_zero() { + if (check_file_readable("/dev/zero")) { + throw_error("failed to read from /dev/null"); + } + return 0; +} + +int test_dev_random() { + if (check_file_readable("/dev/random")) { + throw_error("failed to read from /dev/random"); + } + return 0; +} + +int test_dev_urandom() { + if (check_file_readable("/dev/urandom")) { + throw_error("failed to read from /dev/urandom"); + } + return 0; +} + +int test_dev_arandom() { + if (check_file_readable("/dev/arandom")) { + throw_error("failed to read from /dev/arandom"); + } + return 0; +} + +// ============================================================================ +// Test suite +// ============================================================================ + +static test_case_t test_cases[] = { + TEST_CASE(test_dev_null), + TEST_CASE(test_dev_zero), + TEST_CASE(test_dev_random), + TEST_CASE(test_dev_urandom), + TEST_CASE(test_dev_arandom), +}; + +int main() { + return test_suite_run(test_cases, ARRAY_SIZE(test_cases)); +}