]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Address races in dns_tsigkey_find()
authorMark Andrews <marka@isc.org>
Wed, 28 Jun 2023 23:15:38 +0000 (09:15 +1000)
committerMichał Kępień <michal@isc.org>
Fri, 5 Jan 2024 10:16:12 +0000 (11:16 +0100)
1) Restart the process with a write lock if we discover an expired key
while holding the read lock.

2) Move incrementing the key reference inside the lock block of code.

lib/dns/tsig.c

index 5583688e88a61f45b136370534b4116b6af419d8..e4821194c08ee6c38ff9023e02ed136e35abcf27 100644 (file)
@@ -1539,38 +1539,44 @@ isc_result_t
 dns_tsigkey_find(dns_tsigkey_t **tsigkey, const dns_name_t *name,
                 const dns_name_t *algorithm, dns_tsigkeyring_t *ring) {
        dns_tsigkey_t *key = NULL;
-       isc_stdtime_t now = isc_stdtime_now();
        isc_result_t result;
+       isc_rwlocktype_t locktype = isc_rwlocktype_read;
+       isc_stdtime_t now = isc_stdtime_now();
 
        REQUIRE(name != NULL);
        REQUIRE(VALID_TSIGKEYRING(ring));
        REQUIRE(tsigkey != NULL && *tsigkey == NULL);
 
-       RWLOCK(&ring->lock, isc_rwlocktype_read);
+again:
+       RWLOCK(&ring->lock, locktype);
        result = isc_hashmap_find(ring->keys, dns_name_hash(name), tkey_match,
                                  name, (void **)&key);
        if (result == ISC_R_NOTFOUND) {
-               RWUNLOCK(&ring->lock, isc_rwlocktype_read);
+               RWUNLOCK(&ring->lock, locktype);
                return (result);
        }
        if (algorithm != NULL && !dns_name_equal(key->algorithm, algorithm)) {
-               RWUNLOCK(&ring->lock, isc_rwlocktype_read);
+               RWUNLOCK(&ring->lock, locktype);
                return (ISC_R_NOTFOUND);
        }
        if (key->inception != key->expire && isc_serial_lt(key->expire, now)) {
                /*
                 * The key has expired.
                 */
-               RWUNLOCK(&ring->lock, isc_rwlocktype_read);
-               RWLOCK(&ring->lock, isc_rwlocktype_write);
+               if (locktype == isc_rwlocktype_read) {
+                       RWUNLOCK(&ring->lock, locktype);
+                       locktype = isc_rwlocktype_write;
+                       key = NULL;
+                       goto again;
+               }
                rm_lru(key);
                rm_hashmap(key);
-               RWUNLOCK(&ring->lock, isc_rwlocktype_write);
+               RWUNLOCK(&ring->lock, locktype);
                return (ISC_R_NOTFOUND);
        }
-       RWUNLOCK(&ring->lock, isc_rwlocktype_read);
-       adjust_lru(key);
        dns_tsigkey_ref(key);
+       RWUNLOCK(&ring->lock, locktype);
+       adjust_lru(key);
        *tsigkey = key;
        return (ISC_R_SUCCESS);
 }