fix(starry-kernel): reject private mmap faults past eof#1534
Conversation
There was a problem hiding this comment.
审查结论:APPROVE ✅
变更概述
本 PR 修复了 StarryOS MAP_PRIVATE 文件映射在 fault 到 EOF 之后页面时的行为:旧代码使用 u64::MAX 作为有效边界,导致 EOF 之后的区域被静默映射为零页;新代码使用真实文件长度 file.len() 作为边界,页起始 offset 已到 EOF 时返回 BadAddress,跨 EOF 时只读取文件内剩余字节。同时保留 ELF loader 传入 file_end = Some(...) 时的零填充语义(BSS/tail zero-fill)。
实现分析
cow_file_max_read_len:纯计算函数,根据file_end区分两种语义:file_end = Some(end):以传入的end为有效边界(ELF loader 路径)file_end = None(常规MAP_PRIVATE):以file_len为有效边界,file_read_offset >= file_len时返回BadAddress
cow_file_max_read:在cow_file_max_read_len基础上增加了file.len()?调用。仅在file_end.is_none()时才调用file.len(),避免对 ELF loader 路径产生副作用。- 错误处理:
alloc_new_at中cow_file_max_read失败时,正确调用self.deinit_frame(frame)释放已分配的帧后返回错误。alloc_file_run中由于cow_file_max_read在帧分配之前调用,?传播错误时无需清理。 - 代码设计清晰,函数职责单一,与现有
CowBackend的模式一致。
验证结果
- ✅
cargo fmt --check:通过(无输出) - ✅
cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings:通过 - ✅ CI 状态:
- Check formatting / run_host: success
- Run sync-lint / run_container: success
- Run spin-lint / run_container: success
- Test with std / run_host: success
- Test starry aarch64 qemu / run_container: success
- Test starry loongarch64 qemu / run_container: success
- Test starry self-hosted board orangepi-5-plus: success
- Test starry self-hosted board visionfive2: success
- 其他 Starry 无关的检查(axvisor/arceos/board):success 或 expected skipped
- 无 CI 失败
测试覆盖
新增 axtest 用例 private_mmap_rejects_fault_at_file_eof 覆盖三条路径:
- EOF 拒绝:
file_len=4096, file_end=None, offset=4096→BadAddress✅ - 跨 EOF 截断:
file_len=4096, file_end=None, offset=2048→ 可读 2048 字节 ✅ - Loader 零填充保留:
file_len=4096, file_end=Some(8192), offset=4096→ 可读 4096 字节 ✅
测试链路完整:cow.rs → mod.rs(#[cfg(axtest)] re-export)→ axtest_exports.rs → axtest_kernel.rs,符合项目 axtest 模式的测试发现规范。
重复/重叠 PR 分析
- 搜索
repo:rcore-os/tgoskits type:pr mmap private eof:仅返回本 PR - 搜索
repo:rcore-os/tgoskits type:pr cow file backend:仅返回不相关的 #1017 - 无重复或冲突的开放 PR。
历史审查
本 PR 无前置审查评论。
未解决问题
无。代码正确、测试充分、CI 全绿。
残余风险
无。
Powered by deepseek-v4-pro
9a1616e to
3c3c7ad
Compare
There was a problem hiding this comment.
审查结论:APPROVE ✅
变更概述
本 PR 修复了 StarryOS MAP_PRIVATE 文件映射在缺页 fault 到 EOF 之后页面时的行为问题:旧代码在 CowBackend::alloc_new_at 和 alloc_file_run 中使用 u64::MAX 作为有效文件边界(file_end.map_or(u64::MAX, ...)),导致 EOF 之后的区域被静默分配零页并映射,而不是返回错误。新代码使用真实文件长度 file.len() 作为边界,页起始 offset 已到 EOF 时返回 BadAddress,跨 EOF 时只读取文件内剩余字节。同时保留 ELF loader 传入 file_end = Some(...) 时的零填充语义,避免影响程序段 BSS/tail zero-fill。
实现分析
cow_file_max_read_len:纯计算函数,不涉及 I/O。根据file_end区分两种语义:file_end = Some(end):以传入的end为有效边界(ELF loader BSS 路径,保留零填充语语义)file_end = None(常规 MAP_PRIVATE):以file_len为有效边界,file_read_offset >= file_len时返回BadAddress
cow_file_max_read:在cow_file_max_read_len基础上增加了file.len()?调用(仅在file_end.is_none()时调用),将 I/O 错误向上传播。alloc_new_at:在cow_file_max_read失败时,正确调用self.deinit_frame(frame)释放已分配的帧后返回错误,避免了帧泄漏。alloc_file_run:cow_file_max_read在帧分配之前调用,使用?传播错误时无需清理帧资源。#[cfg(axtest)]测试函数private_mmap_eof_check_for_test:纯单元测试,验证三个语义路径而不依赖实际文件 I/O。- 代码设计清晰,函数职责单一,错误处理完备,与现有
CowBackend的模式一致。
验证结果
本地验证:
- ✅
cargo fmt --check:通过 - ✅
cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings:通过(Finished, 无 warnings)
CI 状态(run #8368, head 3c3c7ad):
- ✅ Check formatting / run_host: success
- ✅ Run sync-lint / run_container: success
- ✅ Run spin-lint / run_container: success
- ✅ Test starry aarch64 qemu / run_container: success
- ✅ Test starry riscv64 qemu / run_host: skipped(
run_hostvsrun_container互斥,合理) - ✅ Test starry loongarch64 qemu / run_host: skipped(同上)
- ✅ Test starry self-hosted board orangepi-5-plus: success
- ✅ Test starry self-hosted board visionfive2: success
- 其他无关检查(axvisor/arceos/board):success 或 expected skipped
- 整体 CI conclusion: success,无失败
测试覆盖
新增 axtest 用例 private_mmap_rejects_fault_at_file_eof,覆盖三条路径:
- EOF 拒绝:
file_len=4096, file_end=None, offset=4096→Err(BadAddress)✅ - 跨 EOF 截断:
file_len=4096, file_end=None, offset=2048→Ok(2048)✅ - Loader 零填充保留:
file_len=4096, file_end=Some(8192), offset=4096→Ok(4096)✅
测试链路完整:cow.rs(#[cfg(axtest)] pub(crate))→ mod.rs(#[cfg(axtest)] re-export)→ axtest_exports.rs → axtest_kernel.rs,符合项目 axtest 模式的测试发现规范。
重复/重叠 PR 分析
- 搜索
repo:rcore-os/tgoskits type:pr mmap private eof:仅返回本 PR #1534 - PR #1164(已合并)修复的是
FileBackend::populate(共享映射,MAP_SHARED)的 EOF 边界问题,与本次CowBackend(MAP_PRIVATE)的修复互补,不重叠。 - 无重复或冲突的开放 PR。
历史审查
本 PR 存在一条来自 mai-team-app[bot] 的前置 APPROVE 审查(commit 9a1616e),当时已通过格式、clippy 和 CI 验证。当前 head 3c3c7ad 为 rebase 后的新版本,冲突仅出现在 axtest_exports.rs 和 axtest_kernel.rs(保留 dev 上已有的 pipe/fcntl axtest 并追加本 PR 的 private mmap EOF axtest),核心逻辑文件 cow.rs 无变化。
未解决问题
无。代码正确、测试充分、CI 全绿、无 crates.io patch 依赖、无重复或冲突 PR。
Powered by deepseek-v4-pro
问题
对照 openkylin/x-kernel 已合并的 !433,本仓库普通文件
MAP_PRIVATE映射在 fault 到文件 EOF 之后的页面时仍会分配零页。这会把应当视为无效访问的 EOF 之后区域静默映射出来。修改
MAP_PRIVATE映射(file_end == None)使用真实文件长度作为有效边界:页起始 offset 已到 EOF 时返回BadAddress,跨 EOF 时只读取文件内剩余字节。file_end = Some(...)时的零填充语义,避免影响程序段 BSS/tail zero-fill。本次冲突处理
rcore-os/tgoskits:dev。axtest_exports.rs和axtest_kernel.rs,处理方式是保留 dev 上已有的 pipe/fcntl axtest,并追加本 PR 的 private mmap EOF axtest。验证
cargo xtask ktest qemu -p starry-kernel --test axtest_kernel,新增用例先失败,AXTEST_SUMMARY pass=4 fail=1。cargo xtask ktest qemu -p starry-kernel --test axtest_kernel,AXTEST_SUMMARY pass=5 fail=0,AXTEST_SUITE_OK。cargo xtask ktest qemu -p starry-kernel --test axtest_kernel,AXTEST_SUMMARY pass=8 fail=0,AXTEST_SUITE_OK。cargo xtask clippy --package starry-kernel,17/17 checks passed。