[GH-ISSUE #4763] [Bug] NativeAOT parser accepts ambiguous PE virtual mapping ownership #2478

Closed
opened 2026-10-17 21:05:23 +00:00 by bsakaguchi · 1 comment
Owner

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

Area

Native analysis or decompilation

Observed behavior

At9c56d09c0, five tiny public-parser controls fail. A PE containing an overlapping zero-filled virtual section reports complete NativeAOT recovery with3MethodTables when that section follows .rdata, but partial recovery with0MethodTables when it precedes .rdata. Contradictory SizeOfHeaders values0x100 and0xb00 also produce complete recovery with3MethodTables;0x4000 produces partial recovery instead of identifying an unsupported image layout.

Reproduction

Executed src/domain/native/nativeAotPe.sectionRanges.test.ts selecting all5cases with pinned Node24.18.0/Vitest;5failed. Inputs are2560-byte authored PE/RTR buffers derived from tests/fixtures/nativeaotPe.ts, each with its independently recomputed SHA-256. For overlapping mappings, add a third .bss section with RVA0x2000,VirtualSize0x400,SizeOfRawData0, then vary its placement before/after .rdata. For header extents, change SizeOfHeaders to each value above. Invoke parseNativeAotPe; assert unsupported-layout before metadata recovery. The added third header fits within the original0x400 header extent. No executable, native engine or OS loader was launched.

Expected behavior

The read-only interpretation should establish one consistent virtual owner before scanning or hydration. Unsupported/ambiguous layouts should retain the artifact digest and an unsupported-layout reason, without choosing bytes or attributes by section-table order or producing recovered type details. Header extent must contain the actual header tables and fit both captured bytes and SizeOfImage. Zero-extent sections, adjacent virtual intervals, raw padding and legitimate zero-filled virtual tails should retain their existing distinct semantics.

Microsoft's PE documentation defines the section virtual/file extents and SizeOfHeaders as the combined header extent, while SizeOfImage includes headers: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format . This report proposes a conservative offline parser support policy; it does not claim runtime reproduction or uniform Windows-loader rejection of unusual layouts.

Impact and scope

Observed source-derived metadata changes based on ambiguous table ordering in two authored layouts; two inconsistent header layouts falsely reach complete recovery. Natural artifact incidence, real Ghidra behavior and Windows compatibility:NOT_ENOUGH_INFO. Source reason: PeImage validates each section separately, but read/virtualBytesRemaining choose a first section, isExecutable searches any section, and directory discovery directly scans section raw ranges. No unique header/section ownership invariant ties them together.

REA version / Runtime and platform

REA6.5.0,source9c56d09c05356c74a7000e4c558ac293639ea33f;Node24.18.0,macOS arm64.

Target and artifact context

Authored2560-byte x64 PE32+/RTR9.1 fixture; no private executable or environment data.

Interface / Earliest failure stage

Other:public domain parser shared by NativeAOT provider enrichment / metadata mapping and layout admission.

Relevant output or evidence

before-data overlap:status partial,MethodTables0,basis raw-image-pointer-scan.
after-data overlap:status complete,MethodTables3,basis raw-image-and-rehydrated-pointer-scan.
SizeOfHeaders0x100/0xb00:complete,3types;0x4000:partial,0types.
All5expected unsupported-layout controls fail. Input-byte immutability is also checked after refusal in the retained control.

Validate complete header ownership and nonempty virtual intervals once in PeImage, before exposing sections to scans/reads/overlay consumers; preserve empty ranges and existing file-backed-vs-virtual semantics. Update the parser profile revision because its interpretation changes.

Open/all-state NativeAOT mapping and PE overlap issues plus open PRs were reviewed. #4750 and PR#4760 concern individual pointer/optional-header read bounds, not constructor-wide mapping ownership. Existing PE resource/managed readers have their own overlap policies; their provider-specific modules must not be imported into this domain parser. #4445/PR#4559 concerns work budgets, separate from this finding.

Originally created by @morluto on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4763 ### Area Native analysis or decompilation ### Observed behavior At9c56d09c0, five tiny public-parser controls fail. A PE containing an overlapping zero-filled virtual section reports complete NativeAOT recovery with3MethodTables when that section follows .rdata, but partial recovery with0MethodTables when it precedes .rdata. Contradictory SizeOfHeaders values0x100 and0xb00 also produce complete recovery with3MethodTables;0x4000 produces partial recovery instead of identifying an unsupported image layout. ### Reproduction Executed src/domain/native/nativeAotPe.sectionRanges.test.ts selecting all5cases with pinned Node24.18.0/Vitest;5failed. Inputs are2560-byte authored PE/RTR buffers derived from tests/fixtures/nativeaotPe.ts, each with its independently recomputed SHA-256. For overlapping mappings, add a third .bss section with RVA0x2000,VirtualSize0x400,SizeOfRawData0, then vary its placement before/after .rdata. For header extents, change SizeOfHeaders to each value above. Invoke parseNativeAotPe; assert unsupported-layout before metadata recovery. The added third header fits within the original0x400 header extent. No executable, native engine or OS loader was launched. ### Expected behavior The read-only interpretation should establish one consistent virtual owner before scanning or hydration. Unsupported/ambiguous layouts should retain the artifact digest and an unsupported-layout reason, without choosing bytes or attributes by section-table order or producing recovered type details. Header extent must contain the actual header tables and fit both captured bytes and SizeOfImage. Zero-extent sections, adjacent virtual intervals, raw padding and legitimate zero-filled virtual tails should retain their existing distinct semantics. Microsoft's PE documentation defines the section virtual/file extents and SizeOfHeaders as the combined header extent, while SizeOfImage includes headers: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format . This report proposes a conservative offline parser support policy; it does not claim runtime reproduction or uniform Windows-loader rejection of unusual layouts. ### Impact and scope Observed source-derived metadata changes based on ambiguous table ordering in two authored layouts; two inconsistent header layouts falsely reach complete recovery. Natural artifact incidence, real Ghidra behavior and Windows compatibility:NOT_ENOUGH_INFO. Source reason: PeImage validates each section separately, but read/virtualBytesRemaining choose a first section, isExecutable searches any section, and directory discovery directly scans section raw ranges. No unique header/section ownership invariant ties them together. ### REA version / Runtime and platform REA6.5.0,source9c56d09c05356c74a7000e4c558ac293639ea33f;Node24.18.0,macOS arm64. ### Target and artifact context Authored2560-byte x64 PE32+/RTR9.1 fixture; no private executable or environment data. ### Interface / Earliest failure stage Other:public domain parser shared by NativeAOT provider enrichment / metadata mapping and layout admission. ### Relevant output or evidence before-data overlap:status partial,MethodTables0,basis raw-image-pointer-scan. after-data overlap:status complete,MethodTables3,basis raw-image-and-rehydrated-pointer-scan. SizeOfHeaders0x100/0xb00:complete,3types;0x4000:partial,0types. All5expected unsupported-layout controls fail. Input-byte immutability is also checked after refusal in the retained control. ### Analysis / Related work Validate complete header ownership and nonempty virtual intervals once in PeImage, before exposing sections to scans/reads/overlay consumers; preserve empty ranges and existing file-backed-vs-virtual semantics. Update the parser profile revision because its interpretation changes. Open/all-state NativeAOT mapping and PE overlap issues plus open PRs were reviewed. #4750 and PR#4760 concern individual pointer/optional-header read bounds, not constructor-wide mapping ownership. Existing PE resource/managed readers have their own overlap policies; their provider-specific modules must not be imported into this domain parser. #4445/PR#4559 concerns work budgets, separate from this finding.
bsakaguchi 2026-10-17 21:05:23 +00:00
  • closed this issue
  • added the
    triage
    bug
    labels
Author
Owner

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

Fixed on main in 3fc007534b.

Root cause: section scans, virtual reads and executable-permission checks could assign different owners to overlapping virtual bytes. PeImage now establishes unique virtual ownership once, before those consumers run. It also rejects contradictory captured header extents, PE/DOS header reuse and image intervals beyond the unsigned 64-bit address domain. Empty/adjacent sections, source order and raw padding retain their existing semantics. The metadata profile revision advances to v5.

Validation: the original five malformed-layout controls failed on 9c56d09c0. The final suite passed 37 parser checks (including additional DOS/64-bit controls) and 35 selected provider checks (87 deselected). Provider controls retain source identity and cached refusals without fabricated type details. check:fast, build:cached, commit and pre-push checks passed. Two scoped source reviews reported no remaining blocker.

Six completed summary-plus-type-detail tasks on the same authored 2,560-byte fixture returned byte-identical 791-token replies. Baseline/candidate warm medians: elapsed 0.030700/0.030692 seconds; CPU 0.025595/0.024649 seconds; OS peak RSS 53,207,040/52,920,320 bytes (one Node process, no children). First processes were recorded separately from two alternating warm repeats. These tiny samples establish no speed improvement; full-agent/catalog tokens, real engines, large inputs and failure-path costs remain unmeasured. Provider profile replies intentionally change revision.

Scope: conservative offline-parser admission, informed by the Microsoft PE format specification. Context7 Node Buffer documentation and supplemental DeepWiki research were checked against source and executed controls. No Windows loader or real Ghidra/target execution was performed. Broader hydration semantics remain outside this fix. Heavy profiling/stress remains stopped.

<!-- gh-comment-id:6233134318 --> @morluto commented on GitHub (Oct 17, 2026): Fixed on main in 3fc007534bb2104d662b43cc712281f9d1d6a7d3. Root cause: section scans, virtual reads and executable-permission checks could assign different owners to overlapping virtual bytes. `PeImage` now establishes unique virtual ownership once, before those consumers run. It also rejects contradictory captured header extents, PE/DOS header reuse and image intervals beyond the unsigned 64-bit address domain. Empty/adjacent sections, source order and raw padding retain their existing semantics. The metadata profile revision advances to v5. Validation: the original five malformed-layout controls failed on 9c56d09c0. The final suite passed 37 parser checks (including additional DOS/64-bit controls) and 35 selected provider checks (87 deselected). Provider controls retain source identity and cached refusals without fabricated type details. `check:fast`, `build:cached`, commit and pre-push checks passed. Two scoped source reviews reported no remaining blocker. Six completed summary-plus-type-detail tasks on the same authored 2,560-byte fixture returned byte-identical 791-token replies. Baseline/candidate warm medians: elapsed 0.030700/0.030692 seconds; CPU 0.025595/0.024649 seconds; OS peak RSS 53,207,040/52,920,320 bytes (one Node process, no children). First processes were recorded separately from two alternating warm repeats. These tiny samples establish no speed improvement; full-agent/catalog tokens, real engines, large inputs and failure-path costs remain unmeasured. Provider profile replies intentionally change revision. Scope: conservative offline-parser admission, informed by the [Microsoft PE format specification](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format). Context7 Node Buffer documentation and supplemental DeepWiki research were checked against source and executed controls. No Windows loader or real Ghidra/target execution was performed. Broader hydration semantics remain outside this fix. Heavy profiling/stress remains stopped.
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#2478
No description provided.