Theori(Xint)の研究チームが、Linuxカーネルの暗号化サブシステムに潜むロジックバグ「Copy Fail(CVE-2026-31431)」を公表した。authencesnテンプレートとAF_ALGソケットの組み合わせで、非特権ユーザーが任意の読み取り可能ファイルのページキャッシュに4バイトの制御可能書き込みを発生させられる。研究者によれば、わずか732バイトのPythonスクリプトで/usr/bin/suを改変してroot権限を奪取できる。Ubuntu 24.04・Amazon Linux 2023・RHEL 10.1・SUSE 16が検証済みで、2017年以降のすべてのLinuxカーネルが該当する。コンテナエスケープにも直結するため、ECS・EKSを運用するチームは即時に対応方針を決める必要がある。
この記事ではLinuxカーネルのページキャッシュ書き込み脆弱性CVE-2026-31431の影響と対策を解説します。サプライチェーンや依存関係を含む全体的な防御戦略はサプライチェーンセキュリティ2026|攻撃手法・防御ツール・実践チェックリストをご覧ください。
この記事のポイント
- 非特権ユーザーが
AF_ALGソケットとsplice()を組み合わせ、/usr/bin/suなどsetuid実行ファイルのページキャッシュを4バイト書き換えてroot奪取できる。 - オンディスクのファイルは無傷のため、Tripwireや
rpm -Vなどのファイル整合性チェックでは検出不可。「メモリ上だけが汚染されたsetuidバイナリ」が走る。 - ページキャッシュはホスト全体で共有されるため、ECS・EKSノードに同居する別コンテナや別Podへ影響が伝播する。マルチテナントクラスタでは特に危険。
Copy Fail(CVE-2026-31431)とは:4バイト書き込みでroot奪取まで届く脆弱性
Copy Failは、Linuxカーネルの暗号化APIであるAF_ALGソケットと、AEADテンプレートauthencesnの動作が結合したロジック系の権限昇格脆弱性だ。CWEとしては「Improper Restriction of Operations within the Bounds of a Memory Buffer」(CWE-119)に近い。Theori Xintが2026年4月に公開したアドバイザリで割り当てられたCVE番号はCVE-2026-31431。
「Copy Fail」というニックネームは、copy_from_user系の入出力がインプレース最適化(同じバッファを入力と出力に使う)によって書き込み禁止であるべきページにまで到達してしまうことを指している。
| 項目 | 内容 |
|---|---|
| CVE | CVE-2026-31431(2026年4月22日割り当て) |
| 公表 | 2026年4月、Theori Xint Labs |
| 種別 | ロジックバグ/インプレース最適化の境界違反 |
| 必要な権限 | 非特権ユーザー(AF_ALGソケットが使えれば十分) |
| 書き込みサイズ | 4バイト(seqno_loの値、AADで制御可能) |
| エクスプロイトサイズ | 約732バイトのPythonスクリプト |
| 検出難度 | オンディスク不変のためFIMで検出不可 |
| 対象カーネル | 2017年以降のすべてのLinuxカーネル |
なぜ非特権ユーザーで成立するのか
AF_ALGは本来、ハードウェア暗号アクセラレータをユーザー空間アプリケーションへ公開するためのカーネル暗号APIだ。socket(AF_ALG, SOCK_SEQPACKET, 0)で誰でもオープンでき、CAP_SYS_ADMINなどの特権は要らない。デフォルトのDocker・containerd・runc seccompプロファイルはsocket()システムコール自体を許可しているため、コンテナ内の非特権プロセスからも到達できる。
splice()は、ファイルディスクリプタからソケットへコピーなしでデータを渡すシステムコールだ。コピーが省かれるということは、カーネル内では「ページキャッシュ上の物理ページへのポインタ」がそのまま暗号化サブシステムに渡るということを意味する。
攻撃の仕組み:authencesn・AF_ALG・splice()の3つの罠
Copy Failは単一バグではなく、Linuxカーネルへ独立に入った3つの変更の合流点で生まれた脆弱性だ。歴史的経緯を押さえると、なぜ2017年以降のすべてのカーネルで成立するのかが見える。
| 年 | 変更 | 役割 |
|---|---|---|
| 2011 | authencesnテンプレート追加 |
IPsec ESN用に「宛先バッファを一時領域として使う」初期設計 |
| 2015 | AF_ALGにAEAD対応+splice()パス追加 |
ユーザー空間からページキャッシュ参照を渡せるように |
| 2017 | algif_aead.cがインプレース動作に変更 |
req->src == req->dstでページキャッシュが「書き込み可能」扱いに |
authencesnが4バイトを書き戻す仕組み
authencesnは、IPsecのExtended Sequence Number(ESN)を扱うための復号テンプレートで、復号中にAAD(追加認証データ)の一部であるseqno_lo(4バイト)を宛先スキャッタリスト末尾の特定オフセットへ書き戻す。通常の用途では復号成功時の出力タグ領域に当たるはずだった。
しかし2017年のインプレース最適化のもとでは、dst[assoclen + cryptlen]の位置がチェーン化されたページキャッシュページに落ちる。HMAC検証が失敗してもこの書き込みは取り消されないため、攻撃者は「タグ検証を意図的に失敗させながらページを書き換える」操作が可能になる。
エクスプロイトの骨格(PoCコード抜粋)
公開されたPoCの中核は以下のような構造だ。splice()で渡された同一ページが暗号化サブシステムの出力バッファにもなるため、カーネルが4バイトを書き込む先は攻撃者が制御できる。
import socket, struct, os, fcntl
# AF_ALG ソケットで authencesn(hmac(sha256),cbc(aes)) にバインド
sock = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
sock.bind((
b"aead",
b"authencesn(hmac(sha256),cbc(aes))",
0, # feat
16, # aeadtype (IVlen=16)
))
# 鍵をセット(32+32+16 バイト: SHA256 HMAC鍵 + AES鍵 + ESN)
key = bytes(80)
sock.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, key)
op = sock.accept()[0]
# su のページキャッシュを splice() で渡す
fd = os.open("/usr/bin/su", os.O_RDONLY)
# pipe 経由で splice を繋ぐ
rfd, wfd = os.pipe()
os.splice(fd, 0, wfd, 0, 4096)
# AAD バイト4-7に書き込みたい4バイト値をセット
want_bytes = struct.pack("<I", 0xdeadbeef)
aad = b"\x00" * 4 + want_bytes + b"\x00" * 8
# sendmsg + recvmsg でトリガー
# ... (HMAC 失敗するが書き込みは完了)
オフセット制御はspliceのオフセット・長さ・assoclenの組み合わせで決まる。4バイト書き込みを繰り返すことで、実行ファイルの任意のシェルコードを注入する。
ページキャッシュ汚染がディスクに書き戻されない理由
カーネルはsplice()経由で渡されたページを「ダーティ」としてマークしない。authencesnの書き込みは暗号処理内部の副作用として発生するため、ページフレームのdirtyフラグが立たない。その結果:
sync/fsyncを呼んでもディスクに書き戻されない- Tripwire・IMA(Integrity Measurement Architecture)・
rpm -V・dpkg -Vはオンディスクのハッシュを検証するため、ページキャッシュ上の改ざんを見逃す - マシン再起動でページキャッシュは消える(揮発性攻撃)が、再起動するまで改ざんが持続する
検出不可の盲点 FIM(ファイル整合性監視)ツールはこの脆弱性を検出できない。「ファイルのハッシュが一致している」は「実行されるコードが正常」を意味しなくなっている。ランタイム保護(eBPFベースのシステムコール監視等)でのみ検知が見込める。
EC2・ECS・EKSへの影響:ページキャッシュはコンテナ境界を越える
この脆弱性がコンテナ運用で特に深刻なのは、ページキャッシュがホスト全体で共有されているからだ。Linuxのページキャッシュは名前空間(namespace)やcgroupでは分離されない。コンテナ1台が同じページをsplice()で取得した瞬間から、そのページへの書き込みはホスト全体、ひいては同一ホスト上のすべてのコンテナに波及する。
(ページキャッシュ共有)"] --> B["ECS Task A
(通常アプリ)"] A --> C["ECS Task B
(悪意あるコンテナ)"] A --> D["ECS Task C
(別チームのサービス)"] C -- "CVE-2026-31431
ページキャッシュ書き込み" --> A A -- "汚染された su/bash
がホスト全体に影響" --> B A --> D style C fill:#ff6b6b,color:#fff style A fill:#ffa94d,color:#fff
素のEC2でも影響する
コンテナを使っていないシンプルなEC2インスタンス単体でも、この脆弱性は成立する。EC2上でSSH接続を受け付けているサービスや、ウェブアプリのプロセスが動いているだけの構成でも、同じインスタンスに別ユーザーがログインしていたり、マルチユーザー環境であれば攻撃が完結する。
具体的に危険なケースは次の通りだ。
- 踏み台サーバー(Bastion Host) — 複数の開発者が同一インスタンスにSSHログインする構成。低権限ユーザーがrootに昇格できる
- CI/CDランナーをEC2で自前構築 — ビルドジョブが非特権で走る環境。悪意あるコードが混入したビルドがroot奪取に繋がる
- マルチテナント共用サーバー — 複数のサービスが同一OS上でLinuxユーザーを分けて動いている構成
- Auto Scaling Group の全インスタンス — 同じAMI・同じカーネルで起動している全インスタンスが一斉に対象になる
EC2 AMIのベースOSがAmazon Linux 2023(kernel 6.18.8)の場合は検証済みの被影響対象だ。Ubuntu 22.04/24.04 ベースのAMIも同様に影響を受ける。
# 自分の EC2 インスタンスが影響を受けるか確認
uname -r
# 例: 6.1.xx.amzn2023.x86_64 → 影響あり
# Amazon Linux 2023 の場合: カーネルアップデートを確認
dnf check-update kernel
# Ubuntu の場合
apt-get update && apt-cache policy linux-image-$(uname -r)
Auto Scaling Group の注意点
Launch Template で使用している AMI のカーネルが古い場合、スケールアウトで起動する新インスタンスも脆弱なカーネルのまま立ち上がる。AMI を更新するか、ユーザーデータでalgif_aeadをブロックするミティゲーションを入れておくこと。
運用形態別の影響と対応優先度
| 運用形態 | カーネル管理 | 影響 | 対応方法 | 優先度 |
|---|---|---|---|---|
| 素の EC2(AL2023/Ubuntu) | 自己管理 | 直接影響。マルチユーザー環境では即時リスク | dnf/apt update kernel → 再起動 |
最高 |
| 踏み台・CI ランナー EC2 | 自己管理 | 複数ユーザーが同居するため特に危険 | カーネル更新 + algif_aead ブロック | 最高 |
| ECS on EC2(AL2023) | 自己管理 | Amazon Linux 2023 (kernel 6.18.8)が検証済み被影響 | AL2023 AMI更新+インスタンス入れ替え | 高 |
| EKS Managed Node | AWS管理(AMI) | EKS最適化AMIのカーネル更新待ち | AMI更新+ノードローテーション | 高 |
| EKS Self-managed Node | 自己管理 | 同上。自分でAMI管理 | dnf update kernel後ノード再起動 |
高 |
| ECS on Fargate | AWS管理 | AWSがホストを管理。パッチ適用はAWS側 | タスク再起動で新ホストへ移行。AWS告知を待機 | 中 |
| Fargate for EKS | AWS管理 | Fargateと同様にAWS側で対応 | Pod再デプロイで新ホストへ | 中 |
| EC2上の自前Docker | 自己管理 | ホストカーネルが直接影響 | dnf/apt update kernel後に再起動 |
高 |
マルチテナントEKSで最も危険なシナリオ
EKSのノードに複数チームのPodが同居する構成(共有ノード)では、あるNamespaceの悪意あるPodが脆弱性を突き、ホスト上のすべてのPodに影響するページを汚染できる。これは実質的なコンテナエスケープであり、ノード全体の制圧に繋がる。
Theoriのアドバイザリでは「Part 2:Kubernetes コンテナエスケープ」が予告されており、より詳細な攻撃手順が近く公開される予定だ。CI/CDランナー(外部からコードを受け取って実行する環境)は最優先でパッチを適用すべきだ。同様のRCEがCI/CDパイプラインで問題になった事例はGitHub RCE脆弱性CVE-2026-3854解説:git push一発でサーバー乗っ取り、Wizが発見も参照されたい。
seccompプロファイルとの関係
デフォルトのDockerおよびKubernetesのseccompプロファイル(runtime/default)は、socket(AF_ALG, ...)を許可している。AF_ALGを明示的にブロックするカスタムseccompプロファイルを適用するか、後述のカーネルモジュール無効化を行わない限り、コンテナ内からも攻撃可能だ。
対策と即時ミティゲーション:パッチ適用前にやれること
根本対策はカーネルパッチ(コミットa664bf3d603d)の適用だ。algif_aead.cがアウトプレース動作に戻され、req->srcとreq->dstが分離される。ページキャッシュが書き込み可能スキャッタリストに入らなくなる。
パッチの確認方法
# カーネルバージョンとパッチ状況確認
uname -r
# Amazon Linux 2023 の場合
dnf check-update kernel
# Ubuntu の場合
apt-get update && apt-cache policy linux-image-$(uname -r)
# カーネルモジュール algif_aead のロード状況確認
lsmod | grep algif
即時ミティゲーション(パッチ適用前)
パッチが適用されるまでの間、algif_aeadカーネルモジュールをブロックすることで攻撃経路を閉じられる。AF_ALGソケット自体は生きているが、authencesnがバインドできなくなる。
# algif_aead モジュールをブロック(ホスト側で実行)
echo "install algif_aead /bin/false" | sudo tee /etc/modprobe.d/disable-algif-aead.conf
# 既にロード済みの場合はアンロード
sudo rmmod algif_aead 2>/dev/null || echo "already unloaded or builtin"
# 設定を永続化
sudo dracut -f # RHEL/AL2023 系
# または
sudo update-initramfs -u # Debian/Ubuntu 系
ECS on EC2 での対応手順
- Launch Template または AMI のユーザーデータに上記
modprobe.d設定を追加 - 新しい AMI または起動設定でインスタンスを入れ替え(In-place再起動でも可)
- AL2023 カーネルアップデート後は設定を元に戻してよい
カスタムseccompプロファイルで AF_ALG をブロック
モジュール無効化ができない環境(Fargateや共有ノード)では、コンテナレベルでAF_ALGソケット作成をブロックするseccompプロファイルを使う。
{
"defaultAction": "SCMP_ACT_ERRNO",
"syscalls": [
{
"names": ["socket"],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 36,
"op": "SCMP_CMP_NE"
}
]
}
]
}
上記はAF_ALGのドメイン値36に対するsocket()呼び出しを拒否する例だ。KubernetesではPodのannotationまたはsecurityContext.seccompProfileで適用できる。
Amazon Linux 2023(ECS/EKS の主要OS)での緊急対応フロー
# Step 1: 現在のカーネルバージョン確認
uname -r
# 例: 6.1.xx-xxx.xxx.amzn2023.x86_64
# Step 2: 最新カーネルへアップデート(パッチ適用版を確認)
sudo dnf update -y kernel kernel-modules
# Step 3: 再起動(ECSタスクを停止してEC2を再起動)
sudo reboot
# Step 4: 再起動後にバージョン確認
uname -r
# Step 5: algif_aead モジュールの状態確認(ミティゲーション適用中の場合)
lsmod | grep algif_aead
eBPFによるランタイム検知:FIMが効かないなら何で検知するか
ファイル整合性監視が効かないため、ランタイムでのシステムコール監視が唯一の検知手段になる。AF_ALGソケットを生成するsocket(AF_ALG, SOCK_SEQPACKET, 0)呼び出しは、通常のWebアプリやAPIサービスではほぼ発生しない。この呼び出しをトリガーにアラートを発報する。
Falcoルール例
- rule: AF_ALG Socket Created
desc: Detect AF_ALG socket creation which may indicate CVE-2026-31431 exploitation
condition: >
syscall.type = socket and
socket.domain = AF_ALG
output: >
AF_ALG socket created (user=%user.name pid=%proc.pid
container=%container.id image=%container.image.repository)
priority: WARNING
tags: [cve-2026-31431, kernel, privilege-escalation]
eBPFプローブによる直接監視
// AF_ALG = 38 (architectureによって異なる)
SEC("kprobe/sys_socket")
int detect_af_alg(struct pt_regs *ctx) {
int domain = (int)PT_REGS_PARM1(ctx);
if (domain == AF_ALG) {
bpf_printk("AF_ALG socket created by pid %d\n", bpf_get_current_pid_tgid());
// アラート送信またはプロセスシグナル
}
return 0;
}
FalcoやTetragonなどeBPFベースのランタイムセキュリティツールを導入していれば、既存のルールセットを拡張するだけで対応できる。AI支援のセキュリティツールが脆弱性を発見する事例についてはYoloFS:AIエージェントのファイルシステム安全性とサンドボックス設計で別の観点から解説している。
実際の緊急度:「侵入されていたら終わり」論で考える
技術的には深刻だが、実務の優先度は構成次第で大きく変わる。冷静に整理しておきたい。
この脆弱性の本質的な制約
Copy Failはローカル権限昇格だ。攻撃者がまず同一システム上でシェルを実行できる状態でないと成立しない。
攻撃が成立するには:
① 攻撃者がEC2/コンテナ内でコード実行できる状態
↓
② そこから Copy Fail でroot昇格
①がなければ②は使えない。言い換えると、①の時点で侵害はすでに成立している。Copy Failはその被害を「限定的な侵害」から「完全なroot掌握」に拡大させる二次的なリスクだ。
典型的な攻撃チェーンはこうだ。
(SQLi/RCE等)"] --> B["アプリプロセスで
シェル取得
(www-data等)"] B --> C["Copy Fail で
root昇格"] C --> D["バックドア設置
認証情報抜き出し
/etc/passwd改ざん"] style A fill:#ff6b6b,color:#fff style C fill:#ffa94d,color:#fff style D fill:#c0392b,color:#fff
ここで重要なのは、AのWebアプリ脆弱性を防ぐ方が優先度が高いという点だ。Copy Failのパッチはその後でも遅くない。
構成別の実際の緊急度
| 構成 | 実際の緊急度 | 理由 |
|---|---|---|
| 踏み台EC2(複数人がSSHログイン) | 今すぐ | 正規ユーザーが①を常に満たしている状態 |
| CI/CDランナー(外部コードを実行) | 今すぐ | 悪意あるコードがそのまま①になる |
| 普通のWebアプリEC2(1サービスのみ) | 低〜中 | ①=アプリへのRCEが別途必要。そこまで来たら既に深刻 |
| ECS/EKS(信頼できるイメージのみ) | 低 | コンテナ内でのシェル取得手段が別途必要 |
| ECS Fargate | 低 | AWS管理。①の手段が限られる |
実務的な対応判断の目安
今週中に対応:踏み台サーバー・CI/CDランナー → algif_aeadブロック+カーネル更新スケジュール確定
次の定期メンテで対応:通常のWebアプリEC2・ECS/EKS → AMI/カーネル更新サイクルに乗せる
AWS告知を待てばOK:Fargate → AWS側がパッチを適用する
記事の技術内容との温度差について
本記事で解説している攻撃フロー(732バイトのPython・コンテナエスケープ・FIM検出不可)は技術的な最大リスクの説明だ。「すべての環境が同じレベルで危険」ではなく、「①の侵入前提が成立する環境」を優先して対処するのが現実的な判断だ。Copy Failより先に塞ぐべき穴がある場合が多い。
まとめ:FIM検出不可のステルス脆弱性に備える
Copy Fail(CVE-2026-31431)は「2017年以降のすべてのLinuxカーネルが影響」「FIMで検出不可」「コンテナ境界を越える」という3点が重なる、対応コストが高い脆弱性だ。
| 脆弱性特性 | Copy Fail の挙動 |
|---|---|
| 必要権限 | 非特権ユーザー(CAP不要) |
| 書き込みサイズ | 4バイト(繰り返し可) |
| オンディスク影響 | なし(ページキャッシュのみ) |
| FIMでの検出 | 不可 |
| コンテナエスケープ | ページキャッシュ共有により可能 |
| 対象カーネル | 2017年以降すべて |
| ミティゲーション | algif_aeadブロックまたはseccomp強化 |
対応の優先度は次の順だ。
- マルチテナントEKS・CIランナー — 即時
algif_aeadブロック+カーネルパッチ待機 - ECS on EC2(Amazon Linux 2023) — AMI更新スケジュール確定+ミティゲーション適用
- ECS on Fargate — AWS側のパッチ告知を監視し、タスク再起動計画を立てる
- EKS Managed Node — Amazon EKS最適化AMIの更新リリースを確認
「オンディスクが正常だから安全」という前提は、このクラスの脆弱性では通用しない。FIMに頼らないランタイム監視層(eBPF/Falco/Tetragon)を防御スタックに加えることが、今後のカーネル脆弱性への備えとしても有効だ。
サプライチェーン攻撃全体の文脈でのコンテナ・カーネルセキュリティはサプライチェーンセキュリティ2026|攻撃手法・防御ツール・実践チェックリストにまとめている。
参照ソース
- Copy Fail: Unauthorized Page Cache Write on Linux Distributions (CVE-2026-31431) - Xint.io
- Linux Kernel Git: algif_aead.c - コミット a664bf3d603d
- Linux Kernel Documentation: AF_ALG - Crypto API User Space Interface
- Falco Security - Kernel Module and eBPF Based Runtime Security
- Amazon Linux Security Center - ALAS Advisories