⬢ DragonFlyBSD Kernel Audit
DF-3521 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -885,10 +885,28 @@
 	 * If the operation is still in-progress then re-acquire the spin-lock
 	 * and block if necessary.  Also initiate the lock cancel.
 	 */
-	if (sync == 0 || (c->flags & (CALLOUT_INPROG | CALLOUT_SET)) == 0) {
+	/*
+	 * If the operation completed inline above (the armed callout was
+	 * removed from the wheel and will never execute), report whether
+	 * execution was PREVENTED.  Returning 0 for a successfully
+	 * cancelled pending callout violates the callout_stop(9) contract
+	 * ("non-zero if the callout was pending and had not yet run") and
+	 * makes every conditional cleanup (`if (callout_stop(&c)) ...`)
+	 * leak the resources it pairs with the callback -- e.g. netgraph
+	 * ng_pptpgre's rack/sack timer accounting (node refs,
+	 * priv->timers, the timer argument), which permanently pins
+	 * netgraph nodes and node-private data.
+	 */
+	if (sync == 0) {
 		exis_drop_gd(gd);
 		return 0;
 	}
+	if ((c->flags & (CALLOUT_INPROG | CALLOUT_SET)) == 0) {
+		/* inline-completed stop/cancel: report PREVENTED, not 0 */
+		res = ((c->flags & CALLOUT_PREVENTED) != 0);
+		exis_drop_gd(gd);
+		return (res);
+	}
 	if (c->flags & CALLOUT_AUTOLOCK)
 		lockmgr(c->lk, LK_CANCEL_BEG);
 	spin_lock(&c->spin);