
Патч для уязвимости CVE-2026-53359
dump_tool.py — это инструмент для автоматического поиска смещений. Как им пользоваться, смотрите в коде.
CVE-2026-53359 (Januscape) — это уязвимость use-after-free (UAF) в теневом MMU KVM ядра Linux.
Функция kvm_mmu_get_page() при поиске повторно используемой теневой таблицы страниц в хеш-таблице сравнивает только gfn (гостевой номер кадра страницы), но не сравнивает role (роль таблицы/роль MMU), что приводит к ошибочному повторному использованию таблицы с несовпадающей ролью и вызывает UAF.
До исправления (уязвимо):
┌──────────────────────────────────────┐
│ kvm_mmu_get_page() │
│ обход хеш-таблицы │
│ if (child->gfn == gfn) │
│ return child ← сравнивается только gfn!
│ несовпадение роли → повторное использование → UAF!
│ выделение новой страницы (безопасно)|
└──────────────────────────────────────┘
В коммите вышестоящего ядра 81ccda30b4e8 добавлена одна строка сравнения 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)
Без изменения исходного кода ядра, без замены функций — напрямую модифицируем уязвимую инструкцию в памяти работающего ядра.
На бинарном уровне:
смещение 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 = уязвимость исправлена
└──────────────────────────────────────┘
kvm_mmu_get_page через kallsyms_lookup_nametext_poke (API горячей модификации кода ядра) через kallsyms_lookup_namestop_machine, чтобы приостановить все CPU и обеспечить безопасность модификацииtext_poke заменяем 6-байтовую инструкцию je на 6-байтовую инструкцию NOPtext_poke| Решение | Проблема |
|---|---|
| Обновление ядра с перезагрузкой | Требуется перезагрузка хоста, все VM останавливаются |
| nested=0 (отключение вложенной виртуализации) | Потеря функциональности вложенной виртуализации, невозможность запуска VM внутри VM |
| Метод kpatch | Требуется kernel-debuginfo, компиляция занимает 10-20 минут, сложные зависимости |
| Замена функции через ftrace | kvm_mmu_get_child_sp встраивается (inlined) GCC, нет отдельной точки входа |
| Мой подход text_poke | Компиляция за 10 секунд, один .c-файл, прямое исправление уязвимой инструкции |
| Функция | Влияние |
|---|---|
| Перезагрузка хоста | Не требуется |
| Перезагрузка/миграция VM | Не требуется |
| Вложенная виртуализация (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. Инструмент выведет смещение для патча, измените 0x108 в KVM-XJ.c
| Версия ядра | Смещение je | Статус |
|---|---|---|
| 4.18.0-496.el8.x86_64 | 0x108 | Протестировано |
| 4.18.0-358.el8.x86_64 | 0xe8 | Протестировано |