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

Commit 12f1ffc4 authored by Gilad Ben-Yossef's avatar Gilad Ben-Yossef Committed by Herbert Xu
Browse files

dm: move dm-verity to generic async completion



dm-verity is starting async. crypto ops and waiting for them to complete.
Move it over to generic code doing the same.

This also avoids a future potential data coruption bug created
by the use of wait_for_completion_interruptible() without dealing
correctly with an interrupt aborting the wait prior to the
async op finishing, should this code ever move to a context
where signals are not masked.

Signed-off-by: default avatarGilad Ben-Yossef <gilad@benyossef.com>
CC: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent d0082e1a
Loading
Loading
Loading
Loading
+20 −61
Original line number Original line Diff line number Diff line
@@ -92,74 +92,33 @@ static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
	return block >> (level * v->hash_per_block_bits);
	return block >> (level * v->hash_per_block_bits);
}
}


/*
 * Callback function for asynchrnous crypto API completion notification
 */
static void verity_op_done(struct crypto_async_request *base, int err)
{
	struct verity_result *res = (struct verity_result *)base->data;

	if (err == -EINPROGRESS)
		return;

	res->err = err;
	complete(&res->completion);
}

/*
 * Wait for async crypto API callback
 */
static inline int verity_complete_op(struct verity_result *res, int ret)
{
	switch (ret) {
	case 0:
		break;

	case -EINPROGRESS:
	case -EBUSY:
		ret = wait_for_completion_interruptible(&res->completion);
		if (!ret)
			ret = res->err;
		reinit_completion(&res->completion);
		break;

	default:
		DMERR("verity_wait_hash: crypto op submission failed: %d", ret);
	}

	if (unlikely(ret < 0))
		DMERR("verity_wait_hash: crypto op failed: %d", ret);

	return ret;
}

static int verity_hash_update(struct dm_verity *v, struct ahash_request *req,
static int verity_hash_update(struct dm_verity *v, struct ahash_request *req,
				const u8 *data, size_t len,
				const u8 *data, size_t len,
				struct verity_result *res)
				struct crypto_wait *wait)
{
{
	struct scatterlist sg;
	struct scatterlist sg;


	sg_init_one(&sg, data, len);
	sg_init_one(&sg, data, len);
	ahash_request_set_crypt(req, &sg, NULL, len);
	ahash_request_set_crypt(req, &sg, NULL, len);


	return verity_complete_op(res, crypto_ahash_update(req));
	return crypto_wait_req(crypto_ahash_update(req), wait);
}
}


/*
/*
 * Wrapper for crypto_ahash_init, which handles verity salting.
 * Wrapper for crypto_ahash_init, which handles verity salting.
 */
 */
static int verity_hash_init(struct dm_verity *v, struct ahash_request *req,
static int verity_hash_init(struct dm_verity *v, struct ahash_request *req,
				struct verity_result *res)
				struct crypto_wait *wait)
{
{
	int r;
	int r;


	ahash_request_set_tfm(req, v->tfm);
	ahash_request_set_tfm(req, v->tfm);
	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP |
	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP |
					CRYPTO_TFM_REQ_MAY_BACKLOG,
					CRYPTO_TFM_REQ_MAY_BACKLOG,
					verity_op_done, (void *)res);
					crypto_req_done, (void *)wait);
	init_completion(&res->completion);
	crypto_init_wait(wait);


	r = verity_complete_op(res, crypto_ahash_init(req));
	r = crypto_wait_req(crypto_ahash_init(req), wait);


	if (unlikely(r < 0)) {
	if (unlikely(r < 0)) {
		DMERR("crypto_ahash_init failed: %d", r);
		DMERR("crypto_ahash_init failed: %d", r);
@@ -167,18 +126,18 @@ static int verity_hash_init(struct dm_verity *v, struct ahash_request *req,
	}
	}


	if (likely(v->salt_size && (v->version >= 1)))
	if (likely(v->salt_size && (v->version >= 1)))
		r = verity_hash_update(v, req, v->salt, v->salt_size, res);
		r = verity_hash_update(v, req, v->salt, v->salt_size, wait);


	return r;
	return r;
}
}


static int verity_hash_final(struct dm_verity *v, struct ahash_request *req,
static int verity_hash_final(struct dm_verity *v, struct ahash_request *req,
			     u8 *digest, struct verity_result *res)
			     u8 *digest, struct crypto_wait *wait)
{
{
	int r;
	int r;


	if (unlikely(v->salt_size && (!v->version))) {
	if (unlikely(v->salt_size && (!v->version))) {
		r = verity_hash_update(v, req, v->salt, v->salt_size, res);
		r = verity_hash_update(v, req, v->salt, v->salt_size, wait);


		if (r < 0) {
		if (r < 0) {
			DMERR("verity_hash_final failed updating salt: %d", r);
			DMERR("verity_hash_final failed updating salt: %d", r);
@@ -187,7 +146,7 @@ static int verity_hash_final(struct dm_verity *v, struct ahash_request *req,
	}
	}


	ahash_request_set_crypt(req, NULL, digest, 0);
	ahash_request_set_crypt(req, NULL, digest, 0);
	r = verity_complete_op(res, crypto_ahash_final(req));
	r = crypto_wait_req(crypto_ahash_final(req), wait);
out:
out:
	return r;
	return r;
}
}
@@ -196,17 +155,17 @@ int verity_hash(struct dm_verity *v, struct ahash_request *req,
		const u8 *data, size_t len, u8 *digest)
		const u8 *data, size_t len, u8 *digest)
{
{
	int r;
	int r;
	struct verity_result res;
	struct crypto_wait wait;


	r = verity_hash_init(v, req, &res);
	r = verity_hash_init(v, req, &wait);
	if (unlikely(r < 0))
	if (unlikely(r < 0))
		goto out;
		goto out;


	r = verity_hash_update(v, req, data, len, &res);
	r = verity_hash_update(v, req, data, len, &wait);
	if (unlikely(r < 0))
	if (unlikely(r < 0))
		goto out;
		goto out;


	r = verity_hash_final(v, req, digest, &res);
	r = verity_hash_final(v, req, digest, &wait);


out:
out:
	return r;
	return r;
@@ -389,7 +348,7 @@ int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
 * Calculates the digest for the given bio
 * Calculates the digest for the given bio
 */
 */
int verity_for_io_block(struct dm_verity *v, struct dm_verity_io *io,
int verity_for_io_block(struct dm_verity *v, struct dm_verity_io *io,
			struct bvec_iter *iter, struct verity_result *res)
			struct bvec_iter *iter, struct crypto_wait *wait)
{
{
	unsigned int todo = 1 << v->data_dev_block_bits;
	unsigned int todo = 1 << v->data_dev_block_bits;
	struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
	struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
@@ -414,7 +373,7 @@ int verity_for_io_block(struct dm_verity *v, struct dm_verity_io *io,
		 */
		 */
		sg_set_page(&sg, bv.bv_page, len, bv.bv_offset);
		sg_set_page(&sg, bv.bv_page, len, bv.bv_offset);
		ahash_request_set_crypt(req, &sg, NULL, len);
		ahash_request_set_crypt(req, &sg, NULL, len);
		r = verity_complete_op(res, crypto_ahash_update(req));
		r = crypto_wait_req(crypto_ahash_update(req), wait);


		if (unlikely(r < 0)) {
		if (unlikely(r < 0)) {
			DMERR("verity_for_io_block crypto op failed: %d", r);
			DMERR("verity_for_io_block crypto op failed: %d", r);
@@ -482,7 +441,7 @@ static int verity_verify_io(struct dm_verity_io *io)
	struct dm_verity *v = io->v;
	struct dm_verity *v = io->v;
	struct bvec_iter start;
	struct bvec_iter start;
	unsigned b;
	unsigned b;
	struct verity_result res;
	struct crypto_wait wait;


	for (b = 0; b < io->n_blocks; b++) {
	for (b = 0; b < io->n_blocks; b++) {
		int r;
		int r;
@@ -507,17 +466,17 @@ static int verity_verify_io(struct dm_verity_io *io)
			continue;
			continue;
		}
		}


		r = verity_hash_init(v, req, &res);
		r = verity_hash_init(v, req, &wait);
		if (unlikely(r < 0))
		if (unlikely(r < 0))
			return r;
			return r;


		start = io->iter;
		start = io->iter;
		r = verity_for_io_block(v, io, &io->iter, &res);
		r = verity_for_io_block(v, io, &io->iter, &wait);
		if (unlikely(r < 0))
		if (unlikely(r < 0))
			return r;
			return r;


		r = verity_hash_final(v, req, verity_io_real_digest(v, io),
		r = verity_hash_final(v, req, verity_io_real_digest(v, io),
					&res);
					&wait);
		if (unlikely(r < 0))
		if (unlikely(r < 0))
			return r;
			return r;


+0 −5
Original line number Original line Diff line number Diff line
@@ -90,11 +90,6 @@ struct dm_verity_io {
	 */
	 */
};
};


struct verity_result {
	struct completion completion;
	int err;
};

static inline struct ahash_request *verity_io_hash_req(struct dm_verity *v,
static inline struct ahash_request *verity_io_hash_req(struct dm_verity *v,
						     struct dm_verity_io *io)
						     struct dm_verity_io *io)
{
{