Skip to content

test(ghidra): expect carved MIPS copies to be refused at target opening - #8227

Merged
morluto merged 3 commits into
morluto:mainfrom
Entrpi:fix-verify-ghidra-mips-carved-fixture
Oct 31, 2026
Merged

morluto merged 3 commits into
morluto:mainfrom
Entrpi:fix-verify-ghidra-mips-carved-fixture

Conversation

@Entrpi

@Entrpi Entrpi commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

npm run verify:ghidra:mips fails on main. Since 651afa445, target opening refuses every ELF that declares a file range beyond EOF, including carved copies, and ac6e0e258 moved the carved MIPS boundary tests to that contract. The real-Ghidra lane still expects a carved copy to resolve with section-table limitations and to be refused later by Ghidra admission, so it stops at its first carved fixture. This PR moves the lane, its shared checks and the MIPS and PSP guides to the current contract. It changes no production code.

No issue is linked: #2362 reports the same failure on main 1173c0a9d in its validation list, and no issue or PR fixes it. This PR is part of the embedded roadmap #7955.

Problem and expected behavior

On main d48e472fa, the lane's direct parseBinaryTarget call (scripts/verify-real-ghidra-mips.mjs:649) for little-hard-carved.elf throws BinaryTargetError: Cannot open artifact: truncated ELF section header table: declared file range 2556..3516 exceeds the 2555-byte file (constraint file_format_rejected), and the lane exits 1.

Expected: open_binary and the CLI both refuse the carved copy before provider selection, as target_unavailable with constraint file_format_rejected. The refusal names the declared section-table range and the captured size, and the copy stays unchanged.

Change and scope

  • tests/conformance/ghidra/mips-checks.mjs: carveMipsElfBeforeSectionTable cuts an ELF32 MIPS image one byte before its section header table. First it asserts that every program header and payload stays captured and that extended section numbering is not in use. It returns the bytes and the expected refusal reason. assertMipsCarvedTargetRefusal requires exactly target_unavailable with details { path, reason, constraint: "file_format_rejected" }.
  • scripts/verify-real-ghidra-mips.mjs: applies both helpers through MCP open_binary and the CLI function command, for the hard- and soft-float fixtures in both byte orders. The carved report has status: "expected-target-refusal" and the reason. The direct parseBinaryTarget call on the carved copy and the superseded assertIncompleteMipsInspection are removed.
  • tests/boundary/filesystem/mipsAbiFlags.test.ts: applies the same carve and assertion to the production resolver and projectAnalysisError in both byte orders, so a later contract change fails without real Ghidra.
  • tests/conformance/ghidra/mips-checks.test.ts: checks the carve's length and reason, and that it refuses to cut a payload. It also checks that the assertion accepts the target-opening refusal and rejects the superseded admission refusal, a wrong file size and a missing constraint.
  • docs/ghidra-mips.md and docs/ghidra-psp.md describe the target-opening refusal and the lane's check.

Not included: no change to target opening or provider admission. Carved PSP stays unverified, as on main. Contribution scope: a test and documentation fix within existing boundaries; not applicable.

Draft #6422 edits the line next to this PR's carved block in scripts/verify-real-ghidra-mips.mjs, so whichever PR merges second will need a one-line conflict resolution.

Contract and boundary impact

  • Semantic owner and earliest changed stage: no production stage changes. Target opening owns the refusal: BinaryTargetResolver calls validateElfDeclaredRanges, unchanged. The lane and the boundary test now consume its projected error instead of resolved MIPS limitations.
  • Contribution scope fit and linked maintainer decision: not applicable.
  • CLI and MCP/tool-catalog contract: none.
  • Provider, bridge, target-format, or platform compatibility: none.
  • Evidence, artifact, provenance, or reconstruction contract: none. Only the verifier's own report for carved copies changes.
  • Target selection, authority, upstream behavior, and cleanup details: not applicable.
  • Generated metadata, package, or installation impact: none.

Expected effects: none new. The PR changes a real-Ghidra verifier, tests and documentation. The verifier reads its own fixtures and launches Ghidra, as on main.

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated: 2 boundary cases (LE and BE) in mipsAbiFlags.test.ts and 3 cases in mips-checks.test.ts, as above.
  • Base reproduction or other evidence: the real lane on main d48e472fa exits 1 at little-hard-carved.elf, as quoted above. feat(ghidra): admit plain MIPS32 PIC shared images #2362 reports the same failure on main 1173c0a9d.
  • User-visible CLI/MCP output: unchanged. The real lane observed this MCP error for little-hard-carved.elf (path shortened). The CLI exits 1 with the same code and details:
{
  "code": "target_unavailable",
  "category": "unsupported_target",
  "message": "Cannot open artifact: truncated ELF section header table: declared file range 2556..3516 exceeds the 2555-byte file.",
  "retryable": false,
  "remediation": {
    "action": "Review the reported file-format reason and select a supported, well-formed target."
  },
  "details": {
    "path": "/tmp/rea-mips-proof-…/little-hard-carved.elf",
    "reason": "truncated ELF section header table: declared file range 2556..3516 exceeds the 2555-byte file",
    "constraint": "file_format_rejected"
  }
}
  • Remaining proof gaps: the lane ran only in generic mode on Linux x86_64. PSP mode, carved PSP and real Ghidra on macOS or Windows were not run.

Boundary regressions: format assumptions (the carve keeps every program header and payload, and the unit test pairs it with a cut that would drop a payload byte, which the helper refuses) and public success and error delivery (the real lane asserts the exact error details through both MCP and the CLI, not only the code). No lifecycle regression applies, because ownership and cleanup do not change.

For evidence-bearing changes: not applicable; no Evidence or artifact contract changes.

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

Local checks ran on macOS arm64 (Darwin 25.5.0) with Node 24.22.1, on the head aa00d7ea3, which merges main d48e472fa:

  • npm run check:fast — passed.
  • npm run format:check — passed.
  • npm run docs:check — passed.
  • npm run verify:module-boundaries — passed.
  • npm run test:focused -- tests/conformance/ghidra/mips-checks.test.ts tests/boundary/filesystem/mipsAbiFlags.test.ts — 2 files, 87 tests passed. These are the two test files this PR changes.
  • npx knip — no findings.

Real Ghidra 12.1.4 in a Debian 13 container (Linux x86_64; OpenJDK 21.0.12.1, Node 24.22.1, clang 19.1.7, GNU readelf 2.44):

  • npm run verify:ghidra:mips on main d48e472fa — exit 1 at little-hard-carved.elf, as above.
  • npm run verify:ghidra:mips on the head aa00d7ea3 — exit 0. All six fixtures pass: recordless legacy LE and BE (pinned MIPS:LE:32:default and MIPS:BE:32:default), and MIPS32r2 hard float and soft float, LE and BE. MCP open_binary and the CLI (exit 1) refuse all four carved copies as target_unavailable with file_format_rejected: hard float 2,555 bytes (declared range 2556..3516), soft float 5,551 bytes (5552..6592). Each copy stays unchanged. Process lineage is verified, with no descendants.

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: real Ghidra 12.1.4 on Linux x86_64 (verify:ghidra:mips, generic mode); no Hopper.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: no new effects; verifier, tests and documentation only.

Author readiness

Human owner: @Entrpi

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

Since 651afa4 target opening refuses every ELF declaration beyond EOF,
including carved copies, and ac6e0e2 moved the carved MIPS boundary tests
to that contract. The real-Ghidra MIPS lane still expected a carved image to
resolve with section-table limitations and be refused later by Ghidra
admission, so verify:ghidra:mips failed at its first carved fixture.

The lane now requires open_binary and the CLI to refuse the carved copy as
target_unavailable (file_format_rejected) with the exact declared
section-table range and captured size. The carve and that expectation live in
the shared MIPS checks, and a boundary regression applies them to the
production resolver and error projection, so a later contract change fails
without real Ghidra. The MIPS and PSP guides describe the current contract.
@greptile-apps

greptile-apps Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Low impact] The PR appears safe to merge; no actionable issues were found.

Summary

Updates the MIPS verifier and guides to expect carved ELF copies to fail at target opening rather than later during Ghidra admission.

  • The MIPS verifier reports carved copies as target-opening refusals.

No actionable correctness or security issues were identified. No tests or real-Ghidra workflows were run during this review. Checking whether another PR supersedes this one was blocked by unavailable GitHub authentication; no supersession claim is made.

Reviews (1) · Last reviewed commit: "Merge upstream main into fix-verify-ghid..." · Reviewed by Greptile

@Entrpi
Entrpi marked this pull request as ready for review October 31, 2026 00:16
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-31T00:16:40.621097Z
We couldn’t complete this review. Comment @codex review to try again.
aa00d7e Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@morluto
morluto merged commit 091892d into morluto:main Oct 31, 2026
46 of 47 checks passed
Entrpi added a commit to Entrpi/rea that referenced this pull request Oct 31, 2026
Entrpi added a commit to Entrpi/rea that referenced this pull request Oct 31, 2026
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