Currently, crypto spawns can be freed in a softirq context (eg: from sctp socket destruction's rcu callbacks). In that context, grabbing the crypto_alg_sem is dangerous and makes CONFIG_DEBUG_ATOMIC_SLEEP scream. Defer transform destruction to a worker function so they don't use that semaphore in a softirq. Reported-by: syzbot+d769eed29cc42d75e2a3@xxxxxxxxxxxxxxxxxxxxxxxxx Closes: https://syzkaller.appspot.com/bug?extid=d769eed29cc42d75e2a3 Reported-by: syzbot+610ec0671f51e838436e@xxxxxxxxxxxxxxxxxxxxxxxxx Closes: https://syzkaller.appspot.com/bug?extid=610ec0671f51e838436e Signed-off-by: Florent Revest <revest@xxxxxxxxxxxx> --- crypto/api.c | 26 ++++++++++++++++++-------- include/linux/crypto.h | 3 +++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/crypto/api.c b/crypto/api.c index b9cc0c906efe..f877251954d5 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -640,6 +640,21 @@ void *crypto_alloc_tfm_node(const char *alg_name, } EXPORT_SYMBOL_GPL(crypto_alloc_tfm_node); +void crypto_destroy_tfm_workfn(struct work_struct *w) +{ + struct crypto_alg *alg; + struct crypto_tfm *tfm; + + tfm = container_of(w, struct crypto_tfm, free_work); + alg = tfm->__crt_alg; + + if (!tfm->exit && alg->cra_exit) + alg->cra_exit(tfm); + crypto_exit_ops(tfm); + crypto_mod_put(alg); + kfree_sensitive(tfm->to_free); +} + /* * crypto_destroy_tfm - Free crypto transform * @mem: Start of tfm slab @@ -650,20 +665,15 @@ EXPORT_SYMBOL_GPL(crypto_alloc_tfm_node); */ void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm) { - struct crypto_alg *alg; - if (IS_ERR_OR_NULL(mem)) return; if (!refcount_dec_and_test(&tfm->refcnt)) return; - alg = tfm->__crt_alg; - if (!tfm->exit && alg->cra_exit) - alg->cra_exit(tfm); - crypto_exit_ops(tfm); - crypto_mod_put(alg); - kfree_sensitive(mem); + tfm->to_free = mem; + INIT_WORK(&tfm->free_work, crypto_destroy_tfm_workfn); + queue_work(system_unbound_wq, &tfm->free_work); } EXPORT_SYMBOL_GPL(crypto_destroy_tfm); diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 31f6fee0c36c..34ff2e1dca2b 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -430,6 +430,9 @@ struct crypto_tfm { struct crypto_alg *__crt_alg; + struct work_struct free_work; + void *to_free; + void *__crt_ctx[] CRYPTO_MINALIGN_ATTR; }; -- 2.41.0.585.gd2178a4bd4-goog