diff options
author | Marek Vasut <marex@denx.de> | 2014-03-13 21:37:04 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2014-03-21 09:54:20 -0400 |
commit | ab6bf4e5e5e4298e8649e635bee25542cccbfd97 (patch) | |
tree | b28d2747b827c6ca66ab3445e737a5eaf3bb6209 /crypto/ahash.c | |
parent | 85e0da925b2ddbf39a6cefb4e02ad51d0a0912c0 (diff) |
crypto: hash - Fix the pointer voodoo in unaligned ahash
Add documentation for the pointer voodoo that is happening in crypto/ahash.c
in ahash_op_unaligned(). This code is quite confusing, so add a beefy chunk
of documentation.
Moreover, make sure the mangled request is completely restored after finishing
this unaligned operation. This means restoring all of .result, .base.data
and .base.complete .
Also, remove the crypto_completion_t complete = ... line present in the
ahash_op_unaligned_done() function. This type actually declares a function
pointer, which is very confusing.
Finally, yet very important nonetheless, make sure the req->priv is free()'d
only after the original request is restored in ahash_op_unaligned_done().
The req->priv data must not be free()'d before that in ahash_op_unaligned_finish(),
since we would be accessing previously free()'d data in ahash_op_unaligned_done()
and cause corruption.
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: David S. Miller <davem@davemloft.net>
Cc: Fabio Estevam <fabio.estevam@freescale.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/ahash.c')
-rw-r--r-- | crypto/ahash.c | 56 |
1 files changed, 49 insertions, 7 deletions
diff --git a/crypto/ahash.c b/crypto/ahash.c index a92dc382f781..4fdb4d3fddec 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c | |||
@@ -201,22 +201,34 @@ static void ahash_op_unaligned_finish(struct ahash_request *req, int err) | |||
201 | memcpy(priv->result, req->result, | 201 | memcpy(priv->result, req->result, |
202 | crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); | 202 | crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); |
203 | 203 | ||
204 | /* Restore the original crypto request. */ | ||
205 | req->result = priv->result; | ||
206 | req->base.complete = priv->complete; | ||
207 | req->base.data = priv->data; | ||
208 | req->priv = NULL; | ||
209 | |||
210 | /* Free the req->priv.priv from the ADJUSTED request. */ | ||
204 | kzfree(priv); | 211 | kzfree(priv); |
205 | } | 212 | } |
206 | 213 | ||
207 | static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) | 214 | static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) |
208 | { | 215 | { |
209 | struct ahash_request *areq = req->data; | 216 | struct ahash_request *areq = req->data; |
210 | struct ahash_request_priv *priv = areq->priv; | ||
211 | crypto_completion_t complete = priv->complete; | ||
212 | void *data = priv->data; | ||
213 | 217 | ||
214 | ahash_op_unaligned_finish(areq, err); | 218 | /* |
219 | * Restore the original request, see ahash_op_unaligned() for what | ||
220 | * goes where. | ||
221 | * | ||
222 | * The "struct ahash_request *req" here is in fact the "req.base" | ||
223 | * from the ADJUSTED request from ahash_op_unaligned(), thus as it | ||
224 | * is a pointer to self, it is also the ADJUSTED "req" . | ||
225 | */ | ||
215 | 226 | ||
216 | areq->base.complete = complete; | 227 | /* First copy areq->result into areq->priv.result */ |
217 | areq->base.data = data; | 228 | ahash_op_unaligned_finish(areq, err); |
218 | 229 | ||
219 | complete(&areq->base, err); | 230 | /* Complete the ORIGINAL request. */ |
231 | areq->base.complete(&areq->base, err); | ||
220 | } | 232 | } |
221 | 233 | ||
222 | static int ahash_op_unaligned(struct ahash_request *req, | 234 | static int ahash_op_unaligned(struct ahash_request *req, |
@@ -234,9 +246,39 @@ static int ahash_op_unaligned(struct ahash_request *req, | |||
234 | if (!priv) | 246 | if (!priv) |
235 | return -ENOMEM; | 247 | return -ENOMEM; |
236 | 248 | ||
249 | /* | ||
250 | * WARNING: Voodoo programming below! | ||
251 | * | ||
252 | * The code below is obscure and hard to understand, thus explanation | ||
253 | * is necessary. See include/crypto/hash.h and include/linux/crypto.h | ||
254 | * to understand the layout of structures used here! | ||
255 | * | ||
256 | * The code here will replace portions of the ORIGINAL request with | ||
257 | * pointers to new code and buffers so the hashing operation can store | ||
258 | * the result in aligned buffer. We will call the modified request | ||
259 | * an ADJUSTED request. | ||
260 | * | ||
261 | * The newly mangled request will look as such: | ||
262 | * | ||
263 | * req { | ||
264 | * .result = ADJUSTED[new aligned buffer] | ||
265 | * .base.complete = ADJUSTED[pointer to completion function] | ||
266 | * .base.data = ADJUSTED[*req (pointer to self)] | ||
267 | * .priv = ADJUSTED[new priv] { | ||
268 | * .result = ORIGINAL(result) | ||
269 | * .complete = ORIGINAL(base.complete) | ||
270 | * .data = ORIGINAL(base.data) | ||
271 | * } | ||
272 | */ | ||
273 | |||
237 | priv->result = req->result; | 274 | priv->result = req->result; |
238 | priv->complete = req->base.complete; | 275 | priv->complete = req->base.complete; |
239 | priv->data = req->base.data; | 276 | priv->data = req->base.data; |
277 | /* | ||
278 | * WARNING: We do not backup req->priv here! The req->priv | ||
279 | * is for internal use of the Crypto API and the | ||
280 | * user must _NOT_ _EVER_ depend on it's content! | ||
281 | */ | ||
240 | 282 | ||
241 | req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1); | 283 | req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1); |
242 | req->base.complete = ahash_op_unaligned_done; | 284 | req->base.complete = ahash_op_unaligned_done; |