Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package dnsmasq for openSUSE:Factory checked in at 2026-11-04 19:42:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/dnsmasq (Old) and /work/SRC/openSUSE:Factory/.dnsmasq.new.3759290 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "dnsmasq" Wed Nov 4 19:42:25 2026 rev:109 rq:1394549 version:2.93 Changes: -------- --- /work/SRC/openSUSE:Factory/dnsmasq/dnsmasq.changes 2026-07-02 20:07:34.189464629 +0200 +++ /work/SRC/openSUSE:Factory/.dnsmasq.new.3759290/dnsmasq.changes 2026-11-04 19:42:29.007935968 +0100 @@ -1,0 +2,19 @@ +Fri Oct 30 14:50:00 UTC 2026 - Reinhard Max <[email protected]> + +- Add upstream security fixes: + * CVE-2026-93006, bsc#1288828: TFTP server can serve the wrong + file contents because a recently used transfer cache is not + invalidated when a transfer finishes + (dnsmasq-CVE-2026-93006.patch). + * CVE-2026-93007, bsc#1288829: TCP DNS service uses a small fixed + pool of child processes and does not set a receive timeout on + client connections (dnsmasq-CVE-2026-93007.patch, partial fix). + * CVE-2026-93008, bsc#1288830: Records for the CNAME target were + cached without checking that they belong to the responding + server's zone (dnsmasq-CVE-2026-93008.patch). + * CVE-2026-93009, bsc#1288831: Out-of-bounds read in the DHCPv6 + FQDN option parser (dnsmasq-CVE-2026-93009.patch). + * CVE-2026-93011, bsc#1288833: One-byte heap overflow of a name + buffer in the DNSSEC validator (dnsmasq-CVE-2026-93011.patch). + +------------------------------------------------------------------- New: ---- dnsmasq-CVE-2026-93006.patch dnsmasq-CVE-2026-93007.patch dnsmasq-CVE-2026-93008.patch dnsmasq-CVE-2026-93009.patch dnsmasq-CVE-2026-93011.patch ----------(New B)---------- New: invalidated when a transfer finishes (dnsmasq-CVE-2026-93006.patch). * CVE-2026-93007, bsc#1288829: TCP DNS service uses a small fixed New: pool of child processes and does not set a receive timeout on client connections (dnsmasq-CVE-2026-93007.patch, partial fix). * CVE-2026-93008, bsc#1288830: Records for the CNAME target were New: cached without checking that they belong to the responding server's zone (dnsmasq-CVE-2026-93008.patch). * CVE-2026-93009, bsc#1288831: Out-of-bounds read in the DHCPv6 New: * CVE-2026-93009, bsc#1288831: Out-of-bounds read in the DHCPv6 FQDN option parser (dnsmasq-CVE-2026-93009.patch). * CVE-2026-93011, bsc#1288833: One-byte heap overflow of a name New: * CVE-2026-93011, bsc#1288833: One-byte heap overflow of a name buffer in the DNSSEC validator (dnsmasq-CVE-2026-93011.patch). ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ dnsmasq.spec ++++++ --- /var/tmp/diff_new_pack.HGYm2t/_old 2026-11-04 19:42:30.323991056 +0100 +++ /var/tmp/diff_new_pack.HGYm2t/_new 2026-11-04 19:42:30.325991140 +0100 @@ -40,6 +40,11 @@ Source5: rc.dnsmasq-suse Source6: system-user-dnsmasq.conf Patch0: dnsmasq-groups.patch +Patch1: dnsmasq-CVE-2026-93006.patch +Patch2: dnsmasq-CVE-2026-93007.patch +Patch3: dnsmasq-CVE-2026-93008.patch +Patch4: dnsmasq-CVE-2026-93009.patch +Patch5: dnsmasq-CVE-2026-93011.patch BuildRequires: dbus-1-devel BuildRequires: dos2unix BuildRequires: libnettle-devel @@ -78,7 +83,9 @@ server's leases. %prep -%autosetup -p0 +%autosetup -N +%autopatch -p0 -M 0 +%autopatch -p1 -m 1 # Remove the executable bit from python example files to # avoid unwanted automatic dependencies ++++++ dnsmasq-CVE-2026-93006.patch ++++++ >From cdbfb972276ca3d07bec9246f57be8cd7c7d5478 Mon Sep 17 00:00:00 2001 From: Simon Kelley <[email protected]> Date: Fri, 16 Oct 2026 22:33:51 +0100 Subject: [PATCH] Fix logic error in TFTP caching. The TFTP subsystem prefetches data from disk. If a TFTP transfer is freed, and a new one allocated the same memory, then previously prefetched data could be wrongly supplied. Thanks to Lucas Celant <[email protected]> for spotting this. CVE-2026-93006 may apply. --- src/tftp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tftp.c b/src/tftp.c index 6d5d56d..da8a9ff 100644 --- a/src/tftp.c +++ b/src/tftp.c @@ -836,6 +836,12 @@ static void free_transfer(struct tftp_transfer *transfer) close(transfer->file->fd); free(transfer->file); } + + /* freeing this transfer and then allocating a new one + may result in the same memory, but the contents of + the transfer is no longer valid to cache. */ + if (daemon->srv_save == transfer) + daemon->srv_save = NULL; free(transfer); } -- 2.56.0 ++++++ dnsmasq-CVE-2026-93007.patch ++++++ >From 11493fe2186f837aeda74e8bf7fae8b92773a498 Mon Sep 17 00:00:00 2001 From: Simon Kelley <[email protected]> Date: Fri, 16 Oct 2026 20:58:00 +0100 Subject: [PATCH] Improve resistance to many simultaneous TCP connections. Dnsmasq limits the number of simultaneous TCP connections, to avoid resource-exhaustion attacks. Once the limit if reached, dnsmasq stops accepting TCP connections from the kernel. When doing dnssec validation, the same resources are used to handle internally generated queries with large answers needed to validate incoming queries which can still arrive via UDP. If a dnsmasq daemon has reached the limit on incoming TCP connections then these queries will fail to validate needlessly. Bump the number of TCP-process resources by 50% when dnssec validation is enabled, and reserve the extra 50% only for internally-generated dnssec validation queries. This allows validation to continue even when dnsmasq is ignoring new TCP requests. Thanks to Lucas Celant <[email protected]> for spotting this. CVE-2026-93007 may apply. --- src/dnsmasq.c | 33 ++++++++++++++++++++++++--------- src/dnsmasq.h | 3 ++- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/dnsmasq.c b/src/dnsmasq.c index adaa692..3337e01 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -140,6 +140,9 @@ int main (int argc, char **argv) /* one char flag per possible RR in answer section (may get extended). */ daemon->rr_status_sz = 64; daemon->rr_status = safe_malloc(sizeof(*daemon->rr_status) * daemon->rr_status_sz); + /* Increase TCP process slots by half, and reserve the extra for validation-to-tcp use only. */ + daemon->dnssec_tcp_slot_reserved = daemon->max_procs/2; + daemon->max_procs += daemon->dnssec_tcp_slot_reserved; } #endif @@ -427,7 +430,8 @@ int main (int argc, char **argv) daemon->tcp_pids = safe_malloc(daemon->max_procs*sizeof(pid_t)); daemon->tcp_pipes = safe_malloc(daemon->max_procs*sizeof(int)); - + daemon->tcp_type = safe_malloc(daemon->max_procs); + for (i = 0; i < daemon->max_procs; i++) daemon->tcp_pipes[i] = -1; } @@ -1652,7 +1656,11 @@ static void async_event(int pipe, time_t now) /* tcp_pipes == -1 && tcp_pids == 0 required to free slot */ if (daemon->tcp_pipes[i] == -1) - daemon->metrics[METRIC_TCP_CONNECTIONS]--; + { + if (daemon->tcp_type[i]) + daemon->dnssec_tcp_slot_reserved++; + daemon->metrics[METRIC_TCP_CONNECTIONS]--; + } } break; @@ -1888,7 +1896,7 @@ static void set_dns_listeners(void) struct serverfd *serverfdp; struct listener *listener; struct randfd_list *rfl; - int i; + int i, j; for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) poll_listen(serverfdp->fd, POLLIN); @@ -1902,8 +1910,8 @@ static void set_dns_listeners(void) poll_listen(rfl->rfd->fd, POLLIN); /* check to see if we have free tcp process slots. */ - for (i = daemon->max_procs - 1; i >= 0; i--) - if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1) + for (j = 0, i = daemon->max_procs - 1; i >= 0; i--) + if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1 && ++j > daemon->dnssec_tcp_slot_reserved) break; for (listener = daemon->listeners; listener; listener = listener->next) @@ -1930,7 +1938,7 @@ static void check_dns_listeners(time_t now) struct serverfd *serverfdp; struct listener *listener; struct randfd_list *rfl; - int i; + int i, j; /* Note that handling events here can create or destroy fds and render the result of the last poll() call invalid. Once @@ -1955,7 +1963,11 @@ static void check_dns_listeners(time_t now) daemon->tcp_pipes[i] = -1; /* tcp_pipes == -1 && tcp_pids == 0 required to free slot */ if (daemon->tcp_pids[i] == 0) - daemon->metrics[METRIC_TCP_CONNECTIONS]--; + { + daemon->metrics[METRIC_TCP_CONNECTIONS]--; + if (daemon->tcp_type[i]) + daemon->dnssec_tcp_slot_reserved++; + } } return; } @@ -1995,8 +2007,8 @@ static void check_dns_listeners(time_t now) at least one a poll() time, that we still do. There may be more waiting connections after poll() returns then free process slots. */ - for (i = daemon->max_procs - 1; i >= 0; i--) - if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1) + for (j = 0,i = daemon->max_procs - 1; i >= 0; i--) + if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1 && ++j > daemon->dnssec_tcp_slot_reserved) break; if (i >= 0) @@ -2159,6 +2171,7 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot) daemon->tcp_pids[slot] = p; daemon->tcp_pipes[slot] = pipefd[0]; + daemon->tcp_type[slot] = 0; daemon->metrics[METRIC_TCP_CONNECTIONS]++; if (daemon->metrics[METRIC_TCP_CONNECTIONS] > daemon->max_procs_used) daemon->max_procs_used = daemon->metrics[METRIC_TCP_CONNECTIONS]; @@ -2280,6 +2293,8 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header /* i holds index of free slot */ daemon->tcp_pids[i] = p; daemon->tcp_pipes[i] = pipefd[0]; + daemon->tcp_type[i] = 1; + daemon->dnssec_tcp_slot_reserved--; daemon->metrics[METRIC_TCP_CONNECTIONS]++; if (daemon->metrics[METRIC_TCP_CONNECTIONS] > daemon->max_procs_used) daemon->max_procs_used = daemon->metrics[METRIC_TCP_CONNECTIONS]; diff --git a/src/dnsmasq.h b/src/dnsmasq.h index ebb8d15..cad57dd 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1295,6 +1295,7 @@ extern struct daemon { int fd_save; /* " " */ pid_t *tcp_pids; int *tcp_pipes; + char *tcp_type; int pipe_to_parent; int numrrand; struct randfd *randomsocks; @@ -1354,7 +1355,7 @@ extern struct daemon { /* file for packet dumps. */ int dumpfd; #endif - int max_procs; + int max_procs, dnssec_tcp_slot_reserved; uint max_procs_used; } *daemon; -- 2.56.0 ++++++ dnsmasq-CVE-2026-93008.patch ++++++ >From 7719737f3687a2e8e98d8ede31e4f1a006f2deea Mon Sep 17 00:00:00 2001 From: Simon Kelley <[email protected]> Date: Fri, 16 Oct 2026 15:22:23 +0100 Subject: [PATCH] Fix subdomain-test in find_soa() Do correct subdomain test, rather than a substring match. Thanks to Lucas Celant <[email protected]> for spotting this. CVE-2026-93008 may apply. --- src/rfc1035.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rfc1035.c b/src/rfc1035.c index 16df1b1..bdb0104 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -560,7 +560,7 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *sub soa_len = strlen(daemon->workspacename); /* SOA must be for the name we're interested in. */ - if (soa_len <= name_len && memcmp(daemon->workspacename, name + name_len - soa_len, soa_len) == 0) + if (hostname_issubdomain(daemon->workspacename, name) != 0) { int prefix = name_len - soa_len; -- 2.56.0 ++++++ dnsmasq-CVE-2026-93009.patch ++++++ >From a627a7847ffa50eefedfe8cf842522a2c12e36c4 Mon Sep 17 00:00:00 2001 From: Simon Kelley <[email protected]> Date: Fri, 16 Oct 2026 23:04:00 +0100 Subject: [PATCH] Fix off-by-one bounds check in DHCPv6 FQDN option. Thanks to Lucas Celant <[email protected]> for spotting this. CVE-2026-93009 may apply. --- src/rfc3315.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rfc3315.c b/src/rfc3315.c index 2ac6f86..119be52 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -502,7 +502,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu state->fqdn_flags &= ~0x04; - if (len != 0 && len < 255) + if (len >= 1 && len < 255) { unsigned char *pp, *op = opt6_ptr(opt, 1); char *pq = daemon->dhcp_buff; -- 2.56.0 ++++++ dnsmasq-CVE-2026-93011.patch ++++++ >From 145abca7f62a7744fb9aa742ac71e1c10af4cda7 Mon Sep 17 00:00:00 2001 From: Simon Kelley <[email protected]> Date: Sat, 17 Oct 2026 01:05:16 +0100 Subject: [PATCH] Fix DNS name buffer overflow. There are a couple of instances in the DNSSEC validation code where the code steps along a DNS name to remove some number if left-hand labels and replace them with * to make a wildcard. The name then gets passed to to_wire() to translate it in-place to the wire format. If external parameters dictate that all the labels are removed, and the name is of exactly the maximum size, then this causes to_wire() to overwrite the buffer by one byte. Having created the wildcard, move it to the start of the buffer to avoid this problem. Thanks to Lucas Celant <[email protected]> for spotting this. CVE-2026-93011 may apply. --- src/dnssec.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/dnssec.c b/src/dnssec.c index 71c9bac..2102597 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -486,7 +486,6 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in int i, wire_len, sig_len; const struct nettle_hash *hash; void *ctx; - char *name_start; u32 nsigttl, ttl, orig_ttl; failflags &= ~DNSSEC_FAIL_NOSIG; @@ -576,13 +575,13 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in if (!extract_name(header, plen, &p, name, EXTR_NAME_EXTRACT, 10)) return STAT_BOGUS; - name_start = name; - /* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */ /* If the name is already the wildcard, we're not going to change it. */ if (labels < name_labels && - !(name_labels - labels == 1 && name_start[0] == '*' && name_start[1] == '.')) + !(name_labels - labels == 1 && name[0] == '*' && name[1] == '.')) { + char *name_start = name; + for (j = name_labels - labels; j != 0; j--) { while (*name_start != '.' && *name_start != 0) @@ -595,11 +594,13 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in *wildcard_offset_out = name_start - name + 1; name_start--; - *name_start = '*'; + *name_start = '*'; + /* move our name to the start of the buffer to avoid pathalogical cases over-running the end in to_wire(). */ + memmove(name, name_start, strlen(name_start) + 1); } - - wire_len = to_wire(name_start); - hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start); + + wire_len = to_wire(name); + hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name); hash->update(ctx, 4, p); /* class and type */ hash->update(ctx, 4, (unsigned char *)&nsigttl); @@ -1687,11 +1688,13 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns wildcard--; *wildcard = '*'; + /* move our name to the start of the buffer to avoid pathalogical cases over-running the end in to_wire(). */ + memmove(name, wildcard, strlen(wildcard) + 1); if (dec_counter(validate_counter, NULL)) return DNSSEC_FAIL_WORK; - if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0) + if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0) return DNSSEC_FAIL_NONSEC; if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1)) -- 2.56.0
