From patchwork Thu May 4 04:09:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 13230764 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 176AAC77B78 for ; Thu, 4 May 2023 04:10:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229460AbjEDEKK (ORCPT ); Thu, 4 May 2023 00:10:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33642 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229661AbjEDEKG (ORCPT ); Thu, 4 May 2023 00:10:06 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0EFA11FDA; Wed, 3 May 2023 21:10:05 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 92B9B63176; Thu, 4 May 2023 04:10:04 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id CAAF8C4339B; Thu, 4 May 2023 04:10:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1683173404; bh=ZLj/BUleOh17v3haSnv1Hp/ZzkI9DqH73VidxAbBQ+U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EI6VYsyx+PFf01GU+nqGKOoMwj/T+6CDtohM+r9ioVv+R0CSW1Nz2nmquPDbkyOm/ Z5k+Glff4YtCOckUx7+lQ8f8Oib9xeqDjvMRuAZ5PCe9RvjVLI5jxBTYwtJ8Zd1D4i tUIxuMJ52GLEUtgeVCLkqEGAz0yTesfJXJDPs6pVjNYPZQpRGs8U8cZ8mXV1elDHiC 8UCOKxe4IBm9+AfCZ3yEFhoA6iZZQsA/rd+lE/yqDO3E4xi2xxTEYf9c1dpQrjuLiU 17089d8YHJ6my+Hze4alyQw21Hk4uSwtiF6epp8bv5HeUNxBIqKGCSan02A/xM2KV8 poaVbqQAS19nw== From: Eric Biggers To: stable@vger.kernel.org Cc: linux-block@vger.kernel.org, Nathan Huckleberry , Christoph Hellwig , Jens Axboe Subject: [PATCH 5.10 1/3] blk-mq: release crypto keyslot before reporting I/O complete Date: Wed, 3 May 2023 21:09:39 -0700 Message-Id: <20230504040941.152614-2-ebiggers@kernel.org> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230504040941.152614-1-ebiggers@kernel.org> References: <20230504040941.152614-1-ebiggers@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org From: Eric Biggers commit 9cd1e566676bbcb8a126acd921e4e194e6339603 upstream. Once all I/O using a blk_crypto_key has completed, filesystems can call blk_crypto_evict_key(). However, the block layer currently doesn't call blk_crypto_put_keyslot() until the request is being freed, which happens after upper layers have been told (via bio_endio()) the I/O has completed. This causes a race condition where blk_crypto_evict_key() can see 'slot_refs != 0' without there being an actual bug. This makes __blk_crypto_evict_key() hit the 'WARN_ON_ONCE(atomic_read(&slot->slot_refs) != 0)' and return without doing anything, eventually causing a use-after-free in blk_crypto_reprogram_all_keys(). (This is a very rare bug and has only been seen when per-file keys are being used with fscrypt.) There are two options to fix this: either release the keyslot before bio_endio() is called on the request's last bio, or make __blk_crypto_evict_key() ignore slot_refs. Let's go with the first solution, since it preserves the ability to report bugs (via WARN_ON_ONCE) where a key is evicted while still in-use. Fixes: a892c8d52c02 ("block: Inline encryption support for blk-mq") Cc: stable@vger.kernel.org Reviewed-by: Nathan Huckleberry Reviewed-by: Christoph Hellwig Signed-off-by: Eric Biggers Link: https://lore.kernel.org/r/20230315183907.53675-2-ebiggers@kernel.org Signed-off-by: Jens Axboe --- block/blk-core.c | 7 +++++++ block/blk-crypto-internal.h | 25 +++++++++++++++++++++---- block/blk-crypto.c | 24 ++++++++++++------------ block/blk-merge.c | 2 ++ block/blk-mq.c | 2 +- 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index 9afb79b322fb0..d0d0dd8151f75 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1444,6 +1444,13 @@ bool blk_update_request(struct request *req, blk_status_t error, req->q->integrity.profile->complete_fn(req, nr_bytes); #endif + /* + * Upper layers may call blk_crypto_evict_key() anytime after the last + * bio_endio(). Therefore, the keyslot must be released before that. + */ + if (blk_crypto_rq_has_keyslot(req) && nr_bytes >= blk_rq_bytes(req)) + __blk_crypto_rq_put_keyslot(req); + if (unlikely(error && !blk_rq_is_passthrough(req) && !(req->rq_flags & RQF_QUIET))) print_req_error(req, error, __func__); diff --git a/block/blk-crypto-internal.h b/block/blk-crypto-internal.h index 0d36aae538d7b..8e08345576203 100644 --- a/block/blk-crypto-internal.h +++ b/block/blk-crypto-internal.h @@ -60,6 +60,11 @@ static inline bool blk_crypto_rq_is_encrypted(struct request *rq) return rq->crypt_ctx; } +static inline bool blk_crypto_rq_has_keyslot(struct request *rq) +{ + return rq->crypt_keyslot; +} + #else /* CONFIG_BLK_INLINE_ENCRYPTION */ static inline bool bio_crypt_rq_ctx_compatible(struct request *rq, @@ -93,6 +98,11 @@ static inline bool blk_crypto_rq_is_encrypted(struct request *rq) return false; } +static inline bool blk_crypto_rq_has_keyslot(struct request *rq) +{ + return false; +} + #endif /* CONFIG_BLK_INLINE_ENCRYPTION */ void __bio_crypt_advance(struct bio *bio, unsigned int bytes); @@ -127,14 +137,21 @@ static inline bool blk_crypto_bio_prep(struct bio **bio_ptr) return true; } -blk_status_t __blk_crypto_init_request(struct request *rq); -static inline blk_status_t blk_crypto_init_request(struct request *rq) +blk_status_t __blk_crypto_rq_get_keyslot(struct request *rq); +static inline blk_status_t blk_crypto_rq_get_keyslot(struct request *rq) { if (blk_crypto_rq_is_encrypted(rq)) - return __blk_crypto_init_request(rq); + return __blk_crypto_rq_get_keyslot(rq); return BLK_STS_OK; } +void __blk_crypto_rq_put_keyslot(struct request *rq); +static inline void blk_crypto_rq_put_keyslot(struct request *rq) +{ + if (blk_crypto_rq_has_keyslot(rq)) + __blk_crypto_rq_put_keyslot(rq); +} + void __blk_crypto_free_request(struct request *rq); static inline void blk_crypto_free_request(struct request *rq) { @@ -173,7 +190,7 @@ static inline blk_status_t blk_crypto_insert_cloned_request(struct request *rq) { if (blk_crypto_rq_is_encrypted(rq)) - return blk_crypto_init_request(rq); + return blk_crypto_rq_get_keyslot(rq); return BLK_STS_OK; } diff --git a/block/blk-crypto.c b/block/blk-crypto.c index 5ffa9aab49de0..0506adfd9ca6b 100644 --- a/block/blk-crypto.c +++ b/block/blk-crypto.c @@ -216,26 +216,26 @@ static bool bio_crypt_check_alignment(struct bio *bio) return true; } -blk_status_t __blk_crypto_init_request(struct request *rq) +blk_status_t __blk_crypto_rq_get_keyslot(struct request *rq) { return blk_ksm_get_slot_for_key(rq->q->ksm, rq->crypt_ctx->bc_key, &rq->crypt_keyslot); } -/** - * __blk_crypto_free_request - Uninitialize the crypto fields of a request. - * - * @rq: The request whose crypto fields to uninitialize. - * - * Completely uninitializes the crypto fields of a request. If a keyslot has - * been programmed into some inline encryption hardware, that keyslot is - * released. The rq->crypt_ctx is also freed. - */ -void __blk_crypto_free_request(struct request *rq) +void __blk_crypto_rq_put_keyslot(struct request *rq) { blk_ksm_put_slot(rq->crypt_keyslot); + rq->crypt_keyslot = NULL; +} + +void __blk_crypto_free_request(struct request *rq) +{ + /* The keyslot, if one was needed, should have been released earlier. */ + if (WARN_ON_ONCE(rq->crypt_keyslot)) + __blk_crypto_rq_put_keyslot(rq); + mempool_free(rq->crypt_ctx, bio_crypt_ctx_pool); - blk_crypto_rq_set_defaults(rq); + rq->crypt_ctx = NULL; } /** diff --git a/block/blk-merge.c b/block/blk-merge.c index fbba277364f01..f3b016b31af86 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -801,6 +801,8 @@ static struct request *attempt_merge(struct request_queue *q, if (!blk_discard_mergable(req)) elv_merge_requests(q, req, next); + blk_crypto_rq_put_keyslot(next); + /* * 'next' is going away, so update stats accordingly */ diff --git a/block/blk-mq.c b/block/blk-mq.c index cf66de0f00fd3..e153a36c9ba3a 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -2193,7 +2193,7 @@ blk_qc_t blk_mq_submit_bio(struct bio *bio) blk_mq_bio_to_request(rq, bio, nr_segs); - ret = blk_crypto_init_request(rq); + ret = blk_crypto_rq_get_keyslot(rq); if (ret != BLK_STS_OK) { bio->bi_status = ret; bio_endio(bio); From patchwork Thu May 4 04:09:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 13230763 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 99AE8C7EE24 for ; Thu, 4 May 2023 04:10:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229738AbjEDEKJ (ORCPT ); Thu, 4 May 2023 00:10:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33644 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229460AbjEDEKG (ORCPT ); Thu, 4 May 2023 00:10:06 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5CE8C2111; Wed, 3 May 2023 21:10:05 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id DB7BE63174; Thu, 4 May 2023 04:10:04 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 24625C4339C; Thu, 4 May 2023 04:10:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1683173404; bh=ONh2darfKTPTYzJEVpGAMWntgyVt0SBzJB7F5Cgn2A4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=re9ZTZ6GmzleCceLMG/MS5IW998INfvu5Y4tE79+XwVhmVgWaPsBcsqPjXkvEBVT0 nBch/u3WYOt9MoDFbV0OwZ7LCcVEcHePQmfgjaVCoQl//H5TBKwfcryp6qwXigTweC uAlTOT22u6ADw/w4P72bwjfYLNzTNAtyJG9vs0ttnsGPAcab+yUhE1ln9rmbfcMgPU 8a+YDZSKxIaJiVxvSURvqw2JRy3XR/2Safg1KELISq0BsrZfgiTFrMUBvg3bdtBU7a eOIfxiMaDPlmbNhqUGCWKiL1iBktIhelN9XeKCPsEpWJNctac18yyqDZBy/H/3uMes jq2u/QDqRagjA== From: Eric Biggers To: stable@vger.kernel.org Cc: linux-block@vger.kernel.org, Christoph Hellwig , Jens Axboe Subject: [PATCH 5.10 2/3] blk-crypto: make blk_crypto_evict_key() return void Date: Wed, 3 May 2023 21:09:40 -0700 Message-Id: <20230504040941.152614-3-ebiggers@kernel.org> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230504040941.152614-1-ebiggers@kernel.org> References: <20230504040941.152614-1-ebiggers@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org From: Eric Biggers commit 70493a63ba04f754f7a7dd53a4fcc82700181490 upstream. blk_crypto_evict_key() is only called in contexts such as inode eviction where failure is not an option. So there is nothing the caller can do with errors except log them. (dm-table.c does "use" the error code, but only to pass on to upper layers, so it doesn't really count.) Just make blk_crypto_evict_key() return void and log errors itself. Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Reviewed-by: Christoph Hellwig Link: https://lore.kernel.org/r/20230315183907.53675-2-ebiggers@kernel.org Signed-off-by: Jens Axboe --- block/blk-crypto.c | 22 ++++++++++------------ include/linux/blk-crypto.h | 4 ++-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/block/blk-crypto.c b/block/blk-crypto.c index 0506adfd9ca6b..d8c48ee44ba69 100644 --- a/block/blk-crypto.c +++ b/block/blk-crypto.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "blk-crypto-internal.h" @@ -393,19 +394,16 @@ int blk_crypto_start_using_key(const struct blk_crypto_key *key, * Upper layers (filesystems) must call this function to ensure that a key is * evicted from any hardware that it might have been programmed into. The key * must not be in use by any in-flight IO when this function is called. - * - * Return: 0 on success or if key is not present in the q's ksm, -err on error. */ -int blk_crypto_evict_key(struct request_queue *q, - const struct blk_crypto_key *key) +void blk_crypto_evict_key(struct request_queue *q, + const struct blk_crypto_key *key) { - if (blk_ksm_crypto_cfg_supported(q->ksm, &key->crypto_cfg)) - return blk_ksm_evict_key(q->ksm, key); + int err; - /* - * If the request queue's associated inline encryption hardware didn't - * have support for the key, then the key might have been programmed - * into the fallback keyslot manager, so try to evict from there. - */ - return blk_crypto_fallback_evict_key(key); + if (blk_ksm_crypto_cfg_supported(q->ksm, &key->crypto_cfg)) + err = blk_ksm_evict_key(q->ksm, key); + else + err = blk_crypto_fallback_evict_key(key); + if (err) + pr_warn_ratelimited("error %d evicting key\n", err); } diff --git a/include/linux/blk-crypto.h b/include/linux/blk-crypto.h index 69b24fe92cbf1..5e96bad548047 100644 --- a/include/linux/blk-crypto.h +++ b/include/linux/blk-crypto.h @@ -97,8 +97,8 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key, const u8 *raw_key, int blk_crypto_start_using_key(const struct blk_crypto_key *key, struct request_queue *q); -int blk_crypto_evict_key(struct request_queue *q, - const struct blk_crypto_key *key); +void blk_crypto_evict_key(struct request_queue *q, + const struct blk_crypto_key *key); bool blk_crypto_config_supported(struct request_queue *q, const struct blk_crypto_config *cfg); From patchwork Thu May 4 04:09:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 13230765 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E2A39C7EE23 for ; Thu, 4 May 2023 04:10:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229585AbjEDEKM (ORCPT ); Thu, 4 May 2023 00:10:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33658 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229758AbjEDEKH (ORCPT ); Thu, 4 May 2023 00:10:07 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A89B31FD8; Wed, 3 May 2023 21:10:05 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 29E5B6317B; Thu, 4 May 2023 04:10:05 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6B317C433D2; Thu, 4 May 2023 04:10:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1683173404; bh=vWExVuIudKQKlBBOsGCLYmL7KDwCvZt1MQlWkawNwlw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Yss2ydu8FhjH7nvLTaRQPcl82XCeypvA2Y7EMUke/x2OueBpXlcuGe3QSPmAdJ7kW GYqeshaGSGT0MDuruC0+hIb4XC11TvHm1AfRj5X7F3YGqA/0y6ZUI2P0Z3350VK8yw noAz7CYAxntIiEfFZMDotrwkKNuom1+eN77A2he7t6Fg0sRoACsHtuO2P6E1SSoxum ZGaEiG8uK5ot8al7rLOnQ6yDylUmXrM//YeFWwlM2/x1ejLuWDoBMHYOWA7W9Dq80I unZHekU+NRU/sMy+gISjc7ODCzICfcplqlghB8eL7YjTP2BaJstO4CrHQH5bxFhwmI BZft8Z1gO8+wA== From: Eric Biggers To: stable@vger.kernel.org Cc: linux-block@vger.kernel.org, Christoph Hellwig , Jens Axboe Subject: [PATCH 5.10 3/3] blk-crypto: make blk_crypto_evict_key() more robust Date: Wed, 3 May 2023 21:09:41 -0700 Message-Id: <20230504040941.152614-4-ebiggers@kernel.org> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230504040941.152614-1-ebiggers@kernel.org> References: <20230504040941.152614-1-ebiggers@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org From: Eric Biggers commit 5c7cb94452901a93e90c2230632e2c12a681bc92 upstream. If blk_crypto_evict_key() sees that the key is still in-use (due to a bug) or that ->keyslot_evict failed, it currently just returns while leaving the key linked into the keyslot management structures. However, blk_crypto_evict_key() is only called in contexts such as inode eviction where failure is not an option. So actually the caller proceeds with freeing the blk_crypto_key regardless of the return value of blk_crypto_evict_key(). These two assumptions don't match, and the result is that there can be a use-after-free in blk_crypto_reprogram_all_keys() after one of these errors occurs. (Note, these errors *shouldn't* happen; we're just talking about what happens if they do anyway.) Fix this by making blk_crypto_evict_key() unlink the key from the keyslot management structures even on failure. Also improve some comments. Fixes: 1b2628397058 ("block: Keyslot Manager for Inline Encryption") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Reviewed-by: Christoph Hellwig Link: https://lore.kernel.org/r/20230315183907.53675-2-ebiggers@kernel.org Signed-off-by: Jens Axboe --- block/blk-crypto.c | 29 +++++++++++++++++++-------- block/keyslot-manager.c | 43 ++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/block/blk-crypto.c b/block/blk-crypto.c index d8c48ee44ba69..87ec55d4354f5 100644 --- a/block/blk-crypto.c +++ b/block/blk-crypto.c @@ -385,15 +385,20 @@ int blk_crypto_start_using_key(const struct blk_crypto_key *key, } /** - * blk_crypto_evict_key() - Evict a key from any inline encryption hardware - * it may have been programmed into - * @q: The request queue who's associated inline encryption hardware this key - * might have been programmed into - * @key: The key to evict + * blk_crypto_evict_key() - Evict a blk_crypto_key from a request_queue + * @q: a request_queue on which I/O using the key may have been done + * @key: the key to evict * - * Upper layers (filesystems) must call this function to ensure that a key is - * evicted from any hardware that it might have been programmed into. The key - * must not be in use by any in-flight IO when this function is called. + * For a given request_queue, this function removes the given blk_crypto_key + * from the keyslot management structures and evicts it from any underlying + * hardware keyslot(s) or blk-crypto-fallback keyslot it may have been + * programmed into. + * + * Upper layers must call this before freeing the blk_crypto_key. It must be + * called for every request_queue the key may have been used on. The key must + * no longer be in use by any I/O when this function is called. + * + * Context: May sleep. */ void blk_crypto_evict_key(struct request_queue *q, const struct blk_crypto_key *key) @@ -404,6 +409,14 @@ void blk_crypto_evict_key(struct request_queue *q, err = blk_ksm_evict_key(q->ksm, key); else err = blk_crypto_fallback_evict_key(key); + /* + * An error can only occur here if the key failed to be evicted from a + * keyslot (due to a hardware or driver issue) or is allegedly still in + * use by I/O (due to a kernel bug). Even in these cases, the key is + * still unlinked from the keyslot management structures, and the caller + * is allowed and expected to free it right away. There's nothing + * callers can do to handle errors, so just log them and return void. + */ if (err) pr_warn_ratelimited("error %d evicting key\n", err); } diff --git a/block/keyslot-manager.c b/block/keyslot-manager.c index 86f8195d8039e..17a1f1ba44efc 100644 --- a/block/keyslot-manager.c +++ b/block/keyslot-manager.c @@ -305,44 +305,43 @@ bool blk_ksm_crypto_cfg_supported(struct blk_keyslot_manager *ksm, return true; } -/** - * blk_ksm_evict_key() - Evict a key from the lower layer device. - * @ksm: The keyslot manager to evict from - * @key: The key to evict - * - * Find the keyslot that the specified key was programmed into, and evict that - * slot from the lower layer device. The slot must not be in use by any - * in-flight IO when this function is called. - * - * Context: Process context. Takes and releases ksm->lock. - * Return: 0 on success or if there's no keyslot with the specified key, -EBUSY - * if the keyslot is still in use, or another -errno value on other - * error. +/* + * This is an internal function that evicts a key from an inline encryption + * device that can be either a real device or the blk-crypto-fallback "device". + * It is used only by blk_crypto_evict_key(); see that function for details. */ int blk_ksm_evict_key(struct blk_keyslot_manager *ksm, const struct blk_crypto_key *key) { struct blk_ksm_keyslot *slot; - int err = 0; + int err; blk_ksm_hw_enter(ksm); slot = blk_ksm_find_keyslot(ksm, key); - if (!slot) - goto out_unlock; + if (!slot) { + /* + * Not an error, since a key not in use by I/O is not guaranteed + * to be in a keyslot. There can be more keys than keyslots. + */ + err = 0; + goto out; + } if (WARN_ON_ONCE(atomic_read(&slot->slot_refs) != 0)) { + /* BUG: key is still in use by I/O */ err = -EBUSY; - goto out_unlock; + goto out_remove; } err = ksm->ksm_ll_ops.keyslot_evict(ksm, key, blk_ksm_get_slot_idx(slot)); - if (err) - goto out_unlock; - +out_remove: + /* + * Callers free the key even on error, so unlink the key from the hash + * table and clear slot->key even on error. + */ hlist_del(&slot->hash_node); slot->key = NULL; - err = 0; -out_unlock: +out: blk_ksm_hw_exit(ksm); return err; }