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" |