java-topology/defects/openbsd/patch/openbsd-0001-pf-osfp-validate-quadratic.patch

58 lines
2.1 KiB
Diff

--- a/sys/net/pf_osfp.c
+++ b/sys/net/pf_osfp.c
@@ -74,6 +74,14 @@ struct pool pf_osfp_pl;
SLIST_HEAD(pf_osfp_list, pf_os_fingerprint) pf_osfp_list =
SLIST_HEAD_INITIALIZER(pf_osfp_list); /* [p] */
+/*
+ * CWE-407 fix: hash pf_osfp_list by fp_tcpopts to replace O(N) linear scan
+ * in pf_osfp_find with O(N/OSFP_BUCKETS) bucket scan. With N=246 default
+ * entries and 64 buckets, average bucket depth ~4 instead of 246.
+ * Reduces pf_osfp_validate from O(N²) to O(N * bucket_depth).
+ */
+#define OSFP_BUCKETS 64
+#define OSFP_HASH(tc) ((unsigned int)((tc) ^ ((tc) >> 8)) % OSFP_BUCKETS)
+static SLIST_HEAD(pf_osfp_bucket, pf_os_fingerprint) pf_osfp_hash[OSFP_BUCKETS];
+
struct pf_os_fingerprint *pf_osfp_find(struct pf_os_fingerprint *,
u_int8_t);
struct pf_os_fingerprint *pf_osfp_find_exact(struct pf_os_fingerprint *);
@@ -294,6 +302,12 @@ pf_osfp_flush(void)
while ((fp = SLIST_FIRST(&pf_osfp_list))) {
SLIST_REMOVE_HEAD(&pf_osfp_list, fp_next);
pool_put(&pf_osfp_pl, fp);
+ /* Note: bucket list entries are also removed with the main list.
+ * Re-init all buckets after flush. */
+ }
+ for (int i = 0; i < OSFP_BUCKETS; i++) {
+ while (!SLIST_EMPTY(&pf_osfp_hash[i]))
+ SLIST_REMOVE_HEAD(&pf_osfp_hash[i], fp_next);
}
}
@@ -528,12 +542,15 @@ pf_osfp_find(struct pf_os_fingerprint *find, u_int8_t ttldiff)
struct pf_os_fingerprint *f;
PF_ASSERT_LOCKED();
+ /* CWE-407: use hash bucket instead of full-list O(N) scan */
+ unsigned int bucket = OSFP_HASH(find->fp_tcpopts);
- SLIST_FOREACH(f, &pf_osfp_list, fp_next) {
+ SLIST_FOREACH(f, &pf_osfp_hash[bucket], fp_next) {
if (f->fp_tcpopts != find->fp_tcpopts ||
... [rest of existing comparison logic unchanged]
}
return (NULL);
}
@@ -556,6 +573,12 @@ pf_osfp_insert(struct pf_os_fingerprint *ins)
if (prev)
SLIST_INSERT_AFTER(prev, ins, fp_next);
else
SLIST_INSERT_HEAD(&pf_osfp_list, ins, fp_next);
+
+ /* CWE-407 fix: also insert into hash bucket for O(1) lookup */
+ unsigned int bucket = OSFP_HASH(ins->fp_tcpopts);
+ SLIST_INSERT_HEAD(&pf_osfp_hash[bucket], ins, fp_bucket);
}