Blame SOURCES/bind-9.16-CVE-2022-3080.patch

3e768d
From 3bcd32572504ac9b92e3c6ec1e2cee3df3b68309 Mon Sep 17 00:00:00 2001
3e768d
From: Petr Mensik <pemensik@redhat.com>
3e768d
Date: Tue, 20 Sep 2022 11:34:42 +0200
3e768d
Subject: [PATCH 2/4] Fix CVE-2022-3080
3e768d
3e768d
5960.	[security]	Fix serve-stale crash that could happen when
3e768d
			stale-answer-client-timeout was set to 0 and there was
3e768d
			a stale CNAME in the cache for an incoming query.
3e768d
			(CVE-2022-3080) [GL #3517]
3e768d
---
3e768d
 lib/ns/include/ns/query.h |  1 +
3e768d
 lib/ns/query.c            | 42 ++++++++++++++++++++++++---------------
3e768d
 2 files changed, 27 insertions(+), 16 deletions(-)
3e768d
3e768d
diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h
3e768d
index 4d48cf6..34b3070 100644
3e768d
--- a/lib/ns/include/ns/query.h
3e768d
+++ b/lib/ns/include/ns/query.h
3e768d
@@ -145,6 +145,7 @@ struct query_ctx {
3e768d
 	bool authoritative;		    /* authoritative query? */
3e768d
 	bool want_restart;		    /* CNAME chain or other
3e768d
 					     * restart needed */
3e768d
+	bool		refresh_rrset;	    /* stale RRset refresh needed */
3e768d
 	bool		need_wildcardproof; /* wildcard proof needed */
3e768d
 	bool		nxrewrite;	    /* negative answer from RPZ */
3e768d
 	bool		findcoveringnsec;   /* lookup covering NSEC */
3e768d
diff --git a/lib/ns/query.c b/lib/ns/query.c
3e768d
index 249321c..a450cb7 100644
3e768d
--- a/lib/ns/query.c
3e768d
+++ b/lib/ns/query.c
3e768d
@@ -5686,7 +5686,6 @@ query_lookup(query_ctx_t *qctx) {
3e768d
 	bool dbfind_stale = false;
3e768d
 	bool stale_timeout = false;
3e768d
 	bool stale_found = false;
3e768d
-	bool refresh_rrset = false;
3e768d
 	bool stale_refresh_window = false;
3e768d
 
3e768d
 	CCTRACE(ISC_LOG_DEBUG(3), "query_lookup");
3e768d
@@ -5868,8 +5867,7 @@ query_lookup(query_ctx_t *qctx) {
3e768d
 					"%s stale answer used, an attempt to "
3e768d
 					"refresh the RRset will still be made",
3e768d
 					namebuf);
3e768d
-				refresh_rrset = STALE(qctx->rdataset);
3e768d
-				qctx->client->nodetach = refresh_rrset;
3e768d
+				qctx->refresh_rrset = STALE(qctx->rdataset);
3e768d
 			}
3e768d
 		} else {
3e768d
 			/*
3e768d
@@ -5907,17 +5905,6 @@ query_lookup(query_ctx_t *qctx) {
3e768d
 
3e768d
 	result = query_gotanswer(qctx, result);
3e768d
 
3e768d
-	if (refresh_rrset) {
3e768d
-		/*
3e768d
-		 * If we reached this point then it means that we have found a
3e768d
-		 * stale RRset entry in cache and BIND is configured to allow
3e768d
-		 * queries to be answered with stale data if no active RRset
3e768d
-		 * is available, i.e. "stale-anwer-client-timeout 0". But, we
3e768d
-		 * still need to refresh the RRset.
3e768d
-		 */
3e768d
-		query_refresh_rrset(qctx);
3e768d
-	}
3e768d
-
3e768d
 cleanup:
3e768d
 	return (result);
3e768d
 }
3e768d
@@ -7737,11 +7724,14 @@ query_addanswer(query_ctx_t *qctx) {
3e768d
 
3e768d
 	/*
3e768d
 	 * On normal lookups, clear any rdatasets that were added on a
3e768d
-	 * lookup due to stale-answer-client-timeout.
3e768d
+	 * lookup due to stale-answer-client-timeout. Do not clear if we
3e768d
+	 * are going to refresh the RRset, because the stale contents are
3e768d
+	 * prioritized.
3e768d
 	 */
3e768d
 	if (QUERY_STALEOK(&qctx->client->query) &&
3e768d
-	    !QUERY_STALETIMEOUT(&qctx->client->query))
3e768d
+	    !QUERY_STALETIMEOUT(&qctx->client->query) && !qctx->refresh_rrset)
3e768d
 	{
3e768d
+		CCTRACE(ISC_LOG_DEBUG(3), "query_clear_stale");
3e768d
 		query_clear_stale(qctx->client);
3e768d
 		/*
3e768d
 		 * We can clear the attribute to prevent redundant clearing
3e768d
@@ -11457,9 +11447,29 @@ ns_query_done(query_ctx_t *qctx) {
3e768d
 	/*
3e768d
 	 * Client may have been detached after query_send(), so
3e768d
 	 * we test and store the flag state here, for safety.
3e768d
+	 * If we are refreshing the RRSet, we must not detach from the client
3e768d
+	 * in the query_send(), so we need to override the flag.
3e768d
 	 */
3e768d
+	if (qctx->refresh_rrset) {
3e768d
+		qctx->client->nodetach = true;
3e768d
+	}
3e768d
 	nodetach = qctx->client->nodetach;
3e768d
 	query_send(qctx->client);
3e768d
+
3e768d
+	if (qctx->refresh_rrset) {
3e768d
+		/*
3e768d
+		 * If we reached this point then it means that we have found a
3e768d
+		 * stale RRset entry in cache and BIND is configured to allow
3e768d
+		 * queries to be answered with stale data if no active RRset
3e768d
+		 * is available, i.e. "stale-anwer-client-timeout 0". But, we
3e768d
+		 * still need to refresh the RRset. To prevent adding duplicate
3e768d
+		 * RRsets, clear the RRsets from the message before doing the
3e768d
+		 * refresh.
3e768d
+		 */
3e768d
+		message_clearrdataset(qctx->client->message, 0);
3e768d
+		query_refresh_rrset(qctx);
3e768d
+	}
3e768d
+
3e768d
 	if (!nodetach) {
3e768d
 		qctx->detach_client = true;
3e768d
 	}
3e768d
-- 
3e768d
2.37.3
3e768d