[GH-ISSUE #6869] [Bug] inspect-elf-notes treats compressed note sections as malformed input #4207

Closed
opened 2026-10-31 00:47:43 +00:00 by bsakaguchi · 0 comments
Owner

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

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

The source-built inspect-elf-notes command rejects a valid ELF object after GNU objcopy compresses its non-allocated SHT_NOTE section. It returns invalid_request / invalid_input with ELF note entry exceeds its table. The same object before compression succeeds.

This is a local fixture; no executable target or network traffic was run.

Reproduction

From a checkout of the revision below, install locked dependencies with npm ci and build with npm run build:cached. Then run:

probe=$(mktemp -d)
cat > "$probe/notes.s" <<'ASM'
.section .debug.notes,"",@note
.balign 4
.long 4
.long 256
.long 3
.asciz "GNU"
.rept 256
.byte 0x2a
.endr
.balign 4
ASM
as --64 -o "$probe/plain.o" "$probe/notes.s"
objcopy --compress-debug-sections=zlib "$probe/plain.o" "$probe/compressed.o"
node scripts/rea.mjs inspect-elf-notes "$probe/plain.o" --format json
node scripts/rea.mjs inspect-elf-notes "$probe/compressed.o" --format json
objcopy --decompress-debug-sections "$probe/compressed.o" "$probe/restored.o"
cmp "$probe/plain.o" "$probe/restored.o"

Observed once for each CLI input before writing this report: plain exits 0; compressed exits 1; the independent objcopy decompression round trip compares byte-for-byte equal (exit 0).

Expected behavior

Recognize SHF_COMPRESSED before interpreting the section payload. Either decode the section using its compression header and retain correct provenance, or return a typed unsupported-compression outcome. Do not describe a valid compression header as a malformed note or tell the caller to correct the input.

The ELF gABI compression contract defines the compression header and its uncompressed size/alignment. The fixture is non-allocated SHT_NOTE, not SHT_NOBITS.

Impact and scope

Offline note inspection fails for this valid compressed object, including the other ordinary note section in the same object. Verified on one generated ELF64 little-endian x86-64 relocatable object. Other classes, byte orders, compression algorithms and real-world prevalence are untested.

A verified workaround is to inspect a separate copy made with objcopy --decompress-debug-sections; the original need not be modified.

REA version

Source main commit 3e7e102a518b9112a2a8aa0590ae6f6951fd0635 (package.json: 6.7.0). Both CLI calls used node scripts/rea.mjs from that clone, not an installed REA package.

Runtime and platform

Node.js v26.12.1; Linux x86_64 (kernel 7.2.8-9-omarchy, glibc 2.44); GNU assembler/objcopy 2.47. The source build ran under the checkout-pinned Node.js v24.22.1.

Target and artifact context

Benign generated ELF64 ET_REL. GNU objcopy emits a 48-byte .debug.notes section with SHF_COMPRESSED = 0x800, ch_type = 1 (zlib), ch_size = 272, and ch_addralign = 4. Independent Python zlib decoding recovered the 272-byte note with namesz = 4, descsz = 256, type = 3.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Compressed CLI result, reduced:

{
  "code": "invalid_request",
  "category": "invalid_input",
  "details": {
    "operation": "inspect_elf_notes",
    "issues": [{
      "path": ["path"],
      "reason": "invalid_format",
      "message": "ELF note entry exceeds its table."
    }]
  }
}

The uncompressed CLI result contains GNU build-id and GNU property note entries. The compression round trip above verifies the object was transformed reversibly.

Typed outcome or recovery expected

A compression-specific unsupported-target result if compressed note decoding is outside the supported profile, rather than invalid-input recovery for path.

Analysis or suspected cause

Source-derived: the SHT_NOTE loop passes the on-disk compressed section directly to parseNoteStream and uses sh_addralign, without consulting sh_flags or the compression header. Compression handling earlier in this file applies only to the section-name table.

Additional context

Related #6692 concerns a compressed section-name table; this fixture leaves .shstrtab uncompressed and compresses the note section itself.

Last known good: NOT_ENOUGH_INFO; no historical comparison was run. Prepared with AI assistance. No fix or source changes are included.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A valid, reversibly compressed ELF object fails public offline note inspection and receives incorrect malformed-input guidance.
  • Workaround status: available
  • Workaround basis: GNU objcopy decompressed a separate copy back to the exact original bytes, and the uncompressed original succeeded in the recorded CLI run.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6869 ## 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 The source-built `inspect-elf-notes` command rejects a valid ELF object after GNU objcopy compresses its non-allocated `SHT_NOTE` section. It returns `invalid_request` / `invalid_input` with `ELF note entry exceeds its table.` The same object before compression succeeds. This is a local fixture; no executable target or network traffic was run. ## Reproduction From a checkout of the revision below, install locked dependencies with `npm ci` and build with `npm run build:cached`. Then run: ```sh probe=$(mktemp -d) cat > "$probe/notes.s" <<'ASM' .section .debug.notes,"",@note .balign 4 .long 4 .long 256 .long 3 .asciz "GNU" .rept 256 .byte 0x2a .endr .balign 4 ASM as --64 -o "$probe/plain.o" "$probe/notes.s" objcopy --compress-debug-sections=zlib "$probe/plain.o" "$probe/compressed.o" node scripts/rea.mjs inspect-elf-notes "$probe/plain.o" --format json node scripts/rea.mjs inspect-elf-notes "$probe/compressed.o" --format json objcopy --decompress-debug-sections "$probe/compressed.o" "$probe/restored.o" cmp "$probe/plain.o" "$probe/restored.o" ``` Observed once for each CLI input before writing this report: plain exits 0; compressed exits 1; the independent objcopy decompression round trip compares byte-for-byte equal (exit 0). ## Expected behavior Recognize `SHF_COMPRESSED` before interpreting the section payload. Either decode the section using its compression header and retain correct provenance, or return a typed unsupported-compression outcome. Do not describe a valid compression header as a malformed note or tell the caller to correct the input. The [ELF gABI compression contract](https://gabi.xinuos.com/v42/elf/03-sheader.html#compressed-sections) defines the compression header and its uncompressed size/alignment. The fixture is non-allocated `SHT_NOTE`, not `SHT_NOBITS`. ## Impact and scope Offline note inspection fails for this valid compressed object, including the other ordinary note section in the same object. Verified on one generated ELF64 little-endian x86-64 relocatable object. Other classes, byte orders, compression algorithms and real-world prevalence are untested. A verified workaround is to inspect a separate copy made with `objcopy --decompress-debug-sections`; the original need not be modified. ## REA version Source `main` commit `3e7e102a518b9112a2a8aa0590ae6f6951fd0635` (`package.json`: 6.7.0). Both CLI calls used `node scripts/rea.mjs` from that clone, not an installed REA package. ## Runtime and platform Node.js v26.12.1; Linux x86_64 (kernel 7.2.8-9-omarchy, glibc 2.44); GNU assembler/objcopy 2.47. The source build ran under the checkout-pinned Node.js v24.22.1. ## Target and artifact context Benign generated ELF64 ET_REL. GNU objcopy emits a 48-byte `.debug.notes` section with `SHF_COMPRESSED = 0x800`, `ch_type = 1` (zlib), `ch_size = 272`, and `ch_addralign = 4`. Independent Python zlib decoding recovered the 272-byte note with `namesz = 4`, `descsz = 256`, `type = 3`. ## Interface CLI ## Earliest failure stage Native analysis or reconstruction ## Relevant output or evidence Compressed CLI result, reduced: ```json { "code": "invalid_request", "category": "invalid_input", "details": { "operation": "inspect_elf_notes", "issues": [{ "path": ["path"], "reason": "invalid_format", "message": "ELF note entry exceeds its table." }] } } ``` The uncompressed CLI result contains GNU build-id and GNU property note entries. The compression round trip above verifies the object was transformed reversibly. ## Typed outcome or recovery expected A compression-specific unsupported-target result if compressed note decoding is outside the supported profile, rather than invalid-input recovery for `path`. ## Analysis or suspected cause Source-derived: the [SHT_NOTE loop](https://github.com/morluto/rea/blob/3e7e102a518b9112a2a8aa0590ae6f6951fd0635/src/native/elf/ElfNoteParser.ts#L415-L439) passes the on-disk compressed section directly to `parseNoteStream` and uses `sh_addralign`, without consulting `sh_flags` or the compression header. Compression handling earlier in this file applies only to the section-name table. ## Additional context Related [#6692](https://github.com/morluto/rea/issues/6692) concerns a compressed section-name table; this fixture leaves `.shstrtab` uncompressed and compresses the note section itself. Last known good: `NOT_ENOUGH_INFO`; no historical comparison was run. Prepared with AI assistance. No fix or source changes are included. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: A valid, reversibly compressed ELF object fails public offline note inspection and receives incorrect malformed-input guidance. - Workaround status: available - Workaround basis: GNU objcopy decompressed a separate copy back to the exact original bytes, and the uncompressed original succeeded in the recorded CLI 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#4207
No description provided.