Skip to content

Commit 1560d1f

Browse files
Xuewen YanPeter Zijlstra
authored andcommitted
sched/eevdf: Prevent vlag from going out of bounds in reweight_eevdf()
It was possible to have pick_eevdf() return NULL, which then causes a NULL-deref. This turned out to be due to entity_eligible() returning falsely negative because of a s64 multiplcation overflow. Specifically, reweight_eevdf() computes the vlag without considering the limit placed upon vlag as update_entity_lag() does, and then the scaling multiplication (remember that weight is 20bit fixed point) can overflow. This then leads to the new vruntime being weird which then causes the above entity_eligible() to go side-ways and claim nothing is eligible. Thus limit the range of vlag accordingly. All this was quite rare, but fatal when it does happen. Closes: https://lore.kernel.org/all/[email protected]/ Closes: https://lore.kernel.org/all/CA+9S74ih+45M_2TPUY_mPPVDhNvyYfy1J1ftSix+KjiTVxg8nw@mail.gmail.com/ Closes: https://lore.kernel.org/lkml/[email protected]/ Fixes: eab03c2 ("sched/eevdf: Fix vruntime adjustment on reweight") Reported-by: Sergei Trofimovich <[email protected]> Reported-by: Igor Raits <[email protected]> Reported-by: Breno Leitao <[email protected]> Reported-by: kernel test robot <[email protected]> Reported-by: Yujie Liu <[email protected]> Signed-off-by: Xuewen Yan <[email protected]> Reviewed-and-tested-by: Chen Yu <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent afae800 commit 1560d1f

File tree

1 file changed

+12
-6
lines changed

1 file changed

+12
-6
lines changed

kernel/sched/fair.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -696,15 +696,21 @@ u64 avg_vruntime(struct cfs_rq *cfs_rq)
696696
*
697697
* XXX could add max_slice to the augmented data to track this.
698698
*/
699-
static void update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
699+
static s64 entity_lag(u64 avruntime, struct sched_entity *se)
700700
{
701-
s64 lag, limit;
701+
s64 vlag, limit;
702+
703+
vlag = avruntime - se->vruntime;
704+
limit = calc_delta_fair(max_t(u64, 2*se->slice, TICK_NSEC), se);
705+
706+
return clamp(vlag, -limit, limit);
707+
}
702708

709+
static void update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
710+
{
703711
SCHED_WARN_ON(!se->on_rq);
704-
lag = avg_vruntime(cfs_rq) - se->vruntime;
705712

706-
limit = calc_delta_fair(max_t(u64, 2*se->slice, TICK_NSEC), se);
707-
se->vlag = clamp(lag, -limit, limit);
713+
se->vlag = entity_lag(avg_vruntime(cfs_rq), se);
708714
}
709715

710716
/*
@@ -3760,7 +3766,7 @@ static void reweight_eevdf(struct sched_entity *se, u64 avruntime,
37603766
* = V - vl'
37613767
*/
37623768
if (avruntime != se->vruntime) {
3763-
vlag = (s64)(avruntime - se->vruntime);
3769+
vlag = entity_lag(avruntime, se);
37643770
vlag = div_s64(vlag * old_weight, weight);
37653771
se->vruntime = avruntime - vlag;
37663772
}

0 commit comments

Comments
 (0)