Skip to content

fix(starry-mm): mprotect returns ENOMEM on unmapped holes within the range#918

Merged
ZR233 merged 2 commits into
rcore-os:devfrom
Lfan-ke:fix-loongarch-loader-hwcap
Jun 5, 2026
Merged

fix(starry-mm): mprotect returns ENOMEM on unmapped holes within the range#918
ZR233 merged 2 commits into
rcore-os:devfrom
Lfan-ke:fix-loongarch-loader-hwcap

Conversation

@Lfan-ke

@Lfan-ke Lfan-ke commented May 24, 2026

Copy link
Copy Markdown
Contributor

这个改动做了什么

sys_mprotect 之前只对范围首页做存在性检查(find_area(start_addr)),范围中间或末尾的未映射空洞会被静默跳过——形如 [已映射][空洞][已映射]mprotect(addr, len) 在 StarryOS 上会"成功"返回 0。

为什么要改

man 2 mprotect 规定:范围内任何缺失映射的页都使调用失败并返回 ENOMEM(保护位应用到空洞之前的前缀)。静默成功会让自己探测映射、依赖该 errno 的程序(GC、sanitizer、做 W^X 的 JIT 等)读到错误结果。

怎么改的

对整段 [addr, addr+len) 做连续覆盖检查:复用已有的 can_access_range,传入空访问掩码即得到纯覆盖判定(每个区域的 flags 都包含空集),遇到第一个空洞即返回 false。检查在修改任何映射之前完成,失败时不改动映射,原子地报 ENOMEM,不留半应用的保护位。

验证

  • x86_64 内核编译通过。
  • x86_64 完整 syscall 回归套件 STARRY_GROUPED_TESTS_PASSED,本改动未引入新失败。

@Lfan-ke

This comment was marked as duplicate.

@Lfan-ke Lfan-ke closed this May 24, 2026
@Lfan-ke Lfan-ke reopened this Jun 4, 2026
@Lfan-ke
Lfan-ke force-pushed the fix-loongarch-loader-hwcap branch from 8d0c53a to 813b154 Compare June 4, 2026 13:48
@Lfan-ke Lfan-ke changed the title fix(starry-kernel): populate AT_HWCAP so loongarch64 userspace detects LSX fix(starry-mm): mprotect returns ENOMEM on unmapped holes within the range Jun 4, 2026
@Lfan-ke

Lfan-ke commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

@codex review pr!

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: PR #918 — mprotect 空洞覆盖检查

改动分析

本次修改将 sys_mprotect 的存在性检查从 find_area(start_addr)(只检查首页)替换为 can_access_range(start_addr, length, MappingFlags::empty()),对整个 [addr, addr+len) 范围做连续覆盖判定,与 Linux mprotect 行为对齐。

正确性评估 ✅

  • can_access_range 遍历 areas 迭代器,逐区间推进 range.start,遇到空洞立即返回 false
  • MappingFlags::empty() 作为空集是所有 flags 的子集,因此 area.flags().contains(empty()) 恒为 true——该调用等价于纯覆盖检查。
  • 检查在 protect() 调用之前完成,失败时映射保持不变,满足原子性语义。
  • 注释清晰,正确解释了 empty() 的语义和 ENOMEM 的 POSIX/Linux 语义来源。

CI 状态

已完成的 job 全部 success:Detect changed paths、Check formatting、Run sync-lint、Test axvisor loongarch64 qemu (container)、Test axvisor x86_64 svm hosted (host)。其余多个 QEMU 测试 job 仍在运行中,尚未发现失败。

重复/重叠分析

本 PR 仅修改 mmap.rs 中的 sys_mprotect,与其他同期 open PR(#1119 netlink、#1118 ShmidDs、#1114 集合修复等)无交集。

测试覆盖

test-suit/starryos/normal/qemu-smp1/syscall/test-mmap-family 已有 mprotect ENOMEM 测试,但仅覆盖「首页完全未映射」场景。本次修复的「[mapped][hole][mapped] 空洞」场景目前无专门回归测试。建议后续补充一个 3 页映射 + 中间 munmap + mprotect 整段 → ENOMEM 的测试用例,以防止回归。

结论

修改逻辑正确、代码清晰、影响范围小,已通过已完成的 CI 检查。

APPROVE,建议后续跟进空洞场景的回归测试。

Powered by mimo-v2.5-pro

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

这轮先请求修改。实现逻辑本身是对的:can_access_range(start, len, MappingFlags::empty()) 会把 mprotect 的存在性检查从“只看起始页”提升为整个区间的连续覆盖检查;由于检查发生在 protect() 前,失败路径也不会半应用新的权限,和 Linux 对区间内任意未映射页返回 ENOMEM 的语义一致。

阻塞项是缺少能复现本 bug 的回归测试。现有 test-mmap-family 只覆盖“首页完全未映射”的 ENOMEM 场景,旧实现 find_area(start_addr) 也能通过,无法防止 [mapped][hole][mapped] 中间空洞误成功的回归。请补一个 3 页匿名映射、munmap 中间页、再对整段 mprotect 期望 ENOMEM 的 normal 回归用例;最好同时验证失败后左右两页仍保持原保护位/可写状态。

本地验证已完成:cargo fmt --check 通过,git diff --check origin/dev...HEAD 通过,cargo xtask clippy --package starry-kernel 通过 13/13。

CI 方面:format、sync-lint、Starry x86_64/loongarch64 QEMU container 均通过;Run clippy / run_host 的日志尾部是 workflow 取消清理,本地 targeted clippy 已通过;Test starry riscv64 qemu / run_host 仍是已知的 smoke 5s 超时,已补充到 #131: https://github.com/rcore-os/tgoskits/issues/131#issuecomment-4626181799。其他 sampled run_host 失败也是后续取消清理,没有看到可归因到本 PR 改动面的独立错误。

重复/重叠检查:base 上已有的 mprotect ENOMEM 测试只覆盖完全未映射首页;open PR #1122 同样涉及 mm hole 的 ENOMEM,但它处理的是 mlock,与本 PR 的 mprotect 语义修复是相邻但不同的 syscall,不是重复实现。当前没有未解决 review thread。

Comment thread os/StarryOS/kernel/src/syscall/mm/mmap.rs
@ZR233
ZR233 requested review from ZCShou and yfblock June 4, 2026 21:19
…nmapped hole

`sys_mprotect` 只对范围首页做了存在性检查 (`find_area(start_addr)`),范围中
间或末尾的未映射空洞会被静默跳过:形如 `[已映射][空洞][已映射]` 的 mprotect
在 starry 上"成功"返回 0,而 Linux 对范围内任何缺失映射的页都返回 ENOMEM。

改为对整段 `[addr, addr+len)` 做连续覆盖检查。复用已有的 `can_access_range`,
传入空的访问掩码即可得到纯覆盖判定(每个区域的 flags 都包含空集),遇到第一个
空洞即返回 false。检查在修改映射之前进行,失败时不改动任何映射(原子地报
ENOMEM,不留半应用的保护位),这正是依赖该 errno 的程序(GC/sanitizer/W^X
JIT 探测自身映射)所需要的行为。

Signed-off-by: Leo Cheng <chengkelfanke@gmail.com>
@Lfan-ke
Lfan-ke force-pushed the fix-loongarch-loader-hwcap branch from 813b154 to c7a523f Compare June 5, 2026 04:03

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: PR #918 — mprotect 空洞连续覆盖检查

改动分析

本 PR 共两个 commit:

  1. 修复 (c7a523fa): 将 sys_mprotect 的存在性检查从 find_area(start_addr)(只检查首页)替换为 can_access_range(start_addr, length, MappingFlags::empty()),对整个 [addr, addr+len) 做连续覆盖判定。与 Linux man 2 mprotect 行为对齐:范围内任何缺失映射的页都使调用失败并返回 ENOMEM
  2. 回归测试 (5c87d027): 新增测试用例,映射 3 页、munmap 中间页制造 [mapped][hole][mapped],再对整段 mprotect 期望 ENOMEM。覆盖了 ZR233 review 中要求的空洞场景回归。

实现逻辑验证

  • can_access_range(aspace/mod.rs:399)遍历 areas 迭代器,逐区间推进 range.start。当 area.start() > range.start(有空洞)时返回 false。
  • MappingFlags::empty() 是所有 flags 的子集,area.flags().contains(empty()) 恒为 true,因此该调用等价于纯连续覆盖检查。
  • 检查在 protect() 调用之前完成,失败时映射保持不变,满足原子性语义。
  • 注释清晰、正确解释了 empty() 语义和 ENOMEM 的 POSIX/Linux 来源。

测试覆盖

新测试正确覆盖了「起始页有映射但中段空洞」的回归场景:

  • mmap 3 页 → munmap 中间页 → mprotect 整段 → 期望 ENOMEM
  • 测试清理了剩余映射(第 1 和第 3 页的 munmap)

base 上已有的 mprotect 未映射区间 → ENOMEM 测试仅覆盖首页完全未映射场景;旧实现 find_area(start) 也能通过。本 PR 补全了该缺失覆盖。

本地验证

  • cargo fmt --check ✅ 通过
  • cargo clippy --package starry-kernel ✅ 通过 13/13
  • git diff --check origin/dev...HEAD ✅ 无格式问题

CI 状态

CI workflow run #5379(head SHA 5c87d027)刚触发,jobs 尚未开始运行,暂无结论。已通过本地 targeted validation。

重复/重叠分析

  • base 上已有 mprotect ENOMEM 测试但仅覆盖首页未映射场景。
  • open PR #1122mlock ENOMEM/holes)是同一作者对相邻 syscall 的修复,与本 PR 的 mprotect 修复是独立的不同 syscall 语义,不是重复实现。
  • 其他近期 open PR(#1150 IRQ、#1134 release、#1119 netlink、#1118 shmid 等)均不涉及 mmap/mprotect,无交集。
  • 当前无未解决 review thread。

结论

修改逻辑正确、测试覆盖到位、代码清晰、影响范围小。APPROVE

Powered by mimo-v2.5-pro

// We pre-check and leave the mapping untouched on failure, i.e. report
// ENOMEM atomically without any half-applied protection — the errno real
// programs test for.
if !aspace.can_access_range(start_addr, length, MappingFlags::empty()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can_access_range + MappingFlags::empty() 是正确的选择:纯连续覆盖检查,contains(empty()) 恒为 true,等价于仅检查区间是否有空洞。逻辑简洁且与 POSIX/Linux 语义一致。

CHECK_ERR(mprotect(hole, 3 * ps, PROT_READ),
ENOMEM, "mprotect 跨中段空洞 → ENOMEM");
munmap(hole, ps);
munmap(hole + 2 * ps, ps);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ 测试结构正确:3 页映射 → munmap 中间页造洞 → mprotect 整段期望 ENOMEM。覆盖了旧实现 find_area(start) 无法检测的 [mapped][hole][mapped] 场景。

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

这轮基于当前 head 5c87d0279020a8cc51f8d9e367b72eb98b99e332 复审后,内核修复方向和本地验证都没有问题,但我这里还是保留一个 blocker:回归测试目前只覆盖了 mprotect([mapped][hole][mapped]) -> ENOMEM,还没有直接证明失败路径上左右两段映射的保护位没有被半应用。

这次我本地重新跑了:

  • git diff --check origin/dev...HEAD
  • cargo fmt --check
  • cargo xtask clippy --package starry-kernel
  • cargo xtask starry test qemu --arch x86_64 -c syscall

其中 starry-kernel clippy 全部通过,syscall 分组 QEMU 也最终通过并把新的 test-mmap-family case 带进 guest 跑完了,所以实现本身和现有回归都已经有比较强的证据。

但上轮要求的是两件事:

  1. [mapped][hole][mapped] 整段 mprotect 返回 ENOMEM
  2. 失败后左右页的原保护位没有被改掉。

现在 PR 只补了第 1 点。考虑到这次实现是先做整段 coverage pre-check、再调用 protect,我同意实际代码大概率已经满足原子性要求;不过既然 PR body 明确把“失败时不改动映射、不给半应用保护位”作为语义的一部分,normal 回归里最好把这个 ABI 也直接锁住,例如在失败后继续验证左右页仍保持 PROT_READ|PROT_WRITE 的可写行为,或用一个更直接的只读/可写探针把两侧页权限检查出来。

重复/重叠检查:

  • origin/dev 里还没有这个 mprotect hole 覆盖修复;
  • 关键字搜索当前 open PR,没有发现同一语义的重复 PR。

把这条原子性断言补上后,这个 PR 我这里就比较容易放行。

…NOMEM atomically

Add a regression to test-mmap-family: map three pages, punch a hole in the
middle page, then mprotect the whole [mapped][hole][mapped] range. Linux returns
ENOMEM (man 2 mprotect: any unmapped page in the range), whereas the old code
only checked the start page's VMA via find_area(start) and silently succeeded
across the hole. This exercises the can_access_range contiguous-coverage check.

Also lock the atomicity: after the failed mprotect, both surviving pages must
stay writable. StarryOS validates the whole range before touching any protection
(can_access_range first), so a hole rejects atomically without half-applying;
the assertion catches any future move of the pre-check after per-page protect.
(Note: real Linux instead applies the prefix up to the hole then returns ENOMEM;
StarryOS deliberately picks the safer atomic semantics, documented in the test.)

> Hey, we're KunKun Groups, brought to you by heke1228. Quick heads-up: we're
> getting renamed to Smart Cluster soon (yeah, you might remember us as Sleepy
> Cluster back in the day).

Signed-off-by: KunKun Groups <haxxorbunny@qq.com>
@Lfan-ke
Lfan-ke force-pushed the fix-loongarch-loader-hwcap branch from 5c87d02 to ec7f7fa Compare June 5, 2026 10:13

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: PR #918 — mprotect 空洞连续覆盖检查 + 原子性锁

改动分析

本 PR 在当前 head ec7f7fadfda 上共两个 commit:

  1. 修复 (c7a523fa): 将 sys_mprotect 的存在性检查从 find_area(start_addr)(只检查首页)替换为 can_access_range(start_addr, length, MappingFlags::empty()),对整个 [addr, addr+len) 做连续覆盖判定。
  2. 回归测试 + 原子性断言 (ec7f7fadfda): 新增 [mapped][hole][mapped] 空洞场景回归,并通过 write_faults (SIGSEGV + sigsetjmp) 探针断言失败路径不会半应用保护位。

实现逻辑验证 ✅

  • can_access_rangeaspace/mod.rs:399)遍历 areas 迭代器,逐区间推进 range.start。当 area.start() > range.start(有空洞)时返回 false
  • MappingFlags::empty() 是所有 flags 的子集,area.flags().contains(empty()) 恒为 true,因此该调用等价于纯连续覆盖检查。
  • 检查在 protect() 调用之前完成,失败时映射保持不变,满足原子性语义。
  • 注释清晰、正确解释了 empty() 语义和 ENOMEM 的 POSIX/Linux 来源。

测试覆盖 ✅

新测试完整覆盖了 ZR233 此前两轮 review 的全部要求:

  1. 空洞 ENOMEM: 3 页映射 → munmap 中间页造洞 → mprotect 整段 → 期望 ENOMEM
  2. 原子性断言: 失败后通过 write_faults(hole)write_faults(hole + 2*ps) 验证左右两页仍保持 PROT_READ|PROT_WRITE 的可写状态 ✅

write_faults 使用 SIGSEGV + sigsetjmp 实现轻量写探针,能精确检测页面是否可写。测试注释也正确文档化了 StarryOS 原子语义与 Linux 前缀应用语义的区别。

本地验证

  • cargo fmt --check ✅ 通过
  • cargo xtask clippy --package starry-kernel ✅ 通过 13/13
  • git diff --check origin/dev...HEAD ✅ 无格式问题
  • cargo xtask starry test qemu --arch x86_64 -c syscall ✅ syscall 分组全部通过(含 test-mmap-family),耗时 173s

CI 状态

当前 head SHA ec7f7fadfda 的 CI workflow run #5412 状态为 pending(刚触发),尚无 job 完成。前序 head 5c87d027 的 format、sync-lint、Starry x86_64/loongarch64 QEMU container 均已通过;当前 head 仅新增了测试代码(无内核代码变更),本地 QEMU 已验证通过。

重复/重叠分析

  • base 上已有 mprotect ENOMEM 测试但仅覆盖首页未映射场景。
  • open PR #1122mlock ENOMEM/holes)是同一作者对相邻 syscall 的修复,与本 PR 的 mprotect 修复是独立的不同 syscall 语义,不是重复实现。
  • 其他近期 open PR(#1156 cgroup、#1155 IRQ、#1151 release 等)均不涉及 mmap/mprotect,无交集。
  • 当前无未解决 review thread。

结论

修改逻辑正确、测试覆盖到位(含原子性断言)、代码清晰、影响范围小。所有本地验证(含 QEMU)通过。

APPROVE

Powered by mimo-v2.5-pro

/* 在中间页打一个洞, 留下 [mapped][hole][mapped] */
CHECK_RET(munmap(hole + ps, ps), 0, "munmap 中间页造洞");
CHECK_ERR(mprotect(hole, 3 * ps, PROT_READ),
ENOMEM, "mprotect 跨中段空洞 → ENOMEM");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

write_faults + SIGSEGV/sigsetjmp 探针方案正确且轻量:在 mprotect 失败后直接写一字节到左右页,若页面仍可写则不触发 SIGSEGV(g_faulted == 0),否则通过 siglongjmp 安全恢复。这精确锁住了 ZR233 要求的原子性 ABI。

注释也正确文档化了 StarryOS 的原子语义(先检查再改,全有或全无)与 Linux 的差异(先改前缀再返回 ENOMEM),避免后续维护者误以为这是 bug。

// We pre-check and leave the mapping untouched on failure, i.e. report
// ENOMEM atomically without any half-applied protection — the errno real
// programs test for.
if !aspace.can_access_range(start_addr, length, MappingFlags::empty()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can_access_range(start_addr, length, MappingFlags::empty()) 逻辑正确:纯连续覆盖检查,contains(empty()) 恒为 true,遇到空洞即返回 false。检查在 protect() 前完成,失败路径映射不变。

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

审阅: PR #918 — mprotect 空洞连续覆盖检查 + 原子性断言

改动分析

本 PR 两个 commit:

  1. 内核修复 (c7a523fa): 将 sys_mprotect 的存在性检查从 find_area(start_addr)(仅检查首页)替换为 can_access_range(start_addr, length, MappingFlags::empty()),对整个 [addr, addr+len) 做连续覆盖判定,与 Linux man 2 mprotect 对区间内任意未映射页返回 ENOMEM 的语义一致。
  2. 回归测试 + 原子性断言 (ec7f7fadfda): 新增 [mapped][hole][mapped] 空洞 ENOMEM 回归,并通过 write_faults(SIGSEGV + sigsetjmp)探针断言失败路径左右两页仍保持 PROT_READ|PROT_WRITE 可写状态。

逻辑验证 ✅

  • can_access_rangeaspace/mod.rs:399)遍历 areas 迭代器,逐区间推进 range.start;当 area.start() > range.start(有空洞)或遍历结束后范围未覆盖完毕时返回 false
  • MappingFlags::empty() 是所有 flags 的子集,area.flags().contains(empty()) 恒为 true,等价于纯连续覆盖检查。
  • 检查在 protect() 调用之前完成,失败时映射保持不变,满足原子性语义。
  • 注释清晰,正确解释了 empty() 语义和 ENOMEM 的 POSIX/Linux 来源,以及 StarryOS 原子语义与 Linux 前缀应用语义的区别。

测试覆盖 ✅

  • write_faults 使用 SIGSEGV + sigsetjmp 实现轻量写探针,精确检测页面是否可写。
  • 测试完整覆盖了 ZR233 前两轮 review 的全部要求:
    1. 3 页映射 → munmap 中间页造洞 → mprotect 整段 → ENOMEM ✅
    2. 失败后通过 write_faults(hole)write_faults(hole + 2*ps) 验证左右两页仍保持原 RW 可写状态 ✅
  • base 上已有的 mprotect ENOMEM 测试仅覆盖首页完全未映射场景,旧实现 find_area(start) 也能通过。本 PR 补全了缺失覆盖。

前序 review 意见处理

  • ZR233 第一轮(813b1545)CHANGES_REQUESTED:要求补 [mapped][hole][mapped] ENOMEM 回归 → 已在 5c87d027 补充 ✅
  • ZR233 第二轮(5c87d027)CHANGES_REQUESTED:要求补原子性断言(失败后左右页保护位不变)→ 已在 ec7f7fadfda 通过 write_faults 探针锁住 ✅
  • 当前无未解决 review thread。

本地验证

  • cargo fmt --check ✅ 通过
  • cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings ✅ 通过
  • git diff --check ✅ 无格式问题

CI 状态

当前 head SHA ec7f7fadfda 的 CI workflow run #5412 状态为 pending(刚触发)。前序 commit 的 format、sync-lint、QEMU container 测试均已通过。本地 targeted clippy 已验证通过。无可归因到本 PR 改动面的 CI 失败。

重复/重叠分析

  • PR #285(已合并)引入了 mprotect ENOMEM 检查但使用 find_area(start) 只检查首页,本 PR 是其正确性的后续改进。
  • open PR #1122mlock ENOMEM/holes)同一作者对相邻 syscall 的修复,与本 PR 是独立的不同 syscall 语义,非重复实现。
  • 其他近期 open PR 均不涉及 mmap/mprotect,无交集。

结论

修改逻辑正确、测试覆盖到位(含原子性断言)、代码清晰、影响范围小。所有本地验证通过,前序 review 意见已全部解决。

APPROVE

Powered by mimo-v2.5-pro

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

复查当前 head ec7f7fadfda,前两轮阻塞项已经解决,我这里批准。

检查点:

  • sys_mprotectfind_area(start_addr) 改为 can_access_range(start_addr, length, MappingFlags::empty()),覆盖检查从“只看起始页”提升为整段连续覆盖;MappingFlags::empty() 在这里等价于纯 coverage check,遇到中间/尾部 hole 会返回 false
  • 检查发生在 protect() 之前,失败路径不会半应用新的保护位,符合 PR 中声明的 StarryOS 原子拒绝语义。
  • test-mmap-family 现在覆盖 3 页映射、中间页 munmap、整段 mprotect 返回 ENOMEM,并通过 write_faults 验证失败后左右页仍保持可写,补齐了此前要求的原子性断言。
  • 我前两轮留下的两个 review thread 已经标记为 resolved。

本地验证:

  • cargo fmt --check 通过。
  • git diff --check origin/dev...HEAD 通过。
  • cargo xtask clippy --package starry-kernel 通过 13/13。
  • cargo xtask starry test qemu --arch x86_64 --test-group normal -c syscall 的 xtask 汇总为 PASS;同时我临时收窄到 test-mmap-family 复核新增 mprotect 断言,mprotect 跨中段空洞 -> ENOMEM、失败后左页仍可写、失败后右页仍可写三项均 PASS。该二进制在本机仍暴露一个既有的 mmap PRIVATE|SHARED 断言失败,和本 PR 新增/修改的 mprotect 路径无关,建议后续单独跟踪。

CI:当前 head 的 GitHub checks 已通过。重叠检查:#1122 处理 mlock hole/ENOMEM,#1120 处理 mmap overflow,#1114 处理 madvise/基础兼容修复,均不是本 PR 的重复实现。

@ZR233
ZR233 merged commit a0d21ff into rcore-os:dev Jun 5, 2026
49 checks passed
@github-actions github-actions Bot mentioned this pull request Jun 5, 2026
silicalet added a commit to silicalet/tgoskits that referenced this pull request Jun 6, 2026
- mount.rs: keep Arc children model with clone_tree/clone_children_from/clone_shallow
- dir.rs: adopt upstream generation-based cache + mountpoint rename transfer
- inode.rs: merge upstream (name, is_dir) signature with pending-delete + truncate_inode

Upstream changes absorbed:
- fix(axfs-ng): zero partial last page when truncating (rcore-os#1124)
- fix(locking): narrow spinlock scope in VFS and Starry paths (rcore-os#1146)
- chore(axbuild): pin ostool runtime bin fix (rcore-os#1158)
- feat(starry-apps): runnable eBPF demos (rcore-os#1132)
- feat(starry): wire qperf app runtime into Starry perf (rcore-os#1095)
- fix(axcpu-aarch64): emulate EL0 MRS reads of ID_AA64* (rcore-os#1128)
- feat(rsext4): fine-grained locking for SMP (rcore-os#1057)
- feat(starry-kernel): implement TCP_INFO sockopt (rcore-os#1044)
- test(starryos): add fork parent-child identity test (rcore-os#995)
- fix(starry-mm): mprotect returns ENOMEM on unmapped holes (rcore-os#918)

Tests verified:
- test-nix-prereqs: PASS
- nix-smoke: PASS
- syscall (upstream): PASS
- test-dup2 (upstream): PASS
@github-actions github-actions Bot mentioned this pull request Jun 9, 2026
aptacc2421 pushed a commit to aptacc2421/tgoskits that referenced this pull request Jun 14, 2026
…range (rcore-os#918)

* fix(starry-mm): return ENOMEM from mprotect when the range spans an unmapped hole

`sys_mprotect` 只对范围首页做了存在性检查 (`find_area(start_addr)`),范围中
间或末尾的未映射空洞会被静默跳过:形如 `[已映射][空洞][已映射]` 的 mprotect
在 starry 上"成功"返回 0,而 Linux 对范围内任何缺失映射的页都返回 ENOMEM。

改为对整段 `[addr, addr+len)` 做连续覆盖检查。复用已有的 `can_access_range`,
传入空的访问掩码即可得到纯覆盖判定(每个区域的 flags 都包含空集),遇到第一个
空洞即返回 false。检查在修改映射之前进行,失败时不改动任何映射(原子地报
ENOMEM,不留半应用的保护位),这正是依赖该 errno 的程序(GC/sanitizer/W^X
JIT 探测自身映射)所需要的行为。

Signed-off-by: Leo Cheng <chengkelfanke@gmail.com>

* test(starry-mm): cover mprotect over [mapped][hole][mapped] returns ENOMEM atomically

Add a regression to test-mmap-family: map three pages, punch a hole in the
middle page, then mprotect the whole [mapped][hole][mapped] range. Linux returns
ENOMEM (man 2 mprotect: any unmapped page in the range), whereas the old code
only checked the start page's VMA via find_area(start) and silently succeeded
across the hole. This exercises the can_access_range contiguous-coverage check.

Also lock the atomicity: after the failed mprotect, both surviving pages must
stay writable. StarryOS validates the whole range before touching any protection
(can_access_range first), so a hole rejects atomically without half-applying;
the assertion catches any future move of the pre-check after per-page protect.
(Note: real Linux instead applies the prefix up to the hole then returns ENOMEM;
StarryOS deliberately picks the safer atomic semantics, documented in the test.)

> Hey, we're KunKun Groups, brought to you by heke1228. Quick heads-up: we're
> getting renamed to Smart Cluster soon (yeah, you might remember us as Sleepy
> Cluster back in the day).

Signed-off-by: KunKun Groups <haxxorbunny@qq.com>

---------

Signed-off-by: Leo Cheng <chengkelfanke@gmail.com>
Signed-off-by: KunKun Groups <haxxorbunny@qq.com>
Co-authored-by: KunKun Groups <haxxorbunny@qq.com>
luodeb pushed a commit that referenced this pull request Jun 30, 2026
…range (#918)

* fix(starry-mm): return ENOMEM from mprotect when the range spans an unmapped hole

`sys_mprotect` 只对范围首页做了存在性检查 (`find_area(start_addr)`),范围中
间或末尾的未映射空洞会被静默跳过:形如 `[已映射][空洞][已映射]` 的 mprotect
在 starry 上"成功"返回 0,而 Linux 对范围内任何缺失映射的页都返回 ENOMEM。

改为对整段 `[addr, addr+len)` 做连续覆盖检查。复用已有的 `can_access_range`,
传入空的访问掩码即可得到纯覆盖判定(每个区域的 flags 都包含空集),遇到第一个
空洞即返回 false。检查在修改映射之前进行,失败时不改动任何映射(原子地报
ENOMEM,不留半应用的保护位),这正是依赖该 errno 的程序(GC/sanitizer/W^X
JIT 探测自身映射)所需要的行为。

Signed-off-by: Leo Cheng <chengkelfanke@gmail.com>

* test(starry-mm): cover mprotect over [mapped][hole][mapped] returns ENOMEM atomically

Add a regression to test-mmap-family: map three pages, punch a hole in the
middle page, then mprotect the whole [mapped][hole][mapped] range. Linux returns
ENOMEM (man 2 mprotect: any unmapped page in the range), whereas the old code
only checked the start page's VMA via find_area(start) and silently succeeded
across the hole. This exercises the can_access_range contiguous-coverage check.

Also lock the atomicity: after the failed mprotect, both surviving pages must
stay writable. StarryOS validates the whole range before touching any protection
(can_access_range first), so a hole rejects atomically without half-applying;
the assertion catches any future move of the pre-check after per-page protect.
(Note: real Linux instead applies the prefix up to the hole then returns ENOMEM;
StarryOS deliberately picks the safer atomic semantics, documented in the test.)

> Hey, we're KunKun Groups, brought to you by heke1228. Quick heads-up: we're
> getting renamed to Smart Cluster soon (yeah, you might remember us as Sleepy
> Cluster back in the day).

Signed-off-by: KunKun Groups <haxxorbunny@qq.com>

---------

Signed-off-by: Leo Cheng <chengkelfanke@gmail.com>
Signed-off-by: KunKun Groups <haxxorbunny@qq.com>
Co-authored-by: KunKun Groups <haxxorbunny@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants