From e7aac6e2ec0499b01d87d9b6657b418b2e159054 Mon Sep 17 00:00:00 2001 From: Ankur Tyagi Date: Fri, 11 Sep 2026 11:09:12 +1200 Subject: [PATCH] unbound: patch CVE-2026-46582 Details: https://nvd.nist.gov/vuln/detail/cve-2026-46582 Signed-off-by: Ankur Tyagi Signed-off-by: Anuj Mittal --- .../unbound/unbound/CVE-2026-46582.patch | 151 ++++++++++++++++++ .../recipes-support/unbound/unbound_1.24.2.bb | 1 + 2 files changed, 152 insertions(+) create mode 100644 meta-networking/recipes-support/unbound/unbound/CVE-2026-46582.patch diff --git a/meta-networking/recipes-support/unbound/unbound/CVE-2026-46582.patch b/meta-networking/recipes-support/unbound/unbound/CVE-2026-46582.patch new file mode 100644 index 0000000000..2091e1622a --- /dev/null +++ b/meta-networking/recipes-support/unbound/unbound/CVE-2026-46582.patch @@ -0,0 +1,151 @@ +From 97245ce2852162fbf19cc23b016ee73fe2aec63c Mon Sep 17 00:00:00 2001 +From: "W.C.A. Wijngaards" +Date: Wed, 22 Jul 2026 10:07:52 +0200 +Subject: [PATCH] - Fix CVE-2026-46582, A wildcard replay, as another piece of + data, triggers poisoning in the serve expired reply path. Thanks to Qifan + Zhang, Palo Alto Networks, for the report. + +(cherry picked from commit fea0ff550bb6193417c9b17ffff409eb6736f90d) + +CVE: CVE-2026-46582 +Upstream-Status: Backport [https://github.com/NLnetLabs/unbound/commit/fea0ff550bb6193417c9b17ffff409eb6736f90d] + +Signed-off-by: Ankur Tyagi +--- + validator/val_utils.c | 15 ++++++++++++--- + validator/validator.c | 31 ++++++++++++++++++++++++++++++- + 2 files changed, 42 insertions(+), 4 deletions(-) + +diff --git a/validator/val_utils.c b/validator/val_utils.c +index 4495695ac..87c5a034a 100644 +--- a/validator/val_utils.c ++++ b/validator/val_utils.c +@@ -439,10 +439,15 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, + * only improves security status + * and bogus is set only once, even if we rechecked the status */ + if(sec > d->security) { ++ int wc_expanded = 0; + d->security = sec; +- if(sec == sec_status_secure) ++ if(sec == sec_status_secure) { ++ uint8_t* wc = NULL; ++ size_t wclen = 0; + d->trust = rrset_trust_validated; +- else if(sec == sec_status_bogus) { ++ if(val_rrset_wildcard(rrset, &wc, &wclen) && wc) ++ wc_expanded = 1; ++ } else if(sec == sec_status_bogus) { + size_t i; + /* update ttl for rrset to fixed value. */ + d->ttl = ve->bogus_ttl; +@@ -455,7 +460,11 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, + lock_basic_unlock(&ve->bogus_lock); + } + /* if status updated - store in cache for reuse */ +- rrset_update_sec_status(env->rrset_cache, rrset, *env->now); ++ /* For a wildcard rrset, that is secure, do not store this ++ * into the cache, because it changes proofs around the ++ * item. */ ++ if(!wc_expanded) ++ rrset_update_sec_status(env->rrset_cache, rrset, *env->now); + } + + return sec; +diff --git a/validator/validator.c b/validator/validator.c +index 5817fc808..68c4bf643 100644 +--- a/validator/validator.c ++++ b/validator/validator.c +@@ -1013,6 +1013,9 @@ validate_positive_response(struct module_env* env, struct val_env* ve, + size_t wl; + int wc_cached = 0; + int wc_NSEC_ok = 0; ++ /* This is used to update the RRset cache, with the combination ++ * of the dname expansion and this wildcard, for security status. */ ++ struct ub_packed_rrset_key* wc_rrset = NULL; + int nsec3s_seen = 0; + size_t i; + struct ub_packed_rrset_key* s; +@@ -1031,6 +1034,9 @@ validate_positive_response(struct module_env* env, struct val_env* ve, + ntohs(s->rk.type), ntohs(s->rk.rrset_class)); + chase_reply->security = sec_status_bogus; + update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); ++ if(wc_rrset) ++ ((struct packed_rrset_data*)wc_rrset-> ++ entry.data)->security = sec_status_bogus; + return; + } + if(wc && !wc_cached && env->cfg->aggressive_nsec) { +@@ -1038,7 +1044,7 @@ validate_positive_response(struct module_env* env, struct val_env* ve, + env->alloc, *env->now); + wc_cached = 1; + } +- ++ if(wc) wc_rrset = s; + } + + /* validate the AUTHORITY section as well - this will generally be +@@ -1095,6 +1101,9 @@ validate_positive_response(struct module_env* env, struct val_env* ve, + "did not exist"); + chase_reply->security = sec_status_bogus; + update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); ++ if(wc_rrset) ++ ((struct packed_rrset_data*)wc_rrset-> ++ entry.data)->security = sec_status_bogus; + return; + } + +@@ -1496,6 +1505,16 @@ validate_any_response(struct module_env* env, struct val_env* ve, + "did not exist"); + chase_reply->security = sec_status_bogus; + update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); ++ /* Make the expanded name and wildcard RRSIG rrsets bogus */ ++ for(i=0; ian_numrrsets; i++) { ++ uint8_t* cwc = NULL; ++ size_t cwl = 0; ++ s = chase_reply->rrsets[i]; ++ if(val_rrset_wildcard(s, &cwc, &cwl) && cwc) { ++ ((struct packed_rrset_data*)s-> ++ entry.data)->security = sec_status_bogus; ++ } ++ } + return; + } + +@@ -1533,6 +1552,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve, + uint8_t* wc = NULL; + size_t wl; + int wc_NSEC_ok = 0; ++ /* This is used to update the RRset cache, with the combination ++ * of the dname expansion and this wildcard, for security status. */ ++ struct ub_packed_rrset_key* wc_rrset = NULL; + int nsec3s_seen = 0; + size_t i; + struct ub_packed_rrset_key* s; +@@ -1553,6 +1575,7 @@ validate_cname_response(struct module_env* env, struct val_env* ve, + update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + return; + } ++ if(wc) wc_rrset = s; + + /* Refuse wildcarded DNAMEs rfc 4597. + * Do not follow a wildcarded DNAME because +@@ -1564,6 +1587,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve, + ntohs(s->rk.type), ntohs(s->rk.rrset_class)); + chase_reply->security = sec_status_bogus; + update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); ++ if(wc_rrset) ++ ((struct packed_rrset_data*)wc_rrset-> ++ entry.data)->security = sec_status_bogus; + return; + } + +@@ -1628,6 +1654,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve, + "did not exist"); + chase_reply->security = sec_status_bogus; + update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); ++ if(wc_rrset) ++ ((struct packed_rrset_data*)wc_rrset-> ++ entry.data)->security = sec_status_bogus; + return; + } + diff --git a/meta-networking/recipes-support/unbound/unbound_1.24.2.bb b/meta-networking/recipes-support/unbound/unbound_1.24.2.bb index 8bd8732fe4..bf17c30572 100644 --- a/meta-networking/recipes-support/unbound/unbound_1.24.2.bb +++ b/meta-networking/recipes-support/unbound/unbound_1.24.2.bb @@ -23,6 +23,7 @@ SRC_URI = "git://github.com/NLnetLabs/unbound.git;protocol=https;branch=master;t file://CVE-2026-42960.patch \ file://CVE-2026-44390.patch \ file://CVE-2026-44608.patch \ + file://CVE-2026-46582.patch \ " SRCREV = "f6269baa605d31859f28770e01a24e3677e5f82c"