diff options
| author | Sona Sarmadi <sona.sarmadi@enea.com> | 2017-09-26 10:49:40 +0200 |
|---|---|---|
| committer | Adrian Dudau <adrian.dudau@enea.com> | 2017-09-26 15:36:31 +0200 |
| commit | 7eddd2b6da1b1ed574e90e19c96b9497e3f59c14 (patch) | |
| tree | eda06497aaa75bf89e70a578831e95a68431ddf1 | |
| parent | 79b2f0f1e6b568dd5611118d7d0610e1df610e10 (diff) | |
| download | meta-enea-bsp-arm-7eddd2b6da1b1ed574e90e19c96b9497e3f59c14.tar.gz | |
linux-cavium: CVE-2017-7618
Infinite recursion in ahash.c by triggering EBUSY on a full queue
Reference:
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7618
Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
Signed-off-by: Adrian Dudau <adrian.dudau@enea.com>
| -rw-r--r-- | recipes-kernel/linux/linux-cavium/CVE-2017-7618.patch | 238 | ||||
| -rw-r--r-- | recipes-kernel/linux/linux-cavium_4.9.inc | 1 |
2 files changed, 239 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-cavium/CVE-2017-7618.patch b/recipes-kernel/linux/linux-cavium/CVE-2017-7618.patch new file mode 100644 index 0000000..14198be --- /dev/null +++ b/recipes-kernel/linux/linux-cavium/CVE-2017-7618.patch | |||
| @@ -0,0 +1,238 @@ | |||
| 1 | From c10479591869177ae7ac0570b54ace6fbdeb57c2 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Herbert Xu <herbert@gondor.apana.org.au> | ||
| 3 | Date: Mon, 10 Apr 2017 17:27:57 +0800 | ||
| 4 | Subject: [PATCH] crypto: ahash - Fix EINPROGRESS notification callback | ||
| 5 | |||
| 6 | commit ef0579b64e93188710d48667cb5e014926af9f1b upstream. | ||
| 7 | |||
| 8 | The ahash API modifies the request's callback function in order | ||
| 9 | to clean up after itself in some corner cases (unaligned final | ||
| 10 | and missing finup). | ||
| 11 | |||
| 12 | When the request is complete ahash will restore the original | ||
| 13 | callback and everything is fine. However, when the request gets | ||
| 14 | an EBUSY on a full queue, an EINPROGRESS callback is made while | ||
| 15 | the request is still ongoing. | ||
| 16 | |||
| 17 | In this case the ahash API will incorrectly call its own callback. | ||
| 18 | |||
| 19 | This patch fixes the problem by creating a temporary request | ||
| 20 | object on the stack which is used to relay EINPROGRESS back to | ||
| 21 | the original completion function. | ||
| 22 | |||
| 23 | This patch also adds code to preserve the original flags value. | ||
| 24 | |||
| 25 | CVE: CVE-2017-7618 | ||
| 26 | Upstream-Status: Backport [backport from: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/?h=v4.9.51&id=c10479591869177ae7ac0570b54ace6fbdeb57c2] | ||
| 27 | |||
| 28 | Fixes: ab6bf4e5e5e4 ("crypto: hash - Fix the pointer voodoo in...") | ||
| 29 | Reported-by: Sabrina Dubroca <sd@queasysnail.net> | ||
| 30 | Tested-by: Sabrina Dubroca <sd@queasysnail.net> | ||
| 31 | Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> | ||
| 32 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
| 33 | Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> | ||
| 34 | --- | ||
| 35 | crypto/ahash.c | 79 ++++++++++++++++++++++++++---------------- | ||
| 36 | include/crypto/internal/hash.h | 10 ++++++ | ||
| 37 | 2 files changed, 60 insertions(+), 29 deletions(-) | ||
| 38 | |||
| 39 | diff --git a/crypto/ahash.c b/crypto/ahash.c | ||
| 40 | index 2ce8bcb..cce0268 100644 | ||
| 41 | --- a/crypto/ahash.c | ||
| 42 | +++ b/crypto/ahash.c | ||
| 43 | @@ -31,6 +31,7 @@ struct ahash_request_priv { | ||
| 44 | crypto_completion_t complete; | ||
| 45 | void *data; | ||
| 46 | u8 *result; | ||
| 47 | + u32 flags; | ||
| 48 | void *ubuf[] CRYPTO_MINALIGN_ATTR; | ||
| 49 | }; | ||
| 50 | |||
| 51 | @@ -252,6 +253,8 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt) | ||
| 52 | priv->result = req->result; | ||
| 53 | priv->complete = req->base.complete; | ||
| 54 | priv->data = req->base.data; | ||
| 55 | + priv->flags = req->base.flags; | ||
| 56 | + | ||
| 57 | /* | ||
| 58 | * WARNING: We do not backup req->priv here! The req->priv | ||
| 59 | * is for internal use of the Crypto API and the | ||
| 60 | @@ -266,38 +269,44 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt) | ||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | -static void ahash_restore_req(struct ahash_request *req) | ||
| 65 | +static void ahash_restore_req(struct ahash_request *req, int err) | ||
| 66 | { | ||
| 67 | struct ahash_request_priv *priv = req->priv; | ||
| 68 | |||
| 69 | + if (!err) | ||
| 70 | + memcpy(priv->result, req->result, | ||
| 71 | + crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); | ||
| 72 | + | ||
| 73 | /* Restore the original crypto request. */ | ||
| 74 | req->result = priv->result; | ||
| 75 | - req->base.complete = priv->complete; | ||
| 76 | - req->base.data = priv->data; | ||
| 77 | + | ||
| 78 | + ahash_request_set_callback(req, priv->flags, | ||
| 79 | + priv->complete, priv->data); | ||
| 80 | req->priv = NULL; | ||
| 81 | |||
| 82 | /* Free the req->priv.priv from the ADJUSTED request. */ | ||
| 83 | kzfree(priv); | ||
| 84 | } | ||
| 85 | |||
| 86 | -static void ahash_op_unaligned_finish(struct ahash_request *req, int err) | ||
| 87 | +static void ahash_notify_einprogress(struct ahash_request *req) | ||
| 88 | { | ||
| 89 | struct ahash_request_priv *priv = req->priv; | ||
| 90 | + struct crypto_async_request oreq; | ||
| 91 | |||
| 92 | - if (err == -EINPROGRESS) | ||
| 93 | - return; | ||
| 94 | - | ||
| 95 | - if (!err) | ||
| 96 | - memcpy(priv->result, req->result, | ||
| 97 | - crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); | ||
| 98 | + oreq.data = priv->data; | ||
| 99 | |||
| 100 | - ahash_restore_req(req); | ||
| 101 | + priv->complete(&oreq, -EINPROGRESS); | ||
| 102 | } | ||
| 103 | |||
| 104 | static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) | ||
| 105 | { | ||
| 106 | struct ahash_request *areq = req->data; | ||
| 107 | |||
| 108 | + if (err == -EINPROGRESS) { | ||
| 109 | + ahash_notify_einprogress(areq); | ||
| 110 | + return; | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | /* | ||
| 114 | * Restore the original request, see ahash_op_unaligned() for what | ||
| 115 | * goes where. | ||
| 116 | @@ -308,7 +317,7 @@ static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) | ||
| 117 | */ | ||
| 118 | |||
| 119 | /* First copy req->result into req->priv.result */ | ||
| 120 | - ahash_op_unaligned_finish(areq, err); | ||
| 121 | + ahash_restore_req(areq, err); | ||
| 122 | |||
| 123 | /* Complete the ORIGINAL request. */ | ||
| 124 | areq->base.complete(&areq->base, err); | ||
| 125 | @@ -324,7 +333,12 @@ static int ahash_op_unaligned(struct ahash_request *req, | ||
| 126 | return err; | ||
| 127 | |||
| 128 | err = op(req); | ||
| 129 | - ahash_op_unaligned_finish(req, err); | ||
| 130 | + if (err == -EINPROGRESS || | ||
| 131 | + (err == -EBUSY && (ahash_request_flags(req) & | ||
| 132 | + CRYPTO_TFM_REQ_MAY_BACKLOG))) | ||
| 133 | + return err; | ||
| 134 | + | ||
| 135 | + ahash_restore_req(req, err); | ||
| 136 | |||
| 137 | return err; | ||
| 138 | } | ||
| 139 | @@ -359,25 +373,14 @@ int crypto_ahash_digest(struct ahash_request *req) | ||
| 140 | } | ||
| 141 | EXPORT_SYMBOL_GPL(crypto_ahash_digest); | ||
| 142 | |||
| 143 | -static void ahash_def_finup_finish2(struct ahash_request *req, int err) | ||
| 144 | +static void ahash_def_finup_done2(struct crypto_async_request *req, int err) | ||
| 145 | { | ||
| 146 | - struct ahash_request_priv *priv = req->priv; | ||
| 147 | + struct ahash_request *areq = req->data; | ||
| 148 | |||
| 149 | if (err == -EINPROGRESS) | ||
| 150 | return; | ||
| 151 | |||
| 152 | - if (!err) | ||
| 153 | - memcpy(priv->result, req->result, | ||
| 154 | - crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); | ||
| 155 | - | ||
| 156 | - ahash_restore_req(req); | ||
| 157 | -} | ||
| 158 | - | ||
| 159 | -static void ahash_def_finup_done2(struct crypto_async_request *req, int err) | ||
| 160 | -{ | ||
| 161 | - struct ahash_request *areq = req->data; | ||
| 162 | - | ||
| 163 | - ahash_def_finup_finish2(areq, err); | ||
| 164 | + ahash_restore_req(areq, err); | ||
| 165 | |||
| 166 | areq->base.complete(&areq->base, err); | ||
| 167 | } | ||
| 168 | @@ -388,11 +391,15 @@ static int ahash_def_finup_finish1(struct ahash_request *req, int err) | ||
| 169 | goto out; | ||
| 170 | |||
| 171 | req->base.complete = ahash_def_finup_done2; | ||
| 172 | - req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; | ||
| 173 | + | ||
| 174 | err = crypto_ahash_reqtfm(req)->final(req); | ||
| 175 | + if (err == -EINPROGRESS || | ||
| 176 | + (err == -EBUSY && (ahash_request_flags(req) & | ||
| 177 | + CRYPTO_TFM_REQ_MAY_BACKLOG))) | ||
| 178 | + return err; | ||
| 179 | |||
| 180 | out: | ||
| 181 | - ahash_def_finup_finish2(req, err); | ||
| 182 | + ahash_restore_req(req, err); | ||
| 183 | return err; | ||
| 184 | } | ||
| 185 | |||
| 186 | @@ -400,7 +407,16 @@ static void ahash_def_finup_done1(struct crypto_async_request *req, int err) | ||
| 187 | { | ||
| 188 | struct ahash_request *areq = req->data; | ||
| 189 | |||
| 190 | + if (err == -EINPROGRESS) { | ||
| 191 | + ahash_notify_einprogress(areq); | ||
| 192 | + return; | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; | ||
| 196 | + | ||
| 197 | err = ahash_def_finup_finish1(areq, err); | ||
| 198 | + if (areq->priv) | ||
| 199 | + return; | ||
| 200 | |||
| 201 | areq->base.complete(&areq->base, err); | ||
| 202 | } | ||
| 203 | @@ -415,6 +431,11 @@ static int ahash_def_finup(struct ahash_request *req) | ||
| 204 | return err; | ||
| 205 | |||
| 206 | err = tfm->update(req); | ||
| 207 | + if (err == -EINPROGRESS || | ||
| 208 | + (err == -EBUSY && (ahash_request_flags(req) & | ||
| 209 | + CRYPTO_TFM_REQ_MAY_BACKLOG))) | ||
| 210 | + return err; | ||
| 211 | + | ||
| 212 | return ahash_def_finup_finish1(req, err); | ||
| 213 | } | ||
| 214 | |||
| 215 | diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h | ||
| 216 | index 1d4f365..f6d9af3e 100644 | ||
| 217 | --- a/include/crypto/internal/hash.h | ||
| 218 | +++ b/include/crypto/internal/hash.h | ||
| 219 | @@ -166,6 +166,16 @@ static inline struct ahash_instance *ahash_alloc_instance( | ||
| 220 | return crypto_alloc_instance2(name, alg, ahash_instance_headroom()); | ||
| 221 | } | ||
| 222 | |||
| 223 | +static inline void ahash_request_complete(struct ahash_request *req, int err) | ||
| 224 | +{ | ||
| 225 | + req->base.complete(&req->base, err); | ||
| 226 | +} | ||
| 227 | + | ||
| 228 | +static inline u32 ahash_request_flags(struct ahash_request *req) | ||
| 229 | +{ | ||
| 230 | + return req->base.flags; | ||
| 231 | +} | ||
| 232 | + | ||
| 233 | static inline struct crypto_ahash *crypto_spawn_ahash( | ||
| 234 | struct crypto_ahash_spawn *spawn) | ||
| 235 | { | ||
| 236 | -- | ||
| 237 | 1.9.1 | ||
| 238 | |||
diff --git a/recipes-kernel/linux/linux-cavium_4.9.inc b/recipes-kernel/linux/linux-cavium_4.9.inc index 8b7fe31..aea3477 100644 --- a/recipes-kernel/linux/linux-cavium_4.9.inc +++ b/recipes-kernel/linux/linux-cavium_4.9.inc | |||
| @@ -23,6 +23,7 @@ SRC_URI = "git://git@git.enea.com/linux/linux-cavium.git;protocol=ssh;name=machi | |||
| 23 | file://CVE-2017-8067.patch \ | 23 | file://CVE-2017-8067.patch \ |
| 24 | file://CVE-2017-8068.patch \ | 24 | file://CVE-2017-8068.patch \ |
| 25 | file://CVE-2017-8069.patch \ | 25 | file://CVE-2017-8069.patch \ |
| 26 | file://CVE-2017-7618.patch \ | ||
| 26 | " | 27 | " |
| 27 | 28 | ||
| 28 | LINUX_KERNEL_TYPE = "tiny" | 29 | LINUX_KERNEL_TYPE = "tiny" |
