[PR #1285] [MERGED] fix(hopper): probe interior navigation from multi-byte instructions #2766

Closed
opened 2026-10-17 21:10:00 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1285
Author: @BaaRai
Created: 10/9/2026
Status: ✅ Merged
Merged: 10/9/2026
Merged by: @morluto

Base: main ← Head: fix/real-hopper-interior-navigation


📝 Commits (1)

  • 9373042 fix(hopper): probe interior navigation from multi-byte instructions

📊 Changes

1 file changed (+21 additions, -6 deletions)

View changed files

📝 scripts/lib/real-hopper-navigation.mjs (+21 -6)

📄 Description

Summary

The real-Hopper boundary-contract navigation probe derived its interior coordinate as anchor + 1, which silently assumes the fixture procedure's first instruction is longer than one byte. On host toolchains that compile the fixture prologue without endbr64 padding, the first instruction is the one-byte push rbp, so anchor + 1 is itself an instruction boundary: goto_address correctly snaps to (and reports) that boundary, and the verifier rejects a correct bridge. The probe now anchors to the first instruction followed by a coordinate gap larger than one byte, so the probed coordinate is strictly inside an instruction on either prologue encoding. Related to the conformance work in #31 / #341.

Problem and expected behavior

Smallest trigger: npm run verify:hopper:linux with fixtures compiled by a gcc that does not default to -fcf-protection (reproduced on Kali rolling, gcc 16.2.0, where rea_entry compiles to push rbp at 0x4011b6 followed by mov rbp,rsp at 0x4011b7).

Violated invariant: the navigation contract probe must exercise an interior (non-boundary) coordinate. With a one-byte first instruction, goto_address(anchor + 1) legitimately returns anchor + 1, and the run fails at scripts/lib/real-hopper-navigation.mjs (goto_address observed 0x4011b7, expected 0x4011b6) even though the bridge, contract text ("Interior coordinates snap to the containing analyzed object's start"), and cursor behavior are all correct.

Change and scope

verifyNavigation now walks the instruction coordinates to the first instruction whose successor coordinate is more than one byte away, then derives goto_address snap, current_address, next_address, prev_address, and post-rejection cursor assertions from that instruction. When the first instruction is multi-byte (the endbr64 encoding used by the CI target hosts), anchor stays 0 and every assertion is identical to the previous ones. Nothing outside scripts/lib/real-hopper-navigation.mjs changes; bridge, contracts, fixtures, and oracles are untouched. Intentionally not included: the same + 1 interior-coordinate pattern in scripts/lib/real-ghidra-boundaries.mjs (inspect_native_instruction not-instruction-boundary probe) is not changed here because I could not execute that lane end to end; flagging it for a maintainer decision instead.

Contract and boundary impact

  • Semantic owner and earliest changed stage: verifier script only (scripts/lib/real-hopper-navigation.mjs); no runtime stage changes.
  • CLI and MCP/tool-catalog contract: none; the asserted contract semantics (interior snap, unmapped rejection, cursor readback) are unchanged.
  • Provider, bridge, target-format, or platform compatibility: improves verifier portability across host toolchain prologue encodings (with and without -fcf-protection); no provider or bridge change.
  • Evidence, artifact, provenance, or reconstruction contract: not applicable.
  • Process execution, authorization, cleanup, or containment impact: not applicable.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: not applicable.

Evidence and regression coverage

  • Tests added or updated: none; this lane has no mocked mirror of the navigation probe, and the real run is the executable evidence.
  • Base reproduction and other evidence: executed real-Hopper Linux demo runs on Kali rolling (glibc 2.43, node 24.19) with the pinned launcher (SHA256 0294ced141cc373468ee22d8343e7dac41980cb05a937994ca81c9f09afe7ded) driven through the private-Xvfb demo lane:
    • Base f0855899: run fails at the goto_address interior assertion (0x4011b7 observed vs 0x4011b6 expected) with default-toolchain fixtures.
    • This change: the same run completes, exit 0, cleanShutdown: true, process lineage verified with zero retained descendants, unrelated-Hopper sentinel survived, 139-tool catalog parity, 171 successful and 63 rejected boundary-contract calls, all navigation/workflow/search flags true.
    • A/B prologue control: fixtures rebuilt with -fcf-protection=branch (endbr64 first instruction) complete identically on the same code, confirming the multi-byte path keeps the previous assertions.
  • User-visible CLI/MCP output: not applicable.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1285 **Author:** [@BaaRai](https://github.com/BaaRai) **Created:** 10/9/2026 **Status:** ✅ Merged **Merged:** 10/9/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/real-hopper-interior-navigation` --- ### 📝 Commits (1) - [`9373042`](https://github.com/morluto/rea/commit/93730429ca121666ee7a5046510f93120afdec45) fix(hopper): probe interior navigation from multi-byte instructions ### 📊 Changes **1 file changed** (+21 additions, -6 deletions) <details> <summary>View changed files</summary> 📝 `scripts/lib/real-hopper-navigation.mjs` (+21 -6) </details> ### 📄 Description ## Summary The real-Hopper boundary-contract navigation probe derived its interior coordinate as `anchor + 1`, which silently assumes the fixture procedure's first instruction is longer than one byte. On host toolchains that compile the fixture prologue without `endbr64` padding, the first instruction is the one-byte `push rbp`, so `anchor + 1` is itself an instruction boundary: `goto_address` correctly snaps to (and reports) that boundary, and the verifier rejects a correct bridge. The probe now anchors to the first instruction followed by a coordinate gap larger than one byte, so the probed coordinate is strictly inside an instruction on either prologue encoding. Related to the conformance work in #31 / #341. ## Problem and expected behavior Smallest trigger: `npm run verify:hopper:linux` with fixtures compiled by a gcc that does not default to `-fcf-protection` (reproduced on Kali rolling, gcc 16.2.0, where `rea_entry` compiles to `push rbp` at `0x4011b6` followed by `mov rbp,rsp` at `0x4011b7`). Violated invariant: the navigation contract probe must exercise an interior (non-boundary) coordinate. With a one-byte first instruction, `goto_address(anchor + 1)` legitimately returns `anchor + 1`, and the run fails at `scripts/lib/real-hopper-navigation.mjs` (`goto_address` observed `0x4011b7`, expected `0x4011b6`) even though the bridge, contract text ("Interior coordinates snap to the containing analyzed object's start"), and cursor behavior are all correct. ## Change and scope `verifyNavigation` now walks the instruction coordinates to the first instruction whose successor coordinate is more than one byte away, then derives `goto_address` snap, `current_address`, `next_address`, `prev_address`, and post-rejection cursor assertions from that instruction. When the first instruction is multi-byte (the endbr64 encoding used by the CI target hosts), `anchor` stays 0 and every assertion is identical to the previous ones. Nothing outside `scripts/lib/real-hopper-navigation.mjs` changes; bridge, contracts, fixtures, and oracles are untouched. Intentionally not included: the same `+ 1` interior-coordinate pattern in `scripts/lib/real-ghidra-boundaries.mjs` (`inspect_native_instruction` not-instruction-boundary probe) is not changed here because I could not execute that lane end to end; flagging it for a maintainer decision instead. ## Contract and boundary impact - Semantic owner and earliest changed stage: verifier script only (`scripts/lib/real-hopper-navigation.mjs`); no runtime stage changes. - CLI and MCP/tool-catalog contract: none; the asserted contract semantics (interior snap, unmapped rejection, cursor readback) are unchanged. - Provider, bridge, target-format, or platform compatibility: improves verifier portability across host toolchain prologue encodings (with and without `-fcf-protection`); no provider or bridge change. - Evidence, artifact, provenance, or reconstruction contract: not applicable. - Process execution, authorization, cleanup, or containment impact: not applicable. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: not applicable. ## Evidence and regression coverage - Tests added or updated: none; this lane has no mocked mirror of the navigation probe, and the real run is the executable evidence. - Base reproduction and other evidence: executed real-Hopper Linux demo runs on Kali rolling (glibc 2.43, node 24.19) with the pinned launcher (SHA256 `0294ced141cc373468ee22d8343e7dac41980cb05a937994ca81c9f09afe7ded`) driven through the private-Xvfb demo lane: - Base f0855899: run fails at the `goto_address` interior assertion (`0x4011b7` observed vs `0x4011b6` expected) with default-toolchain fixtures. - This change: the same run completes, exit 0, `cleanShutdown: true`, process lineage verified with zero retained descendants, unrelated-Hopper sentinel survived, 139-tool catalog parity, 171 successful and 63 rejected boundary-contract calls, all navigation/workflow/search flags true. - A/B prologue control: fixtures rebuilt with `-fcf-protection=branch` (`endbr64` first instruction) complete identically on the same code, confirming the multi-byte path keeps the previous assertions. - User-visible CLI/MCP output: not applicable. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-17 21:10:00 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#2766
No description provided.