]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
4254. [bug] Address missing lock when getting zone's serial.
authorMark Andrews <marka@isc.org>
Thu, 5 Nov 2015 06:43:30 +0000 (17:43 +1100)
committerMark Andrews <marka@isc.org>
Thu, 5 Nov 2015 06:43:30 +0000 (17:43 +1100)
                        [RT #41072]

CHANGES
lib/dns/zone.c

diff --git a/CHANGES b/CHANGES
index de92dc664730f028a86e28ef00fb76b2ac0c7a8e..39f264f4bdedbf8f6507207b1128acbeb971bf1d 100644 (file)
--- 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]
 
index d38f11f50a518a23cadab1952b5b41582ca5a812..de41f176fe825bed3f154887a7fe52cfc1feec66 100644 (file)
@@ -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.