不久前 Copy Fail 刚刚曝光,Linux 又迎来了一个新的重磅安全漏洞:Dirty Frag。

与 Copy Fail 类似,Dirty Frag 也利用了 零拷贝 的特性来篡改普通用户只有读权限的文件,但它作用的 Linux 模块有所不同。

同样地,如果修改 /usr/bin/su,攻击者就能够获取 root 权限。

几乎所有主流 Linux 发行版都受影响,而且该漏洞从 2017 年就已经存在。

更可怕的是,这次漏洞在官方尚未正式修复之前,就已经被第三方公开披露,这意味着 Linux 社区目前还没有可用的补丁来防护该漏洞。

演示

Dirty Frag 的 PoC 可以在 GitHub 上找到:

https://github.com/V4bel/dirtyfrag

我在 Ubuntu 24.04 上测试了这个 PoC,成功获取了 root 权限:

原理

Dirty Frag 属于与 Dirty Pipe 和 Copy Fail 同一类的漏洞。然而,Dirty Pipe 是覆盖 struct pipe_buffer,而 Dirty Frag 则是覆盖 struct sk_buff 的 frag。

在 Copy Fail 中,攻击者使用 splice(file -> pipe -> AF_ALG_fd) 将一个攻击者固定的 page cache 页植入 TX SGL。
在 recv() 内部,TX SGL 的最后 4 个字节(tag)会被分离到 areq->tsgl 并通过 sg_chain 链接到 RX SGL 的末尾。
调用 aead_request_set_crypt(req, src=RX, dst=RX) 决定使用原地模式(in-place mode),而 scatterwalk_map_and_copy(tmp+1, dst, assoclen+cryptlen, 4, 1) 会执行一次 4 字节的 seqno_lo 临时写操作到 dst 的末尾,作为字节重排的一部分。
在正常的 IPsec 路径下,该位置是 skb 的 tag 区,因此写入是无害的。但当攻击者固定的 page 被放置在该位置时,原有假设就被破坏了。

Dirty Frag 是一种漏洞,其攻击模式可以在源自 splice 的非线性 skb 的 frag 上复现。

xfrm-ESP Page-Cache 写入:esp_input 绕过 skb_cow_data,直接在 frag 上运行 crypto_authenc_esn_decrypt。
RxRPC Page-Cache 写入:rxkad_verify_packet_1 使用 pcbc(fcrypt) 在 frag 上进行原地单块解密。

需要注意的是,Dirty Frag 的触发不依赖于 algif_aead 模块是否可用。换句话说,即使在应用了已知 Copy Fail 缓解措施(如 algif_aead 黑名单)的系统上,你的 Linux 仍然可能受到 Dirty Frag 的攻击。

Page Cache (/usr/bin/su 或 /etc/passwd)skb (frag → page cache)RxRPC SubsystemXFRM/ESP SubsystemLinux KernelNamespace / SyscallsAttacker (User Space)Page Cache (/usr/bin/su 或 /etc/passwd)skb (frag → page cache)RxRPC SubsystemXFRM/ESP SubsystemLinux KernelNamespace / SyscallsAttacker (User Space)创建隔离用户/网络命名空间 🔒攻击者控制加密参数 🗝️将用户文件映射到内核skb 📦skb frag 直接指向目标页缓存 ⚠️内存页面固定,直接修改可能覆盖关键文件 📝原地解密,修改页缓存数据 🔧4-byte STORE 写入控制偏移 → 文件覆盖 💥攻击者控制 RxRPC 会话密钥 🔑解密写入,8-byte STORE 覆盖目标文件 💣alt[ESP Page-Cache 写入变体 (xfrm-esp)][RxRPC Page-Cache 写入变体]重复分块写入重建完整 payload (last-write-wins) 🔄unshare(CLONE_NEWUSER|CLONE_NEWNET)1register XFRM SA (控制 seq_hi、keys、ESN)2vmsplice + splice (file → pipe → socket)3build skb with frag pointing to page cache page P4page cache page pinned into skb frag (无复制)5send UDP packet (ESP over UDP encap)6esp_input()7skip skb_cow_data (非线性 + 无 frag_list)8in-place crypto_authenc_esn_decrypt()9scatterwalk_map_and_copy()10page cache modified (/usr/bin/su ELF 或 /etc/passwd)11add_key(rxrpc, session_key = K)12establish rxrpc connection (handshake)13vmsplice + splice (伪造 rxrpc 包)14skb frag points to page cache page P15send rxrpc DATA packet16rxkad_verify_packet_1()17skb_to_sgvec() (frag 上原地映射 sg)18crypto_skcipher_decrypt(pcbc(fcrypt))19in-place decrypt write20page cache modified (/etc/passwd 或目标文件)21execve("/usr/bin/su")22获得 root shell via 修改 setuid 二进制或 PAM 绕过 🥷23

如何缓解

因为负责任披露(responsible disclosure)的时间表和保密期(embargo)已经被打破,目前任何发行版都不存在补丁。请使用以下命令卸载存在漏洞的模块并清理 page cache。

1
sh -c "printf 'install esp4 /bin/false\ninstall esp6 /bin/false\ninstall rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag.conf; rmmod esp4 esp6 rxrpc 2>/dev/null; echo 3 > /proc/sys/vm/drop_caches; true"

执行了上述命令之后,攻击文件将无法成功执行:

1
2
wgxls@server:/tmp/dirtyfrag$ ./exp 
dirtyfrag: failed (rc=1)

Not long after Copy Fail was exposed, Linux has welcomed another blockbuster security vulnerability: Dirty Frag.

Similar to Copy Fail, Dirty Frag also exploits the zero-copy feature to tamper with files that ordinary users only have read access to, but it targets a different Linux subsystem.

Likewise, if /usr/bin/su is modified, an attacker can gain root privileges.

Almost all mainstream Linux distributions are affected, and this vulnerability has existed since 2017.

Even scarier, this time the vulnerability was publicly disclosed by a third party before the official fix was ready — meaning the Linux community currently has no available patch to defend against it.

Demo

The Dirty Frag PoC can be found on GitHub:

https://github.com/V4bel/dirtyfrag

I tested this PoC on Ubuntu 24.04 and successfully gained root privileges:

How It Works

Dirty Frag belongs to the same family of vulnerabilities as Dirty Pipe and Copy Fail. However, Dirty Pipe overwrites struct pipe_buffer, while Dirty Frag overwrites the frag of struct sk_buff.

In Copy Fail, the attacker uses splice(file -> pipe -> AF_ALG_fd) to plant an attacker-controlled page cache page into the TX SGL.
Inside recv(), the last 4 bytes (the tag) of the TX SGL are separated into areq->tsgl and chained to the end of the RX SGL via sg_chain.
Calling aead_request_set_crypt(req, src=RX, dst=RX) selects in-place mode, and scatterwalk_map_and_copy(tmp+1, dst, assoclen+cryptlen, 4, 1) performs a 4-byte seqno_lo temporary write to the end of dst as part of the byte rearrangement.
In the normal IPsec path, that location is the skb’s tag area, so the write is harmless. But when an attacker-pinned page is placed at that location, the original assumption is broken.

Dirty Frag is a vulnerability whose attack pattern can be reproduced on the frags of non-linear skbs originating from splice.

xfrm-ESP Page-Cache Write: esp_input bypasses skb_cow_data and runs crypto_authenc_esn_decrypt directly on the frag.
RxRPC Page-Cache Write: rxkad_verify_packet_1 uses pcbc(fcrypt) to perform in-place single-block decryption on the frag.

Note that triggering Dirty Frag does not depend on whether the algif_aead module is available. In other words, even on systems that have applied known Copy Fail mitigations (such as blacklisting algif_aead), your Linux may still be vulnerable to Dirty Frag.

Page Cache (/usr/bin/su or /etc/passwd)skb (frag → page cache)RxRPC SubsystemXFRM/ESP SubsystemLinux KernelNamespace / SyscallsAttacker (User Space)Page Cache (/usr/bin/su or /etc/passwd)skb (frag → page cache)RxRPC SubsystemXFRM/ESP SubsystemLinux KernelNamespace / SyscallsAttacker (User Space)Create isolated user/network namespace 🔒Attacker controls crypto parameters 🗝️Map user file into kernel skb 📦skb frag points directly at the target page cache ⚠️Page pinned in memory, writes may overwrite critical files 📝In-place decryption modifies page cache data 🔧4-byte STORE at controlled offset → file overwrite 💥Attacker controls RxRPC session key 🔑Decrypt write, 8-byte STORE overwrites target file 💣alt[ESP Page-Cache Write Variant (xfrm-esp)][RxRPC Page-Cache Write Variant]Repeated chunked writes rebuild the full payload (last-write-wins) 🔄unshare(CLONE_NEWUSER|CLONE_NEWNET)1register XFRM SA (control seq_hi, keys, ESN)2vmsplice + splice (file → pipe → socket)3build skb with frag pointing to page cache page P4page cache page pinned into skb frag (no copy)5send UDP packet (ESP over UDP encap)6esp_input()7skip skb_cow_data (non-linear + no frag_list)8in-place crypto_authenc_esn_decrypt()9scatterwalk_map_and_copy()10page cache modified (/usr/bin/su ELF or /etc/passwd)11add_key(rxrpc, session_key = K)12establish rxrpc connection (handshake)13vmsplice + splice (forge rxrpc packet)14skb frag points to page cache page P15send rxrpc DATA packet16rxkad_verify_packet_1()17skb_to_sgvec() (map sg in-place on frag)18crypto_skcipher_decrypt(pcbc(fcrypt))19in-place decrypt write20page cache modified (/etc/passwd or target file)21execve("/usr/bin/su")22Root shell via modified setuid binary or PAM bypass 🥷23

How to Mitigate

Because the responsible disclosure timeline and embargo have already been broken, no distribution currently has a patch. Please use the following command to unload the vulnerable modules and clear the page cache.

1
sh -c "printf 'install esp4 /bin/false\ninstall esp6 /bin/false\ninstall rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag.conf; rmmod esp4 esp6 rxrpc 2>/dev/null; echo 3 > /proc/sys/vm/drop_caches; true"

After running the above command, the exploit will fail to execute successfully:

1
2
wgxls@server:/tmp/dirtyfrag$ ./exp 
dirtyfrag: failed (rc=1)