Summary
When fdt_next_tag() traverses a malformed Flattened Device Tree (FDT) blob, it computes a structure-block offset from an attacker-controlled tag/length field without adequate bounds checking. On a crafted input the running offset is driven to a near-INT_MIN value, and the subsequent offset - startoffset computation overflows signed int, which is undefined behavior. UBSan reports the fault as fatal. This is reachable through the public libfdt traversal API on any untrusted FDT blob.
Note: the actual fault is a signed-integer-overflow, not a misaligned access.
Confirmed reproducing on current main (HEAD 66e1201, 2026-06-17).
Root Cause
fdt_next_tag() advances offset based on the parsed tag and an attacker-controlled length, then computes offset - startoffset to validate the consumed region. Because offset can be pushed to a very large negative value via the crafted length, this subtraction overflows the signed int range.
libfdt/fdt.c (fdt_next_tag, around line 216):
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
{
const fdt32_t *tagp, *lenp;
uint32_t tag, len, sum;
int offset = startoffset;
...
case FDT_PROP:
...
len = fdt32_to_cpu(*lenp);
sum = len + offset;
if (!can_assume(VALID_DTB) &&
(INT_MAX <= sum || sum < (uint32_t) offset))
return FDT_END; /* premature end */
/* skip-name offset, length and value */
offset += sizeof(struct fdt_property) - FDT_TAGSIZE + len;
...
}
if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) // line 216: offset - startoffset overflows int
return FDT_END; /* premature end */
*nextoffset = FDT_TAGALIGN(offset);
return tag;
}
The overflow occurs in the offset - startoffset expression on line 216 (column 47).
PoC
A 60-byte crafted FDT blob (poc.bin) that drives offset to a near-INT_MIN value when parsed by the libfdt traversal API.
Reproduction
Build libfdt from source with UBSan and traverse the attached blob through the public FDT API
(fdt_next_tag is reached by any traversal, e.g. fdt_first_subnode/fdt_next_node):
clang -fsanitize=undefined -fno-sanitize-recover -Ilibfdt -c libfdt/fdt*.c
# then call fdt_next_tag()/fdt_first_subnode() over poc.bin (recreate it from the base64 below)
Output:
libfdt/fdt.c:224:47: runtime error: signed integer overflow: -2147483642 - 8 cannot be represented in type 'int'
Confirmed on current main (HEAD 66e1201, 2026-06-17).
Suggested Fix
Perform the offset arithmetic and the consumed-region length using unsigned/wider types and bounds-check before subtraction, so that offset - startoffset can never overflow signed int. Reject the blob (return FDT_END) when the computed offset is out of the valid [startoffset, INT_MAX] range instead of forming the difference in int.
PoC bytes (self-contained)
The trigger input is 60 bytes (poc/poc.bin).
Recreate it exactly with:
base64 -d > poc.bin <<'B64'
0A3+7X////8AAAAoAAAAPAAAACgAAAARAAAAEAAAAAAAAAAAf///1wAAAAEAAAAAAAAAA3////IAAAAA
B64
Hex: d00dfeed7fffffff000000280000003c00000028000000110000001000000000000000007fffffd70000000100000000000000037ffffff200000000
Credit
Aisle Research (Ze Sheng (O2Lab & TAMU), Dmitrijs Trizna, Luigino Camastra, Guido Vranken).
Summary
When
fdt_next_tag()traverses a malformed Flattened Device Tree (FDT) blob, it computes a structure-block offset from an attacker-controlled tag/length field without adequate bounds checking. On a crafted input the runningoffsetis driven to a near-INT_MINvalue, and the subsequentoffset - startoffsetcomputation overflows signedint, which is undefined behavior. UBSan reports the fault as fatal. This is reachable through the public libfdt traversal API on any untrusted FDT blob.Note: the actual fault is a signed-integer-overflow, not a misaligned access.
Confirmed reproducing on current
main(HEAD66e1201, 2026-06-17).Root Cause
fdt_next_tag()advancesoffsetbased on the parsed tag and an attacker-controlled length, then computesoffset - startoffsetto validate the consumed region. Becauseoffsetcan be pushed to a very large negative value via the crafted length, this subtraction overflows the signedintrange.libfdt/fdt.c(fdt_next_tag, around line 216):The overflow occurs in the
offset - startoffsetexpression on line 216 (column 47).PoC
A 60-byte crafted FDT blob (
poc.bin) that drivesoffsetto a near-INT_MINvalue when parsed by the libfdt traversal API.Reproduction
Build libfdt from source with UBSan and traverse the attached blob through the public FDT API
(
fdt_next_tagis reached by any traversal, e.g.fdt_first_subnode/fdt_next_node):Output:
Confirmed on current
main(HEAD66e1201, 2026-06-17).Suggested Fix
Perform the offset arithmetic and the consumed-region length using unsigned/wider types and bounds-check before subtraction, so that
offset - startoffsetcan never overflow signedint. Reject the blob (returnFDT_END) when the computedoffsetis out of the valid[startoffset, INT_MAX]range instead of forming the difference inint.PoC bytes (self-contained)
The trigger input is 60 bytes (
poc/poc.bin).Recreate it exactly with:
Hex:
d00dfeed7fffffff000000280000003c00000028000000110000001000000000000000007fffffd70000000100000000000000037ffffff200000000Credit
Aisle Research (Ze Sheng (O2Lab & TAMU), Dmitrijs Trizna, Luigino Camastra, Guido Vranken).