DragonFlyBSD Kernel Audit
DF-0597 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/netgraph7/pptpgre/ng_pptpgre.c b/sys/netgraph7/pptpgre/ng_pptpgre.c
--- a/sys/netgraph7/pptpgre/ng_pptpgre.c
+++ b/sys/netgraph7/pptpgre/ng_pptpgre.c
@@ -185,6 +185,8 @@
 static int	ng_pptpgre_xmit(hpriv_p hpriv, item_p item);
 static void	ng_pptpgre_start_send_ack_timer(hpriv_p hpriv);
 static void	ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv);
+static void	ng_pptpgre_free_session(node_p node, hook_p hook,
+		    void *arg1, int arg2);
 static void	ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook,
 		    void *arg1, int arg2);
 static void	ng_pptpgre_send_ack_timeout(node_p node, hook_p hook,
@@ -494,8 +496,19 @@
 		ng_pptpgre_reset(hpriv);
 
 		LIST_REMOVE(hpriv, sessions);
-		mtx_uninit(&hpriv->mtx);
-		kfree(hpriv, M_NETGRAPH);
+		/*
+		 * Defer the free of hpriv (and its mutex uninit) to a
+		 * WRITER function item enqueued AFTER ng_pptpgre_reset().
+		 * ng_uncallout() does NOT dequeue an already-dispatched
+		 * callout trampoline (callout_stop() returns 0 in that
+		 * case), so the corresponding ng_pptpgre_*_ack_timeout
+		 * item may already be queued on cpu0's msgport and could
+		 * run after we return. Running it against freed hpriv is
+		 * a use-after-free; queueing the free behind it via
+		 * ng_send_fn (FIFO on the same msgport) guarantees the
+		 * in-flight timer callback observes a live hpriv.
+		 */
+		ng_send_fn(node, NULL, ng_pptpgre_free_session, hpriv, 0);
 	}
 
 	/* Go away if no longer connected to anything */
@@ -970,6 +983,20 @@
 }
 
 /*
+ * Deferred session free — runs as a WRITER after any already-dispatched
+ * timer callback items have drained from the msgport. Pair with the
+ * ng_send_fn() call in ng_pptpgre_disconnect().
+ */
+static void
+ng_pptpgre_free_session(node_p node, hook_p hook, void *arg1, int arg2)
+{
+	hpriv_p hpriv = arg1;
+
+	mtx_uninit(&hpriv->mtx);
+	kfree(hpriv, M_NETGRAPH);
+}
+
+/*
  * Return the current time scaled & translated to our internally used format.
  */
 static pptptime_t