Correctif à chaud KVM-XJ
dump_tool.py automatise la recherche des offsets ; pour son utilisation, lisez le code.
Aperçu de la vulnérabilité
CVE-2026-53359 (Januscape) est une vulnérabilité use-after-free (UAF) dans le shadow MMU de KVM du noyau Linux.
- Temps de latence : 16 ans (août 2010 à juillet 2026)
- Portée : tous les systèmes x86 Intel/AMD avec virtualisation imbriquée activée
- Gravité : élevée, l'utilisateur root d'une VM peut s'échapper vers l'hôte et obtenir les privilèges root de l'hôte
- Méthode d'exploitation : panique du noyau de l'hôte (DoS) ou évasion complète de la machine virtuelle (aucun POC public)
Principe de la vulnérabilité
Lorsque la fonction kvm_mmu_get_page() recherche dans la table de hachage une table de pages fantômes réutilisable, elle ne compare que la gfn (numéro de cadre de page physique de l'invité), sans comparer la role (rôle de la table de pages / rôle MMU), ce qui provoque une réutilisation erronée d'une table de pages dont le rôle ne correspond pas et déclenche une UAF.
修复前(有漏洞):
┌──────────────────────────────────────┐
│ kvm_mmu_get_page() │
│ 遍历哈希表 │
│ if (child->gfn == gfn) │
│ return child ← 只比较gfn! │
│ 角色不匹配也复用 → UAF! │
│ 分配新页(安全) │
└──────────────────────────────────────┘
Le commit amont 81ccda30b4e8 a ajouté une ligne de comparaison de role :
// 修复前
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)
Ma méthode de correctif
Méthode : correctif à chaud binaire par text_poke (NOP Patch)
Sans modifier le code source du noyau ni remplacer de fonction, on modifie directement l'instruction vulnérable dans la mémoire du noyau en cours d'exécution.
Principe
二进制层面:
偏移 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 = 漏洞修复 │
└──────────────────────────────────────┘
Implémentation technique
- Trouver l'adresse de la fonction
kvm_mmu_get_page via kallsyms_lookup_name
- Trouver la fonction
text_poke via kallsyms_lookup_name (API de modification à chaud du code noyau)
- Utiliser
stop_machine pour suspendre tous les CPU et garantir la sécurité de la modification
- Remplacer l'instruction
je de 6 octets par un NOP de 6 octets avec text_poke
- Au déchargement, restaurer l'instruction d'origine avec
text_poke
Pourquoi ne pas utiliser d'autres solutions
Évaluation de l'impact
Exigences de déploiement
| Condition | Description |
|---|
| Version du noyau | Linux 4.18+ (CentOS 8 / RHEL 8 / Rocky 8, etc.) |
| Environnement de compilation |
Compilation et chargement
# 编译
make
# 加载热补丁
insmod KVM-XJ.ko
# 查看状态
dmesg | grep KVM-XJ
cat /sys/module/kvm_intel/parameters/nested # 应该还是 1
lsmod | grep KVM_XJ
# 卸载(恢复原始代码)
rmmod KVM_XJ
Adaptation à d'autres noyaux
Les optimisations de compilation diffèrent selon les versions du noyau, et l'offset de l'instruction je varie également. Utilisez dump_tool.py pour l'analyse automatique :
# 1. 从母鸡下载 kvm.ko
scp root@母鸡:/lib/modules/.../kvm.ko.xz .
xz -d kvm.ko.xz
# 2. 运行分析工具
python dump_tool.py kvm.ko
# 3. 工具会输出 patch 偏移,修改 KVM-XJ.c 中的 0x108
Noyaux vérifiés
| Version du noyau | Offset de l'instruction je | Statut |
|---|
| 4.18.0-496.el8.x86_64 | 0x108 | Testé |
| 4.18.0-358.el8.x86_64 | 0xe8 | Testé |
Remarques
- Si vous ne savez pas l'utiliser ou lire le code, il est déconseillé de l'utiliser.