DF-5320 / ttys_diff.py
#!/usr/bin/env python3 """DF-5320 evidence: decode sysctl kern.ttys dumps and show that the ucom tty's driver callbacks (t_oproc/t_param/t_stop = ucom.ko text) and t_sc (kernel-heap pointer into the driver softc) persist UNCHANGED after the USB device detached and the softc was kfree'd. New ttys are TAILQ_INSERT_HEAD'ed (ttyregister), and sysctl_kern_ttys walks from the head => the most recently registered tty is record 0. The ucom tty is therefore record 0 of the live dump (registered at ucom attach) and record 0 of the dead dump (ttys are never freed / unregistered). """ import struct, sys TS = 376 # sizeof(struct tty) on X86_64_GENERIC 6.5-DEVELOPMENT # (live-base = 376 bytes exactly; see README) def records(path): b = open(path, 'rb').read() assert len(b) % TS == 0, (path, len(b)) return [b[i:i+TS] for i in range(0, len(b), TS)] def ptrs(r): out = {} for off in range(0, TS-7, 8): v = struct.unpack('<Q', r[off:off+8])[0] if v >= 0xffffffff80000000 or (0xfffff80000000000 <= v < 0xffffffff00000000): out[off] = v return out base, live, dead = (records(p) for p in sys.argv[1:4]) print(f"records: base={len(base)} live={len(live)} dead={len(dead)}") print(f"sizeof(struct tty) assumed: {TS} (4136-3760 == 376)") u_live, u_dead = ptrs(live[0]), ptrs(dead[0]) print("live[0] (ucom tty, head-inserted at attach):") for k in sorted(u_live): print(f" +0x{k:03x}: 0x{u_live[k]:016x}") print("dead[0] (same tty after USB detach + softc kfree):") for k in sorted(u_dead): print(f" +0x{k:03x}: 0x{u_dead[k]:016x}") same = {k for k in u_live if k in u_dead and u_live[k] == u_dead[k]} print("fields identical across detach:", [hex(k) for k in sorted(same)]) cb = [k for k in same if u_live[k] >= 0xffffffff80000000] print("=> driver TEXT pointers retained after detach (t_oproc/t_param/t_stop):", [f"+0x{k:x}=0x{u_live[k]:x}" for k in sorted(cb)]) sc = [k for k in same if 0xfffff80000000000 <= u_live[k] < 0xffffffff00000000] print("=> HEAP pointer retained after detach (t_sc -> freed ucom_softc):", [f"+0x{k:x}=0x{u_live[k]:x}" for k in sorted(sc)]) |