[GH-ISSUE #7315] [Bug] Empty strings block at the reservation boundary rejects a valid DTB #4345

Open
opened 2026-10-31 00:49:05 +00:00 by bsakaguchi · 0 comments
Owner

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

Before submitting

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

Area

Evidence, artifacts, or reconstruction

Observed behavior

The public inspect-devicetree CLI rejects an encoding-valid 72-byte DTB when its zero-length strings block starts at the memory-reservation block's offset. It exits 1 with invalid_request and Unterminated or overlapping FDT reservation block, although the aligned reservation terminator is present. I reproduced this once for each supported FDT version, 16 and 17. Changing only the unused strings offset to EOF makes both files succeed.

Reproduction

From a built checkout, generate the tested v17 bytes and the passing control, then invoke the public launcher:

python3 - <<'PYTHON'
from pathlib import Path
import struct
blob = struct.pack('>10I', 0xd00dfeed, 72, 40, 56, 56, 17, 16, 0, 0, 16)
blob += struct.pack('>4I', 1, 0, 2, 9) + bytes(16)
Path('empty-strings.dtb').write_bytes(blob)
control = bytearray(blob)
struct.pack_into('>I', control, 12, len(control))
Path('empty-strings-eof.dtb').write_bytes(control)
PYTHON
node scripts/rea.mjs inspect-devicetree empty-strings.dtb --json
node scripts/rea.mjs inspect-devicetree empty-strings-eof.dtb --json

I ran these inspections against independently generated equivalent fixtures in an isolated working directory using the checkout's built public launcher. The first fails; the control exits 0 and reports complete coverage, one root node, no properties and no reservations. Both files differ only at byte offset 15. Standard-order and reordered nonempty-strings controls also passed for both versions: eight CLI calls total, all with empty stderr. No target code or external provider runs.

Expected behavior

Inspect the valid tree and return complete Evidence for both files. DTSpec v0.4 defines the usual block order as recommended, with its conventions explicitly allowing alternatives; the strings block may appear at any offset. An empty block occupies no bytes. REA documents v16/v17 inspection without restricting block order, and the passing reordered control establishes that this order is already accepted.

Impact and scope

This bounded case prevents inspection of an otherwise readable DTB. The demonstrated inputs are synthetic; frequency among producer-generated or real-device blobs is unknown. Retain the original and inspect a copy whose unused empty-strings offset points to EOF as a demonstrated workaround. Its tree and reservation bytes remain identical, but its artifact digest changes.

REA version

6.8.0; source revision 3233992733.

Runtime and platform

The verification preflight specifies Node.js v24.22.1; the CLI ran on macOS arm64 without Hopper, Ghidra or dtc. NOT_ENOUGH_INFO: the OS release was not collected.

Target and artifact context

Synthetic standalone FDT v16/v17 files. In the failing v17 case, the header occupies bytes 0–39, the 16-byte root structure starts at 40, and the 16-byte zero reservation terminator starts at 56. The empty strings extent is [56,56). All nonempty extents are disjoint and correctly aligned. No hardware-binding validity is claimed.

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

The failing JSON contains:

{"code":"invalid_request","details":{"operation":"inspect_devicetree","issues":[{"path":["path"],"reason":"invalid_format","message":"Unterminated or overlapping FDT reservation block"}]}}
  • Expected source: docs/devicetree.md:3–7; published DTSpec v0.4 conventions and flattened-format chapter, especially block ordering, reservation termination, tree structure and strings placement.
  • Failure source: The executed public CLI results above; src/firmware/devicetree/DevicetreeParser.ts:102–110 computes the reservation boundary from the empty strings offset, and src/firmware/devicetree/DevicetreeProvider.ts:98–112 maps the resulting format failure to an input issue.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

Typed outcome or recovery expected

Return successful complete DTB Evidence with the root node and empty reservation list for the original fixture, while continuing to reject actual overlap and unterminated reservation data. The EOF-offset and standard-order controls should remain successful.

Analysis or suspected cause

Source-derived: with the original fixture, reservationEnd equals 56 because the strings offset is included despite its zero size. The scan checks whether cursor 56 exceeds 56 minus 16 and rejects before reading the valid terminator. The passing control isolates this boundary calculation from block order and tree content.

Additional context

The v16 case uses a 36-byte header plus four padding bytes and the same structure and reservation offsets; it gives the same failure and passing control. Read-only duplicate searches covered open and closed issues and related PRs. The original DTB feature and the related view-test, CLI-help and FIT-format discussions do not report this boundary failure. NOT_ENOUGH_INFO: the first affected release and prevalence in ordinary producers were not established. MCP was not rerun.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The real CLI refuses valid input for this bounded layout in both supported versions, preventing its inspection; no data loss or broader operational impact was observed.
  • Workaround status: available
  • Workaround basis: The executed EOF-offset controls succeed after changing only the unused strings offset. Inspecting a separate copy preserves the original file and its provenance, while the copy has its own digest.
Originally created by @coygeek on GitHub (Oct 26, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7315 ### 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 Evidence, artifacts, or reconstruction ### Observed behavior The public `inspect-devicetree` CLI rejects an encoding-valid 72-byte DTB when its zero-length strings block starts at the memory-reservation block's offset. It exits 1 with `invalid_request` and `Unterminated or overlapping FDT reservation block`, although the aligned reservation terminator is present. I reproduced this once for each supported FDT version, 16 and 17. Changing only the unused strings offset to EOF makes both files succeed. ### Reproduction From a built checkout, generate the tested v17 bytes and the passing control, then invoke the public launcher: ```sh python3 - <<'PYTHON' from pathlib import Path import struct blob = struct.pack('>10I', 0xd00dfeed, 72, 40, 56, 56, 17, 16, 0, 0, 16) blob += struct.pack('>4I', 1, 0, 2, 9) + bytes(16) Path('empty-strings.dtb').write_bytes(blob) control = bytearray(blob) struct.pack_into('>I', control, 12, len(control)) Path('empty-strings-eof.dtb').write_bytes(control) PYTHON node scripts/rea.mjs inspect-devicetree empty-strings.dtb --json node scripts/rea.mjs inspect-devicetree empty-strings-eof.dtb --json ``` I ran these inspections against independently generated equivalent fixtures in an isolated working directory using the checkout's built public launcher. The first fails; the control exits 0 and reports complete coverage, one root node, no properties and no reservations. Both files differ only at byte offset 15. Standard-order and reordered nonempty-strings controls also passed for both versions: eight CLI calls total, all with empty stderr. No target code or external provider runs. ### Expected behavior Inspect the valid tree and return complete Evidence for both files. DTSpec v0.4 defines the usual block order as recommended, with its conventions explicitly allowing alternatives; the strings block may appear at any offset. An empty block occupies no bytes. REA documents v16/v17 inspection without restricting block order, and the passing reordered control establishes that this order is already accepted. ### Impact and scope This bounded case prevents inspection of an otherwise readable DTB. The demonstrated inputs are synthetic; frequency among producer-generated or real-device blobs is unknown. Retain the original and inspect a copy whose unused empty-strings offset points to EOF as a demonstrated workaround. Its tree and reservation bytes remain identical, but its artifact digest changes. ### REA version 6.8.0; source revision 3233992733c33dabf2de09d22ee4e6d9409f797a. ### Runtime and platform The verification preflight specifies Node.js v24.22.1; the CLI ran on macOS arm64 without Hopper, Ghidra or dtc. NOT_ENOUGH_INFO: the OS release was not collected. ### Target and artifact context Synthetic standalone FDT v16/v17 files. In the failing v17 case, the header occupies bytes 0–39, the 16-byte root structure starts at 40, and the 16-byte zero reservation terminator starts at 56. The empty strings extent is [56,56). All nonempty extents are disjoint and correctly aligned. No hardware-binding validity is claimed. ### Interface CLI ### Earliest failure stage Request parsing or validation ### Relevant output or evidence The failing JSON contains: ```json {"code":"invalid_request","details":{"operation":"inspect_devicetree","issues":[{"path":["path"],"reason":"invalid_format","message":"Unterminated or overlapping FDT reservation block"}]}} ``` - Expected source: `docs/devicetree.md:3–7`; published [DTSpec v0.4 conventions](https://github.com/devicetree-org/devicetree-specification/blob/v0.4/source/chapter1-introduction.rst#L62-L76) and [flattened-format chapter](https://github.com/devicetree-org/devicetree-specification/blob/v0.4/source/chapter5-flattened-format.rst), especially block ordering, reservation termination, tree structure and strings placement. - Failure source: The executed public CLI results above; `src/firmware/devicetree/DevicetreeParser.ts:102–110` computes the reservation boundary from the empty strings offset, and `src/firmware/devicetree/DevicetreeProvider.ts:98–112` maps the resulting format failure to an input issue. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete ### Typed outcome or recovery expected Return successful complete DTB Evidence with the root node and empty reservation list for the original fixture, while continuing to reject actual overlap and unterminated reservation data. The EOF-offset and standard-order controls should remain successful. ### Analysis or suspected cause Source-derived: with the original fixture, `reservationEnd` equals 56 because the strings offset is included despite its zero size. The scan checks whether cursor 56 exceeds 56 minus 16 and rejects before reading the valid terminator. The passing control isolates this boundary calculation from block order and tree content. ### Additional context The v16 case uses a 36-byte header plus four padding bytes and the same structure and reservation offsets; it gives the same failure and passing control. Read-only duplicate searches covered open and closed issues and related PRs. The original DTB feature and the related view-test, CLI-help and FIT-format discussions do not report this boundary failure. NOT_ENOUGH_INFO: the first affected release and prevalence in ordinary producers were not established. MCP was not rerun. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The real CLI refuses valid input for this bounded layout in both supported versions, preventing its inspection; no data loss or broader operational impact was observed. - Workaround status: available - Workaround basis: The executed EOF-offset controls succeed after changing only the unused strings offset. Inspecting a separate copy preserves the original file and its provenance, while the copy has its own digest.
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#4345
No description provided.