Re: [PATCH v4 3/4] blk-cgroup: skip dying blkg in blkcg_activate_policy()
Tao Cui <[email protected]> Sun, 02 Aug 2026 19:47:45 +0800
| Newsgroups | org.kernel.vger.cgroups,org.kernel.vger.linux-block,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
=E4=BA=8E 2026=E5=B9=B48=E6=9C=882=E6=97=A5 GMT+08:00 19:25:19=EF=BC=8CYu K=
uai <yukuai@kernel=2Eorg> =E5=86=99=E9=81=93=EF=BC=9A
>From: Zheng Qixing <zhengqixing@huawei=2Ecom>
>
>When switching IO schedulers on a block device, blkcg_activate_policy()
>can race with concurrent blkcg deletion, leading to a use-after-free in
>rcu_accelerate_cbs=2E
>
>T1: T2:
> blkg_destroy
> kill(&blkg->refcnt) // blkg->refcnt=3D1=
->0
> blkg_release // call_rcu(__blkg_release=
)
> =2E=2E=2E
> blkg_free_workfn
> ->pd_free_fn(pd)
>elv_iosched_store
>elevator_switch
>=2E=2E=2E
>iterate blkg list
>blkg_get(blkg) // blkg->refcnt=3D0->1
> list_del_init(&blkg->q_node)
>blkg_put(pinned_blkg) // blkg->refcnt=3D1->0
>blkg_release // call_rcu again
>rcu_accelerate_cbs // uaf
>
>Fix this by checking hlist_unhashed(&blkg->blkcg_node) before getting
>a reference to the blkg=2E This is the same check used in blkg_destroy()
>to detect if a blkg has already been destroyed=2E If the blkg is already
>unhashed, skip processing it since it's being destroyed=2E
>
>Fixes: f1c006f1c685 ("blk-cgroup: synchronize pd_free_fn() from blkg_free=
_workfn() and blkcg_deactivate_policy()")
>Signed-off-by: Zheng Qixing <zhengqixing@huawei=2Ecom>
>Reviewed-by: Tang Yizhou <yizhou=2Etang@shopee=2Ecom>
>Signed-off-by: Yu Kuai <yukuai@fygo=2Eio>
>---
> block/blk-cgroup=2Ec | 2 ++
> 1 file changed, 2 insertions(+)
>
>diff --git a/block/blk-cgroup=2Ec b/block/blk-cgroup=2Ec
>index 047bb42c282b=2E=2Ed1895bc60fcf 100644
>--- a/block/blk-cgroup=2Ec
>+++ b/block/blk-cgroup=2Ec
>@@ -1577,6 +1577,8 @@ int blkcg_activate_policy(struct gendisk *disk, con=
st struct blkcg_policy *pol)
>=20
> if (blkg->pd[pol->plid])
> continue;
>+ if (hlist_unhashed(&blkg->blkcg_node))
>+ continue;
>=20
> /* If prealloc matches, use it; otherwise try GFP_NOWAIT */
> if (blkg =3D=3D pinned_blkg) {
Reviewed-by: Tao Cui <cuitao@kylinos=2Ecn>