Commit 5d1cdfde authored by Ira Weiny's avatar Ira Weiny Committed by Herbert Xu
Browse files

crypto: ux500 - Fix kmap() bug



Once the crypto hash walk is started by crypto_hash_walk_first()
returning non-zero, crypto_hash_walk_done() must be called to unmap any
memory which was mapped by *_walk_first().

Ensure crypto_hash_walk_done() is called properly by:

	1) Re-arranging the check for device data to be prior to calling
	   *_walk_first()
	2) on error call crypto_hash_walk_done() with an error code to
	   allow the hash walk code to clean up.

While we are at it clean up the 'out' label to be more meaningful.

Signed-off-by: default avatarIra Weiny <ira.weiny@intel.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 3a61cdf4
Loading
Loading
Loading
Loading
+18 −12
Original line number Diff line number Diff line
@@ -1072,27 +1072,32 @@ int hash_hw_update(struct ahash_request *req)
	struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
	struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
	struct crypto_hash_walk walk;
	int msg_length = crypto_hash_walk_first(req, &walk);

	/* Empty message ("") is correct indata */
	if (msg_length == 0)
		return ret;
	int msg_length;

	index = req_ctx->state.index;
	buffer = (u8 *)req_ctx->state.buffer;

	ret = hash_get_device_data(ctx, &device_data);
	if (ret)
		return ret;

	msg_length = crypto_hash_walk_first(req, &walk);

	/* Empty message ("") is correct indata */
	if (msg_length == 0) {
		ret = 0;
		goto release_dev;
	}

	/* Check if ctx->state.length + msg_length
	   overflows */
	if (msg_length > (req_ctx->state.length.low_word + msg_length) &&
	    HASH_HIGH_WORD_MAX_VAL == req_ctx->state.length.high_word) {
		pr_err("%s: HASH_MSG_LENGTH_OVERFLOW!\n", __func__);
		return -EPERM;
		ret = crypto_hash_walk_done(&walk, -EPERM);
		goto release_dev;
	}

	ret = hash_get_device_data(ctx, &device_data);
	if (ret)
		return ret;

	/* Main loop */
	while (0 != msg_length) {
		data_buffer = walk.data;
@@ -1102,7 +1107,8 @@ int hash_hw_update(struct ahash_request *req)
		if (ret) {
			dev_err(device_data->dev, "%s: hash_internal_hw_update() failed!\n",
				__func__);
			goto out;
			crypto_hash_walk_done(&walk, ret);
			goto release_dev;
		}

		msg_length = crypto_hash_walk_done(&walk, 0);
@@ -1112,7 +1118,7 @@ int hash_hw_update(struct ahash_request *req)
	dev_dbg(device_data->dev, "%s: indata length=%d, bin=%d\n",
		__func__, req_ctx->state.index, req_ctx->state.bit_index);

out:
release_dev:
	release_hash_device(device_data);

	return ret;