mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-06-13 17:39:57 +00:00
unbound: patch CVE-2025-5994
Details: https://nvd.nist.gov/vuln/detail/CVE-2025-5994 Backport the patch[1] provided by upstream, which is linked in the upstream advisory[2] referenced by the NVD report. Tests passed successfully in a locally prepared ptest image. [1]: https://nlnetlabs.nl/downloads/unbound/patch_CVE-2025-5994_2.diff [1]: https://nlnetlabs.nl/downloads/unbound/CVE-2025-5994.txt Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
committed by
Anuj Mittal
parent
c3185de08d
commit
7b418ef060
@@ -0,0 +1,279 @@
|
||||
From d2d6b068e26ddb213b5e339b31609c89ae634c54 Mon Sep 17 00:00:00 2001
|
||||
From: Gyorgy Sarvari <skandigraun@gmail.com>
|
||||
Date: Fri, 6 Mar 2026 19:09:55 +0100
|
||||
Subject: [PATCH] Fix RebirthDay Attack CVE-2025-5994, reported by Xiang Li
|
||||
from AOSP Lab Nankai University.
|
||||
|
||||
This patch was taken from https://nlnetlabs.nl/downloads/unbound/CVE-2025-5994.txt,
|
||||
but it is identical to the one mentioned in the Upstream-Status.
|
||||
|
||||
CVE: CVE-2025-5994
|
||||
Upstream-Status: Backport [https://github.com/NLnetLabs/unbound/commit/5bf82f246481098a6473f296b21fc1229d276c0f]
|
||||
Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
|
||||
---
|
||||
edns-subnet/subnetmod.c | 152 ++++++++++++++++++++++++++++++++++++----
|
||||
edns-subnet/subnetmod.h | 4 ++
|
||||
2 files changed, 142 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/edns-subnet/subnetmod.c b/edns-subnet/subnetmod.c
|
||||
index ead720f3..c5e215b8 100644
|
||||
--- a/edns-subnet/subnetmod.c
|
||||
+++ b/edns-subnet/subnetmod.c
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "services/cache/dns.h"
|
||||
#include "util/module.h"
|
||||
#include "util/regional.h"
|
||||
+#include "util/fptr_wlist.h"
|
||||
#include "util/storage/slabhash.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/data/msgreply.h"
|
||||
@@ -155,7 +156,8 @@ int ecs_whitelist_check(struct query_info* qinfo,
|
||||
|
||||
/* Cache by default, might be disabled after parsing EDNS option
|
||||
* received from nameserver. */
|
||||
- if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)) {
|
||||
+ if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)
|
||||
+ && sq->ecs_client_in.subnet_validdata) {
|
||||
qstate->no_cache_store = 0;
|
||||
}
|
||||
|
||||
@@ -522,6 +524,69 @@ common_prefix(uint8_t *a, uint8_t *b, uint8_t net)
|
||||
return !memcmp(a, b, n) && ((net % 8) == 0 || a[n] == b[n]);
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * Create sub request that looks up the query.
|
||||
+ * @param qstate: query state
|
||||
+ * @param sq: subnet qstate
|
||||
+ * @return false on failure.
|
||||
+ */
|
||||
+static int
|
||||
+generate_sub_request(struct module_qstate *qstate, struct subnet_qstate* sq)
|
||||
+{
|
||||
+ struct module_qstate* subq = NULL;
|
||||
+ uint16_t qflags = 0; /* OPCODE QUERY, no flags */
|
||||
+ int prime = 0;
|
||||
+ int valrec = 0;
|
||||
+ struct query_info qinf;
|
||||
+ qinf.qname = qstate->qinfo.qname;
|
||||
+ qinf.qname_len = qstate->qinfo.qname_len;
|
||||
+ qinf.qtype = qstate->qinfo.qtype;
|
||||
+ qinf.qclass = qstate->qinfo.qclass;
|
||||
+ qinf.local_alias = NULL;
|
||||
+
|
||||
+ qflags |= BIT_RD;
|
||||
+ if((qstate->query_flags & BIT_CD)!=0) {
|
||||
+ qflags |= BIT_CD;
|
||||
+ valrec = 1;
|
||||
+ }
|
||||
+
|
||||
+ fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
|
||||
+ if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, valrec,
|
||||
+ &subq)) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ if(subq) {
|
||||
+ /* It is possible to access the subquery module state. */
|
||||
+ if(sq->ecs_client_in.subnet_source_mask == 0 &&
|
||||
+ edns_opt_list_find(qstate->edns_opts_front_in,
|
||||
+ qstate->env->cfg->client_subnet_opcode)) {
|
||||
+ subq->no_cache_store = 1;
|
||||
+ }
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Perform the query without subnet
|
||||
+ * @param qstate: query state
|
||||
+ * @param sq: subnet qstate
|
||||
+ * @return module state
|
||||
+ */
|
||||
+static enum module_ext_state
|
||||
+generate_lookup_without_subnet(struct module_qstate *qstate,
|
||||
+ struct subnet_qstate* sq)
|
||||
+{
|
||||
+ verbose(VERB_ALGO, "subnetcache: make subquery to look up without subnet");
|
||||
+ if(!generate_sub_request(qstate, sq)) {
|
||||
+ verbose(VERB_ALGO, "Could not generate sub query");
|
||||
+ qstate->return_rcode = LDNS_RCODE_FORMERR;
|
||||
+ qstate->return_msg = NULL;
|
||||
+ return module_finished;
|
||||
+ }
|
||||
+ sq->wait_subquery = 1;
|
||||
+ return module_wait_subquery;
|
||||
+}
|
||||
+
|
||||
static enum module_ext_state
|
||||
eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
{
|
||||
@@ -557,14 +622,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
* is still useful to put it in the edns subnet cache for
|
||||
* when a client explicitly asks for subnet specific answer. */
|
||||
verbose(VERB_QUERY, "subnetcache: Authority indicates no support");
|
||||
- if(!sq->started_no_cache_store) {
|
||||
- lock_rw_wrlock(&sne->biglock);
|
||||
- update_cache(qstate, id);
|
||||
- lock_rw_unlock(&sne->biglock);
|
||||
- }
|
||||
- if (sq->subnet_downstream)
|
||||
- cp_edns_bad_response(c_out, c_in);
|
||||
- return module_finished;
|
||||
+ return generate_lookup_without_subnet(qstate, sq);
|
||||
}
|
||||
|
||||
/* Purposefully there was no sent subnet, and there is consequently
|
||||
@@ -589,14 +647,14 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
!common_prefix(s_out->subnet_addr, s_in->subnet_addr,
|
||||
s_out->subnet_source_mask))
|
||||
{
|
||||
- /* we can not accept, restart query without option */
|
||||
+ /* we can not accept, perform query without option */
|
||||
verbose(VERB_QUERY, "subnetcache: forged data");
|
||||
s_out->subnet_validdata = 0;
|
||||
(void)edns_opt_list_remove(&qstate->edns_opts_back_out,
|
||||
qstate->env->cfg->client_subnet_opcode);
|
||||
sq->subnet_sent = 0;
|
||||
sq->subnet_sent_no_subnet = 0;
|
||||
- return module_restart_next;
|
||||
+ return generate_lookup_without_subnet(qstate, sq);
|
||||
}
|
||||
|
||||
lock_rw_wrlock(&sne->biglock);
|
||||
@@ -795,6 +853,9 @@ ecs_edns_back_parsed(struct module_qstate* qstate, int id,
|
||||
} else if(sq->subnet_sent_no_subnet) {
|
||||
/* The answer can be stored as scope 0, not in global cache. */
|
||||
qstate->no_cache_store = 1;
|
||||
+ } else if(sq->subnet_sent) {
|
||||
+ /* Need another query to be able to store in global cache. */
|
||||
+ qstate->no_cache_store = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -812,6 +873,32 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
strmodulevent(event));
|
||||
log_query_info(VERB_QUERY, "subnetcache operate: query", &qstate->qinfo);
|
||||
|
||||
+ if(sq && sq->wait_subquery_done) {
|
||||
+ /* The subquery lookup returned. */
|
||||
+ if(sq->ecs_client_in.subnet_source_mask == 0 &&
|
||||
+ edns_opt_list_find(qstate->edns_opts_front_in,
|
||||
+ qstate->env->cfg->client_subnet_opcode)) {
|
||||
+ if(!sq->started_no_cache_store &&
|
||||
+ qstate->return_msg) {
|
||||
+ lock_rw_wrlock(&sne->biglock);
|
||||
+ update_cache(qstate, id);
|
||||
+ lock_rw_unlock(&sne->biglock);
|
||||
+ }
|
||||
+ if (sq->subnet_downstream)
|
||||
+ cp_edns_bad_response(&sq->ecs_client_out,
|
||||
+ &sq->ecs_client_in);
|
||||
+ /* It is a scope zero lookup, append edns subnet
|
||||
+ * option to the querier. */
|
||||
+ subnet_ecs_opt_list_append(&sq->ecs_client_out,
|
||||
+ &qstate->edns_opts_front_out, qstate,
|
||||
+ qstate->region);
|
||||
+ }
|
||||
+ sq->wait_subquery_done = 0;
|
||||
+ qstate->ext_state[id] = module_finished;
|
||||
+ qstate->no_cache_store = sq->started_no_cache_store;
|
||||
+ qstate->no_cache_lookup = sq->started_no_cache_lookup;
|
||||
+ return;
|
||||
+ }
|
||||
if((event == module_event_new || event == module_event_pass) &&
|
||||
sq == NULL) {
|
||||
struct edns_option* ecs_opt;
|
||||
@@ -822,6 +909,8 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
}
|
||||
|
||||
sq = (struct subnet_qstate*)qstate->minfo[id];
|
||||
+ if(sq->wait_subquery)
|
||||
+ return; /* Wait for that subquery to return */
|
||||
|
||||
if((ecs_opt = edns_opt_list_find(
|
||||
qstate->edns_opts_front_in,
|
||||
@@ -851,6 +940,14 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
/* No clients are interested in result or we could not
|
||||
* parse it, we don't do client subnet */
|
||||
sq->ecs_server_out.subnet_validdata = 0;
|
||||
+ if(edns_opt_list_find(qstate->edns_opts_front_in,
|
||||
+ qstate->env->cfg->client_subnet_opcode)) {
|
||||
+ /* aggregated this deaggregated state */
|
||||
+ qstate->ext_state[id] =
|
||||
+ generate_lookup_without_subnet(
|
||||
+ qstate, sq);
|
||||
+ return;
|
||||
+ }
|
||||
verbose(VERB_ALGO, "subnetcache: pass to next module");
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
return;
|
||||
@@ -891,6 +988,14 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
}
|
||||
lock_rw_unlock(&sne->biglock);
|
||||
}
|
||||
+ if(sq->ecs_client_in.subnet_source_mask == 0 &&
|
||||
+ edns_opt_list_find(qstate->edns_opts_front_in,
|
||||
+ qstate->env->cfg->client_subnet_opcode)) {
|
||||
+ /* client asked for resolution without edns subnet */
|
||||
+ qstate->ext_state[id] = generate_lookup_without_subnet(
|
||||
+ qstate, sq);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
sq->ecs_server_out.subnet_addr_fam =
|
||||
sq->ecs_client_in.subnet_addr_fam;
|
||||
@@ -927,6 +1032,8 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
return;
|
||||
}
|
||||
+ if(sq && sq->wait_subquery)
|
||||
+ return; /* Wait for that subquery to return */
|
||||
/* Query handed back by next module, we have a 'final' answer */
|
||||
if(sq && event == module_event_moddone) {
|
||||
qstate->ext_state[id] = eval_response(qstate, id, sq);
|
||||
@@ -975,10 +1082,27 @@ subnetmod_clear(struct module_qstate *ATTR_UNUSED(qstate),
|
||||
}
|
||||
|
||||
void
|
||||
-subnetmod_inform_super(struct module_qstate *ATTR_UNUSED(qstate),
|
||||
- int ATTR_UNUSED(id), struct module_qstate *ATTR_UNUSED(super))
|
||||
+subnetmod_inform_super(struct module_qstate *qstate, int id,
|
||||
+ struct module_qstate *super)
|
||||
{
|
||||
- /* Not used */
|
||||
+ struct subnet_qstate* super_sq =
|
||||
+ (struct subnet_qstate*)super->minfo[id];
|
||||
+ log_query_info(VERB_ALGO, "subnetcache inform_super: query",
|
||||
+ &super->qinfo);
|
||||
+ super_sq->wait_subquery = 0;
|
||||
+ super_sq->wait_subquery_done = 1;
|
||||
+ if(qstate->return_rcode != LDNS_RCODE_NOERROR ||
|
||||
+ !qstate->return_msg) {
|
||||
+ super->return_msg = NULL;
|
||||
+ super->return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
+ return;
|
||||
+ }
|
||||
+ super->return_rcode = LDNS_RCODE_NOERROR;
|
||||
+ super->return_msg = dns_copy_msg(qstate->return_msg, super->region);
|
||||
+ if(!super->return_msg) {
|
||||
+ log_err("subnetcache: copy response, out of memory");
|
||||
+ super->return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
+ }
|
||||
}
|
||||
|
||||
size_t
|
||||
diff --git a/edns-subnet/subnetmod.h b/edns-subnet/subnetmod.h
|
||||
index 1ff8a23e..3893820f 100644
|
||||
--- a/edns-subnet/subnetmod.h
|
||||
+++ b/edns-subnet/subnetmod.h
|
||||
@@ -102,6 +102,10 @@ struct subnet_qstate {
|
||||
int started_no_cache_store;
|
||||
/** has the subnet module been started with no_cache_lookup? */
|
||||
int started_no_cache_lookup;
|
||||
+ /** Wait for subquery that has been started for nonsubnet lookup. */
|
||||
+ int wait_subquery;
|
||||
+ /** The subquery waited for is done. */
|
||||
+ int wait_subquery_done;
|
||||
};
|
||||
|
||||
void subnet_data_delete(void* d, void* ATTR_UNUSED(arg));
|
||||
@@ -12,6 +12,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=5308494bc0590c0cb036afd781d78f06"
|
||||
SRC_URI = "git://github.com/NLnetLabs/unbound.git;protocol=https;branch=master \
|
||||
file://run-ptest \
|
||||
file://0001-fix-build-with-gcc-15-Wbuiltin-declaration-mismatch-.patch \
|
||||
file://CVE-2025-5994.patch \
|
||||
"
|
||||
|
||||
# 17 commits after 1.22.0 tag:
|
||||
|
||||
Reference in New Issue
Block a user