2017-02-09 16:51:19

by Cyrille Pitchen

[permalink] [raw]
Subject: [PATCH next 0/2] crypto: atmel-sha: fix error management

Hi all,

this series is based on next-20170209.

The first patch fixes a bug reported by Dan Carpenter. I didn't put a
Fixes tag since the buggy patch is only in linux-next for now so its
commit ID is likely to change when entering Linus' tree.
It fixes a wrong 'sed' command: many "return -EINVAL;" lines should have
been replaced by "return atmel_sha_complete(dd, -EINVAL);" but instead
were replaced by direct calls of "atmel_sha_complete(dd, -EINVAL);".
My bad, sorry for that!

The second patch fixes the way error cases are handled from
atmel_sha_start(). For instance, when atmel_sha_update_req() returned an
error, atmel_sha_final_req() may have been called after anyway. This issue
was present even before my rework of the request queue management, which
introduced atmel_sha_start(), so I guess this is a long time issue.

Finally, for driver maintainance purpose, I'm preparing other patches to
fix the very same and very unlikely issue in both atmel-aes.c and
atmel-sha.c:

atmel_{aes|sha}_hw_init() may fail, for instance if clk_enable() fails.
If so, atmel_{aes|sha}_complete() is called to release the hardware and
report the error. Indeed this _complete() function should be called to
report and handle any error. However it also incondionnally calls
clk_disable(). Hence the following sequence may be buggy:

err = atmel_{aes|sha}_hw_init(dd); /* clk_enable() may have failed. */
if (err)
return atmel_{aes|sha}_hw_init(dd, err);
/* clk_disable() is called anyway. */

I didn't finalize my fixes yet for this unlikely bug. Besides the bug was
already present in v4.9 and before, so before introducing
atmel_sha_complete().

from atmel_sha_handle_queue(), the older sequence was:

err = atmel_sha_hw_init(dd);

if (err)
goto err1;

[...]

err1:
if (err != -EINPROGRESS)
/* done_task will not finish it, so do it here */
atmel_sha_finish_req(req, err);

Best regards,

Cyrille

Cyrille Pitchen (2):
crypto: atmel-sha: fix missing "return" instructions
crypto: atmel-sha: fix error management in atmel_sha_start()

drivers/crypto/atmel-sha.c | 37 +++++++++++++++++++++++++++----------
1 file changed, 27 insertions(+), 10 deletions(-)

--
2.7.4


2017-02-09 16:51:20

by Cyrille Pitchen

[permalink] [raw]
Subject: [PATCH next 1/2] crypto: atmel-sha: fix missing "return" instructions

This patch fixes a previous patch: "crypto: atmel-sha - update request
queue management to make it more generic".

Indeed the patch above should have replaced the "return -EINVAL;" lines by
"return atmel_sha_complete(dd, -EINVAL);" but instead replaced them by a
simple call of "atmel_sha_complete(dd, -EINVAL);".
Hence all "return" instructions were missing.

Reported-by: Dan Carpenter <[email protected]>
Signed-off-by: Cyrille Pitchen <[email protected]>
---
drivers/crypto/atmel-sha.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index 22d0c0c118da..d6c3d9529d36 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -668,7 +668,7 @@ static int atmel_sha_xmit_dma(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
}
if (!in_desc)
- atmel_sha_complete(dd, -EINVAL);
+ return atmel_sha_complete(dd, -EINVAL);

in_desc->callback = atmel_sha_dma_callback;
in_desc->callback_param = dd;
@@ -725,7 +725,7 @@ static int atmel_sha_xmit_dma_map(struct atmel_sha_dev *dd,
if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen +
ctx->block_size);
- atmel_sha_complete(dd, -EINVAL);
+ return atmel_sha_complete(dd, -EINVAL);
}

ctx->flags &= ~SHA_FLAGS_SG;
@@ -816,7 +816,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
dev_err(dd->dev, "dma %u bytes error\n",
ctx->buflen + ctx->block_size);
- atmel_sha_complete(dd, -EINVAL);
+ return atmel_sha_complete(dd, -EINVAL);
}

if (length == 0) {
@@ -830,7 +830,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
if (!dma_map_sg(dd->dev, ctx->sg, 1,
DMA_TO_DEVICE)) {
dev_err(dd->dev, "dma_map_sg error\n");
- atmel_sha_complete(dd, -EINVAL);
+ return atmel_sha_complete(dd, -EINVAL);
}

ctx->flags |= SHA_FLAGS_SG;
@@ -844,7 +844,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)

if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
dev_err(dd->dev, "dma_map_sg error\n");
- atmel_sha_complete(dd, -EINVAL);
+ return atmel_sha_complete(dd, -EINVAL);
}

ctx->flags |= SHA_FLAGS_SG;
--
2.7.4

2017-02-09 16:51:21

by Cyrille Pitchen

[permalink] [raw]
Subject: [PATCH next 2/2] crypto: atmel-sha: fix error management in atmel_sha_start()

This patch clarifies and fixes how errors should be handled by
atmel_sha_start().

For update operations, the previous code wrongly assumed that
(err != -EINPROGRESS) implies (err == 0). It's wrong because that doesn't
take the error cases (err < 0) into account.

This patch also adds many comments to detail all the possible returned
values and what should be done in each case.

Especially, when an error occurs, since atmel_sha_complete() has already
been called, hence releasing the hardware, atmel_sha_start() must not call
atmel_sha_finish_req() later otherwise atmel_sha_complete() would be
called a second time.

Signed-off-by: Cyrille Pitchen <[email protected]>
---
drivers/crypto/atmel-sha.c | 27 ++++++++++++++++++++++-----
1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index d6c3d9529d36..0d207dac9aa2 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -1106,22 +1106,39 @@ static int atmel_sha_start(struct atmel_sha_dev *dd)
ctx->op, req->nbytes);

err = atmel_sha_hw_init(dd);
-
if (err)
- goto err1;
+ return atmel_sha_complete(dd, err);
+
+ /*
+ * atmel_sha_update_req() and atmel_sha_final_req() can return either:
+ * -EINPROGRESS: the hardware is busy and the SHA driver will resume
+ * its job later in the done_task.
+ * This is the main path.
+ *
+ * 0: the SHA driver can continue its job then release the hardware
+ * later, if needed, with atmel_sha_finish_req().
+ * This is the alternate path.
+ *
+ * < 0: an error has occurred so atmel_sha_complete(dd, err) has already
+ * been called, hence the hardware has been released.
+ * The SHA driver must stop its job without calling
+ * atmel_sha_finish_req(), otherwise atmel_sha_complete() would be
+ * called a second time.
+ *
+ * Please note that currently, atmel_sha_final_req() never returns 0.
+ */

dd->resume = atmel_sha_done;
if (ctx->op == SHA_OP_UPDATE) {
err = atmel_sha_update_req(dd);
- if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP))
+ if (!err && (ctx->flags & SHA_FLAGS_FINUP))
/* no final() after finup() */
err = atmel_sha_final_req(dd);
} else if (ctx->op == SHA_OP_FINAL) {
err = atmel_sha_final_req(dd);
}

-err1:
- if (err != -EINPROGRESS)
+ if (!err)
/* done_task will not finish it, so do it here */
atmel_sha_finish_req(req, err);

--
2.7.4

2017-02-15 05:33:30

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH next 0/2] crypto: atmel-sha: fix error management

On Thu, Feb 09, 2017 at 05:51:19PM +0100, Cyrille Pitchen wrote:
> Hi all,
>
> this series is based on next-20170209.

All applied. Thanks.
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt