⬢ DragonFlyBSD Kernel Audit
DF-3281 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3281",
  "status": "not_reproduced",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Code defect certain, userland exploitation NOT possible. if_addgroup() executes ifg->ifg_refcnt++ (if.c:1183) outside ifgroup_lock while if_delgroup_locked() decrements under LK_EXCLUSIVE (if.c:1231) - asymmetric, lost-update-capable - and decides group creation without exclusive locking (duplicate same-named groups possible, if.c:1169-1177 + if_creategroup if.c:1106-1123). But ifioctl() holds the global ifnet_mtx across the whole ioctl body (if.c:2029-2450), fully serializing all userland SIOCAIFGROUP/SIOCDIFGROUP calls: a 45s two-racer run (~3.8M cycles) produced 0 anomalous returns (run.log). The live race partners are kernel-side only: if_attachs if_addgroup(IFG_ALL) before ifnet_mtx is taken (if.c:558 vs 689), and if_detachs group teardown which runs after ifnet_mtx is released (if.c:991-996) - i.e. SIOCAIFGROUP racing interface destroy/hot-unplug, both privileged. Consequence if it fires: refcount below membership -> premature if_destroygroup kfree with live ifgl/ifgm -> stale walks/double-free. Severity Low. fix.diff restructures if_addgroup to do scan/create/increment/insert atomically under LK_EXCLUSIVE (with if_creategroup_locked helper); it compiled into fix kernel #1 and 3M+ group cycles ran error-free, but with no userland race baseline fix_status=not_testable.",
  "exploit_chain": "",
  "evidence": [
    "run.log: racers healthy, 0 MARKER lines, ~1.9M add/del cycles per racer in 45s",
    "VERDICT.md: serialization analysis (ifnet_mtx) + kernel-side race partners with path:line",
    "fix.diff: atomic if_addgroup under LK_EXCLUSIVE",
    "../DF-3280/churnFIX.log: 3.0M SIOCAIFGROUP/SIOCDIFGROUP cycles err=0 on the fix kernel"
  ],
  "kernel_refs": [
    "sys/net/if.c:1183",
    "sys/net/if.c:1174",
    "sys/net/if.c:1231",
    "sys/net/if.c:991",
    "sys/net/if.c:558",
    "sys/net/if.c:2029"
  ],
  "poc_changes": "v1 (both racers churn the same ifp) wedges the guest on the first benign EEXIST via the known DF-0272 ifnet_mtx leak; v2 uses one racer per interface (lo0/vtnet0) so benign EEXIST/ENOENT are impossible and any error is a genuine desynchronization marker; group name must not end in a digit (if.c:1155).",
  "attempts": 2,
  "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": 60,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -Wall -o /root/addgrp_race /root/addgrp_race.c",
  "run_cmd": "(root) /root/addgrp_race",
  "code_hash": "sha256:3d44566848a30c6cf576cb50719ad1942fd1b713a2bb12ba178e96257e4bbdbe",
  "notes": "Pass-2 depth result: the ifnet_mtx serialization of the group ioctls is itself the reason no userland race exists; the if_attach/if_detach overlap (interface destroy racing group add) remains the plausible production trigger and is what the fix closes. Guest reset clean after run.",
  "recommended_fix": "Hoist allocations, then perform membership scan, group lookup/creation, ifg_refcnt++ and both TAILQ insertions under a single LK_EXCLUSIVE section (if_creategroup_locked helper); free allocations on the EEXIST path (see fix.diff).",
  "fix_status": "not_testable",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Thu Sep 10 03:02:42 UTC 2026  root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff compiled into fix kernel #1 (with DF-3280s fix) and 3.0M+ group add/del cycles ran error-free on it (churnFIX.log), so the restructure is build- and API-validated; the race itself had no userland-reproducible baseline, so behavioral fix validation is not possible (not_testable).",
  "fix_evidence": "../DF-3280/kbuild.log (BUILD-EXIT=0), ../DF-3280/churnFIX.log (3.0M cycles err=0), fix.diff"
}