Skip to content

Commit d3a7fb2

Browse files
committed
fix(dispatcher): detect pip-clobber of C binary via ELF/PE magic byte check
1 parent 430b828 commit d3a7fb2

1 file changed

Lines changed: 67 additions & 24 deletions

File tree

src/omnipkg/dispatcher.py

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,13 @@ def main():
231231
and not (len(argv_commands) >= 2 and argv_commands[1] == "python")
232232
)
233233
is_config_command = len(argv_commands) >= 1 and argv_commands[0] == "config"
234+
# "daemon logs" (with or without -f) must never consume a pre-warmed worker.
235+
# It just tails a log file; routing it through the daemon burns a worker and
236+
# forces a cold replacement spawn that bloats the next real command.
234237
is_logs_follow = (
235238
len(argv_commands) >= 2
236239
and argv_commands[0] == "daemon"
237240
and argv_commands[1] == "logs"
238-
and "-f" in sys.argv
239241
)
240242
# uninstall without version spec needs interactive picker
241243
is_uninstall_interactive = (
@@ -512,29 +514,70 @@ def _maybe_install_c_dispatcher():
512514
stored_hash = marker_content.split(":", 1)[0].strip()
513515
except Exception:
514516
stored_hash = ""
515-
if stored_hash == src_hash and src_hash: # Native bin is up to date. Also push to any adopted bin dirs that
516-
# are missing their marker or have a stale hash — this heals adopted
517-
# interpreters that were added after the last compile.
518-
for adopted_bin in _collect_all_dispatcher_bin_dirs()[1:]: # skip native (index 0)
519-
adopted_marker = adopted_bin / ".omnipkg_dispatch_compiled"
520-
adopted_ok = False
521-
if adopted_marker.exists():
522-
try:
523-
# Handle both marker formats:
524-
# "hash:path" written by ghost.c and _install_binary_into_bin_dir
525-
# "hash" written by _push_binary_to_bin_dir (older format)
526-
# Always extract the hash prefix so both compare correctly.
527-
adopted_content = adopted_marker.read_text(encoding="utf-8").strip()
528-
adopted_stored_hash = adopted_content.split(":", 1)[0].strip()
529-
adopted_ok = (adopted_stored_hash == src_hash)
530-
except Exception:
531-
pass
532-
if not adopted_ok:
533-
# Push native binary to this adopted bin/ without recompiling
534-
_push_binary_to_bin_dir(bin_dir, adopted_bin, src_hash, debug)
535-
if debug:
536-
print(f"[C-INSTALL] binary is up-to-date (hash match) — skipping recompile", file=sys.stderr)
537-
return
517+
if stored_hash == src_hash and src_hash:
518+
# ── Pip-clobber guard ─────────────────────────────────────────────
519+
# pip install writes Python entry-point shims AFTER our build hook
520+
# already compiled and installed the C binary (and wrote the marker).
521+
# The hash still matches on the next invocation, but argv[0] is now
522+
# a text script — the C binary was silently replaced by pip.
523+
# Detect this by reading the first two bytes of each entry-point file:
524+
# a real C binary starts with the ELF magic "\x7fELF" (Linux/macOS)
525+
# or "MZ" (Windows PE), never "#!" or "imp". If any entry-point is
526+
# a text script we invalidate the marker so we fall through to recompile.
527+
_clobber_detected = False
528+
_exe_suffix = ".exe" if sys.platform == "win32" else ""
529+
for _ep_name in ("8pkg", "omnipkg"):
530+
_ep = bin_dir / (_ep_name + _exe_suffix)
531+
if not _ep.exists():
532+
continue
533+
try:
534+
with open(_ep, "rb") as _f:
535+
_magic = _f.read(4)
536+
# ELF magic: \x7fELF | PE/COFF magic: MZ
537+
_is_binary = _magic[:4] == b"\x7fELF" or _magic[:2] == b"MZ"
538+
if not _is_binary:
539+
_clobber_detected = True
540+
if debug:
541+
print(
542+
f"[C-INSTALL] pip-clobber detected: {_ep.name} is a text script "
543+
f"(magic={_magic!r}) despite valid marker — forcing recompile",
544+
file=sys.stderr,
545+
)
546+
break
547+
except Exception as _ce:
548+
if debug:
549+
print(f"[C-INSTALL] could not read magic bytes of {_ep}: {_ce}", file=sys.stderr)
550+
551+
if _clobber_detected:
552+
# Wipe the marker so we fall through to the compile path below.
553+
try:
554+
marker.unlink()
555+
except Exception:
556+
pass
557+
else:
558+
# Native bin is up to date. Also push to any adopted bin dirs that
559+
# are missing their marker or have a stale hash — this heals adopted
560+
# interpreters that were added after the last compile.
561+
for adopted_bin in _collect_all_dispatcher_bin_dirs()[1:]: # skip native (index 0)
562+
adopted_marker = adopted_bin / ".omnipkg_dispatch_compiled"
563+
adopted_ok = False
564+
if adopted_marker.exists():
565+
try:
566+
# Handle both marker formats:
567+
# "hash:path" written by ghost.c and _install_binary_into_bin_dir
568+
# "hash" written by _push_binary_to_bin_dir (older format)
569+
# Always extract the hash prefix so both compare correctly.
570+
adopted_content = adopted_marker.read_text(encoding="utf-8").strip()
571+
adopted_stored_hash = adopted_content.split(":", 1)[0].strip()
572+
adopted_ok = (adopted_stored_hash == src_hash)
573+
except Exception:
574+
pass
575+
if not adopted_ok:
576+
# Push native binary to this adopted bin/ without recompiling
577+
_push_binary_to_bin_dir(bin_dir, adopted_bin, src_hash, debug)
578+
if debug:
579+
print(f"[C-INSTALL] binary is up-to-date (hash match) — skipping recompile", file=sys.stderr)
580+
return
538581

539582
# ── Failure marker check (all platforms) ─────────────────────────────────
540583
# If we previously failed to compile this exact source hash, don't retry

0 commit comments

Comments
 (0)