84 lines
2.4 KiB
Diff
84 lines
2.4 KiB
Diff
# 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 <net/if_var.h>
|
||
#include <net/route.h>
|
||
|
||
+/*
|
||
+ * 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);
|