⬢ DragonFlyBSD Kernel Audit
DF-3337 / fix.diff
← back to finding ↓ download raw
--- a/sys/net/pf/pf_table.c
+++ b/sys/net/pf/pf_table.c
@@ -42,6 +42,7 @@
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/thread2.h>
+#include <sys/spinlock2.h>
 
 #include <net/if.h>
 #include <net/route.h>
@@ -137,6 +138,12 @@
 struct malloc_type	*pfr_kentry_pl;
 struct malloc_type	*pfr_kentry_pl2;
 static struct pf_addr	 pfr_ffaddr;		/* constant after setup */
+/*
+ * Serializes packet-path (pf_token SHARED) mutators of radix trees and
+ * per-entry counters.  Ioctl paths hold pf_token EXCLUSIVE and are
+ * already serialized against the packet path.
+ */
+static struct spinlock	 pfr_pktmut_lock = SPINLOCK_INITIALIZER(pfr_pktmut_lock, "pf_table pkt mut");
 
 void			 pfr_copyout_addr(struct pfr_addr *,
 			    struct pfr_kentry *ke);
@@ -863,19 +870,27 @@
 	struct pfr_kentry	*p;
 	int			 rv;
 
+	spin_lock(&pfr_pktmut_lock);
 	p = pfr_lookup_addr(kt, ad, 1);
-	if (p != NULL)
+	if (p != NULL) {
+		spin_unlock(&pfr_pktmut_lock);
 		return (0);
+	}
 	p = pfr_create_kentry(ad, 1);
-	if (p == NULL)
+	if (p == NULL) {
+		spin_unlock(&pfr_pktmut_lock);
 		return (EINVAL);
+	}
 
 	rv = pfr_route_kentry(kt, p);
-	if (rv)
+	if (rv) {
+		spin_unlock(&pfr_pktmut_lock);
 		return (rv);
+	}
 
 	p->pfrke_tzero = tzero;
 	kt->pfrkt_cnt++;
+	spin_unlock(&pfr_pktmut_lock);
 
 	return (0);
 }
@@ -2058,6 +2073,7 @@
 	kt->pfrkt_bytes[dir_out][op_pass] += len;
 	if (ke != NULL && op_pass != PFR_OP_XPASS &&
 	    (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) {
+		spin_lock(&pfr_pktmut_lock);
 		if (ke->pfrke_counters == NULL)
 			ke->pfrke_counters = kmalloc(sizeof(struct pfr_kcounters),
 			    M_PFRKCOUNTERSPL, M_NOWAIT|M_ZERO);
@@ -2065,6 +2081,7 @@
 			ke->pfrke_counters->pfrkc_packets[dir_out][op_pass]++;
 			ke->pfrke_counters->pfrkc_bytes[dir_out][op_pass] += len;
 		}
+		spin_unlock(&pfr_pktmut_lock);
 	}
 }