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