CVE-2022-50517CVE-2022-50517是Linux内核透明大页(THP, Transparent Huge Pages)拆分过程中存在的一个内存管理缺陷。该漏洞由提交b653db77350c("mm: Clear page->private when splitting or migrating a page")引入,该提交旨在清除PG_private标志位清除后folio->private仍为非NULL的情况。然而,该提交在实现上存在缺陷:在THP拆分过程中,对于tail page(尾部页),不当地清除了page->private字段,而该字段在swapcache中的页面上用于存储swp_entry_t(交换条目)。当THP尾部页的page->private被错误地清除后,后续的内存回收路径(如madvise(MADV_PAGEOUT)操作触发shrink_page_list -> add_to_swap -> folio_alloc_swap -> scan_swap_map_slots -> __try_to_reclaim_swap -> pagecache_get_page -> __filemap_get_folio -> xas_load -> xas_descend)在访问xarray时因页描述符损坏而陷入无限循环,导致CPU软锁死(soft lockup)。该漏洞可由本地低权限用户通过mmap操作触发,属于本地拒绝服务漏洞,对系统可用性造成高影响(可用性影响为High),但不影响机密性和完整性。
该漏洞的技术原理如下:
1. **根本原因**:Linux内核的透明大页(THP)机制中,每个THP由一个head page和多个tail pages组成。根据内核文档,THP tail pages的page->private字段被复用,用于存储"swp_entry_t if folio_test_swapcache()",即当folio处于swapcache中时,tail page的private字段保存交换条目。
2. **触发路径**:提交b653db77350c在拆分或迁移页面时无条件清除page->private字段,这破坏了上述约定。当一个处于swapcache中的THP被拆分时,其tail pages的swp_entry_t被错误地清除为0或无效值。
3. **崩溃机制**:当后续代码路径(如madvise(MADV_PAGEOUT))尝试回收该页面时,会调用__try_to_reclaim_swap -> pagecache_get_page -> __filemap_get_folio -> xas_load -> xas_descend来查找对应的swap entry。由于swp_entry_t已被损坏,xarray遍历陷入异常状态,CPU在xas_descend+0x28处无限循环,触发软锁死检测(watchdog: BUG: soft lockup - CPU#X stuck for 26s!)。
4. **修复方案**:补丁修改了__split_huge_page函数,仅当head page不在swapcache中时才清除tail page的page->private字段。如果head page在swapcache中,则保留page->private的值(因为它包含有效的swp_entry_t)。同时增加了警告机制,当检测到page->private具有意外值时打印一次警告。
5. **利用条件**:攻击者只需拥有本地低权限用户访问权限,运行stress-ng的mmmap工作负载或其他触发THP拆分和页面回收的操作即可触发该漏洞。