On Sat, 11 Oct 2025 at 20:12, Eric Biggers <[email protected]> wrote: > > The lmk IV mode, which dm-crypt supports for Loop-AES compatibility, > involves an MD5 computation. Update its implementation to use the MD5 > library API instead of crypto_shash. This has many benefits, such as: > > - Simpler code. Notably, much of the error-handling code is no longer > needed, since the library functions can't fail. > > - Reduced stack usage. crypt_iv_lmk_one() now allocates only 112 bytes > on the stack instead of 520 bytes. > > - The library functions are strongly typed, preventing bugs like > https://lore.kernel.org/r/[email protected] > > - Slightly improved performance, as the library provides direct access > to the MD5 code without unnecessary overhead such as indirect calls. > > To preserve the existing behavior of lmk support being disabled when the > kernel is booted with "fips=1", make crypt_iv_lmk_ctr() check > fips_enabled itself. Previously it relied on crypto_alloc_shash("md5") > failing. (I don't know for sure that lmk *actually* needs to be > disallowed in FIPS mode; this just preserves the existing behavior.) > > Signed-off-by: Eric Biggers <[email protected]>
Acked-by: Ard Biesheuvel <[email protected]> > --- > drivers/md/Kconfig | 1 + > drivers/md/dm-crypt.c | 76 ++++++++++++------------------------------- > 2 files changed, 22 insertions(+), 55 deletions(-) > > diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig > index 104aa53550905..dcd232a2ca244 100644 > --- a/drivers/md/Kconfig > +++ b/drivers/md/Kconfig > @@ -297,10 +297,11 @@ config DM_CRYPT > depends on (TRUSTED_KEYS || TRUSTED_KEYS=n) > select CRC32 > select CRYPTO > select CRYPTO_CBC > select CRYPTO_ESSIV > + select CRYPTO_LIB_MD5 # needed by lmk IV mode > help > This device-mapper target allows you to create a device that > transparently encrypts the data on it. You'll need to activate > the ciphers you're going to use in the cryptoapi configuration. > > diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c > index 5ef43231fe77f..04a553529dc27 100644 > --- a/drivers/md/dm-crypt.c > +++ b/drivers/md/dm-crypt.c > @@ -19,10 +19,11 @@ > #include <linux/blk-integrity.h> > #include <linux/crc32.h> > #include <linux/mempool.h> > #include <linux/slab.h> > #include <linux/crypto.h> > +#include <linux/fips.h> > #include <linux/workqueue.h> > #include <linux/kthread.h> > #include <linux/backing-dev.h> > #include <linux/atomic.h> > #include <linux/scatterlist.h> > @@ -118,11 +119,10 @@ struct iv_benbi_private { > int shift; > }; > > #define LMK_SEED_SIZE 64 /* hash + 0 */ > struct iv_lmk_private { > - struct crypto_shash *hash_tfm; > u8 *seed; > }; > > #define TCW_WHITENING_SIZE 16 > struct iv_tcw_private { > @@ -463,14 +463,10 @@ static int crypt_iv_null_gen(struct crypt_config *cc, > u8 *iv, > > static void crypt_iv_lmk_dtr(struct crypt_config *cc) > { > struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk; > > - if (lmk->hash_tfm && !IS_ERR(lmk->hash_tfm)) > - crypto_free_shash(lmk->hash_tfm); > - lmk->hash_tfm = NULL; > - > kfree_sensitive(lmk->seed); > lmk->seed = NULL; > } > > static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti, > @@ -481,26 +477,24 @@ static int crypt_iv_lmk_ctr(struct crypt_config *cc, > struct dm_target *ti, > if (cc->sector_size != (1 << SECTOR_SHIFT)) { > ti->error = "Unsupported sector size for LMK"; > return -EINVAL; > } > > - lmk->hash_tfm = crypto_alloc_shash("md5", 0, > - CRYPTO_ALG_ALLOCATES_MEMORY); > - if (IS_ERR(lmk->hash_tfm)) { > - ti->error = "Error initializing LMK hash"; > - return PTR_ERR(lmk->hash_tfm); > + if (fips_enabled) { > + ti->error = "LMK support is disabled due to FIPS"; > + /* ... because it uses MD5. */ > + return -EINVAL; > } > > /* No seed in LMK version 2 */ > if (cc->key_parts == cc->tfms_count) { > lmk->seed = NULL; > return 0; > } > > lmk->seed = kzalloc(LMK_SEED_SIZE, GFP_KERNEL); > if (!lmk->seed) { > - crypt_iv_lmk_dtr(cc); > ti->error = "Error kmallocing seed storage in LMK"; > return -ENOMEM; > } > > return 0; > @@ -512,11 +506,11 @@ static int crypt_iv_lmk_init(struct crypt_config *cc) > int subkey_size = cc->key_size / cc->key_parts; > > /* LMK seed is on the position of LMK_KEYS + 1 key */ > if (lmk->seed) > memcpy(lmk->seed, cc->key + (cc->tfms_count * subkey_size), > - crypto_shash_digestsize(lmk->hash_tfm)); > + MD5_DIGEST_SIZE); > > return 0; > } > > static int crypt_iv_lmk_wipe(struct crypt_config *cc) > @@ -527,99 +521,71 @@ static int crypt_iv_lmk_wipe(struct crypt_config *cc) > memset(lmk->seed, 0, LMK_SEED_SIZE); > > return 0; > } > > -static int crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv, > - struct dm_crypt_request *dmreq, > - u8 *data) > +static void crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv, > + struct dm_crypt_request *dmreq, u8 *data) > { > struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk; > - SHASH_DESC_ON_STACK(desc, lmk->hash_tfm); > - union { > - struct md5_state md5state; > - u8 state[CRYPTO_MD5_STATESIZE]; > - } u; > + struct md5_ctx ctx; > __le32 buf[4]; > - int i, r; > > - desc->tfm = lmk->hash_tfm; > - > - r = crypto_shash_init(desc); > - if (r) > - return r; > + md5_init(&ctx); > > - if (lmk->seed) { > - r = crypto_shash_update(desc, lmk->seed, LMK_SEED_SIZE); > - if (r) > - return r; > - } > + if (lmk->seed) > + md5_update(&ctx, lmk->seed, LMK_SEED_SIZE); > > /* Sector is always 512B, block size 16, add data of blocks 1-31 */ > - r = crypto_shash_update(desc, data + 16, 16 * 31); > - if (r) > - return r; > + md5_update(&ctx, data + 16, 16 * 31); > > /* Sector is cropped to 56 bits here */ > buf[0] = cpu_to_le32(dmreq->iv_sector & 0xFFFFFFFF); > buf[1] = cpu_to_le32((((u64)dmreq->iv_sector >> 32) & 0x00FFFFFF) | > 0x80000000); > buf[2] = cpu_to_le32(4024); > buf[3] = 0; > - r = crypto_shash_update(desc, (u8 *)buf, sizeof(buf)); > - if (r) > - return r; > + md5_update(&ctx, (u8 *)buf, sizeof(buf)); > > /* No MD5 padding here */ > - r = crypto_shash_export(desc, &u.md5state); > - if (r) > - return r; > - > - for (i = 0; i < MD5_HASH_WORDS; i++) > - __cpu_to_le32s(&u.md5state.hash[i]); > - memcpy(iv, &u.md5state.hash, cc->iv_size); > - > - return 0; > + cpu_to_le32_array(ctx.state.h, ARRAY_SIZE(ctx.state.h)); > + memcpy(iv, ctx.state.h, cc->iv_size); > } > > static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv, > struct dm_crypt_request *dmreq) > { > struct scatterlist *sg; > u8 *src; > - int r = 0; > > if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) { > sg = crypt_get_sg_data(cc, dmreq->sg_in); > src = kmap_local_page(sg_page(sg)); > - r = crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset); > + crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset); > kunmap_local(src); > } else > memset(iv, 0, cc->iv_size); > - > - return r; > + return 0; > } > > static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv, > struct dm_crypt_request *dmreq) > { > struct scatterlist *sg; > u8 *dst; > - int r; > > if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) > return 0; > > sg = crypt_get_sg_data(cc, dmreq->sg_out); > dst = kmap_local_page(sg_page(sg)); > - r = crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset); > + crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset); > > /* Tweak the first block of plaintext sector */ > - if (!r) > - crypto_xor(dst + sg->offset, iv, cc->iv_size); > + crypto_xor(dst + sg->offset, iv, cc->iv_size); > > kunmap_local(dst); > - return r; > + return 0; > } > > static void crypt_iv_tcw_dtr(struct crypt_config *cc) > { > struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw; > > base-commit: 8bd9238e511d02831022ff0270865c54ccc482d6 > -- > 2.51.0 > >
