Skip to content

Commit 306706f

Browse files
CBL-Mariner-Botakhila-gurujujslobodzian
authored
Merge PR "[AUTO-CHERRYPICK] [HIGH] Patch bind for CVE-2025-8677, CVE-2025-40778 and CVE-2025-40780 - branch main" microsoft#15080
Co-authored-by: Akhila Guruju <[email protected]> Co-authored-by: jslobodzian <[email protected]>
1 parent 1674d51 commit 306706f

File tree

4 files changed

+757
-1
lines changed

4 files changed

+757
-1
lines changed

SPECS/bind/CVE-2025-40778.patch

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
From 2ad57cbcedb3a8a4b7c387eafac769dcb6d4c1eb Mon Sep 17 00:00:00 2001
2+
From: akhila-guruju <[email protected]>
3+
Date: Tue, 28 Oct 2025 07:22:33 +0000
4+
Subject: [PATCH] Address CVE-2025-40778
5+
6+
Upstream Patch Reference: https://downloads.isc.org/isc/bind9/9.18.41/patches/0002-CVE-2025-40778.patch
7+
---
8+
lib/dns/include/dns/message.h | 8 +++
9+
lib/dns/message.c | 12 ++++
10+
lib/dns/resolver.c | 107 ++++++++++++++++++++++++++++------
11+
3 files changed, 108 insertions(+), 19 deletions(-)
12+
13+
diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h
14+
index ea45742..f564e1e 100644
15+
--- a/lib/dns/include/dns/message.h
16+
+++ b/lib/dns/include/dns/message.h
17+
@@ -235,6 +235,7 @@ struct dns_message {
18+
unsigned int cc_bad : 1;
19+
unsigned int tkey : 1;
20+
unsigned int rdclass_set : 1;
21+
+ unsigned int has_dname : 1;
22+
23+
unsigned int opt_reserved;
24+
unsigned int sig_reserved;
25+
@@ -1451,4 +1452,11 @@ dns_message_clonebuffer(dns_message_t *msg);
26+
* \li msg be a valid message.
27+
*/
28+
29+
+bool
30+
+dns_message_hasdname(dns_message_t *msg);
31+
+/*%<
32+
+ * Return whether a DNAME was detected in the ANSWER section of a QUERY
33+
+ * message when it was parsed.
34+
+ */
35+
+
36+
ISC_LANG_ENDDECLS
37+
diff --git a/lib/dns/message.c b/lib/dns/message.c
38+
index 12331ab..f29033a 100644
39+
--- a/lib/dns/message.c
40+
+++ b/lib/dns/message.c
41+
@@ -442,6 +442,7 @@ msginit(dns_message_t *m) {
42+
m->cc_bad = 0;
43+
m->tkey = 0;
44+
m->rdclass_set = 0;
45+
+ m->has_dname = 0;
46+
m->querytsig = NULL;
47+
m->indent.string = "\t";
48+
m->indent.count = 0;
49+
@@ -1727,6 +1728,11 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
50+
*/
51+
msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
52+
free_name = false;
53+
+ } else if (rdtype == dns_rdatatype_dname &&
54+
+ sectionid == DNS_SECTION_ANSWER &&
55+
+ msg->opcode == dns_opcode_query)
56+
+ {
57+
+ msg->has_dname = 1;
58+
}
59+
rdataset = NULL;
60+
61+
@@ -4770,3 +4776,9 @@ dns_message_clonebuffer(dns_message_t *msg) {
62+
msg->free_query = 1;
63+
}
64+
}
65+
+
66+
+bool
67+
+dns_message_hasdname(dns_message_t *msg) {
68+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
69+
+ return msg->has_dname;
70+
+}
71+
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
72+
index f0c60aa..9cf5645 100644
73+
--- a/lib/dns/resolver.c
74+
+++ b/lib/dns/resolver.c
75+
@@ -758,6 +758,7 @@ typedef struct respctx {
76+
bool get_nameservers; /* get a new NS rrset at
77+
* zone cut? */
78+
bool resend; /* resend this query? */
79+
+ bool secured; /* message was signed or had a valid cookie */
80+
bool nextitem; /* invalid response; keep
81+
* listening for the correct one */
82+
bool truncated; /* response was truncated */
83+
@@ -7154,7 +7155,8 @@ mark_related(dns_name_t *name, dns_rdataset_t *rdataset, bool external,
84+
* locally served zone.
85+
*/
86+
static bool
87+
-name_external(const dns_name_t *name, dns_rdatatype_t type, fetchctx_t *fctx) {
88+
+name_external(const dns_name_t *name, dns_rdatatype_t type, respctx_t *rctx) {
89+
+ fetchctx_t *fctx = rctx->fctx;
90+
isc_result_t result;
91+
dns_forwarders_t *forwarders = NULL;
92+
dns_fixedname_t fixed, zfixed;
93+
@@ -7167,7 +7169,7 @@ name_external(const dns_name_t *name, dns_rdatatype_t type, fetchctx_t *fctx) {
94+
dns_namereln_t rel;
95+
96+
apex = (ISDUALSTACK(fctx->addrinfo) || !ISFORWARDER(fctx->addrinfo))
97+
- ? &fctx->domain
98+
+ ? rctx->ns_name != NULL ? rctx->ns_name : &fctx->domain
99+
: fctx->fwdname;
100+
101+
/*
102+
@@ -7276,7 +7278,7 @@ check_section(void *arg, const dns_name_t *addname, dns_rdatatype_t type,
103+
result = dns_message_findname(rctx->query->rmessage, section, addname,
104+
dns_rdatatype_any, 0, &name, NULL);
105+
if (result == ISC_R_SUCCESS) {
106+
- external = name_external(name, type, fctx);
107+
+ external = name_external(name, type, rctx);
108+
if (type == dns_rdatatype_a) {
109+
for (rdataset = ISC_LIST_HEAD(name->list);
110+
rdataset != NULL;
111+
@@ -7888,6 +7890,47 @@ betterreferral(respctx_t *rctx) {
112+
return (false);
113+
}
114+
115+
+static bool
116+
+rctx_need_tcpretry(respctx_t *rctx) {
117+
+ resquery_t *query = rctx->query;
118+
+ if ((rctx->retryopts & DNS_FETCHOPT_TCP) != 0) {
119+
+ /* TCP is already in the retry flags */
120+
+ return false;
121+
+ }
122+
+
123+
+ /*
124+
+ * If the message was secured, no need to continue.
125+
+ */
126+
+ if (rctx->secured) {
127+
+ return false;
128+
+ }
129+
+
130+
+ /*
131+
+ * Currently the only extra reason why we might need to
132+
+ * retry a UDP response over TCP is a DNAME in the message.
133+
+ */
134+
+ if (dns_message_hasdname(query->rmessage)) {
135+
+ return true;
136+
+ }
137+
+
138+
+ return false;
139+
+}
140+
+
141+
+static isc_result_t
142+
+rctx_tcpretry(respctx_t *rctx) {
143+
+ /*
144+
+ * Do we need to retry a UDP response over TCP?
145+
+ */
146+
+ if (rctx_need_tcpretry(rctx)) {
147+
+ rctx->retryopts |= DNS_FETCHOPT_TCP;
148+
+ rctx->resend = true;
149+
+ rctx_done(rctx, ISC_R_SUCCESS);
150+
+ return ISC_R_COMPLETE;
151+
+ }
152+
+
153+
+ return ISC_R_SUCCESS;
154+
+}
155+
+
156+
/*
157+
* resquery_response():
158+
* Handles responses received in response to iterative queries sent by
159+
@@ -8062,6 +8105,17 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
160+
return;
161+
}
162+
163+
+ /*
164+
+ * Remember whether this message was signed or had a
165+
+ * valid client cookie; if not, we may need to retry over
166+
+ * TCP later.
167+
+ */
168+
+ if (query->rmessage->cc_ok || query->rmessage->tsig != NULL ||
169+
+ query->rmessage->sig0 != NULL)
170+
+ {
171+
+ rctx.secured = true;
172+
+ }
173+
+
174+
/*
175+
* The dispatcher should ensure we only get responses with QR set.
176+
*/
177+
@@ -8079,10 +8133,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
178+
* This may be a misconfigured anycast server or an attempt to send
179+
* a spoofed response. Skip if we have a valid tsig.
180+
*/
181+
- if (dns_message_gettsig(query->rmessage, NULL) == NULL &&
182+
- !query->rmessage->cc_ok && !query->rmessage->cc_bad &&
183+
- (rctx.retryopts & DNS_FETCHOPT_TCP) == 0)
184+
- {
185+
+ if (!rctx.secured && (rctx.retryopts & DNS_FETCHOPT_TCP) == 0) {
186+
unsigned char cookie[COOKIE_BUFFER_SIZE];
187+
if (dns_adb_getcookie(fctx->adb, query->addrinfo, cookie,
188+
sizeof(cookie)) > CLIENT_COOKIE_SIZE)
189+
@@ -8108,6 +8159,17 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
190+
*/
191+
}
192+
193+
+ /*
194+
+ * Check whether we need to retry over TCP for some other reason.
195+
+ */
196+
+ result = rctx_tcpretry(&rctx);
197+
+ if (result == ISC_R_COMPLETE) {
198+
+ return;
199+
+ }
200+
+
201+
+ /*
202+
+ * Check for EDNS issues.
203+
+ */
204+
rctx_edns(&rctx);
205+
206+
/*
207+
@@ -8836,8 +8898,8 @@ rctx_answer_positive(respctx_t *rctx) {
208+
}
209+
210+
/*
211+
- * Cache records in the authority section, if
212+
- * there are any suitable for caching.
213+
+ * Cache records in the authority section, if there are
214+
+ * any suitable for caching.
215+
*/
216+
rctx_authority_positive(rctx);
217+
218+
@@ -8909,7 +8971,7 @@ rctx_answer_scan(respctx_t *rctx) {
219+
/*
220+
* Don't accept DNAME from parent namespace.
221+
*/
222+
- if (name_external(name, dns_rdatatype_dname, fctx)) {
223+
+ if (name_external(name, dns_rdatatype_dname, rctx)) {
224+
continue;
225+
}
226+
227+
@@ -9208,14 +9270,14 @@ rctx_answer_dname(respctx_t *rctx) {
228+
229+
/*
230+
* rctx_authority_positive():
231+
- * Examine the records in the authority section (if there are any) for a
232+
- * positive answer. We expect the names for all rdatasets in this section
233+
- * to be subdomains of the domain being queried; any that are not are
234+
- * skipped. We expect to find only *one* owner name; any names
235+
- * after the first one processed are ignored. We expect to find only
236+
- * rdatasets of type NS, RRSIG, or SIG; all others are ignored. Whatever
237+
- * remains can be cached at trust level authauthority or additional
238+
- * (depending on whether the AA bit was set on the answer).
239+
+ * If a positive answer was received over TCP or secured with a cookie
240+
+ * or TSIG, examine the authority section. We expect names for all
241+
+ * rdatasets in this section to be subdomains of the domain being queried;
242+
+ * any that are not are skipped. We expect to find only *one* owner name;
243+
+ * any names after the first one processed are ignored. We expect to find
244+
+ * only rdatasets of type NS; all others are ignored. Whatever remains can
245+
+ * be cached at trust level authauthority or additional (depending on
246+
+ * whether the AA bit was set on the answer).
247+
*/
248+
static void
249+
rctx_authority_positive(respctx_t *rctx) {
250+
@@ -9223,6 +9285,11 @@ rctx_authority_positive(respctx_t *rctx) {
251+
bool done = false;
252+
isc_result_t result;
253+
254+
+ /* If it's spoofable, don't cache it. */
255+
+ if (!rctx->secured && (rctx->query->options & DNS_FETCHOPT_TCP) == 0) {
256+
+ return;
257+
+ }
258+
+
259+
result = dns_message_firstname(rctx->query->rmessage,
260+
DNS_SECTION_AUTHORITY);
261+
while (!done && result == ISC_R_SUCCESS) {
262+
@@ -9231,7 +9298,9 @@ rctx_authority_positive(respctx_t *rctx) {
263+
dns_message_currentname(rctx->query->rmessage,
264+
DNS_SECTION_AUTHORITY, &name);
265+
266+
- if (!name_external(name, dns_rdatatype_ns, fctx)) {
267+
+ if (!name_external(name, dns_rdatatype_ns, rctx) &&
268+
+ dns_name_issubdomain(&fctx->name, name))
269+
+ {
270+
dns_rdataset_t *rdataset = NULL;
271+
272+
/*
273+
--
274+
2.43.0
275+

0 commit comments

Comments
 (0)