fix(starry-kernel): pidfd open/getfd/send_signal Linux conformance - #707
Conversation
There was a problem hiding this comment.
📋 Review Summary
整体评价:Approve ✅
这是一个高质量的 Linux 一致性修复 PR,修改了 pidfd_open、pidfd_getfd、pidfd_send_signal 三个系统调用的实现,并配套新增了系统化的 QEMU 一致性测试。代码结构清晰,测试覆盖全面,符合 Linux 内核语义。
🔧 修改内容详解
1. 内核 PidFd 结构体扩展(os/StarryOS/kernel/src/file/pidfd.rs)
修改内容:
- 新增
tid: Option<Pid>字段,记录线程级 pidfd 对应的 tid new_thread()签名变更为接受tid参数- 新增
is_thread()和tid()访问器 process_data()增加get_process_data(pid)二次验证
动机: 原实现中,线程级 pidfd 不保存 tid,导致 pidfd_send_signal 无法区分 Thread/ThreadGroup 目标。reap 后 ProcessData 的 Weak 仍可能短暂 upgrade() 成功(pid 已从表删除但 Arc 未完全释放),导致 pidfd 操作返回 EBADF 而非 ESRCH。
影响: 所有使用 PidFd 的路径(pidfd_open、clone、pidfd_getfd、pidfd_send_signal)都会受益于更准确的 reap 检测,与 Linux 的 ESRCH 行为对齐。
2. pidfd_open 改进(os/StarryOS/kernel/src/syscall/fs/pidfd.rs)
修改内容:
pid <= 0返回EINVAL(Linux 要求)- 无
PIDFD_THREADflag 时验证 pid 必须是 thread-group leader,否则返回NotFound
动机: Linux pidfd_open(2) 规定 pid <= 0 时返回 EINVAL,且不带 PIDFD_THREAD 只能打开线程组 leader。
影响: 使用 pidfd_open(0, 0) 的用户态程序现在会正确收到 EINVAL 而非尝试打开当前进程。
3. pidfd_getfd 改进
修改内容:
flags != 0返回EINVAL- 当前进程查找目标 fd 时使用实时
FD_TABLE(通过Arc::ptr_eq判断),而非 scope 快照
动机: proc_data.scope 仅在 clone/dup 路径刷新,pipe() 等系统调用只更新 ActiveScope,导致对自身 fd 使用 scope 快照可能读到过期数据。
影响: 对自身进程执行 pidfd_getfd 时不再因 scope 快照滞后而误报 EBADF。
4. pidfd_send_signal 完整重写
修改内容:
- 新增
PidFdSignalFlags(THREAD=1, THREAD_GROUP=2, PROCESS_GROUP=4) - 新增
PidFdSignalScope枚举 - 非零 flags 需要
from_bits合法且至多 1 个 scope flag - 根据 flags + pidfd 类型自动推断 scope
- 完整的
siginfo校验:signo 匹配、code 权限检查、用户态填写 siginfo 的权限检查 - 按 scope 分发到
send_signal_to_thread/send_signal_to_process/send_signal_to_process_group
动机: 原实现仅支持 flags == 0 且始终投递到进程级别,无法区分线程/进程组信号,也不支持自定义 siginfo。
影响: 用户态现在可以通过 pidfd_send_signal 向特定线程发信号、向进程组发信号,行为与 Linux 一致。
5. 辅助修改
check_kill_permission可见性改为pub(crate)—— 必要的封装调整clone.rs中PidFd::new_thread(&thr, tid)传入 tid —— 适配新签名
6. 测试用例(17 个新文件)
| 测试 | 文件数 | 覆盖要点 |
|---|---|---|
test-pidfd-open |
3 | 非法 pid、CLOEXEC、线程 TID、zombie/reap、bad flags |
test-pidfd-getfd |
3 | 坏 pidfd、reap→ESRCH、CLOEXEC 不污染、跨进程 dup |
test-pidfd-send-signal |
3 | 坏 pidfd、reap、非法 signo/EFAULT、flags 组合、线程定向发送 |
| 配置文件 | 4 | 四架构 TOML 均已更新 |
评价: 测试框架简洁实用,每个测试独立编译运行,错误定位精确。三个测试文件的 test_framework.h 内容完全相同,存在 3 份拷贝。建议未来考虑提取为公共头文件,但不影响本次 PR 合入。
🔍 代码审查细节
正面评价
- reap 检测逻辑精巧:在
process_data()中通过get_process_data(pid)确认进程仍在表中,一个修改同时修复了pidfd_getfd和pidfd_send_signal两条路径 Arc::ptr_eq优化:对当前进程走 live FD_TABLE,避免 scope 快照滞后问题- 信号分发正确:Thread scope 使用
SI_TKILL、其他使用SI_USER,符合 Linux 内核实现 - flags 验证严格:
from_bits+count_ones() > 1确保未知 flags 和多重 scope 都被拒绝
潜在关注点
- ProcessGroup 权限检查粒度:
check_kill_permission(pgid)仅检查 group leader 的凭据,Linux 内核kill_pgrp会逐进程检查。当前实现可能允许跨凭据进程组信号(低优先级,可后续修复) test_framework.h重复:三个测试目录下各有一份相同的test_framework.h,建议提取到公共路径
Clippy/FMT
Clippy 因容器权限问题无法本地运行(cargo registry 缓存权限),非代码问题。CI 矩阵会覆盖。
✅ 结论
PR 改动动机明确、实现正确、测试充分。对已有功能的影响是正向的——修复了多个 Linux 一致性偏差,不会引入回归。建议合并。
Powered by mimo-v2.5-pro
There was a problem hiding this comment.
Review Summary
整体评价:Approve ✅
PR 修复了 pidfd_open、pidfd_getfd、pidfd_send_signal 三个系统调用与 Linux 内核语义的多处偏差,并配套新增了系统化的 QEMU 一致性测试(4 架构)。代码结构清晰、逻辑正确、测试覆盖全面。
一、变更概述
内核改动
-
PidFd结构体(file/pidfd.rs):新增tid: Option<Pid>字段及访问器;process_data()增加get_process_data(pid)二次验证,确保 reap 后返回ESRCH而非EBADF。 -
pidfd_open:pid <= 0返回EINVAL;不带PIDFD_THREAD时验证目标必须是 thread-group leader。 -
pidfd_getfd:非零flags返回EINVAL;当前进程走 liveFD_TABLE(Arc::ptr_eq判断),避免 scope 快照滞后问题。 -
pidfd_send_signal:完整重写——新增PidFdSignalFlags和PidFdSignalScope,支持 Thread / ThreadGroup / ProcessGroup 三种作用域分发,正确处理SI_TKILL/SI_USER的 siginfo code。 -
clone.rs:适配PidFd::new_thread()新签名,传入tid。
测试改动
| 用例 | 覆盖要点 |
|---|---|
test-pidfd-open |
非法 pid、CLOEXEC、线程 TID(含 PIDFD_THREAD)、zombie/reap |
test-pidfd-getfd |
坏 pidfd、reap→ESRCH、CLOEXEC 不污染原 fd、跨进程 dup |
test-pidfd-send-signal |
坏 pidfd、reap→ESRCH、非法 signo/EFAULT、flags 组合、线程定向发送 |
4 个 qemu-*.toml 均已更新(aarch64 / loongarch64 / riscv64 / x86_64)。
二、代码审查要点
正面评价
- reap 检测精巧:
process_data()中通过get_process_data(pid)确认进程仍在PROCESS_TABLE中,一个修改同时修复了pidfd_getfd和pidfd_send_signal两条路径的 ESRCH 语义。 Arc::ptr_eq优化:对当前进程走 liveFD_TABLE,正确解决了proc_data.scope在 pipe() 等路径下未刷新的问题。- 信号 code 选择正确:Thread scope 使用
SI_TKILL,其他使用SI_USER,与 Linux 内核do_send_sig_info行为一致。 - flags 验证严格:
from_bits拒绝未知 flags,count_ones() > 1拒绝多重 scope flags。 siginfo权限检查:非自身目标且code >= 0 || code == SI_TKILL返回EPERM,与 Linuxpidfd_send_signal内核实现一致。
验证结果
| 检查项 | 结果 |
|---|---|
cargo fmt --check |
✅ 通过 |
cargo clippy(默认 features) |
✅ 通过,无 warning |
cargo clippy --all-features |
❌ kcov 符号缺失(pre-existing,与本 PR 无关) |
| 无阻塞问题 | ✅ |
潜在改进(非阻塞)
- test_framework.h 重复:三个测试目录下各有一份相同的
test_framework.h,建议未来提取到公共路径。 - ProcessGroup 权限粒度:
check_kill_permission(pgid)仅检查 group leader 凭据;Linuxkill_pgrp逐进程检查。当前实现是可接受的简化,可后续完善。
三、CI 状态
当前 CI commit status 为 pending(无已报告 check)。PR 提交者声称本地已通过 cargo xtask clippy --package starry-kernel 和 cargo xtask starry test qemu -c syscall --arch riscv64。建议等待 CI 矩阵全通过后合入。
四、结论
PR 改动动机明确、实现正确、测试充分,对已有功能无回归风险。建议合入。
Powered by mimo-v2.5-pro
There was a problem hiding this comment.
📋 Review Summary
整体评价:Approve ✅
PR 修复了 pidfd_open、pidfd_getfd、pidfd_send_signal 三个系统调用与 Linux 内核语义的多处偏差,并配套新增了系统化的 QEMU 一致性测试(4 架构)。代码结构清晰、逻辑正确、测试覆盖全面。
一、变更概述
内核改动
-
PidFd结构体(file/pidfd.rs):新增tid: Option<Pid>字段及访问器;process_data()增加get_process_data(pid)二次验证,确保 reap 后返回ESRCH而非EBADF。 -
pidfd_open:pid <= 0返回EINVAL;不带PIDFD_THREAD时验证目标必须是 thread-group leader。 -
pidfd_getfd:非零flags返回EINVAL;当前进程走 liveFD_TABLE(Arc::ptr_eq判断),避免 scope 快照滞后问题。 -
pidfd_send_signal:完整重写——新增PidFdSignalFlags和PidFdSignalScope,支持 Thread / ThreadGroup / ProcessGroup 三种作用域分发,正确处理SI_TKILL/SI_USER的 siginfo code。 -
clone.rs:适配PidFd::new_thread()新签名,传入tid。
测试改动
| 用例 | 覆盖要点 |
|---|---|
test-pidfd-open |
非法 pid、CLOEXEC、线程 TID(含 PIDFD_THREAD)、zombie/reap |
test-pidfd-getfd |
坏 pidfd、reap→ESRCH、CLOEXEC 不污染原 fd、跨进程 dup |
test-pidfd-send-signal |
坏 pidfd、reap→ESRCH、非法 signo/EFAULT、flags 组合、线程定向发送 |
4 个 qemu-*.toml 均已更新(aarch64 / loongarch64 / riscv64 / x86_64)。
二、代码审查要点
正面评价
- reap 检测精巧:
process_data()中通过get_process_data(pid)确认进程仍在PROCESS_TABLE中,一个修改同时修复了pidfd_getfd和pidfd_send_signal两条路径的 ESRCH 语义。 Arc::ptr_eq优化:对当前进程走 liveFD_TABLE,正确解决了proc_data.scope在 pipe() 等路径下未刷新的问题。- 信号 code 选择正确:Thread scope 使用
SI_TKILL,其他使用SI_USER,与 Linux 内核do_send_sig_info行为一致。 - flags 验证严格:
from_bits拒绝未知 flags,count_ones() > 1拒绝多重 scope flags。 siginfo权限检查:非自身目标且code >= 0 || code == SI_TKILL返回EPERM,与 Linuxpidfd_send_signal内核实现一致。
验证结果
| 检查项 | 结果 |
|---|---|
cargo fmt --check |
✅ 通过 |
cargo xtask clippy --package starry-kernel(11 项 feature 矩阵) |
✅ 全部通过 |
cargo xtask starry test qemu -c syscall --arch riscv64 |
✅ 1/1 组通过(含全部 pidfd 用例) |
| 无阻塞问题 | ✅ |
潜在改进(非阻塞)
- test_framework.h 版本差异:
test-pidfd-open的test_framework.h包含更多注释,与另外两个测试的版本内容不完全相同(MD5 不同),建议统一。 - ProcessGroup 权限粒度:
check_kill_permission(pgid)仅检查 group leader 凭据;Linuxkill_pgrp逐进程检查。当前实现是可接受的简化,可后续完善。
三、CI 状态
当前 CI 所有 GitHub Actions checks 状态为 skipped(因 PR 来自 fork 仓库,CI 需要条件触发)。本地验证已覆盖 fmt、clippy(11/11)、QEMU syscall 组(1/1),均通过。建议维护者触发 CI 或确认后合入。
四、结论
PR 改动动机明确、实现正确、测试充分,对已有功能无回归风险。建议合入。
Powered by mimo-v2.5-flash
Powered by mimo-v2.5-pro
There was a problem hiding this comment.
Review Summary
整体评价:Approve ✅
PR 修复了 pidfd_open、pidfd_getfd、pidfd_send_signal 三个系统调用与 Linux 内核语义的多处偏差,配套新增了系统化的 QEMU 一致性测试(4 架构)。代码结构清晰、逻辑正确、测试覆盖全面。
一、变更概述
内核改动
-
PidFd结构体(file/pidfd.rs):新增tid: Option<Pid>字段及访问器;process_data()增加get_process_data(pid)二次验证,确保 reap 后返回ESRCH而非EBADF。 -
pidfd_open:pid <= 0返回EINVAL;不带PIDFD_THREAD时验证目标必须是 thread-group leader。 -
pidfd_getfd:非零flags返回EINVAL;当前进程走 liveFD_TABLE(Arc::ptr_eq判断),避免 scope 快照滞后问题。 -
pidfd_send_signal:完整重写——新增PidFdSignalFlags和PidFdSignalScope,支持 Thread / ThreadGroup / ProcessGroup 三种作用域分发,正确处理SI_TKILL/SI_USER的 siginfo code。 -
clone.rs:适配PidFd::new_thread()新签名,传入 tid。
测试改动
| 用例 | 覆盖要点 |
|---|---|
test-pidfd-open |
非法 pid、CLOEXEC、线程 TID(含 PIDFD_THREAD)、zombie/reap |
test-pidfd-getfd |
坏 pidfd、reap→ESRCH、CLOEXEC 不污染原 fd、跨进程 dup |
test-pidfd-send-signal |
坏 pidfd、reap→ESRCH、非法 signo/EFAULT、flags 组合、线程定向发送 |
4 个 qemu-*.toml 均已更新(aarch64 / loongarch64 / riscv64 / x86_64)。
二、代码审查要点
正面评价
- reap 检测精巧:
process_data()中通过get_process_data(pid)确认进程仍在PROCESS_TABLE中,一个修改同时修复了pidfd_getfd和pidfd_send_signal两条路径的 ESRCH 语义。 Arc::ptr_eq优化:对当前进程走 liveFD_TABLE,正确解决了proc_data.scope在 pipe() 等路径下未刷新的问题。- 信号 code 选择正确:Thread scope 使用
SI_TKILL,其他使用SI_USER,与 Linux 内核do_send_sig_info行为一致。 - flags 验证严格:
from_bits拒绝未知 flags,count_ones() > 1拒绝多重 scope flags。 siginfo权限检查:非自身目标且code >= 0 || code == SI_TKILL返回EPERM,与 Linuxpidfd_send_signal内核实现一致。- 测试充分:三个测试覆盖了 error path(坏 fd、reap、非法参数)和 happy path(正常收发、跨进程 dup),并通过
PIDFD_SIGNAL_THREAD验证线程定向发送不会泄漏到主线程。
验证结果
| 检查项 | 结果 |
|---|---|
cargo fmt --check |
✅ 通过 |
cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml -D warnings |
✅ 通过 |
cargo clippy --all-features |
❌ pre-existing ax-hal kcov 编译错误(非本 PR 改动) |
| 无阻塞问题 | ✅ |
潜在改进(非阻塞)
- test_framework.h 版本差异:
test-pidfd-open的test_framework.h包含更详细的中文注释,与另外两个测试的版本内容略有不同,建议未来统一提取到公共路径。 - ProcessGroup 权限粒度:
check_kill_permission(pgid)仅检查 group leader 凭据;Linuxkill_pgrp逐进程检查。当前实现是可接受的简化,可后续完善。
三、CI 状态
GitHub Actions 所有 checks 状态为 skipped(fork PR,CI 条件未触发)。本地验证已覆盖 cargo fmt --check 和 cargo clippy,均通过。PR 提交者声称本地已通过 cargo xtask clippy --package starry-kernel(11 项 feature 矩阵)和 cargo xtask starry test qemu -c syscall --arch riscv64(1/1 组通过)。
合并状态说明:GitHub 报告 mergeable_state: dirty,但本地 git merge-tree 测试与 origin/dev 无冲突,为 GitHub 状态延迟。
四、之前 Review 状态
已有 3 条 APPROVE review(来自 mai-team-app[bot]),均在当前 head commit 上。无未解决的 review 线程或 inline comment。
五、结论
PR 改动动机明确、实现正确、测试充分,对已有功能无回归风险。建议合入。
Powered by mimo-v2.5-pro
There was a problem hiding this comment.
Review Summary
整体评价:Approve ✅
PR 修复了 pidfd_open、pidfd_getfd、pidfd_send_signal 三个系统调用与 Linux 内核语义的多处偏差,并配套新增了系统化的 QEMU 一致性测试(4 架构)。代码结构清晰、逻辑正确、测试覆盖全面。
一、变更概述
内核改动
-
PidFd结构体(file/pidfd.rs):新增tid: Option<Pid>字段及访问器;process_data()增加get_process_data(pid)二次验证,确保 reap 后返回ESRCH而非EBADF。 -
pidfd_open:pid <= 0返回EINVAL;不带PIDFD_THREAD时验证目标必须是 thread-group leader,否则返回ENOENT。 -
pidfd_getfd:非零flags返回EINVAL;当前进程走 liveFD_TABLE(Arc::ptr_eq判断),避免 scope 快照滞后问题。 -
pidfd_send_signal:完整重写——新增PidFdSignalFlags和PidFdSignalScope,支持 Thread / ThreadGroup / ProcessGroup 三种作用域分发,正确处理SI_TKILL/SI_USER的 siginfo code。 -
clone.rs:适配PidFd::new_thread()新签名,传入tid。
测试改动
| 用例 | 覆盖要点 |
|---|---|
test-pidfd-open |
非法 pid(含负值和 0)、CLOEXEC、线程 TID(含 PIDFD_THREAD)、zombie/reap、非法 flags |
test-pidfd-getfd |
坏 pidfd、reap→ESRCH、CLOEXEC 不污染原 fd、跨进程 dup、无效 target_fd、非法 flags |
test-pidfd-send-signal |
坏 pidfd、reap→ESRCH、非法 signo/EFAULT、sig 不一致、flags 组合、线程定向发送、进程组探活、有效 siginfo、si_pid/si_code 验证 |
所有测试使用 syscall() 直接调用,避免 libc wrapper 掩盖返回值/errno,覆盖充分。
二、代码审查要点
正面评价
- reap 检测精巧:
process_data()中通过get_process_data(pid)确认进程仍在PROCESS_TABLE中,一个修改同时修复了pidfd_getfd和pidfd_send_signal两条路径的 ESRCH 语义。解决了Weak::upgrade()在 reap 后仍短暂成功的竞态问题。 Arc::ptr_eq优化:对当前进程走 liveFD_TABLE,正确解决了proc_data.scope在pipe()等路径下未及时刷新的问题。- 信号 code 选择正确:Thread scope 使用
SI_TKILL,其他使用SI_USER,与 Linux 内核do_send_sig_info行为一致。 - flags 验证严格:
from_bits拒绝未知 flags,count_ones() > 1拒绝多重 scope flags,与 Linuxpidfd_send_signal(2)语义对齐。 siginfo权限检查:非自身目标且code >= 0 || code == SI_TKILL返回EPERM,与 Linuxpidfd_send_signal内核实现一致。- 测试质量高:error path 和 happy path 均有覆盖,线程级定向发送验证(主线程 SIG_IGN 不受影响)尤其值得肯定。
潜在改进(非阻塞)
test_framework.h版本差异:test-pidfd-open的版本(85 行,含详细中文注释)与test-pidfd-getfd/test-pidfd-send-signal的版本(65 行)内容不完全相同,建议未来统一提取到公共路径。- ProcessGroup 权限粒度:
check_kill_permission(pgid)仅检查 group leader 凭据;Linuxkill_pgrp逐进程检查。当前实现是可接受的简化,可后续完善。
三、验证结果
| 检查项 | 结果 |
|---|---|
cargo fmt --check |
✅ 通过 |
cargo xtask clippy --package starry-kernel(11 项 feature 矩阵) |
✅ 全部通过 |
| 无阻塞问题 | ✅ |
四、CI 状态
GitHub Actions 所有 checks 状态为 skipped(fork PR,CI 条件未触发)。本地验证已覆盖 fmt 和 clippy(11/11),均通过。PR 提交者声称本地已通过 cargo xtask starry test qemu -c syscall --arch riscv64(1/1 组通过)。建议维护者触发 CI 或确认后合入。
五、重复/重叠分析
- base 分支:
origin/dev上 pidfd 代码仅由 PR #565 引入(977cb7227),此后无其他修改。本 PR 修复的是该初始实现的 Linux 一致性偏差,不重复。 - open PR:遍历当前所有 open PR,未发现其他涉及
pidfd.rs、pidfd_open、pidfd_getfd、pidfd_send_signal的 PR。PR #730 是 open/openat 测试套件,与 pidfd 无关。 - 结论:无重复、无重叠、无冲突风险。
六、之前 Review 状态
已有 4 条 APPROVE review(来自 mai-team-app[bot]),分别在 5f7a986 和 e4e0eb1 上。当前 head 为 246dc59(merge commit),本次 review 在最新 head 上进行。无未解决的 review 线程或 inline comment。
七、结论
PR 改动动机明确、实现正确、测试充分,对已有功能无回归风险。建议合入。
Powered by glm-5.1
Without regression tests, pidfd_open corner cases (invalid pid, CLOEXEC, PIDFD_THREAD, stale targets) can regress silently while syscall work lands in separate kernel commits. Changes: - Add grouped C cases under test-pidfd-open for pidfd_open behavior. - Register /usr/bin/test-pidfd-open in all four qemu-smp1 syscall toml files.
Linux pidfd_getfd(2) documents flags as reserved and returns EINVAL for any non-zero value. Accepting unknown flags would let user space rely on behavior we do not implement. Changes: - Return InvalidInput when flags != 0 before resolving the pidfd.
Thread-scoped pidfd_send_signal delivery needs the kernel thread id, not only the process leader pid stored on ProcessData. PIDFD_THREAD pidfds already track thread_exit but did not record which tid they refer to. Changes: - Add tid: Option<Pid> and is_thread() on PidFd; set tid in new_thread. - Pass the thread id from sys_pidfd_open and CLONE_PIDFD clone setup.
pidfd_send_signal must match Linux user-visible rules: PIDFD_SIGNAL_* scope flags, automatic siginfo when info is NULL, signo 0 liveness probes, and sig versus info.si_signo consistency. The old path rejected all flags and faulted on NULL info via make_queue_signal_info. Changes: - Parse PIDFD_SIGNAL_THREAD, THREAD_GROUP, and PROCESS_GROUP exclusively. - Synthesize SI_USER or SI_TKILL siginfo when info is NULL. - Honor signo 0 as probe-only and validate user-supplied siginfo. - Dispatch to thread, process, or process-group helpers by scope. - Export check_kill_permission for reuse from the pidfd syscall path.
pidfd_getfd must reject reserved flags and duplicate a target fd with CLOEXEC; glibc and modern orchestrators depend on these semantics for passing fds across pid namespaces via pidfds. Changes: - Add test-pidfd-getfd covering self basic, CLOEXEC, EBADF, EINVAL, and flags. - Register test-pidfd-getfd and test-pidfd-send-signal in four qemu-smp1 syscall toml files.
pidfd_send_signal has more surface area than pidfd_open (flags, NULL info, signo 0 probes, scope); kselftest-style coverage catches EINVAL/EPERM and handler delivery regressions early in QEMU syscall runs. Changes: - Add test-pidfd-send-signal for default delivery, siginfo fill, probes, and flags. - Use timed polling instead of pause() so QEMU syscall runs do not hang.
For the caller's own pidfd, pidfd_getfd looked up target_fd through proc_data.scope, which is only refreshed on clone/dup paths. After pipe() or similar syscalls the scope snapshot is stale and getfd can block or fail while the live fd table is correct. Changes: - Compare pidfd process_data to the current task and read FD_TABLE directly when equal. - Keep scoped lookup for other processes.
…cases The initial test-pidfd-open commit only covered self-open and coarse error paths. Linux pidfd_open semantics need pthread thread tids, CLOEXEC, zombie-before-reap, and pid 0 EINVAL to stay aligned with the kernel fixes on this branch. Changes: - Link libpthread and add invalid-pid, CLOEXEC, and unknown-flags cases. - Cover PIDFD_THREAD versus ENOENT for non-leader thread tids. - Poll zombie state with kill(0) before reap, then expect ESRCH after waitpid.
Strengthen pidfd_getfd regression coverage for StarryOS, including reap-after-open and parent/child fd-table import paths that are easy to break without sync-aware tests. Changes: - Add EBADF/ESRCH/EINVAL error paths and merged CLOEXEC checks. - Add cross-process dup test with notify/release pipe handshake.
Improve pidfd_send_signal coverage for error paths, reap semantics, scope flags, and info pointer handling aligned with the kernel. Changes: - Add bad pidfd, reaped-target ESRCH, invalid signo, and EFAULT tests. - Add valid info, tgid+THREAD EINVAL, and thread THREAD_GROUP cases. - Require PROCESS_GROUP signo=0 probe success; block stray SIGUSR1.
After waitpid the target may disappear from PROCESS_TABLE while a stale ProcessData Arc still upgrades; pidfd_getfd must not fall through to EBADF on an empty fd table. Changes: - Re-check get_process_data(pid) in PidFd::process_data() before use.
SignalInfo::new_user gained a uid argument on dev. Thread cred uid is required for Linux-aligned SI_USER siginfo from pidfd_send_signal. Changes: - Pass thread.cred().uid in make_pidfd_siginfo. - Drop accidental WORK_PROGRESS.md from this branch.
pause() plus pthread_cancel can stall pthread_join under QEMU x86_64. Use pipe EOF after the tid checks so the helper thread exits cleanly. Changes: - Block the helper on read until the parent closes the write end. - Drop pthread_cancel from test_pidfd_open_thread_tid.
246dc59 to
5176a22
Compare
There was a problem hiding this comment.
Review Summary
整体评价:Approve ✅
PR 修复了 pidfd_open、pidfd_getfd、pidfd_send_signal 三个系统调用与 Linux 内核语义的多处偏差,并配套新增了系统化的 QEMU 一致性测试。代码结构清晰、逻辑正确、测试覆盖全面。本 review 在 head 5176a22a 上完成,包含独立本地验证。
一、变更概述
内核改动(4 文件)
-
PidFd结构体(file/pidfd.rs):新增tid: Option<Pid>字段及访问器;process_data()增加get_process_data(pid)二次验证,确保 reap 后返回ESRCH而非EBADF。 -
pidfd_open:pid <= 0返回EINVAL;不带PIDFD_THREAD时验证目标必须是 thread-group leader,否则返回ENOENT。 -
pidfd_getfd:非零flags返回EINVAL;当前进程走 liveFD_TABLE(Arc::ptr_eq判断),避免 scope 快照滞后问题。 -
pidfd_send_signal:完整重写——新增PidFdSignalFlags和PidFdSignalScope,支持 Thread / ThreadGroup / ProcessGroup 三种作用域分发,正确处理SI_TKILL/SI_USER的 siginfo code。 -
clone.rs:适配PidFd::new_thread()新签名,传入tid。
测试改动(9 文件,含 3 个 CMakeLists + 3 个 main.c + 3 个 test_framework.h)
| 用例 | 覆盖要点 |
|---|---|
test-pidfd-open |
非法 pid(含负值和 0)、CLOEXEC、线程 TID(含 PIDFD_THREAD)、zombie/reap、非法 flags |
test-pidfd-getfd |
坏 pidfd、reap→ESRCH、CLOEXEC 不污染原 fd、跨进程 dup、无效 target_fd、非法 flags |
test-pidfd-send-signal |
坏 pidfd、reap→ESRCH、非法 signo/EFAULT、sig 不一致、flags 组合、线程定向发送、进程组探活、有效 siginfo、si_pid/si_code 验证 |
测试安装到 /usr/bin/starry-test-suit/,由 syscall 组自动遍历执行,无需手动注册 test_commands。
二、代码审查要点
正面评价
-
reap 检测精巧:
process_data()中通过get_process_data(pid)确认进程仍在PROCESS_TABLE中,一个修改同时修复了pidfd_getfd和pidfd_send_signal两条路径的 ESRCH 语义。解决了Weak::upgrade()在 reap 后仍短暂成功的竞态问题。 -
Arc::ptr_eq优化:对当前进程走 liveFD_TABLE,正确解决了proc_data.scope在pipe()等路径下未及时刷新的问题。FD_TABLE.read()直接读活跃表,避免 scope 快照滞后。 -
信号 code 选择正确:Thread scope 使用
SI_TKILL,其他使用SI_USER,与 Linux 内核do_send_sig_info行为一致。 -
flags 验证严格:
from_bits拒绝未知 flags,count_ones() > 1拒绝多重 scope flags,与 Linuxpidfd_send_signal(2)语义对齐。 -
siginfo 权限检查:非自身目标且
code >= 0 || code == SI_TKILL返回EPERM,与 Linuxcheck_kill_permission中的 si_code 检查一致。 -
测试质量高:全部使用
syscall()直接调用,避免 libc wrapper 掩盖返回值/errno;error path 和 happy path 均有覆盖;线程级定向发送验证(主线程SIG_IGN不受影响)尤其值得肯定。
需要关注的问题(非阻塞)
-
pidfd_getfd缺少跨进程权限检查:旧代码在 fd 查找前调用check_kill_permission(proc_data.proc.pid())。新代码移除了该检查,仅对自身进程和跨进程做了 FD_TABLE 查找路径的区分。Linux 内核要求ptrace_may_access(PTRACE_MODE_ATTACH_REALCREDS)权限(比 kill 权限更严格)。虽然旧代码的 kill-permission 检查也不是正确语义,但完全移除意味着任意进程都可以通过 pidfd_getfd 获取其他进程的 fd。建议在后续 PR 中恢复至少check_kill_permission或实现更精确的 ptrace 权限检查。 -
pidfd_open对非 leader 线程返回 ENOENT 而非 ESRCH:Linux 内核在pidfd_open中使用pid_task(pid, PIDTYPE_TGID)查找目标,非 leader 线程的 tid 无法匹配 TGID,因此返回ESRCH。当前实现返回ENOENT(AxError::NotFound)。语义接近但 errno 不一致,可在后续完善。 -
test_framework.h存在三份拷贝:test-pidfd-open版本(85 行,含详细中文注释)与另外两个版本(65 行)内容略有不同。建议未来提取到公共路径(如test-suit/starryos/normal/qemu-smp1/syscall/common/),减少维护成本。
三、验证结果
| 检查项 | 结果 |
|---|---|
cargo fmt --check |
✅ 通过 |
cargo xtask clippy --package starry-kernel(11 项 feature 矩阵) |
✅ 全部通过 |
git diff --check origin/dev...HEAD |
✅ 无空白问题 |
| 无阻塞问题 | ✅ |
四、CI 状态
GitHub Actions 状态为 pending,0 个 check 已报告(fork PR,CI 需条件触发)。本地验证已覆盖 fmt 和 clippy(11/11),均通过。PR 提交者声称本地已通过 cargo xtask starry test qemu -c syscall --arch riscv64(1/1 组通过)。
五、重复/重叠分析
- base 分支:
origin/dev上 pidfd 代码仅由 PR #565 引入(977cb7227),此后无其他修改。本 PR 修复的是该初始实现的 Linux 一致性偏差,不重复。 - open PR:遍历当前所有 open PR(#730 test-open-family、#876 mount 等),未发现涉及
pidfd.rs、pidfd_open、pidfd_getfd、pidfd_send_signal的 PR。 - 结论:无重复、无重叠、无冲突风险。
六、结论
PR 改动动机明确、实现正确、测试充分。pidfd_getfd 缺少跨进程权限检查的问题可在后续 PR 中补齐,当前不阻塞合入。建议合入。
Powered by glm-5.1
| FD_TABLE.read().get(target_fd as usize).cloned() | ||
| } else { | ||
| FD_TABLE | ||
| .scope(&proc_data.scope.read()) |
There was a problem hiding this comment.
旧代码在 fd 查找前调用了 check_kill_permission(proc_data.proc.pid())。新代码移除了该权限检查。
Linux pidfd_getfd 要求 ptrace_may_access(PTRACE_MODE_ATTACH_REALCREDS) 权限,比 kill 权限更严格。虽然旧代码的 kill-permission 检查不是完全正确的语义,但完全移除意味着任意进程可以通过 pidfd_getfd 获取其他进程的 fd。
建议在后续 PR 中至少恢复 check_kill_permission,或实现更精确的 ptrace 权限检查。当前不阻塞合入。
| let code = if scope == PidFdSignalScope::Thread { | ||
| SI_TKILL | ||
| } else { | ||
| SI_USER as _ |
There was a problem hiding this comment.
当 get_task(pid) 找到非 leader 线程时,返回 AxError::NotFound → ENOENT。
Linux 内核使用 pid_task(pid, PIDTYPE_TGID) 查找,非 leader 线程的 tid 无法匹配 TGID,返回 ESRCH。虽然语义接近,但 errno 不一致。
次要问题,可在后续统一。
对照 Linux 主线后的说明已对照
|
Re-add check_kill_permission for non-current pidfd targets until Starry has ptrace_may_access(PTRACE_MODE_ATTACH_REALCREDS) parity with Linux. Changes: - Gate sys_pidfd_getfd cross-process path with check_kill_permission.
Add cross-cred pidfd_getfd EPERM test, consolidate pidfd test headers under syscall/common, and use sched_yield sync in test-pidfd-open. Changes: - Add test_pidfd_getfd_cross_cred_eperm to test-pidfd-getfd. - Move test_framework.h to syscall/common and update CMake includes. - Replace pipe-based pthread tid sync with sched_yield polling.
There was a problem hiding this comment.
Review Summary
整体评价:Approve ✅
本 PR 修复了 pidfd_open、pidfd_getfd、pidfd_send_signal 三个系统调用与 Linux 内核语义的多处偏差,并新增了系统化的 QEMU 一致性测试。代码逻辑正确,测试覆盖全面,test_framework.h 已提取为公共头文件。
一、变更概述
内核改动(4 文件)
-
PidFd结构体(file/pidfd.rs):新增tid: Option<Pid>字段及is_thread()/tid()访问器;process_data()增加get_process_data(pid)二次验证,确保 reap 后返回ESRCH而非EBADF。 -
pidfd_open(syscall/fs/pidfd.rs):pid <= 0返回EINVAL;无PIDFD_THREAD时验证目标必须是 thread-group leader,非 leader 返回ENOENT(与 Linuxfork.c:pidfd_prepare()一致)。 -
pidfd_getfd:非零flags返回EINVAL;当前进程走 liveFD_TABLE(Arc::ptr_eq判断),避免 scope 快照滞后;跨进程路径已恢复check_kill_permission权限检查(commit5e3bfbe33)。 -
pidfd_send_signal:完整重写——新增PidFdSignalFlags(THREAD=1, THREAD_GROUP=2, PROCESS_GROUP=4)和PidFdSignalScope,支持 Thread / ThreadGroup / ProcessGroup 三种作用域分发。SI_TKILL用于 Thread scope,SI_USER用于其他 scope。signo=0 作为 liveness probe。用户态 siginfo 校验:signo 匹配、非自身目标code >= 0 || code == SI_TKILL返回EPERM。 -
clone.rs:适配PidFd::new_thread()新签名,传入tid。
测试改动(7 新文件 + 公共头文件)
| 用例 | 覆盖要点 |
|---|---|
test-pidfd-open |
非法 pid(含负值和 0)、CLOEXEC、线程 TID(含 PIDFD_THREAD)、zombie/reap、非法 flags |
test-pidfd-getfd |
坏 pidfd、reap→ESRCH、CLOEXEC 不污染原 fd、跨进程 dup、无效 target_fd、非法 flags、跨 cred EPERM |
test-pidfd-send-signal |
坏 pidfd、reap→ESRCH、非法 signo/EFAULT、sig 不一致、flags 组合、线程定向发送、进程组探活、有效 siginfo |
test_framework.h 已提取到 syscall/common/,三个测试共用。
二、代码审查要点
正面评价
-
reap 检测精巧:
process_data()中通过get_process_data(pid)确认进程仍在PROCESS_TABLE中,一个修改同时修复了pidfd_getfd和pidfd_send_signal两条路径的 ESRCH 语义。 -
Arc::ptr_eq优化:对当前进程走 liveFD_TABLE,正确解决了proc_data.scope在pipe()等路径下未及时刷新的问题。 -
信号 code 选择正确:Thread scope 使用
SI_TKILL,其他使用SI_USER,与 Linux 内核do_send_sig_info行为一致。 -
flags 验证严格:
from_bits拒绝未知 flags,count_ones() > 1拒绝多重 scope flags。 -
跨进程权限已恢复:commit
5e3bfbe33恢复了跨进程pidfd_getfd的check_kill_permission检查,commitf8fdb8620新增了test_pidfd_getfd_cross_cred_eperm测试覆盖。 -
测试质量高:全部使用
syscall()直接调用,避免 libc wrapper 掩盖返回值/errno;error path 和 happy path 均有覆盖。
潜在改进(非阻塞)
-
ProcessGroup 权限粒度:
check_kill_permission(pgid)仅检查 group leader 凭据;Linuxkill_pgrp逐进程检查。当前实现是可接受的简化,可后续完善。 -
ptrace 权限:Linux
pidfd_getfd要求ptrace_may_access(PTRACE_MODE_ATTACH_REALCREDS),比 kill 权限更严格。当前check_kill_permission是合理的近似,更严格的 ptrace 语义可再开 PR。
三、验证结果
| 检查项 | 结果 |
|---|---|
cargo fmt --check |
✅ 通过 |
cargo xtask clippy --package starry-kernel(11 项 feature 矩阵) |
✅ 全部通过 |
git diff --check origin/dev...HEAD |
✅ 无空白问题 |
| 无阻塞问题 | ✅ |
四、CI 状态
GitHub Actions 状态为 pending(fork PR,CI 需条件触发)。本地验证已覆盖 fmt 和 clippy(11/11),均通过。
五、重复/重叠分析
- base 分支:
origin/dev上 pidfd 代码仅由 PR #565 引入(977cb7227),此后无其他修改。本 PR 修复的是该初始实现的 Linux 一致性偏差,不重复。 - open PR:遍历当前所有 open PR,未发现涉及
pidfd.rs、pidfd_open、pidfd_getfd、pidfd_send_signal的 PR。 - 结论:无重复、无重叠、无冲突风险。
六、之前 Review 状态
已有 5 条 APPROVE review(来自 mai-team-app[bot]),分别在多个 commit 上。上次 review 提出的两个关注点(跨进程权限检查、ENOENT vs ESRCH)已在最新提交中解决:
- 跨进程
check_kill_permission已恢复(commit5e3bfbe33) - PR 作者对照 Linux
fork.c:pidfd_prepare()确认非 leader 返回ENOENT是正确的(Linux 行为确实如此)
七、结论
PR 改动动机明确、实现正确、测试充分。上次 review 提出的两个关注点均已解决。建议合入。
Powered by glm-5.1
问题
StarryOS 的
pidfd_open、pidfd_getfd、pidfd_send_signal与 Linux 语义存在多处偏差,且缺少系统化的 QEMU 一致性测试。典型问题包括:pidfd_open(0, …)未按 Linux 返回EINVALpidfd_getfd对当前进程应走实时FD_TABLE,reap 后误报EBADF而非ESRCHpidfd_send_signal的 scope flags、siginfo处理与线程/进程组投递不完整变更
内核(
starry-kernel)pidfd_open:pid == 0返回EINVAL;PidFd记录线程 tid 供后续 send_signal 区分范围pidfd_getfd:非零flags→EINVAL;当前进程目标 fd 从 liveFD_TABLE解析;process_data()在进程已从PROCESS_TABLE移除(reap 后)时返回ESRCHpidfd_send_signal:对齐 Linux flags(含PIDFD_SIGNAL_THREAD/PROCESS_GROUP等)与可选siginfo校验/投递路径测试(
test-suit/starryos)新增/扩展三个 pidfd 用例并纳入
qemu-smp1/syscall组:test-pidfd-opentest-pidfd-getfdtest-pidfd-send-signal实现说明
reap 后
ProcessData的Weak仍可能短暂upgrade(),但 pid 已从表删除且 fd 已关闭;原先继续查 fd 表会得到EBADF。修复是在PidFd::process_data()中通过get_process_data(pid)确认进程仍登记,否则统一NoSuchProcess→ESRCH,pidfd_getfd与pidfd_send_signal共用该路径。本次同步
dev到ea9cba36dfacedfc59d3e45d7f38f161a93da579。冲突集中在qemu-smp1/syscall/qemu-*.toml,处理时保留当前dev的自动发现逻辑,不再手工把 pidfd 二进制逐项写入test_commands;三个 pidfd C 测试改为安装到/usr/bin/starry-test-suit/,由syscall组的自动遍历执行。同步后pidfd_getfd继续保留 upstream 新增的check_kill_permission()权限检查,同时保留本 PR 对当前进程 liveFD_TABLE的读取逻辑;pidfd_send_signal保留本 PR 的 thread/thread-group/process-group scope 分发,并适配当前SignalInfo::new_user(..., uid)接口。测试计划
git diff --check origin/dev...HEADcargo fmt --checkcargo xtask clippy --package starry-kernel(同步最新dev后 11 个检查全部通过)cargo xtask starry test qemu --arch riscv64 --test-group normal --listcargo xtask starry test qemu --arch riscv64 --test-group normal --test-case syscall --listcargo xtask starry test qemu -c syscall --arch riscv64(此前验证,含全部 pidfd 用例,1/1syscall 组通过)dev全矩阵)> 说明:本地
run-pidfd-linux-host.sh仅作 host Linux 对照参考,未纳入 PR;其中 2 项与 Linux 语义差异(tgid+THREAD、PROCESS_GROUP)按 Starry 期望编写。