[GH-ISSUE #6154] [Bug] Mach-O with corrupt load commands is admitted, then fails as a generic execution_failure that says to run rea doctor #3764

Closed
opened 2026-10-31 00:43:48 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @Nitin13-git on GitHub (Oct 21, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/6154

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Native analysis or decompilation

Observed behavior

A thin Mach-O whose header is valid but whose load commands are corrupt is admitted by REA's own check, then fails in the provider. Three public CLI commands return exit 1 with code execution_failure and the message "Analysis could not complete. Run rea doctor and review the reported details; repeating the unchanged request is not expected to succeed." (analyze, analyze --provider ghidra, inspect-macho).

Controls (same commands): the same file cut to 200 bytes, an empty file, a text file, a 4-byte file and an ELF header-only file all return target_unavailable with a specific reason (for example "truncated Mach-O load commands").

Reproduction

Executed on macOS arm64, Node 24.18.0, source 3dbe314ad (package 6.7.0); Ghidra 12.1.4 for the Ghidra command. Any thin 64-bit Mach-O works as the starting file (mine is a small clang build):

python3 -c "d=bytearray(open('hello','rb').read()); d[32:200]=b'\xff'*168; open('corrupt','wb').write(d)"
node scripts/rea.mjs analyze corrupt --format json
node scripts/rea.mjs analyze corrupt --provider ghidra --format json
node scripts/rea.mjs inspect-macho corrupt --format json

The fixture's first load command is cmd=0xffffffff cmdsize=0xffffffff; header ncmds=17, sizeofcmds=1056, file size 33,544 bytes. Ghidra's captured output contains "No load spec found for import file"; the inspect-macho failure comes from lipo exiting 1 (provider native-macos).

Expected behavior

A Mach-O whose load-command table cannot be walked (a cmdsize below 8 or running past sizeofcmds, bad alignment, sizes not adding up to sizeofcmds) is rejected at admission as target_unavailable, like the truncated case. Failing that, a provider's "no load spec" or lipo parse failure on a target is reported as an unsupported target, not as an environment failure whose remediation is rea doctor (the environment checks pass in this setup).

Impact and scope

Observed on one synthetic file and two providers. Real-world frequency, Windows and Linux behavior, 32-bit and fat Mach-O, and other formats: NOT_ENOUGH_INFO. No data loss or crash; the cost is a misleading diagnosis and an unneeded provider launch.

REA version

Source 3dbe314ad, package 6.7.0

Runtime and platform

macOS arm64 (26.6.2), Node 24.18.0

Target and artifact context

One authored arm64 Mach-O (SHA-256 of the corrupted file 17a49bd7a3826ae84e108793ba9fb06a388a0522fef4f8721301d4548c22a9cb); no user binary.

Interface

CLI

Earliest failure stage

Setup or provider admission

Relevant output or evidence

Commands actually run are above. For analyze --provider ghidra: code: execution_failure, details.provider_id: ghidra, operation: read_binary_inventory_summary, Ghidra stdout "No load spec found for import file: target-17a49bd7a382.bin" and "Import failed for file". For inspect-macho: provider_id: native-macos, operation: inspect_macho, tool: lipo, reason: nonzero-exit, exit_code: 1.

Analysis or suspected cause

Source-derived, not verified by a fix: parseThinMachO in src/domain/binaryTarget.ts only checks headerSize + sizeofcmds > fileSize; it does not validate the load commands themselves. Related: #1189 (truncated Mach-O header admitted, closed) and #5076 (Go inspection reports Evidence for a Mach-O with a misaligned load command).

Originally created by @Nitin13-git on GitHub (Oct 21, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6154 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Native analysis or decompilation ### Observed behavior A thin Mach-O whose header is valid but whose load commands are corrupt is admitted by REA's own check, then fails in the provider. Three public CLI commands return exit 1 with code `execution_failure` and the message "Analysis could not complete. Run `rea doctor` and review the reported details; repeating the unchanged request is not expected to succeed." (`analyze`, `analyze --provider ghidra`, `inspect-macho`). Controls (same commands): the same file cut to 200 bytes, an empty file, a text file, a 4-byte file and an ELF header-only file all return `target_unavailable` with a specific reason (for example "truncated Mach-O load commands"). ### Reproduction Executed on macOS arm64, Node 24.18.0, source `3dbe314ad` (package 6.7.0); Ghidra 12.1.4 for the Ghidra command. Any thin 64-bit Mach-O works as the starting file (mine is a small `clang` build): ```sh python3 -c "d=bytearray(open('hello','rb').read()); d[32:200]=b'\xff'*168; open('corrupt','wb').write(d)" node scripts/rea.mjs analyze corrupt --format json node scripts/rea.mjs analyze corrupt --provider ghidra --format json node scripts/rea.mjs inspect-macho corrupt --format json ``` The fixture's first load command is `cmd=0xffffffff cmdsize=0xffffffff`; header `ncmds=17`, `sizeofcmds=1056`, file size 33,544 bytes. Ghidra's captured output contains "No load spec found for import file"; the `inspect-macho` failure comes from `lipo` exiting 1 (provider `native-macos`). ### Expected behavior A Mach-O whose load-command table cannot be walked (a `cmdsize` below 8 or running past `sizeofcmds`, bad alignment, sizes not adding up to `sizeofcmds`) is rejected at admission as `target_unavailable`, like the truncated case. Failing that, a provider's "no load spec" or `lipo` parse failure on a target is reported as an unsupported target, not as an environment failure whose remediation is `rea doctor` (the environment checks pass in this setup). ### Impact and scope Observed on one synthetic file and two providers. Real-world frequency, Windows and Linux behavior, 32-bit and fat Mach-O, and other formats: NOT_ENOUGH_INFO. No data loss or crash; the cost is a misleading diagnosis and an unneeded provider launch. ### REA version Source `3dbe314ad`, package 6.7.0 ### Runtime and platform macOS arm64 (26.6.2), Node 24.18.0 ### Target and artifact context One authored arm64 Mach-O (SHA-256 of the corrupted file `17a49bd7a3826ae84e108793ba9fb06a388a0522fef4f8721301d4548c22a9cb`); no user binary. ### Interface CLI ### Earliest failure stage Setup or provider admission ### Relevant output or evidence Commands actually run are above. For `analyze --provider ghidra`: `code: execution_failure`, `details.provider_id: ghidra`, `operation: read_binary_inventory_summary`, Ghidra stdout "No load spec found for import file: target-17a49bd7a382.bin" and "Import failed for file". For `inspect-macho`: `provider_id: native-macos`, `operation: inspect_macho`, `tool: lipo`, `reason: nonzero-exit`, `exit_code: 1`. ### Analysis or suspected cause Source-derived, not verified by a fix: `parseThinMachO` in `src/domain/binaryTarget.ts` only checks `headerSize + sizeofcmds > fileSize`; it does not validate the load commands themselves. Related: #1189 (truncated Mach-O header admitted, closed) and #5076 (Go inspection reports Evidence for a Mach-O with a misaligned load command).
Author
Owner

@XinwangTao commented on GitHub (Oct 22, 2026):

确认,核心问题是失败归因错误:文件本身结构损坏属于 target_unavailable 范畴,却一路穿透 admission 后以 execution_failure 报"run rea doctor"——这不仅误导用户去排查环境,也让"坏输入"和"真分析失败"在统计与告警上无法区分。控制组(截断/空/文本)都能返回具体原因,唯独这个 case 漏了,说明 admission 的完整性校验对"头有效但 load command 表不可遍历"这条路径没有覆盖;#6155 的修法(admission 时拒绝不可遍历的表)正是把它拉回与其它控制组一致的语义。顺带建议把 ELF 的 program header 越界校验(#6161)和 Mach-O 的 load command 表校验统一成一个"结构完整性前置检查",两种格式共用同一错误分类,后续再加格式也不容易漏。

<!-- gh-comment-id:6330402633 --> @XinwangTao commented on GitHub (Oct 22, 2026): 确认,核心问题是失败归因错误:文件本身结构损坏属于 target_unavailable 范畴,却一路穿透 admission 后以 execution_failure 报"run rea doctor"——这不仅误导用户去排查环境,也让"坏输入"和"真分析失败"在统计与告警上无法区分。控制组(截断/空/文本)都能返回具体原因,唯独这个 case 漏了,说明 admission 的完整性校验对"头有效但 load command 表不可遍历"这条路径没有覆盖;#6155 的修法(admission 时拒绝不可遍历的表)正是把它拉回与其它控制组一致的语义。顺带建议把 ELF 的 program header 越界校验(#6161)和 Mach-O 的 load command 表校验统一成一个"结构完整性前置检查",两种格式共用同一错误分类,后续再加格式也不容易漏。
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#3764
No description provided.