DragonFlyBSD Kernel Audit
DF-2741 / mkimages.py
← back to finding ↓ download raw
#!/usr/bin/env python3
# Craft GPT disk images for DF-2741 / DF-2742 / DF-2744 verification.
#
#   gpt.img    : 64 MiB GPT disk with 128 entries  -> dss_nslices = 130
#   mbr.img    : 8 MiB MBR disk, 1 DFLYBSD slice, no label (race victim / clean disk)
#   lbl64.img  : 4 MiB MBR disk, 1 DFLYBSD slice (1024 sectors) containing a
#                disklabel64 whose d_bbase is 32 GiB  -> ds_reserved >> ds_size
#
# All on-disk structures follow sys/sys/{gpt.h,diskmbr.h,disklabel64.h}.
import struct, zlib, sys

def crc(b): return zlib.crc32(b) & 0xffffffff

SECT = 512

# ---------------- gpt.img ----------------
def make_gpt(path, nsec=131072, nent=128):
    img = bytearray(nsec * SECT)
    # protective MBR at LBA0
    img[446+0] = 0x00          # status
    img[446+4] = 0xEE          # DOSPTYP_PMBR
    img[446+8:446+12] = struct.pack('<I', 1)
    img[446+12:446+16] = struct.pack('<I', nsec - 1)
    img[510:512] = b'\x55\xaa'
    # partition entries at LBA2
    entsz = 128
    table = bytearray()
    for i in range(nent):
        start = 34 + i * 512
        end = start + 511
        assert end < nsec
        # ent_type: recognizable 16-byte pattern "DF2741" + index
        t = b'DF2741T' + bytes([i & 0xff, (i >> 8) & 0xff]) + b'0123456'
        u = b'DF2741U' + bytes([i & 0xff, (i >> 8) & 0xff]) + b'0123456'
        table += t + u + struct.pack('<QQQ', start, end, 0) + b'\x00' * 72
        assert len(table) == (i + 1) * entsz
    tbl_lba = 2
    tbl_blocks = (nent * entsz + SECT - 1) // SECT
    img[tbl_lba * SECT:(tbl_lba + tbl_blocks) * SECT] = table
    # GPT header at LBA1 (92 valid bytes)
    hdr = struct.pack('<8sIIIIQQQQ16sQIII',
                      b'EFI PART', 0x00010000, 92, 0, 0,
                      1, nsec - 1, 34, nsec - 2,
                      b'\x11' * 16,
                      tbl_lba, nent, entsz, crc(table))
    assert len(hdr) == 92
    hdr = hdr[:16] + struct.pack('<I', crc(hdr)) + hdr[20:]
    img[SECT:SECT + 92] = hdr
    open(path, 'wb').write(img)
    print(f"gpt: {nent} entries, nslices will be {2 + min(nent,128)}, "
          f"table_blocks={tbl_blocks}")

# ---------------- mbr.img ----------------
def make_mbr(path, nsec=16384, start=63):
    img = bytearray(nsec * SECT)
    size = nsec - start - 1
    img[446+0] = 0x00
    img[446+4] = 0x6C          # DOSPTYP_DFLYBSD
    img[446+8:446+12] = struct.pack('<I', start)
    img[446+12:446+16] = struct.pack('<I', size)
    img[510:512] = b'\x55\xaa'
    open(path, 'wb').write(img)
    print(f"mbr: slice at {start} size {size}")

# ---------------- lbl64.img ----------------
# MBR slice at LBA 128, 1024 sectors. disklabel64 at slice-relative offset 0
# (magic at byte 512 of the slice per sys/disklabel64.h).
def make_lbl64(path, nsec=8192, sl_start=128, sl_size=1024, bbase=32 * 1024**3):
    img = bytearray(nsec * SECT)
    img[446+0] = 0x00
    img[446+4] = 0x6C
    img[446+8:446+12] = struct.pack('<I', sl_start)
    img[446+12:446+16] = struct.pack('<I', sl_size)
    img[510:512] = b'\x55\xaa'
    # disklabel64 inside slice
    sl_bytes = sl_size * SECT
    nparts = 16
    # struct disklabel64 up to d_partitions[]:
    # 512 reserved | magic I | crc I | align I | nparts I | stor_uuid 16 |
    # total_size Q | bbase Q | pbase Q | pstop Q | abase Q | packname 64 |
    # reserved 64 | partitions[] (each 64 bytes: Q Q BBBB IIII uuid16 uuid16)
    PSIZE = 64
    lab = bytearray(512)
    lab += struct.pack('<IIII', 0xc4464c59, 0, 512, nparts)
    lab += b'\x22' * 16                                    # d_stor_uuid
    lab += struct.pack('<QQQQQ', sl_bytes, bbase, 4096, sl_bytes - 4096, 0)
    lab += b'poc2744' + b'\x00' * 57                       # packname
    lab += b'\x00' * 64                                    # reserved
    for i in range(nparts):
        lab += struct.pack('<QQBBBBIII', 0, 0, 0, 0, 0, 0, 0, 0, 0) + b'\x00' * 32
    assert len(lab) == 512 + 16 + 16 + 40 + 128 + 64 * nparts, len(lab)
    # crc over d_magic .. d_partitions[nparts]
    off_magic = 512
    off_end = 512 + 16 + 16 + 40 + 128 + 64 * nparts
    c = crc(lab[off_magic:off_end])
    lab[off_magic + 4:off_magic + 8] = struct.pack('<I', c)
    base = sl_start * SECT
    img[base:base + len(lab)] = lab
    open(path, 'wb').write(img)
    print(f"lbl64: slice {sl_start}/{sl_size} sectors, d_bbase={bbase} "
          f"-> ds_reserved={bbase // SECT} sectors (u32 ok: {bbase // SECT < 2**32})")

if __name__ == '__main__':
    d = sys.argv[1] if len(sys.argv) > 1 else '.'
    make_gpt(f'{d}/gpt.img')
    make_mbr(f'{d}/mbr.img')
    make_lbl64(f'{d}/lbl64.img')