Repository navigation
test(ghidra): expect carved MIPS copies to be refused at target opening - #8227
Conversation
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.
[Low impact] The PR appears safe to merge; no actionable issues were found. SummaryUpdates the MIPS verifier and guides to expect carved ELF copies to fail at target opening rather than later during Ghidra admission.
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 |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
Summary
npm run verify:ghidra:mipsfails onmain. Since651afa445, target opening refuses every ELF that declares a file range beyond EOF, including carved copies, andac6e0e258moved 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
main1173c0a9din its validation list, and no issue or PR fixes it. This PR is part of the embedded roadmap #7955.Problem and expected behavior
On
maind48e472fa, the lane's directparseBinaryTargetcall (scripts/verify-real-ghidra-mips.mjs:649) forlittle-hard-carved.elfthrowsBinaryTargetError: Cannot open artifact: truncated ELF section header table: declared file range 2556..3516 exceeds the 2555-byte file(constraintfile_format_rejected), and the lane exits 1.Expected:
open_binaryand the CLI both refuse the carved copy before provider selection, astarget_unavailablewith constraintfile_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:carveMipsElfBeforeSectionTablecuts 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.assertMipsCarvedTargetRefusalrequires exactlytarget_unavailablewithdetails{ path, reason, constraint: "file_format_rejected" }.scripts/verify-real-ghidra-mips.mjs: applies both helpers through MCPopen_binaryand the CLIfunctioncommand, for the hard- and soft-float fixtures in both byte orders. The carved report hasstatus: "expected-target-refusal"and thereason. The directparseBinaryTargetcall on the carved copy and the supersededassertIncompleteMipsInspectionare removed.tests/boundary/filesystem/mipsAbiFlags.test.ts: applies the same carve and assertion to the production resolver andprojectAnalysisErrorin 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.mdanddocs/ghidra-psp.mddescribe 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
BinaryTargetResolvercallsvalidateElfDeclaredRanges, unchanged. The lane and the boundary test now consume its projected error instead of resolved MIPS limitations.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.Evidence and regression coverage
mipsAbiFlags.test.tsand 3 cases inmips-checks.test.ts, as above.maind48e472faexits 1 atlittle-hard-carved.elf, as quoted above. feat(ghidra): admit plain MIPS32 PIC shared images #2362 reports the same failure onmain1173c0a9d.little-hard-carved.elf(path shortened). The CLI exits 1 with the samecodeanddetails:{ "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" } }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
detailsthrough 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.
Validation performed
Local checks ran on macOS arm64 (Darwin 25.5.0) with Node 24.22.1, on the head
aa00d7ea3, which mergesmaind48e472fa: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:mipsonmaind48e472fa— exit 1 atlittle-hard-carved.elf, as above.npm run verify:ghidra:mipson the headaa00d7ea3— exit 0. All six fixtures pass: recordless legacy LE and BE (pinnedMIPS:LE:32:defaultandMIPS:BE:32:default), and MIPS32r2 hard float and soft float, LE and BE. MCPopen_binaryand the CLI (exit 1) refuse all four carved copies astarget_unavailablewithfile_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
verify:ghidra:mips, generic mode); no Hopper.Author readiness
Human owner: @Entrpi
Before merge
type(scope): outcome.