[dm-devel] [RFC PATCH 2/2] dm crypt: Handle unaligned bio buffer lengths for lmk and tcw
Sudhakar Panneerselvam
sudhakar.panneerselvam at oracle.com
Wed Sep 16 18:40:06 UTC 2020
Us sg_miter_* apis to process unaligned buffer lengths while handling
bio buffers for lmk and tcw IV generation algorithms.
Signed-off-by: Sudhakar Panneerselvam <sudhakar.panneerselvam at oracle.com>
---
drivers/md/dm-crypt.c | 104 +++++++++++++++++++++++++++++++++-----------------
1 file changed, 68 insertions(+), 36 deletions(-)
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 9c26ad08732f..c40ada41d8ef 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -471,11 +471,13 @@ static int crypt_iv_lmk_wipe(struct crypt_config *cc)
static int crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
struct dm_crypt_request *dmreq,
- u8 *data)
+ struct scatterlist *sg)
{
struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
SHASH_DESC_ON_STACK(desc, lmk->hash_tfm);
+ struct sg_mapping_iter miter;
struct md5_state md5state;
+ size_t len = 16 * 31;
__le32 buf[4];
int i, r;
@@ -492,7 +494,19 @@ static int crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
}
/* Sector is always 512B, block size 16, add data of blocks 1-31 */
- r = crypto_shash_update(desc, data + 16, 16 * 31);
+ sg_miter_start(&miter, sg, sg_nents(sg),
+ SG_MITER_ATOMIC | SG_MITER_FROM_SG);
+ sg_miter_skip(&miter, 16);
+ while (sg_miter_next(&miter) && len > 0) {
+ size_t hash_len = min_t(size_t, miter.length, len);
+
+ r = crypto_shash_update(desc, miter.addr, hash_len);
+ if (r)
+ break;
+ len -= hash_len;
+ }
+ sg_miter_stop(&miter);
+
if (r)
return r;
@@ -520,15 +534,11 @@ static int crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
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_atomic(sg_page(sg));
- r = crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset);
- kunmap_atomic(src);
+ r = crypt_iv_lmk_one(cc, iv, dmreq,
+ crypt_get_sg_data(cc, dmreq->sg_in));
} else
memset(iv, 0, cc->iv_size);
@@ -538,22 +548,32 @@ static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv,
static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv,
struct dm_crypt_request *dmreq)
{
+ struct sg_mapping_iter miter;
struct scatterlist *sg;
- u8 *dst;
- int r;
+ int r, offset = 0;
+ size_t len;
if (bio_data_dir(dmreq->ctx->bio_in) == WRITE)
return 0;
sg = crypt_get_sg_data(cc, dmreq->sg_out);
- dst = kmap_atomic(sg_page(sg));
- r = crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset);
+ r = crypt_iv_lmk_one(cc, iv, dmreq, sg);
+ if (r)
+ return r;
/* Tweak the first block of plaintext sector */
- if (!r)
- crypto_xor(dst + sg->offset, iv, cc->iv_size);
+ len = cc->iv_size;
+ sg_miter_start(&miter, sg, sg_nents(sg),
+ SG_MITER_ATOMIC | SG_MITER_TO_SG);
+ while (sg_miter_next(&miter) && len > 0) {
+ size_t xor_len = min_t(size_t, miter.length, len);
+
+ crypto_xor(miter.addr, iv + offset, xor_len);
+ len -= xor_len;
+ offset += xor_len;
+ }
+ sg_miter_stop(&miter);
- kunmap_atomic(dst);
return r;
}
@@ -627,12 +647,14 @@ static int crypt_iv_tcw_wipe(struct crypt_config *cc)
static int crypt_iv_tcw_whitening(struct crypt_config *cc,
struct dm_crypt_request *dmreq,
- u8 *data)
+ struct scatterlist *sg)
{
struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw;
__le64 sector = cpu_to_le64(dmreq->iv_sector);
+ struct sg_mapping_iter miter;
u8 buf[TCW_WHITENING_SIZE];
SHASH_DESC_ON_STACK(desc, tcw->crc32_tfm);
+ size_t remain, sgoffset = 0;
int i, r;
/* xor whitening with sector number */
@@ -656,8 +678,31 @@ static int crypt_iv_tcw_whitening(struct crypt_config *cc,
crypto_xor(&buf[4], &buf[8], 4);
/* apply whitening (8 bytes) to whole sector */
- for (i = 0; i < ((1 << SECTOR_SHIFT) / 8); i++)
- crypto_xor(data + i * 8, buf, 8);
+ sg_miter_start(&miter, sg, sg_nents(sg),
+ SG_MITER_ATOMIC | SG_MITER_TO_SG);
+ sg_miter_next(&miter);
+ remain = miter.length;
+ for (i = 0; i < ((1 << SECTOR_SHIFT) / 8); i++) {
+ size_t len = 8, offset = 0;
+
+ while (len > 0) {
+ size_t xor_len = min_t(size_t, remain, len);
+
+ crypto_xor(miter.addr + sgoffset, buf + offset,
+ xor_len);
+ len -= xor_len;
+ remain -= xor_len;
+ offset += xor_len;
+ sgoffset += xor_len;
+ if (remain == 0) {
+ sg_miter_next(&miter);
+ sgoffset = 0;
+ remain = miter.length;
+ }
+ }
+ }
+ sg_miter_stop(&miter);
+
out:
memzero_explicit(buf, sizeof(buf));
return r;
@@ -666,19 +711,14 @@ static int crypt_iv_tcw_whitening(struct crypt_config *cc,
static int crypt_iv_tcw_gen(struct crypt_config *cc, u8 *iv,
struct dm_crypt_request *dmreq)
{
- struct scatterlist *sg;
struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw;
__le64 sector = cpu_to_le64(dmreq->iv_sector);
- u8 *src;
int r = 0;
/* Remove whitening from ciphertext */
- if (bio_data_dir(dmreq->ctx->bio_in) != WRITE) {
- sg = crypt_get_sg_data(cc, dmreq->sg_in);
- src = kmap_atomic(sg_page(sg));
- r = crypt_iv_tcw_whitening(cc, dmreq, src + sg->offset);
- kunmap_atomic(src);
- }
+ if (bio_data_dir(dmreq->ctx->bio_in) != WRITE)
+ r = crypt_iv_tcw_whitening(cc, dmreq,
+ crypt_get_sg_data(cc, dmreq->sg_in));
/* Calculate IV */
crypto_xor_cpy(iv, tcw->iv_seed, (u8 *)§or, 8);
@@ -692,20 +732,12 @@ static int crypt_iv_tcw_gen(struct crypt_config *cc, u8 *iv,
static int crypt_iv_tcw_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;
/* Apply whitening on ciphertext */
- sg = crypt_get_sg_data(cc, dmreq->sg_out);
- dst = kmap_atomic(sg_page(sg));
- r = crypt_iv_tcw_whitening(cc, dmreq, dst + sg->offset);
- kunmap_atomic(dst);
-
- return r;
+ return crypt_iv_tcw_whitening(cc, dmreq,
+ crypt_get_sg_data(cc, dmreq->sg_out));
}
static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
--
1.8.3.1
More information about the dm-devel
mailing list