Fix blk-crypto keyslot race condition
Eric Biggers
maintainercover Fix blk-crypto keyslot race condition
This series fixes a race condition in blk-crypto keyslot management and makes some related cleanups. It replaces
"[PATCH] blk-crypto: make blk_crypto_evict_key() always try to evict"
(https://lore.kernel.org/r/[email protected]),
which was a simpler fix but didn't fix the keyslot reference counting to work as expected.
Eric Biggers (3):
blk-mq: release crypto keyslot before reporting I/O complete
blk-crypto: make blk_crypto_evict_key() more robust
blk-crypto: remove blk_crypto_insert_cloned_request()
Documentation/block/inline-encryption.rst | 3 +- block/blk-crypto-internal.h | 28 +++++-------- block/blk-crypto-profile.c | 50 +++++++++-------------- block/blk-crypto.c | 47 +++++++++++---------- block/blk-mq.c | 17 +++++++- 5 files changed, 71 insertions(+), 74 deletions(-)
base-commit: 2eb29d59ddf02e39774abfb60b2030b0b7e27c1f
Signature · 1 line
2.39.2
Eric Biggers
maintainerPATCH 1/3 blk-mq: release crypto keyslot before reporting I/O complete
From: Eric Biggers <[email protected]>
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.
--- block/blk-crypto-internal.h | 15 +++++++++++---- block/blk-crypto.c | 24 ++++++++++++------------ block/blk-mq.c | 15 ++++++++++++++- 3 files changed, 37 insertions(+), 17 deletions(-)
block/blk-crypto-internal.h +11 -4
@@ -153,14 +153,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_is_encrypted (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) {
@@ -199,7 +206,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 ; }
block/blk-crypto.c +12 -12
@@ -224,27 +224,27 @@ 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_crypto_get_keyslot (rq->q->crypto_profile, 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_crypto_put_keyslot (rq->crypt_keyslot); + rq->crypt_keyslot =NULL ; +} + +void __blk_crypto_free_request (struct request *rq) +{mempool_free (rq->crypt_ctx, bio_crypt_ctx_pool); -blk_crypto_rq_set_defaults (rq); + rq->crypt_ctx =NULL ; + +/* The keyslot, if one was needed, should have been released earlier. */ +if (WARN_ON_ONCE (rq->crypt_keyslot)) +__blk_crypto_rq_put_keyslot (rq); }/**
block/blk-mq.c +14 -1
@@ -840,6 +840,12 @@ static void blk_complete_request(struct request *req) req->q->integrity.profile->complete_fn (req, total_bytes);#endif +/* +* Upper layers may call blk_crypto_evict_key() anytime after the last +* bio_endio(). Therefore, the keyslot must be released before that. +*/ +blk_crypto_rq_put_keyslot (req); +blk_account_io_completion (req, total_bytes); do {
@@ -905,6 +911,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_is_encrypted (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 )) && !test_bit (GD_DEAD , &req->q->disk->state)) {
@@ -2967,7 +2980,7 @@ void 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);
Signature · 1 line
2.39.2
Re: [PATCH 1/3] blk-mq: release crypto keyslot before reporting I/O complete
Hi Eric,
Quoted 154 lines · Eric Biggers
From: Eric Biggers <[email protected]>
Once all I/O using a
blk_crypto_keyhas completed, filesystems can callblk_crypto_evict_key(). However, the block layer currently doesn't callblk_crypto_put_keyslot()until the request is being freed, which happens after upper layers have been told (viabio_endio()) the I/O has completed. This causes a race condition whereblk_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 inblk_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()ignoreslot_refs. Let's go with the first solution, since it preserves the ability to report bugs (viaWARN_ON_ONCE) where a key is evicted while still in-use.Fixes a892c8d52c02 ("block: Inline encryption support for blk-mq")Signed-off-by Eric Biggers <[email protected]>--- block/blk-crypto-internal.h | 15 +++++++++++---- block/blk-crypto.c | 24 ++++++++++++------------ block/blk-mq.c | 15 ++++++++++++++- 3 files changed, 37 insertions(+), 17 deletions(-)block/blk-crypto-internal.h +11
-4@@ -153,14 +153,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_is_encrypted (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) {@@ -199,7 +206,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 ; }block/blk-crypto.c +12
-12@@ -224,27 +224,27 @@ 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_crypto_get_keyslot (rq->q->crypto_profile, 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_crypto_put_keyslot (rq->crypt_keyslot); + rq->crypt_keyslot =NULL ; +} + +void __blk_crypto_free_request (struct request *rq) +{mempool_free (rq->crypt_ctx, bio_crypt_ctx_pool); -blk_crypto_rq_set_defaults (rq); + rq->crypt_ctx =NULL ; + +/* The keyslot, if one was needed, should have been released earlier. */ +if (WARN_ON_ONCE (rq->crypt_keyslot)) +__blk_crypto_rq_put_keyslot (rq); }/** block/blk-mq.c +14
-2@@ -840,6 +840,12 @@ static void blk_complete_request(struct request *req) req->q->integrity.profile->complete_fn (req, total_bytes);#endif +/* +* Upper layers may call blk_crypto_evict_key() anytime after the last +* bio_endio(). Therefore, the keyslot must be released before that. +*/ +blk_crypto_rq_put_keyslot (req); +blk_account_io_completion (req, total_bytes); do {@@ -905,6 +911,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_is_encrypted (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 )) && !test_bit (GD_DEAD , &req->q->disk->state)) {@@ -2967,7 +2980,7 @@ void 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); --
Quoted 2 lines
2.39.2
Thanks for the updated patchset. This patch looks good to me.
Thanks,
Huck
Eric Biggers
maintainerRe: [PATCH 1/3] blk-mq: release crypto keyslot before reporting I/O complete
In reply to Eric Biggersblock/blk-crypto.c static bool bio_crypt_check_alignment(struct bio *bio) · line 248
Quoted 10 lines · Eric Biggers
block/blk-crypto.c +7
-1+void __blk_crypto_free_request (struct request *rq) +{mempool_free (rq->crypt_ctx, bio_crypt_ctx_pool); -blk_crypto_rq_set_defaults (rq); + rq->crypt_ctx =NULL ; + +/* The keyslot, if one was needed, should have been released earlier. */ +if (WARN_ON_ONCE (rq->crypt_keyslot)) +__blk_crypto_rq_put_keyslot (rq); }
I received a report that this WARN_ON_ONCE can be hit.
To fix this, attempt_merge() will need to release the keyslot too.
- Eric
Eric Biggers
maintainerPATCH 2/3 blk-crypto: make blk_crypto_evict_key() more robust
In reply to Eric BiggersFrom: Eric Biggers <[email protected]>
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 an error 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.
--- block/blk-crypto-profile.c | 50 +++++++++++++++----------------------- block/blk-crypto.c | 23 +++++++++++------- 2 files changed, 33 insertions(+), 40 deletions(-)
block/blk-crypto-profile.c +19 -31
@@ -354,22 +354,10 @@ bool __blk_crypto_cfg_supported(struct blk_crypto_profile *profile,return true; } -/** -* __blk_crypto_evict_key() - Evict a key from a device. -* @profile: the crypto profile of the device -* @key: the key to evict. It must not still be used in any I/O. -* -* If the device has keyslots, this finds the keyslot (if any) that contains the -* specified key and calls the driver's keyslot_evict function to evict it. -* -* Otherwise, this just calls the driver's keyslot_evict function if it is -* implemented, passing just the key (without any particular keyslot). This -* allows layered devices to evict the key from their underlying devices. -* -* Context: Process context. Takes and releases profile->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_crypto_evict_key (struct blk_crypto_profile *profile,const struct blk_crypto_key *key)
@@ -389,22 +377,22 @@ int __blk_crypto_evict_key(struct blk_crypto_profile *profile,blk_crypto_hw_enter (profile); slot =blk_crypto_find_keyslot (profile, key); -if (!slot) - goto out_unlock; - -if (WARN_ON_ONCE (atomic_read (&slot->slot_refs) !=0 )) { - err = -EBUSY ; - goto out_unlock; +if (slot) { +if (WARN_ON_ONCE (atomic_read (&slot->slot_refs) !=0 )) { +/* BUG: key is still in use by I/O */ + err = -EBUSY ; + }else { + err = profile->ll_ops.keyslot_evict ( + profile, key, +blk_crypto_keyslot_index (slot)); + } +/* +* Callers may 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 = profile->ll_ops.keyslot_evict (profile, key, -blk_crypto_keyslot_index (slot)); -if (err) - goto out_unlock; - -hlist_del (&slot->hash_node); - slot->key =NULL ; - err =0 ; -out_unlock:blk_crypto_hw_exit (profile);return err; }
block/blk-crypto.c +14 -9
@@ -399,17 +399,22 @@ int blk_crypto_start_using_key(struct block_device *bdev, }/** -* blk_crypto_evict_key() - Evict a key from any inline encryption hardware -* it may have been programmed into -* @bdev: The block_device 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 block_device +* @bdev: a block_device 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 block_device, 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. * -* Return: 0 on success or if the key wasn't in any keyslot; -errno on error. +* Upper layers must call this before freeing the blk_crypto_key. It must be +* called for every block_device 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. +* Return: 0 on success or if the key wasn't in any keyslot; -errno if the key +* failed to be evicted from a keyslot or is still in-use. Even on +* "failure", the key is removed from the keyslot management structures. */ int blk_crypto_evict_key (struct block_device *bdev,const struct blk_crypto_key *key)
Signature · 1 line
2.39.2
Re: [PATCH 2/3] blk-crypto: make blk_crypto_evict_key() more robust
Hi Eric,
Quoted 75 lines · Eric Biggers
From: Eric Biggers <[email protected]>
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 an error 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 theblk_crypto_keyregardless of the return value ofblk_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.Fixes 1b2628397058 ("block: Keyslot Manager for Inline Encryption")Signed-off-by Eric Biggers <[email protected]>--- block/blk-crypto-profile.c | 50 +++++++++++++++----------------------- block/blk-crypto.c | 23 +++++++++++------- 2 files changed, 33 insertions(+), 40 deletions(-)block/blk-crypto-profile.c +10
-22@@ -354,22 +354,10 @@ bool __blk_crypto_cfg_supported(struct blk_crypto_profile *profile,return true; } -/** -* __blk_crypto_evict_key() - Evict a key from a device. -* @profile: the crypto profile of the device -* @key: the key to evict. It must not still be used in any I/O. -* -* If the device has keyslots, this finds the keyslot (if any) that contains the -* specified key and calls the driver's keyslot_evict function to evict it. -* -* Otherwise, this just calls the driver's keyslot_evict function if it is -* implemented, passing just the key (without any particular keyslot). This -* allows layered devices to evict the key from their underlying devices. -* -* Context: Process context. Takes and releases profile->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_crypto_evict_key (struct blk_crypto_profile *profile,const struct blk_crypto_key *key)@@ -389,22 +377,22 @@ int __blk_crypto_evict_key(struct blk_crypto_profile *profile,blk_crypto_hw_enter (profile); slot =blk_crypto_find_keyslot (profile, key); -if (!slot) - goto out_unlock; - -if (WARN_ON_ONCE (atomic_read (&slot->slot_refs) !=0 )) { - err = -EBUSY ; - goto out_unlock; +if (slot) { +if (WARN_ON_ONCE (atomic_read (&slot->slot_refs) !=0 )) { +/* BUG: key is still in use by I/O */ + err = -EBUSY ; + }else { + err = profile->ll_ops.keyslot_evict(
block/blk-crypto-profile.c int __blk_crypto_evict_key(struct blk_crypto_profile *profile, · line 395
Quoted 10 lines
block/blk-crypto-profile.c +9
-0+ profile, key, + blk_crypto_keyslot_index(slot)); + } +/* +* Callers may 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 ; }
The !slot case still needs to be handled. If profile->num_slots != 0 and !slot, we'll get an invalid index from blk_crypto_keyslot_index.
With that change,
Thanks,
Huck
Quoted 51 lines
block/blk-crypto-profile.c +0
-9- err = profile->ll_ops.keyslot_evict (profile, key, -blk_crypto_keyslot_index (slot)); -if (err) - goto out_unlock; - -hlist_del (&slot->hash_node); - slot->key =NULL ; - err =0 ; -out_unlock:blk_crypto_hw_exit (profile);return err; }block/blk-crypto.c +14
-10@@ -399,17 +399,22 @@ int blk_crypto_start_using_key(struct block_device *bdev, }/** -* blk_crypto_evict_key() - Evict a key from any inline encryption hardware -* it may have been programmed into -* @bdev: The block_device 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 block_device +* @bdev: a block_device 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 block_device, 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. * -* Return: 0 on success or if the key wasn't in any keyslot; -errno on error. +* Upper layers must call this before freeing the blk_crypto_key. It must be +* called for every block_device 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. +* Return: 0 on success or if the key wasn't in any keyslot; -errno if the key +* failed to be evicted from a keyslot or is still in-use. Even on +* "failure", the key is removed from the keyslot management structures. */ int blk_crypto_evict_key (struct block_device *bdev,const struct blk_crypto_key *key) --2.39.2
Eric Biggers
maintainerRe: [PATCH 2/3] blk-crypto: make blk_crypto_evict_key() more robust
Quoted 38 lines · Nathan Huckleberry
Quoted 18 lines
int __blk_crypto_evict_key(struct
blk_crypto_profile*profile,
const structblk_crypto_key*key)block/blk-crypto-profile.c +6
-6@@ -389,22 +377,22 @@ int __blk_crypto_evict_key(struct blk_crypto_profile *profile,blk_crypto_hw_enter (profile); slot =blk_crypto_find_keyslot (profile, key); -if (!slot) - goto out_unlock; - -if (WARN_ON_ONCE (atomic_read (&slot->slot_refs) !=0 )) { - err = -EBUSY ; - goto out_unlock; +if (slot) { +if (WARN_ON_ONCE (atomic_read (&slot->slot_refs) !=0 )) { +/* BUG: key is still in use by I/O */ + err = -EBUSY ; + }else { + err = profile->ll_ops.keyslot_evict(block/blk-crypto-profile.c int __blk_crypto_evict_key(struct blk_crypto_profile *profile, · line 395
Quoted 10 lines
block/blk-crypto-profile.c +9
-0+ profile, key, + blk_crypto_keyslot_index(slot)); + } +/* +* Callers may 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 ; }The !slot case still needs to be handled. If
profile->num_slots!= 0 and !slot, we'll get an invalid index fromblk_crypto_keyslot_index.With that change,
Reviewed-by Nathan Huckleberry <[email protected]>Thanks,
Huck
Quoted 12 lines
block/blk-crypto-profile.c int __blk_crypto_evict_key(struct blk_crypto_profile *profile, · line 398
Quoted 12 lines
block/blk-crypto-profile.c +0
-9- err = profile->ll_ops.keyslot_evict (profile, key, -blk_crypto_keyslot_index (slot)); -if (err) - goto out_unlock; - -hlist_del (&slot->hash_node); - slot->key =NULL ; - err =0 ; -out_unlock:blk_crypto_hw_exit (profile);return err; }
I'm not sure what you're referring to. The !slot case is handled correctly, and it's the same as before.
- Eric
Nathan Huckleberry
Reviewed-byRe: [PATCH 2/3] blk-crypto: make blk_crypto_evict_key() more robust
You're right. Nevermind.
Quoted 57 lines · Eric Biggers
Quoted 38 lines · Nathan Huckleberry
Quoted 18 lines
int __blk_crypto_evict_key(struct
blk_crypto_profile*profile,
const structblk_crypto_key*key)block/blk-crypto-profile.c +6
-6@@ -389,22 +377,22 @@ int __blk_crypto_evict_key(struct blk_crypto_profile *profile,blk_crypto_hw_enter (profile); slot =blk_crypto_find_keyslot (profile, key); -if (!slot) - goto out_unlock; - -if (WARN_ON_ONCE (atomic_read (&slot->slot_refs) !=0 )) { - err = -EBUSY ; - goto out_unlock; +if (slot) { +if (WARN_ON_ONCE (atomic_read (&slot->slot_refs) !=0 )) { +/* BUG: key is still in use by I/O */ + err = -EBUSY ; + }else { + err = profile->ll_ops.keyslot_evict(block/blk-crypto-profile.c int __blk_crypto_evict_key(struct blk_crypto_profile *profile, · line 395
Quoted 10 lines
block/blk-crypto-profile.c +9
-0+ profile, key, + blk_crypto_keyslot_index(slot)); + } +/* +* Callers may 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 ; }The !slot case still needs to be handled. If
profile->num_slots!= 0 and !slot, we'll get an invalid index fromblk_crypto_keyslot_index.With that change,
Reviewed-by Nathan Huckleberry <[email protected]>Thanks,
HuckQuoted 12 lines
block/blk-crypto-profile.c int __blk_crypto_evict_key(struct blk_crypto_profile *profile, · line 398
Quoted 12 lines
block/blk-crypto-profile.c +0
-9- err = profile->ll_ops.keyslot_evict (profile, key, -blk_crypto_keyslot_index (slot)); -if (err) - goto out_unlock; - -hlist_del (&slot->hash_node); - slot->key =NULL ; - err =0 ; -out_unlock:blk_crypto_hw_exit (profile);return err; }I'm not sure what you're referring to. The !slot case is handled correctly, and it's the same as before.
- Eric
Eric Biggers
maintainerPATCH 3/3 blk-crypto: remove blk_crypto_insert_cloned_request()
In reply to Eric BiggersFrom: Eric Biggers <[email protected]>
blk_crypto_insert_cloned_request() is the same as blk_crypto_rq_get_keyslot(), so just use that directly.
--- Documentation/block/inline-encryption.rst | 3 +-- block/blk-crypto-internal.h | 15 --------------- block/blk-mq.c | 2 +- 3 files changed, 2 insertions(+), 18 deletions(-)
Documentation/block/inline-encryption.rst +1 -2
@@ -270,8 +270,7 @@ Request queue based layered devices like dm-rq that wish to support inline encryption need to create their own blk_crypto_profile for their request_queue, and expose whatever functionality they choose. When a layered device wants to pass a clone of that request to another request_queue, blk-crypto will -initialize and prepare the clone as necessary; see -``blk_crypto_insert_cloned_request()``. +initialize and prepare the clone as necessary. Interaction between inline encryption and blk integrity =======================================================
block/blk-crypto-internal.h +0 -15
@@ -195,21 +195,6 @@ static inline int blk_crypto_rq_bio_prep(struct request *rq, struct bio *bio,return 0 ; } -/** -* blk_crypto_insert_cloned_request - Prepare a cloned request to be inserted -* into a request queue. -* @rq: the request being queued -* -* Return: BLK_STS_OK on success, nonzero on error. -*/ -static inline blk_status_t blk_crypto_insert_cloned_request (struct request *rq) -{ - -if (blk_crypto_rq_is_encrypted (rq)) -return blk_crypto_rq_get_keyslot (rq); -return BLK_STS_OK ; -} -#ifdef CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK int blk_crypto_fallback_start_using_mode (enum blk_crypto_mode_num mode_num);
block/blk-mq.c +1 -1
@@ -3048,7 +3048,7 @@ blk_status_t blk_insert_cloned_request(struct request *rq)if (q->disk &&should_fail_request (q->disk->part0,blk_rq_bytes (rq)))return BLK_STS_IOERR ; -if (blk_crypto_insert_cloned_request (rq)) +if (blk_crypto_rq_get_keyslot (rq))return BLK_STS_IOERR ;blk_account_io_start (rq);
Signature · 1 line
2.39.2