DragonFlyBSD Kernel Audit
DF-0604 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/net/pf/pf_if.c b/sys/net/pf/pf_if.c
--- a/sys/net/pf/pf_if.c
+++ b/sys/net/pf/pf_if.c
@@ -84,6 +84,14 @@
 
 static void	 pfi_kif_update(struct pfi_kif *);
 static void	 pfi_dynaddr_update(struct pfi_dynaddr *);
+struct netmsg_pfitable {
+	struct netmsg_base	 base;
+	struct pfr_ktable	*kt;
+	struct pfi_kif		*kif;
+	int			 net;
+	int			 flags;
+};
+
 static void	 pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
 		    int, int);
 static void	 pfi_instance_add(struct ifnet *, int, int);
@@ -503,7 +511,7 @@
 }
 
 static void
-pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
+_pfi_table_update_body(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
 {
 	int			 e, size2 = 0;
 	struct ifg_member	*ifgm;
@@ -527,6 +535,39 @@
 	}
 }
 
+static void
+pfi_table_update_dispatch(netmsg_t nmsg)
+{
+	struct netmsg_pfitable *msg = (struct netmsg_pfitable *)nmsg;
+
+	_pfi_table_update_body(msg->kt, msg->kif, msg->net, msg->flags);
+	netisr_replymsg(&nmsg->base, 0);
+}
+
+/*
+ * DF-0604 fix: dispatch the entire buffer-update critical section to netisr0.
+ * All callers (ifaddr_event already on netisr0, pfioctl on caller CPU, etc.)
+ * now serialize on netisr0's single thread, eliminating the cross-CPU race
+ * on the global pfi_buffer/pfi_buffer_cnt/pfi_buffer_max.
+ */
+static void
+pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
+{
+	if (mycpuid == 0) {
+		_pfi_table_update_body(kt, kif, net, flags);
+	} else {
+		struct netmsg_pfitable msg;
+
+		netmsg_init(&msg.base, NULL, &curthread->td_msgport, 0,
+		    pfi_table_update_dispatch);
+		msg.kt = kt;
+		msg.kif = kif;
+		msg.net = net;
+		msg.flags = flags;
+		netisr_domsg(&msg.base, 0);
+	}
+}
+
 
 struct netmsg_pfiadd {
 	struct netmsg_base	base;