Skip to content

Conversation

@kaleidoscope416
Copy link
Contributor

@kaleidoscope416 kaleidoscope416 commented Nov 21, 2025

  • 验证 offset 参数:当偏移量为负数或发生溢出时返回 EINVAL
  • 验证用户缓冲区:使用 new_checked 确保内存已映射,从而正确返回 EFAULT
  • 检查文件类型:对不可定位的文件(如管道、Socket)返回 ESPIPE
  • 修复 File::readable() 中的权限检查:
    • O_PATH 文件描述符返回 EBADF
    • 对只写模式(Write-only)打开的文件返回 EBADF 而不是 EPERM
  • 修复了 gVisor pread64 测试集中的多个失败项,包括 BadBufferCantReadSocketPairWriteOnlyNotReadablePread64WithOpathBadOffsetOverflow

Note

Validate pread64 offset for overflow/negativity, reject non-seekable fds with ESPIPE, switch to new_checked/user_accessible_len for robust user buffer checks, and enable gVisor pread64 tests (blocklist Overflow).

  • Syscall: pread64 (kernel/src/filesystem/vfs/syscall/sys_pread64.rs)
    • Validate offset and offset + len (cap at i64::MAX, return EINVAL on overflow/negative).
    • Use UserBufferWriter::new_checked to return EFAULT for unmapped/insufficiently mapped buffers.
    • Reject non-seekable types (Pipe, Socket, CharDevice) with ESPIPE before read.
  • User access (kernel/src/syscall/user_access.rs)
    • Replace page-table boolean checks with user_accessible_len in new_checked and convert_with_offset_checked for readers/writers; return EFAULT if accessible range < requested.
  • Tests
    • Add gVisor blocklist for pread64_test: Pread64Test.Overflow.
    • Whitelist pread64_test in user/apps/tests/syscall/gvisor/whitelist.txt.

Written by Cursor Bugbot for commit 667c09c. This will update automatically on new commits. Configure here.

- 验证 `offset` 参数:当偏移量为负数或发生溢出时返回 `EINVAL`。
- 验证用户缓冲区:使用 `new_checked` 确保内存已映射,从而正确返回 `EFAULT`。
- 检查文件类型:对不可定位的文件(如管道、Socket)返回 `ESPIPE`。
- 修复 `File::readable()` 中的权限检查:
    - 对 `O_PATH` 文件描述符返回 `EBADF`。
    - 对只写模式(Write-only)打开的文件返回 `EBADF` 而不是 `EPERM`。
- 修复了 gVisor `pread64` 测试集中的多个失败项,包括 `BadBuffer`、`CantReadSocketPair`、`WriteOnlyNotReadable`、`Pread64WithOpath`、`BadOffset` 和 `Overflow`。
Copilot AI review requested due to automatic review settings November 21, 2025 09:49
@github-actions github-actions bot added the Bug fix A bug is fixed in this pull request label Nov 21, 2025
Copilot finished reviewing on behalf of kaleidoscope416 November 21, 2025 09:52
Copy link
Contributor

Copilot AI left a 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::new to new_checked for 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 the accmode() 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 {
Copy link

Copilot AI Nov 21, 2025

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

Suggested change
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 {

Copilot uses AI. Check for mistakes.
Comment on lines 44 to 45
// 检查offset + len是否溢出
if offset.checked_add(len).is_none() || offset > i64::MAX as usize {
Copy link

Copilot AI Nov 21, 2025

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);
}
Suggested change
// 检查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 {

Copilot uses AI. Check for mistakes.
@kaleidoscope416 kaleidoscope416 marked this pull request as draft November 21, 2025 16:34
Copilot finished reviewing on behalf of kaleidoscope416 November 22, 2025 12:13
Copy link
Contributor

Copilot AI left a 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(): the writeable() method still returns EPERM for read-only files, while readable() now returns EBADF for write-only files. For consistency with POSIX standards and the pattern established in readable(), this should also return EBADF instead of EPERM. Additionally, line 436 should use mode.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.

Copilot finished reviewing on behalf of kaleidoscope416 November 24, 2025 07:59
Copy link
Contributor

Copilot AI left a 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) {
Copy link

Copilot AI Nov 24, 2025

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.

Copilot uses AI. Check for mistakes.
Comment on lines 39 to 43
// 检查offset是否为负数
if (offset as isize) < 0 {
return Err(SystemError::EINVAL);
}

Copy link

Copilot AI Nov 24, 2025

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.

Suggested change
// 检查offset是否为负数
if (offset as isize) < 0 {
return Err(SystemError::EINVAL);
}

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,4 @@
# SYS_MEMFD_CREATE未实现
Pread64Test.Overflow
Copy link

Copilot AI Nov 24, 2025

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.

Suggested change
Pread64Test.Overflow

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a 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) {
Copy link

Copilot AI Nov 24, 2025

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.

Suggested change
if mode == FileMode::O_WRONLY || mode.contains(FileMode::O_PATH) {
if mode.accmode() == FileMode::O_WRONLY.bits() || mode.contains(FileMode::O_PATH) {

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a 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.

@kaleidoscope416 kaleidoscope416 marked this pull request as ready for review November 24, 2025 10:45
}

let mut user_buffer_writer =
UserBufferWriter::new_checked(buf_vaddr, len, frame.is_from_user())?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

要求用户缓冲区已经映射应该是不对的。可能是pagefault延迟映射。应该是使用protected的那个,校验vma

@github-actions github-actions bot added the test Unitest/User space test label Nov 26, 2025
…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]>
Copy link

@cursor cursor bot left a 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug fix A bug is fixed in this pull request test Unitest/User space test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants