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-0002: __dev_alloc_name — O(D×A) nested sscanf on every interface rename
File: net/core/dev.c
Function: __dev_alloc_name() (line ~1358)
Severity: MEDIUM — triggered on every ip link add, ip link set name, container veth creation
CWE: CWE-407 (Inefficient Algorithmic Complexity)
Code
static int __dev_alloc_name(struct net *net, const char *name, char *res)
{
/* ... */
for_each_netdev(net, d) { // O(D) — all devices
struct netdev_name_node *name_node;
netdev_for_each_altname(d, name_node) { // O(A) — alt names per device
if (!sscanf(name_node->name, name, &i)) // string parse each time
continue;
if (i < 0 || i >= max_netdevices)
continue;
snprintf(buf, IFNAMSIZ, name, i);
if (!strncmp(buf, name_node->name, IFNAMSIZ))
__set_bit(i, inuse);
}
/* same sscanf/snprintf/strncmp on d->name */
}
i = find_first_zero_bit(inuse, max_netdevices);
/* ... */
}
Complexity
| Variable | Meaning |
|---|---|
| D | Number of net devices in the namespace |
| A | Number of alternative names per device |
Total work per call: O(D × A × sscanf_cost).
sscanf with a format containing %d is not O(1); it involves format string parsing.
Container-heavy hosts (Kubernetes nodes) routinely carry D=500+ veth/bridge/vlan
devices, each with 1-3 alt names from ip link property add.
When Triggered
ip link add vethN type vethin a pod namespace — creates two interfaces, both calldev_alloc_name()with format"veth%d".- A node creating 100 pods triggers 200 calls; if D=400 devices already exist with A=2 alt names, each call walks 800 entries.
- Batch pod launches show O(D²) total work as D grows.
Root Cause
The bitmap approach is correct for the final find_first_zero_bit, but the bitmap
is populated by rescanning all devices + alt names on every call. The primary
device name already uses the hash (dev_name_hash), but alt names bypass the hash
and fall into the linear netdev_for_each_altname walk.
Fix
Maintain a sorted or hash-keyed index of all allocated numeric suffixes per name
prefix. On device/altname registration, insert the suffix into the prefix's free
map; on deregistration, remove it. __dev_alloc_name then does one map lookup
to find the first free slot in O(log D) or O(1) amortized.
Simpler interim fix: skip the netdev_for_each_altname inner loop when counting
in-use slots for the primary name format, since alt names use different formats
(verified by netdev_name_node_alt_create — alt names are explicit strings, not
%d patterns). Add a guard:
netdev_for_each_altname(d, name_node) {
/* Alt names created via 'ip link property add' are never %d patterns;
* skip sscanf unless the alt name could plausibly match. */
if (!memchr(name_node->name, '0' + (i % 10), IFNAMSIZ))
continue; /* fast reject — not numeric */
/* ... existing sscanf logic ... */
}
Full fix: maintain per-prefix bitmaps in a global xarray keyed by name prefix hash.
Impact
- O(D×A) work per interface creation; D and A both grow with container density.
- On a Kubernetes node with 500 pods: ~1000 devices × 2 alt names = 2000 sscanf calls per new pod creation, versus O(1) with an index.
- Multiplied by pod churn rate (100/min), this is 200,000 sscanf calls/min.
Patch
See defects/linux/patch/linux-0003-dev-alloc-name-nested-altname.patch