diff options
author | Andreas Wellving <andreas.wellving@enea.com> | 2018-10-17 14:27:23 +0200 |
---|---|---|
committer | Andreas Wellving <andreas.wellving@enea.com> | 2018-10-17 14:27:23 +0200 |
commit | 5004d0b1d0556e1da7a4adcafcaf3a583c83b1de (patch) | |
tree | 178753c404c25264d18333dbf00dba5fed83a737 | |
parent | 9663eadc371fa93896030458718a49672f9783d8 (diff) | |
download | enea-kernel-cache-5004d0b1d0556e1da7a4adcafcaf3a583c83b1de.tar.gz |
crypto: CVE-2017-7618
crypto: ahash - Fix EINPROGRESS notification callback
References:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.1.y&id=ce0e21e44f9766aeef6a8c18a750ef9d94c1ca8c
Change-Id: Ifdaf7c4025023947250ee94443d555ad3b0852bc
Signed-off-by: Andreas Wellving <andreas.wellving@enea.com>
-rw-r--r-- | patches/cve/4.1.x.scc | 1 | ||||
-rw-r--r-- | patches/cve/CVE-2017-7618-crypto-ahash-Fix-EINPROGRESS-notification-callback.patch | 239 |
2 files changed, 240 insertions, 0 deletions
diff --git a/patches/cve/4.1.x.scc b/patches/cve/4.1.x.scc index 96110a0..5722514 100644 --- a/patches/cve/4.1.x.scc +++ b/patches/cve/4.1.x.scc | |||
@@ -5,3 +5,4 @@ patch CVE-2016-8655-packet-fix-race-condition-in-packet_set_ring.patch | |||
5 | 5 | ||
6 | #fixed in 4.1.40 | 6 | #fixed in 4.1.40 |
7 | patch CVE-2016-10229-udp-properly-support-MSG_PEEK-with-truncated-buffers.patch | 7 | patch CVE-2016-10229-udp-properly-support-MSG_PEEK-with-truncated-buffers.patch |
8 | patch CVE-2017-7618-crypto-ahash-Fix-EINPROGRESS-notification-callback.patch | ||
diff --git a/patches/cve/CVE-2017-7618-crypto-ahash-Fix-EINPROGRESS-notification-callback.patch b/patches/cve/CVE-2017-7618-crypto-ahash-Fix-EINPROGRESS-notification-callback.patch new file mode 100644 index 0000000..f6e0982 --- /dev/null +++ b/patches/cve/CVE-2017-7618-crypto-ahash-Fix-EINPROGRESS-notification-callback.patch | |||
@@ -0,0 +1,239 @@ | |||
1 | From ce0e21e44f9766aeef6a8c18a750ef9d94c1ca8c 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 | [ Upstream commit ef0579b64e93188710d48667cb5e014926af9f1b ] | ||
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 | ||
27 | |||
28 | Fixes: ab6bf4e5e5e4 ("crypto: hash - Fix the pointer voodoo in...") | ||
29 | Cc: <stable@vger.kernel.org> | ||
30 | Reported-by: Sabrina Dubroca <sd@queasysnail.net> | ||
31 | Tested-by: Sabrina Dubroca <sd@queasysnail.net> | ||
32 | Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> | ||
33 | Signed-off-by: Sasha Levin <alexander.levin@verizon.com> | ||
34 | Signed-off-by: Andreas Wellving <andreas.wellving@enea.com> | ||
35 | --- | ||
36 | crypto/ahash.c | 79 ++++++++++++++++++++++++++---------------- | ||
37 | include/crypto/internal/hash.h | 10 ++++++ | ||
38 | 2 files changed, 60 insertions(+), 29 deletions(-) | ||
39 | |||
40 | diff --git a/crypto/ahash.c b/crypto/ahash.c | ||
41 | index dac1c24..f9caf0f 100644 | ||
42 | --- a/crypto/ahash.c | ||
43 | +++ b/crypto/ahash.c | ||
44 | @@ -31,6 +31,7 @@ struct ahash_request_priv { | ||
45 | crypto_completion_t complete; | ||
46 | void *data; | ||
47 | u8 *result; | ||
48 | + u32 flags; | ||
49 | void *ubuf[] CRYPTO_MINALIGN_ATTR; | ||
50 | }; | ||
51 | |||
52 | @@ -270,6 +271,8 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt) | ||
53 | priv->result = req->result; | ||
54 | priv->complete = req->base.complete; | ||
55 | priv->data = req->base.data; | ||
56 | + priv->flags = req->base.flags; | ||
57 | + | ||
58 | /* | ||
59 | * WARNING: We do not backup req->priv here! The req->priv | ||
60 | * is for internal use of the Crypto API and the | ||
61 | @@ -284,38 +287,44 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt) | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | -static void ahash_restore_req(struct ahash_request *req) | ||
66 | +static void ahash_restore_req(struct ahash_request *req, int err) | ||
67 | { | ||
68 | struct ahash_request_priv *priv = req->priv; | ||
69 | |||
70 | + if (!err) | ||
71 | + memcpy(priv->result, req->result, | ||
72 | + crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); | ||
73 | + | ||
74 | /* Restore the original crypto request. */ | ||
75 | req->result = priv->result; | ||
76 | - req->base.complete = priv->complete; | ||
77 | - req->base.data = priv->data; | ||
78 | + | ||
79 | + ahash_request_set_callback(req, priv->flags, | ||
80 | + priv->complete, priv->data); | ||
81 | req->priv = NULL; | ||
82 | |||
83 | /* Free the req->priv.priv from the ADJUSTED request. */ | ||
84 | kzfree(priv); | ||
85 | } | ||
86 | |||
87 | -static void ahash_op_unaligned_finish(struct ahash_request *req, int err) | ||
88 | +static void ahash_notify_einprogress(struct ahash_request *req) | ||
89 | { | ||
90 | struct ahash_request_priv *priv = req->priv; | ||
91 | + struct crypto_async_request oreq; | ||
92 | |||
93 | - if (err == -EINPROGRESS) | ||
94 | - return; | ||
95 | - | ||
96 | - if (!err) | ||
97 | - memcpy(priv->result, req->result, | ||
98 | - crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); | ||
99 | + oreq.data = priv->data; | ||
100 | |||
101 | - ahash_restore_req(req); | ||
102 | + priv->complete(&oreq, -EINPROGRESS); | ||
103 | } | ||
104 | |||
105 | static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) | ||
106 | { | ||
107 | struct ahash_request *areq = req->data; | ||
108 | |||
109 | + if (err == -EINPROGRESS) { | ||
110 | + ahash_notify_einprogress(areq); | ||
111 | + return; | ||
112 | + } | ||
113 | + | ||
114 | /* | ||
115 | * Restore the original request, see ahash_op_unaligned() for what | ||
116 | * goes where. | ||
117 | @@ -326,7 +335,7 @@ static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) | ||
118 | */ | ||
119 | |||
120 | /* First copy req->result into req->priv.result */ | ||
121 | - ahash_op_unaligned_finish(areq, err); | ||
122 | + ahash_restore_req(areq, err); | ||
123 | |||
124 | /* Complete the ORIGINAL request. */ | ||
125 | areq->base.complete(&areq->base, err); | ||
126 | @@ -342,7 +351,12 @@ static int ahash_op_unaligned(struct ahash_request *req, | ||
127 | return err; | ||
128 | |||
129 | err = op(req); | ||
130 | - ahash_op_unaligned_finish(req, err); | ||
131 | + if (err == -EINPROGRESS || | ||
132 | + (err == -EBUSY && (ahash_request_flags(req) & | ||
133 | + CRYPTO_TFM_REQ_MAY_BACKLOG))) | ||
134 | + return err; | ||
135 | + | ||
136 | + ahash_restore_req(req, err); | ||
137 | |||
138 | return err; | ||
139 | } | ||
140 | @@ -377,25 +391,14 @@ int crypto_ahash_digest(struct ahash_request *req) | ||
141 | } | ||
142 | EXPORT_SYMBOL_GPL(crypto_ahash_digest); | ||
143 | |||
144 | -static void ahash_def_finup_finish2(struct ahash_request *req, int err) | ||
145 | +static void ahash_def_finup_done2(struct crypto_async_request *req, int err) | ||
146 | { | ||
147 | - struct ahash_request_priv *priv = req->priv; | ||
148 | + struct ahash_request *areq = req->data; | ||
149 | |||
150 | if (err == -EINPROGRESS) | ||
151 | return; | ||
152 | |||
153 | - if (!err) | ||
154 | - memcpy(priv->result, req->result, | ||
155 | - crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); | ||
156 | - | ||
157 | - ahash_restore_req(req); | ||
158 | -} | ||
159 | - | ||
160 | -static void ahash_def_finup_done2(struct crypto_async_request *req, int err) | ||
161 | -{ | ||
162 | - struct ahash_request *areq = req->data; | ||
163 | - | ||
164 | - ahash_def_finup_finish2(areq, err); | ||
165 | + ahash_restore_req(areq, err); | ||
166 | |||
167 | areq->base.complete(&areq->base, err); | ||
168 | } | ||
169 | @@ -406,11 +409,15 @@ static int ahash_def_finup_finish1(struct ahash_request *req, int err) | ||
170 | goto out; | ||
171 | |||
172 | req->base.complete = ahash_def_finup_done2; | ||
173 | - req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; | ||
174 | + | ||
175 | err = crypto_ahash_reqtfm(req)->final(req); | ||
176 | + if (err == -EINPROGRESS || | ||
177 | + (err == -EBUSY && (ahash_request_flags(req) & | ||
178 | + CRYPTO_TFM_REQ_MAY_BACKLOG))) | ||
179 | + return err; | ||
180 | |||
181 | out: | ||
182 | - ahash_def_finup_finish2(req, err); | ||
183 | + ahash_restore_req(req, err); | ||
184 | return err; | ||
185 | } | ||
186 | |||
187 | @@ -418,7 +425,16 @@ static void ahash_def_finup_done1(struct crypto_async_request *req, int err) | ||
188 | { | ||
189 | struct ahash_request *areq = req->data; | ||
190 | |||
191 | + if (err == -EINPROGRESS) { | ||
192 | + ahash_notify_einprogress(areq); | ||
193 | + return; | ||
194 | + } | ||
195 | + | ||
196 | + areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; | ||
197 | + | ||
198 | err = ahash_def_finup_finish1(areq, err); | ||
199 | + if (areq->priv) | ||
200 | + return; | ||
201 | |||
202 | areq->base.complete(&areq->base, err); | ||
203 | } | ||
204 | @@ -433,6 +449,11 @@ static int ahash_def_finup(struct ahash_request *req) | ||
205 | return err; | ||
206 | |||
207 | err = tfm->update(req); | ||
208 | + if (err == -EINPROGRESS || | ||
209 | + (err == -EBUSY && (ahash_request_flags(req) & | ||
210 | + CRYPTO_TFM_REQ_MAY_BACKLOG))) | ||
211 | + return err; | ||
212 | + | ||
213 | return ahash_def_finup_finish1(req, err); | ||
214 | } | ||
215 | |||
216 | diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h | ||
217 | index 3b4af1d..a25414c 100644 | ||
218 | --- a/include/crypto/internal/hash.h | ||
219 | +++ b/include/crypto/internal/hash.h | ||
220 | @@ -173,6 +173,16 @@ static inline struct ahash_instance *ahash_alloc_instance( | ||
221 | return crypto_alloc_instance2(name, alg, ahash_instance_headroom()); | ||
222 | } | ||
223 | |||
224 | +static inline void ahash_request_complete(struct ahash_request *req, int err) | ||
225 | +{ | ||
226 | + req->base.complete(&req->base, err); | ||
227 | +} | ||
228 | + | ||
229 | +static inline u32 ahash_request_flags(struct ahash_request *req) | ||
230 | +{ | ||
231 | + return req->base.flags; | ||
232 | +} | ||
233 | + | ||
234 | static inline struct crypto_ahash *crypto_spawn_ahash( | ||
235 | struct crypto_ahash_spawn *spawn) | ||
236 | { | ||
237 | -- | ||
238 | 2.7.4 | ||
239 | |||