惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
腾讯CDC
M
MIT News - Artificial intelligence
Y
Y Combinator Blog
L
LangChain Blog
Vercel News
Vercel News
云风的 BLOG
云风的 BLOG
GbyAI
GbyAI
Stack Overflow Blog
Stack Overflow Blog
Microsoft Azure Blog
Microsoft Azure Blog
B
Blog RSS Feed
The GitHub Blog
The GitHub Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
B
Blog
P
Proofpoint News Feed
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园_首页
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
aimingoo的专栏
aimingoo的专栏
小众软件
小众软件
IT之家
IT之家
A
About on SuperTechFans
H
Help Net Security

dnsmasq-discuss

[Dnsmasq-discuss] Announce: dnsmasq-2.92rc2 Re: [Dnsmasq-discuss] [PATCH] Fix arguments order for chaos subdomain check Re: [Dnsmasq-discuss] patch: block-file/allow-file - for review/feedback Re: [Dnsmasq-discuss] patch: block-file/allow-file - for review/feedback Re: [Dnsmasq-discuss] patch: block-file/allow-file - for review/feedback Re: [Dnsmasq-discuss] patch: block-file/allow-file - for review/feedback [Dnsmasq-discuss] patch: block-file/allow-file - for review/feedback Re: [Dnsmasq-discuss] server= with interface parameter changes behavior over time [Dnsmasq-discuss] NFTsets and hosts-files [Dnsmasq-discuss] [PATCH] Allow expired RRSIGs when stale caching is enabled [Dnsmasq-discuss] [PATCH] Fix local host records being overridden by upstream NXDOMAIN [Dnsmasq-discuss] [PATCH] Fix arguments order for chaos subdomain check Re: [Dnsmasq-discuss] Malformed RRSIG Can Crash dnsmasq [Dnsmasq-discuss] Malformed NSEC/NSEC3 Can Hang dnsmasq [Dnsmasq-discuss] Malformed RRSIG Can Crash dnsmasq [Dnsmasq-discuss] Security - IMPORTANT Re: [Dnsmasq-discuss] Issue with circuit-id matching on dhcp requests Re: [Dnsmasq-discuss] Issue with circuit-id matching on dhcp requests Re: [Dnsmasq-discuss] Issue with circuit-id matching on dhcp requests [Dnsmasq-discuss] Issue with circuit-id matching on dhcp requests Re: [Dnsmasq-discuss] [PATCH] bpf.c: fix memory leak in arp_enumerate() on BSD Re: [Dnsmasq-discuss] [PATCH] bpf.c: fix memory leak in arp_enumerate() on BSD Re: [Dnsmasq-discuss] dnssec problem here and now Re: [Dnsmasq-discuss] dnssec problem here and now [Dnsmasq-discuss] dnssec problem here and now Re: [Dnsmasq-discuss] server= with interface parameter changes behavior over time Re: [Dnsmasq-discuss] [PATCH] bpf.c: fix memory leak in arp_enumerate() on BSD Re: [Dnsmasq-discuss] [PATCH] Preserve existing log file permissions when adding group-write bit. [Dnsmasq-discuss] server= with interface parameter changes behavior over time [Dnsmasq-discuss] [PATCH] bpf.c: fix memory leak in arp_enumerate() on BSD
Re: [Dnsmasq-discuss] [PATCH] bpf.c: fix memory leak in a...
Simon Kelley · 2026-05-05 · via dnsmasq-discuss
Good catch.

That code has been there eating memory for 15 years, and was added just before the dnsmasq git repository started, so how it ended up like that is a bit of a mystery.

The code looks like it's using a common design pattern in dnsmasq, where the buffer is stored in a long-lived iovec and expand_buf() only does anything if the existing buffer is too small. This avoids lots of malloc()/free() calls in hot code paths and resulting heap fragmentation. The only problem is that the iovec in this case is not long-lived. My guess is that this code got copied from elsewhere, and the importance of that detail was missed.

The fix is to declare struct iovec buff as static. Then the buffer becomes long-lived and all the rest of the code, without any free() calls, makes sense.

I just committed

https://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=4bcc9650fac9a48502679cd793d269ef60caef07

which does exactly that. It would be great if you could check it works OK on your tests.


What would be _really_ nice (hint, hint) would be to extend this code to return IPv6 neighbours.


Cheers,

Simon.




On 26.04.2026 17:18, Sagie Duchovne-Nave wrote:
arp_enumerate() allocates a heap buffer via expand_buf() to hold the
kernel ARP table dump retrieved through sysctl(NET_RT_FLAGS). This
buffer is never freed on any return path -- neither the early error
returns nor the normal return after iteration -- causing a leak on
every call.

The leak is most acute in the DHCPv6 path. get_client_mac() calls
find_mac() up to five times per packet with lazy=0. Because the
'updated' flag is local to each find_mac() invocation, a cached
ARP_EMPTY entry for an unresolvable IPv6 address does not short-
circuit the kernel lookup: each call falls through to iface_enumerate()
-> arp_enumerate(), leaking one buffer per call. This yields up to
five leaked allocations per DHCPv6 SOLICIT packet. The leak size per
call equals the full system-wide IPv4 ARP table dump across all
interfaces.

The condition is readily triggered by a DHCPv6 client whose MAC
address cannot be resolved via NDP -- which is the common case on
FreeBSD, because arp_enumerate() queries NET_RT_FLAGS/RTF_LLINFO,
which returns IPv4 ARP entries only; IPv6 NDP neighbour entries are
not included. As a result every IPv6 MAC lookup fails unconditionally
on FreeBSD, every failed lookup produces an ARP_EMPTY record that is
never promoted, and every subsequent packet for that client leaks five
buffers.

Fix: free buff.iov_base on all return paths in arp_enumerate(),
including the early returns inside the retry loop where iov_base may
already be non-NULL from a prior expand_buf() call.

Reported against: FreeBSD 14, dnsmasq 2.91
Observed symptom: steady process memory growth correlated with DHCPv6
SOLICIT traffic from a client whose NDP entry is absent from the
kernel table (confirmed by disabling the client stopping the balloon).

Signed-off-by: Sagie D.
---
  bpf.c | 8 +++++++-
  1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/bpf.c b/bpf.c
index XXXXXXX..XXXXXXX 100644
--- a/bpf.c
+++ b/bpf.c
@@ -xx,12 +xx,18 @@ int arp_enumerate(void *parm, callback_t callback)
    while (1)
      {
        if (!expand_buf(&buff, needed))
-        return 0;
+        {
+          free(buff.iov_base);
+          return 0;
+        }
        if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
            errno != ENOMEM)
          break;
        needed += needed / 8;
      }
    if (rc == -1)
-    return 0;
+    {
+      free(buff.iov_base);
+      return 0;
+    }

    for (next = buff.iov_base ; next < (char *)buff.iov_base + needed;
next += rtm->rtm_msglen)
      {
        rtm = (struct rt_msghdr *)next;
        sin2 = (struct sockaddr_inarp *)(rtm + 1);
        sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
        if (!callback.af_unspec(AF_INET, &sin2->sin_addr, LLADDR(sdl),
sdl->sdl_alen, parm))
-        return 0;
+        {
+          free(buff.iov_base);
+          return 0;
+        }
      }

-  return 1;
+  free(buff.iov_base);
+  return 1;
  }

_______________________________________________
Dnsmasq-discuss mailing list
[email protected]
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss



_______________________________________________
Dnsmasq-discuss mailing list
[email protected]
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss