[PATCH 3.18 052/124] crypto: ahash - Fix EINPROGRESS notification callback

2017-04-20 Thread Greg Kroah-Hartman
3.18-stable review patch.  If anyone has any objections, please let me know.

--

From: Herbert Xu 

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 
Tested-by: Sabrina Dubroca 
Signed-off-by: Herbert Xu 
Signed-off-by: Greg Kroah-Hartman 

---
 crypto/ahash.c |   79 +
 include/crypto/internal/hash.h |   10 +
 2 files changed, 60 insertions(+), 29 deletions(-)

--- 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_r
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_r
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(, -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(stru
 */
 
/* 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(>base, err);
@@ -341,7 +350,12 @@ static int ahash_op_unaligned(struct aha
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_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);
-}
-

[PATCH 3.18 052/124] crypto: ahash - Fix EINPROGRESS notification callback

2017-04-20 Thread Greg Kroah-Hartman
3.18-stable review patch.  If anyone has any objections, please let me know.

--

From: Herbert Xu 

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 
Tested-by: Sabrina Dubroca 
Signed-off-by: Herbert Xu 
Signed-off-by: Greg Kroah-Hartman 

---
 crypto/ahash.c |   79 +
 include/crypto/internal/hash.h |   10 +
 2 files changed, 60 insertions(+), 29 deletions(-)

--- 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_r
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_r
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(, -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(stru
 */
 
/* 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(>base, err);
@@ -341,7 +350,12 @@ static int ahash_op_unaligned(struct aha
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_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;
-
-