From d28e800663c35c92f305c9bf5904a6982bec31f4 Mon Sep 17 00:00:00 2001
From: CentOS Sources <bugs@centos.org>
Date: May 16 2023 06:04:34 +0000
Subject: import unbound-1.16.2-5.el8


---

diff --git a/.gitignore b/.gitignore
index 5c781e9..6248c87 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
+SOURCES/icannbundle.pem
 SOURCES/unbound-1.16.2.tar.gz
diff --git a/.unbound.metadata b/.unbound.metadata
index c8b7a90..1e8d688 100644
--- a/.unbound.metadata
+++ b/.unbound.metadata
@@ -1 +1,2 @@
+9a2f73302a13f38dbf7cb3c5e34eb1665d2f156f SOURCES/icannbundle.pem
 9aea0e923b9d6779b5bc360094e24a4017e2bb25 SOURCES/unbound-1.16.2.tar.gz
diff --git a/SOURCES/icannbundle.pem b/SOURCES/icannbundle.pem
deleted file mode 100644
index ceeef5b..0000000
--- a/SOURCES/icannbundle.pem
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO
-TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV
-BAMTDUlDQU5OIFJvb3QgQ0ExCzAJBgNVBAYTAlVTMB4XDTA5MTIyMzA0MTkxMloX
-DTI5MTIxODA0MTkxMlowXTEOMAwGA1UEChMFSUNBTk4xJjAkBgNVBAsTHUlDQU5O
-IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1JQ0FOTiBSb290IENB
-MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKDb
-cLhPNNqc1NB+u+oVvOnJESofYS9qub0/PXagmgr37pNublVThIzyLPGCJ8gPms9S
-G1TaKNIsMI7d+5IgMy3WyPEOECGIcfqEIktdR1YWfJufXcMReZwU4v/AdKzdOdfg
-ONiwc6r70duEr1IiqPbVm5T05l1e6D+HkAvHGnf1LtOPGs4CHQdpIUcy2kauAEy2
-paKcOcHASvbTHK7TbbvHGPB+7faAztABLoneErruEcumetcNfPMIjXKdv1V1E3C7
-MSJKy+jAqqQJqjZoQGB0necZgUMiUv7JK1IPQRM2CXJllcyJrm9WFxY0c1KjBO29
-iIKK69fcglKcBuFShUECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
-Af8EBAMCAf4wHQYDVR0OBBYEFLpS6UmDJIZSL8eZzfyNa2kITcBQMA0GCSqGSIb3
-DQEBCwUAA4IBAQAP8emCogqHny2UYFqywEuhLys7R9UKmYY4suzGO4nkbgfPFMfH
-6M+Zj6owwxlwueZt1j/IaCayoKU3QsrYYoDRolpILh+FPwx7wseUEV8ZKpWsoDoD
-2JFbLg2cfB8u/OlE4RYmcxxFSmXBg0yQ8/IoQt/bxOcEEhhiQ168H2yE5rxJMt9h
-15nu5JBSewrCkYqYYmaxyOC3WrVGfHZxVI7MpIFcGdvSb2a1uyuua8l0BKgk3ujF
-0/wsHNeP22qNyVO+XVBzrM8fk8BSUFuiT/6tZTYXRtEt5aKQZgXbKU5dUF3jT9qg
-j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk
------END CERTIFICATE-----
diff --git a/SOURCES/unbound-1.16-CVE-2022-3204.patch b/SOURCES/unbound-1.16-CVE-2022-3204.patch
new file mode 100644
index 0000000..2d2da91
--- /dev/null
+++ b/SOURCES/unbound-1.16-CVE-2022-3204.patch
@@ -0,0 +1,218 @@
+From 7af485f0fc9926425681ba0280ab6c2c8dd04530 Mon Sep 17 00:00:00 2001
+From: "W.C.A. Wijngaards" <wouter@nlnetlabs.nl>
+Date: Wed, 21 Sep 2022 11:10:38 +0200
+Subject: [PATCH] - Patch for CVE-2022-3204 Non-Responsive Delegation Attack.
+
+---
+ unbound-1.16.2/iterator/iter_delegpt.c |  3 +++
+ unbound-1.16.2/iterator/iter_delegpt.h |  2 ++
+ unbound-1.16.2/iterator/iter_utils.c   |  3 +++
+ unbound-1.16.2/iterator/iter_utils.h   |  9 +++++++
+ unbound-1.16.2/iterator/iterator.c     | 36 +++++++++++++++++++++++++-
+ unbound-1.16.2/services/cache/dns.c    |  3 +++
+ unbound-1.16.2/services/mesh.c         |  7 +++++
+ unbound-1.16.2/services/mesh.h         | 11 ++++++++
+ 8 files changed, 73 insertions(+), 1 deletion(-)
+
+diff --git a/unbound-1.16.2/iterator/iter_delegpt.c b/unbound-1.16.2/iterator/iter_delegpt.c
+index 4bffa1b..fd07aaa 100644
+--- a/unbound-1.16.2/iterator/iter_delegpt.c
++++ b/unbound-1.16.2/iterator/iter_delegpt.c
+@@ -78,6 +78,7 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
+ 		if(!delegpt_add_ns(copy, region, ns->name, ns->lame,
+ 			ns->tls_auth_name, ns->port))
+ 			return NULL;
++		copy->nslist->cache_lookup_count = ns->cache_lookup_count;
+ 		copy->nslist->resolved = ns->resolved;
+ 		copy->nslist->got4 = ns->got4;
+ 		copy->nslist->got6 = ns->got6;
+@@ -121,6 +122,7 @@ delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
+ 	ns->namelen = len;
+ 	dp->nslist = ns;
+ 	ns->name = regional_alloc_init(region, name, ns->namelen);
++	ns->cache_lookup_count = 0;
+ 	ns->resolved = 0;
+ 	ns->got4 = 0;
+ 	ns->got6 = 0;
+@@ -620,6 +622,7 @@ int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame,
+ 	}
+ 	ns->next = dp->nslist;
+ 	dp->nslist = ns;
++	ns->cache_lookup_count = 0;
+ 	ns->resolved = 0;
+ 	ns->got4 = 0;
+ 	ns->got6 = 0;
+diff --git a/unbound-1.16.2/iterator/iter_delegpt.h b/unbound-1.16.2/iterator/iter_delegpt.h
+index 62c8edc..586597a 100644
+--- a/unbound-1.16.2/iterator/iter_delegpt.h
++++ b/unbound-1.16.2/iterator/iter_delegpt.h
+@@ -101,6 +101,8 @@ struct delegpt_ns {
+ 	uint8_t* name;
+ 	/** length of name */
+ 	size_t namelen;
++	/** number of cache lookups for the name */
++	int cache_lookup_count;
+ 	/** 
+ 	 * If the name has been resolved. false if not queried for yet.
+ 	 * true if the A, AAAA queries have been generated.
+diff --git a/unbound-1.16.2/iterator/iter_utils.c b/unbound-1.16.2/iterator/iter_utils.c
+index 3e13e59..56b184a 100644
+--- a/unbound-1.16.2/iterator/iter_utils.c
++++ b/unbound-1.16.2/iterator/iter_utils.c
+@@ -1209,6 +1209,9 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env,
+ 	struct delegpt_ns* ns;
+ 	size_t num = delegpt_count_targets(dp);
+ 	for(ns = dp->nslist; ns; ns = ns->next) {
++		if(ns->cache_lookup_count > ITERATOR_NAME_CACHELOOKUP_MAX_PSIDE)
++			continue;
++		ns->cache_lookup_count++;
+ 		/* get cached parentside A */
+ 		akey = rrset_cache_lookup(env->rrset_cache, ns->name,
+ 			ns->namelen, LDNS_RR_TYPE_A, qinfo->qclass,
+diff --git a/unbound-1.16.2/iterator/iter_utils.h b/unbound-1.16.2/iterator/iter_utils.h
+index 8583fde..850be96 100644
+--- a/unbound-1.16.2/iterator/iter_utils.h
++++ b/unbound-1.16.2/iterator/iter_utils.h
+@@ -62,6 +62,15 @@ struct ub_packed_rrset_key;
+ struct module_stack;
+ struct outside_network;
+ 
++/* max number of lookups in the cache for target nameserver names.
++ * This stops, for large delegations, N*N lookups in the cache. */
++#define ITERATOR_NAME_CACHELOOKUP_MAX	3
++/* max number of lookups in the cache for parentside glue for nameserver names
++ * This stops, for larger delegations, N*N lookups in the cache.
++ * It is a little larger than the nonpside max, so it allows a couple extra
++ * lookups of parent side glue. */
++#define ITERATOR_NAME_CACHELOOKUP_MAX_PSIDE	5
++
+ /**
+  * Process config options and set iterator module state.
+  * Sets default values if no config is found.
+diff --git a/unbound-1.16.2/iterator/iterator.c b/unbound-1.16.2/iterator/iterator.c
+index 25e5cfe..da9b799 100644
+--- a/unbound-1.16.2/iterator/iterator.c
++++ b/unbound-1.16.2/iterator/iterator.c
+@@ -1218,6 +1218,15 @@ generate_dnskey_prefetch(struct module_qstate* qstate,
+ 		(qstate->query_flags&BIT_RD) && !(qstate->query_flags&BIT_CD)){
+ 		return;
+ 	}
++	/* we do not generate this prefetch when the query list is full,
++	 * the query is fetched, if needed, when the validator wants it.
++	 * At that time the validator waits for it, after spawning it.
++	 * This means there is one state that uses cpu and a socket, the
++	 * spawned while this one waits, and not several at the same time,
++	 * if we had created the lookup here. And this helps to keep
++	 * the total load down, but the query still succeeds to resolve. */
++	if(mesh_jostle_exceeded(qstate->env->mesh))
++		return;
+ 
+ 	/* if the DNSKEY is in the cache this lookup will stop quickly */
+ 	log_nametypeclass(VERB_ALGO, "schedule dnskey prefetch", 
+@@ -1911,6 +1920,14 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
+ 				return 0;
+ 			}
+ 			query_count++;
++			/* If the mesh query list is full, exit the loop here.
++			 * This makes the routine spawn one query at a time,
++			 * and this means there is no query state load
++			 * increase, because the spawned state uses cpu and a
++			 * socket while this state waits for that spawned
++			 * state. Next time we can look up further targets */
++			if(mesh_jostle_exceeded(qstate->env->mesh))
++				break;
+ 		}
+ 		/* Send the A request. */
+ 		if(ie->supports_ipv4 &&
+@@ -1925,6 +1942,9 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
+ 				return 0;
+ 			}
+ 			query_count++;
++			/* If the mesh query list is full, exit the loop. */
++			if(mesh_jostle_exceeded(qstate->env->mesh))
++				break;
+ 		}
+ 
+ 		/* mark this target as in progress. */
+@@ -2085,6 +2105,15 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
+ 			}
+ 			ns->done_pside6 = 1;
+ 			query_count++;
++			if(mesh_jostle_exceeded(qstate->env->mesh)) {
++				/* Wait for the lookup; do not spawn multiple
++				 * lookups at a time. */
++				verbose(VERB_ALGO, "try parent-side glue lookup");
++				iq->num_target_queries += query_count;
++				target_count_increase(iq, query_count);
++				qstate->ext_state[id] = module_wait_subquery;
++				return 0;
++			}
+ 		}
+ 		if(ie->supports_ipv4 && !ns->done_pside4) {
+ 			/* Send the A request. */
+@@ -2560,7 +2589,12 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
+ 	if(iq->depth < ie->max_dependency_depth
+ 		&& iq->num_target_queries == 0
+ 		&& (!iq->target_count || iq->target_count[TARGET_COUNT_NX]==0)
+-		&& iq->sent_count < TARGET_FETCH_STOP) {
++		&& iq->sent_count < TARGET_FETCH_STOP
++		/* if the mesh query list is full, then do not waste cpu
++		 * and sockets to fetch promiscuous targets. They can be
++		 * looked up when needed. */
++		&& !mesh_jostle_exceeded(qstate->env->mesh)
++		) {
+ 		tf_policy = ie->target_fetch_policy[iq->depth];
+ 	}
+ 
+diff --git a/unbound-1.16.2/services/cache/dns.c b/unbound-1.16.2/services/cache/dns.c
+index 6bca8d8..b6e5697 100644
+--- a/unbound-1.16.2/services/cache/dns.c
++++ b/unbound-1.16.2/services/cache/dns.c
+@@ -404,6 +404,9 @@ cache_fill_missing(struct module_env* env, uint16_t qclass,
+ 	struct ub_packed_rrset_key* akey;
+ 	time_t now = *env->now;
+ 	for(ns = dp->nslist; ns; ns = ns->next) {
++		if(ns->cache_lookup_count > ITERATOR_NAME_CACHELOOKUP_MAX)
++			continue;
++		ns->cache_lookup_count++;
+ 		akey = rrset_cache_lookup(env->rrset_cache, ns->name, 
+ 			ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0);
+ 		if(akey) {
+diff --git a/unbound-1.16.2/services/mesh.c b/unbound-1.16.2/services/mesh.c
+index 30bcf7c..2a41194 100644
+--- a/unbound-1.16.2/services/mesh.c
++++ b/unbound-1.16.2/services/mesh.c
+@@ -2240,3 +2240,10 @@ mesh_serve_expired_callback(void* arg)
+ 		mesh_do_callback(mstate, LDNS_RCODE_NOERROR, msg->rep, c, &tv);
+ 	}
+ }
++
++int mesh_jostle_exceeded(struct mesh_area* mesh)
++{
++	if(mesh->all.count < mesh->max_reply_states)
++		return 0;
++	return 1;
++}
+diff --git a/unbound-1.16.2/services/mesh.h b/unbound-1.16.2/services/mesh.h
+index 3be9b63..25121a6 100644
+--- a/unbound-1.16.2/services/mesh.h
++++ b/unbound-1.16.2/services/mesh.h
+@@ -685,4 +685,15 @@ struct dns_msg*
+ mesh_serve_expired_lookup(struct module_qstate* qstate,
+ 	struct query_info* lookup_qinfo);
+ 
++/**
++ * See if the mesh has space for more queries. You can allocate queries
++ * anyway, but this checks for the allocated space.
++ * @param mesh: mesh area.
++ * @return true if the query list is full.
++ * 	It checks the number of all queries, not just number of reply states,
++ * 	that have a client address. So that spawned queries count too,
++ * 	that were created by the iterator, or other modules.
++ */
++int mesh_jostle_exceeded(struct mesh_area* mesh);
++
+ #endif /* SERVICES_MESH_H */
+-- 
+2.37.3
+
diff --git a/SPECS/unbound.spec b/SPECS/unbound.spec
index 1007706..27694db 100644
--- a/SPECS/unbound.spec
+++ b/SPECS/unbound.spec
@@ -34,7 +34,7 @@
 Summary: Validating, recursive, and caching DNS(SEC) resolver
 Name: unbound
 Version: 1.16.2
-Release: 2%{?extra_version:.%{extra_version}}%{?dist}
+Release: 5%{?extra_version:.%{extra_version}}%{?dist}
 License: BSD
 Url: https://www.unbound.net/
 Source: https://www.unbound.net/downloads/%{name}-%{version}%{?extra_version}.tar.gz
@@ -60,6 +60,8 @@ Source18: https://nlnetlabs.nl/downloads/%{name}/%{name}-%{version}%{?extra_vers
 # Makes possible backward binary compatibility with a new features
 Patch1:   unbound-1.15-soversion2-compat.patch
 Patch2:   unbound-1.15-source-compat.patch
+# https://github.com/NLnetLabs/unbound/commit/137719522a8ea5b380fbb6206d2466f402f5b554
+Patch3:   unbound-1.16-CVE-2022-3204.patch
 
 BuildRequires: gdb
 BuildRequires: gcc, make
@@ -161,6 +163,7 @@ pushd %{pkgname}
 
 %patch1 -p2 -b .solib2-compat
 %patch2 -p1 -b .srccompat
+%patch3 -p2 -b .CVE-2022-3204
 
 
 # copy common doc files - after here, since it may be patched
@@ -272,12 +275,6 @@ rm %{buildroot}%{python2_sitearch}/*.la
 rm %{buildroot}%{python3_sitearch}/*.la
 %endif # with_python3
 
-# create softlink for all functions of libunbound man pages
-for mpage in ub_ctx ub_result ub_ctx_create ub_ctx_delete ub_ctx_set_option ub_ctx_get_option ub_ctx_config ub_ctx_set_fwd ub_ctx_resolvconf ub_ctx_hosts ub_ctx_add_ta ub_ctx_add_ta_file ub_ctx_trustedkeys ub_ctx_debugout ub_ctx_debuglevel ub_ctx_async ub_poll ub_wait ub_fd ub_process ub_resolve ub_resolve_async ub_cancel ub_resolve_free ub_strerror ub_ctx_print_local_zones ub_ctx_zone_add ub_ctx_zone_remove ub_ctx_data_add ub_ctx_data_remove;
-do
-  echo ".so man3/libunbound.3" > %{buildroot}%{_mandir}/man3/$mpage ;
-done
-
 mkdir -p %{buildroot}%{_localstatedir}/run/unbound
 
 # Install directories for easier config file drop in
@@ -433,6 +430,16 @@ popd
 %verify(not md5 size mtime) %{_sharedstatedir}/%{name}/root.key
 
 %changelog
+* Sat Oct 15 2022 Petr Menšík <pemensik@redhat.com> - 1.16.2-5
+- Stop creating wrong devel manual pages (#2135322)
+
+* Sat Oct 15 2022 Petr Menšík <pemensik@redhat.com> - 1.16.2-4
+- Apply correctly previous change (CVE-2022-3204)
+
+* Tue Oct 11 2022 Petr Menšík <pemensik@redhat.com> - 1.16.2-3
+- Fix NRDelegation attack leading to uncontrolled resource consumption
+  (CVE-2022-3204)
+
 * Tue Aug 09 2022 Petr Menšík <pemensik@redhat.com> - 1.16.2-2
 - Require openssl tool for unbound-keygen (#2018806)