dump_tool.py はオフセットを自動検索するためのものです。使い方はコードを見てください。
CVE-2026-53359(Januscape)は、Linux カーネル KVM シャドウ MMU における Use-After-Free(UAF)脆弱性です。
kvm_mmu_get_page() 関数は、ハッシュテーブル内で再利用可能なシャドウページテーブルを検索する際、gfn(ゲスト物理ページフレーム番号)のみを比較し、role(ページテーブルロール / MMU ロール)を比較しませんでした。そのため、ロールが一致しないページテーブルが誤って再利用され、UAF が発生します。
修正前(脆弱):
┌──────────────────────────────────────┐
│ kvm_mmu_get_page() │
│ ハッシュテーブルを走査 │
│ if (child->gfn == gfn) │
│ return child ← gfnのみ比較! │
│ ロール不一致でも再利用 → UAF! │
│ 新しいページを割り当て(安全) │
└──────────────────────────────────────┘
上流カーネルのコミット 81ccda30b4e8 でロール比較が1行追加されました:
// 修正前
if (... && spte_to_child_sp(*sptep)->gfn == gfn)
// 修正後
if (... && spte_to_child_sp(*sptep)->gfn == gfn
&& spte_to_child_sp(*sptep)->role.word == role.word)
カーネルソースを変更せず、関数を置き換えず、実行中のカーネルメモリ上で脆弱性の命令を直接修正します。
バイナリレベル:
オフセット 0x104: 49 39 47 28 cmp %rax, 0x28(%r15) ← gfn 比較
オフセット 0x108: 0f 84 9f 01 00 00 je +0x19f ← 一致すればジャンプして再利用
パッチ適用後:
オフセット 0x108: 66 0f 1f 44 00 00 NOP × 6 ← 何もしない
修正後:
┌──────────────────────────────────────┐
│ kvm_mmu_get_page() │
│ ハッシュテーブルを走査 │
│ if (child->gfn == gfn) │
│ NOP(ジャンプが消去され、スルー)│
│ 新しいページを割り当て(強制的に安全経路)│
│ → 再利用しない = UAF を誘発しない = 脆弱性修正 │
└──────────────────────────────────────┘
kallsyms_lookup_name で kvm_mmu_get_page 関数のアドレスを取得kallsyms_lookup_name で text_poke 関数(カーネルコードのホット修正 API)のアドレスを取得stop_machine ですべての CPU を停止し、修正の安全性を確保text_poke で 6 バイトの je 命令を 6 バイトの NOP に置き換えtext_poke で元の命令を復元| 方式 | 問題点 |
|---|---|
| カーネルアップグレード&再起動 | ホストの再起動が必要で、全 VM が停止 |
| nested=0(ネステッド仮想化を無効化) | ネステッド仮想化機能が失われ、VM 内で VM を実行不可 |
| kpatch 方式 | kernel-debuginfo が必要、コンパイルに 10~20 分、依存関係が複雑 |
| ftrace 関数置き換え | kvm_mmu_get_child_sp が GCC でインライン化されており、独立した関数エントリがない |
| 私の text_poke 方式 | コンパイル 10 秒、1 つの .c ファイル、脆弱性命令を直接修正 |
| 機能 | 影響 |
|---|---|
| ホストの再起動 | 不要 |
| VM の再起動/マイグレーション | 不要 |
| ネステッド仮想化(VM 内で VM を実行) | 維持、正常に使用可能 |
| 仮想マシンの作成/起動 | 正常 |
| KSM メモリ統合 | 影響なし、独立した機能 |
| CPU パフォーマンス | ほぼ影響なし(NOP は CPU を消費しない) |
| メモリ | シャドウページテーブルが再利用されず、割り当て毎に新しいページが確保されるため、少量のメモリを余分に消費 |
| KVM モジュールのアンロード | 正常(rmmod で元のコードが自動復元される) |
| 条件 | 説明 |
|---|---|
| カーネルバージョン | Linux 4.18+(CentOS 8 / RHEL 8 / Rocky 8 など) |
| コンパイル環境 | kernel-devel + gcc + make |
| ホストの再起動 | 不要 |
| VM の停止 | 不要 |
| ネステッド仮想化 | 維持 |
# コンパイル
make
# ホットパッチのロード
insmod KVM-XJ.ko
# 状態の確認
dmesg | grep KVM-XJ
cat /sys/module/kvm_intel/parameters/nested # 1 のはず
lsmod | grep KVM_XJ
# アンロード(元のコードを復元)
rmmod KVM_XJ
カーネルバージョンによってコンパイル最適化が異なり、je 命令のオフセットも異なります。dump_tool.py で自動解析します:
# 1. ホストから kvm.ko をダウンロード
scp root@ホスト:/lib/modules/.../kvm.ko.xz .
xz -d kvm.ko.xz
# 2. 解析ツールを実行
python dump_tool.py kvm.ko
# 3. ツールがパッチオフセットを出力するので、KVM-XJ.c 内の 0x108 を修正
| カーネルバージョン | je オフセット | 状態 |
|---|---|---|
| 4.18.0-496.el8.x86_64 | 0x108 | テスト済み |
| 4.18.0-358.el8.x86_64 | 0xe8 | テスト済み |