From: Baokun Li <libaokun@linux.alibaba.com>
To: axboe@kernel.dk, linux-block@vger.kernel.org
Cc: ebiggers@kernel.org, linux-fscrypt@vger.kernel.org, hch@lst.de,
dm-devel@lists.linux.dev, mpatocka@redhat.com,
sweettea-kernel@dorminy.me, satyat@google.com,
libaokun@linux.alibaba.com, stable@vger.kernel.org,
Sashiko <sashiko-bot@kernel.org>
Subject: [PATCH v2 1/2] blk-crypto: fix NULL deref and UAF in __blk_crypto_evict_key()
Date: Wed, 14 Oct 2026 15:18:45 +0800 [thread overview]
Message-ID: <20261014071846.3666398-1-libaokun@linux.alibaba.com> (raw)
Sashiko reported a possible NULL pointer dereference, triggered by the
following flow:
dm-inlinecrypt ctor # first use of the fallback
├─ blk_crypto_init_key() # succeeds, ctx->key.size != 0
├─ blk_crypto_start_using_key()
│ ├─ hw-wrapped key: -EOPNOTSUPP
│ │ # profile never allocated (NULL)
│ └─ raw key: fallback_start_using_mode()
│ └─ blk_crypto_fallback_init() fails
│ └─ kfree(profile) # not NULLed
├─ goto bad
└─ inlinecrypt_dtr() # evicts whenever key.size is set
└─ blk_crypto_evict_key()
└─ blk_crypto_config_supported_natively() = false
└─ blk_crypto_fallback_evict_key()
└─ __blk_crypto_evict_key(blk_crypto_fallback_profile)
└─ profile->num_slots # BOOM!!!
This issue can be reproduced using the following commands:
dd if=/dev/zero of=/tmp/backing bs=1M count=64
LOOP=$(losetup -f --show /tmp/backing)
SZ=$(blockdev --getsz $LOOP)
KEY=$(head -c 64 /dev/urandom | od -An -tx1 | tr -d ' \n')
dmsetup create ic --table "0 $SZ inlinecrypt aes-xts-plain64 \
$KEY 0 $LOOP 0 1 keytype:hw-wrapped"
And the following oops is triggered:
==================================================================
blk-crypto: loop0: no support for wrapped keys
Oops: general protection fault, probably for non-canonical address
0xdffffc000000000b: 0000 [#1] SMP KASAN PTI
KASAN: null-ptr-deref in range [0x0000000000000058-0x000000000000005f]
CPU: 5 UID: 0 PID: 901 Comm: dmsetup 7.3.0-rc3 #1 PREEMPT(lazy)
RIP: 0010:__blk_crypto_evict_key+0x2e/0x3b0
Call Trace:
blk_crypto_evict_key+0x24c/0x320
inlinecrypt_dtr+0xf6/0x160
inlinecrypt_ctr+0x2d3/0xbd0
dm_table_add_target+0x661/0xf40
table_load+0x1c4/0x490
ctl_ioctl+0x32f/0x5f0
dm_ctl_ioctl+0xe/0x20
==================================================================
dm-inlinecrypt is the only caller that can evict a key that was never
started, as fscrypt frees such a key without evicting it.
Fix this by publishing blk_crypto_fallback_profile only after
blk_crypto_fallback_init() succeeds, and by returning early from
__blk_crypto_evict_key() when the profile is NULL. The eviction path
can then only observe either a NULL profile or a fully initialized
profile that is never freed. A key whose start failed cannot be in a
keyslot, so there is nothing to evict.
The profile pointer is published and read locklessly, so use
smp_store_release()/smp_load_acquire() to guarantee that a reader in
the eviction path that observes the pointer also observes the
initialized profile.
The bug has been latent since commit c984ff1423ae ("blk-crypto:
dynamically allocate fallback profile") was merged in v6.5, and only
became actually triggerable when commit e7f57d2c47e2 ("dm-inlinecrypt:
add target for inline block device encryption") was merged in v7.2.
Fixes: c984ff1423ae ("blk-crypto: dynamically allocate fallback profile")
Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://patch.msgid.link/sashiko-outbox-167341@kernel.org
Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
---
block/blk-crypto-fallback.c | 31 +++++++++++++++++++------------
block/blk-crypto-profile.c | 3 +++
2 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c
index 2a8f40a65158..b5dbb092caea 100644
--- a/block/blk-crypto-fallback.c
+++ b/block/blk-crypto-fallback.c
@@ -524,12 +524,18 @@ bool blk_crypto_fallback_bio_prep(struct bio *bio)
int blk_crypto_fallback_evict_key(const struct blk_crypto_key *key)
{
- return __blk_crypto_evict_key(blk_crypto_fallback_profile, key);
+ struct blk_crypto_profile *profile;
+
+ /* Pairs with smp_store_release() in blk_crypto_fallback_init(). */
+ profile = smp_load_acquire(&blk_crypto_fallback_profile);
+
+ return __blk_crypto_evict_key(profile, key);
}
static bool blk_crypto_fallback_inited;
static int blk_crypto_fallback_init(void)
{
+ struct blk_crypto_profile *profile;
int i;
int err;
@@ -543,26 +549,25 @@ static int blk_crypto_fallback_init(void)
goto out;
/* Dynamic allocation is needed because of lockdep_register_key(). */
- blk_crypto_fallback_profile = kzalloc_obj(*blk_crypto_fallback_profile);
- if (!blk_crypto_fallback_profile) {
+ profile = kzalloc_obj(*profile);
+ if (!profile) {
err = -ENOMEM;
goto fail_free_bioset;
}
- err = blk_crypto_profile_init(blk_crypto_fallback_profile,
- blk_crypto_num_keyslots);
+ err = blk_crypto_profile_init(profile, blk_crypto_num_keyslots);
if (err)
goto fail_free_profile;
err = -ENOMEM;
- blk_crypto_fallback_profile->ll_ops = blk_crypto_fallback_ll_ops;
- blk_crypto_fallback_profile->max_dun_bytes_supported = BLK_CRYPTO_MAX_IV_SIZE;
- blk_crypto_fallback_profile->key_types_supported = BLK_CRYPTO_KEY_TYPE_RAW;
+ profile->ll_ops = blk_crypto_fallback_ll_ops;
+ profile->max_dun_bytes_supported = BLK_CRYPTO_MAX_IV_SIZE;
+ profile->key_types_supported = BLK_CRYPTO_KEY_TYPE_RAW;
/* All blk-crypto modes have a crypto API fallback. */
for (i = 0; i < BLK_ENCRYPTION_MODE_MAX; i++)
- blk_crypto_fallback_profile->modes_supported[i] = 0xFFFFFFFF;
- blk_crypto_fallback_profile->modes_supported[BLK_ENCRYPTION_MODE_INVALID] = 0;
+ profile->modes_supported[i] = 0xFFFFFFFF;
+ profile->modes_supported[BLK_ENCRYPTION_MODE_INVALID] = 0;
blk_crypto_wq = alloc_workqueue("blk_crypto_wq",
WQ_UNBOUND | WQ_HIGHPRI |
@@ -590,6 +595,8 @@ static int blk_crypto_fallback_init(void)
if (!bio_fallback_crypt_ctx_pool)
goto fail_free_crypt_ctx_cache;
+ /* Pairs with smp_load_acquire() in blk_crypto_fallback_evict_key(). */
+ smp_store_release(&blk_crypto_fallback_profile, profile);
blk_crypto_fallback_inited = true;
return 0;
@@ -602,9 +609,9 @@ static int blk_crypto_fallback_init(void)
fail_free_wq:
destroy_workqueue(blk_crypto_wq);
fail_destroy_profile:
- blk_crypto_profile_destroy(blk_crypto_fallback_profile);
+ blk_crypto_profile_destroy(profile);
fail_free_profile:
- kfree(blk_crypto_fallback_profile);
+ kfree(profile);
fail_free_bioset:
bioset_exit(&enc_bio_set);
out:
diff --git a/block/blk-crypto-profile.c b/block/blk-crypto-profile.c
index 53126c091b0b..1c5feca3b856 100644
--- a/block/blk-crypto-profile.c
+++ b/block/blk-crypto-profile.c
@@ -346,6 +346,9 @@ int __blk_crypto_evict_key(struct blk_crypto_profile *profile,
struct blk_crypto_keyslot *slot;
int err;
+ if (!profile)
+ return 0;
+
if (profile->num_slots == 0) {
if (profile->ll_ops.keyslot_evict) {
blk_crypto_hw_enter(profile);
--
2.43.7
next reply other threads:[~2026-10-14 7:19 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-14 7:18 Baokun Li [this message]
2026-10-14 7:18 ` [PATCH v2 2/2] blk-crypto: fix missing smp_load_acquire() for tfms_inited[] Baokun Li
2026-10-14 16:11 ` Eric Biggers
2026-10-14 15:51 ` [PATCH v2 1/2] blk-crypto: fix NULL deref and UAF in __blk_crypto_evict_key() Eric Biggers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261014071846.3666398-1-libaokun@linux.alibaba.com \
--to=libaokun@linux.alibaba.com \
--cc=axboe@kernel.dk \
--cc=dm-devel@lists.linux.dev \
--cc=ebiggers@kernel.org \
--cc=hch@lst.de \
--cc=linux-block@vger.kernel.org \
--cc=linux-fscrypt@vger.kernel.org \
--cc=mpatocka@redhat.com \
--cc=sashiko-bot@kernel.org \
--cc=satyat@google.com \
--cc=stable@vger.kernel.org \
--cc=sweettea-kernel@dorminy.me \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox