Module Name: src Committed By: spz Date: Tue Jul 24 18:06:29 UTC 2012
Modified Files: src/external/bsd/bind/dist: CHANGES version src/external/bsd/bind/dist/bin/tests/system/stub: tests.sh src/external/bsd/bind/dist/lib/dns: resolver.c zone.c src/external/bsd/bind/dist/lib/isc/include/isc: queue.h Log Message: Fixes for CVE-2012-3817 and CVE-2012-3868 from ISC: --- 9.9.1-P2 released --- 3346. [security] Bad-cache data could be used before it was initialized, causing an assert. [RT #30025] 3345. [bug] Addressed race condition when removing the last item or inserting the first item in an ISC_QUEUE. [RT #29539] 3342. [bug] Change #3314 broke saving of stub zones to disk resulting in excessive cpu usage in some cases. [RT #29952] To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/external/bsd/bind/dist/CHANGES cvs rdiff -u -r1.1.1.11 -r1.2 src/external/bsd/bind/dist/version cvs rdiff -u -r1.1.1.3 -r1.2 \ src/external/bsd/bind/dist/bin/tests/system/stub/tests.sh cvs rdiff -u -r1.12 -r1.13 src/external/bsd/bind/dist/lib/dns/resolver.c cvs rdiff -u -r1.5 -r1.6 src/external/bsd/bind/dist/lib/dns/zone.c cvs rdiff -u -r1.1.1.1 -r1.2 \ src/external/bsd/bind/dist/lib/isc/include/isc/queue.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/external/bsd/bind/dist/CHANGES diff -u src/external/bsd/bind/dist/CHANGES:1.3 src/external/bsd/bind/dist/CHANGES:1.4 --- src/external/bsd/bind/dist/CHANGES:1.3 Tue Jun 5 00:38:46 2012 +++ src/external/bsd/bind/dist/CHANGES Tue Jul 24 18:06:28 2012 @@ -1,3 +1,16 @@ + --- 9.9.1-P2 released --- + +3346. [security] Bad-cache data could be used before it was + initialized, causing an assert. [RT #30025] + +3345. [bug] Addressed race condition when removing the last item + or inserting the first item in an ISC_QUEUE. + [RT #29539] + +3342. [bug] Change #3314 broke saving of stub zones to disk + resulting in excessive cpu usage in some cases. + [RT #29952] + --- 9.9.1-P1 released --- 3331. [security] dns_rdataslab_fromrdataset could produce bad Index: src/external/bsd/bind/dist/version diff -u src/external/bsd/bind/dist/version:1.1.1.11 src/external/bsd/bind/dist/version:1.2 --- src/external/bsd/bind/dist/version:1.1.1.11 Mon Jun 4 17:53:25 2012 +++ src/external/bsd/bind/dist/version Tue Jul 24 18:06:28 2012 @@ -7,4 +7,4 @@ MAJORVER=9 MINORVER=9 PATCHVER=1 RELEASETYPE=-P -RELEASEVER=1 +RELEASEVER=2 Index: src/external/bsd/bind/dist/bin/tests/system/stub/tests.sh diff -u src/external/bsd/bind/dist/bin/tests/system/stub/tests.sh:1.1.1.3 src/external/bsd/bind/dist/bin/tests/system/stub/tests.sh:1.2 --- src/external/bsd/bind/dist/bin/tests/system/stub/tests.sh:1.1.1.3 Mon Jun 4 17:54:37 2012 +++ src/external/bsd/bind/dist/bin/tests/system/stub/tests.sh Tue Jul 24 18:06:28 2012 @@ -21,14 +21,24 @@ SYSTEMTESTTOP=.. . $SYSTEMTESTTOP/conf.sh status=0 +echo "I:check that the stub zone has been saved to disk" +for i in 1 2 3 4 5 6 7 8 9 20 +do + [ -f ns3/child.example.st ] && break + sleep 1 +done +[ -f ns3/child.example.st ] || { status=1; echo "I:failed"; } + +for pass in 1 2 +do -echo "I:trying an axfr that should be denied (NOTAUTH)" +echo "I:trying an axfr that should be denied (NOTAUTH) (pass=$pass)" ret=0 -$DIG +tcp data.child.example. @10.53.0.3 axfr -p 5300 > dig.out.ns3 || ret=1 +$DIG +tcp child.example. @10.53.0.3 axfr -p 5300 > dig.out.ns3 || ret=1 grep "; Transfer failed." dig.out.ns3 > /dev/null || ret=1 [ $ret = 0 ] || { status=1; echo "I:failed"; } -echo "I:look for stub zone data without recursion (should not be found)" +echo "I:look for stub zone data without recursion (should not be found) (pass=$pass)" for i in 1 2 3 4 5 6 7 8 9 do ret=0 @@ -41,11 +51,20 @@ done $PERL ../digcomp.pl knowngood.dig.out.norec dig.out.ns3 || ret=1 [ $ret = 0 ] || { status=1; echo "I:failed"; } -echo "I:look for stub zone data with recursion (should be found)" +echo "I:look for stub zone data with recursion (should be found) (pass=$pass)" ret=0 $DIG +tcp data.child.example. @10.53.0.3 txt -p 5300 > dig.out.ns3 || ret=1 $PERL ../digcomp.pl knowngood.dig.out.rec dig.out.ns3 || ret=1 [ $ret = 0 ] || { status=1; echo "I:failed"; } +[ $pass = 1 ] && { + echo "I:stopping stub server" + $PERL $SYSTEMTESTTOP/stop.pl . ns3 + + echo "I:re-starting stub server" + $PERL $SYSTEMTESTTOP/start.pl --noclean --restart . ns3 +} +done + echo "I:exit status: $status" exit $status Index: src/external/bsd/bind/dist/lib/dns/resolver.c diff -u src/external/bsd/bind/dist/lib/dns/resolver.c:1.12 src/external/bsd/bind/dist/lib/dns/resolver.c:1.13 --- src/external/bsd/bind/dist/lib/dns/resolver.c:1.12 Tue Jun 5 00:41:39 2012 +++ src/external/bsd/bind/dist/lib/dns/resolver.c Tue Jul 24 18:06:28 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: resolver.c,v 1.12 2012/06/05 00:41:39 christos Exp $ */ +/* $NetBSD: resolver.c,v 1.13 2012/07/24 18:06:28 spz Exp $ */ /* * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") @@ -8452,6 +8452,7 @@ dns_resolver_addbadcache(dns_resolver_t goto cleanup; bad->type = type; bad->hashval = hashval; + bad->expire = *expire; isc_buffer_init(&buffer, bad + 1, name->length); dns_name_init(&bad->name, NULL); dns_name_copy(name, &bad->name, &buffer); @@ -8463,7 +8464,7 @@ dns_resolver_addbadcache(dns_resolver_t if (resolver->badcount < resolver->badhash * 2 && resolver->badhash > DNS_BADCACHE_SIZE) resizehash(resolver, &now, ISC_FALSE); - } + } else bad->expire = *expire; cleanup: UNLOCK(&resolver->lock); Index: src/external/bsd/bind/dist/lib/dns/zone.c diff -u src/external/bsd/bind/dist/lib/dns/zone.c:1.5 src/external/bsd/bind/dist/lib/dns/zone.c:1.6 --- src/external/bsd/bind/dist/lib/dns/zone.c:1.5 Tue Jun 5 00:41:43 2012 +++ src/external/bsd/bind/dist/lib/dns/zone.c Tue Jul 24 18:06:28 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: zone.c,v 1.5 2012/06/05 00:41:43 christos Exp $ */ +/* $NetBSD: zone.c,v 1.6 2012/07/24 18:06:28 spz Exp $ */ /* * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") @@ -8527,6 +8527,7 @@ zone_maintenance(dns_zone_t *zone) { case dns_zone_slave: case dns_zone_key: case dns_zone_redirect: + case dns_zone_stub: LOCK_ZONE(zone); if (zone->masterfile != NULL && isc_time_compare(&now, &zone->dumptime) >= 0 && @@ -8920,7 +8921,7 @@ zone_dump(dns_zone_t *zone, isc_boolean_ goto fail; } - if (compact) { + if (compact && zone->type != dns_zone_stub) { dns_zone_t *dummy = NULL; LOCK_ZONE(zone); zone_iattach(zone, &dummy); @@ -9826,7 +9827,7 @@ stub_callback(isc_task_t *task, isc_even dns_zone_t *zone = NULL; char master[ISC_SOCKADDR_FORMATSIZE]; char source[ISC_SOCKADDR_FORMATSIZE]; - isc_uint32_t nscnt, cnamecnt; + isc_uint32_t nscnt, cnamecnt, refresh, retry, expire; isc_result_t result; isc_time_t now; isc_boolean_t exiting = ISC_FALSE; @@ -9974,19 +9975,32 @@ stub_callback(isc_task_t *task, isc_even ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); if (zone->db == NULL) zone_attachdb(zone, stub->db); + result = zone_get_from_db(zone, zone->db, NULL, NULL, NULL, &refresh, + &retry, &expire, NULL, NULL); + if (result == ISC_R_SUCCESS) { + zone->refresh = RANGE(refresh, zone->minrefresh, + zone->maxrefresh); + zone->retry = RANGE(retry, zone->minretry, zone->maxretry); + zone->expire = RANGE(expire, zone->refresh + zone->retry, + DNS_MAX_EXPIRE); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS); + } ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); dns_db_detach(&stub->db); - if (zone->masterfile != NULL) - zone_needdump(zone, 0); - dns_message_destroy(&msg); isc_event_free(&event); dns_request_destroy(&zone->request); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime); isc_interval_set(&i, zone->expire, 0); DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime); + + if (zone->masterfile != NULL) + zone_needdump(zone, 0); + zone_settimer(zone, &now); goto free_stub; Index: src/external/bsd/bind/dist/lib/isc/include/isc/queue.h diff -u src/external/bsd/bind/dist/lib/isc/include/isc/queue.h:1.1.1.1 src/external/bsd/bind/dist/lib/isc/include/isc/queue.h:1.2 --- src/external/bsd/bind/dist/lib/isc/include/isc/queue.h:1.1.1.1 Mon Jun 4 17:56:50 2012 +++ src/external/bsd/bind/dist/lib/isc/include/isc/queue.h Tue Jul 24 18:06:29 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: queue.h,v 1.1.1.1 2012/06/04 17:56:50 christos Exp $ */ +/* $NetBSD: queue.h,v 1.2 2012/07/24 18:06:29 spz Exp $ */ /* * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") @@ -16,12 +16,13 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* Id */ - /* * This is a generic implementation of a two-lock concurrent queue. * There are built-in mutex locks for the head and tail of the queue, * allowing elements to be safely added and removed at the same time. + * + * NULL is "end of list" + * -1 is "not linked" */ #ifndef ISC_QUEUE_H @@ -36,67 +37,111 @@ #define ISC_QLINK_INSIST(x) (void)0 #endif -#define ISC_QLINK(type) struct { void *next; isc_boolean_t linked; } +#define ISC_QLINK(type) struct { void *prev, *next; } + #define ISC_QLINK_INIT(elt, link) \ do { \ - (elt)->link.next = (void *)(-1); \ - (elt)->link.linked = ISC_FALSE; \ + (elt)->link.next = (elt)->link.prev = (void *)(-1); \ } while (0) -#define ISC_QLINK_LINKED(elt, link) ((elt)->link.linked) + +#define ISC_QLINK_LINKED(elt, link) ((void*)(elt)->link.next != (void*)(-1)) #define ISC_QUEUE(type) struct { \ - type headnode; \ type *head, *tail; \ isc_mutex_t headlock, taillock; \ } #define ISC_QUEUE_INIT(queue, link) \ do { \ - isc_mutex_init(&(queue).headlock); \ isc_mutex_init(&(queue).taillock); \ - (queue).head = (void *) &((queue).headnode); \ - (queue).tail = (void *) &((queue).headnode); \ - ISC_QLINK_INIT((queue).head, link); \ + isc_mutex_init(&(queue).headlock); \ + (queue).tail = (queue).head = NULL; \ } while (0) -#define ISC_QUEUE_EMPTY(queue) ISC_TF((queue).head == (queue).tail) +#define ISC_QUEUE_EMPTY(queue) ISC_TF((queue).head == NULL) #define ISC_QUEUE_DESTROY(queue) \ do { \ ISC_QLINK_INSIST(ISC_QUEUE_EMPTY(queue)); \ - isc_mutex_destroy(&(queue).headlock); \ isc_mutex_destroy(&(queue).taillock); \ + isc_mutex_destroy(&(queue).headlock); \ } while (0) +/* + * queues are meant to separate the locks at either end. For best effect, that + * means keeping the ends separate - i.e. non-empty queues work best. + * + * a push to an empty queue has to take the pop lock to update + * the pop side of the queue. + * Popping the last entry has to take the push lock to update + * the push side of the queue. + * + * The order is (pop, push), because a pop is presumably in the + * latency path and a push is when we're done. + * + * We do an MT hot test in push to see if we need both locks, so we can + * acquire them in order. Hopefully that makes the case where we get + * the push lock and find we need the pop lock (and have to release it) rare. + * + * > 1 entry - no collision, push works on one end, pop on the other + * 0 entry - headlock race + * pop wins - return(NULL), push adds new as both head/tail + * push wins - updates head/tail, becomes 1 entry case. + * 1 entry - taillock race + * pop wins - return(pop) sets head/tail NULL, becomes 0 entry case + * push wins - updates {head,tail}->link.next, pop updates head + * with new ->link.next and doesn't update tail + * + */ #define ISC_QUEUE_PUSH(queue, elt, link) \ do { \ + isc_boolean_t headlocked = ISC_FALSE; \ ISC_QLINK_INSIST(!ISC_QLINK_LINKED(elt, link)); \ - (elt)->link.next = (void *)(-1); \ + if ((queue).head == NULL) { \ + LOCK(&(queue).headlock); \ + headlocked = ISC_TRUE; \ + } \ LOCK(&(queue).taillock); \ - (queue).tail->link.next = elt; \ - (queue).tail = elt; \ + if ((queue).tail == NULL && !headlocked) { \ + UNLOCK(&(queue).taillock); \ + LOCK(&(queue).headlock); \ + LOCK(&(queue).taillock); \ + headlocked = ISC_TRUE; \ + } \ + if ((queue).tail != NULL) \ + (queue).tail->link.next = (elt); \ + (elt)->link.prev = (queue).tail; \ + (elt)->link.next = NULL; \ + (queue).tail = (elt); \ UNLOCK(&(queue).taillock); \ - (elt)->link.linked = ISC_TRUE; \ + if (headlocked) { \ + if ((queue).head == NULL) \ + (queue).head = (elt); \ + UNLOCK(&(queue).headlock); \ + } \ } while (0) #define ISC_QUEUE_POP(queue, link, ret) \ do { \ LOCK(&(queue).headlock); \ - ret = (queue).head->link.next; \ - if (ret == (void *)(-1)) { \ - UNLOCK(&(queue).headlock); \ - ret = NULL; \ - } else { \ - (queue).head->link.next = ret->link.next; \ - if (ret->link.next == (void *)(-1)) { \ + ret = (queue).head; \ + while (ret != NULL) { \ + if (ret->link.next == NULL) { \ LOCK(&(queue).taillock); \ - (queue).tail = (queue).head; \ + if (ret->link.next == NULL) { \ + (queue).head = (queue).tail = NULL; \ UNLOCK(&(queue).taillock); \ + break; \ } \ - UNLOCK(&(queue).headlock); \ - ret->link.next = (void *)(-1); \ - ret->link.linked = ISC_FALSE; \ + UNLOCK(&(queue).taillock); \ + } \ + (queue).head = ret->link.next; \ + (queue).head->link.prev = NULL; \ + break; \ } \ + UNLOCK(&(queue).headlock); \ + if (ret != NULL) \ + (ret)->link.next = (ret)->link.prev = (void *)(-1); \ } while (0) #endif /* ISC_QUEUE_H */