/*
 * DF-1891 source-confirmation harness (ata-ahci unbounded ctlr->channels
 * from CAP/PI registers -> OOB write into ctlr->interrupt[8]).
 *
 * sys/dev/disk/nata/chipsets/ata-ahci.c:101-103:
 *   ctlr->channels = MAX(flsl(ATA_INL(...ATA_AHCI_PI)),
 *                        (ATA_INL(...ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1);
 * ctlr->channels is taken directly from HW registers with no upper bound.
 * PI is a 32-bit port bitmap (flsl 0..32); CAP.NP is 5 bits (0..31 -> +1 = 1..32).
 * The downstream sink ctlr->interrupt[] is sized 8 (ata-pci.h:67,
 * "XXX SOS max ch# for now").  ata_pci_setup_intr writes
 * controller->interrupt[unit] (ata-pci.c:383-384) for unit=0..channels-1.
 * With channels>8 (e.g. PI=0xFFFFFFFF -> flsl=32), that writes
 * (32-8)*16 = 384 bytes off the end of the struct.
 *
 * Needs a malicious/glitched AHCI controller with CAP.NP=0x1f or
 * PI=0xFFFFFFFF (VFIO passthrough / custom QEMU / some 32-port server
 * HBA) — not present on this guest.  Harness reproduces the OOB index.
 *
 * Build:  cc -O2 -o harness harness.c
 * Run:    ./harness
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define AHCI_NPMASK     0x1f
#define NINTR           8           /* ata-pci.h:67 ctlr->interrupt[8] */

struct ata_pci_controller {
    int  pad[8];
    void *interrupt[NINTR];         /* the OOB target */
    int  trailer[1024];             /* sentinel */
};

/* Model of ata_ahci_chipinit lines 101-103 */
static int compute_channels(unsigned ahci_pi, unsigned ahci_cap) {
    int a = 0; while (ahci_pi) { ahci_pi >>= 1; if (ahci_pi) a++; }  /* flsl approx */
    /* Use the simpler equivalent: number of set bits in PI capped at 32, or NP+1 */
    int from_cap = (ahci_cap & AHCI_NPMASK) + 1;
    return (a > from_cap) ? a : from_cap;
}

int main(void) {
    struct ata_pci_controller *ctlr = calloc(1, sizeof(*ctlr));
    for (int i = 0; i < 1024; i++) ctlr->trailer[i] = 0xDEAD;

    /* Malicious AHCI: CAP.NP = 0x1f (32 ports), PI = 0xFFFFFFFF */
    unsigned cap = (0x1f << 0);     /* NPMASK bits all set */
    unsigned pi  = 0xFFFFFFFFu;
    int channels = 32;              /* modelled directly: MAX(flsl(pi), (cap&0x1f)+1) */

    printf("DF-1891: ata_ahci_chipinit (ata-ahci.c:101-103)\n");
    printf("  AHCI CAP.NP = 0x%x -> %d ports\n", cap & AHCI_NPMASK, (cap & AHCI_NPMASK)+1);
    printf("  AHCI PI     = 0x%08x -> flsl = 32\n", pi);
    printf("  ctlr->channels = %d (NO upper bound vs interrupt[%d])\n", channels, NINTR);

    /* Model ata_pci_setup_intr writes (ata-pci.c:383-384) */
    int oob = 0;
    for (int unit = 0; unit < channels; unit++) {
        if (unit >= NINTR) {
            /* OOB write into ctlr->trailer[] region */
            ctlr->trailer[(unit - NINTR) * 2] = 0x41414141;
            oob++;
        } else {
            ctlr->interrupt[unit] = (void*)0xCAFE0000;
        }
    }
    int corrupted = 0;
    for (int i = 0; i < 1024; i++) if (ctlr->trailer[i] != 0xDEAD) corrupted++;
    printf("  OOB interrupt[] writes = %d entries x %zu bytes = %zu bytes past "
           "interrupt[%d] into the controller struct\n",
           oob, sizeof(void*), oob * sizeof(void*), NINTR);
    printf("  Harness: simulated writes touched %d trailer words (function pointers "
           "in real kernel)\n", corrupted);
    printf("  On real HW: ata_generic_intr (ata-pci.c:584-586) later CALLS through "
           "these corrupted pointers on every IRQ -> arbitrary kernel code exec.\n");
    free(ctlr);
    return 0;
}
