linux-fscrypt.vger.kernel.org archive mirror
 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).