β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-0436

Heap OOB read + security-filter bypass via OGF=0/event=0: negative bitstr index into ng_btsocket_hci_raw_sec_filter

Summary

ng_btsocket_hci_raw_filter(:669-718): CMD_PKT uses bit_test(commands[OGF(opcode)-1], OCF(opcode)-1)(:679-684). OGF=0 -> commands[-1] = 128 bytes before commands[0] = 96 bytes before struct start -> heap OOB read. OCF=0 -> bit_test(..,-1) -> name[-1>>3] = 1 byte before array. EVENT_PKT: event=mtod->event-1(:703) then bit_test(events,event)(:709). event code 0 -> bit index -1 -> events[-1] 1 byte before struct. bitstr_t unsigned char bit_test=name[bit>>3]&(1<<(bit&7)). Trigger: unpriv local user sendto() 3-byte HCI cmd OGF=0 (attach:936 no priv required). Heap OOB read leaks slab metadata + when tested bit set -> filter bypass -> unpriv socket injects privileged HCI commands.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0436 Β· 8 files
FileTypeDescriptionSize
trace_analysis.c trigger-source static trace artifact (no runnable PoC; module not shipped) 4.2 KB view raw
build.sh build-script compiles the trace artifact 203 B view raw
run.sh run-script prints the not-reproducible explanation 573 B view raw
VERDICT.md verdict trace-confirmed latent bug analysis 2.9 KB ↓ raw
fix.diff suggested-fix OGF/OCF/event==0 guards in ng_btsocket_hci_raw_filter 1.7 KB view raw
env.txt environment guest uname, kldload ENOENT evidence 1.1 KB view raw
../fix_build_combined.log build-log Combined 41-finding kernel build (rc=0, -Werror clean) 5.6 MB ↓ download
../fix_build_summary.txt build-summary Summary of the combined 41-finding kernel build 826 B view raw
VERDICT.md verdict trace-confirmed latent bug analysis
↓ download raw

DF-0436 β€” ng_btsocket_hci_raw_filter heap OOB read + security bypass

Verdict: NOT REPRODUCED LIVE (latent code bug; module not shipped).

Confirmed by static trace at sys/netgraph7/bluetooth/socket/ng_btsocket_hci_raw.c:669-718. The bug is real; it just can't be triggered on the master DEV ISO because the netgraph7 Bluetooth modules are not shipped in /boot/kernel/ and there is no Bluetooth adapter exposed to the guest.

Mechanism

ng_btsocket_hci_raw_filter() runs the HCI security filter on every CMD/EVENT packet an unprivileged PF_BLUETOOTH raw socket tries to send or receive. The filter uses two bitstr_t arrays inside a kmalloc'd struct ng_btsocket_hci_raw_sec_filter:

struct ng_btsocket_hci_raw_sec_filter {
    bitstr_t events[0xff / 8];             // 32 bytes   @ offset 0
    bitstr_t commands[0x3f][0x3ff / 8];    // 8064 bytes @ offset 32
};

The CMD path (line 681-684) does: bit_test(commands[NG_HCI_OGF(opcode) - 1], NG_HCI_OCF(opcode) - 1) where NG_HCI_OGF(op) = (op>>10)&0x3f and NG_HCI_OCF(op) = op&0x3ff.

With attacker-controlled opcode == 0: - commands[0 - 1] = commands[-1] reads 128 bytes BEFORE commands[0], i.e. 96 bytes BEFORE the struct's kmalloc allocation. Heap OOB read. - bit_test(arr, 0 - 1) reads arr[(-1)>>3] = arr[-1], 1 byte before the inner array. Heap OOB read.

The EVENT path (line 703): event = ...->event - 1 underflows when the event code is 0, then bit_test(events, -1) reads events[-1], 1 byte before the events array (= 1 byte before the struct allocation).

Security bypass: the result of every OOB bit_test drives the EPERM decision. An attacker who can shape heap state (or just gets lucky with uninitialized memory) can let normally-restricted HCI commands/events through the filter.

Why not reproduced

  • /boot/kernel/ on the master DEV ISO ships NO bluetooth modules. Only USB-HCI drivers (uhci/ehci/xhci/sdhci) are present; netgraph7 Bluetooth (ng_btsocket_hci_raw, ng_hci, ng_ubt) is absent.
  • kldload ng_btsocket_hci_raw / ng_hci / ng_ubt all return ENOENT.
  • No Bluetooth adapter is exposed to the QEMU guest.

The bug is therefore a latent code defect: real on any system that builds + loads the netgraph7 BT stack with a BT adapter, but unreachable on the master DEV guest. Classification: not_reproduced (latent), trace-confirmed.

Fix

fix.diff adds OGF/OCF/event == 0 guards before the array indexing. With the fix, opcode 0/0 and event 0 are rejected with EPERM/EINVAL before any bit_test runs.

Notes

  • The fix is mechanical (three zero-checks); the sys/ tree is read-only during audit so the diff is generated but not applied.
  • If DragonFly ever ships the netgraph7 Bluetooth modules by default, this finding becomes live-reproducible as both an OOB read and a security bypass for unprivileged PF_BLUETOOTH sockets.

Fix verification

not_testable

compile validated

see evidence pack

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. ng_btsocket_hci_raw OGF=0/event=0 negative array index OOB read + security bypass. No BT HW/modules shipped.