⬢ DragonFlyBSD Kernel Audit
DF-3305 / fix.diff
← back to finding ↓ download raw
--- /home/maxx/dfbsd/dfbsd/sys/net/ip_mroute/ip_mroute.c	2026-07-18 00:45:16.868076229 +0000
+++ fixed_ip_mroute.c	2026-09-10 09:20:53.482370450 +0000
@@ -905,6 +905,13 @@
 	reg_vif_num = VIFI_INVALID;
 #endif
 
+    /*
+     * The tbf reprocess callout may be armed with this vif as its
+     * argument; stop it before the vif is cleared, or it will fire
+     * with a zeroed vif (v_tbf == NULL) and panic.
+     */
+    callout_stop(&tbf_reprocess_q_ch);
+
     bzero((caddr_t)vifp->v_tbf, sizeof(*(vifp->v_tbf)));
     bzero((caddr_t)vifp, sizeof (*vifp));
 
@@ -973,6 +980,7 @@
     struct rtdetq *rte;
     u_short nstl;
 
+    lwkt_gettoken(&mroute_token);
     rt = mfc_find(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr);
 
     /* If an entry already exists, just update the fields */
@@ -983,7 +991,6 @@
 		(u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr),
 		mfccp->mfcc_parent);
 
-	lwkt_gettoken(&mroute_token);
 	update_mfc_params(rt, mfccp);
 	lwkt_reltoken(&mroute_token);
 	return 0;
@@ -992,7 +999,6 @@
     /*
      * Find the entry for which the upcall was made and update
      */
-    lwkt_gettoken(&mroute_token);
     hash = MFCHASH(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr);
     for (rt = mfctable[hash], nstl = 0; rt; rt = rt->mfc_next) {
 
@@ -1108,15 +1114,16 @@
     *nptr = rt->mfc_next;
 
     /*
-     * free the bw_meter entries
+     * free the bw_meter entries (must be done while holding
+     * mroute_token: unschedule_bw_meter() mutates bw_meter_timers[])
      */
     list = rt->mfc_bw_meter;
     rt->mfc_bw_meter = NULL;
-    lwkt_reltoken(&mroute_token);
 
     kfree(rt, M_MRTABLE);
     free_bw_list(list);
 
+    lwkt_reltoken(&mroute_token);
     return 0;
 }
 
@@ -1424,6 +1431,7 @@
 		    struct bw_meter *x = mfc->mfc_bw_meter;
 
 		    mfc->mfc_bw_meter = x->bm_mfc_next;
+		    unschedule_bw_meter(x);
 		    kfree(x, M_BWMETER);
 		}
 
@@ -1875,7 +1883,7 @@
 {
     struct vif *vifp = xvifp;
 
-    if (ip_mrouter == NULL)
+    if (ip_mrouter == NULL || vifp == NULL || vifp->v_tbf == NULL)
 	return;
     tbf_update_tokens(vifp);
     tbf_process_q(vifp);
@@ -2364,8 +2372,10 @@
 
 	list = mfc->mfc_bw_meter;
 	mfc->mfc_bw_meter = NULL;
-	lwkt_reltoken(&mroute_token);
+	/* free_bw_list() calls unschedule_bw_meter() which walks
+	 * bw_meter_timers[]: must hold mroute_token. */
 	free_bw_list(list);
+	lwkt_reltoken(&mroute_token);
 	return 0;
     } else {			/* Delete a single bw_meter entry */
 	struct bw_meter *prev;
@@ -2823,7 +2833,7 @@
 	mm = m_pullup(mm, sizeof(struct ip));
 	if (mm != NULL) {
 	    ip = mtod(mm, struct ip *);
-	    if ((mrt_api_config & MRT_MFC_RP) &&
+	    if (rt != NULL && (mrt_api_config & MRT_MFC_RP) &&
 		(rt->mfc_rp.s_addr != INADDR_ANY)) {
 		pim_register_send_rp(ip, vifp, mm, rt);
 	    } else {