/*
 * DF-1075 harness — kernel module that replicates the exact allocation+write
 * pattern of the kue(4) driver bug described in if_kue.c.
 *
 * The real bug is: kue_attach() does
 *     sc->sc_mcfilters = kmalloc(KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN, ...)
 * BEFORE the device descriptor is read (so KUE_MCFILTCNT==0 → kmalloc(0)).
 * DragonFly's slab returns ZERO_LENGTH_PTR=(void*)-8 for kmalloc(0)
 * (kern_slaballoc.c:888-891), the NULL check passes, and later
 * kue_setmulti() does memcpy(&sc->sc_mcfilters[i*6], ..., 6) which writes
 * to the unmapped sentinel address → page fault → panic.
 *
 * This guest has no USB hardware, so the actual kue(4) driver cannot attach.
 * This module reproduces the SAME primitive (kmalloc(0) + memcpy) to prove
 * the mechanism panics on this exact kernel build. It is loaded as root
 * purely for primitive characterization (not an unprivileged escalation —
 * the real trigger requires plugging in a USB device).
 *
 * Build:   see Makefile
 * Load:    kldload ./df1075_harness.ko
 * Effect:  immediate kernel panic (Fatal trap 12, page fault at 0xFFFFFFFFFFFFFFF8)
 */

#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/errno.h>
#include <sys/types.h>

/* Matches kue(4): ETHER_ADDR_LEN from net/ethernet.h */
#define HARNESS_ETHER_ADDR_LEN 6

/* Matches the kue(4) allocation exactly: kmalloc(0 * 6) */
#define HARNESS_NFILTERS_AT_ATTACH 0   /* sc_desc is zero-init at kue_attach time */

MALLOC_DECLARE(M_HARNESS);
MALLOC_DEFINE(M_HARNESS, "df1075_harness", "DF-1075 harness");

static int
df1075_modevent(module_t mod, int type, void *arg)
{
	char *mcfilters;
	char fake_mac[HARNESS_ETHER_ADDR_LEN] = {0x33, 0x33, 0x00, 0x00, 0x00, 0x01};

	switch (type) {
	case MOD_LOAD:
		/*
		 * STEP 1 — replicate kue_attach() if_kue.c:488-493:
		 *   sc->sc_mcfilters = kmalloc(KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN,
		 *       M_USBDEV, M_WAITOK);
		 *   if (sc->sc_mcfilters == NULL) goto detach;
		 * KUE_MCFILTCNT(sc) reads sc_desc.kue_mcastfilt which is zero
		 * at kue_attach() time, so size=0.
		 */
		mcfilters = kmalloc(HARNESS_NFILTERS_AT_ATTACH * HARNESS_ETHER_ADDR_LEN,
		    M_HARNESS, M_WAITOK);

		kprintf("DF-1075: kmalloc(0) returned %p (ZERO_LENGTH_PTR expected %p)\n",
		    mcfilters, (void *)-8);
		kprintf("DF-1075: NULL check would %s (bug: sentinel is non-NULL)\n",
		    (mcfilters == NULL) ? "FAIL (correctly caught)" : "PASS (BUG: missed)");

		if (mcfilters == NULL) {
			/* does not happen on DragonFly */
			return (ENOMEM);
		}

		/*
		 * STEP 2 — replicate kue_setmulti() if_kue.c:383-385:
		 *   memcpy(KUE_MCFILT(sc, i),
		 *       LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
		 *       ETHER_ADDR_LEN);
		 * KUE_MCFILT(sc, 0) = &sc->sc_mcfilters[0] = ZERO_LENGTH_PTR+0
		 * Writing 6 bytes to (void*)-8 → page fault → panic.
		 */
		kprintf("DF-1075: about to memcpy 6 bytes into &mcfilters[0] = %p\n",
		    &mcfilters[0]);
		kprintf("DF-1075: THIS SHOULD PANIC WITH: Fatal trap 12: page fault\n");

		memcpy(&mcfilters[0], fake_mac, HARNESS_ETHER_ADDR_LEN);

		/* NOTREACHED — panic above */
		kprintf("DF-1075: SURVIVED (unexpected — slab behavior may differ)\n");
		return (0);

	case MOD_UNLOAD:
		return (0);
	default:
		return (EOPNOTSUPP);
	}
}

static moduledata_t df1075_mod = {
	"df1075_harness",
	df1075_modevent,
	NULL
};

DECLARE_MODULE(df1075_harness, df1075_mod, SI_SUB_EXEC, SI_ORDER_ANY);
MODULE_VERSION(df1075_harness, 1);
