DF-0281 — OBJECT-CODE-LEVEL PROOF: unguarded `idiv` (unpatched) vs guarded (patched) ==================================================================================== Both snippets are from `ng_btsocket_rfcomm_send_credits()` inlined into `ng_btsocket_rfcomm_sessions_task` in the ACTUAL compiled `ng_btsocket.ko` module built 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 divisor is `pcb->mtu` (loaded from offset 0x24 of the PCB, a `u_int16_t`). In the source this is line 3283: credits = ssb_space(&pcb->so->so_rcv) / pcb->mtu; When `pcb->mtu == 0` (set by a peer PN MCC frame, line 3019, no validation), the `idiv` raises #DE -> kernel panic. UNPATCHED (vulnerable) — `idiv %r8` at offset 0xb418, NO guard before it: ------------------------------------------------------------------------ b3df: movzwl 0x24(%r13),%edi ; edi = pcb->mtu (the divisor) b3e4: test %edx,%edx ; (unrelated CFC flag check) b3e6: jne b6bc b3ec: mov 0xf0(%rcx),%rsi ; \ ssb_space(&pcb->so->so_rcv) b3f3: mov 0xf8(%rcx),%rax ; > (the dividend) b3fa: movzwl %di,%r8d ; / r8 = pcb->mtu (ZERO-EXTENDED = divisor) b3fe: sub 0x90(%rcx),%rax b405: sub 0x88(%rcx),%rsi b40c: cmp %rax,%rsi b40f: cmovg %rax,%rsi b413: mov %rsi,%rax ; rax = dividend b416: cqto ; sign-extend rax into rdx:rax b418: idiv %r8 ; *** DIVIDE BY pcb->mtu — NO GUARD *** ; *** if r8==0 -> #DE -> kernel panic *** b41b: mov %eax,%r9d ; r9d = credits NOTE: there is NO `test %r8d,%r8d; je` or any zero-check on the divisor between loading pcb->mtu (b3df/b3fa) and the `idiv` (b418). The divide is unconditional. This is the compiled form of the unguarded line 3283. PATCHED (fix.diff applied) — `idiv %rdi` 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 *** b479: mov 0x0(%r13),%rsi ; only reached when pcb->mtu != 0 b47d: testb $0x4,0xe1(%rsi) b484: jne b5b4 b48a: mov 0xf0(%rsi),%rax ; \ ssb_space(...) dividend b491: mov 0xf8(%rsi),%rdx ; > b498: movzwl %cx,%edi ; / edi = pcb->mtu (KNOWN NON-ZERO here) b49b: sub 0x90(%rsi),%rdx b4a2: sub 0x88(%rsi),%rax b4a9: cmp %rdx,%rax b4ac: cmovg %rdx,%rax b4b0: cqto b4b2: idiv %rdi ; *** DIVIDE — only reached if pcb->mtu != 0 *** b4b5: mov %eax,%r9d ; r9d = credits ... b7d3: mov 0xb8(%rbx),%eax ; <-- je target: clean return path b7d9: jmpq ab8f ; (function epilogue / next iteration) The `test %cx,%cx; je b7d3` at b470/b473 is exactly the compiler's emission of the fix's `if (pcb->mtu == 0) return (EINVAL);` guard. When pcb->mtu == 0, execution jumps past the `idiv` to b7d3 (clean return). The divide-by-zero is now impossible. CONCLUSION: fix.diff closes the bug at the object-code level. The unguarded `idiv %r8` (unpatched) becomes a guarded `idiv %rdi` preceded by `test %cx,%cx; je ` (patched).