diff --git a/Additional_fix_for_CVE-2025-11411.patch b/Additional_fix_for_CVE-2025-11411.patch new file mode 100644 index 0000000000000000000000000000000000000000..381518abb5a39f9538f94d2665dc91abf41b27a3 --- /dev/null +++ b/Additional_fix_for_CVE-2025-11411.patch @@ -0,0 +1,262 @@ +From f6269baa605d31859f28770e01a24e3677e5f82c Mon Sep 17 00:00:00 2001 +From: Yorgos Thessalonikefs +Date: Wed, 26 Nov 2025 11:09:40 +0100 +Subject: [PATCH] - Additional fix for CVE-2025-11411 (possible domain + hijacking attack), to include YXDOMAIN and non-referral nodata answers in + the mitigation as well, reported by TaoFei Guo from Peking University, Yang + Luo and JianJun Chen from Tsinghua University. + +Conflict:change context in iter_scrub.c and ratelimit.testns +Reference:https://github.com/NLnetLabs/unbound/commit/f6269baa605d31859f28770e01a24e3677e5f82c + +--- + iterator/iter_scrub.c | 39 +++++++++-- + testdata/iter_scrub_promiscuous.rpl | 84 ++++++++++++++++++++++++ + testdata/ratelimit.tdir/ratelimit.testns | 30 +++++++-- + 3 files changed, 143 insertions(+), 8 deletions(-) + +diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c +index 553d3655f..8507a3fb6 100644 +--- a/iterator/iter_scrub.c ++++ b/iterator/iter_scrub.c +@@ -418,12 +418,13 @@ shorten_rrset(sldns_buffer* pkt, struct rrset_parse* rrset, int count) + * @param qinfo: original query. + * @param region: where to allocate synthesized CNAMEs. + * @param env: module env with config options. ++ * @param zonename: name of server zone. + * @return 0 on error. + */ + static int + scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, + struct query_info* qinfo, struct regional* region, +- struct module_env* env) ++ struct module_env* env, uint8_t* zonename) + { + uint8_t* sname = qinfo->qname; + size_t snamelen = qinfo->qname_len; +@@ -431,7 +432,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, + struct rrset_parse* rrset, *prev, *nsset=NULL; + + if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR && +- FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN) ++ FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN && ++ FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_YXDOMAIN) + return 1; + + /* For the ANSWER section, remove all "irrelevant" records and add +@@ -470,6 +472,11 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, + &aliaslen, pkt)) { + verbose(VERB_ALGO, "synthesized CNAME " + "too long"); ++ if(FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_YXDOMAIN) { ++ prev = rrset; ++ rrset = rrset->rrset_all_next; ++ continue; ++ } + return 0; + } + if(nx && nx->type == LDNS_RR_TYPE_CNAME && +@@ -650,6 +657,29 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, + "RRset:", pkt, msg, prev, &rrset); + continue; + } ++ /* Also delete promiscuous NS for other RCODEs */ ++ if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR ++ && env->cfg->iter_scrub_promiscuous) { ++ remove_rrset("normalize: removing promiscuous " ++ "RRset:", pkt, msg, prev, &rrset); ++ continue; ++ } ++ /* Also delete promiscuous NS for NOERROR with nodata ++ * for authoritative answers, not for delegations. ++ * NOERROR with an_rrsets!=0 already handled. ++ * Also NOERROR and soa_in_auth already handled. ++ * NOERROR with an_rrsets==0, and not a referral. ++ * referral is (NS not the zonename, noSOA). ++ */ ++ if(FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NOERROR ++ && msg->an_rrsets == 0 ++ && !(dname_pkt_compare(pkt, rrset->dname, ++ zonename) != 0 && !soa_in_auth(msg)) ++ && env->cfg->iter_scrub_promiscuous) { ++ remove_rrset("normalize: removing promiscuous " ++ "RRset:", pkt, msg, prev, &rrset); ++ continue; ++ } + if(nsset == NULL) { + nsset = rrset; + } else { +@@ -1060,7 +1090,8 @@ scrub_message(sldns_buffer* pkt, struct msg_parse* msg, + /* this is not required for basic operation but is a forgery + * resistance (security) feature */ + if((FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NOERROR || +- FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NXDOMAIN) && ++ FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NXDOMAIN || ++ FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_YXDOMAIN) && + msg->qdcount == 0) + return 0; + +@@ -1074,7 +1105,7 @@ scrub_message(sldns_buffer* pkt, struct msg_parse* msg, + } + + /* normalize the response, this cleans up the additional. */ +- if(!scrub_normalize(pkt, msg, qinfo, region, env)) ++ if(!scrub_normalize(pkt, msg, qinfo, region, env, zonename)) + return 0; + /* delete all out-of-zone information */ + if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie)) +diff --git a/testdata/iter_scrub_promiscuous.rpl b/testdata/iter_scrub_promiscuous.rpl +index 61fca0d28..febbee81c 100644 +--- a/testdata/iter_scrub_promiscuous.rpl ++++ b/testdata/iter_scrub_promiscuous.rpl +@@ -16,6 +16,7 @@ SCENARIO_BEGIN Test iterator with scrub of promiscuous records + ; The spoofed contents are ns.attacker.mesa and its IPs 5.6.7.8 and 5.6.7.9. + ; The pollute1.mesa NS, ns.pollute2.mesa A, and test3.atkr.pollute3.mesa NS + ; with ns.pollute3.mesa A records are tested for cache placement. ++; pollute4.mesa uses YXDOMAIN. + + ; ns.root + RANGE_BEGIN 0 400 +@@ -84,6 +85,18 @@ SECTION ADDITIONAL + ns.pollute3.mesa. IN A 1.2.4.3 + ENTRY_END + ++ENTRY_BEGIN ++MATCH opcode subdomain ++ADJUST copy_id copy_query ++REPLY QR NOERROR ++SECTION QUESTION ++pollute4.mesa. IN NS ++SECTION AUTHORITY ++pollute4.mesa. IN NS ns.pollute4.mesa. ++SECTION ADDITIONAL ++ns.pollute4.mesa. IN A 1.2.4.4 ++ENTRY_END ++ + ENTRY_BEGIN + MATCH opcode subdomain + ADJUST copy_id copy_query +@@ -188,6 +201,35 @@ check.pollute3.mesa. IN A 1.8.9.3 + ENTRY_END + RANGE_END + ++; ns.pollute4.mesa ++RANGE_BEGIN 0 400 ++ ADDRESS 1.2.4.4 ++ ++; This is the spoofed answer that is returned. ++ENTRY_BEGIN ++MATCH opcode qtype qname ++ADJUST copy_id ++REPLY QR AA YXDOMAIN ++SECTION QUESTION ++test4.atkr.pollute4.mesa. IN A ++SECTION ANSWER ++test4.atkr.pollute4.mesa. 86400 IN A 1.2.3.4 ++SECTION AUTHORITY ++pollute4.mesa. 86400 IN NS ns.attacker.mesa. ++ENTRY_END ++ ++; correct answer for the check query. ++ENTRY_BEGIN ++MATCH opcode qtype qname ++ADJUST copy_id ++REPLY QR AA NOERROR ++SECTION QUESTION ++check.pollute4.mesa. IN A ++SECTION ANSWER ++check.pollute4.mesa. IN A 1.8.9.4 ++ENTRY_END ++RANGE_END ++ + ; ns.attacker.mesa + RANGE_BEGIN 0 400 + ADDRESS 5.6.7.8 +@@ -370,4 +412,46 @@ check.pollute3.mesa. IN A 1.8.9.3 + ;check.pollute3.mesa. IN A 5.6.7.9 + ENTRY_END + ++; Test query 4 ++STEP 120 QUERY ++ENTRY_BEGIN ++REPLY RD ++SECTION QUESTION ++test4.atkr.pollute4.mesa. IN A ++ENTRY_END ++ ++STEP 130 CHECK_ANSWER ++ENTRY_BEGIN ++MATCH all ++REPLY QR RD RA YXDOMAIN ++SECTION QUESTION ++test4.atkr.pollute4.mesa. IN A ++SECTION ANSWER ++test4.atkr.pollute4.mesa. 86400 IN A 1.2.3.4 ++SECTION AUTHORITY ++; removed record ++;pollute4.mesa. 0 IN NS ns.attacker.mesa. ++ENTRY_END ++ ++; Check the cache contents, for query 4. ++STEP 140 QUERY ++ENTRY_BEGIN ++REPLY RD ++SECTION QUESTION ++check.pollute4.mesa. IN A ++ENTRY_END ++ ++STEP 150 CHECK_ANSWER ++ENTRY_BEGIN ++MATCH all ++REPLY QR RD RA NOERROR ++SECTION QUESTION ++check.pollute4.mesa. IN A ++SECTION ANSWER ++; good answer ++check.pollute4.mesa. IN A 1.8.9.4 ++; bad answer ++;check.pollute4.mesa. IN A 5.6.7.9 ++ENTRY_END ++ + SCENARIO_END +diff --git a/testdata/ratelimit.tdir/ratelimit.testns b/testdata/ratelimit.tdir/ratelimit.testns +index 563c1db6a..5c22c292d 100644 +--- a/testdata/ratelimit.tdir/ratelimit.testns ++++ b/testdata/ratelimit.tdir/ratelimit.testns +@@ -3,11 +3,31 @@ $ORIGIN example.com. + $TTL 3600 + + ENTRY_BEGIN +-MATCH opcode qtype ++MATCH opcode qname qtype + REPLY QR AA NOERROR +-ADJUST copy_id copy_query ++ADJUST copy_id + SECTION QUESTION +-wild IN A ++www1 IN A + SECTION ANSWER +-wild IN A 10.20.30.40 ++www1 IN A 1.1.1.1 ++ENTRY_END ++ ++ENTRY_BEGIN ++MATCH opcode qname qtype ++REPLY QR AA NOERROR ++ADJUST copy_id ++SECTION QUESTION ++www2 IN A ++SECTION ANSWER ++www2 IN A 2.2.2.2 ++ENTRY_END ++ ++ENTRY_BEGIN ++MATCH opcode qname qtype ++REPLY QR AA NOERROR ++ADJUST copy_id ++SECTION QUESTION ++www3 IN A ++SECTION ANSWER ++www3 IN A 3.3.3.3 + ENTRY_END + diff --git a/unbound.spec b/unbound.spec index e1cce0fca232a1df99773a6d9bac15e7b6f0e704..f0bff8f06fc30429725bec4da6b9a00f75505c17 100644 --- a/unbound.spec +++ b/unbound.spec @@ -1,4 +1,4 @@ -%define anolis_release 11 +%define anolis_release 12 Name: unbound Version: 1.17.1 @@ -72,6 +72,8 @@ Patch0016: backport-CVE-2026-44608.patch Patch1007: backport-CVE-2025-5994.patch Patch1008: 1008-bugfix-for-CVE-2025-11411.patch +# https://github.com/NLnetLabs/unbound/commit/f6269baa605d31859f28770e01a24e3677e5f82c +Patch0017: Additional_fix_for_CVE-2025-11411.patch BuildRequires: gcc, make, systemd, pkgconfig(libsystemd), byacc BuildRequires: flex, swig, openssl-devel @@ -304,6 +306,9 @@ fi %{_mandir}/man1/unbound-* %changelog +* Wed Jul 01 2026 mgb01105731 - 1.17.1-12 +- Add patch to additional fix CVE-2025-11411 + * Wed Jun 10 2026 lzq11122 - 1.17.1-11 - Add patch to fix CVE-2026-32792,CVE-2026-42923,CVE-2026-40622,CVE-2026-42534,CVE-2026-44390,CVE-2026-44608