svn commit: r275854 - in releng: 10.0 10.0/contrib/unbound/iterator 10.0/sys/conf 10.1 10.1/contrib/unbound/iterator 10.1/sys/conf
Xin LI
delphij at FreeBSD.org
Wed Dec 17 06:59:51 UTC 2014
Author: delphij
Date: Wed Dec 17 06:59:47 2014
New Revision: 275854
URL: https://svnweb.freebsd.org/changeset/base/275854
Log:
Fix unbound remote denial of service vulnerability.
Security: FreeBSD-SA-14:30.unbound
Security: CVE-2014-8602
Approved by: so
Modified:
releng/10.0/UPDATING
releng/10.0/contrib/unbound/iterator/iterator.c
releng/10.0/contrib/unbound/iterator/iterator.h
releng/10.0/sys/conf/newvers.sh
releng/10.1/UPDATING
releng/10.1/contrib/unbound/iterator/iterator.c
releng/10.1/contrib/unbound/iterator/iterator.h
releng/10.1/sys/conf/newvers.sh
Modified: releng/10.0/UPDATING
==============================================================================
--- releng/10.0/UPDATING Wed Dec 17 06:58:00 2014 (r275853)
+++ releng/10.0/UPDATING Wed Dec 17 06:59:47 2014 (r275854)
@@ -16,6 +16,9 @@ from older versions of FreeBSD, try WITH
stable/10, and then rebuild without this option. The bootstrap process from
older version of current is a bit fragile.
+20141217: p14 FreeBSD-SA-14:30.unbound
+ Fix unbound remote denial of service vulnerability.
+
20141210: p13 FreeBSD-SA-14:28.file
Fix multiple vulnerabilities in file(1) and libmagic(3).
Modified: releng/10.0/contrib/unbound/iterator/iterator.c
==============================================================================
--- releng/10.0/contrib/unbound/iterator/iterator.c Wed Dec 17 06:58:00 2014 (r275853)
+++ releng/10.0/contrib/unbound/iterator/iterator.c Wed Dec 17 06:59:47 2014 (r275854)
@@ -117,6 +117,7 @@ iter_new(struct module_qstate* qstate, i
iq->query_restart_count = 0;
iq->referral_count = 0;
iq->sent_count = 0;
+ iq->target_count = NULL;
iq->wait_priming_stub = 0;
iq->refetch_glue = 0;
iq->dnssec_expected = 0;
@@ -442,6 +443,26 @@ handle_cname_response(struct module_qsta
return 1;
}
+/** create target count structure for this query */
+static void
+target_count_create(struct iter_qstate* iq)
+{
+ if(!iq->target_count) {
+ iq->target_count = (int*)calloc(2, sizeof(int));
+ /* if calloc fails we simply do not track this number */
+ if(iq->target_count)
+ iq->target_count[0] = 1;
+ }
+}
+
+static void
+target_count_increase(struct iter_qstate* iq, int num)
+{
+ target_count_create(iq);
+ if(iq->target_count)
+ iq->target_count[1] += num;
+}
+
/**
* Generate a subrequest.
* Generate a local request event. Local events are tied to this module, and
@@ -513,6 +534,10 @@ generate_sub_request(uint8_t* qname, siz
subiq = (struct iter_qstate*)subq->minfo[id];
memset(subiq, 0, sizeof(*subiq));
subiq->num_target_queries = 0;
+ target_count_create(iq);
+ subiq->target_count = iq->target_count;
+ if(iq->target_count)
+ iq->target_count[0] ++; /* extra reference */
subiq->num_current_queries = 0;
subiq->depth = iq->depth+1;
outbound_list_init(&subiq->outlist);
@@ -1339,6 +1364,12 @@ query_for_targets(struct module_qstate*
if(iq->depth == ie->max_dependency_depth)
return 0;
+ if(iq->depth > 0 && iq->target_count &&
+ iq->target_count[1] > MAX_TARGET_COUNT) {
+ verbose(VERB_QUERY, "request has exceeded the maximum "
+ "number of glue fetches %d", iq->target_count[1]);
+ return 0;
+ }
iter_mark_cycle_targets(qstate, iq->dp);
missing = (int)delegpt_count_missing_targets(iq->dp);
@@ -1487,6 +1518,7 @@ processLastResort(struct module_qstate*
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += qs;
+ target_count_increase(iq, qs);
if(qs != 0) {
qstate->ext_state[id] = module_wait_subquery;
return 0; /* and wait for them */
@@ -1496,6 +1528,12 @@ processLastResort(struct module_qstate*
verbose(VERB_QUERY, "maxdepth and need more nameservers, fail");
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
+ if(iq->depth > 0 && iq->target_count &&
+ iq->target_count[1] > MAX_TARGET_COUNT) {
+ verbose(VERB_QUERY, "request has exceeded the maximum "
+ "number of glue fetches %d", iq->target_count[1]);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
/* mark cycle targets for parent-side lookups */
iter_mark_pside_cycle_targets(qstate, iq->dp);
/* see if we can issue queries to get nameserver addresses */
@@ -1525,6 +1563,7 @@ processLastResort(struct module_qstate*
if(query_count != 0) { /* suspend to await results */
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;
}
@@ -1680,6 +1719,7 @@ processQueryTargets(struct module_qstate
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += extra;
+ target_count_increase(iq, extra);
if(iq->num_target_queries > 0) {
/* wait to get all targets, we want to try em */
verbose(VERB_ALGO, "wait for all targets for fallback");
@@ -1720,6 +1760,7 @@ processQueryTargets(struct module_qstate
/* errors ignored, these targets are not strictly necessary for
* this result, we do not have to reply with SERVFAIL */
iq->num_target_queries += extra;
+ target_count_increase(iq, extra);
}
/* Add the current set of unused targets to our queue. */
@@ -1765,6 +1806,7 @@ processQueryTargets(struct module_qstate
return 1;
}
iq->num_target_queries += qs;
+ target_count_increase(iq, qs);
}
/* Since a target query might have been made, we
* need to check again. */
@@ -2847,6 +2889,8 @@ iter_clear(struct module_qstate* qstate,
iq = (struct iter_qstate*)qstate->minfo[id];
if(iq) {
outbound_list_clear(&iq->outlist);
+ if(iq->target_count && --iq->target_count[0] == 0)
+ free(iq->target_count);
iq->num_current_queries = 0;
}
qstate->minfo[id] = NULL;
Modified: releng/10.0/contrib/unbound/iterator/iterator.h
==============================================================================
--- releng/10.0/contrib/unbound/iterator/iterator.h Wed Dec 17 06:58:00 2014 (r275853)
+++ releng/10.0/contrib/unbound/iterator/iterator.h Wed Dec 17 06:59:47 2014 (r275854)
@@ -52,6 +52,8 @@ struct iter_donotq;
struct iter_prep_list;
struct iter_priv;
+/** max number of targets spawned for a query and its subqueries */
+#define MAX_TARGET_COUNT 32
/** max number of query restarts. Determines max number of CNAME chain. */
#define MAX_RESTART_COUNT 8
/** max number of referrals. Makes sure resolver does not run away */
@@ -254,6 +256,10 @@ struct iter_qstate {
/** number of queries fired off */
int sent_count;
+
+ /** number of target queries spawned in [1], for this query and its
+ * subqueries, the malloced-array is shared, [0] refcount. */
+ int* target_count;
/**
* The query must store NS records from referrals as parentside RRs
Modified: releng/10.0/sys/conf/newvers.sh
==============================================================================
--- releng/10.0/sys/conf/newvers.sh Wed Dec 17 06:58:00 2014 (r275853)
+++ releng/10.0/sys/conf/newvers.sh Wed Dec 17 06:59:47 2014 (r275854)
@@ -32,7 +32,7 @@
TYPE="FreeBSD"
REVISION="10.0"
-BRANCH="RELEASE-p13"
+BRANCH="RELEASE-p14"
if [ "X${BRANCH_OVERRIDE}" != "X" ]; then
BRANCH=${BRANCH_OVERRIDE}
fi
Modified: releng/10.1/UPDATING
==============================================================================
--- releng/10.1/UPDATING Wed Dec 17 06:58:00 2014 (r275853)
+++ releng/10.1/UPDATING Wed Dec 17 06:59:47 2014 (r275854)
@@ -16,6 +16,9 @@ from older versions of FreeBSD, try WITH
stable/10, and then rebuild without this option. The bootstrap process from
older version of current is a bit fragile.
+20141217: p2 FreeBSD-SA-14:30.unbound
+ Fix unbound remote denial of service vulnerability.
+
20141210: p1 FreeBSD-SA-14:27.stdio
FreeBSD-SA-14:28.file
Modified: releng/10.1/contrib/unbound/iterator/iterator.c
==============================================================================
--- releng/10.1/contrib/unbound/iterator/iterator.c Wed Dec 17 06:58:00 2014 (r275853)
+++ releng/10.1/contrib/unbound/iterator/iterator.c Wed Dec 17 06:59:47 2014 (r275854)
@@ -120,6 +120,7 @@ iter_new(struct module_qstate* qstate, i
iq->query_restart_count = 0;
iq->referral_count = 0;
iq->sent_count = 0;
+ iq->target_count = NULL;
iq->wait_priming_stub = 0;
iq->refetch_glue = 0;
iq->dnssec_expected = 0;
@@ -445,6 +446,26 @@ handle_cname_response(struct module_qsta
return 1;
}
+/** create target count structure for this query */
+static void
+target_count_create(struct iter_qstate* iq)
+{
+ if(!iq->target_count) {
+ iq->target_count = (int*)calloc(2, sizeof(int));
+ /* if calloc fails we simply do not track this number */
+ if(iq->target_count)
+ iq->target_count[0] = 1;
+ }
+}
+
+static void
+target_count_increase(struct iter_qstate* iq, int num)
+{
+ target_count_create(iq);
+ if(iq->target_count)
+ iq->target_count[1] += num;
+}
+
/**
* Generate a subrequest.
* Generate a local request event. Local events are tied to this module, and
@@ -516,6 +537,10 @@ generate_sub_request(uint8_t* qname, siz
subiq = (struct iter_qstate*)subq->minfo[id];
memset(subiq, 0, sizeof(*subiq));
subiq->num_target_queries = 0;
+ target_count_create(iq);
+ subiq->target_count = iq->target_count;
+ if(iq->target_count)
+ iq->target_count[0] ++; /* extra reference */
subiq->num_current_queries = 0;
subiq->depth = iq->depth+1;
outbound_list_init(&subiq->outlist);
@@ -1342,6 +1367,12 @@ query_for_targets(struct module_qstate*
if(iq->depth == ie->max_dependency_depth)
return 0;
+ if(iq->depth > 0 && iq->target_count &&
+ iq->target_count[1] > MAX_TARGET_COUNT) {
+ verbose(VERB_QUERY, "request has exceeded the maximum "
+ "number of glue fetches %d", iq->target_count[1]);
+ return 0;
+ }
iter_mark_cycle_targets(qstate, iq->dp);
missing = (int)delegpt_count_missing_targets(iq->dp);
@@ -1524,6 +1555,7 @@ processLastResort(struct module_qstate*
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += qs;
+ target_count_increase(iq, qs);
if(qs != 0) {
qstate->ext_state[id] = module_wait_subquery;
return 0; /* and wait for them */
@@ -1533,6 +1565,12 @@ processLastResort(struct module_qstate*
verbose(VERB_QUERY, "maxdepth and need more nameservers, fail");
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
+ if(iq->depth > 0 && iq->target_count &&
+ iq->target_count[1] > MAX_TARGET_COUNT) {
+ verbose(VERB_QUERY, "request has exceeded the maximum "
+ "number of glue fetches %d", iq->target_count[1]);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
/* mark cycle targets for parent-side lookups */
iter_mark_pside_cycle_targets(qstate, iq->dp);
/* see if we can issue queries to get nameserver addresses */
@@ -1562,6 +1600,7 @@ processLastResort(struct module_qstate*
if(query_count != 0) { /* suspend to await results */
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;
}
@@ -1717,6 +1756,7 @@ processQueryTargets(struct module_qstate
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += extra;
+ target_count_increase(iq, extra);
if(iq->num_target_queries > 0) {
/* wait to get all targets, we want to try em */
verbose(VERB_ALGO, "wait for all targets for fallback");
@@ -1757,6 +1797,7 @@ processQueryTargets(struct module_qstate
/* errors ignored, these targets are not strictly necessary for
* this result, we do not have to reply with SERVFAIL */
iq->num_target_queries += extra;
+ target_count_increase(iq, extra);
}
/* Add the current set of unused targets to our queue. */
@@ -1802,6 +1843,7 @@ processQueryTargets(struct module_qstate
return 1;
}
iq->num_target_queries += qs;
+ target_count_increase(iq, qs);
}
/* Since a target query might have been made, we
* need to check again. */
@@ -2894,6 +2936,8 @@ iter_clear(struct module_qstate* qstate,
iq = (struct iter_qstate*)qstate->minfo[id];
if(iq) {
outbound_list_clear(&iq->outlist);
+ if(iq->target_count && --iq->target_count[0] == 0)
+ free(iq->target_count);
iq->num_current_queries = 0;
}
qstate->minfo[id] = NULL;
Modified: releng/10.1/contrib/unbound/iterator/iterator.h
==============================================================================
--- releng/10.1/contrib/unbound/iterator/iterator.h Wed Dec 17 06:58:00 2014 (r275853)
+++ releng/10.1/contrib/unbound/iterator/iterator.h Wed Dec 17 06:59:47 2014 (r275854)
@@ -52,6 +52,8 @@ struct iter_donotq;
struct iter_prep_list;
struct iter_priv;
+/** max number of targets spawned for a query and its subqueries */
+#define MAX_TARGET_COUNT 32
/** max number of query restarts. Determines max number of CNAME chain. */
#define MAX_RESTART_COUNT 8
/** max number of referrals. Makes sure resolver does not run away */
@@ -254,6 +256,10 @@ struct iter_qstate {
/** number of queries fired off */
int sent_count;
+
+ /** number of target queries spawned in [1], for this query and its
+ * subqueries, the malloced-array is shared, [0] refcount. */
+ int* target_count;
/**
* The query must store NS records from referrals as parentside RRs
Modified: releng/10.1/sys/conf/newvers.sh
==============================================================================
--- releng/10.1/sys/conf/newvers.sh Wed Dec 17 06:58:00 2014 (r275853)
+++ releng/10.1/sys/conf/newvers.sh Wed Dec 17 06:59:47 2014 (r275854)
@@ -32,7 +32,7 @@
TYPE="FreeBSD"
REVISION="10.1"
-BRANCH="RELEASE-p1"
+BRANCH="RELEASE-p2"
if [ "X${BRANCH_OVERRIDE}" != "X" ]; then
BRANCH=${BRANCH_OVERRIDE}
fi
More information about the svn-src-releng
mailing list