# 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)