From: Tejun Heo tj@kernel.org
mainline inclusion from mainline-5.11-rc3 commit d16baa3f1453c14d680c5fee01cd122a22d0e0ce category: bugfix bugzilla: 47177 CVE: NA
-------------------------------------------------
When initializing iocost for a queue, its rqos should be registered before the blkcg policy is activated to allow policy data initiailization to lookup the associated ioc. This unfortunately means that the rqos methods can be called on bios before iocgs are attached to all existing blkgs.
While the race is theoretically possible on ioc_rqos_throttle(), it mostly happened in ioc_rqos_merge() due to the difference in how they lookup ioc. The former determines it from the passed in @rqos and then bails before dereferencing iocg if the looked up ioc is disabled, which most likely is the case if initialization is still in progress. The latter looked up ioc by dereferencing the possibly NULL iocg making it a lot more prone to actually triggering the bug.
* Make ioc_rqos_merge() use the same method as ioc_rqos_throttle() to look up ioc for consistency.
* Make ioc_rqos_throttle() and ioc_rqos_merge() test for NULL iocg before dereferencing it.
* Explain the danger of NULL iocgs in blk_iocost_init().
Signed-off-by: Tejun Heo tj@kernel.org Reported-by: Jonathan Lemon bsd@fb.com Cc: stable@vger.kernel.org # v5.4+ Signed-off-by: Jens Axboe axboe@kernel.dk
Conflicts: block/blk-iocost.c
Signed-off-by: Baokun Li libaokun1@huawei.com Reviewed-by: Yufen Yu yuyufen@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- block/blk-iocost.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/block/blk-iocost.c b/block/blk-iocost.c index a3b1f1c87b0ea..92180abc43e15 100644 --- a/block/blk-iocost.c +++ b/block/blk-iocost.c @@ -1716,8 +1716,8 @@ static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio,
iocg = blkg_to_iocg(blkg);
- /* bypass IOs if disabled or for root cgroup */ - if (!ioc->enabled || !iocg->level) + /* bypass IOs if disabled, still initializing, or for root cgroup */ + if (!ioc->enabled || !iocg || !iocg->level) return;
/* always activate so that even 0 cost IOs get protected to some level */ @@ -1857,8 +1857,8 @@ static void ioc_rqos_merge(struct rq_qos *rqos, struct request *rq, rcu_read_unlock();
iocg = blkg_to_iocg(blkg); - /* bypass if disabled or for root cgroup */ - if (!ioc->enabled || !iocg->level) + /* bypass if disabled, still initializing, or for root cgroup */ + if (!ioc->enabled || !iocg || !iocg->level) return;
abs_cost = calc_vtime_cost(bio, iocg, true); @@ -1997,6 +1997,12 @@ static int blk_iocost_init(struct request_queue *q) ioc_refresh_params(ioc, true); spin_unlock_irq(&ioc->lock);
+ /* + * rqos must be added before activation to allow iocg_pd_init() to + * lookup the ioc from q. This means that the rqos methods may get + * called before policy activation completion, can't assume that the + * target bio has an iocg associated and need to test for NULL iocg. + */ rq_qos_add(q, rqos); ret = blkcg_activate_policy(q, &blkcg_policy_iocost); if (ret) {