[linux] 07/07: crypto: ahash - Fix EINPROGRESS notification callback (CVE-2017-7618)
debian-kernel at lists.debian.org
debian-kernel at lists.debian.org
Wed Apr 19 17:58:41 UTC 2017
This is an automated email from the git hooks/post-receive script.
benh pushed a commit to branch jessie
in repository linux.
commit ec43698e9c82180380fd641742fa53f03bb406a3
Author: Ben Hutchings <ben at decadent.org.uk>
Date: Wed Apr 19 18:53:53 2017 +0100
crypto: ahash - Fix EINPROGRESS notification callback (CVE-2017-7618)
---
debian/changelog | 1 +
...ash-fix-einprogress-notification-callback.patch | 226 +++++++++++++++++++++
debian/patches/series | 1 +
3 files changed, 228 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index 9fa3c8b..49b24b3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -605,6 +605,7 @@ linux (3.16.43-1) UNRELEASED; urgency=medium
* net/packet: Fix integer overflow in various range checks (CVE-2017-7308)
* mm/mempolicy.c: fix error handling in set_mempolicy and mbind
(CVE-2017-7616)
+ * crypto: ahash - Fix EINPROGRESS notification callback (CVE-2017-7618)
[ Salvatore Bonaccorso ]
* sunrpc: fix refcounting problems with auth_gss messages.
diff --git a/debian/patches/bugfix/all/crypto-ahash-fix-einprogress-notification-callback.patch b/debian/patches/bugfix/all/crypto-ahash-fix-einprogress-notification-callback.patch
new file mode 100644
index 0000000..47c2299
--- /dev/null
+++ b/debian/patches/bugfix/all/crypto-ahash-fix-einprogress-notification-callback.patch
@@ -0,0 +1,226 @@
+From: Herbert Xu <herbert at 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 at vger.kernel.org>
+Reported-by: Sabrina Dubroca <sd at queasysnail.net>
+Tested-by: Sabrina Dubroca <sd at queasysnail.net>
+Signed-off-by: Herbert Xu <herbert at 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;
+ };
+
+@@ -263,6 +264,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
+@@ -277,38 +280,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.
+@@ -319,7 +328,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);
+@@ -335,7 +344,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;
+ }
+@@ -370,25 +384,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);
+ }
+@@ -399,11 +402,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;
+ }
+
+@@ -411,7 +418,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);
+ }
+@@ -426,6 +442,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
+@@ -164,6 +164,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)
+ {
diff --git a/debian/patches/series b/debian/patches/series
index 2a23f89..f1b1326 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -684,6 +684,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/mm-mempolicy.c-fix-error-handling-in-set_mempolicy-a.patch
+bugfix/all/crypto-ahash-fix-einprogress-notification-callback.patch
# Fix ABI changes
debian/of-fix-abi-changes.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/kernel/linux.git
More information about the Kernel-svn-changes
mailing list