java-topology/docs/tickets/linux-0002-dev-alloc-name-nested-altname-scan.md
russell@unturf.com 9934133dcf whitepaper: 312 sites / 151 ecosystems — wave2+3 defect tables and PDF rebuild
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
2026-03-27 15:23:43 -04:00

94 lines
3.5 KiB
Markdown
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.

# 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
```c
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 veth` in a pod namespace — creates two interfaces,
both call `dev_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:
```c
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`