Commit 4bd24ebf authored by Chen Ridong's avatar Chen Ridong Committed by Zicheng Qu
Browse files

padata: fix UAF in padata_reorder

mainline inclusion
from mainline-v6.14-rc1
commit e01780ea4661172734118d2a5f41bc9720765668
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBPBHS
CVE: CVE-2025-21727

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e01780ea4661172734118d2a5f41bc9720765668

--------------------------------

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.

As mentioned in [1], do_serial is supposed to be called with BHs disabled
and always happen under RCU protection, to address this issue, add
synchronize_rcu() in 'padata_free_shell' wait for all _do_serial calls
to finish.

[1] https://lore.kernel.org/all/20221028160401.cccypv4euxikusiq@parnassus.localdomain/
[2] https://lore.kernel.org/linux-kernel/jfjz5d7zwbytztackem7ibzalm5lnxldi2eofeiczqmqs2m7o6@fq426cwnjtkm/


Fixes: b128a304 ("padata: allocate workqueue internally")
Signed-off-by: default avatarChen Ridong <chenridong@huawei.com>
Signed-off-by: default avatarQu Zicheng <quzicheng@huawei.com>
Acked-by: default avatarDaniel Jordan <daniel.m.jordan@oracle.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarZicheng Qu <quzicheng@huawei.com>
parent 8c45ad1b
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -1120,6 +1120,12 @@ void padata_free_shell(struct padata_shell *ps)
	if (!ps)
		return;

	/*
	 * Wait for all _do_serial calls to finish to avoid touching
	 * freed pd's and ps's.
	 */
	synchronize_rcu();

	mutex_lock(&ps->pinst->lock);
	list_del(&ps->list);
	pd = rcu_dereference_protected(ps->pd, 1);