]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
vbe: bound FIT external-data offset and size before blk_read
authorAristo Chen <aristo.chen@canonical.com>
Sun, 5 Jul 2026 03:44:10 +0000 (03:44 +0000)
committerTom Rini <trini@konsulko.com>
Thu, 16 Jul 2026 18:06:15 +0000 (12:06 -0600)
vbe_read_fit() loads a firmware-phase FIT from the trusted firmware area
and then issues a blk_read() to pull in the image, and optionally an
FDT, referenced by the FIT image node. The source offset on the device
and the read length both come from the FIT's data-position or data-offset
property and its data-size property, which live on mutable boot media
and can be controlled by an attacker with prior write access to the
firmware area.

Without a range check the resulting blk_read() can read past the
firmware area on the device and, on the non-SPL path, write an
attacker-chosen number of blocks past the malloc(aligned_size) FIT
buffer into adjacent memory. Only the SPL branch routes through
spl_load_simple_fit(), which hashes the data. The external-data block
reached from TPL or VPL, and from the bootflow path via
abrec_read_bootflow_fw() and vbe_simple_read_bootflow_fw(), runs before
any signature or hash check on the loaded phase.

Confine the FIT-supplied [load_addr, load_addr + len) window to
[addr, addr + area_size] before computing block numbers and lengths,
and apply the same constraint to fdt_load_addr and fdt_size. The checks
are written in subtraction-only form against the trusted area_size so
the comparison itself cannot overflow.

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
boot/vbe_common.c

index a86986d86e9472033fec25a3b0f0955b6fb20af4..844100b7ee6b9e933d788e7f361a7ab84a81c60d 100644 (file)
@@ -278,6 +278,17 @@ int vbe_read_fit(struct udevice *blk, ulong area_offset, ulong area_size,
                ulong fdt_offset;
                void *base_buf, *fdt_base_buf;
 
+               /*
+                * load_addr and len describe the external data location in
+                * the FIT, which lives on mutable boot media. Bound them
+                * against the trusted area_size so the blk_read() below
+                * cannot read past the firmware area or write an
+                * attacker-chosen number of blocks past the FIT allocation.
+                */
+               if (load_addr < addr || load_addr - addr > area_size ||
+                   len > area_size - (load_addr - addr))
+                       return log_msg_ret("rng", -E2BIG);
+
                /* Find the start address to load from */
                base = ALIGN_DOWN(load_addr, desc->blksz);
 
@@ -321,6 +332,11 @@ int vbe_read_fit(struct udevice *blk, ulong area_offset, ulong area_size,
 
                /* now the FDT */
                if (fdt_size) {
+                       /* Same constraint as above for the FDT region */
+                       if (fdt_load_addr < addr ||
+                           fdt_load_addr - addr > area_size ||
+                           fdt_size > area_size - (fdt_load_addr - addr))
+                               return log_msg_ret("rng", -E2BIG);
                        fdt_offset = area_offset + fdt_load_addr - addr;
                        blknum = fdt_offset / desc->blksz;
                        extra = fdt_offset % desc->blksz;