⬢ DragonFlyBSD Kernel Audit
DF-3501 / dumpif.c
← back to finding ↓ download raw
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_arp.h>
#include <net/if_types.h>
#include <stdint.h>

/*
 * debug.dumpif: dump sizeof(struct ifnet), arpcom offsets, and the 32
 * bytes immediately past the end of a given interface's ifnet allocation
 * (default lo0).  Used to demonstrate the ng_fec_addport arpcom
 * type-confusion OOB read/write.
 */
static int
dumpif_sysctl(SYSCTL_HANDLER_ARGS)
{
	char ifname[IFNAMSIZ];
	struct ifnet *ifp;
	caddr_t end;
	int i, error;
	uint64_t v;

	strlcpy(ifname, "lo0", sizeof(ifname));
	error = sysctl_handle_string(oidp, ifname, sizeof(ifname), req);
	if (error != 0 || req->newptr == NULL)
		return (error);

	ifnet_lock();
	ifp = ifunit(ifname);
	if (ifp == NULL) {
		ifnet_unlock();
		kprintf("DUMPIF: %s: no such interface\n", ifname);
		return (ENOENT);
	}
	kprintf("DUMPIF: %s ifp=%p sizeof(struct ifnet)=%zu "
	    "sizeof(struct arpcom)=%zu off(ac_enaddr)=%zu off(ac_netgraph)=%zu\n",
	    ifname, ifp, sizeof(struct ifnet), sizeof(struct arpcom),
	    offsetof(struct arpcom, ac_enaddr),
	    offsetof(struct arpcom, ac_netgraph));
	end = (caddr_t)ifp + sizeof(struct ifnet);
	for (i = 0; i < 32; i += 8) {
		v = *(volatile uint64_t *)(end + i);
		kprintf("DUMPIF: %s tail+%3d (ifnet_end%+d): %016jx\n",
		    ifname, i, i, (uintmax_t)v);
	}
	ifnet_unlock();
	return (0);
}
SYSCTL_PROC(_debug, OID_AUTO, dumpif, CTLTYPE_STRING | CTLFLAG_RW,
    0, 0, dumpif_sysctl, "A", "dump bytes past ifnet end");

static int
dumpif_load(struct module *m, int what, void *arg)
{
	switch (what) {
	case MOD_LOAD:
		kprintf("dumpif: loaded; use 'sysctl -n debug.dumpif=<ifname>'\n");
		return (0);
	default:
		return (0);
	}
}

static moduledata_t dumpif_mod = { "dumpif", dumpif_load, NULL };
DECLARE_MODULE(dumpif, dumpif_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);