Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F139410309
D17734.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
3 KB
Referenced Files
None
Subscribers
None
D17734.diff
View Options
Index: head/sys/net/pfvar.h
===================================================================
--- head/sys/net/pfvar.h
+++ head/sys/net/pfvar.h
@@ -1211,6 +1211,13 @@
#define PF_FRAG_ENTRY_POINTS 16
/*
+ * The number of entries in the fragment queue must be limited
+ * to avoid DoS by linear seaching. Instead of a global limit,
+ * use a limit per entry point. For large packets these sum up.
+ */
+#define PF_FRAG_ENTRY_LIMIT 64
+
+/*
* ioctl parameter structures
*/
Index: head/sys/netpfil/pf/pf_norm.c
===================================================================
--- head/sys/netpfil/pf/pf_norm.c
+++ head/sys/netpfil/pf/pf_norm.c
@@ -87,7 +87,10 @@
#define fr_af fr_key.frc_af
#define fr_proto fr_key.frc_proto
+ /* pointers to queue element */
struct pf_frent *fr_firstoff[PF_FRAG_ENTRY_POINTS];
+ /* count entries between pointers */
+ uint8_t fr_entries[PF_FRAG_ENTRY_POINTS];
RB_ENTRY(pf_fragment) fr_entry;
TAILQ_ENTRY(pf_fragment) frag_next;
uint32_t fr_timeout;
@@ -138,7 +141,7 @@
static struct pf_fragment *pf_find_fragment(struct pf_fragment_cmp *key,
struct pf_frag_tree *tree);
static inline int pf_frent_index(struct pf_frent *);
-static void pf_frent_insert(struct pf_fragment *,
+static int pf_frent_insert(struct pf_fragment *,
struct pf_frent *, struct pf_frent *);
void pf_frent_remove(struct pf_fragment *,
struct pf_frent *);
@@ -392,12 +395,24 @@
return frent->fe_off / (0x10000 / PF_FRAG_ENTRY_POINTS);
}
-static void
+static int
pf_frent_insert(struct pf_fragment *frag, struct pf_frent *frent,
struct pf_frent *prev)
{
int index;
+ CTASSERT(PF_FRAG_ENTRY_LIMIT <= 0xff);
+
+ /*
+ * A packet has at most 65536 octets. With 16 entry points, each one
+ * spawns 4096 octets. We limit these to 64 fragments each, which
+ * means on average every fragment must have at least 64 octets.
+ */
+ index = pf_frent_index(frent);
+ if (frag->fr_entries[index] >= PF_FRAG_ENTRY_LIMIT)
+ return ENOBUFS;
+ frag->fr_entries[index]++;
+
if (prev == NULL) {
TAILQ_INSERT_HEAD(&frag->fr_queue, frent, fr_next);
} else {
@@ -406,7 +421,6 @@
TAILQ_INSERT_AFTER(&frag->fr_queue, prev, frent, fr_next);
}
- index = pf_frent_index(frent);
if (frag->fr_firstoff[index] == NULL) {
KASSERT(prev == NULL || pf_frent_index(prev) < index,
("prev == NULL || pf_frent_index(pref) < index"));
@@ -424,6 +438,8 @@
}
frag->fr_holes += pf_frent_holes(frent);
+
+ return 0;
}
void
@@ -460,6 +476,9 @@
}
TAILQ_REMOVE(&frag->fr_queue, frent, fr_next);
+
+ KASSERT(frag->fr_entries[index] > 0, ("No fragments remaining"));
+ frag->fr_entries[index]--;
}
struct pf_frent *
@@ -567,6 +586,7 @@
*(struct pf_fragment_cmp *)frag = *key;
memset(frag->fr_firstoff, 0, sizeof(frag->fr_firstoff));
+ memset(frag->fr_entries, 0, sizeof(frag->fr_entries));
frag->fr_timeout = time_uptime;
frag->fr_maxlen = frent->fe_len;
frag->fr_holes = 1;
@@ -575,7 +595,7 @@
RB_INSERT(pf_frag_tree, &V_pf_frag_tree, frag);
TAILQ_INSERT_HEAD(&V_pf_fragqueue, frag, frag_next);
- /* We do not have a previous fragment. */
+ /* We do not have a previous fragment, cannot fail. */
pf_frent_insert(frag, frent, NULL);
return (frag);
@@ -646,7 +666,11 @@
uma_zfree(V_pf_frent_z, after);
}
- pf_frent_insert(frag, frent, prev);
+ /* If part of the queue gets too long, there is not way to recover. */
+ if (pf_frent_insert(frag, frent, prev)) {
+ DPFPRINTF(("fragment queue limit exceeded"));
+ goto bad_fragment;
+ }
return (frag);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Dec 12, 6:52 PM (2 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26895168
Default Alt Text
D17734.diff (3 KB)
Attached To
Mode
D17734: pf: Limit the fragment entry queue length to 64 per bucket.
Attached
Detach File
Event Timeline
Log In to Comment