feat(vfs): 增加sys_preadv 增加对readable中对 O_PATH的检查 (#1404)

* 实现preadv系统调用, 增加对对 O_PATH 的可读检查

Signed-off-by: 2448956191@qq.com <2448956191@qq.com>
This commit is contained in:
kaleidoscope416 2025-11-26 00:45:16 +08:00 committed by GitHub
parent cb6237403a
commit 94c1f4cd20
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 92 additions and 2 deletions

View File

@ -407,9 +407,10 @@ impl File {
/// @brief 判断当前文件是否可读
#[inline]
pub fn readable(&self) -> Result<(), SystemError> {
let mode = *self.mode.read();
// 暂时认为只要不是write only, 就可读
if *self.mode.read() == FileMode::O_WRONLY {
return Err(SystemError::EPERM);
if mode == FileMode::O_WRONLY || mode.contains(FileMode::O_PATH) {
return Err(SystemError::EBADF);
}
return Ok(());

View File

@ -31,6 +31,7 @@ mod sys_mkdirat;
pub mod sys_mknodat;
mod sys_openat;
mod sys_pread64;
mod sys_preadv;
mod sys_pselect6;
mod sys_pwrite64;
mod sys_pwritev;

View File

@ -0,0 +1,87 @@
use alloc::string::ToString;
use alloc::vec::Vec;
use system_error::SystemError;
use crate::arch::syscall::nr::SYS_PREADV;
use crate::filesystem::vfs::iov::{IoVec, IoVecs};
use crate::process::ProcessManager;
use crate::syscall::table::{FormattedSyscallParam, Syscall};
pub struct SysPreadVHandle;
impl Syscall for SysPreadVHandle {
fn num_args(&self) -> usize {
4
}
fn handle(
&self,
args: &[usize],
_frame: &mut crate::arch::interrupt::TrapFrame,
) -> Result<usize, SystemError> {
let fd = Self::fd(args);
let iov = Self::iov(args);
let iov_count = Self::iov_count(args);
let offset = Self::offset(args);
// Construct IoVecs from user pointer.
// For preadv, we are writing to user buffers, so we need to verify they are writable.
// IoVecs::from_user internally uses UserBufferWriter::new which verifies the area.
let iovecs = unsafe { IoVecs::from_user(iov, iov_count, true) }?;
do_preadv(fd, &iovecs, offset)
}
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
vec![
FormattedSyscallParam::new("fd:", Self::fd(args).to_string()),
FormattedSyscallParam::new("iov:", format!("{:#x}", Self::iov(args) as usize)),
FormattedSyscallParam::new("iov_count:", Self::iov_count(args).to_string()),
FormattedSyscallParam::new("offset:", Self::offset(args).to_string()),
]
}
}
impl SysPreadVHandle {
fn fd(args: &[usize]) -> i32 {
args[0] as i32
}
fn iov(args: &[usize]) -> *const IoVec {
args[1] as *const IoVec
}
fn iov_count(args: &[usize]) -> usize {
args[2]
}
fn offset(args: &[usize]) -> usize {
args[3]
}
}
pub fn do_preadv(fd: i32, iovecs: &IoVecs, offset: usize) -> Result<usize, SystemError> {
let binding = ProcessManager::current_pcb().fd_table();
let fd_table_guard = binding.read();
let file = fd_table_guard
.get_file_by_fd(fd)
.ok_or(SystemError::EBADF)?;
drop(fd_table_guard);
// Create a kernel buffer to read data into.
// TODO: Support scatter-gather I/O directly in FS to avoid this copy.
let mut data = vec![0; iovecs.total_len()];
// Read from file at offset into kernel buffer.
let read_len = file.pread(offset, data.len(), &mut data)?;
// Scatter the read data back to user buffers.
iovecs.scatter(&data[..read_len]);
Ok(read_len)
}
syscall_table_macros::declare_syscall!(SYS_PREADV, SysPreadVHandle);

View File

@ -25,6 +25,7 @@ chdir_test
fchdir_test
rename_test
getdents_test
preadv_test
# 进程相关测试
fork_test