/*
 * DF-0622 — ng_car_disconnect NULL-deref panic PoC (DEMONSTRATION ONLY).
 *
 * *** THE ng_car MODULE CANNOT BE LOADED ON THIS KERNEL ***
 *
 * sys/netgraph7/ng_car.c references three FreeBSD-isms that DO NOT EXIST in
 * DragonFlyBSD:
 *
 *   line 62, 588:   struct bintime         (no such type in sys/)
 *   line 210, 592:  getbinuptime()         (no such function in sys/)
 *   line 596:       bintime_sub()          (no such function in sys/)
 *
 * grep -rln "struct bintime" sys/   =>   ONLY sys/netgraph7/ng_car.c
 *
 * The file is therefore NOT in any build Makefile (`sys/netgraph7/Makefile`
 * SUBDIR list) and no ng_car.ko ships in /boot/kernel/. Trying to build it
 * standalone fails immediately at compile time:
 *
 *    ng_car.c:596:2: error: implicit declaration of function 'bintime_sub'
 *    ng_car.c:588:17: error: unused variable 'newt' [-Werror=unused-variable]
 *
 * The bug pattern identified by the finding is REAL in the source:
 *
 *   * ng_car_shutdown (ng_car.c:539-540) correctly does:
 *        ng_uncallout(&priv->upper.q_callout, node);
 *        ng_uncallout(&priv->lower.q_callout, node);
 *
 *   * ng_car_disconnect (ng_car.c:553-580) does NOT — it only purges the
 *     mbuf queue (NG_FREE_M each entry NULLs the slot at :563) and clears
 *     hook refs (:569-573). A pending callout therefore survives and later
 *     fires ng_car_q_event, whose drain loop has no empty-queue guard:
 *
 *        676:  while (hinfo->tc >= 0) {
 *        679:      m = hinfo->q[hinfo->q_first];            // NULL (purged)
 *        695:      m = hinfo->q[hinfo->q_first];            // another NULL
 *        699:      hinfo->tc -= m->m_pkthdr.len;            // NULL DEREF -> panic
 *
 * But the runtime trigger path is **unreachable on this kernel** because
 * the module cannot be loaded. Classification: real bug in DEAD CODE.
 *
 * This file documents what the PoC WOULD do if ng_car.c were ported. It is
 * kept here to demonstrate the trigger logic and as a ready-to-run PoC for
 * whenever the module is fixed upstream.
 */

/*
 * The PoC would use the standard ng_socket control socket API:
 *
 *   1. open AF_NETGRAPH / control socket
 *   2. ngctl mkpeer car upper socket lower
 *      -> creates a `car` node with two ng_socket peers
 *   3. NGM_CAR_SET_CONF on the upper hook:
 *        mode = NG_CAR_SHAPE
 *        cir  = 10240         (small committed rate so packets queue)
 *        cbs  = 8192
 *        ebs  = 8192
 *   4. Send a burst of >100 packets on the upper data hook
 *      -> fills the SHAPE queue, schedules ng_car_q_event callout
 *   5. While the callout is pending, ngctl rmhook on the upper hook
 *      -> ng_car_disconnect purges queue, does NOT uncallout
 *   6. Within a few ticks the callout fires ng_car_q_event, reads NULL mbuf,
 *      NULL-derefs at m->m_pkthdr.len -> Fatal trap 12: page fault in
 *      kernel mode.
 *
 * Requires root (NGF_NETGRAPH control socket is privileged).
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

/*
 * A full C implementation against the netgraph control socket is large and
 * error-prone; for an admin-reproducible trigger, the equivalent ngctl(8)
 * script is provided in ng_car_trigger.sh.
 */
int
main(void)
{
	fprintf(stderr,
	    "DF-0622: ng_car.ko CANNOT be loaded on this kernel\n"
	    "(struct bintime / getbinuptime / bintime_sub are unported\n"
	    " FreeBSD-isms; the module is not built, not in the SUBDIR\n"
	    " Makefile, and not in /boot/kernel/). The bug pattern is\n"
	    " confirmed in the source (see VERDICT.md). The runtime trigger\n"
	    " requires a ported ng_car.ko.\n"
	    "\n"
	    "See ng_car_trigger.sh for the ngctl sequence that would fire\n"
	    "the panic on a kernel with a working ng_car module.\n");
	return 0;
}
