]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] fix LOADPENDING issues
authorEvan Hunt <each@isc.org>
Mon, 23 Feb 2015 04:43:39 +0000 (20:43 -0800)
committerEvan Hunt <each@isc.org>
Mon, 23 Feb 2015 04:43:39 +0000 (20:43 -0800)
4063. [bug] Asynchronous zone loads were not handled
correctly when the zone load was already in
progress; this could trigger a crash in zt.c.
[RT #37573]

CHANGES
doc/arm/notes.xml
lib/dns/include/dns/zone.h
lib/dns/zone.c

diff --git a/CHANGES b/CHANGES
index 6f3e839055e476d8bace2dd2e83bc640f9a6f88e..7f4e739771df9bbfdc581a33acf35dd400769a7f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,8 @@
+4063.  [bug]           Asynchronous zone loads were not handled
+                       correctly when the zone load was already in
+                       progress; this could trigger a crash in zt.c.
+                       [RT #37573]
+
 4062.  [bug]           Fix an out-of-bounds read in RPZ code. If the
                        read succeeded, it doesn't result in a bug
                        during operation. If the read failed, named
index 61014532b8b1c9530e50fb66ab6182222a7263d5..9f09c1a8f4d5ff837d8ba0c257ec6fb0a5fc45a8 100644 (file)
        <para>
          Fixed some bugs in RFC 5011 trust anchor management,
          including a memory leak and a possible loss of state
-         information.[RT #38458]
+         information. [RT #38458]
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Asynchronous zone loads were not handled correctly when the
+         zone load was already in progress; this could trigger a crash
+         in zt.c. [RT #37573]
        </para>
       </listitem>
     </itemizedlist>
index 0a789ab0361dc1b3b84ae285c401b5789cc3f871..2d612238c3feb7eb99b8996eecbe02cf8a0b4673 100644 (file)
@@ -370,6 +370,15 @@ dns_zone_asyncload(dns_zone_t *zone, dns_zt_zoneloaded_t done, void *arg);
  * its first argument and 'zone' as its second.  (Normally, 'arg' is
  * expected to point to the zone table but is left undefined for testing
  * purposes.)
+ *
+ * Require:
+ *\li  'zone' to be a valid zone.
+ *
+ * Returns:
+ *\li  #ISC_R_ALREADYRUNNING
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_FAILURE
+ *\li  #ISC_R_NOMEMORY
  */
 
 isc_boolean_t
index c0577f38eb0f09aa712fd03c39463d16708eeb1d..7c42f1ec8376993ed5763c4ecaf8f3ab30a6e423 100644 (file)
@@ -1757,7 +1757,7 @@ zone_touched(dns_zone_t *zone) {
 }
 
 static isc_result_t
-zone_load(dns_zone_t *zone, unsigned int flags) {
+zone_load(dns_zone_t *zone, unsigned int flags, isc_boolean_t locked) {
        isc_result_t result;
        isc_time_t now;
        isc_time_t loadtime;
@@ -1766,13 +1766,16 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
 
        REQUIRE(DNS_ZONE_VALID(zone));
 
-       LOCK_ZONE(zone);
+       if (!locked)
+               LOCK_ZONE(zone);
+
        INSIST(zone != zone->raw);
        hasraw = inline_secure(zone);
        if (hasraw) {
-               result = zone_load(zone->raw, flags);
+               result = zone_load(zone->raw, flags, ISC_FALSE);
                if (result != ISC_R_SUCCESS) {
-                       UNLOCK_ZONE(zone);
+                       if (!locked)
+                               UNLOCK_ZONE(zone);
                        return(result);
                }
                LOCK_ZONE(zone->raw);
@@ -1981,7 +1984,8 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
  cleanup:
        if (hasraw)
                UNLOCK_ZONE(zone->raw);
-       UNLOCK_ZONE(zone);
+       if (!locked)
+               UNLOCK_ZONE(zone);
        if (db != NULL)
                dns_db_detach(&db);
        return (result);
@@ -1989,12 +1993,12 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
 
 isc_result_t
 dns_zone_load(dns_zone_t *zone) {
-       return (zone_load(zone, 0));
+       return (zone_load(zone, 0, ISC_FALSE));
 }
 
 isc_result_t
 dns_zone_loadnew(dns_zone_t *zone) {
-       return (zone_load(zone, DNS_ZONELOADFLAG_NOSTAT));
+       return (zone_load(zone, DNS_ZONELOADFLAG_NOSTAT, ISC_FALSE));
 }
 
 static void
@@ -2002,6 +2006,7 @@ zone_asyncload(isc_task_t *task, isc_event_t *event) {
        dns_asyncload_t *asl = event->ev_arg;
        dns_zone_t *zone = asl->zone;
        isc_result_t result = ISC_R_SUCCESS;
+       isc_boolean_t load_pending;
 
        UNUSED(task);
 
@@ -2010,13 +2015,21 @@ zone_asyncload(isc_task_t *task, isc_event_t *event) {
        if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0)
                result = ISC_R_CANCELED;
        isc_event_free(&event);
-       if (result == ISC_R_CANCELED ||
-           !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING))
-               goto cleanup;
 
-       zone_load(zone, 0);
+       if (result == ISC_R_CANCELED)
+               goto cleanup;
 
+       /* Make sure load is still pending */
        LOCK_ZONE(zone);
+       load_pending = ISC_TF(DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING));
+
+       if (!load_pending) {
+               UNLOCK_ZONE(zone);
+               goto cleanup;
+       }
+
+       zone_load(zone, 0, ISC_TRUE);
+
        DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADPENDING);
        UNLOCK_ZONE(zone);
 
@@ -2042,7 +2055,7 @@ dns_zone_asyncload(dns_zone_t *zone, dns_zt_zoneloaded_t done, void *arg) {
 
        /* If we already have a load pending, stop now */
        if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING))
-               done(arg, zone, NULL);
+               return (ISC_R_ALREADYRUNNING);
 
        asl = isc_mem_get(zone->mctx, sizeof (*asl));
        if (asl == NULL)
@@ -2085,9 +2098,10 @@ dns_zone_loadandthaw(dns_zone_t *zone) {
        isc_result_t result;
 
        if (inline_raw(zone))
-               result = zone_load(zone->secure, DNS_ZONELOADFLAG_THAW);
+               result = zone_load(zone->secure, DNS_ZONELOADFLAG_THAW,
+                                  ISC_FALSE);
        else
-               result = zone_load(zone, DNS_ZONELOADFLAG_THAW);
+               result = zone_load(zone, DNS_ZONELOADFLAG_THAW, ISC_FALSE);
 
        switch (result) {
        case DNS_R_CONTINUE: