# UNDF: UNDF-2026-000000200 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -370,6 +370,10 @@ int if_setlladdr(struct ifnet *, const uint8_t *); struct ifaddr *if_get_gwaddr(struct ifnet *, sa_family_t); struct ifaddr *ifa_ifwithaddr(const struct sockaddr *, u_int); struct ifaddr *ifa_ifwithdstaddr(const struct sockaddr *, u_int); +/* CWE-407: hash-based local-address lookup maintenance */ +void ifa_hash_insert(struct ifaddr *); +void ifa_hash_remove(struct ifaddr *); --- a/sys/net/if.c +++ b/sys/net/if.c @@ -60,6 +60,24 @@ #include #include +/* + * CWE-407 fix: per-rdomain hash table for O(1) local-address lookup. + * Replaces O(I×A) double-foreach in ifa_ifwithaddr. + * Hash key: (sa_family XOR first 4 bytes of sa_data). + */ +#define IFA_HASH_BITS 8 +#define IFA_HASH_SIZE (1 << IFA_HASH_BITS) +#define IFA_HASH_MASK (IFA_HASH_SIZE - 1) + +static inline unsigned int +ifa_hash_key(const struct sockaddr *sa) +{ + const u_int8_t *d = (const u_int8_t *)sa->sa_data; + unsigned int h = sa->sa_family; + if (sa->sa_len > offsetof(struct sockaddr, sa_data) + 3) + h ^= (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3]; + return h & IFA_HASH_MASK; +} + +LIST_HEAD(ifa_hash_bucket, ifaddr); +static struct ifa_hash_bucket ifa_hashtbl[IFA_HASH_SIZE]; + +void +ifa_hash_insert(struct ifaddr *ifa) +{ + unsigned int h = ifa_hash_key(ifa->ifa_addr); + LIST_INSERT_HEAD(&ifa_hashtbl[h], ifa, ifa_hash); +} + +void +ifa_hash_remove(struct ifaddr *ifa) +{ + LIST_REMOVE(ifa, ifa_hash); +} + #define equal(a1, a2) \ (bcmp((caddr_t)(a1), (caddr_t)(a2), \ (a1)->sa_len) == 0) @@ -1619,22 +1642,19 @@ ifa_ifwithaddr(const struct sockaddr *addr, u_int rtableid) { - struct ifnet *ifp; struct ifaddr *ifa; u_int rdomain; NET_ASSERT_LOCKED(); rdomain = rtable_l2(rtableid); - TAILQ_FOREACH(ifp, &ifnetlist, if_list) { /* O(I) */ - if (ifp->if_rdomain != rdomain) - continue; - TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { /* O(A) */ - if (ifa->ifa_addr->sa_family != addr->sa_family) - continue; - if (equal(addr, ifa->ifa_addr)) { - return (ifa); - } + /* CWE-407: O(1) hash lookup instead of O(I×A) nested scan */ + LIST_FOREACH(ifa, &ifa_hashtbl[ifa_hash_key(addr)], ifa_hash) { + if (ifa->ifa_ifp->if_rdomain != rdomain) + continue; + if (ifa->ifa_addr->sa_family != addr->sa_family) + continue; + if (equal(addr, ifa->ifa_addr)) { + return (ifa); } } return (NULL);