Add 88 new defect entries to HIGH and MEDIUM tables:
HIGH: mysql-0001/0002, mariadb-0001, redis-0001/0002, valkey-0001/0002, openvpn-0001,
vlc-0001, prometheus-0001, otel-collector-0001, cockroachdb-0001..0004,
tidb-0001..0008, kubernetes-0001/0002, go-0001, kotlin-0002, scala-0001,
allegro5-0001, sdl2-0001, grafana-0001, clickhouse-0001, duckdb-0001,
mongodb-0001, envoy-0001, istio-0001, cilium-0001, linkerd2-0001,
linux-0001/0002/0003, tor-0002/0003, curl-0001, julia-0001, lua-0001,
perl5-0001, nats-0001, spring-0003/0004, tomcat-0001, onos-0002, odl-0002
MEDIUM: helm-0001, mariadb-0002, openssl-0001/0002, memcached-0001,
cassandra-0001..0004, flink-0001, storm-0001/0002, zookeeper-0001..0003,
pip-0001, gradle-0001, nginx-0001, haproxy-0001, caddy-0001, varnish-0001,
ffmpeg-0001, gstreamer-0001, raylib-0001, love2d-0001, php-0001/0002,
r-source-0001, cpython-0002, ruby-0001, rabbitmq-0003/0004, activemq-0001,
ovs-0001, onos-0003, odl-0002, jetty-0001
PDF: 976K
3.5 KiB
linux-0003: lookup_neigh_parms — O(P) linear scan by ifindex on every netlink neigh table op
File: net/core/neighbour.c
Function: lookup_neigh_parms() (line ~1752)
Severity: MEDIUM — triggered on every ip neigh operation and ARP/NDP table config
CWE: CWE-407 (Inefficient Algorithmic Complexity)
Code
static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
struct net *net,
int ifindex)
{
struct neigh_parms *p;
list_for_each_entry(p, &tbl->parms_list, list) { // O(P) linear scan
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;
}
tbl->parms_list holds one neigh_parms per network device that has joined the
neighbour table. In environments with many network devices (bridges, VLANs, VxLAN
tunnels, bond members), this list grows to O(D) entries.
Complexity
| Variable | Meaning |
|---|---|
| P | Length of tbl->parms_list — one entry per netdev registered with this neigh_table |
lookup_neigh_parms is called from neigh_table_set_key() (netlink path) whenever
ip neigh change, ip neigh add, or ip ntable change is issued. On a host
with D=300 network interfaces (common in VxLAN fabrics), each such command walks
300 parms entries.
When Triggered
ip ntable change name arp dev eth0 # calls lookup_neigh_parms O(P)
ip neigh change 192.168.1.1 dev eth0 ... # calls neigh_lookup + parms lookup
Automation scripts that reconfigure neighbour parameters across many interfaces
(e.g., setting base_reachable_time for all VTEP devices) issue O(D) netlink
commands, each doing an O(D) scan → O(D²) total.
Root Cause
parms_list is a flat linked list ordered by insertion. Lookup by ifindex is
O(P) because there is no secondary index.
The natural key for neigh_parms is (net, ifindex). An xarray keyed by ifindex
within each net provides O(1) lookup with no extra memory per entry.
Fix
Replace the parms_list linear search with an xarray stored in struct neigh_table:
/* In struct neigh_table (include/net/neighbour.h): */
struct xarray parms_xa; /* keyed by ifindex, value = neigh_parms * */
struct list_head parms_list; /* keep for iteration (GC, sysctl dumps) */
/* neigh_parms_alloc: */
xa_store(&tbl->parms_xa, p->dev ? p->dev->ifindex : 0, p, GFP_KERNEL);
/* lookup_neigh_parms replacement: */
static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
struct net *net,
int ifindex)
{
struct neigh_parms *p = xa_load(&tbl->parms_xa, ifindex);
if (p && net_eq(neigh_parms_net(p), net))
return p;
return NULL;
}
/* neigh_parms_release: */
xa_erase(&tbl->parms_xa, p->dev ? p->dev->ifindex : 0);
The parms_list is retained for the GC timer path (neigh_periodic_work) which
iterates all parms to call neigh_set_reach_time.
Impact
- O(D) per netlink command; O(D²) for configuration scripts covering all devices.
- On a VxLAN gateway with 500 VTEPs: 500 parms entries × 500 commands = 250,000 list-node comparisons per configuration pass.
- With xarray: 500 commands × O(1) = 500 xa_load calls.
Patch
See defects/linux/patch/linux-0004-neigh-parms-xarray-lookup.patch