mtd: validate trx->len in trx_fixup()

trx_fixup() computed the CRC32 range from the on-flash TRX header
without validating it:

    scan = ptr + offsetof(struct trx_header, flag_version);
    trx->crc32 = crc32buf(scan, trx->len - (scan - ptr));

trx->len is read from the mmap()ed partition and is only sanity checked
in trx_check(), which is a separate entry point. A trx->len larger than
the partition therefore makes crc32buf() walk that many bytes past the
end of the mapping and crash mtd with SIGSEGV.

The mirror case of a trx->len below the 12 byte offset does not overread
in practice: crc32buf() takes a size_t but passes it to crc32(), which
takes an int len and loops on "while (--len >= 0)". The wrapped value
truncates to a negative int, so the loop body never runs and a zero
length CRC32 is written instead. Values at or above 0x8000000c truncate
the same way. Only the range from sizeof(struct trx_header) to roughly
0x8000000b stays positive through the truncation and reads out of
bounds, which is exactly the range a plausible bad length falls into.

Bound trx->len on both sides before computing the range, using the same
lower limit trx_check() already applies. Both comparisons are unsigned,
so the wrapping cases are rejected as well.

trx_fixup() runs as root on the contents of the flash, so this is a
robustness fix rather than a privilege boundary: it is reachable through
"mtd jffs2write" and the jffs2_replaced path of "mtd write", not through
"mtd fixtrx", which uses mtd_fixtrx() and derives its length from
erasesize instead. The practical benefit is not crashing on a truncated
or corrupted header during sysupgrade.

Link: https://github.com/openwrt/openwrt/security/advisories/GHSA-wch3-f5gc-mw2h
Reported-by: @tonoyx91
Reported-by: @0xROI
Fixes: bbd9eb4669 ("clean up mtd, fix up trx header when integrating jffs2 data on broadcom devices")
Assisted-by: Claude:claude-opus-5
Link: https://github.com/openwrt/openwrt/pull/25284
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
Hauke Mehrtens committed 2026-09-26 21:26:29 +02:00
1 parent 83c18c360e
commit e056c32ed0
2 files changed
+6 -1

No files matched your search

+1 -1
View File
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=mtd
PKG_RELEASE:=28
PKG_RELEASE:=29
PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)
STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
+5
View File
@@ -97,6 +97,11 @@ trx_fixup(int fd, const char *name)
goto err2;
}
if (trx->len < sizeof(struct trx_header) || trx->len > len) {
fprintf(stderr, "Invalid TRX header length: %u\n", trx->len);
goto err2;
}
scan = ptr + offsetof(struct trx_header, flag_version);
trx->crc32 = crc32buf(scan, trx->len - (scan - ptr));
msync(ptr, sizeof(struct trx_header), MS_SYNC|MS_INVALIDATE);