From: Chen Ridong <chenridong@xxxxxxxxxx> A bug was found when run ltp test: BUG: KASAN: slab-use-after-free in padata_find_next+0x29/0x1a0 Read of size 4 at addr ffff88bbfe003524 by task kworker/u113:2/3039206 CPU: 0 PID: 3039206 Comm: kworker/u113:2 Kdump: loaded Not tainted 6.6.0+ Workqueue: pdecrypt_parallel padata_parallel_worker Call Trace: <TASK> dump_stack_lvl+0x32/0x50 print_address_description.constprop.0+0x6b/0x3d0 print_report+0xdd/0x2c0 kasan_report+0xa5/0xd0 padata_find_next+0x29/0x1a0 padata_reorder+0x131/0x220 padata_parallel_worker+0x3d/0xc0 process_one_work+0x2ec/0x5a0 If 'mdelay(10)' is added before calling 'padata_find_next' in the 'padata_reorder' function, this issue could be reproduced easily with ltp test (pcrypt_aead01). This can be explained as bellow: pcrypt_aead_encrypt ... padata_do_parallel refcount_inc(&pd->refcnt); // add refcnt ... padata_do_serial padata_reorder // pd while (1) { padata_find_next(pd, true); // using pd queue_work_on ... padata_serial_worker crypto_del_alg padata_put_pd_cnt // sub refcnt padata_free_shell padata_put_pd(ps->pd); // pd is freed // loop again, but pd is freed // call padata_find_next, UAF } In the padata_reorder function, when it loops in 'while', if the alg is deleted, the refcnt may be decreased to 0 before entering 'padata_find_next', which leads to UAF, To fix this issue, add refcnt in the padata_reorder to avoid UAF. Fixes: b128a3040935 ("padata: allocate workqueue internally") Signed-off-by: Chen Ridong <chenridong@xxxxxxxxxx> Signed-off-by: Qu Zicheng <quzicheng@xxxxxxxxxx> --- kernel/padata.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/padata.c b/kernel/padata.c index 5d8e18cdcb25..627014825266 100644 --- a/kernel/padata.c +++ b/kernel/padata.c @@ -319,6 +319,7 @@ static void padata_reorder(struct parallel_data *pd) if (!spin_trylock_bh(&pd->lock)) return; + padata_get_pd(pd); while (1) { padata = padata_find_next(pd, true); @@ -355,6 +356,7 @@ static void padata_reorder(struct parallel_data *pd) reorder = per_cpu_ptr(pd->reorder_list, pd->cpu); if (!list_empty(&reorder->list) && padata_find_next(pd, false)) queue_work(pinst->serial_wq, &pd->reorder_work); + padata_put_pd(pd); } static void invoke_padata_reorder(struct work_struct *work) -- 2.34.1