⬢ DragonFlyBSD Kernel Audit
DF-4986 / df4986_primitive.c
← back to finding ↓ download raw
/*
 * DF-4986 PoC — primitive reproduction of the sink:
 *
 *   mfi_pci.c:281 / mfi_pci.c:294-299  ->  mfi_free(sc)
 *   mfi.c:1074                         ->  callout_terminate(&sc->mfi_watchdog_callout)
 *
 * mfi_watchdog_callout is only initialized by callout_init_mp() at
 * mfi.c:741, i.e. at the very END of mfi_attach().  Any attach failure
 * before that line (firmware not READY -> mfi.c:413-417 ENXIO, verbuf/tb/
 * comms/frames/sense DMA failures, bus_setup_intr failure at mfi.c:672/683,
 * config_intrhook failure, aen setup failure, or the parent-DMA-tag failure
 * at mfi_pci.c:271-282 which reaches mfi_free() before mfi_attach() ran at
 * all) unwinds through mfi_free(), which terminates a callout that was only
 * ever bzero'd by mfi_pci.c:230.
 *
 * callout_terminate() (sys/kern/kern_timeout.c:1104) does:
 *      KKASSERT(cc->flags & CALLOUT_DID_INIT);
 * A bzero'd callout has flags == 0, so on any kernel built with INVARIANTS
 * (stock X86_64_GENERIC, sys/config/X86_64_GENERIC:56) this panics.
 *
 * This module reproduces exactly that call on the running kernel without
 * needing LSI MegaRAID hardware: bzero a callout, terminate it.
 *
 * Expected: immediate kernel panic
 *   assertion "cc->flags & CALLOUT_DID_INIT" failed in callout_terminate
 * (on a kernel built without INVARIANTS the module simply loads and the
 * terminate is a no-op — that is also a valid, documented outcome.)
 */

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/callout.h>

static struct callout co;	/* == sc->mfi_watchdog_callout after bzero(sc) */

static int
df4986_modevent(module_t mod, int type, void *arg)
{
	switch (type) {
	case MOD_LOAD:
		bzero(&co, sizeof(co));	/* mfi_pci.c:230 bzero(sc, sizeof(*sc)) */
		kprintf("DF4986: terminating never-initialized callout "
		    "(mfi_free @ mfi.c:1074 path)\n");
		callout_terminate(&co);	/* <-- KKASSERT fires here */
		kprintf("DF4986: survived: kernel built without INVARIANTS\n");
		return (0);
	case MOD_UNLOAD:
		return (0);
	default:
		return (EOPNOTSUPP);
	}
}

static moduledata_t df4986_mod = {
	"df4986",
	df4986_modevent,
	NULL
};

DECLARE_MODULE(df4986, df4986_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);