Fix unbound remote denial of service vulnerability.

Security:	FreeBSD-SA-14:30.unbound
Security:	CVE-2014-8602
Approved by:	so
This commit is contained in:
delphij 2014-12-17 06:59:47 +00:00 committed by Franco Fichtner
parent 0bdd02b5ef
commit 7d90aec705
4 changed files with 54 additions and 1 deletions

View file

@ -16,6 +16,9 @@ from older versions of FreeBSD, try WITHOUT_CLANG to bootstrap to the tip of
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).

View file

@ -117,6 +117,7 @@ iter_new(struct module_qstate* qstate, int id)
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_qstate* qstate, struct iter_qstate* iq,
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, size_t qnamelen, uint16_t qtype,
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* qstate, struct iter_qstate* iq,
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* qstate, struct iter_qstate* iq,
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* qstate, struct iter_qstate* iq,
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* qstate, struct iter_qstate* iq,
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* qstate, struct iter_qstate* iq,
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* qstate, struct iter_qstate* iq,
/* 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* qstate, struct iter_qstate* iq,
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, int id)
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;

View file

@ -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

View file

@ -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