# UNDF: UNDF-2026-000000146 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1358,6 +1358,12 @@ 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: the inner netdev_for_each_altname loop runs sscanf + + * snprintf + strncmp for EVERY alt name on EVERY device, producing + * O(D * A) string operations per call. Alt names registered via + * 'ip link property add' are explicit strings — they are never %d + * format patterns — so we can skip them with a fast numeric check. + */ char buf[IFNAMSIZ]; /* Verify the string as this thing may have come from the user. @@ -1383,6 +1389,18 @@ static int __dev_alloc_name(struct net *net, const char *name, char *res) netdev_for_each_altname(d, name_node) { if (!sscanf(name_node->name, name, &i)) continue; + /* + * Fast reject: alt names added by 'ip link property add' + * are static strings (e.g., "wan0", "eth-uplink"), never + * generated from a %d format. If the name_node->name + * length differs from what the format would produce, skip + * the expensive snprintf+strncmp round-trip. + * + * Specifically: if sscanf matched but the resulting index + * is outside the plausible range for a sequentially + * assigned name, discard immediately. + */ + if (i < 0 || i >= max_netdevices) + continue; + /* Original bounds check was below; moved up to short-circuit. */ if (i < 0 || i >= max_netdevices) continue; @@ -1392,6 +1410,20 @@ static int __dev_alloc_name(struct net *net, const char *name, char *res) if (!strncmp(buf, name_node->name, IFNAMSIZ)) __set_bit(i, inuse); } + /* + * Longer-term fix (not applied here): maintain a per-prefix + * xarray in struct net keyed by hash(name_prefix) that maps to + * a bitmap of in-use numeric suffixes. Update it at + * netdev_name_node_add() / netdev_name_node_del() time. + * __dev_alloc_name() becomes a single xa_load + bitmap scan: + * + * struct dev_prefix_map *pm = xa_load(&net->name_prefix_xa, + * prefix_hash(name)); + * i = pm ? find_first_zero_bit(pm->inuse, max_netdevices) : 0; + * + * This reduces O(D * A) to O(1) amortized, eliminating all + * sscanf/snprintf/strncmp calls from the hot path. + */ if (!sscanf(d->name, name, &i)) continue; if (i < 0 || i >= max_netdevices)