-
-
Notifications
You must be signed in to change notification settings - Fork 166
fix(vfs): 修复 pread64 系统调用的兼容性和错误处理 #1398
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
fix(vfs): 修复 pread64 系统调用的兼容性和错误处理 #1398
Conversation
- 验证 `offset` 参数:当偏移量为负数或发生溢出时返回 `EINVAL`。
- 验证用户缓冲区:使用 `new_checked` 确保内存已映射,从而正确返回 `EFAULT`。
- 检查文件类型:对不可定位的文件(如管道、Socket)返回 `ESPIPE`。
- 修复 `File::readable()` 中的权限检查:
- 对 `O_PATH` 文件描述符返回 `EBADF`。
- 对只写模式(Write-only)打开的文件返回 `EBADF` 而不是 `EPERM`。
- 修复了 gVisor `pread64` 测试集中的多个失败项,包括 `BadBuffer`、`CantReadSocketPair`、`WriteOnlyNotReadable`、`Pread64WithOpath`、`BadOffset` 和 `Overflow`。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This pull request enhances the pread64 system call implementation to fix compatibility issues with the gVisor test suite by adding comprehensive validation and error handling. The changes improve POSIX compliance by properly validating parameters and file descriptor states before performing read operations.
Key Changes
- Added offset validation to reject negative values and detect arithmetic overflow
- Switched from
UserBufferWriter::newtonew_checkedfor proper EFAULT handling on unmapped memory - Added file type checking to return ESPIPE for non-seekable file types (pipes and sockets)
- Fixed
File::readable()permission checks to properly handle O_PATH file descriptors and return EBADF (instead of EPERM) for write-only files using theaccmode()method
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| kernel/src/filesystem/vfs/syscall/sys_pread64.rs | Added parameter validation (offset bounds, overflow checks), buffer verification, and file type checking for non-seekable files |
| kernel/src/filesystem/vfs/file.rs | Improved readable() method to check O_PATH flag and use proper access mode extraction with correct EBADF error code for write-only files |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| // 检查是否是管道/Socket (ESPIPE) | ||
| let md = file.metadata()?; | ||
| if md.file_type == FileType::Pipe || md.file_type == FileType::Socket { |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incomplete file type check for non-seekable files: The check should also include FileType::CharDevice to be consistent with lseek() at file.rs:364, which returns ESPIPE for both Pipe and CharDevice. Character devices like terminals are non-seekable and should fail pread64 with ESPIPE.
Should be: if md.file_type == FileType::Pipe || md.file_type == FileType::Socket || md.file_type == FileType::CharDevice
| if md.file_type == FileType::Pipe || md.file_type == FileType::Socket { | |
| if md.file_type == FileType::Pipe || md.file_type == FileType::Socket || md.file_type == FileType::CharDevice { |
| // 检查offset + len是否溢出 | ||
| if offset.checked_add(len).is_none() || offset > i64::MAX as usize { |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incomplete overflow check: The validation should also check if offset + len exceeds i64::MAX, not just offset alone. If offset is valid but offset + len > i64::MAX, this should also return EINVAL.
Consider: if offset.checked_add(len).map_or(true, |sum| sum > i64::MAX as usize) || offset > i64::MAX as usize
Or split into clearer logic:
let end_pos = offset.checked_add(len).ok_or(SystemError::EINVAL)?;
if offset > i64::MAX as usize || end_pos > i64::MAX as usize {
return Err(SystemError::EINVAL);
}| // 检查offset + len是否溢出 | |
| if offset.checked_add(len).is_none() || offset > i64::MAX as usize { | |
| // 检查offset + len是否溢出,并且两者都不能超过i64::MAX | |
| let end_pos = offset.checked_add(len).ok_or(SystemError::EINVAL)?; | |
| if offset > i64::MAX as usize || end_pos > i64::MAX as usize { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
kernel/src/filesystem/vfs/file.rs:437
- Inconsistency with
readable(): thewriteable()method still returnsEPERMfor read-only files, whilereadable()now returnsEBADFfor write-only files. For consistency with POSIX standards and the pattern established inreadable(), this should also returnEBADFinstead ofEPERM. Additionally, line 436 should usemode.accmode() == FileMode::O_RDONLY.bits()instead of direct comparison, similar to line 418.
if mode == FileMode::O_RDONLY {
return Err(SystemError::EPERM);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
b691e17 to
334fa6f
Compare
334fa6f to
c8c4dd9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let mode = *self.mode.read(); | ||
|
|
||
| // 检查是否是O_PATH文件描述符 | ||
| if mode == FileMode::O_WRONLY || mode.contains(FileMode::O_PATH) { |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing space after || operator. The condition should be mode == FileMode::O_WRONLY || mode.contains(FileMode::O_PATH) for consistency with Rust formatting conventions.
| // 检查offset是否为负数 | ||
| if (offset as isize) < 0 { | ||
| return Err(SystemError::EINVAL); | ||
| } | ||
|
|
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check (offset as isize) < 0 is redundant with the check on line 47 offset > i64::MAX as usize. Both conditions check if offset >= 2^63 (on 64-bit systems). The first check interprets the value as signed and checks if the sign bit is set, while the second explicitly compares against i64::MAX. Consider removing the first check to avoid duplication and improve code clarity.
| // 检查offset是否为负数 | |
| if (offset as isize) < 0 { | |
| return Err(SystemError::EINVAL); | |
| } |
| @@ -0,0 +1,4 @@ | |||
| # SYS_MEMFD_CREATE未实现 | |||
| Pread64Test.Overflow | |||
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the PR description, the Overflow test case should now be fixed (listed among the fixed test cases). However, it's still present in the blocklist. If the test is indeed fixed, it should be removed from this blocklist. If it still needs to be blocked for a different reason (SYS_MEMFD_CREATE not implemented), the comment and PR description should be clarified to explain that only partial fixes were made.
| Pread64Test.Overflow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let mode = *self.mode.read(); | ||
|
|
||
| // 检查是否是O_PATH文件描述符 | ||
| if mode == FileMode::O_WRONLY || mode.contains(FileMode::O_PATH) { |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check mode == FileMode::O_WRONLY is incorrect because it only matches when the mode is exactly O_WRONLY (0o1) with no other flags set. A file opened with O_WRONLY | O_NONBLOCK (0o4001) would incorrectly pass this check as readable.
The correct check should use the access mode bits:
if mode.accmode() == FileMode::O_WRONLY.bits() || mode.contains(FileMode::O_PATH) {
return Err(SystemError::EBADF);
}This ensures we properly check only the access mode portion of the flags (lowest 2 bits), not the entire flag value.
| if mode == FileMode::O_WRONLY || mode.contains(FileMode::O_PATH) { | |
| if mode.accmode() == FileMode::O_WRONLY.bits() || mode.contains(FileMode::O_PATH) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
| } | ||
|
|
||
| let mut user_buffer_writer = | ||
| UserBufferWriter::new_checked(buf_vaddr, len, frame.is_from_user())?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
要求用户缓冲区已经映射应该是不对的。可能是pagefault延迟映射。应该是使用protected的那个,校验vma
fa5fdb7 to
94d0a91
Compare
8e65bb7 to
0dc99c0
Compare
…ser access modules - Updated SysPread64Handle to use new_checked for user buffer writing. - Enhanced user access validation by replacing direct checks with user_accessible_len in UserBufferReader and UserBufferWriter. Signed-off-by: longjin <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is being reviewed by Cursor Bugbot
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
offset参数:当偏移量为负数或发生溢出时返回EINVAL。new_checked确保内存已映射,从而正确返回EFAULT。ESPIPE。File::readable()中的权限检查:O_PATH文件描述符返回EBADF。EBADF而不是EPERM。pread64测试集中的多个失败项,包括BadBuffer、CantReadSocketPair、WriteOnlyNotReadable、Pread64WithOpath、BadOffset和Overflow。Note
Validate
pread64offset for overflow/negativity, reject non-seekable fds withESPIPE, switch tonew_checked/user_accessible_lenfor robust user buffer checks, and enable gVisorpread64tests (blocklistOverflow).pread64(kernel/src/filesystem/vfs/syscall/sys_pread64.rs)offsetandoffset + len(cap ati64::MAX, returnEINVALon overflow/negative).UserBufferWriter::new_checkedto returnEFAULTfor unmapped/insufficiently mapped buffers.Pipe,Socket,CharDevice) withESPIPEbefore read.kernel/src/syscall/user_access.rs)user_accessible_leninnew_checkedandconvert_with_offset_checkedfor readers/writers; returnEFAULTif accessible range < requested.pread64_test:Pread64Test.Overflow.pread64_testinuser/apps/tests/syscall/gvisor/whitelist.txt.Written by Cursor Bugbot for commit 667c09c. This will update automatically on new commits. Configure here.