⬢ DragonFlyBSD Kernel Audit
DF-2966 / dfv_boom.c
← back to finding ↓ download raw
/*
 * dfv_boom.c — deterministic panic/wedge triggers.
 *   dfv.d2966=1 : publish a half-initialized domain into the global domains
 *                 list (replicates the exact state of the kldload window
 *                 between uipc_domain.c:138 SLIST_INSERT_HEAD and :140
 *                 net_init_domain). Then userland socket()+getpeername()
 *                 dispatches a NULL pru_peeraddr -> panic.
 *   dfv.m2907=1 : md_get_mbuf(mdp, 128) on a 64-byte chain. On INVARIANTS
 *                 kernels m_copym KASSERTs; otherwise (production claim)
 *                 the ignored md_get_mem return yields silent success with
 *                 a short mbuf.
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/module.h>
#include <sys/sysctl.h>
#include <sys/mbuf.h>
#include <sys/mchain.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/msgport.h>
#include <sys/msgport2.h>
#include <sys/thread2.h>
#include <sys/socket.h>
#include <net/netmsg.h>

/* ---------------- DF-2966 ---------------- */
static void dfv66_attach(netmsg_t msg);

static struct pr_usrreqs dfv66_usrreqs = {
	.pru_attach = dfv66_attach,
	/* every other hook NULL: exactly the pre-net_init_domain state */
};

static struct protosw dfv66_protosw[] = {
	{ .pr_type = SOCK_STREAM, .pr_protocol = 0,
	  .pr_domain = NULL,	/* set at fire time */
	  .pr_usrreqs = &dfv66_usrreqs },
};
static struct protosw dfv66_protosw_end[] = {
	{ .pr_type = 0, .pr_protocol = 0, .pr_domain = NULL, .pr_usrreqs = NULL },
};

#define AF_DFV 99
static struct domain dfv66_domain = {
	.dom_family = AF_DFV,
	.dom_name = "dfv66",
	.dom_protosw = dfv66_protosw,
	.dom_protoswNPROTOSW = dfv66_protosw_end,
};

static void
dfv66_attach(netmsg_t msg)
{
	lwkt_replymsg(&msg->lmsg, 0);
}

static int
dfv_d2966(SYSCTL_HANDLER_ARGS)
{
	int error, go = 0;

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

	dfv66_protosw[0].pr_domain = &dfv66_domain;
	crit_enter();
	SLIST_INSERT_HEAD(&domains, &dfv66_domain, dom_next);
	crit_exit();
	kprintf("DF2966: half-initialized domain AF=%d published (pru_attach "
		"valid, pru_peeraddr/pru_shutdown/... NULL). Socket() + "
		"getpeername()/shutdown() now dispatches NULL -> panic.\n",
		AF_DFV);
	return (0);
}

/* ---------------- DF-2907 (panic form) ---------------- */
static int
dfv_m2907(SYSCTL_HANDLER_ARGS)
{
	struct mbchain mb;
	struct mdchain md;
	struct mbuf *m = NULL;
	u_char data[64];
	int r, error, go = 0;

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

	memset(data, 0x42, sizeof(data));
	mb_init(&mb);
	mb_put_mem(&mb, data, sizeof(data), MB_MSYSTEM);
	md_initm(&md, mb_detach(&mb));
	kprintf("DF2907P: chain holds 64 bytes; calling md_get_mbuf(128) "
		"(oversize; md_get_mem return is ignored at :518)\n");
	r = md_get_mbuf(&md, 128, &m);
	/* INVARIANTS: KASSERT in m_copym panics before we get here.
	   non-INVARIANTS: r==0 with a SHORT m -> silent short copy. */
	kprintf("DF2907P: md_get_mbuf(128) returned %d m=%p m_len=%d "
		"(silent success with short mbuf)\n",
		r, m, m ? m->m_len : -1);
	if (m)
		m_freem(m);
	md_done(&md);
	return (0);
}

static SYSCTL_NODE(, OID_AUTO, dfvboom, CTLFLAG_RW, 0, "DF boom rig");
SYSCTL_PROC(_dfvboom, OID_AUTO, d2966, CTLTYPE_INT|CTLFLAG_RW, 0, 0,
    dfv_d2966, "I", "DF-2966 publish half-init domain");
SYSCTL_PROC(_dfvboom, OID_AUTO, m2907, CTLTYPE_INT|CTLFLAG_RW, 0, 0,
    dfv_m2907, "I", "DF-2985 oversize md_get_mbuf");

static int
dfv_boom_modevent(module_t mod, int type, void *data)
{
	switch (type) {
	case MOD_LOAD:
		kprintf("dfv_boom loaded\n");
		return (0);
	case MOD_UNLOAD:
		return (0);
	}
	return (EOPNOTSUPP);
}
static moduledata_t dfv_boom_mod = { "dfv_boom", dfv_boom_modevent, 0 };
DECLARE_MODULE(dfv_boom, dfv_boom_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);