summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Audia2026-06-15 12:21:46 +0000
committerJonas Jelonek2026-06-16 10:14:55 +0000
commitcd8d701c7fc0efe9b8170b44354945a21474c066 (patch)
treec685f8f18f48d46978856d83684f83286117ffde
parent886e0248e82c0bfa571add7a099360cc035dbeee (diff)
backport: update dnsmasq to v2.93 from master
Wholesale drop of dnsmasq from master/not a cherry pick. Reference PR: https://github.com/openwrt/openwrt/pull/23669 Signed-off-by: John Audia <therealgraysky@proton.me> Link: https://github.com/openwrt/openwrt/pull/23804 Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
-rw-r--r--package/network/services/dnsmasq/Makefile9
-rwxr-xr-xpackage/network/services/dnsmasq/files/dhcp-script.sh9
-rwxr-xr-xpackage/network/services/dnsmasq/files/dnsmasq.init27
-rw-r--r--package/network/services/dnsmasq/patches/0001-Fix-spurious-resource-limit-exceeded-messages.patch43
-rw-r--r--package/network/services/dnsmasq/patches/0002-PATCH-Fix-error-introduced-in-51471cafa5a4fa44d6fe49.patch31
-rw-r--r--package/network/services/dnsmasq/patches/0003-Handle-DS-queries-to-auth-zones.patch98
-rw-r--r--package/network/services/dnsmasq/patches/001-CVE-2026-2291.patch29
-rw-r--r--package/network/services/dnsmasq/patches/002-CVE-2026-4890.dnsmasq-2.91.patch63
-rw-r--r--package/network/services/dnsmasq/patches/003-CVE-2026-4891.patch32
-rw-r--r--package/network/services/dnsmasq/patches/004-CVE-2026-4892.patch28
-rw-r--r--package/network/services/dnsmasq/patches/005-CVE-2026-4893.patch26
-rw-r--r--package/network/services/dnsmasq/patches/006-CVE-2026-5172.patch26
-rw-r--r--package/network/services/dnsmasq/patches/100-remove-old-runtime-kernel-support.patch15
-rw-r--r--package/network/services/dnsmasq/patches/200-ubus_dns.patch32
14 files changed, 60 insertions, 408 deletions
diff --git a/package/network/services/dnsmasq/Makefile b/package/network/services/dnsmasq/Makefile
index ff5d5a7ad9..19ae7b7cd1 100644
--- a/package/network/services/dnsmasq/Makefile
+++ b/package/network/services/dnsmasq/Makefile
@@ -8,13 +8,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=dnsmasq
-PKG_UPSTREAM_VERSION:=2.90
+PKG_UPSTREAM_VERSION:=2.93
PKG_VERSION:=$(subst test,~~test,$(subst rc,~rc,$(PKG_UPSTREAM_VERSION)))
-PKG_RELEASE:=5
+PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_UPSTREAM_VERSION).tar.xz
PKG_SOURCE_URL:=https://thekelleys.org.uk/dnsmasq/
-PKG_HASH:=8e50309bd837bfec9649a812e066c09b6988b73d749b7d293c06c57d46a109e4
+PKG_HASH:=0c00d4e5c97c8306e5fb932b348b34269c9c29a0e7df0e8e82958b407092bc19
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=COPYING
@@ -44,13 +44,14 @@ define Package/dnsmasq/Default
CATEGORY:=Base system
TITLE:=DNS and DHCP server
URL:=http://www.thekelleys.org.uk/dnsmasq/
- DEPENDS:=+libubus
+ DEPENDS:=+libubus +@BUSYBOX_CONFIG_PIDOF
USERID:=dnsmasq=453:dnsmasq=453
endef
define Package/dnsmasq
$(call Package/dnsmasq/Default)
VARIANT:=nodhcpv6
+ DEFAULT_VARIANT:=1
endef
define Package/dnsmasq-dhcpv6
diff --git a/package/network/services/dnsmasq/files/dhcp-script.sh b/package/network/services/dnsmasq/files/dhcp-script.sh
index 470097bf6b..f0c8b50902 100755
--- a/package/network/services/dnsmasq/files/dhcp-script.sh
+++ b/package/network/services/dnsmasq/files/dhcp-script.sh
@@ -8,6 +8,15 @@ json_init
json_add_array env
hotplugobj=""
+oldIFS=$IFS
+IFS=$'\n'
+for var in $(env); do
+ if [ "${var}" != "${var#DNSMASQ_}" ]; then
+ json_add_string "" "${var%%=*}=${var#*=}"
+ fi
+done
+IFS=$oldIFS
+
case "$1" in
add | del | old | arp-add | arp-del)
json_add_string "" "MACADDR=$2"
diff --git a/package/network/services/dnsmasq/files/dnsmasq.init b/package/network/services/dnsmasq/files/dnsmasq.init
index e9afcc78d3..61dc396707 100755
--- a/package/network/services/dnsmasq/files/dnsmasq.init
+++ b/package/network/services/dnsmasq/files/dnsmasq.init
@@ -20,7 +20,7 @@ BASEDHCPSTAMPFILE="/var/run/dnsmasq"
DHCPBOGUSHOSTNAMEFILE="/usr/share/dnsmasq/dhcpbogushostname.conf"
RFC6761FILE="/usr/share/dnsmasq/rfc6761.conf"
DHCPSCRIPT="/usr/lib/dnsmasq/dhcp-script.sh"
-DHCPSCRIPT_DEPENDS="/usr/share/libubox/jshn.sh /usr/bin/jshn /bin/ubus"
+DHCPSCRIPT_DEPENDS="/usr/share/libubox/jshn.sh /usr/bin/jshn /bin/ubus /usr/bin/env"
DNSMASQ_DHCP_VER=4
@@ -170,7 +170,9 @@ append_rev_server() {
}
append_address() {
+ local address_as_local="$2"
xappend "--address=$1"
+ [ $address_as_local -gt 0 ] && xappend "--local=${1%/*}/"
}
append_connmark_allowlist() {
@@ -597,10 +599,20 @@ dhcp_add() {
nettag="${networkid:+set:${networkid},}"
# make sure the DHCP range is not empty
- if [ "$dhcpv4" != "disabled" ] && ipcalc "$ipaddr/$prefix_or_netmask" "$start" "$limit" ; then
- [ "$dynamicdhcpv4" = "0" ] && END="static"
-
- xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}"
+ if [ "$dhcpv4" != "disabled" ]; then
+ unset START
+ unset END
+ unset NETMASK
+ ipcalc "$ipaddr/$prefix_or_netmask" "$start" "$limit"
+
+ if [ -z "$START" ] || [ -z "$END" ] || [ -z "$NETMASK" ]; then
+ logger -t dnsmasq \
+ "unable to set dhcp-range for dhcp uci config section '$cfg'" \
+ "on interface '$ifname', please check your config"
+ else
+ [ "$dynamicdhcpv4" = "0" ] && END="static"
+ xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}"
+ fi
fi
if [ "$dynamicdhcpv6" = "0" ] ; then
@@ -1026,7 +1038,10 @@ dnsmasq_start()
config_list_foreach "$cfg" "listen_address" append_listenaddress
config_list_foreach "$cfg" "server" append_server
config_list_foreach "$cfg" "rev_server" append_rev_server
- config_list_foreach "$cfg" "address" append_address
+
+ local address_as_local
+ config_get address_as_local "$cfg" address_as_local 0
+ config_list_foreach "$cfg" "address" append_address "$address_as_local"
local connmark_allowlist_enable
config_get connmark_allowlist_enable "$cfg" connmark_allowlist_enable 0
diff --git a/package/network/services/dnsmasq/patches/0001-Fix-spurious-resource-limit-exceeded-messages.patch b/package/network/services/dnsmasq/patches/0001-Fix-spurious-resource-limit-exceeded-messages.patch
deleted file mode 100644
index f25ee20413..0000000000
--- a/package/network/services/dnsmasq/patches/0001-Fix-spurious-resource-limit-exceeded-messages.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 1ed783b8d7343c42910a61f12a8fc6237eb80417 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Mon, 19 Feb 2024 12:22:43 +0000
-Subject: Fix spurious "resource limit exceeded" messages.
-
-Replies from upstream with a REFUSED rcode can result in
-log messages stating that a resource limit has been exceeded,
-which is not the case.
-
-Thanks to Dominik Derigs and the Pi-hole project for
-spotting this.
----
- CHANGELOG | 5 +++++
- src/forward.c | 6 +++---
- 2 files changed, 8 insertions(+), 3 deletions(-)
-
---- a/CHANGELOG
-+++ b/CHANGELOG
-@@ -1,3 +1,8 @@
-+version 2.91
-+ Fix spurious "resource limit exceeded messages". Thanks to
-+ Dominik Derigs for the bug report.
-+
-+
- version 2.90
- Fix reversion in --rev-server introduced in 2.88 which
- caused breakage if the prefix length is not exactly divisible
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -937,10 +937,10 @@ static void dnssec_validate(struct frec
- status = dnssec_validate_reply(now, header, plen, daemon->namebuff, daemon->keyname, &forward->class,
- !option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
- NULL, NULL, NULL, &orig->validate_counter);
-- }
-
-- if (STAT_ISEQUAL(status, STAT_ABANDONED))
-- log_resource = 1;
-+ if (STAT_ISEQUAL(status, STAT_ABANDONED))
-+ log_resource = 1;
-+ }
-
- /* Can't validate, as we're missing key data. Put this
- answer aside, whilst we get that. */
diff --git a/package/network/services/dnsmasq/patches/0002-PATCH-Fix-error-introduced-in-51471cafa5a4fa44d6fe49.patch b/package/network/services/dnsmasq/patches/0002-PATCH-Fix-error-introduced-in-51471cafa5a4fa44d6fe49.patch
deleted file mode 100644
index 5c50ae8446..0000000000
--- a/package/network/services/dnsmasq/patches/0002-PATCH-Fix-error-introduced-in-51471cafa5a4fa44d6fe49.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From ccff85ad72d2f858d9743d40525128e4f62d41a8 Mon Sep 17 00:00:00 2001
-From: renmingshuai <renmingshuai@huawei.com>
-Date: Wed, 21 Feb 2024 00:24:25 +0000
-Subject: [PATCH] Fix error introduced in
- 51471cafa5a4fa44d6fe490885d9910bd72a5907
-
-Signed-off-by: renmingshuai <renmingshuai@huawei.com>
----
- src/dnssec.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1547,7 +1547,7 @@ static int prove_non_existence_nsec3(str
- nsecs[i] = NULL; /* Speculative, will be restored if OK. */
-
- if (!(p = skip_name(nsec3p, header, plen, 15)))
-- return 0; /* bad packet */
-+ return DNSSEC_FAIL_BADPACKET; /* bad packet */
-
- p += 10; /* type, class, TTL, rdlen */
-
-@@ -1640,7 +1640,7 @@ static int prove_non_existence_nsec3(str
- if (!wildname)
- {
- if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
-- return 0;
-+ return DNSSEC_FAIL_NONSEC;
-
- wildcard--;
- *wildcard = '*';
diff --git a/package/network/services/dnsmasq/patches/0003-Handle-DS-queries-to-auth-zones.patch b/package/network/services/dnsmasq/patches/0003-Handle-DS-queries-to-auth-zones.patch
deleted file mode 100644
index bd7270c904..0000000000
--- a/package/network/services/dnsmasq/patches/0003-Handle-DS-queries-to-auth-zones.patch
+++ /dev/null
@@ -1,98 +0,0 @@
-From 8ce27433f8b2e17c557cb55e4f16941d309deeac Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Fri, 17 Jan 2025 17:49:29 +0000
-Subject: [PATCH] Handle DS queries to auth zones.
-Origin: upstream, v2.91test8
-
-When dnsmasq is configured to act as an authoritative server and has
-an authoritative zone configured, and recieves a query for
-that zone _as_forwarder_ it answers the query directly rather
-than forwarding it. This doesn't affect the answer, but it
-saves dnsmasq forwarding the query to the recusor upstream,
-whch then bounces it back to dnsmasq in auth mode. The
-exception should be when the query is for the root of zone, for a DS
-RR. The answer to that has to come from the parent, via the
-recursor, and will typically be a proof-of-nonexistence since
-dnsmasq doesn't support signed zones. This patch suppresses
-local answers and forces forwarding to the upstream recursor
-for such queries. It stops breakage when a DNSSEC validating
-client makes queries to dnsmasq acting as forwarder for a zone
-for which it is authoritative.
-
-[ukleinek: drop changes to CHANGELOG to prevent conflicts]
----
- src/forward.c | 52 +++++++++++++++++++++++++++++++++++++--------------
- 1 file changed, 38 insertions(+), 14 deletions(-)
-
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -1744,15 +1744,27 @@ void receive_query(struct listener *list
- #endif
-
- #ifdef HAVE_AUTH
-- /* find queries for zones we're authoritative for, and answer them directly */
-+ /* Find queries for zones we're authoritative for, and answer them directly.
-+ The exception to this is DS queries for the zone route. They
-+ have to come from the parent zone. Since dnsmasq's auth server
-+ can't do DNSSEC, the zone will be unsigned, and anything using
-+ dnsmasq as a forwarder and doing validation will be expecting to
-+ see the proof of non-existence from the parent. */
- if (!auth_dns && !option_bool(OPT_LOCALISE))
- for (zone = daemon->auth_zones; zone; zone = zone->next)
-- if (in_zone(zone, daemon->namebuff, NULL))
-- {
-- auth_dns = 1;
-- local_auth = 1;
-- break;
-- }
-+ {
-+ char *cut;
-+
-+ if (in_zone(zone, daemon->namebuff, &cut))
-+ {
-+ if (type != T_DS || cut)
-+ {
-+ auth_dns = 1;
-+ local_auth = 1;
-+ }
-+ break;
-+ }
-+ }
- #endif
-
- #ifdef HAVE_LOOP
-@@ -2268,15 +2280,27 @@ unsigned char *tcp_request(int confd, ti
- &peer_addr, auth_dns ? "auth" : "query", qtype);
-
- #ifdef HAVE_AUTH
-- /* find queries for zones we're authoritative for, and answer them directly */
-+ /* Find queries for zones we're authoritative for, and answer them directly.
-+ The exception to this is DS queries for the zone route. They
-+ have to come from the parent zone. Since dnsmasq's auth server
-+ can't do DNSSEC, the zone will be unsigned, and anything using
-+ dnsmasq as a forwarder and doing validation will be expecting to
-+ see the proof of non-existence from the parent. */
- if (!auth_dns && !option_bool(OPT_LOCALISE))
- for (zone = daemon->auth_zones; zone; zone = zone->next)
-- if (in_zone(zone, daemon->namebuff, NULL))
-- {
-- auth_dns = 1;
-- local_auth = 1;
-- break;
-- }
-+ {
-+ char *cut;
-+
-+ if (in_zone(zone, daemon->namebuff, &cut))
-+ {
-+ if (qtype != T_DS || cut)
-+ {
-+ auth_dns = 1;
-+ local_auth = 1;
-+ }
-+ break;
-+ }
-+ }
- #endif
- }
- }
diff --git a/package/network/services/dnsmasq/patches/001-CVE-2026-2291.patch b/package/network/services/dnsmasq/patches/001-CVE-2026-2291.patch
deleted file mode 100644
index 7e8c02a836..0000000000
--- a/package/network/services/dnsmasq/patches/001-CVE-2026-2291.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-commit ec2fbfbbdaa7d7db1c707dce26ce1a37cfe09660
-Author: Simon Kelley <simon@thekelleys.org.uk>
-Date: Fri Apr 10 16:29:31 2026 +0100
-
- Fix buffer overflow in struct bigname. CVE-2026-2291
-
- All buffers capable of holding a domain name should be
- at least MAXDNAME*2 + 1 bytes long, where MAXDNAME is the maximum
- size of a domain name. The accounts for the trailing zero and the
- fact that some characters are escaped in the internal representation
- of a domain name in dnsmasq.
-
- The declaration of struct bigname get this wrong, with the effect
- that a remote attacker capable of asking DNS queries or answering DNS
- queries can cause a large OOB write in the heap.
-
- This was first spotted by Andrew S. Fasano.
-
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -467,7 +467,7 @@ struct interface_name {
- };
-
- union bigname {
-- char name[MAXDNAME];
-+ char name[(2*MAXDNAME) + 1];
- union bigname *next; /* freelist */
- };
-
diff --git a/package/network/services/dnsmasq/patches/002-CVE-2026-4890.dnsmasq-2.91.patch b/package/network/services/dnsmasq/patches/002-CVE-2026-4890.dnsmasq-2.91.patch
deleted file mode 100644
index 9519d5ce94..0000000000
--- a/package/network/services/dnsmasq/patches/002-CVE-2026-4890.dnsmasq-2.91.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-commit de76f21e115c451cf0653790fc4b209cd4778a07
-Author: Simon Kelley <simon@thekelleys.org.uk>
-Date: Fri Apr 10 22:16:45 2026 +0100
-
- Fix NSEC bitmap parsing infinite loop. CVE-2026-4890
-
- Report from Royce M <royce@xchglabs.com>.
-
- Location: dnssec.c:1290-1306, dnssec.c:1450-1463
-
- The bitmap window iteration advances by p[1] instead of p[1]+2 (missing the 2-byte window header). With bitmap_length=0, both rdlen and p are
- unchanged, causing an infinite loop and dnsmasq stops responding to all queries.
-
- The same code accesses p[2] after only checking rdlen >= 2 without verifying p[1] >= 1, causing OOB reads at 6 locations.
-
- Both bugs are reachable before RRSIG validation (confirmed by the source comment at line 2125), so no valid DNSSEC signatures are needed.
-
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1270,10 +1270,10 @@ static int prove_non_existence_nsec(stru
- packet checked to be as long as rdlen implies in prove_non_existence() */
-
- /* If we can prove that there's no NS record, return that information. */
-- if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
-+ if (nons && rdlen >= 2 && p[0] == 0 && p[1] >= 1 && (p[2] & (0x80 >> T_NS)) != 0)
- *nons = 0;
-
-- if (rdlen >= 2 && p[0] == 0)
-+ if (rdlen >= 2 && p[0] == 0 && p[1] >= 1)
- {
- /* A CNAME answer would also be valid, so if there's a CNAME is should
- have been returned. */
-@@ -1301,8 +1301,8 @@ static int prove_non_existence_nsec(stru
- break; /* finished checking */
- }
-
-- rdlen -= p[1];
-- p += p[1];
-+ rdlen -= p[1] + 2;
-+ p += p[1] + 2;
- }
-
- return 0;
-@@ -1429,7 +1429,7 @@ static int check_nsec3_coverage(struct d
- p += hash_len; /* skip next-domain hash */
- rdlen -= p - psave;
-
-- if (rdlen >= 2 && p[0] == 0)
-+ if (rdlen >= 2 && p[0] == 0 && p[1] >= 1)
- {
- /* If we can prove that there's no NS record, return that information. */
- if (nons && (p[2] & (0x80 >> T_NS)) != 0)
-@@ -1458,8 +1458,8 @@ static int check_nsec3_coverage(struct d
- break; /* finished checking */
- }
-
-- rdlen -= p[1];
-- p += p[1];
-+ rdlen -= p[1] + 2;
-+ p += p[1] + 2;
- }
-
- return 1;
diff --git a/package/network/services/dnsmasq/patches/003-CVE-2026-4891.patch b/package/network/services/dnsmasq/patches/003-CVE-2026-4891.patch
deleted file mode 100644
index a4fdc36b0d..0000000000
--- a/package/network/services/dnsmasq/patches/003-CVE-2026-4891.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-commit 2cacea42e4d45717bd0ce3ccfe8e78960245e5da
-Author: Simon Kelley <simon@thekelleys.org.uk>
-Date: Wed Mar 25 23:04:08 2026 +0000
-
- Verify rdlen field in RRSIG packets. CVE-2026-4891
-
- Bug report from Royce M <royce@xchglabs.com>
-
- This avoids crafted packets which give a value for rdlen _less_
- then the space taken up by the fixed data and the signer's name
- and engender a negative calculated length for the signature.
-
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -546,10 +546,14 @@ static int validate_rrset(time_t now, st
-
- *ttl_out = ttl;
- }
--
-+
-+ /* Don't trust rdlen not to be too small and give us a negative sig_len
-+ It has already been checked that it doesn't run us off the end
-+ of the packet. */
-+ if ((sig_len = rdlen - (p - psav)) <= 0)
-+ return STAT_BOGUS;
-+
- sig = p;
-- sig_len = rdlen - (p - psav);
--
- nsigttl = htonl(orig_ttl);
-
- hash->update(ctx, 18, psav);
diff --git a/package/network/services/dnsmasq/patches/004-CVE-2026-4892.patch b/package/network/services/dnsmasq/patches/004-CVE-2026-4892.patch
deleted file mode 100644
index d51ce9510d..0000000000
--- a/package/network/services/dnsmasq/patches/004-CVE-2026-4892.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-commit 011a36c51438c986535a7248ed2e7f424f8e1078
-Author: Simon Kelley <simon@thekelleys.org.uk>
-Date: Wed Mar 25 23:16:35 2026 +0000
-
- Fix buffer overflow in helper.c with large CLIDs. CVE-2026-4892
-
- Bug reported bt Royce M <royce@xchglabs.com>
-
- Location: helper.c:265-270
- DHCPv6 CLIDs can be up to 65535 bytes. When --dhcp-script is configured,
- the helper hex-encodes raw CLID bytes via sprintf("%.2x") into daemon->packet (5131 bytes).
- A 1000-byte CLID writes ~3000 bytes. The helper process retains root privileges.
-
- Note: log6_packet() correctly caps CLID to 100 bytes for logging, but the helper code path was missed.
-
---- a/src/helper.c
-+++ b/src/helper.c
-@@ -261,8 +261,8 @@ int create_helper(int event_fd, int err_
- data.hostname_len + data.ed_len + data.clid_len, 1))
- continue;
-
-- /* CLID into packet */
-- for (p = daemon->packet, i = 0; i < data.clid_len; i++)
-+ /* CLID into packet: limit to 100 bytes to avoid overflowing buffer. */
-+ for (p = daemon->packet, i = 0; i < data.clid_len && i < 100; i++)
- {
- p += sprintf(p, "%.2x", buf[i]);
- if (i != data.clid_len - 1)
diff --git a/package/network/services/dnsmasq/patches/005-CVE-2026-4893.patch b/package/network/services/dnsmasq/patches/005-CVE-2026-4893.patch
deleted file mode 100644
index 83b1e5c193..0000000000
--- a/package/network/services/dnsmasq/patches/005-CVE-2026-4893.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-commit 434d68f2eb1a58744470698483a3ae09b5a9a870
-Author: Simon Kelley <simon@thekelleys.org.uk>
-Date: Wed Mar 25 23:22:37 2026 +0000
-
- Fix broken client subnet validation. CVE-2026-4893
-
- Bug report from Royce M <royce@xchglabs.com>
-
- Location: forward.c:713, edns0.c:421
-
- With --add-subnet enabled, process_reply() passes the OPT record
- length (~23 bytes) instead of the packet length to check_source().
- All internal bounds checks fail, and the function always returns 1.
- ECS source validation per RFC 7871 Section 9.2 is completely bypassed.
-
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -710,7 +710,7 @@ static size_t process_reply(struct dns_h
- /* Get extended RCODE. */
- rcode |= sizep[2] << 4;
-
-- if (option_bool(OPT_CLIENT_SUBNET) && !check_source(header, plen, pheader, query_source))
-+ if (option_bool(OPT_CLIENT_SUBNET) && !check_source(header, n, pheader, query_source))
- {
- my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
- return 0;
diff --git a/package/network/services/dnsmasq/patches/006-CVE-2026-5172.patch b/package/network/services/dnsmasq/patches/006-CVE-2026-5172.patch
deleted file mode 100644
index 4859f60d3d..0000000000
--- a/package/network/services/dnsmasq/patches/006-CVE-2026-5172.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-commit fa3c8ddef6712b52f562813317e6a997e1210123
-Author: Simon Kelley <simon@thekelleys.org.uk>
-Date: Mon Mar 30 16:24:33 2026 +0100
-
- Fix buffer overflow vulnerability in extract_addresses() CVE-2026-5172
-
- Thanks to Hugo Martinez Ray for spotting this.
-
- The value of rdlen for an RR can be a lie, allowing the
- call to extract_name() at rfc1025.c:952 to advance the value of p1
- past the calculated end of the record. The makes the calculation
- of bytes remaining in the RR underflow to a huge number and results
- in a massive heap OOB read and certain crash.
-
---- a/src/rfc1035.c
-+++ b/src/rfc1035.c
-@@ -932,7 +932,8 @@ int extract_addresses(struct dns_header
- /* Name, extract it then re-encode. */
- int len;
-
-- if (!extract_name(header, qlen, &p1, name, 1, 0))
-+ /* rdlen may lie, and extract_name() advances p1 past where it says the record ends. */
-+ if (!extract_name(header, qlen, &p1, name, 1, 0) || (p1 > endrr))
- {
- blockdata_free(addr.rrblock.rrdata);
- return 2;
diff --git a/package/network/services/dnsmasq/patches/100-remove-old-runtime-kernel-support.patch b/package/network/services/dnsmasq/patches/100-remove-old-runtime-kernel-support.patch
index 26c1b463b9..c2213439db 100644
--- a/package/network/services/dnsmasq/patches/100-remove-old-runtime-kernel-support.patch
+++ b/package/network/services/dnsmasq/patches/100-remove-old-runtime-kernel-support.patch
@@ -13,7 +13,7 @@ Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
-@@ -105,10 +105,6 @@ int main (int argc, char **argv)
+@@ -114,10 +114,6 @@ int main (int argc, char **argv)
read_opts(argc, argv, compile_opts);
@@ -26,7 +26,7 @@ Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
-@@ -1277,7 +1277,7 @@ extern struct daemon {
+@@ -1310,7 +1310,7 @@ extern struct daemon {
int inotifyfd;
#endif
#if defined(HAVE_LINUX_NETWORK)
@@ -35,7 +35,7 @@ Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
#elif defined(HAVE_BSD_NETWORK)
int dhcp_raw_fd, dhcp_icmp_fd, routefd;
#endif
-@@ -1491,9 +1491,6 @@ int read_write(int fd, unsigned char *pa
+@@ -1544,9 +1544,6 @@ int read_writev(int fd, struct iovec *io
void close_fds(long max_fd, int spare1, int spare2, int spare3);
int wildcard_match(const char* wildcard, const char* match);
int wildcard_matchn(const char* wildcard, const char* match, int num);
@@ -140,11 +140,10 @@ Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
my_syslog(LOG_ERR, _("failed to update ipset %s: %s"), setname, strerror(errno));
--- a/src/util.c
+++ b/src/util.c
-@@ -866,22 +866,3 @@ int wildcard_matchn(const char* wildcard
-
+@@ -928,25 +928,6 @@ int wildcard_matchn(const char* wildcard
return (!num) || (*wildcard == *match);
}
--
+
-#ifdef HAVE_LINUX_NETWORK
-int kernel_version(void)
-{
@@ -163,3 +162,7 @@ Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
- return version * 256 + (split ? atoi(split) : 0);
-}
-#endif
+-
+ #define hash_ptr(x) (((uintptr_t)(x)) & 0xffffff)
+
+ void *whine_malloc_real(const char *func, unsigned int line, size_t size)
diff --git a/package/network/services/dnsmasq/patches/200-ubus_dns.patch b/package/network/services/dnsmasq/patches/200-ubus_dns.patch
index 72acbaeba9..5abc641cae 100644
--- a/package/network/services/dnsmasq/patches/200-ubus_dns.patch
+++ b/package/network/services/dnsmasq/patches/200-ubus_dns.patch
@@ -1,19 +1,19 @@
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
-@@ -2021,6 +2021,10 @@ static void check_dns_listeners(time_t n
- daemon->pipe_to_parent = pipefd[1];
- }
+@@ -2184,6 +2184,10 @@ static void do_tcp_connection(struct lis
+ daemon->pipe_to_parent = pipefd[1];
+ }
+#ifdef HAVE_UBUS
-+ drop_ubus_listeners();
++ drop_ubus_listeners();
+#endif
+
- /* start with no upstream connections. */
- for (s = daemon->servers; s; s = s->next)
- s->tcpfd = -1;
+ /* The connected socket inherits non-blocking
+ attribute from the listening socket.
+ Reset that here. */
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
-@@ -1670,14 +1670,26 @@ void emit_dbus_signal(int action, struct
+@@ -1747,14 +1747,26 @@ void emit_dbus_signal(int action, struct
/* ubus.c */
#ifdef HAVE_UBUS
@@ -50,7 +50,7 @@
+ if ((daemon->doctors || ubus_dns_notify_has_subscribers()) && do_doctor(header, n, daemon->namebuff))
cache_secure = 0;
- /* check_for_bogus_wildcard() does it's own caching, so
+ /* check_for_bogus_wildcard() does its own caching, so
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -13,8 +13,10 @@
@@ -63,9 +63,9 @@
+#include <libubox/blobmsg.h>
+#endif
- int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
- char *name, int isExtract, int extrabytes)
-@@ -384,10 +386,65 @@ static int private_net6(struct in6_addr
+ /* EXTR_NAME_EXTRACT -> extract name
+ EXTR_NAME_COMPARE -> compare name, case insensitive
+@@ -452,10 +454,65 @@ int private_net6(struct in6_addr *a, int
((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
}
@@ -132,7 +132,7 @@
int done = 0;
if (!(p = skip_questions(header, qlen)))
-@@ -404,7 +461,7 @@ int do_doctor(struct dns_header *header,
+@@ -472,7 +529,7 @@ int do_doctor(struct dns_header *header,
GETSHORT(qtype, p);
GETSHORT(qclass, p);
@@ -141,7 +141,7 @@
GETSHORT(rdlen, p);
if (qclass == C_IN && qtype == T_A)
-@@ -415,6 +472,9 @@ int do_doctor(struct dns_header *header,
+@@ -483,6 +540,9 @@ int do_doctor(struct dns_header *header,
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
return done;
@@ -151,7 +151,7 @@
/* alignment */
memcpy(&addr.addr4, p, INADDRSZ);
-@@ -444,6 +504,14 @@ int do_doctor(struct dns_header *header,
+@@ -512,6 +572,14 @@ int do_doctor(struct dns_header *header,
break;
}
}
@@ -222,7 +222,7 @@
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
-@@ -328,6 +354,53 @@ fail:
+@@ -333,6 +359,53 @@ fail:
} \
} while (0)