[GH-ISSUE #8378] [Bug] Ghidra startup fails at the macOS Unix socket path boundary #6576

Open
opened 2026-11-01 21:12:22 +00:00 by bsakaguchi · 2 comments
Owner

Originally created by @morluto on GitHub (Oct 31, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8378

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

On macOS arm64 with Ghidra 12.1.4 and JDK 21.0.12.1, a 103-byte absolute Unix-socket path causes the Ghidra bridge to exit before startup. The same input succeeds at 102 bytes and at 104 bytes, where REA chooses a short separate socket root. MCP reports generic execution_failure with doctor advice; captured bridge output says java.net.SocketException: Unix domain path too long.

Reproduction

  1. With the source checkout below, compile or select a small local arm64 Mach-O and configure Ghidra/JDK. The observed fixture was a self-built executable with SHA-256 ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d.
  2. Start REA with a caller-owned TMPDIR whose canonical path makes <TMPDIR>/rea-ghidra-XXXXXX/bridge.sock exactly 102, 103, then 104 UTF-8 bytes. XXXXXX represents the six characters allocated by mkdtemp; calculate bytes rather than character count.
  3. Through MCP, call open_binary with provider_id: ghidra, then list_documents. In separate CLI processes, run rea decompile <target> _evaluate --provider ghidra --format json. On the tested fixture, 102 and 104 succeeded; 103 returned the failure above in both interfaces. Each MCP session closed successfully and the executable hash remained unchanged. The target was not executed.

Expected behavior

Use a socket location accepted by the actual Java bridge at the boundary, retaining private ownership and cleanup, or return a precise recoverable error. A path just below the fallback threshold should not fail while a longer path succeeds via fallback.

Impact and scope

One controlled run per length and interface on one macOS host and ASCII-only paths. Startup fails before analysis; I did not establish frequency in normal environments, Unicode-path behavior, Linux, other JDKs or other Ghidra versions.

REA version

df8ecf959d69c6104c1e1be47f0a91b65490feec (draft #8377; its changes are guidance-only). The Ghidra transport, client and bridge sources are identical to main d54a4661da20382ad8456564a08569fdd24131c5.

Runtime and platform

Node 24.22.1; macOS 26.3 arm64; Ghidra 12.1.4; Homebrew OpenJDK 21.0.12.1.

Target and artifact context

Self-built arm64 Mach-O, read-only static analysis. Separate caller-owned temporary directories were removed after the checks.

Interface

MCP and CLI

Earliest failure stage

Setup or provider admission

Relevant output or evidence

Canonical proposed endpoint bytes MCP list_documents CLI exit Bridge diagnostic
102 success 0 none
103 execution_failure 1 Unix domain path too long
104 success 0 short socket root used

An independent Java NIO ServerSocketChannel.open(UNIX) control on this host bound 100, 101 and 102-byte paths, but rejected 103 and 104 bytes with the same exception. Node's net.createServer().listen reported success for those paths through 104 bytes; I did not use it to establish that connections or path identity were correct at 104 bytes. These are runtime observations, not a cross-platform maximum.

Analysis or suspected cause

Source-derived: createGhidraEndpoint accepts up to 103 bytes on Darwin before allocating the shorter socket root. real-ghidra-boundaries.mjs exercises an over-107-byte path, so that existing real-provider fallback check does not exercise this boundary. The observed JDK limit, not Node's listen result alone, should inform a fix; verify Linux independently rather than assuming its Java boundary.

Additional context

Discovered while building a real selected-project identity regression for #8169. No credentials were recovered or exposed. cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

Originally created by @morluto on GitHub (Oct 31, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8378 ### 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 On macOS arm64 with Ghidra 12.1.4 and JDK 21.0.12.1, a 103-byte absolute Unix-socket path causes the Ghidra bridge to exit before startup. The same input succeeds at 102 bytes and at 104 bytes, where REA chooses a short separate socket root. MCP reports generic `execution_failure` with doctor advice; captured bridge output says `java.net.SocketException: Unix domain path too long`. ### Reproduction 1. With the source checkout below, compile or select a small local arm64 Mach-O and configure Ghidra/JDK. The observed fixture was a self-built executable with SHA-256 `ffad1b70c6a5a7ef3f7c3f59126be516520210777d949b35e97c9067f272aa2d`. 2. Start REA with a caller-owned `TMPDIR` whose **canonical** path makes `<TMPDIR>/rea-ghidra-XXXXXX/bridge.sock` exactly 102, 103, then 104 UTF-8 bytes. `XXXXXX` represents the six characters allocated by `mkdtemp`; calculate bytes rather than character count. 3. Through MCP, call `open_binary` with `provider_id: ghidra`, then `list_documents`. In separate CLI processes, run `rea decompile <target> _evaluate --provider ghidra --format json`. On the tested fixture, 102 and 104 succeeded; 103 returned the failure above in both interfaces. Each MCP session closed successfully and the executable hash remained unchanged. The target was not executed. ### Expected behavior Use a socket location accepted by the actual Java bridge at the boundary, retaining private ownership and cleanup, or return a precise recoverable error. A path just below the fallback threshold should not fail while a longer path succeeds via fallback. ### Impact and scope One controlled run per length and interface on one macOS host and ASCII-only paths. Startup fails before analysis; I did not establish frequency in normal environments, Unicode-path behavior, Linux, other JDKs or other Ghidra versions. ### REA version `df8ecf959d69c6104c1e1be47f0a91b65490feec` (draft #8377; its changes are guidance-only). The Ghidra transport, client and bridge sources are identical to main `d54a4661da20382ad8456564a08569fdd24131c5`. ### Runtime and platform Node 24.22.1; macOS 26.3 arm64; Ghidra 12.1.4; Homebrew OpenJDK 21.0.12.1. ### Target and artifact context Self-built arm64 Mach-O, read-only static analysis. Separate caller-owned temporary directories were removed after the checks. ### Interface MCP and CLI ### Earliest failure stage Setup or provider admission ### Relevant output or evidence | Canonical proposed endpoint bytes | MCP `list_documents` | CLI exit | Bridge diagnostic | | --- | --- | --- | --- | | 102 | success | 0 | none | | 103 | `execution_failure` | 1 | `Unix domain path too long` | | 104 | success | 0 | short socket root used | An independent Java NIO `ServerSocketChannel.open(UNIX)` control on this host bound 100, 101 and 102-byte paths, but rejected 103 and 104 bytes with the same exception. Node's `net.createServer().listen` reported success for those paths through 104 bytes; I did not use it to establish that connections or path identity were correct at 104 bytes. These are runtime observations, not a cross-platform maximum. ### Analysis or suspected cause Source-derived: [`createGhidraEndpoint`](https://github.com/morluto/rea/blob/d54a4661da20382ad8456564a08569fdd24131c5/src/ghidra/GhidraTransport.ts#L33-L60) accepts up to 103 bytes on Darwin before allocating the shorter socket root. [`real-ghidra-boundaries.mjs`](https://github.com/morluto/rea/blob/d54a4661da20382ad8456564a08569fdd24131c5/scripts/lib/real-ghidra-boundaries.mjs#L124-L133) exercises an over-107-byte path, so that existing real-provider fallback check does not exercise this boundary. The observed JDK limit, not Node's `listen` result alone, should inform a fix; verify Linux independently rather than assuming its Java boundary. ### Additional context Discovered while building a real selected-project identity regression for #8169. No credentials were recovered or exposed. cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Source-derived follow-up: upstream OpenJDK 21u's nio_util.h defines its Unix-domain path maximum as sizeof(sun_path) - 2, and UnixDomainSockets.c rejects longer byte arrays before bind. This is consistent with the 102-byte maximum observed on the tested Mac and explains why the native sockaddr's terminating-NUL allowance alone is not the Java limit.

The source suggests the same extra-byte distinction matters on Linux, but I have not run the REA or Java boundary test there, and I have not established the exact source commit used to build the installed Homebrew JDK. Keep those as source-based reasoning and an unverified runtime scope, respectively.

<!-- gh-comment-id:6549578976 --> @morluto commented on GitHub (Oct 31, 2026): Source-derived follow-up: upstream OpenJDK 21u's [`nio_util.h`](https://github.com/openjdk/jdk21u/blob/ccb06ed8ec75927d88ff859a9198a7ea72f698b6/src/java.base/unix/native/libnio/ch/nio_util.h#L51-L55) defines its Unix-domain path maximum as `sizeof(sun_path) - 2`, and [`UnixDomainSockets.c`](https://github.com/openjdk/jdk21u/blob/ccb06ed8ec75927d88ff859a9198a7ea72f698b6/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c) rejects longer byte arrays before `bind`. This is consistent with the 102-byte maximum observed on the tested Mac and explains why the native sockaddr's terminating-NUL allowance alone is not the Java limit. The source suggests the same extra-byte distinction matters on Linux, but I have not run the REA or Java boundary test there, and I have not established the exact source commit used to build the installed Homebrew JDK. Keep those as source-based reasoning and an unverified runtime scope, respectively.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

I tested a candidate that selects the existing short private socket root above OpenJDK's sizeof(sun_path) - 2 limit. On this macOS/Ghidra 12.1.4/JDK 21 host, a new real-provider MCP check succeeded at 102 bytes in the original runtime root and at 103 and 104 bytes using the short root. A separate 103-byte path containing 雪 also selected the short root based on UTF-8 bytes; CLI analysis at the boundary succeeded. The test verified private fallback permissions, cleanup, and an unchanged target hash. The same check failed on the original implementation at the 103-byte MCP request.

The candidate also uses the source-derived 106-byte OpenJDK limit for Linux's 108-byte sun_path. Linux runtime verification is still unavailable here; the real-provider regression is written to exercise its corresponding 106/107/108-byte cases on a Linux Ghidra lane rather than claiming those were run.

<!-- gh-comment-id:6549818870 --> @morluto commented on GitHub (Oct 31, 2026): I tested a candidate that selects the existing short private socket root above OpenJDK's `sizeof(sun_path) - 2` limit. On this macOS/Ghidra 12.1.4/JDK 21 host, a new real-provider MCP check succeeded at 102 bytes in the original runtime root and at 103 and 104 bytes using the short root. A separate 103-byte path containing `雪` also selected the short root based on UTF-8 bytes; CLI analysis at the boundary succeeded. The test verified private fallback permissions, cleanup, and an unchanged target hash. The same check failed on the original implementation at the 103-byte MCP request. The candidate also uses the source-derived 106-byte OpenJDK limit for Linux's 108-byte `sun_path`. Linux runtime verification is still unavailable here; the real-provider regression is written to exercise its corresponding 106/107/108-byte cases on a Linux Ghidra lane rather than claiming those were run.
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#6576
No description provided.