⬢ DragonFlyBSD Kernel Audit
DF-5738 / fix_run.log
← back to finding ↓ download raw
DF-5738 fix validation run — patched module (fix.diff applied to the
guest's /usr/src/sys/netbt copy, module rebuilt verbatim from the
patched sources, guest rebooted, module reloaded).

$ cd /usr/src/sys && patch -p2 < /root/hcih/fix.diff
(3 hunks applied to hci_link.c, 1 to hci.h; see fix.diff)
$ cd /root/hcih && sh build.sh
-rw-r--r-- 1 root root 48664 Oct 11 00:22 hci_link_harness.ko
== build OK ==
$ reboot; kldload /root/hcih/hci_link_harness.ko
$ sysctl hw.hlh_setup=1 ; sysctl hw.hlh_sco_anchor=1 ; sysctl hw.hlh_fire_discon=2
[harness] after SCO anchor: ACL link #5 hl_refcnt=1 (anchor only, no L2CAP channels), unit links=2, sco_newconn=1
[harness] EXPECT hl_refcnt == 1: the SCO link's hci_acl_open() reference (hci_link.c:810)
[harness] === DF-5738 control: SCO-first ordering (what hci_cmd_reset assumes) ===
[harness] <- Connection_Complete(SCO handle 9) (14 bytes): 04 03 0b 00 09 00 11 22 33 44 55 66 00 00
[harness] <- Disconnect_Complete(handle 9) (7 bytes): 04 05 04 00 09 00 13
[harness] SCO-first control done: ACL refcnt=0 links=1 sco_disconnected=1 (clean, no panic)
[harness] state: unit links=1
[harness]  link 0xfffff80118101af0 type=1 state=5 handle=5 refcnt=0 txqlen=0 rxp=0
[harness] sco_newconn=1 sco_disconnected=1 cmds_sent=1
$ sysctl hw.hlh_uaf=1                # same FIRE sequence as baseline
[harness] === DF-5738 UAF sequence (offsetof(hl_refcnt)=38, sizeof(hci_link)=168) ===
[harness] <- Connection_Request(SCO) (13 bytes): 04 04 0a 11 22 33 44 55 66 22 22 22 00
[harness] 1) anchored: ACL#5 refcnt=1 links=2
[harness]    SCO link 0xfffff8004f20a7e0 pcb 0xfffff8008976ba00 hl_link=0xfffff80118101af0 (== ACL#5)
[harness] <- Disconnect_Complete(5) (7 bytes): 04 05 04 00 05 00 13
[harness] 2) ACL#5 freed: links=0 (SCO still holds hl_link=... -- DANGLING)   <-- narrative label only;
                                                                           the fix released the SCO anchor INSIDE
                                                                           hci_link_free(): links already 0, no dangling use
[harness] 3) sprayed 256 x 168-byte objects (0xa5)
[harness] <- Connection_Complete(SCO 9) (14 bytes): 04 03 0b 00 09 00 11 22 33 44 55 66 00 00
[harness] <- Disconnect_Complete(9) (7 bytes): 04 05 04 00 09 00 13
[harness] 4) SCO teardown done: links=0 sco_disconnected=2
[harness] 5) result: 0/256 spray objects show the freed-link decrement (slot not reclaimed this round -- re-run)
[harness] state: unit links=0
[harness] sco_newconn=2 sco_disconnected=2 cmds_sent=1

(no trap; guest alive)

RESULT: fixed.
- The ACL teardown released the SCO anchor BEFORE kfree: the SCO link's
  disconnected callback fired inside hci_link_free(acl) (sco_disconnected
  1 -> 2), both links gone, links=0, no leak.
- hci_acl_close() never ran on freed memory: the 256-object spray canary
  scan found ZERO decrements (baseline crashed inside this exact
  sequence with a supervisor-write fault in hci_link_free).
- Note on harness labels: step 2's "(... -- DANGLING)" string and step
  5's "(slot not reclaimed...)" string are static narrative text written
  for the BASELINE flow; under the fix the SCO link is freed first, so
  the later discon(9) finds no link (lookup by handle 9 -> none) and
  nothing touches reclaimed memory -- which is exactly what the 0/256
  canary result certifies.