diff --git a/kernel/src/device/full.rs b/kernel/src/device/full.rs index 76884f7a8..a29c617d9 100644 --- a/kernel/src/device/full.rs +++ b/kernel/src/device/full.rs @@ -18,7 +18,7 @@ impl Device for Full { } fn id(&self) -> DeviceId { - // Same value with Linux + // The same value as Linux DeviceId::new(1, 7) } diff --git a/kernel/src/device/mod.rs b/kernel/src/device/mod.rs index 35b3f5c4c..25f690fd4 100644 --- a/kernel/src/device/mod.rs +++ b/kernel/src/device/mod.rs @@ -20,7 +20,7 @@ pub use urandom::Urandom; use crate::{ fs::{ - device::{add_node, Device, DeviceId, DeviceType}, + device::{add_node, Device, DeviceId}, fs_resolver::FsPath, ramfs::RamFs, }, diff --git a/kernel/src/device/null.rs b/kernel/src/device/null.rs index b488ca61d..8ae14bd0e 100644 --- a/kernel/src/device/null.rs +++ b/kernel/src/device/null.rs @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MPL-2.0 -#![expect(unused_variables)] - -use super::*; use crate::{ events::IoEvents, - fs::inode_handle::FileIo, + fs::{ + device::{Device, DeviceId, DeviceType}, + inode_handle::FileIo, + }, prelude::*, process::signal::{PollHandle, Pollable}, }; @@ -18,7 +18,7 @@ impl Device for Null { } fn id(&self) -> DeviceId { - // Same value with Linux + // The same value as Linux DeviceId::new(1, 3) } @@ -28,7 +28,7 @@ impl Device for Null { } impl Pollable for Null { - fn poll(&self, mask: IoEvents, poller: Option<&mut PollHandle>) -> IoEvents { + fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents { let events = IoEvents::IN | IoEvents::OUT; events & mask } @@ -40,6 +40,8 @@ impl FileIo for Null { } fn write(&self, reader: &mut VmReader) -> Result { - Ok(reader.remain()) + let len = reader.remain(); + reader.skip(len); + Ok(len) } } diff --git a/kernel/src/device/random.rs b/kernel/src/device/random.rs index 93f659f3e..92d35eb09 100644 --- a/kernel/src/device/random.rs +++ b/kernel/src/device/random.rs @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -#![expect(unused_variables)] - +use super::Urandom; use crate::{ events::IoEvents, fs::{ @@ -10,15 +9,14 @@ use crate::{ }, prelude::*, process::signal::{PollHandle, Pollable}, - util::random::getrandom, }; pub struct Random; impl Random { - pub fn getrandom(buf: &mut [u8]) -> Result { - getrandom(buf); - Ok(buf.len()) + pub fn getrandom(writer: &mut VmWriter) -> Result { + // TODO: Support true randomness by collecting environment noise. + Urandom::getrandom(writer) } } @@ -38,7 +36,7 @@ impl Device for Random { } impl Pollable for Random { - fn poll(&self, mask: IoEvents, poller: Option<&mut PollHandle>) -> IoEvents { + fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents { let events = IoEvents::IN | IoEvents::OUT; events & mask } @@ -46,13 +44,12 @@ impl Pollable for Random { impl FileIo for Random { fn read(&self, writer: &mut VmWriter) -> Result { - let mut buf = vec![0; writer.avail()]; - let size = Self::getrandom(buf.as_mut_slice()); - writer.write_fallible(&mut buf.as_slice().into())?; - size + Self::getrandom(writer) } fn write(&self, reader: &mut VmReader) -> Result { - Ok(reader.remain()) + let len = reader.remain(); + reader.skip(len); + Ok(len) } } diff --git a/kernel/src/device/tdxguest/mod.rs b/kernel/src/device/tdxguest/mod.rs index 8f4e0d98b..d5d3ae296 100644 --- a/kernel/src/device/tdxguest/mod.rs +++ b/kernel/src/device/tdxguest/mod.rs @@ -3,11 +3,14 @@ use ostd::mm::{DmaCoherent, FrameAllocOptions, HasPaddr, VmIo}; use tdx_guest::tdcall::{get_report, TdCallError}; -use super::*; use crate::{ - error::Error, events::IoEvents, - fs::{inode_handle::FileIo, utils::IoctlCmd}, + fs::{ + device::{Device, DeviceId, DeviceType}, + inode_handle::FileIo, + utils::IoctlCmd, + }, + prelude::*, process::signal::{PollHandle, Pollable}, }; diff --git a/kernel/src/device/urandom.rs b/kernel/src/device/urandom.rs index 92a5deb06..79d4560f2 100644 --- a/kernel/src/device/urandom.rs +++ b/kernel/src/device/urandom.rs @@ -1,7 +1,5 @@ // SPDX-License-Identifier: MPL-2.0 -#![expect(unused_variables)] - use crate::{ events::IoEvents, fs::{ @@ -16,9 +14,26 @@ use crate::{ pub struct Urandom; impl Urandom { - pub fn getrandom(buf: &mut [u8]) -> Result { - getrandom(buf); - Ok(buf.len()) + pub fn getrandom(writer: &mut VmWriter) -> Result { + const IO_CAPABILITY: usize = 4096; + + if !writer.has_avail() { + return Ok(0); + } + + let mut buffer = vec![0; writer.avail().min(IO_CAPABILITY)]; + let mut written_bytes = 0; + + while writer.has_avail() { + getrandom(&mut buffer[..writer.avail().min(IO_CAPABILITY)]); + match writer.write_fallible(&mut VmReader::from(buffer.as_slice())) { + Ok(len) => written_bytes += len, + Err((err, 0)) if written_bytes == 0 => return Err(err.into()), + Err((_, len)) => return Ok(written_bytes + len), + } + } + + Ok(written_bytes) } } @@ -38,7 +53,7 @@ impl Device for Urandom { } impl Pollable for Urandom { - fn poll(&self, mask: IoEvents, poller: Option<&mut PollHandle>) -> IoEvents { + fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents { let events = IoEvents::IN | IoEvents::OUT; events & mask } @@ -46,13 +61,12 @@ impl Pollable for Urandom { impl FileIo for Urandom { fn read(&self, writer: &mut VmWriter) -> Result { - let mut buf = vec![0; writer.avail()]; - let size = Self::getrandom(buf.as_mut_slice()); - writer.write_fallible(&mut buf.as_slice().into())?; - size + Self::getrandom(writer) } fn write(&self, reader: &mut VmReader) -> Result { - Ok(reader.remain()) + let len = reader.remain(); + reader.skip(len); + Ok(len) } } diff --git a/kernel/src/device/zero.rs b/kernel/src/device/zero.rs index 348590eab..c687805ee 100644 --- a/kernel/src/device/zero.rs +++ b/kernel/src/device/zero.rs @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MPL-2.0 -#![expect(unused_variables)] - -use super::*; use crate::{ events::IoEvents, - fs::inode_handle::FileIo, + fs::{ + device::{Device, DeviceId, DeviceType}, + inode_handle::FileIo, + }, prelude::*, process::signal::{PollHandle, Pollable}, }; @@ -18,7 +18,7 @@ impl Device for Zero { } fn id(&self) -> DeviceId { - // Same value with Linux + // The same value as Linux DeviceId::new(1, 5) } @@ -28,7 +28,7 @@ impl Device for Zero { } impl Pollable for Zero { - fn poll(&self, mask: IoEvents, poller: Option<&mut PollHandle>) -> IoEvents { + fn poll(&self, mask: IoEvents, _poller: Option<&mut PollHandle>) -> IoEvents { let events = IoEvents::IN | IoEvents::OUT; events & mask } diff --git a/kernel/src/syscall/getrandom.rs b/kernel/src/syscall/getrandom.rs index 4d7393898..588191adb 100644 --- a/kernel/src/syscall/getrandom.rs +++ b/kernel/src/syscall/getrandom.rs @@ -4,28 +4,39 @@ use super::SyscallReturn; use crate::{device, prelude::*}; pub fn sys_getrandom(buf: Vaddr, count: usize, flags: u32, ctx: &Context) -> Result { - let flags = GetRandomFlags::from_bits_truncate(flags); + let flags = GetRandomFlags::from_bits(flags) + .ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid 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]; + + if flags.contains(GetRandomFlags::GRND_INSECURE | GetRandomFlags::GRND_RANDOM) { + return_errno_with_message!( + Errno::EINVAL, + "requesting insecure and blocking randomness makes no sense" + ); + } + + // Currently we don't really generate true randomness by collecting environment noise, so we + // will never block. + // TODO: Support `GRND_NONBLOCK` and `GRND_INSECURE`. + + let user_space = ctx.user_space(); + let mut writer = user_space.writer(buf, count)?; let read_len = if flags.contains(GetRandomFlags::GRND_RANDOM) { - device::Random::getrandom(&mut buffer)? + device::Random::getrandom(&mut writer)? } else { - device::Urandom::getrandom(&mut buffer)? + device::Urandom::getrandom(&mut writer)? }; - ctx.user_space() - .write_bytes(buf, &mut VmReader::from(buffer.as_slice()))?; Ok(SyscallReturn::Return(read_len as isize)) } bitflags::bitflags! { - #[derive(Pod)] - #[repr(C)] - pub struct GetRandomFlags: u32 { + /// Flags for `getrandom`. + /// + /// Reference: . + struct GetRandomFlags: u32 { const GRND_NONBLOCK = 0x0001; const GRND_RANDOM = 0x0002; const GRND_INSECURE = 0x0004; diff --git a/test/src/apps/devfs/full.c b/test/src/apps/devfs/full.c index 800374833..d56274135 100644 --- a/test/src/apps/devfs/full.c +++ b/test/src/apps/devfs/full.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: MPL-2.0 -#include -#include #include #include #include @@ -64,4 +62,4 @@ FN_SETUP(close) { CHECK(close(fd)); } -END_SETUP() \ No newline at end of file +END_SETUP() diff --git a/test/src/apps/devfs/random.c b/test/src/apps/devfs/random.c new file mode 100644 index 000000000..4aba6f338 --- /dev/null +++ b/test/src/apps/devfs/random.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MPL-2.0 + +#include +#include +#include +#include "../test.h" + +#define PAGE_SIZE 4096 + +FN_TEST(short_rw) +{ + int fd; + char *buf; + + fd = TEST_SUCC(open("/dev/random", O_RDONLY)); + + buf = TEST_SUCC(mmap(NULL, PAGE_SIZE * 3, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); + TEST_SUCC(munmap(buf + PAGE_SIZE * 2, PAGE_SIZE)); + + // Invalid address + TEST_ERRNO(read(fd, buf + PAGE_SIZE * 2, PAGE_SIZE), EFAULT); + TEST_RES(read(fd, buf + PAGE_SIZE * 2, 0), _ret == 0); + + // Valid address, insufficient space + TEST_RES(read(fd, buf + PAGE_SIZE * 2 - 1, PAGE_SIZE), _ret == 1); + TEST_RES(read(fd, buf + PAGE_SIZE * 2 - (PAGE_SIZE - 1), PAGE_SIZE + 2), + _ret == (PAGE_SIZE - 1)); + TEST_RES(read(fd, buf + PAGE_SIZE * 2 - PAGE_SIZE, PAGE_SIZE + 2), + _ret == PAGE_SIZE); + TEST_RES(read(fd, buf + PAGE_SIZE * 2 - (PAGE_SIZE + 1), PAGE_SIZE + 2), + _ret == (PAGE_SIZE + 1)); + + // Valid address, sufficient space + TEST_RES(read(fd, buf + PAGE_SIZE * 2 - 1, 1), _ret == 1); + TEST_RES(read(fd, buf + PAGE_SIZE * 2 - (PAGE_SIZE - 1), PAGE_SIZE - 2), + _ret == (PAGE_SIZE - 2)); + TEST_RES(read(fd, buf + PAGE_SIZE * 2 - PAGE_SIZE, PAGE_SIZE - 1), + _ret == (PAGE_SIZE - 1)); + TEST_RES(read(fd, buf + PAGE_SIZE * 2 - (PAGE_SIZE + 1), PAGE_SIZE), + _ret == PAGE_SIZE); + + TEST_SUCC(munmap(buf, PAGE_SIZE * 2)); + TEST_SUCC(close(fd)); +} +END_TEST() diff --git a/test/src/apps/scripts/fs.sh b/test/src/apps/scripts/fs.sh index 6861605b2..5ca39262c 100755 --- a/test/src/apps/scripts/fs.sh +++ b/test/src/apps/scripts/fs.sh @@ -67,3 +67,4 @@ epoll/epoll_err epoll/poll_err file_io/iovec_err devfs/full +devfs/random diff --git a/test/src/syscall/ltp/testcases/all.txt b/test/src/syscall/ltp/testcases/all.txt index b80671631..857d5431e 100644 --- a/test/src/syscall/ltp/testcases/all.txt +++ b/test/src/syscall/ltp/testcases/all.txt @@ -513,7 +513,7 @@ getrandom01 getrandom02 getrandom03 getrandom04 -# getrandom05 +getrandom05 getresgid01 # getresgid01_16