summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta-networking/recipes-support/unbound/unbound/CVE-2025-5994.patch275
-rw-r--r--meta-networking/recipes-support/unbound/unbound_1.19.3.bb1
2 files changed, 276 insertions, 0 deletions
diff --git a/meta-networking/recipes-support/unbound/unbound/CVE-2025-5994.patch b/meta-networking/recipes-support/unbound/unbound/CVE-2025-5994.patch
new file mode 100644
index 0000000000..b6c0e37e43
--- /dev/null
+++ b/meta-networking/recipes-support/unbound/unbound/CVE-2025-5994.patch
@@ -0,0 +1,275 @@
1Backport of:
2
3From 5bf82f246481098a6473f296b21fc1229d276c0f Mon Sep 17 00:00:00 2001
4From: "W.C.A. Wijngaards" <wouter@nlnetlabs.nl>
5Date: Wed, 16 Jul 2025 10:02:01 +0200
6Subject: [PATCH] - Fix RebirthDay Attack CVE-2025-5994, reported by Xiang Li
7 from AOSP Lab Nankai University.
8
9CVE: CVE-2025-5994
10Upstream-Status: Backport [https://github.com/NLnetLabs/unbound/commit/5bf82f246481098a6473f296b21fc1229d276c0f]
11Signed-off-by: Naman Jain <namanj1@kpit.com>
12
13---
14 edns-subnet/subnetmod.c | 152 ++++++++++++++++++++++++++++++++++++----
15 edns-subnet/subnetmod.h | 4 ++
16 2 files changed, 142 insertions(+), 14 deletions(-)
17
18--- a/edns-subnet/subnetmod.c
19+++ b/edns-subnet/subnetmod.c
20@@ -51,6 +51,7 @@
21 #include "services/cache/dns.h"
22 #include "util/module.h"
23 #include "util/regional.h"
24+#include "util/fptr_wlist.h"
25 #include "util/storage/slabhash.h"
26 #include "util/config_file.h"
27 #include "util/data/msgreply.h"
28@@ -152,7 +153,8 @@ int ecs_whitelist_check(struct query_inf
29
30 /* Cache by default, might be disabled after parsing EDNS option
31 * received from nameserver. */
32- if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL)) {
33+ if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL)
34+ && sq->ecs_client_in.subnet_validdata) {
35 qstate->no_cache_store = 0;
36 }
37
38@@ -504,6 +506,69 @@ common_prefix(uint8_t *a, uint8_t *b, ui
39 return !memcmp(a, b, n) && ((net % 8) == 0 || a[n] == b[n]);
40 }
41
42+/**
43+ * Create sub request that looks up the query.
44+ * @param qstate: query state
45+ * @param sq: subnet qstate
46+ * @return false on failure.
47+ */
48+static int
49+generate_sub_request(struct module_qstate *qstate, struct subnet_qstate* sq)
50+{
51+ struct module_qstate* subq = NULL;
52+ uint16_t qflags = 0; /* OPCODE QUERY, no flags */
53+ int prime = 0;
54+ int valrec = 0;
55+ struct query_info qinf;
56+ qinf.qname = qstate->qinfo.qname;
57+ qinf.qname_len = qstate->qinfo.qname_len;
58+ qinf.qtype = qstate->qinfo.qtype;
59+ qinf.qclass = qstate->qinfo.qclass;
60+ qinf.local_alias = NULL;
61+
62+ qflags |= BIT_RD;
63+ if((qstate->query_flags & BIT_CD)!=0) {
64+ qflags |= BIT_CD;
65+ valrec = 1;
66+ }
67+
68+ fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
69+ if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, valrec,
70+ &subq)) {
71+ return 0;
72+ }
73+ if(subq) {
74+ /* It is possible to access the subquery module state. */
75+ if(sq->ecs_client_in.subnet_source_mask == 0 &&
76+ edns_opt_list_find(qstate->edns_opts_front_in,
77+ qstate->env->cfg->client_subnet_opcode)) {
78+ subq->no_cache_store = 1;
79+ }
80+ }
81+ return 1;
82+}
83+
84+/**
85+ * Perform the query without subnet
86+ * @param qstate: query state
87+ * @param sq: subnet qstate
88+ * @return module state
89+ */
90+static enum module_ext_state
91+generate_lookup_without_subnet(struct module_qstate *qstate,
92+ struct subnet_qstate* sq)
93+{
94+ verbose(VERB_ALGO, "subnetcache: make subquery to look up without subnet");
95+ if(!generate_sub_request(qstate, sq)) {
96+ verbose(VERB_ALGO, "Could not generate sub query");
97+ qstate->return_rcode = LDNS_RCODE_FORMERR;
98+ qstate->return_msg = NULL;
99+ return module_finished;
100+ }
101+ sq->wait_subquery = 1;
102+ return module_wait_subquery;
103+}
104+
105 static enum module_ext_state
106 eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
107 {
108@@ -539,14 +604,7 @@ eval_response(struct module_qstate *qsta
109 * is still useful to put it in the edns subnet cache for
110 * when a client explicitly asks for subnet specific answer. */
111 verbose(VERB_QUERY, "subnetcache: Authority indicates no support");
112- if(!sq->started_no_cache_store) {
113- lock_rw_wrlock(&sne->biglock);
114- update_cache(qstate, id);
115- lock_rw_unlock(&sne->biglock);
116- }
117- if (sq->subnet_downstream)
118- cp_edns_bad_response(c_out, c_in);
119- return module_finished;
120+ return generate_lookup_without_subnet(qstate, sq);
121 }
122
123 /* Purposefully there was no sent subnet, and there is consequently
124@@ -571,14 +629,14 @@ eval_response(struct module_qstate *qsta
125 !common_prefix(s_out->subnet_addr, s_in->subnet_addr,
126 s_out->subnet_source_mask))
127 {
128- /* we can not accept, restart query without option */
129+ /* we can not accept, perform query without option */
130 verbose(VERB_QUERY, "subnetcache: forged data");
131 s_out->subnet_validdata = 0;
132 (void)edns_opt_list_remove(&qstate->edns_opts_back_out,
133 qstate->env->cfg->client_subnet_opcode);
134 sq->subnet_sent = 0;
135 sq->subnet_sent_no_subnet = 0;
136- return module_restart_next;
137+ return generate_lookup_without_subnet(qstate, sq);
138 }
139
140 lock_rw_wrlock(&sne->biglock);
141@@ -763,6 +821,9 @@ ecs_edns_back_parsed(struct module_qstat
142 } else if(sq->subnet_sent_no_subnet) {
143 /* The answer can be stored as scope 0, not in global cache. */
144 qstate->no_cache_store = 1;
145+ } else if(sq->subnet_sent) {
146+ /* Need another query to be able to store in global cache. */
147+ qstate->no_cache_store = 1;
148 }
149
150 return 1;
151@@ -780,6 +841,32 @@ subnetmod_operate(struct module_qstate *
152 strmodulevent(event));
153 log_query_info(VERB_QUERY, "subnetcache operate: query", &qstate->qinfo);
154
155+ if(sq && sq->wait_subquery_done) {
156+ /* The subquery lookup returned. */
157+ if(sq->ecs_client_in.subnet_source_mask == 0 &&
158+ edns_opt_list_find(qstate->edns_opts_front_in,
159+ qstate->env->cfg->client_subnet_opcode)) {
160+ if(!sq->started_no_cache_store &&
161+ qstate->return_msg) {
162+ lock_rw_wrlock(&sne->biglock);
163+ update_cache(qstate, id);
164+ lock_rw_unlock(&sne->biglock);
165+ }
166+ if (sq->subnet_downstream)
167+ cp_edns_bad_response(&sq->ecs_client_out,
168+ &sq->ecs_client_in);
169+ /* It is a scope zero lookup, append edns subnet
170+ * option to the querier. */
171+ subnet_ecs_opt_list_append(&sq->ecs_client_out,
172+ &qstate->edns_opts_front_out, qstate,
173+ qstate->region);
174+ }
175+ sq->wait_subquery_done = 0;
176+ qstate->ext_state[id] = module_finished;
177+ qstate->no_cache_store = sq->started_no_cache_store;
178+ qstate->no_cache_lookup = sq->started_no_cache_lookup;
179+ return;
180+ }
181 if((event == module_event_new || event == module_event_pass) &&
182 sq == NULL) {
183 struct edns_option* ecs_opt;
184@@ -790,6 +877,8 @@ subnetmod_operate(struct module_qstate *
185 }
186
187 sq = (struct subnet_qstate*)qstate->minfo[id];
188+ if(sq->wait_subquery)
189+ return; /* Wait for that subquery to return */
190
191 if((ecs_opt = edns_opt_list_find(
192 qstate->edns_opts_front_in,
193@@ -819,6 +908,14 @@ subnetmod_operate(struct module_qstate *
194 /* No clients are interested in result or we could not
195 * parse it, we don't do client subnet */
196 sq->ecs_server_out.subnet_validdata = 0;
197+ if(edns_opt_list_find(qstate->edns_opts_front_in,
198+ qstate->env->cfg->client_subnet_opcode)) {
199+ /* aggregated this deaggregated state */
200+ qstate->ext_state[id] =
201+ generate_lookup_without_subnet(
202+ qstate, sq);
203+ return;
204+ }
205 verbose(VERB_ALGO, "subnetcache: pass to next module");
206 qstate->ext_state[id] = module_wait_module;
207 return;
208@@ -859,6 +956,14 @@ subnetmod_operate(struct module_qstate *
209 }
210 lock_rw_unlock(&sne->biglock);
211 }
212+ if(sq->ecs_client_in.subnet_source_mask == 0 &&
213+ edns_opt_list_find(qstate->edns_opts_front_in,
214+ qstate->env->cfg->client_subnet_opcode)) {
215+ /* client asked for resolution without edns subnet */
216+ qstate->ext_state[id] = generate_lookup_without_subnet(
217+ qstate, sq);
218+ return;
219+ }
220
221 sq->ecs_server_out.subnet_addr_fam =
222 sq->ecs_client_in.subnet_addr_fam;
223@@ -895,6 +1000,8 @@ subnetmod_operate(struct module_qstate *
224 qstate->ext_state[id] = module_wait_module;
225 return;
226 }
227+ if(sq && sq->wait_subquery)
228+ return; /* Wait for that subquery to return */
229 /* Query handed back by next module, we have a 'final' answer */
230 if(sq && event == module_event_moddone) {
231 qstate->ext_state[id] = eval_response(qstate, id, sq);
232@@ -943,10 +1050,27 @@ subnetmod_clear(struct module_qstate *AT
233 }
234
235 void
236-subnetmod_inform_super(struct module_qstate *ATTR_UNUSED(qstate),
237- int ATTR_UNUSED(id), struct module_qstate *ATTR_UNUSED(super))
238+subnetmod_inform_super(struct module_qstate *qstate, int id,
239+ struct module_qstate *super)
240 {
241- /* Not used */
242+ struct subnet_qstate* super_sq =
243+ (struct subnet_qstate*)super->minfo[id];
244+ log_query_info(VERB_ALGO, "subnetcache inform_super: query",
245+ &super->qinfo);
246+ super_sq->wait_subquery = 0;
247+ super_sq->wait_subquery_done = 1;
248+ if(qstate->return_rcode != LDNS_RCODE_NOERROR ||
249+ !qstate->return_msg) {
250+ super->return_msg = NULL;
251+ super->return_rcode = LDNS_RCODE_SERVFAIL;
252+ return;
253+ }
254+ super->return_rcode = LDNS_RCODE_NOERROR;
255+ super->return_msg = dns_copy_msg(qstate->return_msg, super->region);
256+ if(!super->return_msg) {
257+ log_err("subnetcache: copy response, out of memory");
258+ super->return_rcode = LDNS_RCODE_SERVFAIL;
259+ }
260 }
261
262 size_t
263--- a/edns-subnet/subnetmod.h
264+++ b/edns-subnet/subnetmod.h
265@@ -102,6 +102,10 @@ struct subnet_qstate {
266 int started_no_cache_store;
267 /** has the subnet module been started with no_cache_lookup? */
268 int started_no_cache_lookup;
269+ /** Wait for subquery that has been started for nonsubnet lookup. */
270+ int wait_subquery;
271+ /** The subquery waited for is done. */
272+ int wait_subquery_done;
273 };
274
275 void subnet_data_delete(void* d, void* ATTR_UNUSED(arg));
diff --git a/meta-networking/recipes-support/unbound/unbound_1.19.3.bb b/meta-networking/recipes-support/unbound/unbound_1.19.3.bb
index 076f03f2ae..7e3e37406f 100644
--- a/meta-networking/recipes-support/unbound/unbound_1.19.3.bb
+++ b/meta-networking/recipes-support/unbound/unbound_1.19.3.bb
@@ -16,6 +16,7 @@ SRC_URI = "git://github.com/NLnetLabs/unbound.git;protocol=https;nobranch=1 \
16 file://CVE-2024-43167.patch \ 16 file://CVE-2024-43167.patch \
17 file://CVE-2024-43168_1.patch \ 17 file://CVE-2024-43168_1.patch \
18 file://CVE-2024-43168_2.patch \ 18 file://CVE-2024-43168_2.patch \
19 file://CVE-2025-5994.patch \
19 " 20 "
20SRCREV = "48b6c60a24e9a5d6d369a7a37c9fe2a767f26abd" 21SRCREV = "48b6c60a24e9a5d6d369a7a37c9fe2a767f26abd"
21 22