diff --git a/sys/netgraph7/ng_car.c b/sys/netgraph7/ng_car.c --- a/sys/netgraph7/ng_car.c +++ b/sys/netgraph7/ng_car.c @@ -558,6 +558,16 @@ const priv_p priv = NG_NODE_PRIVATE(node); if (hinfo) { + /* + * Cancel any pending queue-processing callout before + * tearing down the queue state it depends on. Otherwise + * a pending callout (which holds its own ref on node+hook) + * survives the disconnect and fires ng_car_q_event on a + * purged queue, NULL-dereferencing the mbuf slots. + * Mirrors the cleanup already done in ng_car_shutdown(). + */ + ng_uncallout(&hinfo->q_callout, node); + /* Purge queue if not empty. */ while (hinfo->q_first != hinfo->q_last) { NG_FREE_M(hinfo->q[hinfo->q_first]); @@ -672,6 +682,14 @@ /* Refill tokens for time we have slept. */ ng_car_refillhook(hinfo); + /* + * The queue may have been drained/purged out-of-band (e.g. hook + * disconnect) since this callout was scheduled; bail before touching + * mbufs to avoid a NULL deref on the purged slots. + */ + if (hinfo->q_first == hinfo->q_last) + return; + /* If we have some tokens */ while (hinfo->tc >= 0) {