diff --git a/Cargo.lock b/Cargo.lock index 732851fa..823bb2d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -302,6 +302,17 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "ghost" version = "0.1.7" @@ -564,6 +575,7 @@ dependencies = [ "controlled", "core2", "cpio-decoder", + "getrandom", "int-to-c-enum", "intrusive-collections", "jinux-block", @@ -650,9 +662,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.137" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "libflate" @@ -1130,6 +1142,12 @@ dependencies = [ "libc", ] +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "winnow" version = "0.3.3" diff --git a/services/libs/jinux-std/Cargo.toml b/services/libs/jinux-std/Cargo.toml index c871c4e1..bd8d7bfc 100644 --- a/services/libs/jinux-std/Cargo.toml +++ b/services/libs/jinux-std/Cargo.toml @@ -42,6 +42,7 @@ spin = "0.9.4" vte = "0.10" lru = "0.9.0" log = "0.4" +getrandom = { version = "0.2.10", default-features = false, features = ["rdrand"] } [dependencies.lazy_static] version = "1.0" diff --git a/services/libs/jinux-std/src/device/mod.rs b/services/libs/jinux-std/src/device/mod.rs index 97fc350c..1abbb746 100644 --- a/services/libs/jinux-std/src/device/mod.rs +++ b/services/libs/jinux-std/src/device/mod.rs @@ -1,9 +1,13 @@ mod null; +mod random; pub mod tty; +mod urandom; mod zero; use crate::fs::device::{add_node, Device, DeviceId, DeviceType}; use crate::prelude::*; +pub use random::Random; +pub use urandom::Urandom; /// Init the device node in fs, must be called after mounting rootfs. pub fn init() -> Result<()> { @@ -14,5 +18,9 @@ pub fn init() -> Result<()> { tty::init(); let tty = tty::get_n_tty().clone(); add_node(tty, "tty")?; + let random = Arc::new(random::Random); + add_node(random, "random")?; + let urandom = Arc::new(urandom::Urandom); + add_node(urandom, "urandom")?; Ok(()) } diff --git a/services/libs/jinux-std/src/device/random.rs b/services/libs/jinux-std/src/device/random.rs new file mode 100644 index 00000000..91a0567c --- /dev/null +++ b/services/libs/jinux-std/src/device/random.rs @@ -0,0 +1,36 @@ +use crate::fs::device::{Device, DeviceId, DeviceType}; +use crate::prelude::*; + +pub struct Random; + +impl Random { + pub fn getrandom(buf: &mut [u8]) -> Result { + getrandom::getrandom(buf)?; + Ok(buf.len()) + } +} + +impl Device for Random { + fn type_(&self) -> DeviceType { + DeviceType::CharDevice + } + + fn id(&self) -> DeviceId { + // The same value as Linux + DeviceId::new(1, 8) + } + + fn read(&self, buf: &mut [u8]) -> Result { + Self::getrandom(buf) + } + + fn write(&self, buf: &[u8]) -> Result { + Ok(buf.len()) + } +} + +impl From for Error { + fn from(value: getrandom::Error) -> Self { + Error::with_message(Errno::ENOSYS, "cannot generate random bytes") + } +} diff --git a/services/libs/jinux-std/src/device/urandom.rs b/services/libs/jinux-std/src/device/urandom.rs new file mode 100644 index 00000000..529b3c8d --- /dev/null +++ b/services/libs/jinux-std/src/device/urandom.rs @@ -0,0 +1,30 @@ +use crate::fs::device::{Device, DeviceId, DeviceType}; +use crate::prelude::*; + +pub struct Urandom; + +impl Urandom { + pub fn getrandom(buf: &mut [u8]) -> Result { + getrandom::getrandom(buf)?; + Ok(buf.len()) + } +} + +impl Device for Urandom { + fn type_(&self) -> DeviceType { + DeviceType::CharDevice + } + + fn id(&self) -> DeviceId { + // The same value as Linux + DeviceId::new(1, 9) + } + + fn read(&self, buf: &mut [u8]) -> Result { + Self::getrandom(buf) + } + + fn write(&self, buf: &[u8]) -> Result { + Ok(buf.len()) + } +} diff --git a/services/libs/jinux-std/src/syscall/getrandom.rs b/services/libs/jinux-std/src/syscall/getrandom.rs new file mode 100644 index 00000000..6c2f8d70 --- /dev/null +++ b/services/libs/jinux-std/src/syscall/getrandom.rs @@ -0,0 +1,36 @@ +use crate::device; +use crate::log_syscall_entry; +use crate::prelude::*; +use crate::syscall::SYS_GETRANDOM; +use crate::util::write_bytes_to_user; + +use super::SyscallReturn; + +pub fn sys_getrandom(buf: Vaddr, count: usize, flags: u32) -> Result { + log_syscall_entry!(SYS_GETRANDOM); + let flags = GetRandomFlags::from_bits_truncate(flags); + debug!( + "buf = 0x{:x}, count = 0x{:x}, flags = {:?}", + buf, count, flags + ); + // TODO: support nonblock flag. + // Currently our getrandom implementation relies on x86-specific `rdrand` instruction, so it will never block. + let mut buffer = vec![0u8; count]; + let read_len = if flags.contains(GetRandomFlags::GRND_RANDOM) { + device::Random::getrandom(&mut buffer)? + } else { + device::Urandom::getrandom(&mut buffer)? + }; + write_bytes_to_user(buf, &buffer)?; + Ok(SyscallReturn::Return(read_len as isize)) +} + +bitflags::bitflags! { + #[derive(Pod)] + #[repr(C)] + pub struct GetRandomFlags: u32 { + const GRND_NONBLOCK = 0x0001; + const GRND_RANDOM = 0x0002; + const GRND_INSECURE = 0x0004; + } +} diff --git a/services/libs/jinux-std/src/syscall/mod.rs b/services/libs/jinux-std/src/syscall/mod.rs index 5ad0fee6..b58de1fa 100644 --- a/services/libs/jinux-std/src/syscall/mod.rs +++ b/services/libs/jinux-std/src/syscall/mod.rs @@ -75,6 +75,7 @@ use self::accept::sys_accept; use self::bind::sys_bind; use self::connect::sys_connect; use self::getpeername::sys_getpeername; +use self::getrandom::sys_getrandom; use self::getsockname::sys_getsockname; use self::listen::sys_listen; use self::pread64::sys_pread64; @@ -114,6 +115,7 @@ mod getpeername; mod getpgrp; mod getpid; mod getppid; +mod getrandom; mod getsockname; mod gettid; mod gettimeofday; @@ -295,7 +297,8 @@ define_syscall_nums!( SYS_UTIMENSAT = 280, SYS_EPOLL_CREATE1 = 291, SYS_PIPE2 = 293, - SYS_PRLIMIT64 = 302 + SYS_PRLIMIT64 = 302, + SYS_GETRANDOM = 318 ); pub struct SyscallArgument { @@ -453,6 +456,7 @@ pub fn syscall_dispatch( SYS_EPOLL_CREATE1 => syscall_handler!(1, sys_epoll_create1, args), SYS_PIPE2 => syscall_handler!(2, sys_pipe2, args), SYS_PRLIMIT64 => syscall_handler!(4, sys_prlimit64, args), + SYS_GETRANDOM => syscall_handler!(3, sys_getrandom, args), _ => { error!("Unimplemented syscall number: {}", syscall_number); return_errno_with_message!(Errno::ENOSYS, "Syscall was unimplemented");