crypto: ahash - Fix EINPROGRESS notification callback (CVE-2017-7618)
This commit is contained in:
parent
4d042ae0ff
commit
3f62574711
|
@ -249,6 +249,7 @@ linux (4.9.22-1) UNRELEASED; urgency=medium
|
|||
- rtmutex: Provide rt_mutex_lock_state()
|
||||
- rtmutex: Provide locked slowpath
|
||||
- rwsem/rt: Lift single reader restriction
|
||||
* crypto: ahash - Fix EINPROGRESS notification callback (CVE-2017-7618)
|
||||
|
||||
[ Salvatore Bonaccorso ]
|
||||
* ping: implement proper locking (CVE-2017-2671)
|
||||
|
|
226
debian/patches/bugfix/all/crypto-ahash-fix-einprogress-notification-callback.patch
vendored
Normal file
226
debian/patches/bugfix/all/crypto-ahash-fix-einprogress-notification-callback.patch
vendored
Normal file
|
@ -0,0 +1,226 @@
|
|||
From: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
Date: Mon, 10 Apr 2017 17:27:57 +0800
|
||||
Subject: crypto: ahash - Fix EINPROGRESS notification callback
|
||||
Origin: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6.git/commit?id=ef0579b64e93188710d48667cb5e014926af9f1b
|
||||
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2017-7618
|
||||
|
||||
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...")
|
||||
Cc: <stable@vger.kernel.org>
|
||||
Reported-by: Sabrina Dubroca <sd@queasysnail.net>
|
||||
Tested-by: Sabrina Dubroca <sd@queasysnail.net>
|
||||
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
---
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -252,6 +253,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
|
||||
@@ -266,38 +269,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(&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.
|
||||
@@ -308,7 +317,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(&areq->base, err);
|
||||
@@ -324,7 +333,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;
|
||||
}
|
||||
@@ -359,25 +373,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;
|
||||
-
|
||||
- ahash_def_finup_finish2(areq, err);
|
||||
+ ahash_restore_req(areq, err);
|
||||
|
||||
areq->base.complete(&areq->base, err);
|
||||
}
|
||||
@@ -388,11 +391,15 @@ static int ahash_def_finup_finish1(struc
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -400,7 +407,16 @@ static void ahash_def_finup_done1(struct
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -415,6 +431,11 @@ static int ahash_def_finup(struct ahash_
|
||||
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);
|
||||
}
|
||||
|
||||
--- a/include/crypto/internal/hash.h
|
||||
+++ b/include/crypto/internal/hash.h
|
||||
@@ -166,6 +166,16 @@ static inline struct ahash_instance *aha
|
||||
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)
|
||||
{
|
|
@ -126,6 +126,7 @@ bugfix/all/net-packet-fix-overflow-in-check-for-priv-area-size.patch
|
|||
bugfix/all/net-packet-fix-overflow-in-check-for-tp_frame_nr.patch
|
||||
bugfix/all/net-packet-fix-overflow-in-check-for-tp_reserve.patch
|
||||
bugfix/all/ping-implement-proper-locking.patch
|
||||
bugfix/all/crypto-ahash-fix-einprogress-notification-callback.patch
|
||||
|
||||
# Fix exported symbol versions
|
||||
bugfix/ia64/revert-ia64-move-exports-to-definitions.patch
|
||||
|
|
Loading…
Reference in New Issue