概要
How Cloudflare responded to the “Copy Fail” Linux vulnerability
公開日: 2026-05-07
著者: Chris J Arges, Sourov Zaman, Rian Islam
所要時間: 約8分
2026年4月29日、ローカル権限昇格のLinuxカーネル脆弱性が「Copy Fail」として公開されました(CVE-2026-31431)。CloudflareのSecurityおよびEngineeringチームは公開と同時に脆弱性の評価を開始しました。エクスプロイト手法を精査し、インフラ全体の曝露を評価し、既存の振る舞い検知が数分以内にエクスプロイトパターンを検知できることを検証しました。Cloudflare環境への影響はなく、顧客データの危険はなく、サービスの中断も発生しませんでした。以下では、我々の準備がどのように効いたのかを説明します。
背景
我々のLinuxカーネルリリースプロセス
Cloudflareは大規模なグローバルLinuxサーバー基盤を運用しており、データセンターは330都市に分散しています。我々はコミュニティのLong-Term Support (LTS) バージョンをベースにしたカスタムLinuxカーネルビルドを維持し、この規模での更新を効率的に管理しています。ある時点で複数のLTSシリーズ(例: 6.12 や 6.18)を併用していることがあり、コミュニティがマージ/公開するセキュリティおよび安定性の更新はほぼ毎週の自動ジョブで内部カーネルビルドを生成します。これらのビルドはステージングデータセンターで安定性テストを経てからグローバルロールアウトされます。
リリース後、Edge Reboot Release (ERR) パイプラインはエッジインフラの体系的な更新と再起動を4週間サイクルで管理します。コントロールプレーンインフラは通常、最新のカーネルを採用し、再起動はワークロード要件に応じてスケジュールされます。CVEが公表される頃には、必要な修正は数週間前には安定したLinux LTSリリースに統合されており、我々の手順により既にこれらのパッチをデプロイ済みであることが多いです。
「Copy Fail」公開時点では、インフラの大半が 6.12 LTS を稼働させており、一部のマシンは新しい 6.18 LTS へ移行を始めていました。
Copy Fail 脆弱性について
本件の対応を語る前に、脆弱性の仕組みを理解しておくと役立ちます。詳しい解説は元の Xint Code の公開ポストにあります。
AF_ALG とカーネルの crypto API
Linuxカーネルの内部 crypto API は kTLS や IPsec のような機能を管理します。ユーザー空間プログラムは AF_ALG ソケットファミリを通じてこのAPIにアクセスし、非特権プロセスでも暗号化/復号を依頼できます。algif_aead モジュールは AEAD 暗号のためにこれを仲介します。
非特権プログラムの典型的な流れ:
- AF_ALG ソケットを開き、AEAD テンプレートに
bind() する。
- キーを設定し、リクエストソケットを
accept() する。
sendmsg() または splice() で入力を送る。
recvmsg() で操作を実行する。
ここで重要なのは splice() システムコールで、ページキャッシュ参照を渡すことでデータを移動します。
メモリの仕組み: ページキャッシュとインプレース暗号
ページキャッシュはファイル内容の共有キャッシュです。setuid バイナリに属するページを書き換えると、そのページが追い出されるまで全ユーザーに対してそのプログラムが変更された状態になります。crypto API は scatterlist を利用し、複数のメモリページを連結する構造を使います。2017年に algif_aead はインプレース操作のために最適化され、宛先ページと参照ページをチェインする設計が採られました。この設計はアルゴリズムが意図した境界を越えて書き込むことを防ぐ強制が欠けていました。
脆弱性: 末尾外書き込み (out-of-bounds write)
ユーザーが recvmsg() を実行すると、カーネル側の authencesn ラッパーは正当な出力領域の4バイトを越えて書き込みを行います:
scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
攻撃者は splice() を使って、ターゲットファイルのページキャッシュページを scatterlist にチェインできます。これにより、末尾外書き込みはキャッシュ済みファイルを汚染し、攻撃者はどのファイルが変更されるか、オフセット、そして書き込まれる具体的な4バイトを制御できます。つまり、このエクスプロイトによって攻撃者は以下を制御できます:
- ファイル: 任意の読み取り可能なファイル
- オフセット:
assoclen と splice パラメータで調整可能
- 値:
sendmsg() の AAD バイト 4–7 で制御
エクスプロイトの手順
デフォルトのエクスプロイトは、ほぼ全てのディストリビューションに存在する setuid-root バイナリ /usr/bin/su を標的とします。
- キャッシュ参照:
/usr/bin/su を O_RDONLY で開き read() してページキャッシュを充填する。
splice() でそのファイルディスクリプタのページキャッシュ参照を crypto scatterlist に渡す。
- セットアップ: AF_ALG ソケットを作成し、
bind() を authencesn(hmac(sha256),cbc(aes)) に対して行い、キーを設定して特権なしでリクエストソケットを accept() する。
- 書込構築: 4バイト毎にシェルコードチャンクを用意し、AAD バイト 4–7 にそのチャンクを入れて
sendmsg() を行う。splice() でバイナリをパイプへ、次に AF_ALG ソケットへ流し assoclen + cryptlen が目的の .text オフセットを指すようにする。
- トリガ:
recvmsg() が復号を開始。authencesn はスクラッチデータを /usr/bin/su のページキャッシュ上の目的オフセットへ書き込む。関数は -EBADMSG を返すが、4バイトの書き込みはグローバルページキャッシュ内に残る。
- 実行:
execve("/usr/bin/su") を実行すると汚染されたページキャッシュが読み込まれ、setuid-root のため注入したシェルコードが root 権限で実行される。
上流での修正(コミット a664bf3d603d)は2017年のインプレース最適化を元に戻すもので、これによりエクスプロイトは無効化されます。
我々の対応
公開時に複数のワークストリームが同時並行で始まりました:
- 爆発範囲のマッピング: セキュリティチームはカーネルエンジニアと協力し、どのカーネルバージョンが脆弱かを特定し曝露の可能性を評価しました。
- 遮蔽確認: セキュリティはエクスプロイト手法を精査し、既存の振る舞い検知が認可された内部検証で数分以内にエクスプロイトパターンを検知できることを確認しました。
- プロアクティブな脅威ハンティング: セキュリティは公開前に悪用されていないかを確認するため、フリート全体のログを遡り48時間分を調査しました。
- 緩和策の構築: カーネルエンジニアは、プロダクションを壊さずにフリートを保護するランタイム緩和策の構築を開始しました。
- ソフトウェア更新の継続: エンジニアは更新済みLinuxカーネルの提供に取り組み、サーバーの慎重な再起動とロールアウトを行いました。
対応中に顧客への影響は一切ありませんでした。
検知カバレッジの検証
最初に行ったことの1つは、既存のエンドポイント検知がこのエクスプロイトを捕捉するかを確認することでした。我々のサーバーは挙動検知を常時実行しており、プロセス実行パターンを監視します。特定の脆弱性を知ることに依存せず、フリート全体の異常な振る舞いを監視します。
対応チームが内部で脆弱性を検証した際、検知プラットフォームは数分以内にそれをフラグしました。システムはスクリプトインタプリタから始まり、カーネルの暗号サブシステムを経由して権限昇格バイナリに至る全実行チェーンを結び付け、フリート全体の挙動パターンに基づいて悪性と判定しました。これはシグネチャ更新もルール変更も人手介入も不要で発生しました。
我々の振る舞い検知はこの特定の Copy Fail エクスプロイトに対するカスタムロジックを書き込む前から存在しており、検知確認は脆弱性固有のルール作成前にカバレッジを持っていることを意味しました。
悪用のハンティング
エンジニアがより標的化された緩和に取り組む一方で、セキュリティ調査は公開時点から継続して実行されていました。重大脆弱性に対する我々の標準手順はシンプルです: 証明できるまで「侵害があった」と仮定する。
調査は、脆弱性が公になる前に悪用されていた可能性を前提に始まり、系統的に確認または否定していきました。エクスプロイトは実行時にカーネルログに特徴的な痕跡を残します。我々は集中ログ基盤を横断してその痕跡を検索し、公表の48時間前まで遡りました。もし事前に誰かが悪用していれば検知できたはずです。
影響を受けたシステムのアクセスログを取得し、誰がいつ接続しどんなコマンドを実行したかを再構築しました。これにより対象インフラ上の対話的活動について完全なフォレンジック像を得ました。システムバイナリの改ざんがないことを確認し、既知の正しいパッケージマニフェストとハッシュを突き合わせ、永続化メカニズムの有無を調査し、ネットワーク接続の異常を監査しました。結果はクリーンでした。
インシデントのタイムラインと影響
- 2026-04-29 16:00 — Copy Fail 公開。
- 2026-04-29 ~21:00 — Security と Engineering がフリート曝露と緩和オプションの評価を開始(Incident Response の正式宣言前)。
- 2026-04-29 22:52 — Security が既存の振る舞い検知が Copy Fail エクスプロイトパターンをカバーしていることを確認。内部検証中に検知が数分でフラグ。
- 2026-04-29 23:01 — 既存の振る舞い検知がエクスプロイト類似活動を高重大度アラートとして生成し、検知カバレッジを確認。
- 2026-04-29(夜)— 最初の緩和をステージングデータセンターへプッシュ。デプロイ過程で依存関係の競合が表面化し、ロールバック。プロダクション影響なし。
- 2026-04-29(深夜)—
bpf-lsm 緩和プログラムを草案。
- 2026-04-30 03:14 — セキュリティインシデントを宣言し、横断的協力と緊急性を促進。過去データのフリート幅調査を実施しCloudflareシステムに悪性活動が存在しないことを確認。
- 2026-04-30(午前)— エンジニアが
bpf-lsm 緩和プログラムをテストし、プロダクション対応に準備完了。
- 2026-04-30 14:25 — エンジニアリングインシデントを宣言し、緩和プログラムと Linux パッチのロールアウトを調整。
- 2026-04-30 ~17:00 — 決定: 旧 LTS 系の修正版ビルドを再起動自動化経由で展開する(新 LTS を加速しない)。それまで
bpf-lsm による防御に頼る。
- 2026-04-30(午後)— 可視性パイプライン(AF_ALG ソケット使用の eBPF トレーシング)をフリート全体に展開。正当な AF_ALG 利用者の全体像を把握可能に。
- 2026-04-30(夜)—
bpf-lsm 緩和プログラムを別ゲートでロールアウトしフリートを完全に保護。以前に脆弱だったテストノードでエンドツーエンド検証を行い、エクスプロイトが動作しないことを確認。
- 2026-05-04(午前)— 修正版カーネルで再起動自動化を通常速度で再開。
- 2026-05-04 以降 — 週初めに再起動自動化を既に通過したサーバーは手動で再起動して修正カーネルを適用。未更新のサーバーは通常の再起動自動化に従って更新。
(注: グラフは我々の緩和プログラムがインフラを通じて進行した様を示します。)
どのように緩和したか?
修正版のLinuxカーネルを展開するには時間がかかるため、再起動を伴わない緩和策も並行して進めました。
モジュールの削除
問題は algif_aead カーネルモジュールにありました。したがって単純な緩和はこのモジュールを削除し、再ロードを禁止することです。これは脆弱性を特定したセキュリティ研究者による Copy Fail の公開でも推奨されている対処です。
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
rmmod algif_aead 2>/dev/null || true
しかしモジュールを削除すると kernel crypto API を利用するソフトウェアに影響を与えるため、より外科的な緩和が必要でした。
bpf-lsm
我々はこの正確なシナリオのために既にツールを用意していました: bpf-lsm。モジュールをそのまま残したまま、正当なユーザーの利用は許可しつつ、BPF Linux Security Module プログラムを使って AF_ALG ソケットの作成や利用を制限し、不正な経路によるエクスプロイトをブロックします。これにより再起動を伴わない保護をフリート全体に適用できました。
(本文はここまでの情報に基づき翻訳しています。)