diff --git a/CHANGES b/CHANGES index 9c17e8462a..1890342708 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +3298. [bug] Named could dereference a NULL pointer in + zmgr_start_xfrin_ifquota if the zone was being removed. + [RT #28419] + 3297. [bug] Named could die on a malformed master file. [RT #28467] 3296. [bug] Named could die with a INSIST failure in diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 7cc8859d45..bda3c5158a 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -13165,11 +13165,13 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { * This transfer finishing freed up a transfer quota slot. * Let any other zones waiting for quota have it. */ + UNLOCK_ZONE(zone); RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); ISC_LIST_UNLINK(zone->zmgr->xfrin_in_progress, zone, statelink); zone->statelist = NULL; zmgr_resume_xfrs(zone->zmgr, ISC_FALSE); RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); + LOCK_ZONE(zone); /* * Retry with a different server if necessary. @@ -14137,13 +14139,23 @@ zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) { isc_uint32_t maxtransfersin, maxtransfersperns; isc_event_t *e; + /* + * If we are exiting just pretend we got quota so the zone will + * be cleaned up in the zone's task context. + */ + LOCK_ZONE(zone); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { + UNLOCK_ZONE(zone); + goto gotquota; + } + /* * Find any configured information about the server we'd * like to transfer this zone from. */ isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); - (void)dns_peerlist_peerbyaddr(zone->view->peers, - &masterip, &peer); + (void)dns_peerlist_peerbyaddr(zone->view->peers, &masterip, &peer); + UNLOCK_ZONE(zone); /* * Determine the total maximum number of simultaneous @@ -14167,7 +14179,11 @@ zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) { x = ISC_LIST_NEXT(x, statelink)) { isc_netaddr_t xip; + + LOCK_ZONE(x); isc_netaddr_fromsockaddr(&xip, &x->masteraddr); + UNLOCK_ZONE(x); + nxfrsin++; if (isc_netaddr_equal(&xip, &masterip)) nxfrsperns++; @@ -14180,15 +14196,14 @@ zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) { if (nxfrsperns >= maxtransfersperns) return (ISC_R_QUOTA); + gotquota: /* * We have sufficient quota. Move the zone to the "xfrin_in_progress" * list and send it an event to let it start the actual transfer in the * context of its own task. */ - e = isc_event_allocate(zmgr->mctx, zmgr, - DNS_EVENT_ZONESTARTXFRIN, - got_transfer_quota, zone, - sizeof(isc_event_t)); + e = isc_event_allocate(zmgr->mctx, zmgr, DNS_EVENT_ZONESTARTXFRIN, + got_transfer_quota, zone, sizeof(isc_event_t)); if (e == NULL) return (ISC_R_NOMEMORY);