DF-0625 / args_overflow.c
/* * DF-0625 — ng_l2cap L2CA_Ping missing arglen check (kernel heap OOB read). * * Trigger path (when ng_l2cap is loaded + a BT lower layer/HCI is connected): * * socket(AF_NETGRAPH, ...) * bind to a node, connect to "l2cap" hook * send NGM_L2CAP_L2CA_PING control message with: * - arglen = 8 (just the ng_l2cap_l2ca_ping_ip header) * - ip->echo_size = 200 (claimed echo payload size) * - ip->bdaddr = remote BT addr (attacker-controlled peer) * * Expected on vulnerable kernel + with BT HCI lower layer attached: * - ng_l2cap_l2ca_ping_req passes the `arglen < sizeof(*ip)` check (:1306) * - passes the `echo_size <= MAX` check (:1316) * - reaches _ng_l2cap_echo_req at :1357 with msg->data+8 and size=200 * - m_copyback reads 200 bytes from msg->data+8 into a fresh mbuf * (msg was allocated as sizeof(ng_mesg)+8, so the read runs ~192 bytes * past the allocation into adjacent kernel heap) * - the mbuf is queued to the BT lower layer and transmitted as an * L2CAP Echo Request to ip->bdaddr -> kernel heap info leak over the air * * WHY THIS PoC DOES NOT FIRE ON THE AUDIT GUEST: * * 1. The audit guest has NO Bluetooth hardware and no ng_hci/ng_ubt lower * layer. Without an HCI hook connected to the l2cap node, the bug path * at ulpi.c:1357 is unreachable: * * ulpi.c:1325 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr); // NULL * ulpi.c:1328 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr); * llpi.c:87-92 if (l2cap->hci == NULL) return ENOTCONN; * ulpi.c:1329 if (error != 0) goto out; // takes the early out * * The function returns ENOTCONN long before reaching the buggy * _ng_l2cap_echo_req call. The OOB read cannot occur. * * 2. ng_l2cap.ko is also not loadable on this guest: ng_l2cap declares * MODULE_DEPEND on netgraph (NG_ABI_VERSION), and the pre-installed * /boot/kernel/netgraph.ko in the audit snapshot is ABI-incompatible * with a freshly-built ng_l2cap.ko. Even after rebuilding both from * the same source, the in-tree netgraph.ko loaded by the rc scripts * is the older version. * * The bug is **confirmed by source-level analysis** (see VERDICT.md): the * missing arglen check is real and exploitable in any deployment that * actually uses DragonFly's Bluetooth L2CAP stack. * * This PoC source documents the trigger so a maintainer with a working * ng_l2cap + ng_hci setup (or an emulator like QEMU + an HCI passthrough) * can verify the fix. */ #include <stdio.h> #include <stdlib.h> /* * The headers above (netgraph7/*, bluetooth/*) live inside the kernel tree * and are not exposed to userland builds. They are not needed for this PoC, * which is a documentation stub: the actual trigger requires kernel-side * netgraph message construction that is far cleaner to drive via ngctl(8) * than via this userland C. See VERDICT.md for the path analysis. */ int main(void) { fprintf(stderr, "DF-0625: ng_l2cap L2CA_Ping missing arglen check\n" "\n" "This PoC would, on a kernel with working ng_l2cap + an HCI\n" "lower layer connected:\n" " 1. open a netgraph control socket\n" " 2. create + connect an l2cap node\n" " 3. send NGM_L2CAP_L2CA_PING with arglen=8, echo_size=200\n" " 4. trigger _ng_l2cap_echo_req's m_copyback to read ~192 bytes\n" " past the ng_mesg allocation into adjacent kernel heap\n" " 5. capture the resulting L2CAP Echo Request at the attacker's\n" " Bluetooth peer to recover kernel heap contents\n" "\n" "On THIS audit guest: no Bluetooth hardware and no ng_hci lower\n" "layer, so ng_l2cap_lp_con_req returns ENOTCONN and the bug path\n" "is unreachable. The bug is confirmed in source (see VERDICT.md)\n" "and the fix is in fix.diff.\n"); return 0; } |