Repository navigation
feat(shipping): #549 S2-2 N03 sealed-memfd load with offline admission and a compiled N03 pin (Phase 2, P-N03 rev 3d) - #584
Merged
Conversation
Implements P-N03 rev 3c with D-N03-5: the shipping entrypoints name the runtime package's operator library from the kernel mapping of <prefix>/libexec/<entrypoint>; the detector load refuses any other binding, reads that file once (openat2, no symlinks), hashes it, seals it into a labeled memfd, reads it back, dlopens /proc/self/fd/<M> and checks the mapping is that memfd. One verified operator per process. The loader auditor identifies every mapped object from /proc/self/maps and refuses names that do not identify their mapping unless they are the verified operator memfd. Per-object N03 scope is loaded_buffer; the aggregate load_verification stays hashed_before_load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds real-loader controls for the sealed-memfd load: the production host (operator_loader.cpp) under the production auditor, through the launcher and by direct exec; host refusal of a foreign binding (D-N03-5); auditor refusal of post-hash source changes and of every descriptor, alias and provenance bypass found in P-N03. Build-tree callers that load the operator now run from an install-shaped prefix: the preflight positive control, the two-root legacy comparison and the parity harness (stage_runtime_prefix); the SIGKILL control waits for the operator memfd mapping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Records the sealed-memfd operator load (P-N03 rev 3c, D-N03-5 strict in both modes), its auditor rule (§17.9), the local CPU/GPU/real-loader evidence and the residuals: package checkers that still read the operator by path, availability, compatibility restrictions and the pending coordinate republication. N03 MB-41 stays OPEN until merge and main CI; the aggregate byte scope stays hashed_before_load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1 (Phase 2): the operator's DT_RPATH/DT_RUNPATH must not use $ORIGIN (a memfd load would expand it under /proc/self/fd), so the verified ELF is checked before sealing; a non-ELF object is refused there too. After a successful dlopen the mapping is checked once; any failure poisons the process registry and keeps the memfd open so its number is never reused, and the registry is published only after validation. A request prepared while an identical one loaded reuses it. Tests: descriptor reuse through load() (fails with the post-check removed), F_SEAL_FUTURE_WRITE-only seals, $ORIGIN fixtures, and the production auditor's maps parser at its buffer boundaries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only implementation changes, from bc378f688f9cd71b7a72b567f0718ac3d87d153fd8b246a15e6c17c927e24e5c to 02f4dd970c4e6bfd9a2b8a2d80e89a9c8316e431ad0a33739241a4f26201ec95: 303 to 305 files, two new (operator_loader.hpp/.cpp) and eight modified shipping loader/auditor/ plan/driver files, no deletions. Decision surface, identity semantics, environment and runtime inputs are unchanged. Fresh --run-probe capture after a complete Release build of 492bb3d; publication_complete=true. The probe digest equals the outgoing one but is freshly computed; equality does not establish equivalence. The append-only archive keeps the outgoing canonical bytes (SHA-256 63f7ebebb38c758a54ef58a86d75c76b1c845758217a0d0f9d1ab0adc13d0c74); candidate SHA-256 1ed472d1e91c35dc3993e19bd9fea3cef24c9467ede3336fe723ec059e005a5a. The attested staleness check passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebinds the evidence to source 492bb3d: CPU loader controls (30/30 runs), the post-check mutation run, GPU native ctest, the real-loader auditor suite, CLI suites, the seven-sequence GPU replay with direct memfd identity (device, inode, seals, SHA-256) and the republished coordinate; records the review round 1 dispositions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 2 (Phase 2): the $ORIGIN check read PT_DYNAMIC at its file offset while the loader reads it at its virtual address, so a split table could hide $ORIGIN. The check now reads the table through p_vaddr within a file-backed PT_LOAD, requires the stated file offset to agree, a DT_NULL terminator and a string table within its segment (overflow-safe), and refuses two PT_DYNAMIC. The per-request mapping is copied before the registry is published. CPU controls cover the split (accepted by the previous parser), unterminated, oversized DT_STRSZ and duplicate cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mfd load" This reverts commit 91a0037.
Only implementation changes, from bc378f688f9cd71b7a72b567f0718ac3d87d153fd8b246a15e6c17c927e24e5c to 8cf46e38e1f836abc4f5db2d4613dcbfa32d263ae6d72086218329ea10f796ae: 303 to 305 files, two new (operator_loader.hpp/.cpp) and eight modified shipping loader/auditor/ plan/driver files, no deletions. Decision surface, identity semantics, environment and runtime inputs are unchanged. Fresh --run-probe capture after a complete Release build of 7fb8c7a (source of HEAD 85086d5); publication_complete=true. The probe digest equals the outgoing one but is freshly computed; equality does not establish equivalence. The append-only archive keeps the outgoing canonical bytes (SHA-256 63f7ebebb38c758a54ef58a86d75c76b1c845758217a0d0f9d1ab0adc13d0c74); candidate SHA-256 a78c7ad3547b41a62dffc4eb49470e93e9eb20240b2304c2a4f80f4931f58f05. The attested staleness check passes. The coordinate of 91a0037 (reverted, never pushed) described an intermediate source and is not archived. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebinds CPU, GPU native, real-loader, CLI and seven-sequence GPU replay evidence to head 85086d5 (code 7fb8c7a), records the review round 2 dispositions, the ELF split-table attack (accepted by the previous parser, refused now) and the final coordinate republication. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 3 (Phase 2): overlapping PT_LOAD segments let the check translate the dynamic table through an earlier segment that the loader maps over (MAP_FIXED), hiding $ORIGIN. The check now requires ascending, page-disjoint loadable segments whose file offsets are congruent to their addresses, so every mapped byte comes from one segment. $ORIGIN is also refused in DT_NEEDED, DT_AUXILIARY and DT_FILTER, whose names the loader expands too. Controls: a CPU overlap case (accepted by the previous parser) and a real-loader DT_NEEDED case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mfd load" This reverts commit 001ecec.
Only implementation changes, from bc378f688f9cd71b7a72b567f0718ac3d87d153fd8b246a15e6c17c927e24e5c to 671bc0a935dc20ca08390967cb9ee2fcffe7a7f262729e6d562876e24156459a: 303 to 305 files, two new (operator_loader.hpp/.cpp) and eight modified shipping loader/auditor/ plan/driver files, no deletions. Decision surface, identity semantics, environment and runtime inputs are unchanged. Fresh --run-probe capture after a complete Release build of 0e09a85 (source of HEAD c5510fd); publication_complete=true. The probe digest equals the outgoing one but is freshly computed; equality does not establish equivalence. The append-only archive keeps the outgoing canonical bytes (SHA-256 63f7ebebb38c758a54ef58a86d75c76b1c845758217a0d0f9d1ab0adc13d0c74); candidate SHA-256 9cceaf3b44e7650616e7427968c89ff8595fa32ad839bbaac66f4381f86d7674. The attested staleness check passes. Earlier republications on this branch (91a0037, 001ecec) described intermediate sources, were reverted before any push and are not archived. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 4 (Phase 2): a PT_LOAD with p_memsz 0 skipped the layout rule while the dynamic-table translation could still use it, and the loader maps its file bytes. Every PT_LOAD is now validated, zero-size load segments are refused, and the segment end and page rounding are checked in separate overflow-safe steps. The DT_NEEDED control pins --no-as-needed; the docs list the validated ELF properties and leave other ELF checks to dlopen. Controls: zero-size overlap (accepted by the previous parser) and a segment wrapping past 2^64. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mfd load" This reverts commit 456f948.
Record the reviewed rev 3d proposal (offline ELF admission, compiled singleton N03 pin, link-time pin object, digest-only install/package checks) and the owner's acceptance of O-N03-1..3. Mark the Phase 2 evidence at 1d0ffa1 as historical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…3 rev 3d) The runtime no longer parses the operator ELF. VerifiedOperator::prepare requires the plan's SHA-256 (and Gate A's size when known) to be the compiled N03 pin before the registry, the open or dlopen, and the source to have the pin's size and digest. - shipping/n03_operator_pin.json is compiled at configure time into saccade_shipping_n03_pin; configure and install refuse a pin that is not the tracked attestation's op_library; saccade_track's POST_BUILD requires the pin digest; check_shipping_package compares the packaged operator with the pin. - The loader is its own library linking the production pin; CPU tests link a fixture pin ahead of it, so they test the runtime's object. - The $ORIGIN/layout rule moved unchanged to saccade_shipping_n03_admission and the CPU tool saccade_n03_admission (record on the pinned bytes); no runtime target links it. Its fixture controls moved with it, plus the braced form and all five expanded tags. - Tests: unknown self-consistent operators are refused by the pin (CPU, real-loader auditor suite, CLI stand-in bundles); constructor sentinel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
install_model_root.cmake now requires SACCADE_N03_OPERATOR_PIN and refuses an attestation whose op_library is not the pin; the fake repository gets a pin, and a control refuses a pin of another digest or size before any file is copied. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- install_model_root.cmake compares against the pin this build compiled into the runtime (SACCADE_N03_BUILT_PIN_*), refuses a source pin changed since the build, and requires the attestation to be that pin; configure and install share cmake/n03_pin.cmake. - shipping CMake minimum 3.19 (string(JSON) at configure). - saccade_n03_admission reads through one descriptor: fstat's size, then end of file; any read error refuses. - check_shipping_package.check_n03_pin, with behavioral controls; rule controls for mismatched and malformed pins via cmake -P. - The headline-publication install fixture gets a pin. - Tighter controls: exact pin diagnostics in the auditor and CLI tests, a size refusal before registry reuse, a constructor sentinel case that attempts load() after the refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- install_model_root.cmake checks the attestation snapshot it copies against (n03_pin.cmake takes the JSON text, not a path), and requires this build's saccade_track, when the tree takes it, to carry the pin's digest (a reconfigure without a rebuild cannot pair the binary with another operator); a pinned entrypoint predates the pin and is not checked. - Controls for the entrypoint binding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only implementation changes, from bc378f688f9cd71b7a72b567f0718ac3d87d153fd8b246a15e6c17c927e24e5c to 5eb66833ac4556b3cac7b49ddc59ec0597fa761369e69c8ebe9b3b547650f773: 303 to 312 files. Nine added (n03_operator_pin.json, cmake/n03_operator_pin.cpp.in, cmake/n03_pin.cmake, cmake/check_n03_pin.cmake, operator_loader.hpp/.cpp, n03_admission.hpp/.cpp, tools/saccade_n03_admission.cpp) and nine modified (shipping/CMakeLists.txt, cmake/install_model_root.cmake, detector_host.hpp/.cpp, detector_plan.hpp/.cpp, loader_audit.c, tools/saccade_detector_probe.cpp, tools/track_driver.hpp), no deletions: the #549 S2-2 Phase 2 sealed-memfd load and its P-N03 rev 3d revision relative to main's canonical. Decision surface, identity semantics, environment and runtime inputs are unchanged. Fresh --run-probe capture after a complete Release build of 8b020ec (build/runtime_identity); publication_complete=true. The probe behavior digest 2dabed0b... equals the outgoing one but is freshly computed; equality does not establish equivalence (equivalence stays unproven). The append-only archive keeps the outgoing canonical bytes (SHA-256 63f7ebebb38c758a54ef58a86d75c76b1c845758217a0d0f9d1ab0adc13d0c74); candidate SHA-256 2331fd8031eb626834e7a329e80f1c2fec25d7d897585af46d158cc1b84aceac. The attested staleness check passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Final local chain on the frozen source 8b020ec: CPU loader 47 checks 30/30, admission 32 and pin 2 checks, the admission record for the pinned N03, GPU native ctest 8/8, CLI suites 617 passed / 0 skipped, and the seven-sequence GPU replay (raw sections EXACT, formal verdicts UNRESOLVED under V5, memfd SHA-256 = the pin). The coordinate republication bc4e77c passed its independent review. Rev 3c runs are kept as historical evidence. N03 MB-41 stays OPEN, S2-2 PARTIAL, aggregate hashed_before_load, V5 UNRESOLVED, local-only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
manifest_head took any failed git show of shipping/n03_operator_pin.json for a source commit before P-N03 rev 3d and skipped the check. The pin is now required once the commit's shipping CMake compiles it (read_n03_pin); an unreadable or non-JSON pin refuses. End-to-end manifest_head controls on a fake source commit: the pinned operator passes, an unreadable pin, another digest or a malformed pin refuse, a commit whose build compiles no pin has none to check. Restoring the fail-open read fails the unreadable-pin control. Outside the runtime coordinate's axes (scripts/native/). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
raylei50653
marked this pull request as ready for review
October 12, 2026 04:03
This was referenced Oct 12, 2026
This was referenced Oct 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
openat2, hashed, copied into a labeled memfd, sealed and read back, thendlopened from/proc/self/fd/<M>with a maps post-check, a process registry and poisoning. D-N03-5 is strict in both modes, and the loader auditor identifies each object by its kernel mapping (P-N03 rev 3c, reviewed in Draft docs(shipping): #549 S2-2 N03 TOCTOU threat model and P-N03 proposal (Phase 1) #583).shipping/n03_operator_pin.json,aa84cccd…, 3,517,632 bytes) and refuses any other operator before the registry, the open ordlopen, even one whose attestation is self-consistent. The$ORIGIN/layout rule moved unchanged to the CPU-onlysaccade_n03_admissiontool, which no runtime target links. Configure, install and the package checker compare digests against the pin. Design:docs/reference/model_bundle_s2_2_n03_offline_proposal_549.md.docs/reference/model_bundle_s2_2_n03_phase2_549.md(+.evidence.json).Status (unchanged by this PR until merge and main CI): N03 MB-41 OPEN, S2-2 PARTIAL, aggregate
hashed_before_load, V5 UNRESOLVED, installed package UNVERIFIED,distribution.status=local-only,owner_confirmation=null. Merge is not authorized.Decision-layer change?
mamba_whole_graph*.yaml)scripts/eval/config/**)pipeline.pyset_*/ private det-set)docs/research/tracker-decision/Behavior change?
Yes. Shipping runtime behavior changes:
DetectorLoadError, exit 2, Gate A identity kept);cfea78…) are refused; that build no longer exists.Ladder on the frozen source
8b020ec0: the seven-sequence GPU replay (shipping trace/no-trace, measurement double-buffer and serial, 5,316 frames each), 7 negative controls, manifest mode, the launcher run and the failure states. Raw sections are EXACT, and MOT/trace hashes equal the feat(shipping): verify S2-2 model buffers and compatibility gates #582 replay. Formal verdicts are UNRESOLVED on this host (V5: driver 617.42 ≠ 616.92). Section equality is a local diagnostic, not qualified parity.Adding, tightening, or retiring a check? (hook /
pre_push.sh/ pytest / CI)Test plan
Final chain on the frozen source
8b020ec0(results/549_s2_2_n03_phase2/verify_chain_r3d.sh, local-only):$ORIGIN/${ORIGIN}under all five tags, layout controls, pin pairing). Production pin test: 2/2. Admission record for the real N03:admitted.saccade_trackbuilds carry the pin digest and no admission strings.gpu_8b020ec0240d: memfd SHA-256 equals the pin, seals0x2f, no operator path mapped. Reports showloaded_buffer×3 with aggregatehashed_before_load.--run-probecapture, append-only archive, attested check passes, independent review found nothing.scripts/pre_push.sh: all checks passed (pytest 5730 passed).manifest_headand configure (see the doc's review table).e4e93bde: P2 (package checker took an unreadable pin for an older commit) is fixed inc73ff7c1. The pin is now required once the commit's shipping CMake compiles it, with end-to-endmanifest_headcontrols; a mutation restoring the fail-open read fails them. The change is outside the coordinate's axes, and pre-push passes. P3 (the install copies the attestation from its source after validating a snapshot) predates this PR and is tracked separately.Known residuals:
sources/strace readers do not understand the memfd load.fbab8b79…) predates the pin. An installed package enforces the pin only after a package re-pin, which this PR does not authorize.string(JSON)at configure.🤖 Generated with Claude Code