crypto: sun8i-ce-hash - fix error handling in sun8i_ce_hash_run()
authorOvidiu Panait <ovidiu.panait.oss@gmail.com>
Tue, 1 Apr 2025 19:23:16 +0000 (22:23 +0300)
committerHerbert Xu <herbert@gondor.apana.org.au>
Tue, 8 Apr 2025 07:54:38 +0000 (15:54 +0800)
Rework error handling in sun8i_ce_hash_run() to unmap the dma buffers in
case of failure. Currently, the dma unmap functions are not called if the
function errors out at various points.

Fixes: 56f6d5aee88d1 ("crypto: sun8i-ce - support hash algorithms")
Signed-off-by: Ovidiu Panait <ovidiu.panait.oss@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c

index 6072dd9f390b40a1adfd8bf51dee81d6ccd4e3b1..3f9d79ea01aaa671cfd41214fd8d16278df96955 100644 (file)
@@ -343,9 +343,8 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq)
        u32 common;
        u64 byte_count;
        __le32 *bf;
-       void *buf = NULL;
+       void *buf, *result;
        int j, i, todo;
-       void *result = NULL;
        u64 bs;
        int digestsize;
        dma_addr_t addr_res, addr_pad;
@@ -365,14 +364,14 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq)
        buf = kcalloc(2, bs, GFP_KERNEL | GFP_DMA);
        if (!buf) {
                err = -ENOMEM;
-               goto theend;
+               goto err_out;
        }
        bf = (__le32 *)buf;
 
        result = kzalloc(digestsize, GFP_KERNEL | GFP_DMA);
        if (!result) {
                err = -ENOMEM;
-               goto theend;
+               goto err_free_buf;
        }
 
        flow = rctx->flow;
@@ -398,7 +397,7 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq)
        if (nr_sgs <= 0 || nr_sgs > MAX_SG) {
                dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs);
                err = -EINVAL;
-               goto theend;
+               goto err_free_result;
        }
 
        len = areq->nbytes;
@@ -411,7 +410,7 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq)
        if (len > 0) {
                dev_err(ce->dev, "remaining len %d\n", len);
                err = -EINVAL;
-               goto theend;
+               goto err_unmap_src;
        }
        addr_res = dma_map_single(ce->dev, result, digestsize, DMA_FROM_DEVICE);
        cet->t_dst[0].addr = desc_addr_val_le32(ce, addr_res);
@@ -419,7 +418,7 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq)
        if (dma_mapping_error(ce->dev, addr_res)) {
                dev_err(ce->dev, "DMA map dest\n");
                err = -EINVAL;
-               goto theend;
+               goto err_unmap_src;
        }
 
        byte_count = areq->nbytes;
@@ -441,7 +440,7 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq)
        }
        if (!j) {
                err = -EINVAL;
-               goto theend;
+               goto err_unmap_result;
        }
 
        addr_pad = dma_map_single(ce->dev, buf, j * 4, DMA_TO_DEVICE);
@@ -450,7 +449,7 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq)
        if (dma_mapping_error(ce->dev, addr_pad)) {
                dev_err(ce->dev, "DMA error on padding SG\n");
                err = -EINVAL;
-               goto theend;
+               goto err_unmap_result;
        }
 
        if (ce->variant->hash_t_dlen_in_bits)
@@ -463,16 +462,25 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq)
        err = sun8i_ce_run_task(ce, flow, crypto_ahash_alg_name(tfm));
 
        dma_unmap_single(ce->dev, addr_pad, j * 4, DMA_TO_DEVICE);
-       dma_unmap_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE);
+
+err_unmap_result:
        dma_unmap_single(ce->dev, addr_res, digestsize, DMA_FROM_DEVICE);
+       if (!err)
+               memcpy(areq->result, result, algt->alg.hash.base.halg.digestsize);
 
+err_unmap_src:
+       dma_unmap_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE);
 
-       memcpy(areq->result, result, algt->alg.hash.base.halg.digestsize);
-theend:
-       kfree(buf);
+err_free_result:
        kfree(result);
+
+err_free_buf:
+       kfree(buf);
+
+err_out:
        local_bh_disable();
        crypto_finalize_hash_request(engine, breq, err);
        local_bh_enable();
+
        return 0;
 }