All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] Fix blk-crypto keyslot race condition
@ 2023-03-15 18:39 Eric Biggers
  2023-03-15 18:39 ` [PATCH v3 1/6] blk-mq: release crypto keyslot before reporting I/O complete Eric Biggers
                   ` (6 more replies)
  0 siblings, 7 replies; 16+ messages in thread
From: Eric Biggers @ 2023-03-15 18:39 UTC (permalink / raw)
  To: linux-block, Jens Axboe; +Cc: linux-fscrypt, Nathan Huckleberry

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/20230226203816.207449-1-ebiggers@kernel.org),
which was a simpler fix but didn't fix the keyslot reference counting to
work as expected.

Changed in v3:
  - Add a patch that makes blk_crypto_evict_key() return void
  - Add a patch that makes blk_insert_cloned_request() pass on the
    actual error code from blk_crypto_rq_put_keyslot()
  - Use gotos in __blk_crypto_evict_key()

Changed in v2:
  - Call blk_crypto_rq_put_keyslot() when requests are merged
  - Add and use blk_crypto_rq_has_keyslot()
  - Add patch "blk-crypto: drop the NULL check from blk_crypto_put_keyslot()"

Eric Biggers (6):
  blk-mq: release crypto keyslot before reporting I/O complete
  blk-crypto: make blk_crypto_evict_key() return void
  blk-crypto: make blk_crypto_evict_key() more robust
  blk-crypto: remove blk_crypto_insert_cloned_request()
  blk-mq: return actual keyslot error in blk_insert_cloned_request()
  blk-crypto: drop the NULL check from blk_crypto_put_keyslot()

 Documentation/block/inline-encryption.rst |  3 +-
 block/blk-crypto-internal.h               | 38 ++++++-------
 block/blk-crypto-profile.c                | 60 +++++++++------------
 block/blk-crypto.c                        | 66 +++++++++++++----------
 block/blk-merge.c                         |  2 +
 block/blk-mq.c                            | 20 +++++--
 drivers/md/dm-table.c                     | 19 ++-----
 include/linux/blk-crypto.h                |  4 +-
 8 files changed, 110 insertions(+), 102 deletions(-)


base-commit: eeac8ede17557680855031c6f305ece2378af326
-- 
2.39.2


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v3 1/6] blk-mq: release crypto keyslot before reporting I/O complete
  2023-03-15 18:39 [PATCH v3 0/6] Fix blk-crypto keyslot race condition Eric Biggers
@ 2023-03-15 18:39 ` Eric Biggers
  2023-03-15 18:39 ` [PATCH v3 2/6] blk-crypto: make blk_crypto_evict_key() return void Eric Biggers
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 16+ messages in thread
From: Eric Biggers @ 2023-03-15 18:39 UTC (permalink / raw)
  To: linux-block, Jens Axboe
  Cc: linux-fscrypt, Nathan Huckleberry, stable, Christoph Hellwig

From: Eric Biggers <ebiggers@google.com>

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 <nhuck@google.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 block/blk-crypto-internal.h | 25 +++++++++++++++++++++----
 block/blk-crypto.c          | 24 ++++++++++++------------
 block/blk-merge.c           |  2 ++
 block/blk-mq.c              | 15 ++++++++++++++-
 4 files changed, 49 insertions(+), 17 deletions(-)

diff --git a/block/blk-crypto-internal.h b/block/blk-crypto-internal.h
index a8cdaf26851e1..4f1de2495f0c3 100644
--- a/block/blk-crypto-internal.h
+++ b/block/blk-crypto-internal.h
@@ -65,6 +65,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;
+}
+
 blk_status_t blk_crypto_get_keyslot(struct blk_crypto_profile *profile,
 				    const struct blk_crypto_key *key,
 				    struct blk_crypto_keyslot **slot_ptr);
@@ -119,6 +124,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);
@@ -153,14 +163,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)
 {
@@ -199,7 +216,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 45378586151f7..d0c7feb447e96 100644
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -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)
+{
+	/* 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 6460abdb24267..65e75efa9bd36 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -867,6 +867,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 d0cb2ef18fe21..49825538d932d 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -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_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)) &&
 		     !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);
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 2/6] blk-crypto: make blk_crypto_evict_key() return void
  2023-03-15 18:39 [PATCH v3 0/6] Fix blk-crypto keyslot race condition Eric Biggers
  2023-03-15 18:39 ` [PATCH v3 1/6] blk-mq: release crypto keyslot before reporting I/O complete Eric Biggers
@ 2023-03-15 18:39 ` Eric Biggers
  2023-03-16 15:14   ` Christoph Hellwig
  2023-03-15 18:39 ` [PATCH v3 3/6] blk-crypto: make blk_crypto_evict_key() more robust Eric Biggers
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 16+ messages in thread
From: Eric Biggers @ 2023-03-15 18:39 UTC (permalink / raw)
  To: linux-block, Jens Axboe; +Cc: linux-fscrypt, Nathan Huckleberry, stable

From: Eric Biggers <ebiggers@google.com>

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 <ebiggers@google.com>
---
 block/blk-crypto.c         | 20 +++++++++-----------
 drivers/md/dm-table.c      | 19 +++++--------------
 include/linux/blk-crypto.h |  4 ++--
 3 files changed, 16 insertions(+), 27 deletions(-)

diff --git a/block/blk-crypto.c b/block/blk-crypto.c
index d0c7feb447e96..e800f305e9eda 100644
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -13,6 +13,7 @@
 #include <linux/blkdev.h>
 #include <linux/blk-crypto-profile.h>
 #include <linux/module.h>
+#include <linux/ratelimit.h>
 #include <linux/slab.h>
 
 #include "blk-crypto-internal.h"
@@ -408,21 +409,18 @@ int blk_crypto_start_using_key(struct block_device *bdev,
  * 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 the key wasn't in any keyslot; -errno on error.
  */
-int blk_crypto_evict_key(struct block_device *bdev,
-			 const struct blk_crypto_key *key)
+void blk_crypto_evict_key(struct block_device *bdev,
+			  const struct blk_crypto_key *key)
 {
 	struct request_queue *q = bdev_get_queue(bdev);
+	int err;
 
 	if (blk_crypto_config_supported_natively(bdev, &key->crypto_cfg))
-		return __blk_crypto_evict_key(q->crypto_profile, key);
-
-	/*
-	 * If the block_device didn't support the key, then blk-crypto-fallback
-	 * may have been used, so try to evict the key from blk-crypto-fallback.
-	 */
-	return blk_crypto_fallback_evict_key(key);
+		err = __blk_crypto_evict_key(q->crypto_profile, key);
+	else
+		err = blk_crypto_fallback_evict_key(key);
+	if (err)
+		pr_warn_ratelimited("%pg: error %d evicting key\n", bdev, err);
 }
 EXPORT_SYMBOL_GPL(blk_crypto_evict_key);
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 2055a758541de..7899f5fb4c133 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -1202,21 +1202,12 @@ struct dm_crypto_profile {
 	struct mapped_device *md;
 };
 
-struct dm_keyslot_evict_args {
-	const struct blk_crypto_key *key;
-	int err;
-};
-
 static int dm_keyslot_evict_callback(struct dm_target *ti, struct dm_dev *dev,
 				     sector_t start, sector_t len, void *data)
 {
-	struct dm_keyslot_evict_args *args = data;
-	int err;
+	const struct blk_crypto_key *key = data;
 
-	err = blk_crypto_evict_key(dev->bdev, args->key);
-	if (!args->err)
-		args->err = err;
-	/* Always try to evict the key from all devices. */
+	blk_crypto_evict_key(dev->bdev, key);
 	return 0;
 }
 
@@ -1229,7 +1220,6 @@ static int dm_keyslot_evict(struct blk_crypto_profile *profile,
 {
 	struct mapped_device *md =
 		container_of(profile, struct dm_crypto_profile, profile)->md;
-	struct dm_keyslot_evict_args args = { key };
 	struct dm_table *t;
 	int srcu_idx;
 
@@ -1242,11 +1232,12 @@ static int dm_keyslot_evict(struct blk_crypto_profile *profile,
 
 		if (!ti->type->iterate_devices)
 			continue;
-		ti->type->iterate_devices(ti, dm_keyslot_evict_callback, &args);
+		ti->type->iterate_devices(ti, dm_keyslot_evict_callback,
+					  (void *)key);
 	}
 
 	dm_put_live_table(md, srcu_idx);
-	return args.err;
+	return 0;
 }
 
 static int
diff --git a/include/linux/blk-crypto.h b/include/linux/blk-crypto.h
index 1e3e5d0adf120..5e5822c18ee41 100644
--- a/include/linux/blk-crypto.h
+++ b/include/linux/blk-crypto.h
@@ -95,8 +95,8 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key, const u8 *raw_key,
 int blk_crypto_start_using_key(struct block_device *bdev,
 			       const struct blk_crypto_key *key);
 
-int blk_crypto_evict_key(struct block_device *bdev,
-			 const struct blk_crypto_key *key);
+void blk_crypto_evict_key(struct block_device *bdev,
+			  const struct blk_crypto_key *key);
 
 bool blk_crypto_config_supported_natively(struct block_device *bdev,
 					  const struct blk_crypto_config *cfg);
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 3/6] blk-crypto: make blk_crypto_evict_key() more robust
  2023-03-15 18:39 [PATCH v3 0/6] Fix blk-crypto keyslot race condition Eric Biggers
  2023-03-15 18:39 ` [PATCH v3 1/6] blk-mq: release crypto keyslot before reporting I/O complete Eric Biggers
  2023-03-15 18:39 ` [PATCH v3 2/6] blk-crypto: make blk_crypto_evict_key() return void Eric Biggers
@ 2023-03-15 18:39 ` Eric Biggers
  2023-03-16 15:14   ` Christoph Hellwig
  2023-03-15 18:39 ` [PATCH v3 4/6] blk-crypto: remove blk_crypto_insert_cloned_request() Eric Biggers
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 16+ messages in thread
From: Eric Biggers @ 2023-03-15 18:39 UTC (permalink / raw)
  To: linux-block, Jens Axboe; +Cc: linux-fscrypt, Nathan Huckleberry, stable

From: Eric Biggers <ebiggers@google.com>

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 <ebiggers@google.com>
---
 block/blk-crypto-profile.c | 46 +++++++++++++++++---------------------
 block/blk-crypto.c         | 28 ++++++++++++++++-------
 2 files changed, 41 insertions(+), 33 deletions(-)

diff --git a/block/blk-crypto-profile.c b/block/blk-crypto-profile.c
index 0307fb0d95d34..3290c03c9918d 100644
--- a/block/blk-crypto-profile.c
+++ b/block/blk-crypto-profile.c
@@ -354,28 +354,16 @@ 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)
 {
 	struct blk_crypto_keyslot *slot;
-	int err = 0;
+	int err;
 
 	if (profile->num_slots == 0) {
 		if (profile->ll_ops.keyslot_evict) {
@@ -389,22 +377,30 @@ 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 (!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 = profile->ll_ops.keyslot_evict(profile, key,
 					    blk_crypto_keyslot_index(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_crypto_hw_exit(profile);
 	return err;
 }
diff --git a/block/blk-crypto.c b/block/blk-crypto.c
index e800f305e9eda..4d760b092deb9 100644
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -400,15 +400,19 @@ 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.
+ *
+ * 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.
  */
 void blk_crypto_evict_key(struct block_device *bdev,
 			  const struct blk_crypto_key *key)
@@ -420,6 +424,14 @@ void blk_crypto_evict_key(struct block_device *bdev,
 		err = __blk_crypto_evict_key(q->crypto_profile, 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("%pg: error %d evicting key\n", bdev, err);
 }
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 4/6] blk-crypto: remove blk_crypto_insert_cloned_request()
  2023-03-15 18:39 [PATCH v3 0/6] Fix blk-crypto keyslot race condition Eric Biggers
                   ` (2 preceding siblings ...)
  2023-03-15 18:39 ` [PATCH v3 3/6] blk-crypto: make blk_crypto_evict_key() more robust Eric Biggers
@ 2023-03-15 18:39 ` Eric Biggers
  2023-03-16 15:15   ` Christoph Hellwig
  2023-03-15 18:39 ` [PATCH v3 5/6] blk-mq: return actual keyslot error in blk_insert_cloned_request() Eric Biggers
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 16+ messages in thread
From: Eric Biggers @ 2023-03-15 18:39 UTC (permalink / raw)
  To: linux-block, Jens Axboe; +Cc: linux-fscrypt, Nathan Huckleberry

From: Eric Biggers <ebiggers@google.com>

blk_crypto_insert_cloned_request() is the same as
blk_crypto_rq_get_keyslot(), so just use that directly.

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 Documentation/block/inline-encryption.rst |  3 +--
 block/blk-crypto-internal.h               | 15 ---------------
 block/blk-mq.c                            |  2 +-
 3 files changed, 2 insertions(+), 18 deletions(-)

diff --git a/Documentation/block/inline-encryption.rst b/Documentation/block/inline-encryption.rst
index f9bf18ea65093..90b733422ed46 100644
--- a/Documentation/block/inline-encryption.rst
+++ b/Documentation/block/inline-encryption.rst
@@ -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
 =======================================================
diff --git a/block/blk-crypto-internal.h b/block/blk-crypto-internal.h
index 4f1de2495f0c3..93a141979694b 100644
--- a/block/blk-crypto-internal.h
+++ b/block/blk-crypto-internal.h
@@ -205,21 +205,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);
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 49825538d932d..5e819de2f5e70 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -3049,7 +3049,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);
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 5/6] blk-mq: return actual keyslot error in blk_insert_cloned_request()
  2023-03-15 18:39 [PATCH v3 0/6] Fix blk-crypto keyslot race condition Eric Biggers
                   ` (3 preceding siblings ...)
  2023-03-15 18:39 ` [PATCH v3 4/6] blk-crypto: remove blk_crypto_insert_cloned_request() Eric Biggers
@ 2023-03-15 18:39 ` Eric Biggers
  2023-03-15 18:50   ` Jens Axboe
  2023-03-16 15:15   ` Christoph Hellwig
  2023-03-15 18:39 ` [PATCH v3 6/6] blk-crypto: drop the NULL check from blk_crypto_put_keyslot() Eric Biggers
  2023-03-16 15:35 ` [PATCH v3 0/6] Fix blk-crypto keyslot race condition Jens Axboe
  6 siblings, 2 replies; 16+ messages in thread
From: Eric Biggers @ 2023-03-15 18:39 UTC (permalink / raw)
  To: linux-block, Jens Axboe; +Cc: linux-fscrypt, Nathan Huckleberry

From: Eric Biggers <ebiggers@google.com>

To avoid hiding information, pass on the error code from
blk_crypto_rq_get_keyslot() instead of always using BLK_STS_IOERR.

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 block/blk-mq.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/block/blk-mq.c b/block/blk-mq.c
index 5e819de2f5e70..a875b1cdff9b5 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -3049,8 +3049,9 @@ 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_rq_get_keyslot(rq))
-		return BLK_STS_IOERR;
+	ret = blk_crypto_rq_get_keyslot(rq);
+	if (ret != BLK_STS_OK)
+		return ret;
 
 	blk_account_io_start(rq);
 
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 6/6] blk-crypto: drop the NULL check from blk_crypto_put_keyslot()
  2023-03-15 18:39 [PATCH v3 0/6] Fix blk-crypto keyslot race condition Eric Biggers
                   ` (4 preceding siblings ...)
  2023-03-15 18:39 ` [PATCH v3 5/6] blk-mq: return actual keyslot error in blk_insert_cloned_request() Eric Biggers
@ 2023-03-15 18:39 ` Eric Biggers
  2023-03-16 15:35 ` [PATCH v3 0/6] Fix blk-crypto keyslot race condition Jens Axboe
  6 siblings, 0 replies; 16+ messages in thread
From: Eric Biggers @ 2023-03-15 18:39 UTC (permalink / raw)
  To: linux-block, Jens Axboe
  Cc: linux-fscrypt, Nathan Huckleberry, Christoph Hellwig

From: Eric Biggers <ebiggers@google.com>

Now that all callers of blk_crypto_put_keyslot() check for NULL before
calling it, there is no need for blk_crypto_put_keyslot() to do the NULL
check itself.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 block/blk-crypto-profile.c | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/block/blk-crypto-profile.c b/block/blk-crypto-profile.c
index 3290c03c9918d..2a67d3fb63e5c 100644
--- a/block/blk-crypto-profile.c
+++ b/block/blk-crypto-profile.c
@@ -227,14 +227,13 @@ EXPORT_SYMBOL_GPL(blk_crypto_keyslot_index);
  * @profile: the crypto profile of the device the key will be used on
  * @key: the key that will be used
  * @slot_ptr: If a keyslot is allocated, an opaque pointer to the keyslot struct
- *	      will be stored here; otherwise NULL will be stored here.
+ *	      will be stored here.  blk_crypto_put_keyslot() must be called
+ *	      later to release it.  Otherwise, NULL will be stored here.
  *
  * If the device has keyslots, this gets a keyslot that's been programmed with
  * the specified key.  If the key is already in a slot, this reuses it;
  * otherwise this waits for a slot to become idle and programs the key into it.
  *
- * This must be paired with a call to blk_crypto_put_keyslot().
- *
  * Context: Process context. Takes and releases profile->lock.
  * Return: BLK_STS_OK on success, meaning that either a keyslot was allocated or
  *	   one wasn't needed; or a blk_status_t error on failure.
@@ -312,20 +311,15 @@ blk_status_t blk_crypto_get_keyslot(struct blk_crypto_profile *profile,
 
 /**
  * blk_crypto_put_keyslot() - Release a reference to a keyslot
- * @slot: The keyslot to release the reference of (may be NULL).
+ * @slot: The keyslot to release the reference of
  *
  * Context: Any context.
  */
 void blk_crypto_put_keyslot(struct blk_crypto_keyslot *slot)
 {
-	struct blk_crypto_profile *profile;
+	struct blk_crypto_profile *profile = slot->profile;
 	unsigned long flags;
 
-	if (!slot)
-		return;
-
-	profile = slot->profile;
-
 	if (atomic_dec_and_lock_irqsave(&slot->slot_refs,
 					&profile->idle_slots_lock, flags)) {
 		list_add_tail(&slot->idle_slot_node, &profile->idle_slots);
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 5/6] blk-mq: return actual keyslot error in blk_insert_cloned_request()
  2023-03-15 18:39 ` [PATCH v3 5/6] blk-mq: return actual keyslot error in blk_insert_cloned_request() Eric Biggers
@ 2023-03-15 18:50   ` Jens Axboe
  2023-03-15 18:54     ` Eric Biggers
  2023-03-16 15:15   ` Christoph Hellwig
  1 sibling, 1 reply; 16+ messages in thread
From: Jens Axboe @ 2023-03-15 18:50 UTC (permalink / raw)
  To: Eric Biggers, linux-block; +Cc: linux-fscrypt, Nathan Huckleberry

On 3/15/23 12:39 PM, Eric Biggers wrote:
> From: Eric Biggers <ebiggers@google.com>
> 
> To avoid hiding information, pass on the error code from
> blk_crypto_rq_get_keyslot() instead of always using BLK_STS_IOERR.

Maybe just fold this with the previous patch?

-- 
Jens Axboe



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 5/6] blk-mq: return actual keyslot error in blk_insert_cloned_request()
  2023-03-15 18:50   ` Jens Axboe
@ 2023-03-15 18:54     ` Eric Biggers
  2023-03-15 18:55       ` Jens Axboe
  0 siblings, 1 reply; 16+ messages in thread
From: Eric Biggers @ 2023-03-15 18:54 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block, linux-fscrypt, Nathan Huckleberry

On Wed, Mar 15, 2023 at 12:50:45PM -0600, Jens Axboe wrote:
> On 3/15/23 12:39 PM, Eric Biggers wrote:
> > From: Eric Biggers <ebiggers@google.com>
> > 
> > To avoid hiding information, pass on the error code from
> > blk_crypto_rq_get_keyslot() instead of always using BLK_STS_IOERR.
> 
> Maybe just fold this with the previous patch?

I'd prefer to keep the behavior change separate from the cleanup.

- Eric

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 5/6] blk-mq: return actual keyslot error in blk_insert_cloned_request()
  2023-03-15 18:54     ` Eric Biggers
@ 2023-03-15 18:55       ` Jens Axboe
  2023-03-15 19:04         ` Eric Biggers
  0 siblings, 1 reply; 16+ messages in thread
From: Jens Axboe @ 2023-03-15 18:55 UTC (permalink / raw)
  To: Eric Biggers; +Cc: linux-block, linux-fscrypt, Nathan Huckleberry

On 3/15/23 12:54 PM, Eric Biggers wrote:
> On Wed, Mar 15, 2023 at 12:50:45PM -0600, Jens Axboe wrote:
>> On 3/15/23 12:39 PM, Eric Biggers wrote:
>>> From: Eric Biggers <ebiggers@google.com>
>>>
>>> To avoid hiding information, pass on the error code from
>>> blk_crypto_rq_get_keyslot() instead of always using BLK_STS_IOERR.
>>
>> Maybe just fold this with the previous patch?
> 
> I'd prefer to keep the behavior change separate from the cleanup.

OK fair enough, not a big deal to me. Series looks fine as far as
I'm concerned. Not loving the extra additions in the completion path,
but I suppose there's no way around that.

-- 
Jens Axboe



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 5/6] blk-mq: return actual keyslot error in blk_insert_cloned_request()
  2023-03-15 18:55       ` Jens Axboe
@ 2023-03-15 19:04         ` Eric Biggers
  0 siblings, 0 replies; 16+ messages in thread
From: Eric Biggers @ 2023-03-15 19:04 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block, linux-fscrypt, Nathan Huckleberry

On Wed, Mar 15, 2023 at 12:55:31PM -0600, Jens Axboe wrote:
> On 3/15/23 12:54 PM, Eric Biggers wrote:
> > On Wed, Mar 15, 2023 at 12:50:45PM -0600, Jens Axboe wrote:
> >> On 3/15/23 12:39 PM, Eric Biggers wrote:
> >>> From: Eric Biggers <ebiggers@google.com>
> >>>
> >>> To avoid hiding information, pass on the error code from
> >>> blk_crypto_rq_get_keyslot() instead of always using BLK_STS_IOERR.
> >>
> >> Maybe just fold this with the previous patch?
> > 
> > I'd prefer to keep the behavior change separate from the cleanup.
> 
> OK fair enough, not a big deal to me. Series looks fine as far as
> I'm concerned. Not loving the extra additions in the completion path,
> but I suppose there's no way around that.

Well, my first patch didn't have that:

https://lore.kernel.org/linux-block/20230226203816.207449-1-ebiggers@kernel.org

But it didn't fix the keyslot refcounting work as expected, which Nathan didn't
like (and I agree with that).

- Eric

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 2/6] blk-crypto: make blk_crypto_evict_key() return void
  2023-03-15 18:39 ` [PATCH v3 2/6] blk-crypto: make blk_crypto_evict_key() return void Eric Biggers
@ 2023-03-16 15:14   ` Christoph Hellwig
  0 siblings, 0 replies; 16+ messages in thread
From: Christoph Hellwig @ 2023-03-16 15:14 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-block, Jens Axboe, linux-fscrypt, Nathan Huckleberry, stable

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 3/6] blk-crypto: make blk_crypto_evict_key() more robust
  2023-03-15 18:39 ` [PATCH v3 3/6] blk-crypto: make blk_crypto_evict_key() more robust Eric Biggers
@ 2023-03-16 15:14   ` Christoph Hellwig
  0 siblings, 0 replies; 16+ messages in thread
From: Christoph Hellwig @ 2023-03-16 15:14 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-block, Jens Axboe, linux-fscrypt, Nathan Huckleberry, stable

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 4/6] blk-crypto: remove blk_crypto_insert_cloned_request()
  2023-03-15 18:39 ` [PATCH v3 4/6] blk-crypto: remove blk_crypto_insert_cloned_request() Eric Biggers
@ 2023-03-16 15:15   ` Christoph Hellwig
  0 siblings, 0 replies; 16+ messages in thread
From: Christoph Hellwig @ 2023-03-16 15:15 UTC (permalink / raw)
  To: Eric Biggers; +Cc: linux-block, Jens Axboe, linux-fscrypt, Nathan Huckleberry

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 5/6] blk-mq: return actual keyslot error in blk_insert_cloned_request()
  2023-03-15 18:39 ` [PATCH v3 5/6] blk-mq: return actual keyslot error in blk_insert_cloned_request() Eric Biggers
  2023-03-15 18:50   ` Jens Axboe
@ 2023-03-16 15:15   ` Christoph Hellwig
  1 sibling, 0 replies; 16+ messages in thread
From: Christoph Hellwig @ 2023-03-16 15:15 UTC (permalink / raw)
  To: Eric Biggers; +Cc: linux-block, Jens Axboe, linux-fscrypt, Nathan Huckleberry

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 0/6] Fix blk-crypto keyslot race condition
  2023-03-15 18:39 [PATCH v3 0/6] Fix blk-crypto keyslot race condition Eric Biggers
                   ` (5 preceding siblings ...)
  2023-03-15 18:39 ` [PATCH v3 6/6] blk-crypto: drop the NULL check from blk_crypto_put_keyslot() Eric Biggers
@ 2023-03-16 15:35 ` Jens Axboe
  6 siblings, 0 replies; 16+ messages in thread
From: Jens Axboe @ 2023-03-16 15:35 UTC (permalink / raw)
  To: linux-block, Eric Biggers; +Cc: linux-fscrypt, Nathan Huckleberry


On Wed, 15 Mar 2023 11:39:01 -0700, Eric Biggers wrote:
> 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/20230226203816.207449-1-ebiggers@kernel.org),
> which was a simpler fix but didn't fix the keyslot reference counting to
> work as expected.
> 
> [...]

Applied, thanks!

[1/6] blk-mq: release crypto keyslot before reporting I/O complete
      (no commit info)
[2/6] blk-crypto: make blk_crypto_evict_key() return void
      (no commit info)
[3/6] blk-crypto: make blk_crypto_evict_key() more robust
      (no commit info)
[4/6] blk-crypto: remove blk_crypto_insert_cloned_request()
      (no commit info)
[5/6] blk-mq: return actual keyslot error in blk_insert_cloned_request()
      (no commit info)
[6/6] blk-crypto: drop the NULL check from blk_crypto_put_keyslot()
      (no commit info)

Best regards,
-- 
Jens Axboe




^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2023-03-16 15:38 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-15 18:39 [PATCH v3 0/6] Fix blk-crypto keyslot race condition Eric Biggers
2023-03-15 18:39 ` [PATCH v3 1/6] blk-mq: release crypto keyslot before reporting I/O complete Eric Biggers
2023-03-15 18:39 ` [PATCH v3 2/6] blk-crypto: make blk_crypto_evict_key() return void Eric Biggers
2023-03-16 15:14   ` Christoph Hellwig
2023-03-15 18:39 ` [PATCH v3 3/6] blk-crypto: make blk_crypto_evict_key() more robust Eric Biggers
2023-03-16 15:14   ` Christoph Hellwig
2023-03-15 18:39 ` [PATCH v3 4/6] blk-crypto: remove blk_crypto_insert_cloned_request() Eric Biggers
2023-03-16 15:15   ` Christoph Hellwig
2023-03-15 18:39 ` [PATCH v3 5/6] blk-mq: return actual keyslot error in blk_insert_cloned_request() Eric Biggers
2023-03-15 18:50   ` Jens Axboe
2023-03-15 18:54     ` Eric Biggers
2023-03-15 18:55       ` Jens Axboe
2023-03-15 19:04         ` Eric Biggers
2023-03-16 15:15   ` Christoph Hellwig
2023-03-15 18:39 ` [PATCH v3 6/6] blk-crypto: drop the NULL check from blk_crypto_put_keyslot() Eric Biggers
2023-03-16 15:35 ` [PATCH v3 0/6] Fix blk-crypto keyslot race condition Jens Axboe

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.