Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5ebaee6d authored by Milan Broz's avatar Milan Broz Committed by Alasdair G Kergon
Browse files

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: default avatarMilan Broz <mbroz@redhat.com>
Signed-off-by: default avatarAlasdair G Kergon <agk@redhat.com>
parent 28513fcc
Loading
Loading
Loading
Loading
+104 −81
Original line number Original line Diff line number Diff line
@@ -107,11 +107,10 @@ struct crypt_config {
	struct workqueue_struct *io_queue;
	struct workqueue_struct *io_queue;
	struct workqueue_struct *crypt_queue;
	struct workqueue_struct *crypt_queue;


	/*
	char *cipher;
	 * crypto related data
	char *cipher_mode;
	 */

	struct crypt_iv_operations *iv_gen_ops;
	struct crypt_iv_operations *iv_gen_ops;
	char *iv_mode;
	union {
	union {
		struct iv_essiv_private essiv;
		struct iv_essiv_private essiv;
		struct iv_benbi_private benbi;
		struct iv_benbi_private benbi;
@@ -135,8 +134,6 @@ struct crypt_config {
	unsigned int dmreq_start;
	unsigned int dmreq_start;
	struct ablkcipher_request *req;
	struct ablkcipher_request *req;


	char cipher[CRYPTO_MAX_ALG_NAME];
	char chainmode[CRYPTO_MAX_ALG_NAME];
	struct crypto_ablkcipher *tfm;
	struct crypto_ablkcipher *tfm;
	unsigned long flags;
	unsigned long flags;
	unsigned int key_size;
	unsigned int key_size;
@@ -1032,90 +1029,102 @@ static void crypt_dtr(struct dm_target *ti)
	if (cc->dev)
	if (cc->dev)
		dm_put_device(ti, 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 */
	/* Must zero key material before freeing */
	kzfree(cc);
	kzfree(cc);
}
}


/*
static int crypt_ctr_cipher(struct dm_target *ti,
 * Construct an encryption mapping:
			    char *cipher_in, char *key)
 * <cipher> <key> <iv_offset> <dev_path> <start>
 */
static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
{
	struct crypt_config *cc;
	struct crypt_config *cc = ti->private;
	char *tmp;
	char *tmp, *cipher, *chainmode, *ivmode, *ivopts;
	char *cipher;
	char *cipher_api = NULL;
	char *chainmode;
	char *ivmode;
	char *ivopts;
	unsigned int key_size;
	unsigned long long tmpll;
	int ret = -EINVAL;
	int ret = -EINVAL;


	if (argc != 5) {
	/* Convert to crypto api definition? */
		ti->error = "Not enough arguments";
	if (strchr(cipher_in, '(')) {
		ti->error = "Bad cipher specification";
		return -EINVAL;
		return -EINVAL;
	}
	}


	tmp = argv[0];
	/*
	 * Legacy dm-crypt cipher specification
	 * cipher-mode-iv:ivopts
	 */
	tmp = cipher_in;
	cipher = strsep(&tmp, "-");
	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, "-");
	chainmode = strsep(&tmp, "-");
	ivopts = strsep(&tmp, "-");
	ivopts = strsep(&tmp, "-");
	ivmode = strsep(&ivopts, ":");
	ivmode = strsep(&ivopts, ":");


	if (tmp)
	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 mappings */

	if (!chainmode || (!strcmp(chainmode, "plain") && !ivmode)) {
	/* Compatibility mode for old dm-crypt cipher strings */
		kfree(cc->cipher_mode);
	if (!chainmode || (strcmp(chainmode, "plain") == 0 && !ivmode)) {
		cc->cipher_mode = kstrdup("cbc-plain", GFP_KERNEL);
		chainmode = "cbc";
		chainmode = "cbc";
		ivmode = "plain";
		ivmode = "plain";
	}
	}


	if (strcmp(chainmode, "ecb") && !ivmode) {
	if (strcmp(chainmode, "ecb") && !ivmode) {
		ti->error = "This chaining mode requires an IV mechanism";
		ti->error = "IV mechanism required";
		goto bad;
		return -EINVAL;
	}
	}


	ret = -ENOMEM;
	cipher_api = kmalloc(CRYPTO_MAX_ALG_NAME, GFP_KERNEL);
	if (snprintf(cc->cipher, CRYPTO_MAX_ALG_NAME, "%s(%s)",
	if (!cipher_api)
		     chainmode, cipher) >= CRYPTO_MAX_ALG_NAME) {
		goto bad_mem;
		ti->error = "Chain mode + cipher name is too long";

		goto bad;
	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)) {
	if (IS_ERR(cc->tfm)) {
		ret = PTR_ERR(cc->tfm);
		ti->error = "Error allocating crypto tfm";
		ti->error = "Error allocating crypto tfm";
		goto bad;
		goto bad;
	}
	}


	strcpy(cc->cipher, cipher);
	/* Initialize and set key */
	strcpy(cc->chainmode, chainmode);
	ret = crypt_set_key(cc, key);

	ret = crypt_set_key(cc, argv[1]);
	if (ret < 0) {
	if (ret < 0) {
		ti->error = "Error decoding and setting key";
		ti->error = "Error decoding and setting key";
		goto bad;
		goto bad;
	}
	}


	/*
	/* Initialize IV */
	 * Choose ivmode. Valid modes: "plain", "essiv:<esshash>", "benbi".
	cc->iv_size = crypto_ablkcipher_ivsize(cc->tfm);
	 * See comments at iv code
	if (cc->iv_size)
	 */
		/* at least a 64 bit sector number should fit in our buffer */
	ret = -EINVAL;
		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)
	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)
@@ -1129,6 +1138,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
	else if (strcmp(ivmode, "null") == 0)
	else if (strcmp(ivmode, "null") == 0)
		cc->iv_gen_ops = &crypt_iv_null_ops;
		cc->iv_gen_ops = &crypt_iv_null_ops;
	else {
	else {
		ret = -EINVAL;
		ti->error = "Invalid IV mode";
		ti->error = "Invalid IV mode";
		goto bad;
		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);
	ret = 0;
	if (cc->iv_size)
bad:
		/* at least a 64 bit sector number should fit in our buffer */
	kfree(cipher_api);
		cc->iv_size = max(cc->iv_size,
	return ret;
				  (unsigned int)(sizeof(u64) / sizeof(u8)));

	else {
bad_mem:
		if (cc->iv_gen_ops) {
	ti->error = "Cannot allocate cipher strings";
			DMWARN("Selected cipher does not support IVs");
	return -ENOMEM;
			if (cc->iv_gen_ops->dtr)
}
				cc->iv_gen_ops->dtr(cc);

			cc->iv_gen_ops = NULL;
/*
 * 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;
	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) {
@@ -1217,17 +1252,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
	cc->start = tmpll;
	cc->start = tmpll;


	ret = -ENOMEM;
	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");
	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";
@@ -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,
static int crypt_status(struct dm_target *ti, status_type_t type,
			char *result, unsigned int maxlen)
			char *result, unsigned int maxlen)
{
{
	struct crypt_config *cc = (struct crypt_config *) ti->private;
	struct crypt_config *cc = ti->private;
	unsigned int sz = 0;
	unsigned int sz = 0;


	switch (type) {
	switch (type) {
@@ -1282,11 +1306,10 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
		break;
		break;


	case STATUSTYPE_TABLE:
	case STATUSTYPE_TABLE:
		if (cc->iv_mode)
		if (cc->cipher_mode)
			DMEMIT("%s-%s-%s ", cc->cipher, cc->chainmode,
			DMEMIT("%s-%s ", cc->cipher, cc->cipher_mode);
			       cc->iv_mode);
		else
		else
			DMEMIT("%s-%s ", cc->cipher, cc->chainmode);
			DMEMIT("%s ", cc->cipher);


		if (cc->key_size > 0) {
		if (cc->key_size > 0) {
			if ((maxlen - sz) < ((cc->key_size << 1) + 1))
			if ((maxlen - sz) < ((cc->key_size << 1) + 1))