已开启
[OLK-6.6] sched/fair:sparsemask 环绕遍历提前终止导致 try_steal() 漏扫过载 CPU #9808
qinyungao创建于  8月24日
qinyungao
8月24日 创建

环境信息

【OS版本】
NAME="openEuler"
VERSION="24.03 (LTS-SP2)"
ID="openEuler"
VERSION_ID="24.03"
PRETTY_NAME="openEuler 24.03 (LTS-SP2)"
ANSI_COLOR="0;31"

【内核版本】
6.6.0-98.0.0.103.oe2403sp2.x86_64

【硬件平台】
x86虚拟机

缺陷信息

sparsemask-repro.zip: e92ab47099164049b763a79a32ab2a31.zip
sparsemask-fix.zip: 4bdeca4523e0450888f3165a8c4fdb73.zip

sparsemask.h 中的 sparsemask_for_each() 存在环绕遍历提前终止的问题:从指定 origin 开始遍历置位元素时,可能因错误的 origin 边界判断、末元素环绕处理以及不完整 chunk 的搜索长度计算,漏掉部分置位元素。

fair.c 中 try_steal() 以目标 CPU(dst_cpu)作为 origin 遍历 cfs_overload_cpus。该问题会漏掉部分过载 CPU,导致空闲 CPU 无法从其窃取 CFS 任务,可能造成负载不均和 CPU 非预期空闲。

该问题在4.19、5.10、6.6版本内核都有同样的问题。

【问题复现步骤】

  1. 解压附件中的sparsemask-repro.tar.gz并进入复现目录:
    tar -xzf sparsemask-repro.tar.gz
    cd sparsemask-repro

  2. 执行一键测试
    chmod +x run_test.sh
    ./run_test.sh

  3. 检查输出
    sparsemask_repro: REPRODUCED: 3/3 cases failed

【实际结果】sparsemask_for_each() 遍历提前结束:
用例一:位图在 2、6、9、13 位置置位,origin=5。从位置 5 开始,应先向后遍历 6、9、13,再环绕到头部遍历 2,即 6 -> 9 -> 13 -> 2;实际只返回 6,说明遍历被提前终止。
用例二:位图在 1、15 位置置位,origin=15。应先返回 origin 位置的 15,再环绕到头部返回 1,即 15 -> 1;实际只返回 15,说明到达位图末尾后没有正确环绕。
用例三:位图共 15 位,在 0、10 位置置位,origin=1。应从位置 1 向后返回 10,再环绕到头部返回 0,即 10 -> 0;实际只返回 10,说明最后一个 chunk 不完整时漏掉了环绕后的头部元素。

下面是运行附件中sparsemask-repro.tar.gz问题复现版本sparsemask-repro/run_test.sh的输出
[32076.014268] sparsemask_repro: CASE premature-origin-stop: nelems=16 density=2 origin=5
[32076.014274] sparsemask_repro: element : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[32076.014275] sparsemask_repro: bitmap : 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0
[32076.014276] sparsemask_repro: set bits : 2 -> 6 -> 9 -> 13
[32076.014277] sparsemask_repro: expected order : 6 -> 9 -> 13 -> 2
[32076.014277] sparsemask_repro: actual order : 6
[32076.014278] sparsemask_repro: CASE premature-origin-stop: FAIL (got 1 elements, expected 4)

[32076.014279] sparsemask_repro: CASE previous-is-last-element: nelems=16 density=2 origin=15
[32076.014281] sparsemask_repro: element : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[32076.014281] sparsemask_repro: bitmap : 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
[32076.014282] sparsemask_repro: set bits : 1 -> 15
[32076.014282] sparsemask_repro: expected order : 15 -> 1
[32076.014283] sparsemask_repro: actual order : 15
[32076.014283] sparsemask_repro: CASE previous-is-last-element: FAIL (got 1 elements, expected 2)

[32076.014284] sparsemask_repro: CASE partial-final-chunk: nelems=15 density=2 origin=1
[32076.014286] sparsemask_repro: element : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
[32076.014286] sparsemask_repro: bitmap : 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0
[32076.014287] sparsemask_repro: set bits : 0 -> 10
[32076.014287] sparsemask_repro: expected order : 10 -> 0
[32076.014288] sparsemask_repro: actual order : 10
[32076.014288] sparsemask_repro: CASE partial-final-chunk: FAIL (got 1 elements, expected 2)

[32076.014289] sparsemask_repro: REPRODUCED: 3/3 cases failed

【期望结果】sparsemask_for_each() 应遍历全部置位元素,并在 mask 尾部正确环绕到头部。

用例一:位图共 16 位,在 2、6、9、13 位置置位,origin=5。从位置 5 开始向后遍历,再环绕到头部,实际顺序为 6 -> 9 -> 13 -> 2,与期望一致,用例通过。
用例二:位图共 16 位,在 1、15 位置置位,origin=15。先返回 origin 位置的 15,再从位图末尾环绕到头部返回 1,实际顺序为 15 -> 1,与期望一致,用例通过。
用例三:位图共 15 位,在 0、10 位置置位,origin=1。从位置 1 开始先返回 10,再经过不完整的最后一个 chunk 环绕到头部返回 0,实际顺序为 10 -> 0,与期望一致,用例通过。

下面是运行附件中sparsemask-fix.tar.gz修复版本的sparsemask-fix/run_test.sh的输出
[32154.284053] sparsemask_repro: CASE premature-origin-stop: nelems=16 density=2 origin=5
[32154.284060] sparsemask_repro: element : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[32154.284060] sparsemask_repro: bitmap : 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0
[32154.284061] sparsemask_repro: set bits : 2 -> 6 -> 9 -> 13
[32154.284062] sparsemask_repro: expected order : 6 -> 9 -> 13 -> 2
[32154.284063] sparsemask_repro: actual order : 6 -> 9 -> 13 -> 2
[32154.284063] sparsemask_repro: CASE premature-origin-stop: PASS

[32154.284064] sparsemask_repro: CASE previous-is-last-element: nelems=16 density=2 origin=15
[32154.284065] sparsemask_repro: element : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[32154.284066] sparsemask_repro: bitmap : 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
[32154.284067] sparsemask_repro: set bits : 1 -> 15
[32154.284067] sparsemask_repro: expected order : 15 -> 1
[32154.284068] sparsemask_repro: actual order : 15 -> 1
[32154.284068] sparsemask_repro: CASE previous-is-last-element: PASS

[32154.284068] sparsemask_repro: CASE partial-final-chunk: nelems=15 density=2 origin=1
[32154.284070] sparsemask_repro: element : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
[32154.284070] sparsemask_repro: bitmap : 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0
[32154.284071] sparsemask_repro: set bits : 0 -> 10
[32154.284071] sparsemask_repro: expected order : 10 -> 0
[32154.284072] sparsemask_repro: actual order : 10 -> 0
[32154.284072] sparsemask_repro: CASE partial-final-chunk: PASS

[32154.284073] sparsemask_repro: FIX VERIFIED: all 3 cases passed

【已分析信息】如已经做过分析和定位,请尽量附上详细的分析结果
问题定位在:
kernel/sched/sparsemask.h
sparsemask_next()
该函数负责从指定 origin 开始查找置位元素,到达位图末尾后环绕到头部,并在再次到达 origin 前结束。
分析确认存在以下三个问题:

  1. 原代码使用 next >= origin 判断遍历结束,但没有区分是否已经发生环绕。因此在 origin=5 时,返回元素 6 后可能错误结束,漏掉 9、13、2。补丁增加 wrapped 状态,仅在真正环绕后才检查 origin 边界。
  2. 当 prev 是最后一个元素时,next = prev + 1 等于 nelems,原代码直接返回,无法从元素 0 继续搜索。补丁将 next 重置为 0,并标记已经环绕。
  3. 最后一个 chunk 不完整时,原代码错误地再次扣除越界位数:
    nbits -= (next - nelems);
    越界部分此前已经按完整 word 扣除,应当补回:
    nbits += (next - nelems);
    同时需要在完成该调整后再判断搜索范围是否耗尽,避免漏掉位图头部的有效元素。
    验证结果:
    未应用补丁:3/3 cases failed
    应用补丁:3/3 cases passed
    补丁应用后,三个用例的实际遍历顺序均与期望一致:
    origin=5 :6 -> 9 -> 13 -> 2
    origin=15 :15 -> 1
    origin=1 :10 -> 0
    因此可以确认,问题由 sparsemask_next() 的环绕状态判断、末元素处理和不完整 chunk 搜索长度计算错误共同导致,sparsemask-fix/sched-fix-sparsemask_next-wrap-around-termination.patch中的补丁可以修复上述问题。

二、缺陷分析结构反馈
影响性分析说明:

缺陷严重等级:(Critical/High/Moderate/Low)

缺陷根因说明:

受影响版本排查(受影响/不受影响):
openEuler-20.03-LTS-SP4
openEuler-22.03-LTS-SP3
openEuler-22.03-LTS-SP4
openEuler-24.03-LTS
openEuler-24.03-LTS-SP1
openEuler-24.03-LTS-SP2

修复是否涉及abi变化(是/否):
openEuler-20.03-LTS-SP4
openEuler-22.03-LTS-SP3
openEuler-22.03-LTS-SP4
openEuler-24.03-LTS
openEuler-24.03-LTS-SP1
openEuler-24.03-LTS-SP2

likedislike
openeuler-ci-botopeneuler-ci-bot成员
8月24日 添加了label:sig/Kernel
openeuler-ci-botopeneuler-ci-bot成员
8月24日 issue状态由 已挂起 改变为 待办的
openeuler-ci-bot
openeuler-ci-bot成员
8月24日 评论:

Welcome To openEuler Community

Hey @qinyungao , thanks for your contribution to the community.

Bot Usage Manual

I'm the Bot here serving you. You can find the instructions on how to interact with me at Here . That means you can comment below every pull request or issue to trigger Bot Commands. You can self-configure the PR merge rules for this repository. For more details, please refer to Here.

Contact Guide

If you have any questions, please contact the SIG: Kernel ,
and any of the maintainers: @hanjunguo, @oekernel, @sanglipeng, @wkfxxx, @zeng_zhaorong ,
and any of the committers: @CTC-XiboWang, @Frank_Sae, @GoGo_phytium, @GongLei-, @LiuYongQiang0816, @SuperSix173, @Tankll2021, @TrueAI, @YiweiZ, @allen-shi, @baratta, @bibo_mao, @caixu-blue, @chen-jun-hw, @chenjiesong, @chenjunxin1992, @chenke2026, @chiqijun, @chriszjh, @duanqiangwen, @eingesch, @fangfeng123, @fanghaiqinghw, @gang_he, @gaojuxin09, @gouhao2022, @guohaocs2c, @guzitao, @hanjunguo, @hanliyang, @hellotcc, @henryze, @hewanhan, @hjx_gitff, @hongwu-wang, @htforge, @hu-chunzhi, @hunan4222, @jackknight, @jerry_lilijun, @jiayi0118, @junlong-zheng, @juntianlinux, @kailiu42, @kaitiandu, @kazero00, @kevinzhu1, @kile2009, @klmengkd, @koishimind, @kongzizaixian, @kylin-mayukun, @leoliu-oc, @li-huisong, @linan888, @linyunsheng, @liulongfang, @liyihang0226, @lostway1, @lujialin2, @mao-hongbo, @markyuan4ta21, @mawupeng, @mingqian218472, @mingrui-liu, @mufengyan, @pigalsofine, @robinorg, @rock_hw, @sanglipeng, @shu-shengming, @shuaijiakun, @sming56_admin, @stavewu, @stkid, @sun_nanyong, @wangboe2022, @wanghang73, @wenzhiwei11, @whoisxxx, @wkfxxx, @woqidaideshi, @wsoydl, @xingmz1, @xukuohai, @yeweihua999, @ygn-ndwd-official, @yonghu_4dc5, @young-sun, @yubo-liu1, @yuehaibing_planb, @yuzenghui1, @zhang-changzhong, @zhangyi089, @zhujianwei001, @zichengqu, @zouyipeng, @zqiao216 .

likedislike
openeuler-ci-bot
openeuler-ci-bot成员
8月24日 评论:

@
issue变更为 [已取消/已挂起] 状态前,请操作者填写相关原因
请按如下格式评论原因后,重新进行操作


/reason xxxxxx

likedislike
openeuler-ci-botopeneuler-ci-bot成员
8月24日 将 allen-shi 设为负责人
openeuler-ci-botopeneuler-ci-bot成员
8月24日 修改了issue 的描述
openeuler-ci-bot
openeuler-ci-bot成员
8月24日 评论:

以下的要求不是强制性的, 未按模板评论时对issue无任何影响
issue处理注意事项:
1. 当前issue受影响的分支提交pr时, 须在pr描述中填写当前issue编号进行关联, 否则无法关闭当前issue;
2. 模板内容需要填写完整, 无论是受影响或者不受影响都需要填写完整内容,未引入的分支不需要填写, 否则无法关闭当前issue;
3. 以下为模板中需要填写完整的内容, 请复制到评论区回复, 注: 内容的标题名称(影响性分析说明, 缺陷严重等级, 受影响版本排查(受影响/不受影响), 修复是否涉及abi变化(是/否))不能省略,省略后defect-manager将无法正常解析填写内容.
评论区可能使用到的指令说明:

指令 指令说明 使用权限
/check-issue 触发defect-manager校验 不限
/reason xxx /reason +挂起或取消条件 不限

影响性分析说明:

缺陷严重等级:(Critical/High/Moderate/Low)

缺陷根因说明:

受影响版本排查(受影响/不受影响):

  1. openEuler-20.03-LTS-SP4:
  2. openEuler-22.03-LTS-SP3:
  3. openEuler-22.03-LTS-SP4:
  4. openEuler-24.03-LTS:
  5. openEuler-24.03-LTS-SP1:
  6. openEuler-24.03-LTS-SP2:

abi变化(是/否):

  1. openEuler-20.03-LTS-SP4:
  2. openEuler-22.03-LTS-SP3:
  3. openEuler-22.03-LTS-SP4:
  4. openEuler-24.03-LTS:
  5. openEuler-24.03-LTS-SP1:
  6. openEuler-24.03-LTS-SP2:

缺陷issue处理具体操作请参考:
https://atomgit.com/openeuler/cve-manager/blob/master/cve-vulner-manager/doc/md/defect-manager-manual.md
pr关联issue具体操作请参考:
https://docs.atomgit.com/docs/help/home/org_project/pullrequests/pr-related-issue

likedislike
openeuler-ci-botopeneuler-ci-bot成员
8月24日 添加了label:DEFECT/UNFIXED
此处折叠了9条事件消息 查看更多
Qqinyungao
8月24日 修改标题为 “[OLK-6.6] sched/fair:sparsemask 环绕遍历提前终止导致 try_steal() 漏扫过载 CPU”,原标题为“【OLK-6.6】sched/fair:sparsemask 环绕遍历提前终止导致 try_steal() 漏扫过载 CPU”
qinyungao
8月24日 评论:

影响性分析说明: sparsemask 环绕遍历提前终止导致 try_steal() 漏扫过载 CPU

缺陷严重等级:(Critical/High/Moderate/Low)
Moderate

缺陷根因说明: sparsemask.h 中的 sparsemask_for_each() 存在环绕遍历提前终止的问题:从指定 origin 开始遍历置位元素时,可能因错误的 origin 边界判断、末元素环绕处理以及不完整 chunk 的搜索长度计算,漏掉部分置位元素

受影响版本排查(受影响/不受影响):

openEuler-20.03-LTS-SP4:受影响
openEuler-22.03-LTS-SP3:受影响
openEuler-22.03-LTS-SP4:受影响
openEuler-24.03-LTS:受影响
openEuler-24.03-LTS-SP1:受影响
openEuler-24.03-LTS-SP2:受影响
abi变化(是/否):

openEuler-20.03-LTS-SP4:否
openEuler-22.03-LTS-SP3:否
openEuler-22.03-LTS-SP4:否
openEuler-24.03-LTS:否
openEuler-24.03-LTS-SP1:否
openEuler-24.03-LTS-SP2:否

likedislike
openeuler-ci-bot
openeuler-ci-bot成员
8月24日 评论:

@allen-shi 经过defect-manager解析,已分析的内容如下表所示:

状态 需分析 内容
已分析 1.影响性分析说明 sparsemask环绕遍历提前终止导致try_steal()漏扫过载CPU
已分析 2.缺陷严重等级 Moderate
已分析 3.缺陷根因定位 sparsemask.h中的sparsemask_for_each()存在环绕遍历提前终止的问题:从指定origin开始遍历置位元素时,可能因错误的origin边界判断、末元素环绕处理以及不完整chunk的搜索长度计算,漏掉部分置位元素
已分析 4.受影响版本排查 openEuler-20.03-LTS-SP4:受影响,openEuler-22.03-LTS-SP3:受影响,openEuler-22.03-LTS-SP4:受影响,openEuler-24.03-LTS:受影响,openEuler-24.03-LTS-SP1:受影响,openEuler-24.03-LTS-SP2:受影响
已分析 5.abi变化 openEuler-20.03-LTS-SP4:否,openEuler-22.03-LTS-SP3:否,openEuler-22.03-LTS-SP4:否,openEuler-24.03-LTS:否,openEuler-24.03-LTS-SP1:否,openEuler-24.03-LTS-SP2:否

请确认分析内容的准确性,确认无误后,您可以进行后续步骤,否则您可以继续分析

likedislike
qinyungao
8月24日 评论:

官方源码历史显示,该文件分别进入了 openEuler 的三条内核线:
内核线 引入提交 对应产品版本 结论
4.19 6866be5a3aff,2021-04-14 openEuler-20.03-LTS-SP4 受影响
5.10 bf693f727c38,2021-11-11 openEuler-22.03-LTS-SP3、SP4 受影响
6.6 5d26ce2a32e3,2024-01-02 openEuler-24.03-LTS、SP1、SP2 受影响

likedislike
qinyungao
8月25日 评论:

/assign @qinyungao

likedislike
Qqinyungao
8月25日 关联了pull request:sched: Fix sparsemask_next() wrap-around termination
openeuler-ci-botopeneuler-ci-bot成员
27 天前 关闭了 issue
openeuler-ci-botopeneuler-ci-bot成员
27 天前 issue状态由 待办的 改变为 已完成
openeuler-ci-botopeneuler-ci-bot成员
27 天前 issue状态由 已完成 改变为 待办的
openeuler-ci-botopeneuler-ci-bot成员
27 天前 重新打开了 issue
openeuler-ci-bot
openeuler-ci-bot成员
27 天前 评论:

@allen-shi
关闭issue前,需要将受影响的分支在合并pr时关联上当前issue编号: #9808
受影响分支: openEuler-20.03-LTS-SP4/openEuler-22.03-LTS-SP3/openEuler-22.03-LTS-SP4/openEuler-24.03-LTS/openEuler-24.03-LTS-SP1/openEuler-24.03-LTS-SP2
具体操作参考: https://docs.atomgit.com/docs/help/home/org_project/pullrequests/pr-related-issue

likedislike
openeuler-ci-botopeneuler-ci-bot成员
21 天前 关闭了 issue
openeuler-ci-botopeneuler-ci-bot成员
21 天前 issue状态由 待办的 改变为 已完成
openeuler-ci-botopeneuler-ci-bot成员
21 天前 issue状态由 已完成 改变为 待办的
openeuler-ci-botopeneuler-ci-bot成员
21 天前 重新打开了 issue
openeuler-ci-bot
openeuler-ci-bot成员
21 天前 评论:

@allen-shi
关闭issue前,需要将受影响的分支在合并pr时关联上当前issue编号: #9808
受影响分支: openEuler-20.03-LTS-SP4/openEuler-22.03-LTS-SP3/openEuler-22.03-LTS-SP4/openEuler-24.03-LTS/openEuler-24.03-LTS-SP2
具体操作参考: https://docs.atomgit.com/docs/help/home/org_project/pullrequests/pr-related-issue

likedislike