⬢ DragonFlyBSD Kernel Audit
DF-3525 / run.log
← back to finding ↓ download raw
DF-3525 run.log — gated repro on DF-3524-FIXED kernel #1 (stock ng_l2cap module)

NOTE: on the STOCK kernel this entry is unreachable because DF-3524
(ng_uncallout/ETIMEDOUT wedge) prevents any L2CAP con from ever reaching
CON_OPEN (llpi.c:648 state check drops all ACL data).  Fixing DF-3524
(kern_timeout.c, kernel #1) un-gates it; the reassembly defect itself is
present in the stock module.

[1] # ./l2cap_con lie
LP_CON_IND          -> ok
HCI_NODE_UP         -> ok          (pkt_size=65535, num_pkts=8)
L2CAP SET_DEBUG(9)  -> ok
LP_CON_CFM (pos)    -> ok   (connection accepted -> CON_OPEN)
ECHO_RSP            -> 13 real bytes received
outgoing ACL header length field = 65527
real payload bytes in mbuf chain  = 9
LIE PROPAGATED: ACL header claims 65527 bytes, 9 exist -> 65518 phantom
bytes (driver TX OOB read on real HW)
exit=0

    (13 received bytes = 5-byte packed ACL hdr + 4-byte L2CAP hdr +
     4-byte cmd hdr; phantom = 65527 - 8 = 65519 exactly as constructed.)

[2] kernel side (dmesg):
    ng_l2cap_lp_receive: got ACL data packet, con_handle=291, PB=0x2, length=8
    ng_l2cap_lp_receive: staring new L2CAP packet, con_handle=291, length=65523
    ng_l2cap_lp_receive: got ACL data packet, con_handle=291, PB=0x1, length=65519
    ng_l2cap_lp_send: attaching ACL packet, con_handle=291, PB=0x2, length=65527
    ng_l2cap_lp_deliver: sending ACL packet, con_handle=291, len=65532

    -> the ZERO-byte FRAGMENT claiming 65519 bytes was accepted
       (llpi.c:702 `rx_pkt->m_pkthdr.len += length` never checks `length`
        against the bytes actually present), the completed "packet"
       passed ng_l2cap_receive's consistency check by construction
       (hdr->length == pkthdr.len - 4), and the echo response carried
       the lie into the outgoing ACL header (lp_send :548).

[3] CONTROL (truthful single-fragment echo, same session type):
    ECHO_RSP -> received 17 bytes; ACL length field == actual.

[4] FIX VALIDATED (module-level, ng_l2cap_llpi.c claim check:
    `if (length > m->m_pkthdr.len) { error = EMSGSIZE; goto drop; }`
    right after length = le16toh(acl_hdr->length)):
    ./l2cap_con lie  -> ECHO_RSP NOT RECEIVED   (lie suppressed)
    ./l2cap_con con  -> ECHO_RSP received 17 bytes, exit=0
                        (truthful traffic unaffected)
    kernel log for con: got ACL ... length=12 == actual.