⬢ DragonFlyBSD Kernel Audit
DF-5767 / itd_offset_sim.py
← back to finding ↓ download raw
# Faithful simulation of ohci_device_isoc_enter ITD-fill (ohci.c:1900-1965)
# + QEMU hcd-ohci.c address computation, to find OOB DMA.
PAGE=0x1000
def mk_offs(v): return 0xe000 | (v & 0x1fff)   # OHCI_ITD_MK_OFFS
def qemu_start(psw, bp0, be):
    if (psw & 0x1000)==0: return (bp0 & ~0xfff) | (psw & 0xfff)
    return (be & ~0xfff) | (psw & 0xfff)

def build(frlens, buf_page_off, phys_base):
    """returns list of (frame_idx, intended_addr, qemu_addr, be, bp0) per ITD"""
    out=[]; buf_off=0; length=0; ncur=0; itd=[]
    plen=frlens[:]
    starts=[0]
    for i,x in enumerate(plen[1:],1): starts.append(starts[-1]+plen[i-1])
    n=len(plen); i=0
    while i < n:
        itd.append((i, length))          # frame i starts at cumulative 'length'
        buf_off += plen[i]; length += plen[i]; ncur += 1; i+=1
        if ncur==8 or (length & 0xf000) or i==n:
            # fill ITD: bp0 = page of first byte
            first = buf_off - length
            bp0_abs = phys_base + buf_page_off + first
            be_abs  = phys_base + buf_page_off + buf_off - 1
            bp0 = bp0_abs & ~0xfff
            po = (phys_base + buf_page_off + first) & 0xfff
            for (fi, cum) in itd:
                psw = mk_offs(po + cum)
                intended = bp0_abs + cum
                qa = qemu_start(psw, bp0, be_abs)
                out.append((fi, plen[fi], intended, qa, be_abs, bp0_abs))
            length=0; ncur=0; itd=[]
    return out

# 15 frames x 1023 bytes = 15345 bytes, buffer starts page-aligned (phys 0x100000)
fr=[1023]*30
res=build(fr, 0, 0x100000)
end_of_buffer = 0x100000 + sum(fr) - 1
print("buffer: [0x%x .. 0x%x]" % (0x100000, end_of_buffer))
prev_be=None
for fi,ln,intended,qa,be,bp0 in res:
    tag=""
    if qa != intended: tag += " MISMAP"
    # write range for IN frame: [qa, qa+ln-1] clamped by QEMU to page(qa)
    last = min(qa+ln-1, (qa & ~0xfff)+0xfff)
    if last > end_of_buffer: tag += " *** OOB-WRITE past buffer end by 0x%x" % (last-end_of_buffer)
    if fi==0 or tag:
        print("f%-2d len=%4d intended=0x%06x qemu=0x%06x be=0x%06x%s" % (fi,ln,intended,qa,be,tag))