⬢ DragonFlyBSD Kernel Audit
DF-3361 / fix.diff
← back to finding ↓ download raw
--- a/sys/net/pf/pf_norm.c
+++ b/sys/net/pf/pf_norm.c
@@ -962,6 +962,22 @@
 		    max > frag->fr_max)
 			goto bad;
 
+		/* NOTE (DF-3361): enforce the registered fragment pool
+		 * limit (pfctl set limit frags; default
+		 * PFFRAG_FRENT_HIWAT).  The pool_sethardlimit() calls
+		 * were disabled in the DragonFly port, so nothing ever
+		 * checked it and a fragment flood grew the pools without
+		 * bound.
+		 */
+		if (pf_nfrents >= pf_pool_limits[PF_LIMIT_FRAGS].limit) {
+			pf_flush_fragments();
+			if (pf_nfrents >=
+			    pf_pool_limits[PF_LIMIT_FRAGS].limit) {
+				REASON_SET(reason, PFRES_MEMORY);
+				return (PF_DROP);
+			}
+		}
+
 		/* Get an entry for the fragment queue */
 		frent = kmalloc(sizeof(struct pf_frent), M_PFFRENTPL, M_NOWAIT);
 		if (frent == NULL) {
@@ -998,6 +1014,17 @@
 
 		frag = pf_find_fragment(h, &pf_cache_tree[cpu]);
 
+		/* NOTE (DF-3361): same as above for the non-buffering
+		 * fragment cache descriptors.
+		 */
+		if (pf_ncache >= PFFRAG_FRCACHE_HIWAT) {
+			pf_flush_fragments();
+			if (pf_ncache >= PFFRAG_FRCACHE_HIWAT) {
+				REASON_SET(reason, PFRES_MEMORY);
+				return (PF_DROP);
+			}
+		}
+
 		/* Check if we saw the last fragment already */
 		if (frag != NULL && (frag->fr_flags & PFFRAG_SEENLAST) &&
 		    max > frag->fr_max) {