Skip to content

[deckhouse-cli] fix macOS SIGKILL by installing the binary atomically - #430

Open
nevermarine wants to merge 1 commit into
mainfrom
fix/install/atomic-binary-replace
Open

[deckhouse-cli] fix macOS SIGKILL by installing the binary atomically#430
nevermarine wants to merge 1 commit into
mainfrom
fix/install/atomic-binary-replace

Conversation

@nevermarine

@nevermarine nevermarine commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Problem

On macOS (Apple Silicon), after the installer reinstalls/updates d8, the binary is killed with SIGKILL on every invocation, before any output:

$ d8 --version
fish: Job 1, 'd8 --version' terminated by signal SIGKILL (Forced quit)
$ d8            # from bash
Killed: 9       d8

codesign --verify --deep --strict on the installed binary passes, and a byte-for-byte copy of the same file at a different path runs fine — so the binary and its ad-hoc signature are intact. The kill comes from the kernel code-signing subsystem (AMFI), not Gatekeeper (no dialog) or an EDR (none present).

Root cause

install_binary places the binary with cp "$binary_path" "$target_path" over an existing target. cp onto an existing path is open(O_TRUNC)+write — it keeps the same inode. When updating in place, the kernel still holds the code-signing validation cached for the previous contents of that vnode; the new pages no longer match → cs_invalid → AMFI sends SIGKILL on exec. codesign --verify still passes because it checks the on-disk seal, not the kernel's cached state.

A fresh inode (via rename()) has no stale cache, which is why copying the file elsewhere makes it run.

Fix

Copy to a temporary file next to the target and mv -f it into place — an atomic rename(), so the new binary always gets a fresh inode. Applied to both the sudo and non-sudo paths.

Testing

  • sh -n tools/install.sh — syntax OK.
  • Reproduced the SIGKILL with an in-place cp overwrite; confirmed the installed binary runs after the atomic-replace path.

@nevermarine
nevermarine requested a review from ldmonster as a code owner July 31, 2026 10:01
The installer overwrote the binary in place with `cp` over the existing
target path, which keeps the same inode. On macOS this leaves the kernel
holding a stale code-signing validation for the previous contents of the
ad-hoc signed binary, so an updated d8 is killed with SIGKILL on exec even
though `codesign --verify` still passes.

Copy to a temporary file next to the target and rename it into place so the
new binary always gets a fresh inode.

Signed-off-by: Maksim Fedotov <[email protected]>
@nevermarine
nevermarine force-pushed the fix/install/atomic-binary-replace branch from af1f975 to 23146b5 Compare July 31, 2026 10:06
@ldmonster
ldmonster requested a review from Copilot July 31, 2026 10:30

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

Pull request overview

This PR updates the tools/install.sh installer to avoid macOS (Apple Silicon) SIGKILL after in-place upgrades by installing the d8 binary via atomic replacement (rename()), preventing stale kernel code-signing cache issues.

Changes:

  • Replace in-place cp overwrite with a cp to a temporary sibling file and mv -f into place (atomic install).
  • Apply the atomic install approach to both sudo and non-sudo install paths.
Suppressed comments (1)

tools/install.sh:404

  • Same issue as the sudo branch: if ${target_path}.tmp.$$ already exists, cp will truncate it in-place and keep its inode, which can defeat the “fresh inode via rename” guarantee. Remove any pre-existing temp file (or use mktemp) and store the temp path in a variable to avoid repetition.
    cp "$binary_path" "${target_path}.tmp.$$"
    chmod +x "${target_path}.tmp.$$"
    mv -f "${target_path}.tmp.$$" "$target_path"

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tools/install.sh
Comment on lines +391 to +393
sudo cp "$binary_path" "${target_path}.tmp.$$"
sudo chmod +x "${target_path}.tmp.$$"
sudo mv -f "${target_path}.tmp.$$" "$target_path"
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