⬢ DragonFlyBSD Kernel Audit
DF-4529 / nvmedetach.c
← back to finding ↓ download raw
/*
 * nvmedetach.c -- DF-4528/DF-4529 PoC trigger (TEST ONLY, never for sys/).
 *
 * MOD_LOAD:   device_detach() nvme unit 0   -> runs nvme_pci_detach()
 * MOD_UNLOAD: device_attach() nvme unit 0   -> re-runs the full attach
 *              (identify controller / make queues / identify namespaces
 *              admin-command storm)
 *
 * This simulates, deterministically, what a PCI hot-unplug / surprise
 * removal (or hot-plug) does to the driver while user processes hold the
 * namespace devices open and are issuing NVMEIOCGETLOG ioctls.
 */
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/bus.h>

static devclass_t nvme_dc;

static int
nvmedetach_handler(module_t mod, int what, void *arg)
{
	device_t dev;
	int error;

	switch (what) {
	case MOD_LOAD:
		nvme_dc = devclass_find("nvme");
		if (nvme_dc == NULL) {
			kprintf("nvmedetach: devclass 'nvme' not found\n");
			return (ENOENT);
		}
		dev = devclass_get_device(nvme_dc, 0);
		if (dev == NULL) {
			kprintf("nvmedetach: nvme0 not present\n");
			return (ENOENT);
		}
		kprintf("nvmedetach: DETACH %s%d ...\n",
		    device_get_name(dev), device_get_unit(dev));
		error = device_detach(dev);
		kprintf("nvmedetach: DETACH done error=%d\n", error);
		return (0);
	case MOD_UNLOAD:
		if (nvme_dc == NULL) {
			kprintf("nvmedetach: no devclass on unload\n");
			return (0);
		}
		dev = devclass_get_device(nvme_dc, 0);
		if (dev == NULL) {
			kprintf("nvmedetach: no unit 0 on unload\n");
			return (0);
		}
		kprintf("nvmedetach: ATTACH %s%d ...\n",
		    device_get_name(dev), device_get_unit(dev));
		error = device_probe_and_attach(dev);
		kprintf("nvmedetach: ATTACH done error=%d\n", error);
		return (0);
	default:
		return (0);
	}
	/* NOTREACHED */
}

static moduledata_t nvmedetach_mod = {
	"nvmedetach",
	nvmedetach_handler,
	NULL
};

DECLARE_MODULE(nvmedetach, nvmedetach_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
MODULE_VERSION(nvmedetach, 1);