Skip to content

fix: rewrite and resign SIP executables on execve/posix_spawn #3

Closed
not-matthias wants to merge 4 commits into
codspeedfrom
sip-resign-exec-redirect
Closed

fix: rewrite and resign SIP executables on execve/posix_spawn #3
not-matthias wants to merge 4 commits into
codspeedfrom
sip-resign-exec-redirect

Conversation

@not-matthias

Copy link
Copy Markdown
Member

No description provided.

@not-matthias not-matthias force-pushed the sip-resign-exec-redirect branch 2 times, most recently from 1424a61 to 9e6e169 Compare June 2, 2026 16:35
Use `xcrun --show-sdk-path` instead of a hardcoded Xcode SDK path so the
build works regardless of where the toolchain is installed, and set
CARGO_TARGET_ARM64E_APPLE_DARWIN_LINKER=clang so the -Zbuild-std arm64e
target links correctly.
Add a `log` backend that formats records into a fixed stack buffer (there
is no allocator in a preload) and writes them to stderr, gated behind the
SAMPLY_PRELOAD_DEBUG env var. Wire `logging::init()` into the preload
constructor and trace the samply handoff lifecycle.
macOS strips every DYLD_* env var when the kernel execs an Apple platform
binary in a SIP-protected path (/usr/bin/env, /bin/sh, the coreutils, ...),
which unloads this preload from that process and its whole descendant tree
(the classic `env -> bash -> uv -> python` blind spot).

Interpose the execve/posix_spawn{,p} family: when the target is such a SIP
binary, transparently exec an ad-hoc re-signed copy from a writable cache
instead. The copy is not a platform binary, so dyld keeps DYLD_*, the
preload re-arms in the child, and the var keeps propagating down the tree.
Shebang interpreter chains (pnpm/pip via #!/usr/bin/env) are handled by
redirecting the interpreter and rebuilding argv. samply seeds the shared
cache dir via the SAMPLY_SIP_REDIRECT_DIR env var.
Rebuild the bundled fat dylib and per-arch binaries to include the SIP
exec-redirect feature and the debug logger.
@not-matthias not-matthias force-pushed the sip-resign-exec-redirect branch from f0fe523 to 20b3819 Compare June 3, 2026 15:15
@not-matthias not-matthias marked this pull request as ready for review June 3, 2026 15:16
@not-matthias not-matthias requested a review from Copilot June 3, 2026 15:16

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

Pull request overview

This PR adds a macOS SIP “exec redirect” mechanism to keep DYLD_INSERT_LIBRARIES propagation intact across SIP-protected platform-binary exec/spawn boundaries by copying + ad-hoc re-signing target binaries into a writable cache, then exec’ing the cached copies.

Changes:

  • Plumb a new SAMPLY_SIP_REDIRECT_DIR env var from the mac task launcher to enable SIP redirect caching.
  • Add a new sip_redirect preload module that interposes execve / posix_spawn{,p} and redirects SIP binaries + SIP-interpreter shebang scripts to re-signed cached copies.
  • Add preload debug logging + an integration smoke test script, and update preload build tooling/deps.

Reviewed changes

Copilot reviewed 10 out of 16 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
samply/src/mac/process_launcher.rs Sets up SAMPLY_SIP_REDIRECT_DIR for child processes to enable redirect caching.
samply-mac-preload/tests/preload_smoke.sh Adds end-to-end smoke tests for exec/posix_spawn redirect + setuid policy.
samply-mac-preload/src/sip_redirect/sys.rs New low-level libc helpers (env/argv/copy + codesign spawn).
samply-mac-preload/src/sip_redirect/redirect.rs Implements redirect policy (SIP binary detection, shebang parsing, cache build).
samply-mac-preload/src/sip_redirect/mod.rs Adds the actual interposes for execve / posix_spawn{,p}.
samply-mac-preload/src/sip_redirect/buffers.rs Stack buffers for redirected path building + rebuilt argv storage.
samply-mac-preload/src/logging.rs Adds optional stderr logging for preload debugging.
samply-mac-preload/src/lib.rs Wires in logging + sip_redirect module and adds InterposeEntry::new.
samply-mac-preload/Cargo.toml Adds heapless, itoa, and log dependencies for the new modules.
samply-mac-preload/Cargo.lock Updates lockfile for new dependencies / format version bump.
samply-mac-preload/build.sh Makes SDK discovery dynamic and adjusts arm64e linker env.

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

Comment on lines +43 to +55
/// `<dst>.<pid>.tmp` for an atomic build.
pub(super) fn set_tmp_path(&mut self, dst: &CPathBuffer) -> bool {
let pid = unsafe { libc::getpid() };
let mut itoa_buf = itoa::Buffer::new();
let pid_str = itoa_buf.format(pid as u32);

self.bytes.clear();
self.bytes.extend_from_slice(dst.as_bytes()).is_ok()
&& self.bytes.push(b'.').is_ok()
&& self.bytes.extend_from_slice(pid_str.as_bytes()).is_ok()
&& self.bytes.extend_from_slice(b".tmp").is_ok()
&& self.bytes.push(0).is_ok()
}
Comment on lines +96 to +110
// Skip "#!" and leading whitespace
let mut start = 2;
while start < line.len() && line[start] == b' ' {
start += 1;
}
if start >= line.len() {
return false;
}

// Find end of interpreter path
let interp_end = line[start..]
.iter()
.position(|&b| b == b' ')
.map(|p| start + p)
.unwrap_or(line.len());
Comment on lines +144 to +151
if interp_end < line.len() {
let arg_bytes = &line[interp_end + 1..];
// Trim at the next whitespace (only a single interpreter arg is supported).
let arg_end = arg_bytes
.iter()
.position(|&b| b == b' ')
.unwrap_or(arg_bytes.len());
let arg = &arg_bytes[..arg_end];
Comment on lines +105 to +108
let devnull = c"/dev/null".as_ptr();
libc::posix_spawn_file_actions_addopen(&mut fa, 1, devnull, libc::O_WRONLY, 0);
libc::posix_spawn_file_actions_addopen(&mut fa, 2, devnull, libc::O_WRONLY, 0);

Comment on lines +54 to +57
node_is_preloaded() {
[[ -n "$NODE" ]] || return 1
[[ "$("$NODE" -e "process.stdout.write(process.env.DYLD_INSERT_LIBRARIES?'y':'n')" 2>/dev/null)" == "y" ]]
}
@not-matthias not-matthias removed the request for review from GuillaumeLagrange June 10, 2026 09:49
@not-matthias

Copy link
Copy Markdown
Member Author

Superseded by #4

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