From 95e65c9b9ffd811c83e0a54bed593d0e0cc13e24 Mon Sep 17 00:00:00 2001 From: Antonio Russo Date: Sat, 6 Mar 2021 03:18:46 -0700 Subject: [PATCH] Acquire sk_dk_lock during spa_keystore_lookup_key As seen in #11490, dck_holds may be incremented (acquired) after the check in dsl_crypto_key_rele, but before the completion of dsl_crypto_key_free. All other published accesses to dsl_crypto_key-> dck_holds (i.e., spa_keystore_dsl_key_hold_impl) are protected by its parent spa->sk_dk_lock. We avoid the race by also aquiring sk_dk_lock during during spa_keystore_lookup_key's critical section. Signed-off-by: Antonio Russo --- module/zfs/dsl_crypt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/module/zfs/dsl_crypt.c b/module/zfs/dsl_crypt.c index e38ec0cae8..6e39dee58f 100644 --- a/module/zfs/dsl_crypt.c +++ b/module/zfs/dsl_crypt.c @@ -1095,6 +1095,7 @@ spa_keystore_lookup_key(spa_t *spa, uint64_t dsobj, void *tag, /* init the search key mapping */ search_km.km_dsobj = dsobj; + rw_enter(&spa->spa_keystore.sk_dk_lock, RW_READER); rw_enter(&spa->spa_keystore.sk_km_lock, RW_READER); /* remove the mapping from the tree */ @@ -1109,6 +1110,7 @@ spa_keystore_lookup_key(spa_t *spa, uint64_t dsobj, void *tag, zfs_refcount_add(&found_km->km_key->dck_holds, tag); rw_exit(&spa->spa_keystore.sk_km_lock); + rw_exit(&spa->spa_keystore.sk_dk_lock); if (dck_out != NULL) *dck_out = found_km->km_key; @@ -1116,6 +1118,7 @@ spa_keystore_lookup_key(spa_t *spa, uint64_t dsobj, void *tag, error_unlock: rw_exit(&spa->spa_keystore.sk_km_lock); + rw_exit(&spa->spa_keystore.sk_dk_lock); if (dck_out != NULL) *dck_out = NULL;