# DF-3477 — Unprivileged L2CAP PSM bind (no privilege check in ng_btsocket_l2cap_bind) ## What `ng_btsocket_l2cap_bind()` (sys/netgraph7/bluetooth/socket/ng_btsocket_l2cap.c:2037-2096) contains no `priv_check()`/capability check and no PSM range restriction. Any local user can `bind()` a `PF_BLUETOOTH / SOCK_SEQPACKET / BLUETOOTH_PROTO_L2CAP` socket to **any** L2CAP PSM — including the assigned/reserved service PSMs (1 = SDP service discovery, 3 = RFCOMM) — and then `listen()` on it. Because inbound L2CAP connections are dispatched by `ng_btsocket_l2cap_pcb_by_addr()` (:2679-2699, exact bdaddr match first, then the ANY-bound fallback), the first socket bound to a PSM receives **all** inbound connections for that PSM. An unprivileged user can therefore squat or hijack local Bluetooth services on any system where the ng_btsocket stack is loaded and a Bluetooth adapter is present: the service's own listener either fails to bind (EADDRINUSE) or, if it bound later/earlier without the exact address, connections are delivered to the attacker's socket. Related sibling (filed separately for the raw node): DF-0499 (read-only node ioctls). This finding is the SEQPACKET data-path equivalent with a stronger impact (service impersonation rather than info exposure). ## Reproduce Guest: DragonFly 6.5-DEVELOPMENT #0 (X86_64_GENERIC, INVARIANTS), netgraph7 module stack loaded: kldload netgraph.ko ng_bluetooth.ko ng_btsocket.ko Build and run as an unprivileged user (uid 1001): cc -o df3477_bind df3477_bind.c ./df3477_bind Expected (vulnerable): DF-3477: unprivileged L2CAP PSM bind test (uid=1001) uid=1001 bind(psm=1) -> SUCCESS uid=1001 bind(psm=3) -> SUCCESS RESULT: VULNERABLE — unprivileged user occupied a reserved L2CAP service PSM uid=1001 bind(psm=1) -> Address already in use The second `bind(psm=1)` returning EADDRINUSE proves the occupation semantics that make service hijacking possible. ## Fix direction Add a privilege check for non-ephemeral PSMs (or at minimum PSMs in the assigned/reserved range < 0x1001), e.g.: ```diff --- a/sys/netgraph7/bluetooth/socket/ng_btsocket_l2cap.c +++ b/sys/netgraph7/bluetooth/socket/ng_btsocket_l2cap.c @@ -2071,6 +2071,12 @@ ng_btsocket_l2cap_bind(netmsg_t msg) psm = le16toh(sa->l2cap_psm); + + /* Assigned/reserved PSMs require privilege */ + if (psm != 0 && psm < 0x1001) { + struct thread *td = msg->bind.nm_td; + if (td && priv_check(td, PRIV_NETBOUND) != 0) + ERROUT(EACCES); + } ``` (matching whatever privilege primitive the project prefers for socket binds).