⬢ DragonFlyBSD Kernel Audit
DF-3465 / wireshim.c
← back to finding ↓ download raw
/*
 * DF-3465 PoC wiring shim.
 *
 * ip_fw3_log.c's ip_fw3_log_modevent(MOD_LOAD) attaches the "ipfw" cloner
 * and registers ip_fw3_log_clone_destroy as a handler for the GLOBAL
 * ifnet_detach_event.  In the stock tree ipfw3_basic's module handler
 * (ip_fw3_basic.c:657-658) never calls it, so the whole subsystem is
 * dormant (ip_fw3_log_ptr is likewise never assigned).  This shim performs
 * exactly the one-line wiring the module is missing, so the dormant code
 * becomes live the way upstream intends.  After that, destroying or
 * renaming ANY interface whose if_dunit collides with a live ipfwN clone
 * unit (0..9) triggers the type-confused destroy -> double if_detach +
 * double if_free of the wrong ifnet.
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/eventhandler.h>
#include <net/if_var.h>
#include <net/if_clone.h>

extern void ip_fw3_log_modevent(int type);

static void
wireshim_detach_event(void *ctx, struct ifnet *ifp)
{
	kprintf("wireshim: ifnet_detach_event: ifp=%s dname=%s dunit=%d "
	    "(ctx=%p)\n",
	    ifp->if_xname, ifp->if_dname ? ifp->if_dname : "(null)",
	    ifp->if_dunit, ctx);
}

static eventhandler_tag wireshim_cookie;

static int
wireshim_modevent(module_t mod, int type, void *data)
{
	switch (type) {
	case MOD_LOAD:
		/*
		 * Layout facts needed to predict what the (mis-registered)
		 * ipfw3 handler reads when EVENTHANDLER_INVOKE calls
		 * ip_fw3_log_clone_destroy(&ipfw3_log_cloner, ifp).
		 */
		kprintf("wireshim: offsetof(struct ifnet, if_dunit) = %zu\n",
		    offsetof(struct ifnet, if_dunit));
		kprintf("wireshim: sizeof(struct if_clone) = %zu "
		    "offsetof(ifc_name)=%zu ifc_minifs=%zu ifc_maxunit=%zu\n",
		    sizeof(struct if_clone),
		    offsetof(struct if_clone, ifc_name),
		    offsetof(struct if_clone, ifc_minifs),
		    offsetof(struct if_clone, ifc_maxunit));
		ip_fw3_log_modevent(MOD_LOAD);
		wireshim_cookie = EVENTHANDLER_REGISTER(ifnet_detach_event,
		    wireshim_detach_event, NULL, EVENTHANDLER_PRI_ANY);
		kprintf("wireshim: ipfw3 log subsystem wired "
		    "(cloner attached + ifnet_detach_event handler)\n");
		break;
	case MOD_UNLOAD:
		EVENTHANDLER_DEREGISTER(ifnet_detach_event, wireshim_cookie);
		ip_fw3_log_modevent(MOD_UNLOAD);
		break;
	default:
		break;
	}
	return 0;
}

static moduledata_t wireshim_mod = { "wireshim", wireshim_modevent, NULL };
DECLARE_MODULE(wireshim, wireshim_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
MODULE_DEPEND(wireshim, ipfw3_basic, 1, 1, 1);
MODULE_VERSION(wireshim, 1);