|
|
9abc64 |
From e2aed3e1885bbc6d94d8845edbd9a8dfb869eb67 Mon Sep 17 00:00:00 2001
|
|
|
9abc64 |
From: Petr Mensik <pemensik@redhat.com>
|
|
|
9abc64 |
Date: Fri, 15 May 2020 14:55:26 +0200
|
|
|
9abc64 |
Subject: [PATCH] CVE-2020-8616
|
|
|
9abc64 |
|
|
|
9abc64 |
5395. [security] Further limit the number of queries that can be
|
|
|
9abc64 |
triggered from a request. Root and TLD servers
|
|
|
9abc64 |
are no longer exempt from max-recursion-queries.
|
|
|
9abc64 |
Fetches for missing name server address records
|
|
|
9abc64 |
are limited to 4 for any domain. (CVE-2020-8616)
|
|
|
9abc64 |
[GL #1388]
|
|
|
9abc64 |
---
|
|
|
9abc64 |
lib/dns/adb.c | 18 ++++++++--------
|
|
|
9abc64 |
lib/dns/include/dns/adb.h | 4 ++++
|
|
|
9abc64 |
lib/dns/resolver.c | 45 ++++++++++++++++++++++++++-------------
|
|
|
9abc64 |
3 files changed, 43 insertions(+), 24 deletions(-)
|
|
|
9abc64 |
|
|
|
9abc64 |
diff --git a/lib/dns/adb.c b/lib/dns/adb.c
|
|
|
9abc64 |
index 1eb00c2..ea06a95 100644
|
|
|
9abc64 |
--- a/lib/dns/adb.c
|
|
|
9abc64 |
+++ b/lib/dns/adb.c
|
|
|
9abc64 |
@@ -402,14 +402,13 @@ static void log_quota(dns_adbentry_t *entry, const char *fmt, ...)
|
|
|
9abc64 |
*/
|
|
|
9abc64 |
#define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
|
|
|
9abc64 |
#define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
|
|
|
9abc64 |
-#define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
|
|
|
9abc64 |
- != 0)
|
|
|
9abc64 |
-#define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \
|
|
|
9abc64 |
- != 0)
|
|
|
9abc64 |
-#define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
|
|
|
9abc64 |
-#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
|
|
|
9abc64 |
-#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list))
|
|
|
9abc64 |
-#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
|
|
|
9abc64 |
+#define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) != 0)
|
|
|
9abc64 |
+#define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) != 0)
|
|
|
9abc64 |
+#define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
|
|
|
9abc64 |
+#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
|
|
|
9abc64 |
+#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list))
|
|
|
9abc64 |
+#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
|
|
|
9abc64 |
+#define FIND_NOFETCH(fn) (((fn)->options & DNS_ADBFIND_NOFETCH) != 0)
|
|
|
9abc64 |
|
|
|
9abc64 |
/*
|
|
|
9abc64 |
* These are currently used on simple unsigned ints, so they are
|
|
|
9abc64 |
@@ -3167,7 +3166,8 @@ dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|
|
9abc64 |
else
|
|
|
9abc64 |
have_address = ISC_FALSE;
|
|
|
9abc64 |
if (wanted_fetches != 0 &&
|
|
|
9abc64 |
- ! (FIND_AVOIDFETCHES(find) && have_address)) {
|
|
|
9abc64 |
+ ! (FIND_AVOIDFETCHES(find) && have_address) &&
|
|
|
9abc64 |
+ ! FIND_NOFETCH(find)) {
|
|
|
9abc64 |
/*
|
|
|
9abc64 |
* We're missing at least one address family. Either the
|
|
|
9abc64 |
* caller hasn't instructed us to avoid fetches, or we don't
|
|
|
9abc64 |
diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h
|
|
|
9abc64 |
index bfc8e43..0efaf89 100644
|
|
|
9abc64 |
--- a/lib/dns/include/dns/adb.h
|
|
|
9abc64 |
+++ b/lib/dns/include/dns/adb.h
|
|
|
9abc64 |
@@ -204,6 +204,10 @@ struct dns_adbfind {
|
|
|
9abc64 |
* lame for this query.
|
|
|
9abc64 |
*/
|
|
|
9abc64 |
#define DNS_ADBFIND_OVERQUOTA 0x00000400
|
|
|
9abc64 |
+/*%
|
|
|
9abc64 |
+ * Don't perform a fetch even if there are no address records available.
|
|
|
9abc64 |
+ */
|
|
|
9abc64 |
+#define DNS_ADBFIND_NOFETCH 0x00000800
|
|
|
9abc64 |
|
|
|
9abc64 |
/*%
|
|
|
9abc64 |
* The answers to queries come back as a list of these.
|
|
|
9abc64 |
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
|
|
|
9abc64 |
index 9df33c7..e13d684 100644
|
|
|
9abc64 |
--- a/lib/dns/resolver.c
|
|
|
9abc64 |
+++ b/lib/dns/resolver.c
|
|
|
9abc64 |
@@ -175,6 +175,14 @@
|
|
|
9abc64 |
#define DEFAULT_MAX_QUERIES 75
|
|
|
9abc64 |
#endif
|
|
|
9abc64 |
|
|
|
9abc64 |
+/*
|
|
|
9abc64 |
+ * After NS_FAIL_LIMIT attempts to fetch a name server address,
|
|
|
9abc64 |
+ * if the number of addresses in the NS RRset exceeds NS_RR_LIMIT,
|
|
|
9abc64 |
+ * stop trying to fetch, in order to avoid wasting resources.
|
|
|
9abc64 |
+ */
|
|
|
9abc64 |
+#define NS_FAIL_LIMIT 4
|
|
|
9abc64 |
+#define NS_RR_LIMIT 5
|
|
|
9abc64 |
+
|
|
|
9abc64 |
/* Number of hash buckets for zone counters */
|
|
|
9abc64 |
#ifndef RES_DOMAIN_BUCKETS
|
|
|
9abc64 |
#define RES_DOMAIN_BUCKETS 523
|
|
|
9abc64 |
@@ -3086,8 +3094,8 @@ sort_finds(dns_adbfindlist_t *findlist, unsigned int bias) {
|
|
|
9abc64 |
static void
|
|
|
9abc64 |
findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port,
|
|
|
9abc64 |
unsigned int options, unsigned int flags, isc_stdtime_t now,
|
|
|
9abc64 |
- isc_boolean_t *overquota, isc_boolean_t *need_alternate)
|
|
|
9abc64 |
-{
|
|
|
9abc64 |
+ isc_boolean_t *overquota, isc_boolean_t *need_alternate,
|
|
|
9abc64 |
+ unsigned int *no_addresses) {
|
|
|
9abc64 |
dns_adbaddrinfo_t *ai;
|
|
|
9abc64 |
dns_adbfind_t *find;
|
|
|
9abc64 |
dns_resolver_t *res;
|
|
|
9abc64 |
@@ -3176,6 +3184,9 @@ findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port,
|
|
|
9abc64 |
(res->dispatches6 == NULL &&
|
|
|
9abc64 |
find->result_v4 != DNS_R_NXDOMAIN)))
|
|
|
9abc64 |
*need_alternate = ISC_TRUE;
|
|
|
9abc64 |
+ if (no_addresses != NULL) {
|
|
|
9abc64 |
+ (*no_addresses)++;
|
|
|
9abc64 |
+ }
|
|
|
9abc64 |
} else {
|
|
|
9abc64 |
if ((find->options & DNS_ADBFIND_OVERQUOTA) != 0) {
|
|
|
9abc64 |
if (overquota != NULL)
|
|
|
9abc64 |
@@ -3226,6 +3237,7 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) {
|
|
|
9abc64 |
dns_rdata_ns_t ns;
|
|
|
9abc64 |
isc_boolean_t need_alternate = ISC_FALSE;
|
|
|
9abc64 |
isc_boolean_t all_spilled = ISC_TRUE;
|
|
|
9abc64 |
+ unsigned int no_addresses = 0;
|
|
|
9abc64 |
|
|
|
9abc64 |
FCTXTRACE5("getaddresses", "fctx->depth=", fctx->depth);
|
|
|
9abc64 |
|
|
|
9abc64 |
@@ -3384,8 +3396,13 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) {
|
|
|
9abc64 |
if (result != ISC_R_SUCCESS)
|
|
|
9abc64 |
continue;
|
|
|
9abc64 |
|
|
|
9abc64 |
- findname(fctx, &ns.name, 0, stdoptions, 0, now,
|
|
|
9abc64 |
- &overquota, &need_alternate);
|
|
|
9abc64 |
+ if (no_addresses > NS_FAIL_LIMIT &&
|
|
|
9abc64 |
+ dns_rdataset_count(&fctx->nameservers) > NS_RR_LIMIT)
|
|
|
9abc64 |
+ {
|
|
|
9abc64 |
+ stdoptions |= DNS_ADBFIND_NOFETCH;
|
|
|
9abc64 |
+ }
|
|
|
9abc64 |
+ findname(fctx, &ns.name, 0, stdoptions, 0, now, &overquota,
|
|
|
9abc64 |
+ &need_alternate, &no_addresses);
|
|
|
9abc64 |
|
|
|
9abc64 |
if (!overquota)
|
|
|
9abc64 |
all_spilled = ISC_FALSE;
|
|
|
9abc64 |
@@ -3409,7 +3426,7 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) {
|
|
|
9abc64 |
if (!a->isaddress) {
|
|
|
9abc64 |
findname(fctx, &a->_u._n.name, a->_u._n.port,
|
|
|
9abc64 |
stdoptions, FCTX_ADDRINFO_FORWARDER,
|
|
|
9abc64 |
- now, NULL, NULL);
|
|
|
9abc64 |
+ now, NULL, NULL, NULL);
|
|
|
9abc64 |
continue;
|
|
|
9abc64 |
}
|
|
|
9abc64 |
if (isc_sockaddr_pf(&a->_u.addr) != family)
|
|
|
9abc64 |
@@ -3771,16 +3788,14 @@ fctx_try(fetchctx_t *fctx, isc_boolean_t retrying, isc_boolean_t badcache) {
|
|
|
9abc64 |
}
|
|
|
9abc64 |
}
|
|
|
9abc64 |
|
|
|
9abc64 |
- if (dns_name_countlabels(&fctx->domain) > 2) {
|
|
|
9abc64 |
- result = isc_counter_increment(fctx->qc);
|
|
|
9abc64 |
- if (result != ISC_R_SUCCESS) {
|
|
|
9abc64 |
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
|
|
|
9abc64 |
- DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
|
|
|
9abc64 |
- "exceeded max queries resolving '%s'",
|
|
|
9abc64 |
- fctx->info);
|
|
|
9abc64 |
- fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
|
|
|
9abc64 |
- return;
|
|
|
9abc64 |
- }
|
|
|
9abc64 |
+ result = isc_counter_increment(fctx->qc);
|
|
|
9abc64 |
+ if (result != ISC_R_SUCCESS) {
|
|
|
9abc64 |
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
|
|
|
9abc64 |
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
|
|
|
9abc64 |
+ "exceeded max queries resolving '%s'",
|
|
|
9abc64 |
+ fctx->info);
|
|
|
9abc64 |
+ fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
|
|
|
9abc64 |
+ return;
|
|
|
9abc64 |
}
|
|
|
9abc64 |
|
|
|
9abc64 |
bucketnum = fctx->bucketnum;
|
|
|
9abc64 |
--
|
|
|
9abc64 |
2.21.1
|
|
|
9abc64 |
|