Skip to content

Commit 94c1f4c

Browse files
feat(vfs): 增加sys_preadv 增加对readable中对 O_PATH的检查 (#1404)
* 实现preadv系统调用, 增加对对 O_PATH 的可读检查 Signed-off-by: [email protected] <[email protected]>
1 parent cb62374 commit 94c1f4c

File tree

4 files changed

+92
-2
lines changed

4 files changed

+92
-2
lines changed

kernel/src/filesystem/vfs/file.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,10 @@ impl File {
407407
/// @brief 判断当前文件是否可读
408408
#[inline]
409409
pub fn readable(&self) -> Result<(), SystemError> {
410+
let mode = *self.mode.read();
410411
// 暂时认为只要不是write only, 就可读
411-
if *self.mode.read() == FileMode::O_WRONLY {
412-
return Err(SystemError::EPERM);
412+
if mode == FileMode::O_WRONLY || mode.contains(FileMode::O_PATH) {
413+
return Err(SystemError::EBADF);
413414
}
414415

415416
return Ok(());

kernel/src/filesystem/vfs/syscall/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ mod sys_mkdirat;
3131
pub mod sys_mknodat;
3232
mod sys_openat;
3333
mod sys_pread64;
34+
mod sys_preadv;
3435
mod sys_pselect6;
3536
mod sys_pwrite64;
3637
mod sys_pwritev;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use alloc::string::ToString;
2+
use alloc::vec::Vec;
3+
4+
use system_error::SystemError;
5+
6+
use crate::arch::syscall::nr::SYS_PREADV;
7+
use crate::filesystem::vfs::iov::{IoVec, IoVecs};
8+
use crate::process::ProcessManager;
9+
use crate::syscall::table::{FormattedSyscallParam, Syscall};
10+
11+
pub struct SysPreadVHandle;
12+
13+
impl Syscall for SysPreadVHandle {
14+
fn num_args(&self) -> usize {
15+
4
16+
}
17+
18+
fn handle(
19+
&self,
20+
args: &[usize],
21+
_frame: &mut crate::arch::interrupt::TrapFrame,
22+
) -> Result<usize, SystemError> {
23+
let fd = Self::fd(args);
24+
let iov = Self::iov(args);
25+
let iov_count = Self::iov_count(args);
26+
let offset = Self::offset(args);
27+
28+
// Construct IoVecs from user pointer.
29+
// For preadv, we are writing to user buffers, so we need to verify they are writable.
30+
// IoVecs::from_user internally uses UserBufferWriter::new which verifies the area.
31+
let iovecs = unsafe { IoVecs::from_user(iov, iov_count, true) }?;
32+
33+
do_preadv(fd, &iovecs, offset)
34+
}
35+
36+
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
37+
vec![
38+
FormattedSyscallParam::new("fd:", Self::fd(args).to_string()),
39+
FormattedSyscallParam::new("iov:", format!("{:#x}", Self::iov(args) as usize)),
40+
FormattedSyscallParam::new("iov_count:", Self::iov_count(args).to_string()),
41+
FormattedSyscallParam::new("offset:", Self::offset(args).to_string()),
42+
]
43+
}
44+
}
45+
46+
impl SysPreadVHandle {
47+
fn fd(args: &[usize]) -> i32 {
48+
args[0] as i32
49+
}
50+
51+
fn iov(args: &[usize]) -> *const IoVec {
52+
args[1] as *const IoVec
53+
}
54+
55+
fn iov_count(args: &[usize]) -> usize {
56+
args[2]
57+
}
58+
59+
fn offset(args: &[usize]) -> usize {
60+
args[3]
61+
}
62+
}
63+
64+
pub fn do_preadv(fd: i32, iovecs: &IoVecs, offset: usize) -> Result<usize, SystemError> {
65+
let binding = ProcessManager::current_pcb().fd_table();
66+
let fd_table_guard = binding.read();
67+
68+
let file = fd_table_guard
69+
.get_file_by_fd(fd)
70+
.ok_or(SystemError::EBADF)?;
71+
72+
drop(fd_table_guard);
73+
74+
// Create a kernel buffer to read data into.
75+
// TODO: Support scatter-gather I/O directly in FS to avoid this copy.
76+
let mut data = vec![0; iovecs.total_len()];
77+
78+
// Read from file at offset into kernel buffer.
79+
let read_len = file.pread(offset, data.len(), &mut data)?;
80+
81+
// Scatter the read data back to user buffers.
82+
iovecs.scatter(&data[..read_len]);
83+
84+
Ok(read_len)
85+
}
86+
87+
syscall_table_macros::declare_syscall!(SYS_PREADV, SysPreadVHandle);

user/apps/tests/syscall/gvisor/whitelist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ chdir_test
2525
fchdir_test
2626
rename_test
2727
getdents_test
28+
preadv_test
2829

2930
# 进程相关测试
3031
fork_test

0 commit comments

Comments
 (0)