提交 28513fcc 编写于 作者: M Milan Broz 提交者: Alasdair G Kergon

dm crypt: simplify crypt_config destruction logic

Use just one label and reuse common destructor for crypt target.

Parse remaining argv arguments in logic order.

Also do not ignore error values from IV init and set key functions.

No functional change in this patch except changed return codes
based on above.
Signed-off-by: NMilan Broz <mbroz@redhat.com>
Signed-off-by: NAlasdair G Kergon <agk@redhat.com>
上级 7e507eb6
...@@ -999,6 +999,45 @@ static int crypt_wipe_key(struct crypt_config *cc) ...@@ -999,6 +999,45 @@ static int crypt_wipe_key(struct crypt_config *cc)
return crypto_ablkcipher_setkey(cc->tfm, cc->key, cc->key_size); return crypto_ablkcipher_setkey(cc->tfm, cc->key, cc->key_size);
} }
static void crypt_dtr(struct dm_target *ti)
{
struct crypt_config *cc = ti->private;
ti->private = NULL;
if (!cc)
return;
if (cc->io_queue)
destroy_workqueue(cc->io_queue);
if (cc->crypt_queue)
destroy_workqueue(cc->crypt_queue);
if (cc->bs)
bioset_free(cc->bs);
if (cc->page_pool)
mempool_destroy(cc->page_pool);
if (cc->req_pool)
mempool_destroy(cc->req_pool);
if (cc->io_pool)
mempool_destroy(cc->io_pool);
if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
if (cc->tfm && !IS_ERR(cc->tfm))
crypto_free_ablkcipher(cc->tfm);
if (cc->dev)
dm_put_device(ti, cc->dev);
kfree(cc->iv_mode);
/* Must zero key material before freeing */
kzfree(cc);
}
/* /*
* Construct an encryption mapping: * Construct an encryption mapping:
* <cipher> <key> <iv_offset> <dev_path> <start> * <cipher> <key> <iv_offset> <dev_path> <start>
...@@ -1006,7 +1045,6 @@ static int crypt_wipe_key(struct crypt_config *cc) ...@@ -1006,7 +1045,6 @@ static int crypt_wipe_key(struct crypt_config *cc)
static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{ {
struct crypt_config *cc; struct crypt_config *cc;
struct crypto_ablkcipher *tfm;
char *tmp; char *tmp;
char *cipher; char *cipher;
char *chainmode; char *chainmode;
...@@ -1014,6 +1052,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -1014,6 +1052,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
char *ivopts; char *ivopts;
unsigned int key_size; unsigned int key_size;
unsigned long long tmpll; unsigned long long tmpll;
int ret = -EINVAL;
if (argc != 5) { if (argc != 5) {
ti->error = "Not enough arguments"; ti->error = "Not enough arguments";
...@@ -1032,12 +1071,13 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -1032,12 +1071,13 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
key_size = strlen(argv[1]) >> 1; key_size = strlen(argv[1]) >> 1;
cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL); cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
if (cc == NULL) { if (!cc) {
ti->error = ti->error = "Cannot allocate transparent encryption context";
"Cannot allocate transparent encryption context";
return -ENOMEM; return -ENOMEM;
} }
ti->private = cc;
/* Compatibility mode for old dm-crypt cipher strings */ /* Compatibility mode for old dm-crypt cipher strings */
if (!chainmode || (strcmp(chainmode, "plain") == 0 && !ivmode)) { if (!chainmode || (strcmp(chainmode, "plain") == 0 && !ivmode)) {
chainmode = "cbc"; chainmode = "cbc";
...@@ -1046,35 +1086,36 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -1046,35 +1086,36 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (strcmp(chainmode, "ecb") && !ivmode) { if (strcmp(chainmode, "ecb") && !ivmode) {
ti->error = "This chaining mode requires an IV mechanism"; ti->error = "This chaining mode requires an IV mechanism";
goto bad_cipher; goto bad;
} }
ret = -ENOMEM;
if (snprintf(cc->cipher, CRYPTO_MAX_ALG_NAME, "%s(%s)", if (snprintf(cc->cipher, CRYPTO_MAX_ALG_NAME, "%s(%s)",
chainmode, cipher) >= CRYPTO_MAX_ALG_NAME) { chainmode, cipher) >= CRYPTO_MAX_ALG_NAME) {
ti->error = "Chain mode + cipher name is too long"; ti->error = "Chain mode + cipher name is too long";
goto bad_cipher; goto bad;
} }
tfm = crypto_alloc_ablkcipher(cc->cipher, 0, 0); cc->tfm = crypto_alloc_ablkcipher(cc->cipher, 0, 0);
if (IS_ERR(tfm)) { if (IS_ERR(cc->tfm)) {
ti->error = "Error allocating crypto tfm"; ti->error = "Error allocating crypto tfm";
goto bad_cipher; goto bad;
} }
strcpy(cc->cipher, cipher); strcpy(cc->cipher, cipher);
strcpy(cc->chainmode, chainmode); strcpy(cc->chainmode, chainmode);
cc->tfm = tfm;
if (crypt_set_key(cc, argv[1]) < 0) { ret = crypt_set_key(cc, argv[1]);
if (ret < 0) {
ti->error = "Error decoding and setting key"; ti->error = "Error decoding and setting key";
goto bad_ivmode; goto bad;
} }
/* /*
* Choose ivmode. Valid modes: "plain", "essiv:<esshash>", "benbi". * Choose ivmode. Valid modes: "plain", "essiv:<esshash>", "benbi".
* See comments at iv code * See comments at iv code
*/ */
ret = -EINVAL;
if (ivmode == NULL) if (ivmode == NULL)
cc->iv_gen_ops = NULL; cc->iv_gen_ops = NULL;
else if (strcmp(ivmode, "plain") == 0) else if (strcmp(ivmode, "plain") == 0)
...@@ -1089,20 +1130,28 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -1089,20 +1130,28 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
cc->iv_gen_ops = &crypt_iv_null_ops; cc->iv_gen_ops = &crypt_iv_null_ops;
else { else {
ti->error = "Invalid IV mode"; ti->error = "Invalid IV mode";
goto bad_ivmode; goto bad;
} }
if (cc->iv_gen_ops && cc->iv_gen_ops->ctr && /* Allocate IV */
cc->iv_gen_ops->ctr(cc, ti, ivopts) < 0) if (cc->iv_gen_ops && cc->iv_gen_ops->ctr) {
goto bad_ivmode; ret = cc->iv_gen_ops->ctr(cc, ti, ivopts);
if (ret < 0) {
ti->error = "Error creating IV";
goto bad;
}
}
if (cc->iv_gen_ops && cc->iv_gen_ops->init && /* Initialize IV (set keys for ESSIV etc) */
cc->iv_gen_ops->init(cc) < 0) { if (cc->iv_gen_ops && cc->iv_gen_ops->init) {
ti->error = "Error initialising IV"; ret = cc->iv_gen_ops->init(cc);
goto bad_slab_pool; if (ret < 0) {
ti->error = "Error initialising IV";
goto bad;
}
} }
cc->iv_size = crypto_ablkcipher_ivsize(tfm); cc->iv_size = crypto_ablkcipher_ivsize(cc->tfm);
if (cc->iv_size) if (cc->iv_size)
/* at least a 64 bit sector number should fit in our buffer */ /* at least a 64 bit sector number should fit in our buffer */
cc->iv_size = max(cc->iv_size, cc->iv_size = max(cc->iv_size,
...@@ -1116,62 +1165,65 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -1116,62 +1165,65 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
} }
} }
ret = -ENOMEM;
cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool); cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool);
if (!cc->io_pool) { if (!cc->io_pool) {
ti->error = "Cannot allocate crypt io mempool"; ti->error = "Cannot allocate crypt io mempool";
goto bad_slab_pool; goto bad;
} }
cc->dmreq_start = sizeof(struct ablkcipher_request); cc->dmreq_start = sizeof(struct ablkcipher_request);
cc->dmreq_start += crypto_ablkcipher_reqsize(tfm); cc->dmreq_start += crypto_ablkcipher_reqsize(cc->tfm);
cc->dmreq_start = ALIGN(cc->dmreq_start, crypto_tfm_ctx_alignment()); cc->dmreq_start = ALIGN(cc->dmreq_start, crypto_tfm_ctx_alignment());
cc->dmreq_start += crypto_ablkcipher_alignmask(tfm) & cc->dmreq_start += crypto_ablkcipher_alignmask(cc->tfm) &
~(crypto_tfm_ctx_alignment() - 1); ~(crypto_tfm_ctx_alignment() - 1);
cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start + cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start +
sizeof(struct dm_crypt_request) + cc->iv_size); sizeof(struct dm_crypt_request) + cc->iv_size);
if (!cc->req_pool) { if (!cc->req_pool) {
ti->error = "Cannot allocate crypt request mempool"; ti->error = "Cannot allocate crypt request mempool";
goto bad_req_pool; goto bad;
} }
cc->req = NULL; cc->req = NULL;
cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0); cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
if (!cc->page_pool) { if (!cc->page_pool) {
ti->error = "Cannot allocate page mempool"; ti->error = "Cannot allocate page mempool";
goto bad_page_pool; goto bad;
} }
cc->bs = bioset_create(MIN_IOS, 0); cc->bs = bioset_create(MIN_IOS, 0);
if (!cc->bs) { if (!cc->bs) {
ti->error = "Cannot allocate crypt bioset"; ti->error = "Cannot allocate crypt bioset";
goto bad_bs; goto bad;
} }
ret = -EINVAL;
if (sscanf(argv[2], "%llu", &tmpll) != 1) { if (sscanf(argv[2], "%llu", &tmpll) != 1) {
ti->error = "Invalid iv_offset sector"; ti->error = "Invalid iv_offset sector";
goto bad_device; goto bad;
} }
cc->iv_offset = tmpll; cc->iv_offset = tmpll;
if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &cc->dev)) {
ti->error = "Device lookup failed";
goto bad;
}
if (sscanf(argv[4], "%llu", &tmpll) != 1) { if (sscanf(argv[4], "%llu", &tmpll) != 1) {
ti->error = "Invalid device sector"; ti->error = "Invalid device sector";
goto bad_device; goto bad;
} }
cc->start = tmpll; cc->start = tmpll;
if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &cc->dev)) { ret = -ENOMEM;
ti->error = "Device lookup failed";
goto bad_device;
}
if (ivmode && cc->iv_gen_ops) { if (ivmode && cc->iv_gen_ops) {
if (ivopts) if (ivopts)
*(ivopts - 1) = ':'; *(ivopts - 1) = ':';
cc->iv_mode = kstrdup(ivmode, GFP_KERNEL); cc->iv_mode = kstrdup(ivmode, GFP_KERNEL);
if (!cc->iv_mode) { if (!cc->iv_mode) {
ti->error = "Error kmallocing iv_mode string"; ti->error = "Error kmallocing iv_mode string";
goto bad_ivmode_string; goto bad;
} }
} else } else
cc->iv_mode = NULL; cc->iv_mode = NULL;
...@@ -1179,67 +1231,21 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -1179,67 +1231,21 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
cc->io_queue = create_singlethread_workqueue("kcryptd_io"); cc->io_queue = create_singlethread_workqueue("kcryptd_io");
if (!cc->io_queue) { if (!cc->io_queue) {
ti->error = "Couldn't create kcryptd io queue"; ti->error = "Couldn't create kcryptd io queue";
goto bad_io_queue; goto bad;
} }
cc->crypt_queue = create_singlethread_workqueue("kcryptd"); cc->crypt_queue = create_singlethread_workqueue("kcryptd");
if (!cc->crypt_queue) { if (!cc->crypt_queue) {
ti->error = "Couldn't create kcryptd queue"; ti->error = "Couldn't create kcryptd queue";
goto bad_crypt_queue; goto bad;
} }
ti->num_flush_requests = 1; ti->num_flush_requests = 1;
ti->private = cc;
return 0; return 0;
bad_crypt_queue: bad:
destroy_workqueue(cc->io_queue); crypt_dtr(ti);
bad_io_queue: return ret;
kfree(cc->iv_mode);
bad_ivmode_string:
dm_put_device(ti, cc->dev);
bad_device:
bioset_free(cc->bs);
bad_bs:
mempool_destroy(cc->page_pool);
bad_page_pool:
mempool_destroy(cc->req_pool);
bad_req_pool:
mempool_destroy(cc->io_pool);
bad_slab_pool:
if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
bad_ivmode:
crypto_free_ablkcipher(tfm);
bad_cipher:
/* Must zero key material before freeing */
kzfree(cc);
return -EINVAL;
}
static void crypt_dtr(struct dm_target *ti)
{
struct crypt_config *cc = (struct crypt_config *) ti->private;
destroy_workqueue(cc->io_queue);
destroy_workqueue(cc->crypt_queue);
if (cc->req)
mempool_free(cc->req, cc->req_pool);
bioset_free(cc->bs);
mempool_destroy(cc->page_pool);
mempool_destroy(cc->req_pool);
mempool_destroy(cc->io_pool);
kfree(cc->iv_mode);
if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
crypto_free_ablkcipher(cc->tfm);
dm_put_device(ti, cc->dev);
/* Must zero key material before freeing */
kzfree(cc);
} }
static int crypt_map(struct dm_target *ti, struct bio *bio, static int crypt_map(struct dm_target *ti, struct bio *bio,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册