mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-12-11 08:54:28 -05:00
235 lines
6.7 KiB
Diff
235 lines
6.7 KiB
Diff
From c2798145e731005fa1e6ee2a489940c1dd8f03e4 Mon Sep 17 00:00:00 2001
|
|
From: Herbert Xu <herbert@gondor.apana.org.au>
|
|
Date: Mon, 10 Apr 2017 17:27:57 +0800
|
|
Subject: crypto: ahash - Fix EINPROGRESS notification callback
|
|
|
|
commit ef0579b64e93188710d48667cb5e014926af9f1b upstream.
|
|
|
|
The ahash API modifies the request's callback function in order
|
|
to clean up after itself in some corner cases (unaligned final
|
|
and missing finup).
|
|
|
|
When the request is complete ahash will restore the original
|
|
callback and everything is fine. However, when the request gets
|
|
an EBUSY on a full queue, an EINPROGRESS callback is made while
|
|
the request is still ongoing.
|
|
|
|
In this case the ahash API will incorrectly call its own callback.
|
|
|
|
This patch fixes the problem by creating a temporary request
|
|
object on the stack which is used to relay EINPROGRESS back to
|
|
the original completion function.
|
|
|
|
This patch also adds code to preserve the original flags value.
|
|
|
|
Fixes: ab6bf4e5e5e4 ("crypto: hash - Fix the pointer voodoo in...")
|
|
Reported-by: Sabrina Dubroca <sd@queasysnail.net>
|
|
Tested-by: Sabrina Dubroca <sd@queasysnail.net>
|
|
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
---
|
|
crypto/ahash.c | 79 ++++++++++++++++++++++++++----------------
|
|
include/crypto/internal/hash.h | 10 ++++++
|
|
2 files changed, 60 insertions(+), 29 deletions(-)
|
|
|
|
diff --git a/crypto/ahash.c b/crypto/ahash.c
|
|
index 46ab909..a11220e 100644
|
|
--- a/crypto/ahash.c
|
|
+++ b/crypto/ahash.c
|
|
@@ -31,6 +31,7 @@ struct ahash_request_priv {
|
|
crypto_completion_t complete;
|
|
void *data;
|
|
u8 *result;
|
|
+ u32 flags;
|
|
void *ubuf[] CRYPTO_MINALIGN_ATTR;
|
|
};
|
|
|
|
@@ -269,6 +270,8 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
|
|
priv->result = req->result;
|
|
priv->complete = req->base.complete;
|
|
priv->data = req->base.data;
|
|
+ priv->flags = req->base.flags;
|
|
+
|
|
/*
|
|
* WARNING: We do not backup req->priv here! The req->priv
|
|
* is for internal use of the Crypto API and the
|
|
@@ -283,38 +286,44 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
|
|
return 0;
|
|
}
|
|
|
|
-static void ahash_restore_req(struct ahash_request *req)
|
|
+static void ahash_restore_req(struct ahash_request *req, int err)
|
|
{
|
|
struct ahash_request_priv *priv = req->priv;
|
|
|
|
+ if (!err)
|
|
+ memcpy(priv->result, req->result,
|
|
+ crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
|
|
+
|
|
/* Restore the original crypto request. */
|
|
req->result = priv->result;
|
|
- req->base.complete = priv->complete;
|
|
- req->base.data = priv->data;
|
|
+
|
|
+ ahash_request_set_callback(req, priv->flags,
|
|
+ priv->complete, priv->data);
|
|
req->priv = NULL;
|
|
|
|
/* Free the req->priv.priv from the ADJUSTED request. */
|
|
kzfree(priv);
|
|
}
|
|
|
|
-static void ahash_op_unaligned_finish(struct ahash_request *req, int err)
|
|
+static void ahash_notify_einprogress(struct ahash_request *req)
|
|
{
|
|
struct ahash_request_priv *priv = req->priv;
|
|
+ struct crypto_async_request oreq;
|
|
|
|
- if (err == -EINPROGRESS)
|
|
- return;
|
|
-
|
|
- if (!err)
|
|
- memcpy(priv->result, req->result,
|
|
- crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
|
|
+ oreq.data = priv->data;
|
|
|
|
- ahash_restore_req(req);
|
|
+ priv->complete(&oreq, -EINPROGRESS);
|
|
}
|
|
|
|
static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
|
|
{
|
|
struct ahash_request *areq = req->data;
|
|
|
|
+ if (err == -EINPROGRESS) {
|
|
+ ahash_notify_einprogress(areq);
|
|
+ return;
|
|
+ }
|
|
+
|
|
/*
|
|
* Restore the original request, see ahash_op_unaligned() for what
|
|
* goes where.
|
|
@@ -325,7 +334,7 @@ static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
|
|
*/
|
|
|
|
/* First copy req->result into req->priv.result */
|
|
- ahash_op_unaligned_finish(areq, err);
|
|
+ ahash_restore_req(areq, err);
|
|
|
|
/* Complete the ORIGINAL request. */
|
|
areq->base.complete(&areq->base, err);
|
|
@@ -341,7 +350,12 @@ static int ahash_op_unaligned(struct ahash_request *req,
|
|
return err;
|
|
|
|
err = op(req);
|
|
- ahash_op_unaligned_finish(req, err);
|
|
+ if (err == -EINPROGRESS ||
|
|
+ (err == -EBUSY && (ahash_request_flags(req) &
|
|
+ CRYPTO_TFM_REQ_MAY_BACKLOG)))
|
|
+ return err;
|
|
+
|
|
+ ahash_restore_req(req, err);
|
|
|
|
return err;
|
|
}
|
|
@@ -376,25 +390,14 @@ int crypto_ahash_digest(struct ahash_request *req)
|
|
}
|
|
EXPORT_SYMBOL_GPL(crypto_ahash_digest);
|
|
|
|
-static void ahash_def_finup_finish2(struct ahash_request *req, int err)
|
|
+static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
|
|
{
|
|
- struct ahash_request_priv *priv = req->priv;
|
|
+ struct ahash_request *areq = req->data;
|
|
|
|
if (err == -EINPROGRESS)
|
|
return;
|
|
|
|
- if (!err)
|
|
- memcpy(priv->result, req->result,
|
|
- crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
|
|
-
|
|
- ahash_restore_req(req);
|
|
-}
|
|
-
|
|
-static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
|
|
-{
|
|
- struct ahash_request *areq = req->data;
|
|
-
|
|
- ahash_def_finup_finish2(areq, err);
|
|
+ ahash_restore_req(areq, err);
|
|
|
|
areq->base.complete(&areq->base, err);
|
|
}
|
|
@@ -405,11 +408,15 @@ static int ahash_def_finup_finish1(struct ahash_request *req, int err)
|
|
goto out;
|
|
|
|
req->base.complete = ahash_def_finup_done2;
|
|
- req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
|
|
+
|
|
err = crypto_ahash_reqtfm(req)->final(req);
|
|
+ if (err == -EINPROGRESS ||
|
|
+ (err == -EBUSY && (ahash_request_flags(req) &
|
|
+ CRYPTO_TFM_REQ_MAY_BACKLOG)))
|
|
+ return err;
|
|
|
|
out:
|
|
- ahash_def_finup_finish2(req, err);
|
|
+ ahash_restore_req(req, err);
|
|
return err;
|
|
}
|
|
|
|
@@ -417,7 +424,16 @@ static void ahash_def_finup_done1(struct crypto_async_request *req, int err)
|
|
{
|
|
struct ahash_request *areq = req->data;
|
|
|
|
+ if (err == -EINPROGRESS) {
|
|
+ ahash_notify_einprogress(areq);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
|
|
+
|
|
err = ahash_def_finup_finish1(areq, err);
|
|
+ if (areq->priv)
|
|
+ return;
|
|
|
|
areq->base.complete(&areq->base, err);
|
|
}
|
|
@@ -432,6 +448,11 @@ static int ahash_def_finup(struct ahash_request *req)
|
|
return err;
|
|
|
|
err = tfm->update(req);
|
|
+ if (err == -EINPROGRESS ||
|
|
+ (err == -EBUSY && (ahash_request_flags(req) &
|
|
+ CRYPTO_TFM_REQ_MAY_BACKLOG)))
|
|
+ return err;
|
|
+
|
|
return ahash_def_finup_finish1(req, err);
|
|
}
|
|
|
|
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
|
|
index 3b4af1d..a25414c 100644
|
|
--- a/include/crypto/internal/hash.h
|
|
+++ b/include/crypto/internal/hash.h
|
|
@@ -173,6 +173,16 @@ static inline struct ahash_instance *ahash_alloc_instance(
|
|
return crypto_alloc_instance2(name, alg, ahash_instance_headroom());
|
|
}
|
|
|
|
+static inline void ahash_request_complete(struct ahash_request *req, int err)
|
|
+{
|
|
+ req->base.complete(&req->base, err);
|
|
+}
|
|
+
|
|
+static inline u32 ahash_request_flags(struct ahash_request *req)
|
|
+{
|
|
+ return req->base.flags;
|
|
+}
|
|
+
|
|
static inline struct crypto_ahash *crypto_spawn_ahash(
|
|
struct crypto_ahash_spawn *spawn)
|
|
{
|
|
--
|
|
cgit v1.1
|
|
|