⬢ DragonFlyBSD Kernel Audit
DF-4218 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4218",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "MECHANISM PROVEN live on the audit guest by deterministic replica of if_ae.cs exact callout/serializer protocol (DF-3715 family, ae instance; adapted from the PROVEN DF-3991 ale replica). ae(4) arms ONE non-MP callout (callout_init if_ae.c:1262; _callout_init sets only CALLOUT_DID_INIT, kern_timeout.c:760) whose handler takes the driver serializer by hand and self re-arms (ae_tick :988-999: BLOCKING lwkt_serialize_enter :995, callout_reset(hz) :997); every teardown stops it while HOLDING that serializer (ae_stop :225 ASSERT_SERIALIZED + :232 callout_stop; callers: ae_ioctl down :1220-1221, ae_init :799 \u2014 also from the ae_intr error path :770-775 IN INTERRUPT CONTEXT \u2014, watchdog :983, detach :1417, suspend :1786, shutdown :1801). callout_stop is synchronous (kern_timeout.c:1091 -> sync=1 -> ssleep costp :920): stopper holds serializer and sleeps; INPROG callback parks in lwkt_serialize_enter (lwkt_serialize.c:105-113) waiting for that serializer (holding the mplock, being non-MP) \u2014 permanent AB-BA. Guest replica run: tick handler BLOCKED on our serializer (fired=148 ran=147) - entering callout_stop(), NO callout_stop returned line, ps stopper D4/costp, STILL_WEDGED_AFTER_30S, follow-on ssh commands timed out (mplock held), serial console ends at the BLOCKED line; guest reset with-src and verified clean afterwards. ae-specific end-to-end trigger hardware-gated (no 1969:2048, if_ae not in X86_64_GENERIC, guest src md5 == audited tree) -> inconclusive per family convention.",
  "exploit_chain": "On real hardware: race the 1 Hz ae_tick against any stop path (repeated `ifconfig ae0 down`, suspend, detach, or the intr-error reinit) while the callback is INPROG-parked on the serializer -> stopper sleeps in callout_stop(costp), callback waits on the serializer -> permanent AB-BA wedge + mplock held => system-wide degradation until reboot. No privilege path.",
  "evidence": "run.log (replica: BLOCKED message + ps D4/costp + STILL_WEDGED_AFTER_30S + serial-console tail), build.log (kmod built on guest with -Werror, clean), env.txt (NO_ATTANSIC_PCI + no if_ae in kernel config + guest-src md5 match), ae_replica.c (annotated protocol replica), VERDICT.md, fix.diff (try-enter family fix, git-apply clean)",
  "kernel_refs": [
    "sys/dev/netif/ae/if_ae.c:1262",
    "sys/dev/netif/ae/if_ae.c:995",
    "sys/dev/netif/ae/if_ae.c:997",
    "sys/dev/netif/ae/if_ae.c:225",
    "sys/dev/netif/ae/if_ae.c:232",
    "sys/dev/netif/ae/if_ae.c:799",
    "sys/dev/netif/ae/if_ae.c:770",
    "sys/dev/netif/ae/if_ae.c:1221",
    "sys/dev/netif/ae/if_ae.c:1417",
    "sys/dev/netif/ae/if_ae.c:1786",
    "sys/kern/kern_timeout.c:1091",
    "sys/kern/kern_timeout.c:920",
    "sys/kern/lwkt_serialize.c:105"
  ],
  "poc_changes": "No seed PoC. Authored ae_replica.c by adapting the PROVEN DF-3991 ale replica to aes exact protocol (non-MP callout_init :1262, hz self re-arm :997, same stop sites); executed on the guest to mechanism-proof.",
  "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": 480,
  "guest_dirty": 0,
  "build_cmd": "cd /root/kmod/aesink && make (KMOD= ae_replica SRCS= ae_replica.c)",
  "run_cmd": "kldload /root/kmod/aesink/ae_replica.ko; sysctl kern.aereplica.arm=1; (sysctl kern.aereplica.stop=1 &); sleep 8; dmesg|tail; ps -ax -o pid,stat,wchan,comm | grep costp; sleep 30; re-check; then vm.sh reset with-src",
  "code_hash": "89db03e3475bb114d00a0f774072f3e5ebd1020314f41e34cc542f318f2e70a7",
  "notes": "Pass-2 result for if_ae.c (GLM 5.3). DF-3715 (em, PROVEN) / DF-3760 (alc) / DF-3776 (jme) / DF-3935 (age, PROVEN) / DF-3991 (ale, PROVEN) family instance with identical code shape in ae. First hunk-count of the authored fix.diff was off; regenerated mechanically and git-apply verified. Guest was reset with-src after the proof (wedge by design) and verified clean.",
  "recommended_fix": "Use lwkt_serialize_try() + early re-arm in ae_tick so the callback can always complete (see fix.diff \u2014 identical to the validated DF-3760/DF-3935/DF-3991 family fix).",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Baseline mechanism proven by the replica; the ae-specific fix path cannot be runtime-validated (no Attansic L2 hardware on the guest). fix.diff is the family fix (lwkt_serialize_try + re-arm, exactly the validated DF-3760/DF-3935/DF-3991 shape) and breaks the deadlock precondition (the callback can never park on the serializer the stopper holds); git-apply clean against the audited tree.",
  "fix_evidence": "fix.diff (git-apply --check clean); replica mechanism proof in run.log"
}