From: Mark Andrews Date: Thu, 5 Nov 2015 06:43:30 +0000 (+1100) Subject: 4254. [bug] Address missing lock when getting zone's serial. X-Git-Tag: v9.11.0a1~327^2~13 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=29868ebbe3c7bc06f833e329ea190dc442331bf1;p=thirdparty%2Fbind9.git 4254. [bug] Address missing lock when getting zone's serial. [RT #41072] --- diff --git a/CHANGES b/CHANGES index de92dc66473..39f264f4bde 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4254. [bug] Address missing lock when getting zone's serial. + [RT #41072] + 4253. [bug] Address fetch context reference count handling error on socket error. [RT#40945] diff --git a/lib/dns/zone.c b/lib/dns/zone.c index d38f11f50a5..de41f176fe8 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -9769,6 +9769,7 @@ static void dump_done(void *arg, isc_result_t result) { const char me[] = "dump_done"; dns_zone_t *zone = arg; + dns_zone_t *secure = NULL; dns_db_t *db; dns_dbversion_t *version; isc_boolean_t again = ISC_FALSE; @@ -9782,30 +9783,54 @@ dump_done(void *arg, isc_result_t result) { if (result == ISC_R_SUCCESS && zone->journal != NULL && zone->journalsize != -1) { - /* * We don't own these, zone->dctx must stay valid. */ db = dns_dumpctx_db(zone->dctx); version = dns_dumpctx_version(zone->dctx); - tresult = dns_db_getsoaserial(db, version, &serial); + + /* + * Handle lock order inversion. + */ + again: + LOCK_ZONE(zone); + if (inline_raw(zone)) { + secure = zone->secure; + INSIST(secure != zone); + TRYLOCK_ZONE(result, secure); + if (result != ISC_R_SUCCESS) { + UNLOCK_ZONE(zone); + secure = NULL; +#if ISC_PLATFORM_USETHREADS + isc_thread_yield(); +#endif + goto again; + } + } + /* * If there is a secure version of this zone * use its serial if it is less than ours. */ - if (tresult == ISC_R_SUCCESS && inline_raw(zone) && - zone->secure->db != NULL) - { + if (tresult == ISC_R_SUCCESS && secure != NULL) { isc_uint32_t sserial; isc_result_t mresult; - mresult = dns_db_getsoaserial(zone->secure->db, - NULL, &sserial); - if (mresult == ISC_R_SUCCESS && - isc_serial_lt(sserial, serial)) - serial = sserial; + ZONEDB_LOCK(&secure->dblock, isc_rwlocktype_read); + if (secure->db != NULL) { + mresult = dns_db_getsoaserial(zone->secure->db, + NULL, &sserial); + if (mresult == ISC_R_SUCCESS && + isc_serial_lt(sserial, serial)) + serial = sserial; + } + ZONEDB_UNLOCK(&secure->dblock, isc_rwlocktype_read); } + if (secure != NULL) + UNLOCK_ZONE(secure); + UNLOCK_ZONE(zone); + /* * Note: we are task locked here so we can test * zone->xfr safely.