⬢ DragonFlyBSD Kernel Audit
DF-4783 / mmcbang.c
← back to finding ↓ download raw
/*
 * mmcbang.c -- DF-4783 PoC trigger (TEST ONLY, never for sys/).
 *
 * Invokes the sdhci_pci driver's OWN attach/detach driver-methods on unit 0
 * so the device_t remains in the devclass and the cycle is repeatable:
 *
 *   sysctl hw.mmcbang.action=1  -> sdhci_pci_detach()  (card removal /
 *                                                     hot-unplug teardown)
 *   sysctl hw.mmcbang.action=2  -> sdhci_pci_attach()  (re-insert / rescan)
 *
 * detach cascades: sdhci_cleanup_slot -> device_delete_child(mmcX) ->
 * mmc_detach -> mmc_delete_cards -> device_delete_child(mmcsdX) ->
 * mmcsd_detach + newbus frees the mmcsd softc — while raw-pread spammers
 * are inside mmcsd_strategy() on /dev/mmcsd0 (no exclusion: DF-4646 family).
 */
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/sysctl.h>
#include <sys/kobj.h>

static int mmcbang_action(SYSCTL_HANDLER_ARGS);

static int mmcbang_act = 0;
SYSCTL_NODE(_hw, OID_AUTO, mmcbang, CTLFLAG_RW, 0, "mmcsd bang test");
SYSCTL_PROC(_hw_mmcbang, OID_AUTO, action, CTLTYPE_INT | CTLFLAG_RW,
    &mmcbang_act, 0, mmcbang_action, "I", "1=detach 2=attach");

static int
mmcbang_action(SYSCTL_HANDLER_ARGS)
{
	devclass_t dc;
	driver_t *drv;
	kobj_method_t *m;
	device_t dev;
	int error;
	int (*attach_fn)(device_t) = NULL;
	int (*detach_fn)(device_t) = NULL;

	error = sysctl_handle_int(oidp, &mmcbang_act, 0, req);
	if (error || req->newptr == NULL)
		return (error);
	if (mmcbang_act == 0)
		return (0);

	dc = devclass_find("sdhci_pci");
	if (dc == NULL) {
		kprintf("mmcbang: devclass 'sdhci_pci' not found\n");
		return (ENOENT);
	}
	dev = devclass_get_device(dc, 0);
	if (dev == NULL) {
		kprintf("mmcbang: sdhci_pci0 not present\n");
		return (ENOENT);
	}
	drv = device_get_driver(dev);
	if (drv == NULL || drv->methods == NULL) {
		kprintf("mmcbang: no driver\n");
		return (ENOENT);
	}
	for (m = drv->methods; m && m->func; ++m) {
		if (m->desc == NULL)
			continue;
		if (m->desc == &device_attach_desc)
			attach_fn = (int (*)(device_t))m->func;
		else if (m->desc == &device_detach_desc)
			detach_fn = (int (*)(device_t))m->func;
	}
	if (mmcbang_act == 1 && detach_fn) {
		kprintf("mmcbang: DETACH on %s...\n",
		    device_get_nameunit(dev));
		error = detach_fn(dev);
		kprintf("mmcbang: detach returned %d\n", error);
	} else if (mmcbang_act == 2 && attach_fn) {
		kprintf("mmcbang: ATTACH on %s...\n",
		    device_get_nameunit(dev));
		error = attach_fn(dev);
		kprintf("mmcbang: attach returned %d\n", error);
	} else {
		kprintf("mmcbang: no method\n");
		error = ENODEV;
	}
	return (error);
}

DEV_MODULE(mmcbang, NULL, NULL);