[GH-ISSUE #4373] [Bug] Empty header resource mapping skips a section starting at the same RVA #1729

Closed
opened 2026-10-16 21:09:33 +00:00 by bsakaguchi · 0 comments
Owner

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

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

SOURCE-ONLY: The built-in PE resource mapper can return a header-backed file offset for an empty payload whose RVA is also the start of a declared section. It calculates the owning section, then bypasses it in the header branch. This report concerns inconsistent location provenance for an empty range; no incorrect payload-byte read or native loader behavior was observed.

Reproduction

Only defensive source inspection was run. No image was constructed, parsed, loaded, or executed, and no CLI/MCP runtime reproduction is claimed. From a checkout of the main revision listed below, run:

sed -n '37,150p' src/native/pe/PeResourceLayout.ts
sed -n '66,91p;166,199p;255,280p' src/native/pe/PeResourceParser.ts
sed -n '173,191p;335,360p' src/native/pe/PeResourceParser.test.ts
sed -n '22,52p' src/cli/binaryDiagnosticsCommands.ts
cat src/composition/binaryDiagnostics.ts
sed -n '21,56p' src/native/pe/PeResourcesProvider.ts
sed -n '31,82p;99,147p' src/application/binaryDiagnostics/PeResourcesService.ts

Trace an otherwise admitted conventional type/name/language tree with a nonempty resource directory in an ordinary file-backed section, and an empty non-icon leaf with size === 0. Its payload RVA is below SizeOfHeaders and equals another section's start; that section has positive virtual extent, a distinct raw offset after the headers, and no overlapping raw file range. These are source-path premises, not a constructed fixture.

Section admission constrains raw/header overlap but does not exclude that virtual start. containing includes the section because equality at its start is accepted. In the header branch, section.rva < rva + size becomes rva < rva, which is false. If no other section intersects the point, the branch returns the header RVA as the file offset. The parser stores that offset as payload.location with length zero; recordRange omits zero-size ranges from overlap rejection, and service validation only checks that the location fits the artifact. The normal bounded directory and identity checks do not reject these leaf conditions.

The same header predicate and parser projection were inspected in the release source. Its section-end fallback and newer boundary test differ from main; no release test parity is claimed.

Expected behavior

The mapper promises unambiguous file-backed RVA mapping. An empty payload at a declared section start must obey a consistent ownership rule, or return the existing format failure when header and section ownership conflict. It should not silently choose the header location while recognizing that the same RVA belongs to a section.

Impact and scope

The source-derived consequence is a conflicting file offset in static resource location provenance for this zero-length boundary. No resource bytes are read from the wrong location because the length is zero. Frequency in real images, native Windows acceptance, and end-to-end CLI/MCP output are NOT_ENOUGH_INFO. Other payload sizes and ordinary section layouts are outside this report; no security impact is claimed.

REA version

Current main source 8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd; latest published rea-agents@6.5.0 source 3b79af28e80785afce9f5998d8f03289402a1847.

Runtime and platform

Read-only source inspection on macOS arm64. Node.js and native analysis providers were not invoked; platform-specific loader behavior was not exercised.

Target and artifact context

Static PE32/PE32+ resource data entry with zero payload size and an RVA inside SizeOfHeaders equal to a positive-extent section start.

Interface

Other

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Source-derived evidence, inspected locally:

NOT_ENOUGH_INFO for runtime output from this exact image layout. The observations above are a static proof of the branch and projection, not a parser execution.

Typed outcome or recovery expected

A consistent location under the section/header ownership contract, or the existing invalid_format outcome for ambiguous resource header mapping. Preserve support for unambiguous empty resources.

Analysis or suspected cause

Source-derived: the header interval intersection uses a nonempty-interval predicate for a zero-length payload and returns before the calculated section candidates are considered.

Additional context

Related closed issue #3970 covers rejection of an empty payload at a section end. Its follow-up PRs #3997, #4007 and #4155 concern that end-boundary behavior, while #1678 concerns raw padding versus virtual extent. This report concerns the separate header/section-start collision that remains in the current header branch. Proposed restoration check, not run: confirm that this equality case does not silently return a conflicting header location, while an empty unambiguous header payload, an empty ordinary section-start payload, and the existing nonempty header-overlap rejection retain their intended behavior.

Triage assessment

  • Impact level: P2
  • Assessment status: provisional
  • Impact basis: Static proof shows conflicting resource location provenance in a bounded zero-length case. Runtime incidence and downstream use of that offset were not measured; no payload bytes are read.
  • Workaround status: unverified
  • Workaround basis: No equivalent public workflow workaround was exercised; rejecting or ignoring the resource would not preserve the reported location result.
Originally created by @coygeek on GitHub (Oct 16, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4373 ### 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 SOURCE-ONLY: The built-in PE resource mapper can return a header-backed file offset for an empty payload whose RVA is also the start of a declared section. It calculates the owning section, then bypasses it in the header branch. This report concerns inconsistent location provenance for an empty range; no incorrect payload-byte read or native loader behavior was observed. ### Reproduction Only defensive source inspection was run. No image was constructed, parsed, loaded, or executed, and no CLI/MCP runtime reproduction is claimed. From a checkout of the main revision listed below, run: ```sh sed -n '37,150p' src/native/pe/PeResourceLayout.ts sed -n '66,91p;166,199p;255,280p' src/native/pe/PeResourceParser.ts sed -n '173,191p;335,360p' src/native/pe/PeResourceParser.test.ts sed -n '22,52p' src/cli/binaryDiagnosticsCommands.ts cat src/composition/binaryDiagnostics.ts sed -n '21,56p' src/native/pe/PeResourcesProvider.ts sed -n '31,82p;99,147p' src/application/binaryDiagnostics/PeResourcesService.ts ``` Trace an otherwise admitted conventional type/name/language tree with a nonempty resource directory in an ordinary file-backed section, and an empty non-icon leaf with `size === 0`. Its payload RVA is below `SizeOfHeaders` and equals another section's start; that section has positive virtual extent, a distinct raw offset after the headers, and no overlapping raw file range. These are source-path premises, not a constructed fixture. Section admission constrains raw/header overlap but does not exclude that virtual start. `containing` includes the section because equality at its start is accepted. In the header branch, `section.rva < rva + size` becomes `rva < rva`, which is false. If no other section intersects the point, the branch returns the header RVA as the file offset. The parser stores that offset as `payload.location` with length zero; `recordRange` omits zero-size ranges from overlap rejection, and service validation only checks that the location fits the artifact. The normal bounded directory and identity checks do not reject these leaf conditions. The same header predicate and parser projection were inspected in the release source. Its section-end fallback and newer boundary test differ from main; no release test parity is claimed. ### Expected behavior The mapper promises unambiguous file-backed RVA mapping. An empty payload at a declared section start must obey a consistent ownership rule, or return the existing format failure when header and section ownership conflict. It should not silently choose the header location while recognizing that the same RVA belongs to a section. ### Impact and scope The source-derived consequence is a conflicting file offset in static resource location provenance for this zero-length boundary. No resource bytes are read from the wrong location because the length is zero. Frequency in real images, native Windows acceptance, and end-to-end CLI/MCP output are NOT_ENOUGH_INFO. Other payload sizes and ordinary section layouts are outside this report; no security impact is claimed. ### REA version Current main source `8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd`; latest published `rea-agents@6.5.0` source `3b79af28e80785afce9f5998d8f03289402a1847`. ### Runtime and platform Read-only source inspection on macOS arm64. Node.js and native analysis providers were not invoked; platform-specific loader behavior was not exercised. ### Target and artifact context Static PE32/PE32+ resource data entry with zero payload size and an RVA inside SizeOfHeaders equal to a positive-extent section start. ### Interface Other ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence Source-derived evidence, inspected locally: - [Mapper admission, section ownership, and header branch](https://github.com/morluto/rea/blob/8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd/src/native/pe/PeResourceLayout.ts#L37-L150): raw ranges must not overlap headers, while the virtual/header equality case reaches a strict intersection predicate and `return rva`. - [Parser location projection and zero-size overlap handling](https://github.com/morluto/rea/blob/8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd/src/native/pe/PeResourceParser.ts#L66-L199): the declared leaf size reaches `layout.map` unchanged and its result becomes the payload location. - [Existing header ambiguity and empty section-start tests](https://github.com/morluto/rea/blob/8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd/src/native/pe/PeResourceParser.test.ts#L173-L360): these separately encode rejection of section/header ambiguity and section-start ownership for empty payloads. Tests were read, not executed. - [Public CLI entry point](https://github.com/morluto/rea/blob/8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd/src/cli/binaryDiagnosticsCommands.ts#L22-L52), [service composition](https://github.com/morluto/rea/blob/8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd/src/composition/binaryDiagnostics.ts#L1-L10), [built-in provider](https://github.com/morluto/rea/blob/8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd/src/native/pe/PeResourcesProvider.ts#L21-L56), and [service output admission](https://github.com/morluto/rea/blob/8ab5024397ddbd3b37ab68a13cabedc2eb7ce7dd/src/application/binaryDiagnostics/PeResourcesService.ts#L31-L147) establish supported reachability without a provider-specific precondition. - [Release header branch](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/native/pe/PeResourceLayout.ts#L94-L139) retains the same equality gap. NOT_ENOUGH_INFO for runtime output from this exact image layout. The observations above are a static proof of the branch and projection, not a parser execution. ### Typed outcome or recovery expected A consistent location under the section/header ownership contract, or the existing `invalid_format` outcome for ambiguous resource header mapping. Preserve support for unambiguous empty resources. ### Analysis or suspected cause Source-derived: the header interval intersection uses a nonempty-interval predicate for a zero-length payload and returns before the calculated section candidates are considered. ### Additional context Related [closed issue #3970](https://github.com/morluto/rea/issues/3970) covers rejection of an empty payload at a section end. Its follow-up PRs #3997, #4007 and #4155 concern that end-boundary behavior, while #1678 concerns raw padding versus virtual extent. This report concerns the separate header/section-start collision that remains in the current header branch. Proposed restoration check, not run: confirm that this equality case does not silently return a conflicting header location, while an empty unambiguous header payload, an empty ordinary section-start payload, and the existing nonempty header-overlap rejection retain their intended behavior. ## Triage assessment - Impact level: P2 - Assessment status: provisional - Impact basis: Static proof shows conflicting resource location provenance in a bounded zero-length case. Runtime incidence and downstream use of that offset were not measured; no payload bytes are read. - Workaround status: unverified - Workaround basis: No equivalent public workflow workaround was exercised; rejecting or ignoring the resource would not preserve the reported location result.
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#1729
No description provided.