DF-0735 / df735_fixed.c
/* * df735_fixed.c - DF-0735 fix-validation harness. * * Same trigger pattern as df735_trigger.c, but instead of calling ip_input(m) * directly from the sysctl-handler thread (which trips ASSERT_NETISR_NCPUS), * it routes the mbuf through netisr_queue(NETISR_IP, m) -- exactly the fix * applied in fix.diff to sys/netgraph7/ng_ipfw.c:248. The mbuf is then * dispatched to a netisr thread and ip_input runs there, so the assertion * holds and no panic occurs. * * Trigger: sysctl debug.df735_fixed=1 (as root) * * If the fix concept is correct, this sysctl should NOT panic the kernel -- * a deliberate contrast with the buggy df735_trigger.ko, which panics * every time on default-GENERIC. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/mbuf.h> #include <sys/sysctl.h> #include <sys/malloc.h> #include <sys/types.h> #include <net/netisr.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_var.h> /* See note in df735_trigger.c. */ extern void ip_input(struct mbuf *); static int df735_fixed(SYSCTL_HANDLER_ARGS); SYSCTL_PROC(_debug, OID_AUTO, df735_fixed, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, df735_fixed, "I", "DF-0735 fix validation: write 1 to dispatch mbuf via netisr_queue"); static int df735_fixed(SYSCTL_HANDLER_ARGS) { int error, val = 0; error = sysctl_handle_int(oidp, &val, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (val) { struct mbuf *m; m = m_gethdr(M_WAITOK, MT_DATA); if (m == NULL) return (ENOMEM); m->m_pkthdr.len = m->m_len = 0; /* DF-0735 fix pattern (mirrors ng_ip_input.c:122-125): * hand the mbuf to NETISR_IP, do not call ip_input directly. */ m->m_flags &= ~M_HASH; netisr_queue(NETISR_IP, m); /* ip_input() will be called from the NETISR_IP thread, where * ASSERT_NETISR_NCPUS holds. The mbuf is malformed (zero * length) so it will be dropped inside ip_input -- but the * important property is that NO panic occurs. */ } return (0); } |