⬢ DragonFlyBSD Kernel Audit
DF-3449 / fix.diff
← back to finding ↓ download raw
--- a/sys/net/dummynet3/ip_dummynet3.c
+++ b/sys/net/dummynet3/ip_dummynet3.c
@@ -2009,29 +2009,51 @@
 static void
 ip_dn_stop_dispatch(netmsg_t msg)
 {
+	int error;
+
 	crit_enter();
 
+	/*
+	 * DF-3449: ip_fw3_unregister_module() returns 1 while any ipfw3
+	 * rule still references the dummynet module (pipe/queue actions).
+	 * It must run before the module text goes away: it clears
+	 * filter_funcs[MODULE_DUMMYNET_ID][] -- which check_body() calls
+	 * through without a NULL check -- and drops the module
+	 * registration so no new pipe/queue rules can be compiled after
+	 * the unload.  Every sibling module (ipfw3_basic/nat/layer2/
+	 * layer4) already does this; dummynet3 was the only one that
+	 * did not.
+	 */
+	error = ip_fw3_unregister_module(MODULE_DUMMYNET_ID);
+	if (error) {
+		error = EBUSY;
+		goto back;
+	}
+
 	dummynet_flush();
 
 	ip_dn_ctl_ptr = NULL;
 	ip_dn_io_ptr = NULL;
 
 	systimer_del(&dn_clock);
-
+back:
 	crit_exit();
-	lwkt_replymsg(&msg->lmsg, 0);
+	lwkt_replymsg(&msg->lmsg, error);
 }
 
-static void
+static int
 ip_dn_stop(void)
 {
 	struct netmsg_base smsg;
+	int error;
 
 	netmsg_init(&smsg, NULL, &curthread->td_msgport,
 			0, ip_dn_stop_dispatch);
 	lwkt_domsg(netisr_cpuport(ip_dn_cpu), &smsg.lmsg, 0);
+	error = smsg.lmsg.ms_error;
 
 	netmsg_service_sync();
+	return error;
 }
 
 #endif	/* KLD_MODULE */
@@ -2048,7 +2070,11 @@
 			kprintf("dummynet statically compiled, cannot unload\n");
 			return EINVAL;
 #else
-			ip_dn_stop();
+			{
+				int error = ip_dn_stop();
+				if (error)
+					return error;
+			}
 #endif
 			break;