]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix reference counting in get_attached_entry
authorOndřej Surý <ondrej@isc.org>
Tue, 6 Dec 2022 14:59:35 +0000 (15:59 +0100)
committerOndřej Surý <ondrej@isc.org>
Wed, 7 Dec 2022 15:16:22 +0000 (16:16 +0100)
When get_attached_entry() encounters entry that would be expired, it
needs to get reference to the entry before calling maybe_expire_entry(),
so the ADB entry doesn't get destroyed inside the its own lock.

lib/dns/adb.c

index b3d962f3c2f34a0f26c7cdbe3833d10bfa90fb87..6f6b2ac78d2f25e453d86ef64f2bf1fa84ab9df7 100644 (file)
@@ -1358,15 +1358,18 @@ get_attached_name(dns_adb_t *adb, const dns_name_t *name, bool start_at_zone,
        case ISC_R_NOTFOUND:
                /* Allocate a new name and add it to the hash table. */
                adbname = new_adbname(adb, name, start_at_zone);
+               dns_adbname_ref(adbname);
+               adbname->last_used = now;
+
                result = isc_hashmap_add(adb->names, &hashval,
                                         &adbname->key.key, adbname->key.size,
                                         adbname);
                INSIST(result == ISC_R_SUCCESS);
 
                ISC_LIST_PREPEND(adb->names_lru, adbname, link);
-               adbname->last_used = now;
                break;
        case ISC_R_SUCCESS:
+               dns_adbname_ref(adbname);
                LOCK(&adbname->lock);
                if (adbname->last_used + ADB_STALE_MARGIN <= last_update) {
                        adbname->last_used = now;
@@ -1384,8 +1387,6 @@ get_attached_name(dns_adb_t *adb, const dns_name_t *name, bool start_at_zone,
         * expire_name() - the unused adbname stored in the hashtable and lru
         * has always refcount == 1
         */
-       dns_adbname_ref(adbname);
-
        UNLOCK(&adb->names_lock);
 
        return (adbname);
@@ -1424,16 +1425,19 @@ get_attached_entry(dns_adb_t *adb, isc_stdtime_t now,
        create:
                /* Allocate a new entry and add it to the hash table. */
                adbentry = new_adbentry(adb, addr);
+               dns_adbentry_ref(adbentry);
+               adbentry->last_used = now;
+
                result = isc_hashmap_add(adb->entries, &hashval,
                                         &adbentry->sockaddr,
                                         sizeof(adbentry->sockaddr), adbentry);
                INSIST(result == ISC_R_SUCCESS);
 
                ISC_LIST_PREPEND(adb->entries_lru, adbentry, link);
-               adbentry->last_used = now;
                break;
        }
        case ISC_R_SUCCESS:
+               dns_adbentry_ref(adbentry);
                LOCK(&adbentry->lock);
                if (maybe_expire_entry(adbentry, now)) {
                        UNLOCK(&adbentry->lock);
@@ -1451,7 +1455,6 @@ get_attached_entry(dns_adb_t *adb, isc_stdtime_t now,
        default:
                UNREACHABLE();
        }
-       dns_adbentry_ref(adbentry);
 
        UNLOCK(&adb->entries_lock);