java-topology/defects/linux/patch/linux-0004-neigh-parms-xarray-lookup.patch
russell@unturf.com 9cc2a89d0f linux: add complexity gate headers to all 8 patches; fix 0003/0007/0008 code issues
- All 8 patches now carry required # CWE-407 / # Defect / # Fix / # Complexity gate
  header blocks per patch file format spec
- linux-0001 (headerdep.pl): header only — code was correct
- linux-0002 (auditsc.c): header + explicit break to prevent ctx->names_list fall-through
- linux-0003 (dev.c): rewrote fix — skip altname loop when format has no percent-d
  placeholder; removes duplicate bounds check from prior draft
- linux-0004 (neighbour.c): header + cleaned up ifdef guards; xarray with fallback
- linux-0005 (component.c): header + existing hash fast-path retained
- linux-0006 (btf.c): header + fixed cache hit path — no longer re-runs
  btf_find_by_name_kind on hit; uses stored btf_id directly
- linux-0007 (pktgen.c): rewrote fix — replaced xa_for_each (O(N)) with dual
  DECLARE_HASHTABLE: dev_ht (by dev*) and name_ht (by jhash(ifname))
- linux-0008 (taskstats.c): fixed mixed list_for_each_entry/hash_for_each_possible
  syntax; clean replacement of duplicate-pid list scan with hash_for_each_possible
- Combined patch: linux-0001..0008-hashstruct.patch (8 defects, was missing 0004)
- outreach/linux.md: updated to 8 defects, corrected numbering (0001=headerdep,
  0002=auditsc, 0003=dev, 0004=neighbour, 0005-0008 as before)
2026-04-04 11:33:15 -04:00

93 lines
3.8 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UNDF: UNDF-2026-000000147
# CWE-407: Algorithmic Complexity — O(P) → O(1) in net/core/neighbour.c lookup_neigh_parms()
#
# Defect: lookup_neigh_parms() walks tbl->parms_list — one entry per registered network
# device — via list_for_each_entry until the matching ifindex is found. In VxLAN/bridge
# environments with P=hundreds of devices joined to ARP/NDP tables, every netlink neigh
# parameter command pays O(P) cost. Called on every 'ip neigh change', ARP table config,
# and NDP parameter update.
#
# Fix: maintain tbl->parms_xa (struct xarray) keyed by ifindex alongside the existing
# parms_list. neigh_parms_alloc() stores into it; neigh_parms_release() erases from it.
# lookup_neigh_parms() becomes a single xa_load() — O(1). parms_list is retained for
# GC iteration and module compatibility.
#
# Complexity gate (unit/LinuxTest.java linux-0003 benchmark):
# P=500 devices: slow O(500) avg=250 comparisons, fast O(1).
# At P=500: >250× speedup. 20× is a conservative lower bound even at P=20.
# Gate: ratio slow/fast must be ≥20× at P=500 sequential lookups.
#
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1752,11 +1752,37 @@ static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net,
spin_unlock_irqrestore(&list->lock, flags);
}
+/*
+ * CWE-407 fix: replace O(P) linear parms_list scan with O(1) xarray lookup.
+ *
+ * The original lookup_neigh_parms walks tbl->parms_list which holds one entry
+ * per network device registered with this neighbour table. In VxLAN/bridge
+ * environments with hundreds of devices, this is O(D) per netlink command.
+ *
+ * Fix: maintain tbl->parms_xa (struct xarray) keyed by ifindex.
+ * neigh_parms_alloc() stores into it; neigh_parms_release() erases from it.
+ * lookup_neigh_parms() becomes a single xa_load() call.
+ *
+ * parms_list is retained for GC iteration. ifindex==0 means global parms;
+ * stored at xarray key 0.
+ *
+ * NOTE: struct neigh_table in include/net/neighbour.h must gain:
+ * struct xarray parms_xa;
+ * Initialised in neigh_table_init() via xa_init(&tbl->parms_xa).
+ * Destroyed in neigh_table_unregister() via xa_destroy(&tbl->parms_xa).
+ */
static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
struct net *net, int ifindex)
{
- struct neigh_parms *p;
+ struct neigh_parms *p; /* retained for slow-path fallback */
- list_for_each_entry(p, &tbl->parms_list, list) {
- if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
- (!p->dev && !ifindex && net_eq(net, &init_net)))
+ /* CWE-407 fast path: O(1) xarray lookup by ifindex. */
+ p = xa_load(&tbl->parms_xa, (unsigned long)ifindex);
+ if (p && net_eq(neigh_parms_net(p), net))
+ return p;
+
+ /*
+ * Slow fallback: handles the case where parms_xa is not yet populated
+ * (boot time, module load) or net namespace mismatch. O(P).
+ */
+ list_for_each_entry(p, &tbl->parms_list, list) {
+ if ((p->dev && p->dev->ifindex == ifindex &&
+ net_eq(neigh_parms_net(p), net)) ||
+ (!p->dev && !ifindex && net_eq(net, &init_net)))
return p;
}
return NULL;
}
@@ -1790,6 +1816,10 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
p->dev = dev;
p->dev_tracker = dev_tracker;
list_add(&p->list, &tbl->parms_list);
+ /* CWE-407 fix: populate xarray so lookup_neigh_parms() is O(1). */
+ xa_store(&tbl->parms_xa,
+ (unsigned long)(dev ? dev->ifindex : 0),
+ p, GFP_KERNEL);
write_pnet(&p->net, net);
}
return p;
@@ -1822,6 +1852,9 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
if (parms == &tbl->parms)
return;
list_del(&parms->list);
+ /* CWE-407 fix: evict from xarray on release. */
+ xa_erase(&tbl->parms_xa,
+ (unsigned long)(parms->dev ? parms->dev->ifindex : 0));
kfree_rcu(parms, rcu_head);
}
EXPORT_SYMBOL(neigh_parms_release);