[PR #3103] [CLOSED] fix(ghidra): parse and reconcile MIPS GNU ABI attributes #5618

Closed
opened 2026-10-31 01:08:01 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/3103
Author: @AurelioB
Created: 10/14/2026
Status: ❌ Closed

Base: main ← Head: fix/mips-gnu-attributes


📝 Commits (5)

  • 333504b fix(ghidra): parse and reconcile MIPS GNU ABI attributes
  • 7f2f693 test(ghidra): expect the documented refusal of carved MIPS executables
  • 3af6be5 fix(ghidra): apply the GNU MSA ABI refusal to PSP admission
  • 94fa5bf Merge remote-tracking branch 'origin/main' into HEAD
  • 1838181 Merge origin/main into fix/mips-gnu-attributes

📊 Changes

5 files changed (+118 additions, -69 deletions)

View changed files

📝 scripts/verify-real-ghidra-mips-shared.mjs (+14 -0)
📝 scripts/verify-real-ghidra-mips.mjs (+51 -63)
📝 tests/conformance/ghidra/mips-checks.d.mts (+7 -1)
📝 tests/conformance/ghidra/mips-checks.mjs (+44 -5)
📝 tests/conformance/ghidra/psp-fixture.mjs (+2 -0)

📄 Description

Closes #3096.

Problem

d4bd65c53 refuses any MIPS ELF with an SHT_GNU_ATTRIBUTES section "until the declared ABI is parsed and reconciled". GCC and GNU ld emit that section in nearly every MIPS object, so on main all 225 MIPS ELF files of a real MIPS32r2 Linux firmware are refused at target resolution. The executable lane verify:ghidra:mips also fails, because of the carved-fixture refusal from the same commit.

Change

fix(ghidra): parse and reconcile MIPS GNU ABI attributes

  • Strict parser (src/application/MipsGnuAttributes.ts), following the ELF attributes layout binutils uses:
    • Format version A, one gnu vendor subsection, and Tag_File scope.
    • Length fields in the ELF byte order, accounted exactly.
    • ULEB128 tags and values limited to 32 bits.
    • Only Tag_GNU_MIPS_ABI_FP (4) and Tag_GNU_MIPS_ABI_MSA (8) are interpreted.
    • Refused: other vendors, section or symbol scope, unknown or repeated tags, repeated vendor subsections, and truncated or overrunning lengths.
  • Reader (MipsElfMetadata.ts):
    • The section is still found by numeric type; names are never consulted.
    • Its declared size is checked against a 4 KiB bound before the read.
    • A second attribute section is refused.
    • A nonzero FP tag must equal the ABI flags fp_abi. infer_mips_abiflags in binutils sets fp_abi from Tag_GNU_MIPS_ABI_FP, and ld warns "inconsistent FP ABI between .gnu.attributes and .MIPS.abiflags". 0 is Val_GNU_MIPS_ABI_FP_ANY and declares no requirement.
    • The MSA tag is not reconciled with AFL_ASE_MSA. Binutils doesn't derive one from the other: the tag is the vector argument-passing ABI, while the ASE bit records instruction use.
  • Admission (GhidraMipsProfile.ts):
    • The 128-bit MSA vector argument ABI is refused.
    • Without an ABI flags record (the recordless legacy and MIPS16 lanes), the FP tag must be absent, 0, double (1) or FPXX (5). Those are the values the declared-ABI lane already admits under the default o32 compiler specification. Soft, single and FP64 are refused.
  • Profile: mips_elf.gnu_attributes is committed to the analysis profile, so it invalidates profile-bound snapshots.
  • Oracles: the real-Ghidra readelf oracles (mips-checks.mjs, PSP fixture) derive gnuAttributes independently from readelf -A. The MIPS16 lane checks the FPXX tag that GNU as records for its recordless fixture.

test(ghidra): expect the documented refusal of carved MIPS executables, a separate commit:

d4bd65c53 refuses incomplete ABI inspections and documents it, but verify:ghidra:mips still required the carved fixture to open. The fixture is now a negative control:

  • Target resolution must still read the program-header ABI record and report the unavailable section headers.
  • MCP and CLI must both refuse it with the incomplete-inspection reason.

Drop this commit if the intent is to re-admit carved images instead.

Verification

All on 7f2f6936b with Ghidra 12.1.4:

  • Real-Ghidra lanes, all exit 0:
    • verify:ghidra:mips: 6 fixtures verified (LE/BE, hard/soft, recordless legacy); the 4 carved variants are refused as expected.
    • verify:ghidra:mips-relocatable.
    • verify:ghidra:mips-shared (MIPS16, 8 controls; GNU binutils 2.45.90 with --hash-style=sysv). Its GNU-built fixtures carry .gnu.attributes; the recordless variant's FPXX tag is admitted and matches readelf -A.
  • Firmware (one MIPS32r2 rootfs):
    • Admission went from 0 of 225 to 105 of 108 ET_EXEC and 30 of 30 ET_REL. The 3 refused executables declare o32 without an ABI flags record, the existing refusal.
    • The 87 ET_DYN libraries need #2362.
    • Every file's GNU FP tag matches its ABI flags fp_abi (190 double, 30 soft).
    • CLI decompilation of bluealsa main (hard double) and soc_msc.ko ingenic_mmc_command_done (soft) succeeds, with the committed gnu_attributes.
  • Unit and boundary tests:
    • 19 parser tests: both byte orders; every malformed and refused shape listed above.
    • Through the file reader and parseBinaryTarget: agreement and conflict with the record, FP ANY, the MSA refusal, a duplicate section, the size bound before the read (LE/BE), and recordless admission and refusal.
  • Repo checks: tsc, oxfmt --check ., check:fast and verify:test-discovery pass. test:fast has 7363 passed and 5 failed; the same 5 files (IdaNativeProtocol, electronWrappedCallPaths, javascriptSemanticAmbientWrites, javascriptSemanticAnalysis.native_bindings, JavaScriptSemanticGraphResources) fail identically on the base b3c5672ce.
  • Not run: the PSP lane (no psp-gcc here); its oracle change is a consistency edit.

🔄 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/3103 **Author:** [@AurelioB](https://github.com/AurelioB) **Created:** 10/14/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/mips-gnu-attributes` --- ### 📝 Commits (5) - [`333504b`](https://github.com/morluto/rea/commit/333504b008045dc09e46c413358fae874cc458d5) fix(ghidra): parse and reconcile MIPS GNU ABI attributes - [`7f2f693`](https://github.com/morluto/rea/commit/7f2f6936ba4aa4e6d420a651440d02f88ae5b77e) test(ghidra): expect the documented refusal of carved MIPS executables - [`3af6be5`](https://github.com/morluto/rea/commit/3af6be5e54ca87ccad6b7e1bcdd104984c2f503a) fix(ghidra): apply the GNU MSA ABI refusal to PSP admission - [`94fa5bf`](https://github.com/morluto/rea/commit/94fa5bf20dcdbc1199656901eb82704cff00719e) Merge remote-tracking branch 'origin/main' into HEAD - [`1838181`](https://github.com/morluto/rea/commit/1838181098aebc813a728c9ea0f1a3ef308e1dbf) Merge origin/main into fix/mips-gnu-attributes ### 📊 Changes **5 files changed** (+118 additions, -69 deletions) <details> <summary>View changed files</summary> 📝 `scripts/verify-real-ghidra-mips-shared.mjs` (+14 -0) 📝 `scripts/verify-real-ghidra-mips.mjs` (+51 -63) 📝 `tests/conformance/ghidra/mips-checks.d.mts` (+7 -1) 📝 `tests/conformance/ghidra/mips-checks.mjs` (+44 -5) 📝 `tests/conformance/ghidra/psp-fixture.mjs` (+2 -0) </details> ### 📄 Description Closes #3096. ## Problem `d4bd65c53` refuses any MIPS ELF with an `SHT_GNU_ATTRIBUTES` section "until the declared ABI is parsed and reconciled". GCC and GNU ld emit that section in nearly every MIPS object, so on `main` all 225 MIPS ELF files of a real MIPS32r2 Linux firmware are refused at target resolution. The executable lane `verify:ghidra:mips` also fails, because of the carved-fixture refusal from the same commit. ## Change **`fix(ghidra): parse and reconcile MIPS GNU ABI attributes`** - **Strict parser** (`src/application/MipsGnuAttributes.ts`), following the ELF attributes layout binutils uses: - Format version `A`, one `gnu` vendor subsection, and `Tag_File` scope. - Length fields in the ELF byte order, accounted exactly. - ULEB128 tags and values limited to 32 bits. - Only `Tag_GNU_MIPS_ABI_FP` (4) and `Tag_GNU_MIPS_ABI_MSA` (8) are interpreted. - Refused: other vendors, section or symbol scope, unknown or repeated tags, repeated vendor subsections, and truncated or overrunning lengths. - **Reader** (`MipsElfMetadata.ts`): - The section is still found by numeric type; names are never consulted. - Its declared size is checked against a 4 KiB bound before the read. - A second attribute section is refused. - A nonzero FP tag must equal the ABI flags `fp_abi`. `infer_mips_abiflags` in binutils sets `fp_abi` from `Tag_GNU_MIPS_ABI_FP`, and ld warns "inconsistent FP ABI between .gnu.attributes and .MIPS.abiflags". 0 is `Val_GNU_MIPS_ABI_FP_ANY` and declares no requirement. - The MSA tag is not reconciled with `AFL_ASE_MSA`. Binutils doesn't derive one from the other: the tag is the vector argument-passing ABI, while the ASE bit records instruction use. - **Admission** (`GhidraMipsProfile.ts`): - The 128-bit MSA vector argument ABI is refused. - Without an ABI flags record (the recordless legacy and MIPS16 lanes), the FP tag must be absent, 0, double (1) or FPXX (5). Those are the values the declared-ABI lane already admits under the default o32 compiler specification. Soft, single and FP64 are refused. - **Profile:** `mips_elf.gnu_attributes` is committed to the analysis profile, so it invalidates profile-bound snapshots. - **Oracles:** the real-Ghidra `readelf` oracles (`mips-checks.mjs`, PSP fixture) derive `gnuAttributes` independently from `readelf -A`. The MIPS16 lane checks the FPXX tag that GNU as records for its recordless fixture. **`test(ghidra): expect the documented refusal of carved MIPS executables`**, a separate commit: `d4bd65c53` refuses incomplete ABI inspections and documents it, but `verify:ghidra:mips` still required the carved fixture to open. The fixture is now a negative control: - Target resolution must still read the program-header ABI record and report the unavailable section headers. - MCP and CLI must both refuse it with the incomplete-inspection reason. Drop this commit if the intent is to re-admit carved images instead. ## Verification All on `7f2f6936b` with Ghidra 12.1.4: - **Real-Ghidra lanes, all exit 0:** - `verify:ghidra:mips`: 6 fixtures verified (LE/BE, hard/soft, recordless legacy); the 4 carved variants are refused as expected. - `verify:ghidra:mips-relocatable`. - `verify:ghidra:mips-shared` (MIPS16, 8 controls; GNU binutils 2.45.90 with `--hash-style=sysv`). Its GNU-built fixtures carry `.gnu.attributes`; the recordless variant's FPXX tag is admitted and matches `readelf -A`. - **Firmware** (one MIPS32r2 rootfs): - Admission went from 0 of 225 to 105 of 108 `ET_EXEC` and 30 of 30 `ET_REL`. The 3 refused executables declare o32 without an ABI flags record, the existing refusal. - The 87 `ET_DYN` libraries need #2362. - Every file's GNU FP tag matches its ABI flags `fp_abi` (190 double, 30 soft). - CLI decompilation of `bluealsa` `main` (hard double) and `soc_msc.ko` `ingenic_mmc_command_done` (soft) succeeds, with the committed `gnu_attributes`. - **Unit and boundary tests:** - 19 parser tests: both byte orders; every malformed and refused shape listed above. - Through the file reader and `parseBinaryTarget`: agreement and conflict with the record, FP ANY, the MSA refusal, a duplicate section, the size bound before the read (LE/BE), and recordless admission and refusal. - **Repo checks:** `tsc`, `oxfmt --check .`, `check:fast` and `verify:test-discovery` pass. `test:fast` has 7363 passed and 5 failed; the same 5 files (`IdaNativeProtocol`, `electronWrappedCallPaths`, `javascriptSemanticAmbientWrites`, `javascriptSemanticAnalysis.native_bindings`, `JavaScriptSemanticGraphResources`) fail identically on the base `b3c5672ce`. - **Not run:** the PSP lane (no `psp-gcc` here); its oracle change is a consistency edit. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:08:01 +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#5618
No description provided.