DF-3528 fix = the already-validated DF-3523 layer-2 fix (ng_uncallout must actually free the callout item) PLUS freeing the orphaned previous item on rearm. Apply together with the kern_timeout contract fix (DF-3521/DF-3515, kern_timeout.diff in findings/poc/DF-3523/) — each layer alone was measured insufficient in-guest by DF-3523. For ng_car.c itself the actionable change is a port to DragonFly primitives (bintime -> systimer/tvtohz or binuptime shim, mtx -> spinlock/lockmgr) or deletion of the dead file; the leak is in ng_base.c, not in ng_car.c. --- a/sys/netgraph7/netgraph/ng_base.c +++ b/sys/netgraph7/netgraph/ng_base.c @@ -3263,6 +3263,12 @@ ng_callout(struct callout *c, node_p node, hook_p hook, int ticks, NGI_FN(item) = fn; NGI_ARG1(item) = arg1; NGI_ARG2(item) = arg2; + /* + * If the callout was still armed with another item, that item (and + * its node/hook references) would be orphaned by the reset below. + * DF-3528/DF-3523: free it now. ng_free_item() releases the + * NG_NODE_REF/NG_HOOK_REF taken at arm time. + */ oitem = callout_arg(c); callout_reset(c, ticks, &ng_callout_trampoline, item); + if (oitem != NULL && oitem != item && callout_func(c) == &ng_callout_trampoline) + ng_free_item(oitem); return (0); } @@ -3288,7 +3294,8 @@ ng_uncallout(struct callout *c, node_p node) * We successfully removed it from the queue before it ran * So now we need to unreference everything that was * given extra references. (NG_FREE_ITEM does this). */ NG_FREE_ITEM(item); + ng_free_item(item); /* NG_FREE_ITEM is flag-only in ng7 */ } callout_set_arg(c, NULL); return (rval);