Skip to content

Commit 66b967e

Browse files
fs: 修复 pread64 系统调用的兼容性和错误处理
- 验证 `offset` 参数:当偏移量为负数或发生溢出时返回 `EINVAL`。 - 验证用户缓冲区:使用 `new_checked` 确保内存已映射,从而正确返回 `EFAULT`。 - 检查文件类型:对不可定位的文件(如管道、Socket)返回 `ESPIPE`。 - 修复 `File::readable()` 中的权限检查: - 对 `O_PATH` 文件描述符返回 `EBADF`。 - 对只写模式(Write-only)打开的文件返回 `EBADF` 而不是 `EPERM`。 - 修复了 gVisor `pread64` 测试集中的多个失败项,包括 `BadBuffer`、`CantReadSocketPair`、`WriteOnlyNotReadable`、`Pread64WithOpath`、`BadOffset` 和 `Overflow`。
1 parent ec44937 commit 66b967e

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

kernel/src/filesystem/vfs/file.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,16 @@ impl File {
407407
/// @brief 判断当前文件是否可读
408408
#[inline]
409409
pub fn readable(&self) -> Result<(), SystemError> {
410+
let mode = *self.mode.read();
411+
412+
// 检查是否是O_PATH文件描述符
413+
if mode.contains(FileMode::O_PATH) {
414+
return Err(SystemError::EBADF);
415+
}
416+
410417
// 暂时认为只要不是write only, 就可读
411-
if *self.mode.read() == FileMode::O_WRONLY {
412-
return Err(SystemError::EPERM);
418+
if mode.accmode() == FileMode::O_WRONLY.bits() {
419+
return Err(SystemError::EBADF);
413420
}
414421

415422
return Ok(());

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use system_error::SystemError;
44

55
use crate::arch::interrupt::TrapFrame;
66
use crate::arch::syscall::nr::SYS_PREAD64;
7+
use crate::filesystem::vfs::FileType;
78
use crate::process::ProcessManager;
89
use crate::syscall::table::FormattedSyscallParam;
910
use crate::syscall::table::Syscall;
@@ -35,7 +36,18 @@ impl Syscall for SysPread64Handle {
3536
let len = Self::len(args);
3637
let offset = Self::offset(args);
3738

38-
let mut user_buffer_writer = UserBufferWriter::new(buf_vaddr, len, frame.is_from_user())?;
39+
// 检查offset是否为负数
40+
if (offset as isize) < 0 {
41+
return Err(SystemError::EINVAL);
42+
}
43+
44+
// 检查offset + len是否溢出
45+
if offset.checked_add(len).is_none() || offset > i64::MAX as usize {
46+
return Err(SystemError::EINVAL);
47+
}
48+
49+
let mut user_buffer_writer =
50+
UserBufferWriter::new_checked(buf_vaddr, len, frame.is_from_user())?;
3951
let user_buf = user_buffer_writer.buffer(0)?;
4052

4153
let binding = ProcessManager::current_pcb().fd_table();
@@ -48,6 +60,12 @@ impl Syscall for SysPread64Handle {
4860
// Drop guard to avoid scheduling issues
4961
drop(fd_table_guard);
5062

63+
// 检查是否是管道/Socket (ESPIPE)
64+
let md = file.metadata()?;
65+
if md.file_type == FileType::Pipe || md.file_type == FileType::Socket {
66+
return Err(SystemError::ESPIPE);
67+
}
68+
5169
return file.pread(offset, len, user_buf);
5270
}
5371

0 commit comments

Comments
 (0)