Skip to content

修复 macOS 上内核更新后启动即被 SIGKILL 的问题(原地覆写可执行文件导致) - #233

Open
dont-see-big-shark wants to merge 2 commits into
router-for-me:mainfrom
dont-see-big-shark:fix/macos-core-sigkill-after-update
Open

dont-see-big-shark wants to merge 2 commits into
router-for-me:mainfrom
dont-see-big-shark:fix/macos-core-sigkill-after-update

Conversation

@dont-see-big-shark

Copy link
Copy Markdown

关联 Issue

Fixes #224(内核启动后立即退出:signal: 9 (SIGKILL) / exit code: 0

问题现象

macOS 上 CPA 内核启动后立即退出,GUI 报错:

  • CPA 内核启动后立即退出: signal: 9 (SIGKILL)
  • 同一 issue 中另有 CPA 内核启动后立即退出: exit code: 0 的变体

根因分析

macOS 内核会按文件(vnode/inode)缓存代码签名校验结果

  1. 内核更新时,overlay_directory 对已存在的二进制直接 fs::copy 原地覆写(同一 inode,内容被改写);
  2. 该 inode 的缓存签名随即失效,此后对这个文件的每一次 exec 都会在 main() 之前被内核直接 SIGKILL
  3. 由于 vnode 缓存按 inode 生效,只有这个文件被杀:字节完全相同的副本(新 inode)可以正常运行,甚至在同一目录改名后依然被杀。且该状态在本次开机会话内无法自愈。

实测复现(macOS 26):

  • 原文件(被更新流程覆写过的 inode):exec 即刻 SIGKILL,无任何输出;
  • cp 出的字节相同副本:正常启动;
  • 把原文件改名后仍在同目录:依旧 SIGKILL(证明与文件名/路径无关,与 inode 绑定);
  • 用副本重新覆盖原文件名(新 inode):恢复正常,管理端口正常监听。

exit code: 0 变体的成因是 GUI 启动内核时 stdout/stderr 均为 Stdio::null(),内核启动后正常打印日志并干净退出时(例如配置目录类错误),用户只能看到空白的 "exit code: 0",无从排查。

修复内容

  1. 根因修复:新增 copy_file_replaceoverlay_directory 对文件改为「写入同目录临时文件 + fs::rename 原子替换」。更新后的内核二进制始终是全新 inode,不会再触发签名失效缓存;
  2. 存量自愈start_core_process_inner 检测到子进程被 SIGKILL 立即退出时(macOS),自动用同样的「临时副本 + rename」重物化内核二进制并重试一次。已中毒的旧安装无需重装内核即可自愈;重试仍失败时,错误信息提示重新安装内核;
  3. 可诊断性:内核 stderr 改为追加写入 logs/core-start-output.log(位于内核安装目录上一级),exit code: 0 这类静默退出可据此看到内核的真实输出;打开失败时自动回退 Stdio::null(),不影响启动;
  4. 回归测试copy_file_replace_*overlay_directory_replaces_existing_binary_with_fresh_inode,使用 inode 断言确保更新流程永不原地覆写可执行文件。

测试情况

  • cargo check --tests 通过;
  • cargo test --bin cpa-gui -- tests::core_runtime:26/26 通过(含新增 3 个);
  • macOS 26 实机端到端验证:复现 SIGKILL → 应用修复 → 内核正常启动、管理端口监听正常、SIGTERM 干净退出。

对受影响用户的临时解决办法(在未合入本 PR 前退出)

删除整个 cpa-core 目录后,在 GUI 内重新下载/安装内核(目录不存在时安装走 fs::rename 整目录替换,新 inode,可正常启动):

~/Library/Application Support/com.cpa.gui/cpa-core

注意:仅在 GUI 内反复重试无效,因为更新流程会再次原地覆写同一 inode。

问题现象:macOS 上 CPA 内核启动后立即退出,错误信息为
"CPA 内核启动后立即退出: signal: 9 (SIGKILL)"(见 router-for-me#224)。

根因:macOS 内核会按文件(vnode/inode)缓存代码签名校验结果。
内核更新流程 overlay_directory 对已存在的二进制直接 fs::copy
原地覆写,导致同一 inode 的缓存签名失效;此后对该文件的每一次
exec 都会在 main() 之前被内核以 SIGKILL 杀死。字节完全相同的
副本(新 inode)可以正常执行,只有被原地覆写过的那个文件被杀,
且在本次开机会话内无法自愈。

修复:
- overlay_directory 改为 copy_file_replace:先写入同目录临时
  文件再原子 rename 替换目标文件,更新后的内核始终是全新 inode,
  不再触发签名失效;
- start_core_process_inner 检测到子进程被 SIGKILL 立即退出时,
  自动用同样的"临时副本 + rename"方式重物化内核二进制并重试一次,
  已中毒的旧安装无需重装即可自愈;仍失败时提示重新安装内核;
- 内核 stderr 改为写入 logs/core-start-output.log(此前为
  Stdio::null 丢弃),"exit code: 0" 这类静默退出可以据此排查;
- 新增回归测试,用 inode 断言确保更新不会原地覆写可执行文件。

验证:cargo check 通过;tests::core_runtime 26/26 通过;
新增 3 个测试通过;在 macOS 26 实机复现并验证修复后内核可正常
启动并监听管理端口。

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8d4a7f003b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src-tauri/src/core_runtime.rs Outdated
@lzt404

lzt404 commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

感谢您的贡献,为了保持git commit消息的一致,请使用英文提交commit

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.

内核启动失败:CPA 内核启动后立即退出: exit code: 0

2 participants