From 1d62ca52b7beeb128d22d946d98df7b2fe6efad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= Date: Wed, 18 Mar 2026 19:40:19 +0100 Subject: [PATCH] Fix improper validated wire format of DNS name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure extract_name stops whenever name is longer than 255 bytes. That is defined by RFC 1035 and MAXDNAME is derived from that length. Dnsmasq until now relied on upstream servers filtering similar responses to be filtered out. Stop immediately if the packet is big enough, but binary name length exceeds 255 bytes. That is prerequisite for escaped name to become longer than existing buffer long MAXDNAME. Introduce new MAXWNAME constant for on-wire length limit. MAXDNAME remains escaped "presentation" format limit, possibly containing IDN or escaping. Standard escaping is \ddd, where ddd are decadic value of that byte. Such escaping is not implemented by dnsmasq. MAXDNAME should be large enough for any escaped names as long as MAXWNAME cannot exceed defined length. Signed-off-by: Petr Menšík Resolves-Vulnerability: CVE-2026-2291 Resolves: RHEL-181040 --- dnsmasq-CVE-2026-2291.patch | 95 +++++++++++++++++++++++++++++++++++++ dnsmasq.spec | 9 +++- 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 dnsmasq-CVE-2026-2291.patch diff --git a/dnsmasq-CVE-2026-2291.patch b/dnsmasq-CVE-2026-2291.patch new file mode 100644 index 0000000..92a6f7b --- /dev/null +++ b/dnsmasq-CVE-2026-2291.patch @@ -0,0 +1,95 @@ +From 74b2a7d33baa96761c14433671916c1c153d6017 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Tue, 24 Feb 2026 20:36:04 +0100 +Subject: [PATCH] Fix improper validated wire format of DNS name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Ensure extract_name stops whenever name is longer than 255 bytes. That +is defined by RFC 1035 and MAXDNAME is derived from that length. Dnsmasq +until now relied on upstream servers filtering similar responses to be +filtered out. + +Stop immediately if the packet is big enough, but binary name length +exceeds 255 bytes. That is prerequisite for escaped name to become +longer than existing buffer long MAXDNAME. Introduce new MAXWNAME +constant for on-wire length limit. MAXDNAME remains escaped +"presentation" format limit, possibly containing IDN or escaping. +Standard escaping is \ddd, where ddd are decadic value of that byte. +Such escaping is not implemented by dnsmasq. MAXDNAME should be large +enough for any escaped names as long as MAXWNAME cannot exceed defined +length. + +Signed-off-by: Petr Menšík +--- + src/dns-protocol.h | 1 + + src/rfc1035.c | 2 +- + src/rrfilter.c | 14 ++++++++++---- + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/src/dns-protocol.h b/src/dns-protocol.h +index e71bedc4..8103b558 100644 +--- a/src/dns-protocol.h ++++ b/src/dns-protocol.h +@@ -23,6 +23,7 @@ + #define INADDRSZ 4 + + #define PACKETSZ 512 /* maximum packet size */ ++#define MAXWNAME 255 /* maximum on-wire domain name */ + #define MAXDNAME 1025 /* maximum presentation domain name */ + #define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ + #define MAXLABEL 63 /* maximum length of domain label */ +diff --git a/src/rfc1035.c b/src/rfc1035.c +index f0e10822..bea30380 100644 +--- a/src/rfc1035.c ++++ b/src/rfc1035.c +@@ -109,7 +109,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, + else if (label_type == 0x00) + { /* label_type = 0 -> label. */ + namelen += l + 1; /* include period */ +- if (namelen >= MAXDNAME) ++ if (namelen > MAXWNAME) + return 0; + if (!CHECK_LEN(header, p, plen, l)) + return 0; +diff --git a/src/rrfilter.c b/src/rrfilter.c +index 29f69c74..b8093cf5 100644 +--- a/src/rrfilter.c ++++ b/src/rrfilter.c +@@ -23,6 +23,7 @@ + static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count) + { + unsigned char *ansp = *namep; ++ unsigned int namelen = 0; + + while(1) + { +@@ -84,15 +85,20 @@ static int check_name(unsigned char **namep, struct dns_header *header, size_t p + count = *(ansp++); /* Bits in bitstring */ + + if (count == 0) /* count == 0 means 256 bits */ +- ansp += 32; ++ count = 32; + else +- ansp += ((count-1)>>3)+1; ++ count = ((count-1)>>3)+1; ++ namelen += count + 1; ++ if (namelen > MAXWNAME) ++ return 0; ++ ansp += count; + } + else + { /* label type == 0 Bottom six bits is length */ + unsigned int len = (*ansp++) & 0x3f; +- +- if (!ADD_RDLEN(header, ansp, plen, len)) ++ ++ namelen += len + 1; ++ if (!ADD_RDLEN(header, ansp, plen, len) || namelen > MAXWNAME) + return 0; + + if (len == 0) +-- +2.53.0 + diff --git a/dnsmasq.spec b/dnsmasq.spec index 04ce743..a84fa3c 100644 --- a/dnsmasq.spec +++ b/dnsmasq.spec @@ -20,7 +20,7 @@ Name: dnsmasq Version: 2.85 -Release: 19%{?extraversion:.%{extraversion}}%{?dist} +Release: 20%{?extraversion:.%{extraversion}}%{?dist} Summary: A lightweight DHCP/caching DNS server License: GPLv2 or GPLv3 @@ -84,6 +84,10 @@ Patch21: dnsmasq-2.93-CVE-2026-4890.patch Patch22: dnsmasq-2.93-CVE-2026-4891.patch Patch23: dnsmasq-2.93-CVE-2026-4892.patch Patch24: dnsmasq-2.93-CVE-2026-4893.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2439088 +# downstream addition to upstream fix +Patch25: dnsmasq-CVE-2026-2291.patch + # This is workaround to nettle bug #1549190 # https://bugzilla.redhat.com/show_bug.cgi?id=1549190 @@ -231,6 +235,9 @@ install -Dpm 644 %{SOURCE5} %{buildroot}%{_tmpfilesdir}/%{name}.conf %{_mandir}/man1/dhcp_* %changelog +* Fri Jun 05 2026 Petr Menšík - 2.85-20 +- Prevent using too long names in downstream change (CVE-2026-2291) + * Tue May 05 2026 Petr Menšík - 2.85-19 - Prevent overflow in extract_name function (CVE-2026-2291) - Prevent DoS in DNSSEC validation (CVE-2026-4890)