Remote kernel panic: divide-by-zero via PN MCC command with mtu=0
Summary
ng_btsocket_rfcomm_set_pn(:3019) copies peer PN mtu into pcb->mtu with NO validation (can be 0). ng_btsocket_rfcomm_send_credits(:3283) ssb_space/pcb->mtu unconditional division. Peer: PN mtu=0 + one UIH data frame -> divide-by-zero #DE -> kernel panic. Deterministic single-shot no auth required. Division executes before mtu oversize check(:2438).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0281 Β· 18 files| File | Type | Description | Size | |
|---|---|---|---|---|
| divzero_proof.c | trigger-source | userspace replication of the exact kernel arithmetic on the confirmed vulnerable path; every arithmetic/control op annotated with its kernel source line | 8.5 KB | view raw |
| build.sh | build-script | builds divzero_proof (vulnerable) and divzero_proof_fixed (-DFIX_MTU) | 502 B | view raw |
| run.sh | run-script | runs vulnerable path (expect SIGFPE) then guarded path (expect NO FAULT) | 454 B | view raw |
| build.log | build-log | full userspace build output, both variants | 133 B | view raw |
| run.log | run-log | decisive vulnerable-path run, full output incl SIGFPE | 821 B | view raw |
| run.fixed.log | run-log | guarded-path run (-DFIX_MTU), full output incl NO FAULT | 685 B | view raw |
| run.stress.log | stress-log | 3x determinism check β SIGFPE every run | 1002 B | view raw |
| module_build.log | build-log | FULL output of building the ACTUAL ng_btsocket.ko from /usr/src against the audit kernel (unpatched baseline); rc=0, then objdump idiv count=1 | 1.1 KB | view raw |
| fix_build.log | build-log | FULL output of rebuilding ng_btsocket.ko with fix.diff applied (Phase 8); rc=0, idiv count=1 but now preceded by test/je guard | 1.5 KB | view raw |
| objdump_unpatched.dis | objdump | full objdump -d of the unpatched ng_btsocket.ko; idiv %r8 at offset 0xb418 with NO preceding zero-check on the divisor | 446.4 KB | β download |
| objdump_patched.dis | objdump | full objdump -d of the patched ng_btsocket.ko; idiv %rdi at offset 0xb4b2 preceded by 'test %cx,%cx; je b7d3' guard | 446.5 KB | β download |
| idiv_comparison.txt | evidence | focused before/after object-code comparison: unguarded idiv (unpatched) vs guarded idiv (patched), with annotations | 3.6 KB | view raw |
| env.txt | environment | uname, kern.version, cc version, kldstat, GENERIC bluetooth check, module build result | 772 B | view raw |
| fix.diff | suggested-fix | git-apply-able unified diff: (1) set_pn clamps mtu!=0 to RFCOMM_DEFAULT_MTU, (2) send_credits returns EINVAL if pcb->mtu==0 before the divide | 1.1 KB | view raw |
| README.md | readme | human-facing summary: what the pack contains, build/run, expected output, reachability caveat | 4.2 KB | β raw |
| VERDICT.md | verdict | full narrative: reproduced at code/object-code level; line-by-line trace; objdump proof; why no runtime trigger; fix validation | 11.9 KB | β 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 |
DF-0281 β PoC evidence pack
Finding: ng_btsocket_rfcomm_set_pn copies a peer-supplied PN mtu into
pcb->mtu with no validation (:3019); ng_btsocket_rfcomm_send_credits
later divides ssb_space / pcb->mtu unconditionally (:3283). A peer PN with
mtu=0 plus one UIH data frame β divide-by-zero #DE β kernel panic.
CWE-369 (divide-by-zero), severity High.
Verdict: REPRODUCED (code/object-code level, certain)
The bug is confirmed three independent ways:
- Static line-by-line trace β every hop from peer PN frame to the unguarded
divisor is cited
path:lineinVERDICT.md. - Actual kernel module build + objdump β
ng_btsocket.kobuilds cleanly from/usr/src/sys/netgraph7/bluetooth/socket/against the audit kernel;objdumpconfirms the unguardedidiv %r8(divisor =pcb->mtu) at module offset0xb418with no preceding zero-check. (objdump_unpatched.dis,idiv_comparison.txt) - Userspace arithmetic replication β
divzero_proof.creproduces the exact kernel integer arithmetic; withpcb->mtu = 0it raises SIGFPE 3/3 runs.
No runtime trigger on this KVM guest: ng_btsocket is not in
X86_64_GENERIC, the freshly-built .ko won't kldload (netgraph ABI
mismatch), and reaching the live path needs real bluetooth HW anyway. The
object-code-level proof is the accepted reproduction (precedent: DF-0594 /
DF-0616).
What this pack contains
divzero_proof.cβ userspace replication of the exact kernel arithmetic (every step annotated with its kernel source line).build.sh/run.shβ build & run the harness.build.log/run.log/run.fixed.log/run.stress.logβ full output.module_build.logβ building the actualng_btsocket.kofrom source (unpatched baseline).fix_build.logβ rebuildingng_btsocket.kowithfix.diffapplied.objdump_unpatched.dis/objdump_patched.disβ full disassemblies.idiv_comparison.txtβ focused before/after object-code comparison.fix.diffβgit apply-able fix (validated both directions).env.txtβ guest environment + reachability evidence.VERDICT.mdβ full narrative.manifest.jsonβ machine-readable catalog.
Build (userspace harness)
./build.sh
Produces divzero_proof (vulnerable arithmetic) and divzero_proof_fixed
(same code compiled with -DFIX_MTU, which clamps pcb->mtu).
Run
./run.sh
Expected output
Vulnerable path (bug present β the kernel arithmetic reaches the zero divisor):
STEP 1: peer PN with mtu=0 processed by set_pn (line 3019); now pcb->mtu = 0 STEP 2: ... --rx_cred=20 <= MAX_CREDITS/2 -> send_credits() called (line 2429) STEP 3: send_credits line 3283: credits = ssb_space / pcb->mtu ... ### SIGFPE: divide by zero at step 3 (send_credits, line 3283) ### PROOF: pcb->mtu==0 reached the unguarded divisor -> kernel would #DE/panic
Guarded path (fix active): prints NO FAULT: pcb->mtu was guarded before
the divisor (fix active); credits path completed. and exits 0.
Object-code proof (the strong evidence)
Build the actual vulnerable module and disassemble:
ssh dfbsd 'cd /usr/src/sys/netgraph7/bluetooth/socket && make &&
objdump -d ng_btsocket.ko | grep idiv'
# -> exactly one "idiv %r8" at offset 0xb418, divisor = pcb->mtu, NO guard
Apply the fix and rebuild:
ssh dfbsd 'cd /usr/src && patch -p1 < /root/fix.diff &&
cd sys/netgraph7/bluetooth/socket && make &&
objdump -d ng_btsocket.ko | grep -B3 idiv'
# -> "idiv %rdi" at 0xb4b2, preceded by "test %cx,%cx; je <return>" at 0xb470
See idiv_comparison.txt for the annotated before/after.
Reproducing the kernel panic
Cannot be done on this master DEV guest (no bluetooth HW, module won't load).
On a host that does have bluetooth hardware and ng_btsocket loaded, the
panic is produced by a malicious peer that:
1. opens an L2CAP channel on PSM RFCOMM (0x0003) and completes the RFCOMM
session handshake,
2. sends a PN MCC frame with mtu = 0 and flow_control = 0xf0 (enables CFC),
3. sends a single UIH data frame on the DLC to drive rx_cred down to
RFCOMM_MAX_CREDITS/2, which calls send_credits() β #DE β panic.
See VERDICT.md for the full line-by-line trace.
DF-0281 β netgraph7 RFCOMM divide-by-zero via peer PN mtu=0
Verdict
REPRODUCED at code/object-code level (certain). The divide-by-zero is real, deterministic, and unambiguous β confirmed three independent ways:
- Static line-by-line trace of the cited path in the audited master DEV
source (every hop cited
path:linebelow). - Actual kernel module build:
ng_btsocket.kocompiles cleanly from/usr/src/sys/netgraph7/bluetooth/socket/against the audit-source kernel (DragonFly 6.5-DEVELOPMENT #0, Thu Jul 2 06:02:54 UTC 2026). The vulnerable functionng_btsocket_rfcomm_send_creditsis inlined intong_btsocket_rfcomm_sessions_taskandobjdumpconfirms the unguardedidiv %r8instruction (divisor =pcb->mtu, offset0x24of the PCB) at module offset0xb418. There is no zero-check between loading the divisor and theidiv. (Full disassembly:objdump_unpatched.dis; focused comparison:idiv_comparison.txt.) - Userspace arithmetic replication (
divzero_proof.c) reproduces the exact kernel integer arithmetic on the confirmed path; withpcb->mtu = 0it raises SIGFPE (the userspace analogue of in-kernel #DE) 3/3 runs β deterministic, as expected for a zero-divisor integer divide.
It is NOT runtime-triggerable on this KVM guest because (a) the
ng_btsocket module is neither compiled into X86_64_GENERIC nor shipped as
a .ko, and (b) kldload of the freshly-built module fails with a netgraph
ABI version mismatch (KLD ng_btsocket.ko: depends on netgraph - not available
or version mismatch) β and even with the module loaded, reaching the live
path requires a real RFCOMM session over L2CAP/HCI, i.e. real bluetooth
hardware, which the QEMU guest lacks and DragonFlyBSD provides no virtual/software
HCI device for. The object-code-level proof is the accepted reproduction
(precedent: DF-0594 TKIP / DF-0616 netmap code-level harnesses; here it is
stronger β the actual vulnerable .ko is built and disassembled, not just a
userspace reimplementation).
This supersedes the prior inconclusive run (id 23): that run had only the
userspace arithmetic replication; this run adds the real-module build + objdump
proof + object-code-level fix validation.
The bug (confirmed line-by-line)
All citations are sys/netgraph7/bluetooth/socket/ng_btsocket_rfcomm.c unless
noted; line numbers are current master DEV (commit 6cc80ee9).
-
pcb->mtuisu_int16_t(sys/netgraph7/bluetooth/include/ng_btsocket_rfcomm.h:176). Default on DLC creation isRFCOMM_DEFAULT_MTU = 667(ng_btsocket_rfcomm.c:432). The only writer that takes a peer-controlled value isset_pn. -
ng_btsocket_rfcomm_set_pn(pcb, cr, flow_control, credits, mtu)(:3013-3043) performs, at:3019:c pcb->mtu = le16toh(mtu);with no validation β no!= 0, no range check. A PN (Parameter Negotiation) MCC frame carries a 16-bit MTU field that is fully attacker- chosen;mtu = 0is copied verbatim. (Confirmed by reading the source and by the objdump:set_pnis inlined and thele16toh(mtu)store reaches the same0x24(%r13)slot that theidivlater reads.) -
PN reachability from a peer frame.
ng_btsocket_rfcomm_receive_pn(:2881) only checkspn->dlci != 0(:2899); it never inspectspn->mtu. It callsset_pnat:2913(PN request, existing DLC),:2931(PN response), and:2955(incoming connection).receive_pnis called fromng_btsocket_rfcomm_receive_mcc(:2553), fromng_btsocket_rfcomm_receive_frame(:2022), fromng_btsocket_rfcomm_session_receive(:1679). The session-receive routine pulls frames off the L2CAP socket withsoreceive(s->l2so, β¦)at:1665β i.e. the data arrives from a remote RFCOMM peer over L2CAP/HCI. No local-only / software path feeds this socket. -
The unguarded divisor.
ng_btsocket_rfcomm_send_credits(pcb)(:3268-3309) computes, at:3283:c credits = ssb_space(&pcb->so->so_rcv) / pcb->mtu;ssb_space()returnslong(sys/sys/socketvar.h:270-282). The expression islong / u_int16_tβ on x86-64 anidivwith divisor 0 whenpcb->mtu == 0. A zero divisor traps as #DE (divide error) regardless of the dividend β0/0faults just asN/0does. β kernel panic. -
Trigger sequence & ordering (finding's central claim is correct).
ng_btsocket_rfcomm_receive_uih(:2356), on a data-bearing UIH frame (m0->m_pkthdr.len > 0,:2424) with credit-based flow control on (:2426), decrementsrx_cred(:2428) and, when it has dropped to<= RFCOMM_MAX_CREDITS/2, callssend_credits(pcb)at:2429. That call site is before the MTU-oversize check at:2438(if (m0->m_pkthdr.len > pcb->mtu)). So the divide-by-zero at:3283executes before any code that could indirectly noticemtu == 0. Confirmed.
Net: a remote peer that (a) establishes an L2CAP channel on PSM RFCOMM
(0x0003) and an RFCOMM session, (b) sends a PN MCC with mtu = 0 and
flow_control = 0xf0 (enabling CFC), and (c) sends one UIH data frame to
drive rx_cred down to MAX_CREDITS/2, deterministically panics the kernel
via #DE. No authentication is required (RFCOMM/SPP is unauthenticated by
design). This matches the finding's claim exactly.
Object-code-level proof (the new evidence)
The vulnerable .ko was built from /usr/src (same audit commit) and
disassembled. The inlined send_credits lives inside
ng_btsocket_rfcomm_sessions_task. objdump shows exactly one idiv in the
entire module, and it is the unguarded divide by pcb->mtu:
UNPATCHED ng_btsocket.ko β idiv at offset 0xb418 (NO guard before it):
b3df: movzwl 0x24(%r13),%edi ; edi = pcb->mtu (the divisor)
...
b3fa: movzwl %di,%r8d ; r8 = pcb->mtu (divisor, zero-extended)
...
b413: mov %rsi,%rax ; rax = ssb_space(...) (dividend)
b416: cqto ; sign-extend
b418: idiv %r8 ; *** DIVIDE BY pcb->mtu β NO GUARD ***
; *** if r8==0 (peer PN mtu=0) -> #DE -> panic ***
There is no test/je/jne on r8/edi between loading pcb->mtu
(b3df/b3fa) and the idiv (b418). The divide is unconditional. This is
the compiled form of the unguarded line :3283. (Full module disassembly in
objdump_unpatched.dis.)
Why it does NOT reproduce at runtime on this guest
| Check on the running master DEV guest | Result |
|---|---|
kldstat |
kernel, ehci.ko, xhci.ko only β no bluetooth |
grep bluetooth netgraph7 ng_bt X86_64_GENERIC |
0 matches β not configured |
ng_btsocket.ko build from /usr/src |
succeeds (rc=0) β code is healthy |
kldload ng_btsocket.ko (freshly built) |
fails: depends on netgraph - not available or version mismatch (ABI mismatch between the Jul-2 kernel build and the Jul-3 module build; netgraph.ko is busy/in-kernel and cannot be swapped) |
socket(AF_BLUETOOTH=31, β¦) from userspace |
-1 β socket domain not registered |
| bluetooth HW on QEMU guest | none (no -device bt*); DragonFlyBSD has no virtual HCI |
So the vulnerable code is dead on the running kernel image (the module is
not loaded), and even rebuilding+loading it would not help: the only way to
feed a PN frame to receive_pn is over a real RFCOMM/L2CAP/HCI session, and
DragonFlyBSD has no virtual HCI device. The object-code-level proof (module
build + objdump + userspace arithmetic replication) is the accepted
reproduction.
Exploit chain
Not a memory-corruption class β it is a single-instruction DoS (divide-by-zero
β #DE β panic). There is no further primitive to derive from the #DE itself:
on x86 the trap is non-resumable and the kernel panics. Weaponization =
remote unauthenticated kernel panic of any DragonFlyBSD host that (a) has
the ng_btsocket module loaded (or bluetooth compiled in) and (b) has a
bluetooth adapter up and accepting RFCOMM connections (SPP). Single malformed
PN + one UIH frame; deterministic. Availability-only (C:N/I:N/A:H), matching
the finding's CVSS AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H β adjacency is
required (bluetooth range), there is no confidentiality or integrity impact.
Recommended fix & validation
fix.diff (validated: applies cleanly with patch -p1 both directions) adds
two guards, both minimal:
- Root cause β in
ng_btsocket_rfcomm_set_pn(:3019), do not store a zero MTU; fall back toRFCOMM_DEFAULT_MTU:pcb->mtu = (le16toh(mtu) != 0) ? le16toh(mtu) : RFCOMM_DEFAULT_MTU; - Defense-in-depth at the fault site β in
ng_btsocket_rfcomm_send_credits(:3283), bail out before the divisor:if (pcb->mtu == 0) return (EINVAL);
Either guard alone prevents the panic; both together close the untrusted-input
path and protect the divisor regardless of how pcb->mtu could later become
zero. This supersedes any pre-verification proposal (no finding markdown
exists for DF-0281; this is the authoritative verified fix).
Object-code-level fix validation (Phase 8)
The fix was validated at the .ko object-code level (a full kernel rebuild
+ runtime trigger is impossible: no bluetooth HW + module won't load). The
patched module was rebuilt from the same source with fix.diff applied, and
objdump confirms the compiler now emits a guard immediately before the
idiv:
PATCHED ng_btsocket.ko β idiv at offset 0xb4b2, GUARDED by test/je:
b46b: movzwl 0x24(%r13),%ecx ; ecx = pcb->mtu (the divisor)
b470: test %cx,%cx ; *** THE GUARD: is pcb->mtu == 0? ***
b473: je b7d3 ; *** YES -> jump to clean return (b7d3),
; SKIPPING the divide entirely ***
...
b498: movzwl %cx,%edi ; edi = pcb->mtu (KNOWN NON-ZERO here)
...
b4b0: cqto
b4b2: idiv %rdi ; *** DIVIDE β only reached if pcb->mtu != 0 ***
b7d3: mov 0xb8(%rbx),%eax ; <-- je target: clean return path
b7d9: jmpq ab8f ; (function epilogue)
The test %cx,%cx; je b7d3 at b470/b473 is exactly the compiler's
emission of if (pcb->mtu == 0) return (EINVAL);. When pcb->mtu == 0,
execution jumps past the idiv to b7d3 (clean return). The divide-by-zero
is now impossible. (Full module disassembly in objdump_patched.dis.)
The userspace arithmetic replication (divzero_proof_fixed, compiled with
-DFIX_MTU) also completes with NO FAULT when pcb->mtu is clamped to
RFCOMM_DEFAULT_MTU, confirming the arithmetic path is closed.
Before/after contrast:
- Unpatched .ko: one idiv %r8, no preceding zero-check on the divisor
β #DE when pcb->mtu == 0 β kernel panic.
- Patched .ko: idiv %rdi preceded by test %cx,%cx; je <return>
β divide skipped when pcb->mtu == 0 β no fault.
PoC changes (this run vs prior inconclusive run)
The PoC sources (divzero_proof.c, build.sh, run.sh, fix.diff) are
unchanged β the prior run's harness and fix were already correct. What
changed is the evidence: this run adds (a) the actual ng_btsocket.ko
module build log proving the vulnerable code links cleanly against the audit
kernel, (b) objdump_unpatched.dis / objdump_patched.dis proving the
unguarded idiv exists in the compiled binary and is guarded after the fix,
and (c) idiv_comparison.txt β the focused before/after object-code
comparison. This elevates the verdict from inconclusive (userspace
arithmetic only) to reproduced (object-code-level proof on the real built
module).
Fix verification
fixedVALIDATED at object-code level: the unpatched ng_btsocket.ko (built from /usr/src) contains an unguarded 'idiv %r8' at offset 0xb418 with divisor=pcb->mtu and NO preceding zero-check. After applying fix.diff and rebuilding the module, objdump confirms the compiler now emits 'test %cx,%cx; je b7d3' (offset 0xb470) immediately before the 'idiv %rdi' (offset 0xb4b2) -- when pcb->mtu==0, execution jumps to b7d3 (clean return) and the divide is skipped entirely. The userspace arithmetic replication with -DFIX_MTU also completes with NO FAULT. Runtime trigger impossible on this guest (no bluetooth HW + module won't kldload), so object-code-level validation -- the strongest possible without HW -- is the Phase 8 proof.
=== BEFORE (unpatched module): unguarded idiv, NO zero-check ===
b3df: movzwl 0x24(%r13),%edi ; load pcb->mtu
b3fa: movzwl %di,%r8d ; r8 = pcb->mtu (divisor)
b418: idiv %r8 ; *** DIVIDE -- #DE if mtu==0 ***
=== AFTER (patched module): idiv guarded by test/je ===
b46b: movzwl 0x24(%r13),%ecx ; load pcb->mtu
b470: test %cx,%cx ; *** GUARD: is mtu==0? ***
b473: je b7d3 ; *** YES -> skip divide (clean return) ***
b498: movzwl %cx,%edi ; edi = mtu (known non-zero here)
b4b2: idiv %rdi ; divide -- only if mtu!=0
=== userspace replication ===
unpatched: '### SIGFPE: divide by zero at step 3 ###' (3/3 runs)
fixed (-DFIX_MTU): 'NO FAULT: pcb->mtu was guarded before the divisor (fix active)'
Confirmed kernel references
- sys/netgraph7/bluetooth/socket/ng_btsocket_rfcomm.c:3019
- sys/netgraph7/bluetooth/socket/ng_btsocket_rfcomm.c:3283
- sys/netgraph7/bluetooth/socket/ng_btsocket_rfcomm.c:2429
- sys/netgraph7/bluetooth/socket/ng_btsocket_rfcomm.c:2438
- sys/netgraph7/bluetooth/socket/ng_btsocket_rfcomm.c:2899
- sys/netgraph7/bluetooth/include/ng_btsocket_rfcomm.h:176
Detail
Exploit chain
none -- not a memory-corruption class. Single-instruction DoS: idiv-by-0 -> #DE -> non-resumable kernel trap -> panic. No further primitive derivable. Weaponization = remote unauthenticated kernel panic of any DragonFlyBSD host with ng_btsocket loaded + a bluetooth adapter accepting RFCOMM (SPP): one PN(mtu=0, flow_control=0xf0) + one UIH frame; deterministic. Availability-only (C:N/I:N:A:H), CVSS AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H.
Evidence (decisive lines)
=== UNPATCHED ng_btsocket.ko objdump (idiv at 0xb418, NO guard) ===
b3df: movzwl 0x24(%r13),%edi ; edi = pcb->mtu (divisor)
b3fa: movzwl %di,%r8d ; r8 = pcb->mtu (divisor, zero-extended)
b413: mov %rsi,%rax ; dividend = ssb_space(...)
b416: cqto
b418: idiv %r8 ; *** DIVIDE BY pcb->mtu -- NO GUARD -- #DE if 0 ***
=== userspace replication (run.log, vulnerable) ===
STEP 1: peer PN with mtu=0 processed by set_pn (line 3019); now pcb->mtu = 0
STEP 3: send_credits line 3283: credits = ssb_space / pcb->mtu ...
### SIGFPE: divide by zero at step 3 (send_credits, line 3283) ###
PROOF: pcb->mtu==0 reached the unguarded divisor -> kernel would #DE/panic
(stress: SIGFPE 3/3 runs -- deterministic)
PoC changes
PoC sources (divzero_proof.c, build.sh, run.sh, fix.diff) UNCHANGED -- the prior inconclusive run's harness and fix were already correct. New EVIDENCE this run: (a) module_build.log -- full output of building the ACTUAL ng_btsocket.ko from /usr/src (rc=0); (b) objdump_unpatched.dis / objdump_patched.dis -- full disassemblies; (c) idiv_comparison.txt -- focused before/after object-code comparison proving the unguarded 'idiv %r8' becomes a guarded 'idiv %rdi' preceded by 'test %cx,%cx; je'; (d) fix_build.log -- Phase 8 patched-module rebuild log; (e) rewritten VERDICT.md/README.md/manifest.json. Elevates verdict from inconclusive (userspace arithmetic only) to reproduced (real-module objdump proof).
Verified recommended fix
fix.diff applies two minimal guards (both in sys/netgraph7/bluetooth/socket/ng_btsocket_rfcomm.c): (1) root cause at :3019 -- clamp peer mtu to RFCOMM_DEFAULT_MTU when zero: 'pcb->mtu = (le16toh(mtu) != 0) ? le16toh(mtu) : RFCOMM_DEFAULT_MTU;'; (2) defense-in-depth at the fault site :3283 -- 'if (pcb->mtu == 0) return (EINVAL);' before the divide. Either alone prevents the panic; both close the untrusted-input path. Full git-apply-able diff in findings/poc/DF-0281/fix.diff.
Verdict
REPRODUCED at code/object-code level (certain). The bug is real and confirmed three independent ways. (1) Static trace: ng_btsocket_rfcomm_set_pn copies a peer-supplied PN mtu into pcb->mtu with NO validation at sys/netgraph7/bluetooth/socket/ng_btsocket_rfcomm.c:3019; ng_btsocket_rfcomm_send_credits divides ssb_space/pcb->mtu unconditionally at :3283; the send_credits call site at :2429 is BEFORE the mtu-oversize check at :2438, so a peer PN with mtu=0 + one UIH frame deterministically hits idiv-by-0 -> #DE -> kernel panic. (2) Built the ACTUAL ng_btsocket.ko from /usr/src against the audit kernel (rc=0); objdump confirms exactly one 'idiv %r8' at module offset 0xb418 with divisor=pcb->mtu (loaded from PCB offset 0x24) and NO preceding zero-check. (3) Userspace arithmetic replication raises SIGFPE 3/3 runs. Not runtime-triggerable on this guest (ng_btsocket not in GENERIC, freshly-built .ko won't kldload due to netgraph ABI mismatch, and the live path needs real bluetooth HW which QEMU lacks) -- the object-code proof is the accepted reproduction. This supersedes the prior inconclusive run which had only userspace arithmetic; this run adds the real-module build + objdump proof.
No comments yet.