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

Commit 1cf55613 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-4.15/dm-fixes-2' of...

Merge tag 'for-4.15/dm-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm

Pull device mapper fixes from Mike Snitzer:
 "All fixes marked for stable:

   - Fix DM thinp btree corruption seen when inserting a new key/value
     pair into a full root node.

   - Fix DM thinp btree removal deadlock due to artificially low number
     of allowed concurrent locks allowed.

   - Fix possible DM crypt corruption if kernel keyring service is used.
     Only affects ciphers using following IVs: essiv, lmk and tcw.

   - Two DM crypt device initialization error checking fixes.

   - Fix DM integrity to allow use of async ciphers that require DMA"

* tag 'for-4.15/dm-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
  dm crypt: fix error return code in crypt_ctr()
  dm crypt: wipe kernel key copy after IV initialization
  dm integrity: don't store cipher request on the stack
  dm crypt: fix crash by adding missing check for auth key size
  dm btree: fix serious bug in btree_split_beneath()
  dm thin metadata: THIN_MAX_CONCURRENT_LOCKS should be 6
parents ec835f81 3cc2e57c
Loading
Loading
Loading
Loading
+15 −5
Original line number Diff line number Diff line
@@ -1954,10 +1954,15 @@ static int crypt_setkey(struct crypt_config *cc)
	/* Ignore extra keys (which are used for IV etc) */
	subkey_size = crypt_subkey_size(cc);

	if (crypt_integrity_hmac(cc))
	if (crypt_integrity_hmac(cc)) {
		if (subkey_size < cc->key_mac_size)
			return -EINVAL;

		crypt_copy_authenckey(cc->authenc_key, cc->key,
				      subkey_size - cc->key_mac_size,
				      cc->key_mac_size);
	}

	for (i = 0; i < cc->tfms_count; i++) {
		if (crypt_integrity_hmac(cc))
			r = crypto_aead_setkey(cc->cipher_tfm.tfms_aead[i],
@@ -2053,9 +2058,6 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string

	ret = crypt_setkey(cc);

	/* wipe the kernel key payload copy in each case */
	memset(cc->key, 0, cc->key_size * sizeof(u8));

	if (!ret) {
		set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
		kzfree(cc->key_string);
@@ -2523,6 +2525,10 @@ static int crypt_ctr_cipher(struct dm_target *ti, char *cipher_in, char *key)
		}
	}

	/* wipe the kernel key payload copy */
	if (cc->key_string)
		memset(cc->key, 0, cc->key_size * sizeof(u8));

	return ret;
}

@@ -2740,6 +2746,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
			cc->tag_pool_max_sectors * cc->on_disk_tag_size);
		if (!cc->tag_pool) {
			ti->error = "Cannot allocate integrity tags mempool";
			ret = -ENOMEM;
			goto bad;
		}

@@ -2961,6 +2968,9 @@ static int crypt_message(struct dm_target *ti, unsigned argc, char **argv)
				return ret;
			if (cc->iv_gen_ops && cc->iv_gen_ops->init)
				ret = cc->iv_gen_ops->init(cc);
			/* wipe the kernel key payload copy */
			if (cc->key_string)
				memset(cc->key, 0, cc->key_size * sizeof(u8));
			return ret;
		}
		if (argc == 2 && !strcasecmp(argv[1], "wipe")) {
@@ -3007,7 +3017,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)

static struct target_type crypt_target = {
	.name   = "crypt",
	.version = {1, 18, 0},
	.version = {1, 18, 1},
	.module = THIS_MODULE,
	.ctr    = crypt_ctr,
	.dtr    = crypt_dtr,
+37 −12
Original line number Diff line number Diff line
@@ -2559,7 +2559,8 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
	int r = 0;
	unsigned i;
	__u64 journal_pages, journal_desc_size, journal_tree_size;
	unsigned char *crypt_data = NULL;
	unsigned char *crypt_data = NULL, *crypt_iv = NULL;
	struct skcipher_request *req = NULL;

	ic->commit_ids[0] = cpu_to_le64(0x1111111111111111ULL);
	ic->commit_ids[1] = cpu_to_le64(0x2222222222222222ULL);
@@ -2617,9 +2618,20 @@ static int create_journal(struct dm_integrity_c *ic, char **error)

		if (blocksize == 1) {
			struct scatterlist *sg;
			SKCIPHER_REQUEST_ON_STACK(req, ic->journal_crypt);
			unsigned char iv[ivsize];
			skcipher_request_set_tfm(req, ic->journal_crypt);

			req = skcipher_request_alloc(ic->journal_crypt, GFP_KERNEL);
			if (!req) {
				*error = "Could not allocate crypt request";
				r = -ENOMEM;
				goto bad;
			}

			crypt_iv = kmalloc(ivsize, GFP_KERNEL);
			if (!crypt_iv) {
				*error = "Could not allocate iv";
				r = -ENOMEM;
				goto bad;
			}

			ic->journal_xor = dm_integrity_alloc_page_list(ic);
			if (!ic->journal_xor) {
@@ -2641,9 +2653,9 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
				sg_set_buf(&sg[i], va, PAGE_SIZE);
			}
			sg_set_buf(&sg[i], &ic->commit_ids, sizeof ic->commit_ids);
			memset(iv, 0x00, ivsize);
			memset(crypt_iv, 0x00, ivsize);

			skcipher_request_set_crypt(req, sg, sg, PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, iv);
			skcipher_request_set_crypt(req, sg, sg, PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, crypt_iv);
			init_completion(&comp.comp);
			comp.in_flight = (atomic_t)ATOMIC_INIT(1);
			if (do_crypt(true, req, &comp))
@@ -2659,10 +2671,22 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
			crypto_free_skcipher(ic->journal_crypt);
			ic->journal_crypt = NULL;
		} else {
			SKCIPHER_REQUEST_ON_STACK(req, ic->journal_crypt);
			unsigned char iv[ivsize];
			unsigned crypt_len = roundup(ivsize, blocksize);

			req = skcipher_request_alloc(ic->journal_crypt, GFP_KERNEL);
			if (!req) {
				*error = "Could not allocate crypt request";
				r = -ENOMEM;
				goto bad;
			}

			crypt_iv = kmalloc(ivsize, GFP_KERNEL);
			if (!crypt_iv) {
				*error = "Could not allocate iv";
				r = -ENOMEM;
				goto bad;
			}

			crypt_data = kmalloc(crypt_len, GFP_KERNEL);
			if (!crypt_data) {
				*error = "Unable to allocate crypt data";
@@ -2670,8 +2694,6 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
				goto bad;
			}

			skcipher_request_set_tfm(req, ic->journal_crypt);

			ic->journal_scatterlist = dm_integrity_alloc_journal_scatterlist(ic, ic->journal);
			if (!ic->journal_scatterlist) {
				*error = "Unable to allocate sg list";
@@ -2695,12 +2717,12 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
				struct skcipher_request *section_req;
				__u32 section_le = cpu_to_le32(i);

				memset(iv, 0x00, ivsize);
				memset(crypt_iv, 0x00, ivsize);
				memset(crypt_data, 0x00, crypt_len);
				memcpy(crypt_data, &section_le, min((size_t)crypt_len, sizeof(section_le)));

				sg_init_one(&sg, crypt_data, crypt_len);
				skcipher_request_set_crypt(req, &sg, &sg, crypt_len, iv);
				skcipher_request_set_crypt(req, &sg, &sg, crypt_len, crypt_iv);
				init_completion(&comp.comp);
				comp.in_flight = (atomic_t)ATOMIC_INIT(1);
				if (do_crypt(true, req, &comp))
@@ -2758,6 +2780,9 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
	}
bad:
	kfree(crypt_data);
	kfree(crypt_iv);
	skcipher_request_free(req);

	return r;
}

+5 −1
Original line number Diff line number Diff line
@@ -80,10 +80,14 @@
#define SECTOR_TO_BLOCK_SHIFT 3

/*
 * For btree insert:
 *  3 for btree insert +
 *  2 for btree lookup used within space map
 * For btree remove:
 *  2 for shadow spine +
 *  4 for rebalance 3 child node
 */
#define THIN_MAX_CONCURRENT_LOCKS 5
#define THIN_MAX_CONCURRENT_LOCKS 6

/* This should be plenty */
#define SPACE_MAP_ROOT_SIZE 128
+2 −17
Original line number Diff line number Diff line
@@ -683,23 +683,8 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key)
	pn->keys[1] = rn->keys[0];
	memcpy_disk(value_ptr(pn, 1), &val, sizeof(__le64));

	/*
	 * rejig the spine.  This is ugly, since it knows too
	 * much about the spine
	 */
	if (s->nodes[0] != new_parent) {
		unlock_block(s->info, s->nodes[0]);
		s->nodes[0] = new_parent;
	}
	if (key < le64_to_cpu(rn->keys[0])) {
		unlock_block(s->info, right);
		s->nodes[1] = left;
	} else {
	unlock_block(s->info, left);
		s->nodes[1] = right;
	}
	s->count = 2;

	unlock_block(s->info, right);
	return 0;
}