/*
 * DF-1192 harness — ciss_filter_physical negative bus index
 * (userspace replica of sys/dev/raid/ciss/ciss.c:1538-1554)
 *
 * For each physical LUN the controller returns a 32-bit "extra_address". The
 * driver computes:
 *     bus    = CISS_EXTRA_BUS2(ea) - 1;	// 0..63, then -1
 *     target = CISS_EXTRA_TARGET2(ea);	// 0..255
 *     sc->ciss_physical[bus][target].cp_address = ...;
 * The preceding filter (ciss.c:1539-1541) rejects only BUS3/TARGET3/MODE2==3,
 * NOT BUS2==0. When BUS2==0 -> bus=-1 -> ciss_physical[-1][target] reads a
 * kernel pointer from BEFORE the array and writes cp_address/cp_online through
 * it. This harness reproduces the negative index with the real macros.
 *
 * Build: cc -O2 -Wall -o harness harness.c
 * Run:   ./harness
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

/* ---- real kernel macros (sys/dev/raid/ciss/cissreg.h:62-67) ---- */
#define CISS_EXTRA_MODE2(extra)   ((extra & 0xc0000000) >> 30)
#define CISS_EXTRA_BUS2(extra)    ((extra & 0x3f000000) >> 24)	/* 0..63 */
#define CISS_EXTRA_TARGET2(extra) ((extra & 0x00ff0000) >> 16)	/* 0..255 */
#define CISS_EXTRA_BUS3(extra)    ((extra & 0x00003f00) >> 8)
#define CISS_EXTRA_TARGET3(extra) ((extra & 0x000000ff))
#define CISS_MAX_PHYSTGT 256	/* cissvar.h:171 */

struct ciss_pdrive { uint64_t cp_address; int cp_online; };

struct sc_replica {
	int    ciss_max_physical_bus;	/* rows of ciss_physical[][] */
	struct ciss_pdrive **ciss_physical;
};

/* exact replica of the filter+index (ciss.c:1538-1554).
 * Returns: 0 = in-bounds, 1 = OOB (would-be write), 2 = filtered out (continue).
 * Sets *bus_out to the computed bus index. */
static int filter_and_index(struct sc_replica *sc, uint32_t ea, int *bus_out)
{
	int bus, target;

	/* ciss.c:1539-1541 filter */
	if ((CISS_EXTRA_BUS3(ea) != 0) || (CISS_EXTRA_TARGET3(ea) != 0) ||
	    (CISS_EXTRA_MODE2(ea) == 0x3)) {
		*bus_out = 0;
		return 2;	/* filtered out (continue) */
	}

	bus    = CISS_EXTRA_BUS2(ea) - 1;	/* ciss.c:1551 */
	target = CISS_EXTRA_TARGET2(ea);		/* ciss.c:1552 */
	*bus_out = bus;

	/* KERNEL HAS NO bus>=0 / bus<max check here:
	 *     sc->ciss_physical[bus][target].cp_address = ...;
	 *     sc->ciss_physical[bus][target].cp_online = 1; */
	printf("BUS2=%2u target=%2u -> index bus=%d (valid 0..%d) target=%d\n",
	       CISS_EXTRA_BUS2(ea), CISS_EXTRA_TARGET2(ea),
	       bus, sc->ciss_max_physical_bus - 1, target);
	if (bus < 0 || bus >= sc->ciss_max_physical_bus)
		return 1;	/* would be OOB */
	return 0;		/* in-bounds */
}

int main(void)
{
	struct sc_replica sc;
	int max_physical_bus = 4;
	sc.ciss_max_physical_bus = max_physical_bus;
	sc.ciss_physical = calloc(max_physical_bus, sizeof(struct ciss_pdrive *));

	printf("== DF-1192 ciss_filter_physical negative-bus harness ==\n");
	printf("ciss_max_physical_bus=%d\n\n", max_physical_bus);

	/* Malicious extra_address: BUS2==0 (the unfiltered case), valid MODE2!=3,
	 * BUS3==0, TARGET3==0, target=5. */
	uint32_t ea_mal = (uint32_t)0 << 24 | 5u << 16;	/* BUS2=0,target=5 */
	int bus_mal; printf("[malicious] ");
	int res_mal = filter_and_index(&sc, ea_mal, &bus_mal);

	/* A benign in-range one for contrast */
	uint32_t ea_ok = (uint32_t)2 << 24 | 5u << 16;		/* BUS2=2 -> bus=1 */
	int bus_ok; printf("[benign   ] ");
	int res_ok = filter_and_index(&sc, ea_ok, &bus_ok);

	printf("\n");
	if (res_mal == 1) {
		printf("[BUG REPRODUCED] malicious LUN PASSES the filter and indexes "
		       "ciss_physical[%d][5]\n", bus_mal);
		printf("On a real kernel: ciss_physical[-1] reads a kernel pointer from before\n");
		printf("the array; the subsequent cp_address/cp_online writes corrupt whatever\n");
		printf("that pointer references (controlled OOB write).\n");
		free(sc.ciss_physical);
		return 0;
	} else if (res_mal == 2) {
		printf("[not-reproduced] malicious LUN was filtered out\n");
	} else {
		printf("[not-reproduced] malicious LUN indexed in-bounds (bus=%d)\n", bus_mal);
	}
	free(sc.ciss_physical);
	return 1;
}
