U-Boot — Out-of-Bounds Write in the BMP RLE8 Decoder
U-Boot's RLE8 bitmap decoder does not bound its writes to the framebuffer, so a crafted RLE8-compressed BMP decoded during boot writes past the end of the framebuffer and corrupts adjacent memory inside the bootloader.
- Advisory
- BYTERAY-2026-0213
- CVE
- CVE-2026-71972
- CWE
- CWE-787
- CVSS
- 6.0 (CVSS:4.0/AV:A/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:H/SC:N/SI:N/SA:N); 5.9 (CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H)
- Vendor
- U-Boot
- Product
- U-Boot
- Reported
- 2026-07-29
- Disclosure
- 2026-09-29
- Affected
- U-Boot through 2026.10-rc5
- Fixed in
- Commit 5201e83342d64c2f438ea35158575f28225e752e (in u-boot/next; not yet in a tagged release)
Executive Summary
U-Boot decodes a boot logo or splash image during the boot flow. The decoder for RLE8-compressed BMP images does not bound its writes to the framebuffer, so a crafted image writes past the end of it. The logo is commonly loaded from unsigned, attacker-writable storage and decoded before the next boot stage is authenticated, which places an attacker-controlled memory-corruption primitive inside the component that enforces verified boot.
Affected Products and Versions
- Product: U-Boot, BMP RLE8 decode path in
drivers/video/video_bmp.c(video_display_rle8_bitmap()). - Affected: U-Boot through 2026.10-rc5.
- Fixed: commit
5201e83342d64c2f438ea35158575f28225e752e, present in theu-boot/nextbranch; at the time of writing it is not yet in a tagged release.
Technical Details
video_display_rle8_bitmap() decodes an RLE8-compressed 8-bit BMP straight into
the framebuffer. RLE8 is a sequence of opcodes: a run of one color, a run of
literal bytes, an end-of-line marker, an end-of-bitmap marker, and a delta that
jumps the write cursor. BMP scanlines are stored bottom to top, so the decoder
starts at the bottom row of the framebuffer and walks upward, moving to the next
row on each end-of-line marker.
The write cursor is the pointer fb. The end-of-line handler moves it toward
lower addresses by one row on every marker, and checks no lower bound:
case BMP_RLE8_EOL: /* end of line */
bmap += 2;
x = 0;
y--;
fb -= width * bytes_per_pixel + priv->line_length;
break;
The only bounds check near the writes is on the logical row counter y, not on
fb:
default: /* unencoded run */
runlen = bmap[1];
bmap += 2;
if (y < height) { /* checks the row, never fb */
if (x < width) {
...
draw_unencoded_bitmap(&fb, bpix, eformat, bmap, palette, cnt);
}
x += runlen;
}
y and fb are advanced by different opcodes: the end-of-line marker moves
fb, while the run opcodes advance the image, so the two drift apart. An
attacker sends N end-of-line markers with N smaller than the image height. y
counts down from height - 1 and stays a small positive value that keeps
passing the y < height guard, while fb slides
N * (width * bytes_per_pixel + line_length) bytes below the start of the
framebuffer. A single unencoded run after that copies attacker-controlled bytes
through the drifted fb, writing out of bounds below the framebuffer (an
underwrite) at an attacker-chosen distance. The delta opcode has the same
defect: it recomputes fb from the unchecked y, so it can place the cursor at
an arbitrary offset.
When the framebuffer is 8 bits per pixel the decoder stores each palette index
directly (*fb++ = *bmap), so every byte written is a raw attacker byte at the
target address, which gives byte-exact control over the out-of-bounds write.
Deeper framebuffers map the index through the palette before storing it, which
still corrupts memory but removes that byte-exact control.
On the SoCs whose display controller scans out from DRAM (for example NXP
i.MX6, Amlogic Meson, STMicro STM32), U-Boot places the framebuffer at the top
of RAM directly above its own relocated image, so walking fb below the
framebuffer walks it into U-Boot's own code and function-pointer tables. The
vulnerable path is built when CONFIG_VIDEO_BMP_RLE8 is enabled.
Reachability and Preconditions
- The device decodes a boot logo or splash BMP during boot.
- The attacker can place a crafted BMP in the storage U-Boot reads the logo from. This storage is commonly unsigned and attacker-writable, and the decode runs before the next stage is authenticated.
Impact
An out-of-bounds write corrupting memory adjacent to the framebuffer and crashing the bootloader. Because the decode runs inside U-Boot, the verified-boot enforcer, before the next stage is authenticated, the primitive can corrupt the verification logic and bypass secure boot.
Remediation and Mitigation
Update U-Boot to a build containing commit
5201e83342d64c2f438ea35158575f28225e752e (currently in u-boot/next). Where
the boot logo is loaded from untrusted storage, restrict write access to that
storage until the fix is deployed.
Timeline
- 2026-07-29 — Vulnerability public and fix available upstream.
- 2026-07-29 — Fix committed to
u-boot/next(commit5201e83342d64c2f438ea35158575f28225e752e); not yet in a tagged release. - 2026-09-29 — CVE-2026-71972 record published by VulnCheck.
Credits
Discovered and reported by Shahriyar Jalayeri and Mehrun P. Hunter of ByteRay Ltd.