# DF-3478 — listen(2) on L2CAP SEQPACKET socket: unbounded solisten()↔pru_listen recursion → kernel stack overflow → double fault (unprivileged kernel panic)

## What

`ng_btsocket_l2cap_listen()` — the `pru_listen` handler for
`PF_BLUETOOTH/SOCK_SEQPACKET/L2CAP` — ends with:

```c
	solisten(so, backlog, td);			/* ng_btsocket_l2cap.c:2460 */
```

On DragonFly, `solisten()` (sys/kern/uipc_socket.c:330-344) is the **syscall-side**
helper: it sets `SO_ACCEPTCONN`/`so_qlimit` and then **calls
`so_pru_listen(so, td)` itself** (uipc_socket.c:343), which dispatches the
listen netmsg to `so->so_port` — for this socket family
`netisr_cpuport(0)` (no `pr_initport` in the protosw, sys/kern/uipc_socket.c:259).

The handler therefore re-enters its own dispatch:

```
listen(2) → kern_listen → solisten → so_pru_listen
   → lwkt_domsg(netisr_cpuport(0)) → ng_btsocket_l2cap_listen
      → solisten → so_pru_listen
         → lwkt_domsg(same port; dispatched inline on the netisr thread)
            → ng_btsocket_l2cap_listen → solisten → ...   (unbounded)
```

Each level consumes kernel stack until the push in `so_pru_listen+0x4d`
(the `callq lwkt_domsg`) lands on an unmapped page → CPU double fault →
`panic: double fault` → system down in DDB.

This is a porting defect: in FreeBSD `solisten()` does not re-dispatch
`pru_listen`; the 2008-era netgraph7 port kept the call without adapting it to
DragonFly's message-dispatching socket layer.

## Reachability / threat

* Requires only `ng_btsocket.ko` to be loaded (Bluetooth stack in use).
* `socket()` + `bind()` + `listen()` — **no privilege needed anywhere**
  (see DF-3477 for the unprivileged bind). Three syscalls, 100% reproducible.
* No Bluetooth hardware or peer required.

## Reproduce (3/3 reproductions, two independent boots + one fresh driver)

    cc -o step_listen step_listen.c
    ./step_listen

Console (serial) shows, then the guest dies:

    STEP: start
    STEP: socket done
    STEP: bind done
    DOUBLE FAULT
    Fatal double fault
    rip = 0xffffffff806c2b4d        <-- so_pru_listen+0x4d (callq lwkt_domsg)
    rsp = 0xfffff8008d1f6000
    panic: double fault

(`0xffffffff806c2b4d` resolves inside `so_pru_listen` in the guest's
/boot/kernel/kernel via nm/objdump.)

## Fix (validated)

Remove the `solisten()` call from the handler — the syscall side already ran
it before dispatch. See fix.diff. With the patched module the same program
prints:

    STEP: listen done
    STEP: ALL OK

and `accept()` on the listener works (used by the DF-3479/DF-3480 harness to
drive an inbound connection to OPEN).

The same defect exists in `ng_btsocket_rfcomm.c:974` (and `:1427` indirectly)
— separate file, reported via cross-reference.
