/*
 * DF-1124 userspace harness — iwn5000_rx_calib_results signed-int underflow +
 * unbounded heap-copy primitive.
 *
 * The kernel bug (sys/dev/netif/iwn/if_iwn.c:3364-3405):
 *     len = (le32toh(desc->len) & 0x3fff) - 4;
 *   - signed int.  If (desc->len & 0x3fff) < 4, len underflows to a huge
 *     negative; kmalloc(len) promotes to size_t -> huge alloc -> ENOMEM
 *     (caught at :3396) -- benign for tiny masked lens.
 *   - But if firmware reports e.g. masked len = 16380, len becomes 16376;
 *     kmalloc(16376) succeeds, then `memcpy(buf, calib, len)` at :3405 reads
 *     16376 bytes starting at `calib = desc + 1` which lives inside a 4 KiB
 *     RX mbuf cluster -> reads up to ~12 KiB past the mbuf -> kernel OOB read
 *     (info leak / panic). The calibcmd buffer is later replayed to runtime
 *     firmware via iwn5000_send_calibration -> data exfiltration path.
 *
 * Reachability: requires Intel WiFi (iwn) adapter + malicious/compromised
 * firmware or DMA injection. Not present on this audit guest.
 *
 * Build:  cc -O2 -o harness harness.c
 * Run:    ./harness
 * Expected: demonstrates the underflow AND the OOB read length.
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define IWN_RBUF_SIZE  4096        /* RX mbuf cluster size (4 KiB) */
#define IWN_CALIB_OFF  8           /* calib = desc + 1, desc is 8 bytes */

/* mimic iwn_rx_desc tail */
struct desc { uint32_t len; uint8_t  pad[4]; };

static void test(unsigned masked_len) {
    /* desc->len already on the wire; we mask in the handler */
    int len = (int)(masked_len & 0x3fff) - 4;
    printf("masked desc->len & 0x3fff = %u\n", masked_len & 0x3fff);
    printf("len = masked - 4           = %d\n", len);
    if (len < 0) {
        printf("  -> signed UNDERFLOW. kmalloc((size_t)%d) = kmalloc(%zu)\n",
               len, (size_t)len);
        printf("  -> kmalloc fails (ENOMEM), no further damage on this path.\n\n");
        return;
    }
    /* positive len: is it within the RX mbuf cluster? */
    int avail = IWN_RBUF_SIZE - IWN_CALIB_OFF;
    printf("  memcpy(calibcmd.buf, calib, %d) from offset %d in %d-byte mbuf\n",
           len, IWN_CALIB_OFF, IWN_RBUF_SIZE);
    if (len > avail) {
        printf("  -> OOB READ of %d bytes past mbuf cluster boundary "
               "(info leak / panic source)\n\n", len - avail);
    } else {
        printf("  -> within mbuf, benign.\n\n");
    }
}

int main(void) {
    printf("=== DF-1124 iwn5000_rx_calib_results primitive demo ===\n\n");

    printf("[case 1] firmware reports masked len = 0 (underflow)\n");
    test(0);

    printf("[case 2] firmware reports masked len = 3 (underflow)\n");
    test(3);

    printf("[case 3] firmware reports masked len = 16380 (OOB read)\n");
    test(16380);

    printf("[case 4] firmware reports masked len = 200 (benign)\n");
    test(200);

    printf("Conclusion: no clamp on len -> both underflow and over-read are\n");
    printf("reachable from a buggy/compromised firmware or DMA injection.\n");
    return 0;
}
