PwnEscape(CVE-2026-99999)とは — 「KVM脱出」の正体はLinux IPv4のチェックサム処理だった
はじめに
10月中旬に公開された CVE-2026-99999、通称「PwnEscape」は、ゲスト VM からホストのメモリを読み、条件がそろえばホストで任意のコードを実行できる脆弱性です。さくらインターネットなどが相次いで告知を出し、「KVM からの脱出」として広まりました。
ただ、壊れていたのは KVM ではありません。原因は Linux カーネルの IPv4 処理で、ゲストが渡す「チェックサムをどこに書くか」という情報を信用しすぎていたことです。この記事では、何が起きたか、なぜヘッダが書き換わるのか、そして自分の環境で何を確認すればよいかを順に整理します。
何が起きたのか
発端は、Vercel が 2026年8月18日に始めた賞金総額100万ドルの「Vercel Sandbox」攻略チャレンジです。pwn.ai の Paulos Yibelo 氏が開始3日目にこの不具合を見つけ、プログラムで唯一の Critical 評価を受けました。
公開されている経緯は次のとおりです。
| 日付 | 出来事 |
|---|---|
| 8/20 | ホストのメモリ漏えいを Vercel に報告 |
| 9/4 | カーネルのセキュリティ窓口へ非公開で報告(修正案つき) |
| 9/7 | virtio のメンテナである Michael S. Tsirkin 氏が再現を確認 |
| 10/7〜8 | 修正が net ツリーに取り込まれる |
| 10/13〜14 | stable 版のレビューと CVE の調整 |
研究者が示した影響は3段階あります。
- ホストのメモリ漏えい: Vercel の本番 Sandbox で確認。テストでは1パケットあたり32バイト
- ホストのクラッシュ: 研究者の環境で、Linux 6.12 と 7.x 系のホストで確認
- ホストでのコード実行: 研究者の KVM 環境で、ホストのカーネルメモリへ狙った64バイトを書き込めた
ここで区別しておきたいのは、クラッシュとコード実行は研究者が用意した環境での実証だという点です。Vercel は、Sandbox の顧客データに誰かがアクセスした報告はないとしています。CVSS v3.1 は Linux CNA が 9.3、Red Hat と SUSE は 8.8 です。差は主に「攻撃者に権限が要るか(PR)」の見方の違いで、Red Hat と SUSE はゲスト内の権限を前提にしています。
なぜ IPv4 ヘッダが書き換わるのか
チェックサムオフロードの仕組み
ネットワークカードや仮想 NIC には「チェックサムの計算を後回しにする」仕組みがあります。送り手はパケットに CHECKSUM_PARTIAL という印を付け、次の2つの値を添えます。
csum_start: チェックサムの計算を始める位置csum_offset:csum_startから数えて、計算結果を書き込む位置
virtio-net では、この2つはゲストが virtio_net_hdr に入れてホストへ渡します。つまり書き込み位置をゲストが決められるということです。ホスト側は、ハードウェアに任せられない経路に入ったとき、skb_checksum_help() でソフトウェアで計算して書き込みます。
検証したあとに書き換わる
問題は処理の順番にありました。研究者の説明を簡単にすると、次の流れです。
- ホストは IPv4 ヘッダを読み、先頭1バイト
0x45(IPv4・ヘッダ長20バイト)を確認する - フラグメント処理
ip_do_fragment()に入り、skb_checksum_help()で遅らせていたチェックサムを書き込む - ゲストは、この書き込み先が IPv4 ヘッダの先頭に重なるように
csum_startとcsum_offsetを細工している。その結果、先頭バイトが0x4f(ヘッダ長60バイト)に変わる ip_do_fragment()がヘッダ長を読み直すと60バイトと解釈し、後ろの40バイトを IP オプションとして扱う
研究者の例では、実際のデータは28バイト(ヘッダ20バイト+ペイロード8バイト)しかありません。そのため、足りない32バイトはパケットの外にあるホストのメモリから読まれ、IP オプションとしてネットワークに送り出されます。これが「1パケット32バイトの漏えい」です。
一度検証した値を、あとから信用できない入力が書き換えてしまう。時刻のずれを突く TOCTOU とよく似た形ですが、ここでは「処理を後回しにした書き込み」がそのずれを作っています。
修正の中身
修正コミット 6785011f8b16(作者は Tsirkin 氏)は、include/net/ip.h に小さなチェックを足しています。
static inline int ip_check_csum_start(const struct sk_buff *skb)
{
if (unlikely(skb->csum_start < skb->network_header + ip_hdrlen(skb)))
return -EINVAL;
return 0;
}
「チェックサムの開始位置が IPv4 ヘッダの終わりより前なら拒否する」という条件です。これを skb_checksum_help() を呼ぶ前の5か所に入れています。
ip_do_fragment()(IPv4 フラグメント)nf_br_ip_fragment()(ブリッジの conntrack)nf_queue_checksum_help()(NFQUEUE)checksum_tg()(iptables の CHECKSUM ターゲット)xfrm_output()(IPsec)
Fixes タグが指しているのは、2008年の tun への GSO 対応と、2010年の AF_PACKET へのオフロード対応です。不具合は十数年前からあったことになります。また入口は virtio-net に限らず、TUN や AF_PACKET 経由でも同じ情報を渡せます。
エンジニアへの影響
まず、自分がホスト側を管理しているかどうかで判断が分かれます。
管理していない場合(EC2・Lambda・Fargate など): AWS はマネージドサービスは影響を受けず、対応は不要としています。Vercel は Firecracker の microVM でサンドボックスを動かしており、「次のゼロデイ」を前提にした対策を挙げています。ホストのカーネルを最新に保つこと、ネストした仮想化を止めること、Firecracker の jailer で権限を絞ることの3つです。VMware ESXi や Hyper-V(Azure の基盤)のようにホストが Linux でなければ、この不具合でホストへ抜けられることはありません。ただし、その上で動いている Linux ゲストのカーネルは別に確認が必要です。
管理している場合(Proxmox、自前の KVM/QEMU、Firecracker、Kata Containers など): ホストのカーネルを修正版にして再起動します。上流の修正版は次のとおりです。
- 5.10.272 / 5.15.223 / 6.1.190 / 6.6.159 / 6.12.113 / 6.18.57 / 7.2.11 以降
注意したいのは、ディストリビューションの版番号はこの表と一致しないことです。たとえば AWS の告知では、Amazon Linux 2023 の修正版は kernel-6.1.188-233.385.amzn2023 で、上流の 6.1.190 より番号が小さくなっています。修正を古い版に取り込んで配っているためです。uname -r の数字だけで判断せず、使っているディストリビューションの告知(Debian の DSA-6568-1、Ubuntu、Red Hat、SUSE など)と照らし合わせてください。AlmaLinux は 10/16 時点ではテスト版の提供のみでした。
すぐに再起動できない場合の回避策も挙がっています。たとえばチェックサムオフロードを切る方法や、NFQUEUE・CHECKSUM ターゲット・IPsec の経路を避ける方法です。ただし CloudLinux は「部分的な回避策はあるが、どれもこのバグに対して試されていない」と書いています。Qiita の記事も同じ立場で、修正を当てるのが本筋です。
VM を使っていない環境も無関係ではありません。Qiita の記事によれば、VM がなくても TUN デバイスがあれば同じ情報を渡せます。CloudLinux は、TUN(IFF_VNET_HDR)や AF_PACKET(PACKET_VNET_HDR)を使える非特権のローカルユーザーも入口になり得るとしています。ユーザー名前空間を経由する場合も含みます。部分的な回避策として user.max_user_namespaces=0 も挙げています。信用できないユーザーやコンテナが動く CI ランナーや共用の Linux ホストも、カーネルの版を確認しておくとよいでしょう。
まとめ
- PwnEscape の原因は KVM ではなく、Linux の IPv4 処理がゲストのチェックサム位置情報を検証せずに使っていたこと
- 検証済みの IPv4 ヘッダ長があとから書き換わり、ホストのメモリ漏えいやカーネルメモリへの書き込みにつながった
- マネージドクラウドの利用者は対応不要。Linux ホストを自分で管理しているなら、カーネル更新と再起動が必要
- 版番号はディストリビューションの告知で確認する。上流の番号とは一致しない
AI を使った探索で十数年前の不具合が見つかった例でもあります。研究チームは GPT-5.6 Sol をソース解析に使ったと書いています。「後回しにした処理が、検証済みのデータを書き換えないか」という見方は、ほかのオフロード処理でも今後点検が進みそうです。