一个针对 CVE-2026-31694 的被动式 Linux 主机评估工具,该漏洞是 Linux 内核中 FUSE readdir 缓存的越界写入。
该扫描器评估运行中的内核、FUSE 暴露面、本地软件包元数据、内核源码证据、执行环境以及操作系统家族。当主机可能受影响时,它会生成针对所检测发行版量身定制的缓解指南。
作者: Aung Myat Thu [w01f]
cve_2026_31694_scanner.py 是一个本地、非利用型的漏洞评估工具。
它不会通过触发受影响的 FUSE 代码路径来确认漏洞,而是综合多种被动指标:
CONFIG_FUSE_FS 内核配置;/dev/fuse 是否存在及当前用户访问权限;结果是暴露面评估,而非基于利用的证明。
CVE-2026-31694 影响 Linux 内核的 FUSE readdir 缓存。
存在漏洞的逻辑根据服务器控制的名称长度计算目录项的序列化大小,并将该记录复制到单个页缓存页中。名称为 4095 的目录项可以产生 4120 字节的序列化大小。
在使用 4096 字节页的系统中,该记录会超出单页 24 字节。
上游修复会在缓存复制发生之前拒绝无法容纳在单页内的目录记录。
fs/fuse/readdir.c fuse_add_dirent_to_cache()
### 扫描器基线数据
扫描器包含以下上游稳定修复基线:
| 内核系列 | 修复基线 |
|---|---:|
| 5.10 | 5.10.258 |
| 5.15 | 5.15.209 |
| 6.1 | 6.1.175 |
| 6.6 | 6.6.136 |
| 6.12 | 6.12.84 |
| 6.18 | 6.18.25 |
| 7.0 | 7.0.2 |
| 主线 | 7.1 或更高版本 |
这些版本被用作评估输入之一。它们并非唯一的判断依据,因为发行版厂商可能会在保留较旧上游版本号的同时向后移植修复补丁。
---
## 安全模型
该扫描器旨在避免触发易受攻击的操作。
### 扫描器不会
- 挂载 FUSE 文件系统;
- 打开或与 `/dev/fuse` 通信;
- 启动 FUSE 服务器;
- 提交特制的目录记录;
- 为页放置测试分配内存;
- 整理内核分配器;
- 修改 `/etc/passwd`;
- 更改内核配置;
- 加载或卸载内核模块;
- 修改 `/dev/fuse` 权限;
- 安装或移除软件包;
- 重启系统;
- 尝试提权。
### 扫描器可能
- 读取 `/proc`、`/boot`、`/lib/modules`、`/usr/lib/modules`、`/usr/src` 以及软件包元数据目录下的文件;
- 执行有界、只读的软件包查询;
- 检查活动挂载和文件系统注册信息;
- 仅在显式提供 `--output` 时写入报告;
- 打印缓解命令供管理员审阅。
缓解命令是文档性输出,绝不会自动执行。
---
## 功能
### 主机与内核识别
- 读取 `platform.release()` 并解析上游风格的内核版本。
- 读取 `/etc/os-release` 或 `/usr/lib/os-release`。
- 检测 CPU 架构和内存页大小。
- 识别被扫描的内核是否属于当前操作系统。
### FUSE 暴露评估
- 从可用的内核配置源读取 `CONFIG_FUSE_FS`。
- 检测内置 FUSE 支持和可加载模块配置。
- 读取 `/proc/filesystems`。
- 检查 `/dev/fuse` 元数据和当前用户的读/写访问权限。
- 定位 `fusermount3` 或 `fusermount`。
- 从 `/proc/self/mountinfo` 解析活动的 FUSE 挂载。
### 补丁证据
- 将正在运行的版本与上游修复基线进行比较。
- 在已安装的内核源码中搜索超长记录防护代码。
- 检查本地 RPM 或 Debian 软件包变更日志中是否包含:
- `CVE-2026-31694`;
- 上游补丁标题。
### 软件包与重启状态
- 尝试识别拥有当前运行内核的软件包。
- 在不刷新软件源的情况下查询本地软件包管理器元数据。
- 当主机环境具有权威性时,检测是否有更新的已安装内核。
- 在适用时检查 `/var/run/reboot-required`。
### 环境感知
- 检测与 Docker 兼容的容器。
- 检测与 Podman 兼容的容器。
- 检测与容器相关的 cgroups。
- 检测 WSL。
- 在可用时使用 `systemd-detect-virt` 检测虚拟机。
### 报告
- 人类可读的文本输出。
- 机器可读的 JSON 输出。
- Markdown 报告输出。
- 仅缓解命令输出。
- 可选的文件输出。
- 有意义的进程退出码。
---
## 要求
### 必需项
- 需 Linux 进行内核评估。
- Python 3.9 或更高版本。
- 对常规系统元数据的读取权限。
该扫描器仅使用 Python 标准库。
### 可选命令
当存在以下工具时,会收集额外的证据:
| 工具 | 用途 |
|---|---|
| `dpkg-query` | Debian/Ubuntu 内核软件包所有权和变更日志发现 |
| `rpm` | Fedora/RHEL/SUSE 软件包所有权和变更日志检查 |
| `pacman` | Arch 系列内核软件包和更新元数据 |
| `apt` | Debian 系列缓存更新查询 |
| `dnf` 或 `dnf5` | Fedora/RHEL 缓存更新查询 |
| `zypper` | SUSE 缓存 CVE 补丁查询 |
| `apk` | Alpine 软件包/更新查询 |
| `systemd-detect-virt` | 容器和虚拟机检测 |
正常扫描不需要 root 权限。
由于系统特定的文件权限,某些证据可能对非特权账户不可用。
---
## 安装
将扫描器放到一个工作目录中:```bash
chmod +x cve_2026_31694_scanner.py
直接运行:```bash ./cve_2026_31694_scanner.py
或者使用 Python 调用它:```bash
python3 cve_2026_31694_scanner.py
无需安装 Python 包。
python3 cve_2026_31694_scanner.py
### JSON 输出```bash
python3 cve_2026_31694_scanner.py --format json
下面的兼容别名会产生相同的格式:```bash python3 cve_2026_31694_scanner.py --json
### Markdown 报告```bash
python3 cve_2026_31694_scanner.py --format markdown
python3 cve_2026_31694_scanner.py
--format markdown
--output cve-2026-31694-report.md
### 仅打印修复指导```bash
python3 cve_2026_31694_scanner.py --mitigation-only
python3 cve_2026_31694_scanner.py --no-package-query
### 报告后始终返回成功```bash
python3 cve_2026_31694_scanner.py --no-exit-status
此选项在收集报告但不想让漏洞状态导致编排任务失败时非常有用。
| 选项 | 说明 |
|---|---|
--format text | 人类可读的终端输出。这是默认选项。 |
--format json | 以 JSON 格式输出的完整结构化报告。 |
--format markdown | 技术性 Markdown 报告。 |
--json | --format json 的别名。 |
--output PATH | 将报告写入文件而不是标准输出。 |
--mitigation-only | 仅返回生成的缓解措施部分。 |
--no-package-query | 跳过本地包管理器更新查询。 |
--no-exit-status | 生成输出后始终以状态 0 退出。 |
-h, --help | 显示命令帮助。 |
扫描器按以下顺序评估证据。
扫描器确定:
环境检测会改变对包和重启数据的解读。
例如,容器可以看到宿主内核,但通常无法从容器文件系统确定宿主内核包。
扫描器在以下位置搜索运行中内核的配置:```text /proc/config.gz /boot/config-$(uname -r) /lib/modules/$(uname -r)/build/.config /usr/lib/modules/$(uname -r)/build/.config
它评估:```text
CONFIG_FUSE_FS=y
CONFIG_FUSE_FS=m
CONFIG_FUSE_FS is not set
解读:
| 值 | 含义 |
|---|---|
y | FUSE 已内置到内核中。模块黑名单无法禁用它。 |
m | FUSE 可作为可加载模块使用。 |
n | FUSE 在检测到的配置中已被禁用。 |
| 未知 | 没有可用的可读配置来源。 |
扫描器检查:```text /proc/filesystems /dev/fuse PATH for fusermount3 or fusermount /proc/self/mountinfo
缺少 `/dev/fuse` 或 `fusermount3` 会降低当前环境中的即时可用性,但并不能证明内核已打补丁。
### 4. 页面大小几何结构
文档中记载的超大记录为 `4120` 字节。
当主机页面大小至少为 `4120` 字节时,文档中记载的记录不会跨越页面边界。扫描器可能报告系统在该文档记载的页面几何结构下不受影响。
该结论仅适用于文档中记载的记录以及被评估的实现行为。它并不是一种普遍性陈述,即所有 FUSE 内存安全问题在页面更大的系统上都不可能发生。
### 5. 已安装源代码检查
当已安装的源代码可用时,扫描器会搜索:```text
fs/fuse/readdir.c
它查找受影响的函数以及一个等同于拒绝 reclen > PAGE_SIZE 的防护检查。
直接源码证据比版本比较具有更高的置信度。
被检查的源码必须与正在运行的内核相对应,结果才具有权威性。/usr/src 下的发行版源码树可能代表不同的已安装内核。
扫描器尝试使用检测到的发行版包数据库,将正在运行的内核镜像映射到其所属的包。
可能的机制包括:```text dpkg-query -S rpm -qf pacman -Qo apk info -W
当识别到某个软件包时,可以检查本地变更日志元数据中是否包含对应的 CVE ID 或补丁标题。
没有变更日志匹配并不能证明不存在漏洞。厂商并不总是会在本地安装的变更日志中列出每条 CVE 引用。
### 7. 上游版本比较
解析出的内核版本会与扫描器的固定基线表进行比较。
版本比较产生的是启发式结果,原因如下:
- 厂商内核可能包含反向移植补丁;
- 内核软件包的发布修订版本因发行版而异;
- 云、实时、加固及硬件启用内核可能有各自独立的补丁时间线;
- 版本字符串可能代表的是厂商维护的分支,而非未经修改的上游发布版本。
### 8. 软件包更新元数据
在支持的情况下,扫描器会对现有的本地元数据执行只读查询。
它不会刷新仓库。
示例:```text
apt list --upgradable
pacman -Qu
dnf --cacheonly --quiet check-upgrade
zypper --no-refresh list-patches --all --cve=CVE-2026-31694
apk version -l <
显示没有可用更新的结果,其时效性仅相当于缓存的仓库元数据。
在普通主机或虚拟机上,扫描器会比较正在运行的内核与检测到的已安装内核,并检查 Debian 系列系统使用的重启标记。
在容器或 WSL 客户机内部,此检查被标记为由宿主机控制,而不是将客户机文件与宿主机内核进行比较。
证据优先级大致如下:
PATCHED直接本地证据表明修复已存在。
示例:
置信度通常较高,但仍应验证源代码与正在运行的内核之间的一致性。
NOT_EXPOSED检测到的运行中内核配置已禁用 FUSE。
这是一个暴露结果,并非内核源代码本身包含修复的证据。
NOT_EXPOSED_BY_DOCUMENTED_PAGE_GEOMETRY内存页面大小足以容纳文档记载的 4120 字节记录,且不会跨页边界。
该结论仅限于文档记载的漏洞几何。
UPSTREAM_BASELINE_SAFE解析出的运行版本符合已知的已修复上游基线,或早于受影响实现。
仍建议进行供应商软件包验证。
POTENTIALLY_VULNERABLE解析出的内核位于受影响的上游范围内,且未发现直接的本机补丁证据。
在声明已安装的内核易受攻击之前,此结果需要检查操作系统供应商公告。
INCONCLUSIVE扫描器无法获得足够证据。
常见原因:
NOT_APPLICABLE当前操作系统不是 Linux。
| Code | Meaning |
|---|---|
0 | 已修复证据、安全的上游基线,或文档记载的暴露不存在 |
1 | 可能易受攻击 |
2 | 无法确定 |
3 | 扫描器或报告生成错误 |
示例:```bash python3 cve_2026_31694_scanner.py status=$?
case "$status" in 0) echo "No actionable exposure detected by the scanner" ;; 1) echo "Potential exposure detected" ;; 2) echo "Assessment inconclusive" ;; 3) echo "Scanner execution failed" ;; esac
When `--no-exit-status` is specified, the scanner returns `0` after producing the report.
---
## Detection Sources