userfaultfd:修复对巨大 PMD 的检查(CVE-2024-46787)
CVE编号
CVE-2024-46787利用情况
暂无补丁情况
N/A披露时间
2024-09-18漏洞描述
在Linux内核中,已经解决了一个漏洞,具体描述如下:关于userfaultfd的漏洞修复:解决PMDs的检查问题。修复系列为:"userfaultfd: fix races around pmd_trans_huge() check",版本号为v2。在mfill_atomic()中的pmd_trans_huge()代码存在三个不同的问题,具体取决于内核版本:1. pmd_trans_huge()的检查存在竞态条件,可能导致BUG_ON()触发(如果你碰到了正确的两个竞态窗口)。我已经在一些带有额外mdelay()调用的内核构建中测试过这个问题。关于竞态情景的描述,请参见提交信息。在旧版本的内核(6.5之前),我认为如果碰到了正确的5个狭窄的竞态窗口,理论上甚至可能导致访问transhuge页面的内容作为页表(我还没有测试过这种情况)。2. 如Qi Zheng所指出的,pmd_trans_huge()不足以检测那些不指向页表的PMDs。在旧版本的内核(6.5之前),你只需要赢得一个相当宽的竞态就能碰到这个问题。我在6.1稳定版上通过尝试迁移(带有延迟的尝试迁移)与UFFDIO_ZEROPAGE的竞争来测试这个问题,在我的x86虚拟机上,这会导致内核在ptlock_ptr()处出现错误。3. 在新版本的内核(>=6.5)中,对于shmem映射,khugepaged允许从我们这里拽出页表(尽管我还没有测试过),因此我认为mfill_atomic()中的BUG_ON()检查只是错误的。我决定为这些问题编写两个独立的修复方案(一个修复问题1+2,一个修复问题3),以便第一个修复可以回退到受问题1+2影响的内核。此补丁解决了两个问题:我发现会发生以下竞态情况: mfill_atomic 其他线程============ ============ <zap PMD> pmdp_get_lockless()[读取无PMD] <如果转换巨大则退出> <如果无:> <pagefault创建transhuge zeropage> __pte_alloc [无操作] <zap PMD> <如果pmd_trans_huge(*dst_pmd)>退出 BUG_ON(pmd_none(*dst_pmd)) 我在带有额外mdelay()调用的内核中进行了实验验证,BUG_ON(pmd_none(*dst_pmd))触发了。在新于提交0d940a9b270b(“mm/pgtable: allow pte_offset_map[_lock]() to fail”)的内核中,这不会导致比BUG_ON()更坏的结果,因为页表访问助手实际上被设计成处理页表同时消失的情况;但在旧版本的内核(<=6.4)中,我认为我们可能理论上会跳过两个BUG_ON()检查,最终将一个大页当作页表来处理。第二个问题是,如Qi Zheng所指出的,还有其他类型的大PMDs,pmd_trans_huge()无法捕获:devmap PMDs和swap PMDs(尤其是迁移PMDs)。在<=6.4的版本中,这个问题比第一个问题更严重:如果mfill_atomic()在一个包含迁移条目的PMD上运行(只需要赢得一个相当宽的竞态),它会将PMD传递给pte_offset_map_lock(),该函数假定PMD指向一个页表。接下来的行为是:首先,内核试图获取PTE锁(如果存在迁移条目中的地址位没有对应的“struct page”,这可能会导致崩溃或更糟的情况 - 我认为在X86上通常没有对应的“struct page”要感谢PTE反转缓解措施,amd64看起来有所不同)。然后,内核会尝试将PTE写入它错误地认为是一个页表的地址。为了解决这些问题,删除__pte_alloc()之前的pmd_trans_huge()检查是多余的,我们无论如何都会在之后进行检查。注意:在旧版本中,需要针对此问题进行适当的修改或适配。解决建议
建议您更新当前系统或软件至最新版,完成漏洞的修复。- 攻击路径 N/A
- 攻击复杂度 N/A
- 权限要求 N/A
- 影响范围 N/A
- 用户交互 N/A
- 可用性 N/A
- 保密性 N/A
- 完整性 N/A
CWE-ID | 漏洞类型 |
Exp相关链接

版权声明
本站原创文章转载请注明文章出处及链接,谢谢合作!
评论