Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 26 Nov 2025 22:47:52 +0000
From:      Shawn Webb <shawn.webb@hardenedbsd.org>
To:        Gordon Tetlow <gordon@freebsd.org>
Cc:        src-committers@freebsd.org, dev-commits-src-all@freebsd.org,  dev-commits-src-main@freebsd.org
Subject:   Re: git: 2a3a6a177114 - main - Mitigate YXDOMAIN and nodata non-referral answer poisoning.
Message-ID:  <vkvj4ijewblmfnzzwqv64fkzkfpvdl4rxos2i27b5r6fmstefr@wf5wqc4t5awb>
In-Reply-To: <69272395.3426e.56ff4912@gitrepo.freebsd.org>
References:  <69272395.3426e.56ff4912@gitrepo.freebsd.org>

index | next in thread | previous in thread | raw e-mail

[-- Attachment #1 --]
On Wed, Nov 26, 2025 at 03:58:13PM +0000, Gordon Tetlow wrote:
> The branch main has been updated by gordon:
> 
> URL: https://cgit.FreeBSD.org/src/commit/?id=2a3a6a1771148a709c2d9694c1d66c41ce8dee79
> 
> commit 2a3a6a1771148a709c2d9694c1d66c41ce8dee79
> Author:     Gordon Tetlow <gordon@FreeBSD.org>
> AuthorDate: 2025-11-21 21:24:58 +0000
> Commit:     Gordon Tetlow <gordon@FreeBSD.org>
> CommitDate: 2025-11-26 15:57:33 +0000
> 
>     Mitigate YXDOMAIN and nodata non-referral answer poisoning.
>     
>     Add a fix to apply scrubbing of unsolicited NS RRSets (and their
>     respective address records) for YXDOMAIN and nodata non-referral
>     answers. This prevents a malicious actor from exploiting a possible
>     cache poison attack.
>     
>     Obtained from:  NLnet Labs
>     Security:       CVE-2025-11411
> ---
>  contrib/unbound/iterator/iter_scrub.c | 39 +++++++++++++++++++++++++++++++----
>  1 file changed, 35 insertions(+), 4 deletions(-)
> 
> diff --git a/contrib/unbound/iterator/iter_scrub.c b/contrib/unbound/iterator/iter_scrub.c
> index 553d3655f0e3..8507a3fb65ac 100644
> --- a/contrib/unbound/iterator/iter_scrub.c
> +++ b/contrib/unbound/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,
>  	int cname_length = 0; /* number of CNAMEs, or DNAMEs */
>  
>  	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;
>  			}
>  			cname_length++;
> @@ -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, qstate))
> 

Hey Gordon,

Do you know if this fix was the incomplete one from Unbound 1.24.1? Or
does this include the additional fix that landed in 1.24.2 earlier
today?

Thanks,

-- 
Shawn Webb
Cofounder / Security Engineer
HardenedBSD

Signal Username:  shawn_webb.74
Tor-ified Signal: +1 303-901-1600 / shawn_webb_opsec.50
https://git.hardenedbsd.org/hardenedbsd/pubkeys/-/raw/master/Shawn_Webb/03A4CBEBB82EA5A67D9F3853FF2E67A277F8E1FA.pub.asc

[-- Attachment #2 --]
-----BEGIN PGP SIGNATURE-----

iQIzBAABCAAdFiEEA6TL67gupaZ9nzhT/y5nonf44foFAmkng5IACgkQ/y5nonf4
4fr0iBAAijqdG8MO0Np86jNz8P13yc8IPXV+wcLJitOPFgP+1km+eAD3tlvqm+hm
9YXvLLr2kZ0sVu2yr03LJMR22UbQyg2B6g/c7Nq1UB/HqQixqWYyMXvCtMazx9Ij
W69QBXlF0Es9bGbVIcXI0EK4Tf81azI1cWTJ5kvsBqfLsppJKIZKUyq/Sot6QtSc
Db7NOig1GckJxhnvrM113pRmkfJGwDOBPjKaGwMBAe/IGdzcQfQ03bzJokshIpLm
crdwwmTToA0T9zxuo9e+eD1EDQSuBN5XJc0eXzHdqi7x8L4hqRfPTO03poQtvLX4
bVS7gBWLuZzaOwEZlGd0P8LEb2cpAa2IIigu/GQgxCx2kY95t5Dk+kpCaPIWckFS
+2EXespt3JS1g5EiW/EzI6virY+96KUTS9TdDCMM3n386PRhrVQXGb5pH2LQ0Kz2
B3fZvXoY5/z8MKxG7TcTZDZBoGMDEJuiSQxNlj9Zj6ams+y4/0UuEpWmDwHwxzxN
+xMvMejdTJkaB00cl+hRG5RBrHX9ZujHtWDSzTiaekh6zF4jI3nKDFdCiUWxQ7DJ
SUFCbExA+yItBjsEpDHojv08nxZMlUhokfT9Iw5KtdwWCOIMEJQRXkd1kT18kI1K
c78kV7kZVKtIlv7eSQL07AQlRs0gNOWR7B8vfhCIy/EmX5ARopA=
=wmej
-----END PGP SIGNATURE-----
help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?vkvj4ijewblmfnzzwqv64fkzkfpvdl4rxos2i27b5r6fmstefr>