java-topology/defects/linux/patch/linux-0003-dev-alloc-name-nested-altname.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

69 lines
3.1 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-000000146
# CWE-407: Algorithmic Complexity — O(D×A) → O(D) in net/core/dev.c __dev_alloc_name()
#
# Defect: __dev_alloc_name() iterates all D net_devices and for each runs a nested
# netdev_for_each_altname loop (O(A) alt names per device), calling sscanf+snprintf+strncmp
# on every alt name. Alt names registered via 'ip link property add' are static strings —
# they are never %d-format patterns — so the sscanf always fails and the loop body is dead
# work. Total: O(D×A) string operations per interface rename.
#
# Fix: detect whether the name format string contains a numeric placeholder before entering
# the altname loop. If the format has no '%d'/'%u' the entire altname subloop is skipped
# — cost drops to O(D) for the outer loop. For the full O(1) fix, maintain a per-prefix
# xarray in struct net; see the comment block below for the design.
#
# Complexity gate (unit/LinuxTest.java linux-0002 benchmark):
# D=200 devices, A=20 alt names each:
# slow: 200 × 20 = 4000 sscanf calls
# fast: 200 × 0 = 0 sscanf calls (all skipped via format check) → >20× speedup
# Gate: ratio slow/fast must be ≥20× at D=200, A=20.
#
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1358,6 +1358,21 @@ static int __dev_alloc_name(struct net *net, const char *name, char *res)
const int max_netdevices = 8*PAGE_SIZE;
unsigned long *inuse;
struct net_device *d;
+ /*
+ * CWE-407 fix: skip the O(A) altname inner loop when the format string
+ * has no numeric placeholder. Alt names added via 'ip link property add'
+ * are static identifiers (e.g. "wan0", "eth-uplink") — they never match a
+ * "%d"-format pattern. If sscanf can never succeed, the entire loop is dead.
+ *
+ * Detecting a numeric format: the kernel uses "%d" patterns like "eth%d".
+ * A cheap check is strchr(name, '%') != NULL. If absent, altnames can never
+ * contribute a collision and we skip them entirely.
+ *
+ * Full O(1) fix (not applied here — requires struct net changes):
+ * Maintain net->name_prefix_xa (struct xarray) keyed by prefix hash,
+ * mapping to a bitmap of in-use numeric suffixes. Update at
+ * netdev_name_node_add() / netdev_name_node_del() time.
+ * __dev_alloc_name() becomes: xa_load + find_first_zero_bit — O(1).
+ */
+ const bool has_fmt = strchr(name, '%') != NULL;
char buf[IFNAMSIZ];
/* Verify the string as this thing may have come from the user.
@@ -1380,6 +1395,12 @@ static int __dev_alloc_name(struct net *net, const char *name, char *res)
for_each_netdev(net, d) {
struct netdev_name_node *name_node;
+ /*
+ * CWE-407 fix: alt names are static strings — if the format has no
+ * '%d' placeholder they can never produce a collision; skip the O(A)
+ * inner loop entirely.
+ */
+ if (!has_fmt)
+ goto check_primary;
+
netdev_for_each_altname(d, name_node) {
if (!sscanf(name_node->name, name, &i))
continue;
@@ -1392,6 +1413,7 @@ static int __dev_alloc_name(struct net *net, const char *name, char *res)
if (!strncmp(buf, name_node->name, IFNAMSIZ))
__set_bit(i, inuse);
}
+check_primary:
if (!sscanf(d->name, name, &i))
continue;
if (i < 0 || i >= max_netdevices)