Skip to content

Commit 2673d1c

Browse files
herbertxgregkh
authored andcommitted
crypto: ahash - Fix EINPROGRESS notification callback
commit ef0579b64e93188710d48667cb5e014926af9f1b upstream. 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: ab6bf4e ("crypto: hash - Fix the pointer voodoo in...") Reported-by: Sabrina Dubroca <sd@queasysnail.net> Tested-by: Sabrina Dubroca <sd@queasysnail.net> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 70e55aa commit 2673d1c

2 files changed

Lines changed: 60 additions & 29 deletions

File tree

crypto/ahash.c

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct ahash_request_priv {
3131
crypto_completion_t complete;
3232
void *data;
3333
u8 *result;
34+
u32 flags;
3435
void *ubuf[] CRYPTO_MINALIGN_ATTR;
3536
};
3637

@@ -270,6 +271,8 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
270271
priv->result = req->result;
271272
priv->complete = req->base.complete;
272273
priv->data = req->base.data;
274+
priv->flags = req->base.flags;
275+
273276
/*
274277
* WARNING: We do not backup req->priv here! The req->priv
275278
* is for internal use of the Crypto API and the
@@ -284,38 +287,44 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
284287
return 0;
285288
}
286289

287-
static void ahash_restore_req(struct ahash_request *req)
290+
static void ahash_restore_req(struct ahash_request *req, int err)
288291
{
289292
struct ahash_request_priv *priv = req->priv;
290293

294+
if (!err)
295+
memcpy(priv->result, req->result,
296+
crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
297+
291298
/* Restore the original crypto request. */
292299
req->result = priv->result;
293-
req->base.complete = priv->complete;
294-
req->base.data = priv->data;
300+
301+
ahash_request_set_callback(req, priv->flags,
302+
priv->complete, priv->data);
295303
req->priv = NULL;
296304

297305
/* Free the req->priv.priv from the ADJUSTED request. */
298306
kzfree(priv);
299307
}
300308

301-
static void ahash_op_unaligned_finish(struct ahash_request *req, int err)
309+
static void ahash_notify_einprogress(struct ahash_request *req)
302310
{
303311
struct ahash_request_priv *priv = req->priv;
312+
struct crypto_async_request oreq;
304313

305-
if (err == -EINPROGRESS)
306-
return;
307-
308-
if (!err)
309-
memcpy(priv->result, req->result,
310-
crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
314+
oreq.data = priv->data;
311315

312-
ahash_restore_req(req);
316+
priv->complete(&oreq, -EINPROGRESS);
313317
}
314318

315319
static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
316320
{
317321
struct ahash_request *areq = req->data;
318322

323+
if (err == -EINPROGRESS) {
324+
ahash_notify_einprogress(areq);
325+
return;
326+
}
327+
319328
/*
320329
* Restore the original request, see ahash_op_unaligned() for what
321330
* goes where.
@@ -326,7 +335,7 @@ static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
326335
*/
327336

328337
/* First copy req->result into req->priv.result */
329-
ahash_op_unaligned_finish(areq, err);
338+
ahash_restore_req(areq, err);
330339

331340
/* Complete the ORIGINAL request. */
332341
areq->base.complete(&areq->base, err);
@@ -342,7 +351,12 @@ static int ahash_op_unaligned(struct ahash_request *req,
342351
return err;
343352

344353
err = op(req);
345-
ahash_op_unaligned_finish(req, err);
354+
if (err == -EINPROGRESS ||
355+
(err == -EBUSY && (ahash_request_flags(req) &
356+
CRYPTO_TFM_REQ_MAY_BACKLOG)))
357+
return err;
358+
359+
ahash_restore_req(req, err);
346360

347361
return err;
348362
}
@@ -377,25 +391,14 @@ int crypto_ahash_digest(struct ahash_request *req)
377391
}
378392
EXPORT_SYMBOL_GPL(crypto_ahash_digest);
379393

380-
static void ahash_def_finup_finish2(struct ahash_request *req, int err)
394+
static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
381395
{
382-
struct ahash_request_priv *priv = req->priv;
396+
struct ahash_request *areq = req->data;
383397

384398
if (err == -EINPROGRESS)
385399
return;
386400

387-
if (!err)
388-
memcpy(priv->result, req->result,
389-
crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
390-
391-
ahash_restore_req(req);
392-
}
393-
394-
static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
395-
{
396-
struct ahash_request *areq = req->data;
397-
398-
ahash_def_finup_finish2(areq, err);
401+
ahash_restore_req(areq, err);
399402

400403
areq->base.complete(&areq->base, err);
401404
}
@@ -406,19 +409,32 @@ static int ahash_def_finup_finish1(struct ahash_request *req, int err)
406409
goto out;
407410

408411
req->base.complete = ahash_def_finup_done2;
409-
req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
412+
410413
err = crypto_ahash_reqtfm(req)->final(req);
414+
if (err == -EINPROGRESS ||
415+
(err == -EBUSY && (ahash_request_flags(req) &
416+
CRYPTO_TFM_REQ_MAY_BACKLOG)))
417+
return err;
411418

412419
out:
413-
ahash_def_finup_finish2(req, err);
420+
ahash_restore_req(req, err);
414421
return err;
415422
}
416423

417424
static void ahash_def_finup_done1(struct crypto_async_request *req, int err)
418425
{
419426
struct ahash_request *areq = req->data;
420427

428+
if (err == -EINPROGRESS) {
429+
ahash_notify_einprogress(areq);
430+
return;
431+
}
432+
433+
areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
434+
421435
err = ahash_def_finup_finish1(areq, err);
436+
if (areq->priv)
437+
return;
422438

423439
areq->base.complete(&areq->base, err);
424440
}
@@ -433,6 +449,11 @@ static int ahash_def_finup(struct ahash_request *req)
433449
return err;
434450

435451
err = tfm->update(req);
452+
if (err == -EINPROGRESS ||
453+
(err == -EBUSY && (ahash_request_flags(req) &
454+
CRYPTO_TFM_REQ_MAY_BACKLOG)))
455+
return err;
456+
436457
return ahash_def_finup_finish1(req, err);
437458
}
438459

include/crypto/internal/hash.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,16 @@ static inline struct ahash_instance *ahash_alloc_instance(
173173
return crypto_alloc_instance2(name, alg, ahash_instance_headroom());
174174
}
175175

176+
static inline void ahash_request_complete(struct ahash_request *req, int err)
177+
{
178+
req->base.complete(&req->base, err);
179+
}
180+
181+
static inline u32 ahash_request_flags(struct ahash_request *req)
182+
{
183+
return req->base.flags;
184+
}
185+
176186
static inline struct crypto_ahash *crypto_spawn_ahash(
177187
struct crypto_ahash_spawn *spawn)
178188
{

0 commit comments

Comments
 (0)