mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 23:34:05 +08:00
dm crypt: simplify crypt_ctr
Allocate cipher strings indpendently of struct crypt_config and move cipher parsing and allocation into a separate function to prepare for supporting the cryptoapi format e.g. "xts(aes)". No functional change in this patch. Signed-off-by: Milan Broz <mbroz@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
This commit is contained in:
parent
28513fccf0
commit
5ebaee6d29
@ -107,11 +107,10 @@ struct crypt_config {
|
||||
struct workqueue_struct *io_queue;
|
||||
struct workqueue_struct *crypt_queue;
|
||||
|
||||
/*
|
||||
* crypto related data
|
||||
*/
|
||||
char *cipher;
|
||||
char *cipher_mode;
|
||||
|
||||
struct crypt_iv_operations *iv_gen_ops;
|
||||
char *iv_mode;
|
||||
union {
|
||||
struct iv_essiv_private essiv;
|
||||
struct iv_benbi_private benbi;
|
||||
@ -135,8 +134,6 @@ struct crypt_config {
|
||||
unsigned int dmreq_start;
|
||||
struct ablkcipher_request *req;
|
||||
|
||||
char cipher[CRYPTO_MAX_ALG_NAME];
|
||||
char chainmode[CRYPTO_MAX_ALG_NAME];
|
||||
struct crypto_ablkcipher *tfm;
|
||||
unsigned long flags;
|
||||
unsigned int key_size;
|
||||
@ -1032,90 +1029,102 @@ static void crypt_dtr(struct dm_target *ti)
|
||||
if (cc->dev)
|
||||
dm_put_device(ti, cc->dev);
|
||||
|
||||
kfree(cc->iv_mode);
|
||||
kzfree(cc->cipher);
|
||||
kzfree(cc->cipher_mode);
|
||||
|
||||
/* Must zero key material before freeing */
|
||||
kzfree(cc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct an encryption mapping:
|
||||
* <cipher> <key> <iv_offset> <dev_path> <start>
|
||||
*/
|
||||
static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
static int crypt_ctr_cipher(struct dm_target *ti,
|
||||
char *cipher_in, char *key)
|
||||
{
|
||||
struct crypt_config *cc;
|
||||
char *tmp;
|
||||
char *cipher;
|
||||
char *chainmode;
|
||||
char *ivmode;
|
||||
char *ivopts;
|
||||
unsigned int key_size;
|
||||
unsigned long long tmpll;
|
||||
struct crypt_config *cc = ti->private;
|
||||
char *tmp, *cipher, *chainmode, *ivmode, *ivopts;
|
||||
char *cipher_api = NULL;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (argc != 5) {
|
||||
ti->error = "Not enough arguments";
|
||||
/* Convert to crypto api definition? */
|
||||
if (strchr(cipher_in, '(')) {
|
||||
ti->error = "Bad cipher specification";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tmp = argv[0];
|
||||
/*
|
||||
* Legacy dm-crypt cipher specification
|
||||
* cipher-mode-iv:ivopts
|
||||
*/
|
||||
tmp = cipher_in;
|
||||
cipher = strsep(&tmp, "-");
|
||||
|
||||
cc->cipher = kstrdup(cipher, GFP_KERNEL);
|
||||
if (!cc->cipher)
|
||||
goto bad_mem;
|
||||
|
||||
if (tmp) {
|
||||
cc->cipher_mode = kstrdup(tmp, GFP_KERNEL);
|
||||
if (!cc->cipher_mode)
|
||||
goto bad_mem;
|
||||
}
|
||||
|
||||
chainmode = strsep(&tmp, "-");
|
||||
ivopts = strsep(&tmp, "-");
|
||||
ivmode = strsep(&ivopts, ":");
|
||||
|
||||
if (tmp)
|
||||
DMWARN("Unexpected additional cipher options");
|
||||
DMWARN("Ignoring unexpected additional cipher options");
|
||||
|
||||
key_size = strlen(argv[1]) >> 1;
|
||||
|
||||
cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
|
||||
if (!cc) {
|
||||
ti->error = "Cannot allocate transparent encryption context";
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ti->private = cc;
|
||||
|
||||
/* Compatibility mode for old dm-crypt cipher strings */
|
||||
if (!chainmode || (strcmp(chainmode, "plain") == 0 && !ivmode)) {
|
||||
/* Compatibility mode for old dm-crypt mappings */
|
||||
if (!chainmode || (!strcmp(chainmode, "plain") && !ivmode)) {
|
||||
kfree(cc->cipher_mode);
|
||||
cc->cipher_mode = kstrdup("cbc-plain", GFP_KERNEL);
|
||||
chainmode = "cbc";
|
||||
ivmode = "plain";
|
||||
}
|
||||
|
||||
if (strcmp(chainmode, "ecb") && !ivmode) {
|
||||
ti->error = "This chaining mode requires an IV mechanism";
|
||||
goto bad;
|
||||
ti->error = "IV mechanism required";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
if (snprintf(cc->cipher, CRYPTO_MAX_ALG_NAME, "%s(%s)",
|
||||
chainmode, cipher) >= CRYPTO_MAX_ALG_NAME) {
|
||||
ti->error = "Chain mode + cipher name is too long";
|
||||
goto bad;
|
||||
cipher_api = kmalloc(CRYPTO_MAX_ALG_NAME, GFP_KERNEL);
|
||||
if (!cipher_api)
|
||||
goto bad_mem;
|
||||
|
||||
ret = snprintf(cipher_api, CRYPTO_MAX_ALG_NAME,
|
||||
"%s(%s)", chainmode, cipher);
|
||||
if (ret < 0) {
|
||||
kfree(cipher_api);
|
||||
goto bad_mem;
|
||||
}
|
||||
|
||||
cc->tfm = crypto_alloc_ablkcipher(cc->cipher, 0, 0);
|
||||
/* Allocate cipher */
|
||||
cc->tfm = crypto_alloc_ablkcipher(cipher_api, 0, 0);
|
||||
if (IS_ERR(cc->tfm)) {
|
||||
ret = PTR_ERR(cc->tfm);
|
||||
ti->error = "Error allocating crypto tfm";
|
||||
goto bad;
|
||||
}
|
||||
|
||||
strcpy(cc->cipher, cipher);
|
||||
strcpy(cc->chainmode, chainmode);
|
||||
|
||||
ret = crypt_set_key(cc, argv[1]);
|
||||
/* Initialize and set key */
|
||||
ret = crypt_set_key(cc, key);
|
||||
if (ret < 0) {
|
||||
ti->error = "Error decoding and setting key";
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Choose ivmode. Valid modes: "plain", "essiv:<esshash>", "benbi".
|
||||
* See comments at iv code
|
||||
*/
|
||||
ret = -EINVAL;
|
||||
/* Initialize IV */
|
||||
cc->iv_size = crypto_ablkcipher_ivsize(cc->tfm);
|
||||
if (cc->iv_size)
|
||||
/* at least a 64 bit sector number should fit in our buffer */
|
||||
cc->iv_size = max(cc->iv_size,
|
||||
(unsigned int)(sizeof(u64) / sizeof(u8)));
|
||||
else if (ivmode) {
|
||||
DMWARN("Selected cipher does not support IVs");
|
||||
ivmode = NULL;
|
||||
}
|
||||
|
||||
/* Choose ivmode, see comments at iv code. */
|
||||
if (ivmode == NULL)
|
||||
cc->iv_gen_ops = NULL;
|
||||
else if (strcmp(ivmode, "plain") == 0)
|
||||
@ -1129,6 +1138,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
else if (strcmp(ivmode, "null") == 0)
|
||||
cc->iv_gen_ops = &crypt_iv_null_ops;
|
||||
else {
|
||||
ret = -EINVAL;
|
||||
ti->error = "Invalid IV mode";
|
||||
goto bad;
|
||||
}
|
||||
@ -1151,20 +1161,45 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
cc->iv_size = crypto_ablkcipher_ivsize(cc->tfm);
|
||||
if (cc->iv_size)
|
||||
/* at least a 64 bit sector number should fit in our buffer */
|
||||
cc->iv_size = max(cc->iv_size,
|
||||
(unsigned int)(sizeof(u64) / sizeof(u8)));
|
||||
else {
|
||||
if (cc->iv_gen_ops) {
|
||||
DMWARN("Selected cipher does not support IVs");
|
||||
if (cc->iv_gen_ops->dtr)
|
||||
cc->iv_gen_ops->dtr(cc);
|
||||
cc->iv_gen_ops = NULL;
|
||||
}
|
||||
ret = 0;
|
||||
bad:
|
||||
kfree(cipher_api);
|
||||
return ret;
|
||||
|
||||
bad_mem:
|
||||
ti->error = "Cannot allocate cipher strings";
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct an encryption mapping:
|
||||
* <cipher> <key> <iv_offset> <dev_path> <start>
|
||||
*/
|
||||
static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
{
|
||||
struct crypt_config *cc;
|
||||
unsigned int key_size;
|
||||
unsigned long long tmpll;
|
||||
int ret;
|
||||
|
||||
if (argc != 5) {
|
||||
ti->error = "Not enough arguments";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_size = strlen(argv[1]) >> 1;
|
||||
|
||||
cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
|
||||
if (!cc) {
|
||||
ti->error = "Cannot allocate encryption context";
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ti->private = cc;
|
||||
ret = crypt_ctr_cipher(ti, argv[0], argv[1]);
|
||||
if (ret < 0)
|
||||
goto bad;
|
||||
|
||||
ret = -ENOMEM;
|
||||
cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool);
|
||||
if (!cc->io_pool) {
|
||||
@ -1217,17 +1252,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
cc->start = tmpll;
|
||||
|
||||
ret = -ENOMEM;
|
||||
if (ivmode && cc->iv_gen_ops) {
|
||||
if (ivopts)
|
||||
*(ivopts - 1) = ':';
|
||||
cc->iv_mode = kstrdup(ivmode, GFP_KERNEL);
|
||||
if (!cc->iv_mode) {
|
||||
ti->error = "Error kmallocing iv_mode string";
|
||||
goto bad;
|
||||
}
|
||||
} else
|
||||
cc->iv_mode = NULL;
|
||||
|
||||
cc->io_queue = create_singlethread_workqueue("kcryptd_io");
|
||||
if (!cc->io_queue) {
|
||||
ti->error = "Couldn't create kcryptd io queue";
|
||||
@ -1273,7 +1297,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
|
||||
static int crypt_status(struct dm_target *ti, status_type_t type,
|
||||
char *result, unsigned int maxlen)
|
||||
{
|
||||
struct crypt_config *cc = (struct crypt_config *) ti->private;
|
||||
struct crypt_config *cc = ti->private;
|
||||
unsigned int sz = 0;
|
||||
|
||||
switch (type) {
|
||||
@ -1282,11 +1306,10 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
|
||||
break;
|
||||
|
||||
case STATUSTYPE_TABLE:
|
||||
if (cc->iv_mode)
|
||||
DMEMIT("%s-%s-%s ", cc->cipher, cc->chainmode,
|
||||
cc->iv_mode);
|
||||
if (cc->cipher_mode)
|
||||
DMEMIT("%s-%s ", cc->cipher, cc->cipher_mode);
|
||||
else
|
||||
DMEMIT("%s-%s ", cc->cipher, cc->chainmode);
|
||||
DMEMIT("%s ", cc->cipher);
|
||||
|
||||
if (cc->key_size > 0) {
|
||||
if ((maxlen - sz) < ((cc->key_size << 1) + 1))
|
||||
|
Loading…
Reference in New Issue
Block a user