⬢ DragonFlyBSD Kernel Audit
DF-3970 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3970",
  "status": "not_reproduced",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Certain unbounded table walk: rt2560.c:2210 for (i = 0; rt2560_rf5222[i].chan != chan; i++); scans the 41-entry unterminated RT2560_RF5222 table (rt2560reg.h:449-489) with no loop bound. Safe by accident on stock configs because the default channel lists (ieee80211_regdomain.c:101-108) are fully covered, but SIOCS80211/IEEE80211_IOC_REGDOMAIN installs an admin channel table into ic->ic_channels with only freq/flags/maxregpower validated (ieee80211_regdomain.c:342+; the ral drivers null_setregdomain at regdomain.c:59-65 accepts anything), so selecting an installed channel whose ieee number is outside the table (165, 34, 184-196) walks off the end of .rodata until a coincidental byte match and programs garbage into RF R1/R2/R4. OOB read with no userspace disclosure path + radio misbehavior; admin-gated. Not reproduced: no Ralink NIC on the guest (env.txt) and the trigger needs a privileged regdomain install; recipe in trigger.c.",
  "exploit_chain": "root installs custom regdomain channel table containing e.g. ieee=165 -> ifconfig wlan0 channel 165 -> ic_curchan->ic_ieee=165 not present in rt2560_rf5222[] -> unbounded walk past table end in kernel .rodata -> OOB read + garbage RF programming (radio DoS).",
  "evidence": "VERDICT.md (walk + table + regdomain ioctl chain with path:line), trigger.c (on-target recipe), env.txt, fix.diff (nitems() bound + unknown channel bail), build.log (if_ral.ko rebuilt -Werror clean on the guest /usr/src copy)",
  "kernel_refs": [
    "sys/dev/netif/ral/rt2560.c:2210",
    "sys/dev/netif/ral/rt2560reg.h:449",
    "sys/dev/netif/ral/rt2560reg.h:489",
    "sys/netproto/802_11/wlan/ieee80211_regdomain.c:101",
    "sys/netproto/802_11/wlan/ieee80211_regdomain.c:59",
    "sys/netproto/802_11/wlan/ieee80211_ioctl.c:2126"
  ],
  "poc_changes": "Trigger is a documented privileged-config recipe (needs NIC); informational C stub compiled only.",
  "attempts": 1,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "runtime_sec": 5,
  "guest_dirty": 0,
  "build_cmd": "guest: cd /usr/src && patch -p1 < /root/fix2.diff && cd sys/dev/netif/ral && make   # -Werror, full if_ral.ko link (build.log)",
  "run_cmd": "dfbsd-qemu/vm.sh run_root pciconf -lv | grep -i ralink; ifconfig -l   # => no Ralink device (run.log/env.txt)",
  "code_hash": "93d2a56d8a38598a283e72ce54ca427c46e8c6c999572aece53cfe1b173b9dcd",
  "notes": "Pass-2 finding (GLM 5.3). FreeBSD-inherited defect (their tree has the same unterminated walk). Low: no default-config reachability, no disclosure path, admin-gated.",
  "recommended_fix": "Bound the RF5222 walk with nitems() and bail on unknown channel (fix.diff).",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "nitems() bound + unknown channel %u for RF5222 log-and-break; git apply --check clean against sys/ and the patched module rebuilt -Werror clean (build.log; combined with the other two rt2560 fix.diffs of this batch). Runtime validation impossible without the NIC.",
  "fix_evidence": "fix.diff; build.log (if_ral.ko linked from patched rt2560.o with -Werror on the guest /usr/src copy)"
}