aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Percival <cperciva@FreeBSD.org>2007-02-09 20:24:15 +0000
committerColin Percival <cperciva@FreeBSD.org>2007-02-09 20:24:15 +0000
commit1872069d5fc7db3bf2335cfb43301ef3d98b0c31 (patch)
tree02f48cd9330a3199441b93bf528dddcce3dcdef9
parenta06da17a53955a2c8448db69eb4a3ff521aa7bf4 (diff)
downloadsrc-1872069d5fc7db3bf2335cfb43301ef3d98b0c31.tar.gz
src-1872069d5fc7db3bf2335cfb43301ef3d98b0c31.zip
Correct two remote denials of service in BIND involving DNSSEC and
recursive DNS queries respectively. Security: FreeBSD-SA-07:02.bind Approved by: so (cperciva)
Notes
Notes: svn path=/releng/5.5/; revision=166606
-rw-r--r--UPDATING4
-rw-r--r--contrib/bind9/lib/dns/include/dns/validator.h10
-rw-r--r--contrib/bind9/lib/dns/resolver.c49
-rw-r--r--contrib/bind9/lib/dns/validator.c24
-rw-r--r--sys/conf/newvers.sh2
5 files changed, 81 insertions, 8 deletions
diff --git a/UPDATING b/UPDATING
index 1da4c1e2538e..519b1e58e27f 100644
--- a/UPDATING
+++ b/UPDATING
@@ -8,6 +8,10 @@ Items affecting the ports and packages system can be found in
/usr/ports/UPDATING. Please read that file before running
portupgrade.
+20070209 p11 FreeBSD-SA-07:02.bind
+ Correct two remote denials of service in BIND involving DNSSEC and
+ recursive DNS queries respectively.
+
20070111: p10 FreeBSD-SA-07:01.jail
Correct jail rc.d script privilege escalation.
diff --git a/contrib/bind9/lib/dns/include/dns/validator.h b/contrib/bind9/lib/dns/include/dns/validator.h
index 24769f3c88a5..65ded0488c56 100644
--- a/contrib/bind9/lib/dns/include/dns/validator.h
+++ b/contrib/bind9/lib/dns/include/dns/validator.h
@@ -129,6 +129,7 @@ struct dns_validator {
};
#define DNS_VALIDATOR_DLV 1
+#define DNS_VALIDATOR_DEFER 2
ISC_LANG_BEGINDECLS
@@ -173,6 +174,15 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
*/
void
+dns_validator_send(dns_validator_t *validator);
+/*%<
+ * Send a deferred validation request
+ *
+ * Requires:
+ * 'validator' to points to a valid DNSSEC validator.
+ */
+
+void
dns_validator_cancel(dns_validator_t *validator);
/*
* Cancel a DNSSEC validation in progress.
diff --git a/contrib/bind9/lib/dns/resolver.c b/contrib/bind9/lib/dns/resolver.c
index 06752f7eb4e9..b82e7d8f1d22 100644
--- a/contrib/bind9/lib/dns/resolver.c
+++ b/contrib/bind9/lib/dns/resolver.c
@@ -215,6 +215,11 @@ struct fetchctx {
dns_name_t nsname;
dns_fetch_t * nsfetch;
dns_rdataset_t nsrrset;
+
+ /*%
+ * Number of queries that reference this context.
+ */
+ unsigned int nqueries;
};
#define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!')
@@ -348,6 +353,7 @@ static isc_result_t ncache_adderesult(dns_message_t *message,
dns_rdataset_t *ardataset,
isc_result_t *eresultp);
static void validated(isc_task_t *task, isc_event_t *event);
+static void maybe_destroy(fetchctx_t *fctx);
static isc_result_t
valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
@@ -366,6 +372,9 @@ valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
valarg->fctx = fctx;
valarg->addrinfo = addrinfo;
+ if (!ISC_LIST_EMPTY(fctx->validators))
+ INSIST((valoptions & DNS_VALIDATOR_DEFER) != 0);
+
result = dns_validator_create(fctx->res->view, name, type, rdataset,
sigrdataset, fctx->rmessage,
valoptions, task, validated, valarg,
@@ -513,6 +522,9 @@ resquery_destroy(resquery_t **queryp) {
INSIST(query->tcpsocket == NULL);
+ query->fctx->nqueries--;
+ if (SHUTTINGDOWN(query->fctx))
+ maybe_destroy(query->fctx); /* Locks bucket. */
query->magic = 0;
isc_mem_put(query->mctx, query, sizeof(*query));
*queryp = NULL;
@@ -971,6 +983,8 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
if (result != ISC_R_SUCCESS)
return (result);
+ INSIST(ISC_LIST_EMPTY(fctx->validators));
+
dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
query = isc_mem_get(res->mctx, sizeof(*query));
@@ -1084,6 +1098,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
}
ISC_LIST_APPEND(fctx->queries, query, link);
+ query->fctx->nqueries++;
return (ISC_R_SUCCESS);
@@ -1530,7 +1545,7 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
want_done = ISC_TRUE;
}
} else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 &&
- ISC_LIST_EMPTY(fctx->validators)) {
+ fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) {
bucketnum = fctx->bucketnum;
LOCK(&res->buckets[bucketnum].lock);
/*
@@ -2384,8 +2399,8 @@ fctx_destroy(fetchctx_t *fctx) {
REQUIRE(ISC_LIST_EMPTY(fctx->finds));
REQUIRE(ISC_LIST_EMPTY(fctx->altfinds));
REQUIRE(fctx->pending == 0);
- REQUIRE(ISC_LIST_EMPTY(fctx->validators));
REQUIRE(fctx->references == 0);
+ REQUIRE(ISC_LIST_EMPTY(fctx->validators));
FCTXTRACE("destroy");
@@ -2559,7 +2574,7 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
}
if (fctx->references == 0 && fctx->pending == 0 &&
- ISC_LIST_EMPTY(fctx->validators))
+ fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators))
bucket_empty = fctx_destroy(fctx);
UNLOCK(&res->buckets[bucketnum].lock);
@@ -2600,6 +2615,7 @@ fctx_start(isc_task_t *task, isc_event_t *event) {
* pending ADB finds and no pending validations.
*/
INSIST(fctx->pending == 0);
+ INSIST(fctx->nqueries == 0);
INSIST(ISC_LIST_EMPTY(fctx->validators));
if (fctx->references == 0) {
/*
@@ -2761,6 +2777,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
fctx->restarts = 0;
fctx->timeouts = 0;
fctx->attributes = 0;
+ fctx->nqueries = 0;
dns_name_init(&fctx->nsname, NULL);
fctx->nsfetch = NULL;
@@ -3083,12 +3100,21 @@ maybe_destroy(fetchctx_t *fctx) {
unsigned int bucketnum;
isc_boolean_t bucket_empty = ISC_FALSE;
dns_resolver_t *res = fctx->res;
+ dns_validator_t *validator;
REQUIRE(SHUTTINGDOWN(fctx));
- if (fctx->pending != 0 || !ISC_LIST_EMPTY(fctx->validators))
+ if (fctx->pending != 0 || fctx->nqueries != 0)
return;
+ for (validator = ISC_LIST_HEAD(fctx->validators);
+ validator != NULL;
+ validator = ISC_LIST_HEAD(fctx->validators)) {
+ ISC_LIST_UNLINK(fctx->validators, validator, link);
+ dns_validator_cancel(validator);
+ dns_validator_destroy(&validator);
+ }
+
bucketnum = fctx->bucketnum;
LOCK(&res->buckets[bucketnum].lock);
if (fctx->references == 0)
@@ -3219,7 +3245,9 @@ validated(isc_task_t *task, isc_event_t *event) {
result = vevent->result;
add_bad(fctx, &addrinfo->sockaddr, result);
isc_event_free(&event);
- if (sentresponse)
+ if (!ISC_LIST_EMPTY(fctx->validators))
+ dns_validator_send(ISC_LIST_HEAD(fctx->validators));
+ else if (sentresponse)
fctx_done(fctx, result);
else
fctx_try(fctx);
@@ -3315,6 +3343,7 @@ validated(isc_task_t *task, isc_event_t *event) {
* more rdatasets that still need to
* be validated.
*/
+ dns_validator_send(ISC_LIST_HEAD(fctx->validators));
goto cleanup_event;
}
@@ -3623,6 +3652,13 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
rdataset,
sigrdataset,
valoptions, task);
+ /*
+ * Defer any further validations.
+ * This prevents multiple validators
+ * from manipulating fctx->rmessage
+ * simultaniously.
+ */
+ valoptions |= DNS_VALIDATOR_DEFER;
}
} else if (CHAINING(rdataset)) {
if (rdataset->type == dns_rdatatype_cname)
@@ -6346,7 +6382,8 @@ dns_resolver_destroyfetch(dns_fetch_t **fetchp) {
/*
* No one cares about the result of this fetch anymore.
*/
- if (fctx->pending == 0 && ISC_LIST_EMPTY(fctx->validators) &&
+ if (fctx->pending == 0 && fctx->nqueries == 0 &&
+ ISC_LIST_EMPTY(fctx->validators) &&
SHUTTINGDOWN(fctx)) {
/*
* This fctx is already shutdown; we were just
diff --git a/contrib/bind9/lib/dns/validator.c b/contrib/bind9/lib/dns/validator.c
index a62db3413768..8fc0e133dc65 100644
--- a/contrib/bind9/lib/dns/validator.c
+++ b/contrib/bind9/lib/dns/validator.c
@@ -2632,7 +2632,8 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
ISC_LINK_INIT(val, link);
val->magic = VALIDATOR_MAGIC;
- isc_task_send(task, ISC_EVENT_PTR(&event));
+ if ((options & DNS_VALIDATOR_DEFER) == 0)
+ isc_task_send(task, ISC_EVENT_PTR(&event));
*validatorp = val;
@@ -2650,6 +2651,21 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
}
void
+dns_validator_send(dns_validator_t *validator) {
+ isc_event_t *event;
+ REQUIRE(VALID_VALIDATOR(validator));
+
+ LOCK(&validator->lock);
+
+ INSIST((validator->options & DNS_VALIDATOR_DEFER) != 0);
+ event = (isc_event_t *)validator->event;
+ validator->options &= ~DNS_VALIDATOR_DEFER;
+ UNLOCK(&validator->lock);
+
+ isc_task_send(validator->task, ISC_EVENT_PTR(&event));
+}
+
+void
dns_validator_cancel(dns_validator_t *validator) {
REQUIRE(VALID_VALIDATOR(validator));
@@ -2663,6 +2679,12 @@ dns_validator_cancel(dns_validator_t *validator) {
if (validator->subvalidator != NULL)
dns_validator_cancel(validator->subvalidator);
+ if ((validator->options & DNS_VALIDATOR_DEFER) != 0) {
+ isc_task_t *task = validator->event->ev_sender;
+ validator->options &= ~DNS_VALIDATOR_DEFER;
+ isc_event_free((isc_event_t **)&validator->event);
+ isc_task_detach(&task);
+ }
}
UNLOCK(&validator->lock);
}
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
index ee612bad463a..80c900c5f58d 100644
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -32,7 +32,7 @@
TYPE="FreeBSD"
REVISION="5.5"
-BRANCH="RELEASE-p10"
+BRANCH="RELEASE-p11"
RELEASE="${REVISION}-${BRANCH}"
VERSION="${TYPE} ${RELEASE}"