DF-0759 / run.sh
#!/bin/sh # DF-0759 run.sh — reproduce the double NG_FREE_ITEM KKASSERT panic in ng_split. # # CONTEXT (read before judging the result): # * ng_split lives ONLY in sys/netgraph7/ (the opt-in parallel netgraph # stack). It is NOT in the default X86_64_GENERIC kernel and is NOT in the # default module build (Makefile.modules picks sys/netgraph unless # WANT_NETGRAPH7 is set; ng_split also has no upstream module Makefile). # * Reaching the out-hook data path needs a netgraph topology, which needs # the privileged netgraph control socket -> ROOT ONLY. # * The default X86_64_GENERIC kernel ships `options INVARIANTS`. When # ng_split is compiled with INVARIANTS (either compiled into such a kernel # via `options NETGRAPH7_SPLIT`, OR as a kld module built with # KCFLAGS=-DINVARIANTS), the KKASSERT inside NG_FREE_ITEM (netgraph.h:818) # is active and the double NG_FREE_ITEM PANICS. Without INVARIANTS the # second NG_FREE_ITEM is a harmless idempotent flag-set (KKASSERT no-op). # * NOTE on kld modules: bsd.kmod.mk does NOT inherit the kernel's INVARIANTS # define, so a stock kld build has KKASSERT compiled out. This script # therefore builds ng_split with KCFLAGS=-DINVARIANTS to reproduce the # INVARIANTS-kernel behaviour the finding describes. # # This script runs as ROOT and: # 1. builds netgraph7 core + ng_socket7 (stock, no INVARIANTS) and ng_split # (WITH INVARIANTS so its NG_FREE_ITEM assertion is live), # 2. loads the netgraph7 stack + ng_split, # 3. drives a single data byte onto a split node's "out" hook via the # `inject` userland helper (linked against libnetgraph7, NG_VERSION=8). # # Expected (bug present, INVARIANTS active): # assertion "!(item->el_flags & NGQF_FREE)" failed in ng_split_rcvdata # at netgraph7/netgraph.h:818 -> kernel panic, ssh dies. # Expected (bug present, INVARIANTS OFF, or AFTER the fix): # "NO_PANIC" printed, guest stays up. set -e cd "$(dirname "$0")" echo "=== [1/4] netgraph7 core module ===" make -C /usr/src/sys/netgraph7/netgraph obj 2>&1 | tail -1 make -C /usr/src/sys/netgraph7/netgraph 2>&1 | tail -2 cp /usr/obj/usr/src/sys/netgraph7/netgraph/netgraph.ko /root/netgraph7.ko echo "=== [2/4] ng_socket7 module ===" make -C /usr/src/sys/netgraph7/socket obj 2>&1 | tail -1 make -C /usr/src/sys/netgraph7/socket 2>&1 | tail -2 cp /usr/obj/usr/src/sys/netgraph7/socket/ng_socket.ko /root/ng_socket7.ko echo "=== [3/4] ng_split module (INVARIANTS active -> KKASSERT live) ===" mkdir -p /usr/src/sys/netgraph7/split cp /usr/src/sys/netgraph7/ng_split.c /usr/src/sys/netgraph7/split/ cd /usr/src/sys/netgraph7/split ln -sf ../ng_message.h . ln -sf ../netgraph.h . ln -sf ../dragonfly.h . ln -sf ../ng_split.h . touch opt_netgraph.h cat > Makefile <<'MK' KMOD= ng_split SRCS= ng_split.c KCFLAGS= -DINVARIANTS .include <bsd.kmod.mk> MK make obj 2>&1 | tail -1 make 2>&1 | tail -2 cp /usr/obj/usr/src/sys/netgraph7/split/ng_split.ko /root/ # sanity: the assertion string must be present (KKASSERT compiled in) strings /root/ng_split.ko | grep -q "NGQF_FREE" && \ echo "[+] ng_split.ko has INVARIANTS assertion compiled in" || \ { echo "[-] ng_split.ko MISSING assertion -- INVARIANTS not active"; exit 1; } cd - echo "=== install libnetgraph7 (NG_VERSION=8) if not present ===" if [ ! -e /usr/lib/libnetgraph.so.3 ]; then ( cd /usr/src/lib/libnetgraph7 && make obj && make && make install ) 2>&1 | tail -3 fi echo "=== [4/4] load netgraph7 stack + ng_split ===" kldload /root/netgraph7.ko kldload /root/ng_socket7.ko kldload /root/ng_split.ko kldstat | grep -iE "netgraph|ng_" echo "=== compile injector (libnetgraph7 / NG_VERSION=8) ===" cc -O2 -Wall -o inject inject.c -lnetgraph ls -l inject echo "=== FIRING TRIGGER: data byte -> split:out -> ng_split_rcvdata(out) ===" echo " (double NG_FREE_ITEM; KKASSERT(!(NGQF_FREE)) should fire -> panic)" ./inject echo "INJECT_EXIT=$?" |