
vcheck v1.6.3
Инструмент обнаружения и устранения уязвимостей для ошибок Copy Fail и Dirty Frag (CVE-2026-31431, CVE-2026-43284, CVE-2026-43500)
vcheck
Проверка удалённого Linux-хоста по SSH на уязвимости ядерных модулей Copy Fail и Dirty Frag и, при необходимости, применение мер по устранению:
| CVE | Название | Затронутые модули |
|---|---|---|
| CVE-2026-31431 | Copy Fail | algif_aead |
| CVE-2026-43284 | Dirty Frag (IPsec) | esp4, esp6, ipcomp4, ipcomp6, xfrm_user |
| CVE-2026-43500 | Dirty Frag (RxRPC) | rxrpc, kafs |
Для каждого затронутого модуля vcheck сообщает, загружен ли он в данный момент, встроен ли в работающее ядро, есть ли следы его использования в журналах ядра, есть ли активные сокеты AF_ALG (только для Copy Fail) и внесён ли он уже в чёрный список в /etc/modprobe.d/.
С флагом -fix vcheck сообщает исходное состояние, записывает фрагмент cve-XXXX-XXXXX-disable.conf для каждого модуля, который ещё не внесён в чёрный список, затем повторно выполняет проверки и сообщает итоговое состояние. С -fix -unload vcheck также пытается выгрузить затронутые модули, которые были загружены до применения исправления, а затем с помощью финального сканирования проверяет, загружены ли они по-прежнему. С -fix -rebuild-initramfs vcheck пересобирает initramfs (только) для текущего работающего ядра после записи фрагмента, чтобы чёрный список был встроен в следующий загрузочный образ. Старые записи ядра сохраняют исходный initramfs в качестве запасного варианта.
Используйте -fix только после проверочного запуска
Всегда сначала запускайте vcheck без -fix. Изучите отчёт и убедитесь, что затронутые модули можно безопасно отключить на этом хосте, прежде чем повторно запускать с -fix. Отключение ядерных модулей, от которых зависят легитимные рабочие нагрузки, может повлиять на пользователей и нарушить работу приложений.
В частности:
- Считайте
-fixбезопасным только когда ни один из затронутых модулей в данный момент не загружен — то есть каждый модуль сообщается либо какmitigated, либо какmodule not blacklisted(отсутствуют строкиVULNERABLEилиblacklisted but currently loaded). Загруженный модуль почти всегда означает, что что-то на хосте активно его использует; проверьте это перед внесением в чёрный список. - Модули IPsec (
esp4,esp6,ipcomp4,ipcomp6,xfrm_user) необходимы для любых развёртываний IPsec/strongSwan/WireGuard-over-IPsec/IKE. Модулиipcomp4/ipcomp6реализуют сжатие полезной нагрузки IPComp и могут автоматически согласовываться в составе IPsec SA, даже если не были явно сконфигурированы. Не вносите ни один из них в чёрный список на VPN-шлюзе, IPsec-конечной точке или в любом месте, гдеip xfrm policyвозвращает правила. Обратите внимание, что модуль фреймворкаxfrm_algoнамеренно не включён в этот список — согласно рекомендациям производителей (Red Hat, Ubuntu, AWS), блокировки модулей протоколов ESP и IPComp плюс интерфейса конфигурации netlinkxfrm_userдостаточно, а внесениеxfrm_algoв чёрный список сломало бы все остальные xfrm-преобразования без какой-либо дополнительной пользы. - Модули RxRPC (
rxrpc,kafs) необходимы для любого хоста, который монтирует файловые системы AFS. Их отключение нарушит эти монтирования при следующей загрузке. algif_aeadпредоставляет доступ к криптографии ядра через семейство сокетовAF_ALG. Он редко используется прикладным кодом напрямую, но перед внесением в чёрный список проверьте активные сокеты (ss -p --af-alg) и потребителей в пользовательском пространстве.
Фрагменты чёрного списка, которые записывает vcheck, вступают в силу только в момент загрузки модуля (обычно при следующей перезагрузке или при modprobe -r <module>, когда система простаивает). Модуль, который уже загружен, продолжит работать даже после -fix — vcheck сообщит об этом как blacklisted but currently loaded; run 'modprobe -r' or reboot. Передача -unload вместе с -fix предписывает vcheck выполнить modprobe -r для загруженных затронутых модулей после записи фрагментов чёрного списка. Используйте это только после того, как подтвердили, что модули можно безопасно удалить из работающего ядра.
Передача -rebuild-initramfs вместе с -fix пересоздаёт initramfs только для текущего работающего ядра (update-initramfs -u -k $(uname -r) на Debian/Ubuntu, dracut -f --kver $(uname -r) на RHEL/Fedora). Остальные установленные ядра сохраняют свой initramfs нетронутым, поэтому если после перезагрузки что-то пойдёт не так, вы сможете выбрать более старую запись ядра из меню загрузки и восстановиться. Будущие установки ядра пересобирают собственный initramfs на основе текущего состояния /etc/modprobe.d/, поэтому чёрный список распространяется автоматически без повторного запуска vcheck. Если ни update-initramfs, ни dracut не установлены (например, Arch, Alpine, неизменяемые образы), vcheck выводит предупреждение и продолжает работу — пересоберите вручную инструментом вашего дистрибутива перед перезагрузкой.
Пересборка может занять несколько минут (особенно dracut на хостах с большим количеством драйверов), что превысило бы диагностический -command-timeout. Она выполняется под собственным -initramfs-timeout (по умолчанию 10m), поэтому пересборка получает необходимое время, а быстрые проверки сохраняют свой жёсткий бюджет. Увеличьте -initramfs-timeout для медленного оборудования или укажите 0, чтобы полностью отключить тайм-аут. Во время длительных удалённых команд vcheck по умолчанию отправляет SSH keepalive-запросы каждые 30s, чтобы таймеры простоя NAT/межсетевых экранов не разрывали соединение. Настройте это параметром -ssh-keepalive или укажите 0, чтобы отключить его.
Установка
Homebrew (macOS):
brew install --cask krisiasty/tap/vcheck
Готовые бинарные файлы для Linux, macOS и Windows публикуются на странице релизов.
Из исходников (требуется Go 1.26+):
go install github.com/krisiasty/vcheck@latest
Использование
vcheck -host HOST [flags]
| Флаг | По умолчанию | Описание |
|---|---|---|
-host | (обязательный) | Удалённый хост |
-user | $USER | Удалённый пользователь |
-port | 22 | Удалённый SSH-порт |
-agent | true | Использовать SSH-агент для аутентификации |
-identity | (пусто) | Путь к файлу закрытого ключа (запросит парольную фразу, если ключ зашифрован) |
-password | false | Запросить SSH-пароль |
-insecure | false | Принимать ключи хостов, ещё не записанные в known_hosts; несовпадения с записанным ключом по-прежнему приводят к ошибке |
-fix | false | Записать фрагменты в /etc/modprobe.d для модулей, которые ещё не внесены в чёрный список |
-unload | false | Вместе с -fix выгрузить затронутые модули после внесения их в чёрный список |
-rebuild-initramfs | false | Вместе с -fix пересобрать initramfs только для работающего ядра (update-initramfs или dracut) |
-skip-logs | false | Пропустить проверки истории журналов ядра |
-timeout | 15s | Тайм-аут SSH-подключения |
-ssh-keepalive | 30s | Интервал SSH keepalive (0 отключает) |
-command-timeout | 30s | Тайм-аут удалённой команды (0 отключает) |
-initramfs-timeout | 10m | Тайм-аут для шага пересборки initramfs (0 отключает); используется только с -rebuild-initramfs |
-debug | false | Повысить подробность журналирования |
-version | false | Показать версию и выйти |
По крайней мере один из -agent, -identity или -password должен обеспечить рабочий метод аутентификации. Методы перебираются в указанном порядке.
На целевом хосте требуется sudo. Если настроен sudo без пароля, инструмент продолжает работу без запросов; в противном случае он один раз запрашивает пароль (ввод скрыт) и передаёт его через sudo -S для каждой последующей команды.
Коды выхода
| Код | Значение |
|---|---|
0 | Все затронутые модули внесены в чёрный список, выгружены, не встроены в ядро и неактивны |
1 | Ошибка использования |
2 | Не удалось установить SSH-подключение |
3 | Ошибка аутентификации sudo |
4 | Один или несколько модулей не внесены в чёрный список (текущей угрозы нет) |
5 | Один или несколько модулей в данный момент загружены, встроены в ядро или активно используются |
99 | Внутренняя ошибка / ошибка проверки |
Пример вывода
Полностью защищённый хост
$ vcheck -host host.example.com -identity ~/.ssh/id_ed25519
INF connected user=ops host=host.example.com port=22
INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail"
INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)"
INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)"
INF mitigated cve=CVE-2026-31431 module=algif_aead
INF mitigated cve=CVE-2026-43284 module=esp4
INF mitigated cve=CVE-2026-43284 module=esp6
INF mitigated cve=CVE-2026-43284 module=ipcomp4
INF mitigated cve=CVE-2026-43284 module=ipcomp6
INF mitigated cve=CVE-2026-43284 module=xfrm_user
INF mitigated cve=CVE-2026-43500 module=rxrpc
INF mitigated cve=CVE-2026-43500 module=kafs
Незащищённый и частично загруженный хост — обычная проверка
$ vcheck -host host.example.com -identity ~/.ssh/id_ed25519
INF connected user=ops host=host.example.com port=22
INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail"
INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)"
INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)"
INF mitigated cve=CVE-2026-31431 module=algif_aead
ERR VULNERABLE cve=CVE-2026-43284 module=esp4 loaded=true
ERR module not blacklisted cve=CVE-2026-43284 module=esp6
ERR module not blacklisted cve=CVE-2026-43284 module=ipcomp4
ERR module not blacklisted cve=CVE-2026-43284 module=ipcomp6
ERR module not blacklisted cve=CVE-2026-43284 module=xfrm_user
ERR module not blacklisted cve=CVE-2026-43500 module=rxrpc
ERR module not blacklisted cve=CVE-2026-43500 module=kafs
Тот же хост с -fix — первый запуск
$ vcheck -fix -host host.example.com -identity ~/.ssh/id_ed25519
INF connected user=ops host=host.example.com port=22
INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail"
INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)"
INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)"
INF findings before fix
INF mitigated cve=CVE-2026-31431 module=algif_aead
ERR VULNERABLE cve=CVE-2026-43284 module=esp4 loaded=true
ERR module not blacklisted cve=CVE-2026-43284 module=esp6
ERR module not blacklisted cve=CVE-2026-43284 module=ipcomp4
ERR module not blacklisted cve=CVE-2026-43284 module=ipcomp6
ERR module not blacklisted cve=CVE-2026-43284 module=xfrm_user
ERR module not blacklisted cve=CVE-2026-43500 module=rxrpc
ERR module not blacklisted cve=CVE-2026-43500 module=kafs
INF writing modprobe.d snippet path=/etc/modprobe.d/cve-2026-43284-disable.conf modules="[esp4 esp6 ipcomp4 ipcomp6 xfrm_user]"
INF writing modprobe.d snippet path=/etc/modprobe.d/cve-2026-43500-disable.conf modules="[rxrpc kafs]"
INF re-scanning after fix snippets_written=2
INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail"
INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)"
INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)"
INF findings after fix
INF mitigated cve=CVE-2026-31431 module=algif_aead
ERR blacklisted but currently loaded; run 'modprobe -r' or reboot cve=CVE-2026-43284 module=esp4
INF mitigated cve=CVE-2026-43284 module=esp6
INF mitigated cve=CVE-2026-43284 module=ipcomp4
INF mitigated cve=CVE-2026-43284 module=ipcomp6
INF mitigated cve=CVE-2026-43284 module=xfrm_user
INF mitigated cve=CVE-2026-43500 module=rxrpc
INF mitigated cve=CVE-2026-43500 module=kafs
Чёрный список на месте, но esp4 был загружен в ядро до записи фрагмента. Перезагрузите хост или выполните sudo modprobe -r esp4 на целевом хосте, чтобы полностью его выгрузить.
Второй запуск — esp4 всё ещё загружен
$ vcheck -fix -host host.example.com -identity ~/.ssh/id_ed25519
INF connected user=ops host=host.example.com port=22
INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail"
INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)"
INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)"
INF findings before fix
INF mitigated cve=CVE-2026-31431 module=algif_aead
ERR blacklisted but currently loaded; run 'modprobe -r' or reboot cve=CVE-2026-43284 module=esp4
INF mitigated cve=CVE-2026-43284 module=esp6
INF mitigated cve=CVE-2026-43284 module=ipcomp4
INF mitigated cve=CVE-2026-43284 module=ipcomp6
INF mitigated cve=CVE-2026-43284 module=xfrm_user
INF mitigated cve=CVE-2026-43500 module=rxrpc
INF mitigated cve=CVE-2026-43500 module=kafs
INF fix: nothing to do — all affected modules already blacklisted
Третий запуск — после modprobe -r esp4
$ vcheck -host host.example.com -identity ~/.ssh/id_ed25519
INF connected user=ops host=host.example.com port=22
INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail"
INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)"
INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)"
INF mitigated cve=CVE-2026-31431 module=algif_aead
INF mitigated cve=CVE-2026-43284 module=esp4
INF mitigated cve=CVE-2026-43284 module=esp6
INF mitigated cve=CVE-2026-43284 module=ipcomp4
INF mitigated cve=CVE-2026-43284 module=ipcomp6
INF mitigated cve=CVE-2026-43284 module=xfrm_user
INF mitigated cve=CVE-2026-43500 module=rxrpc
INF mitigated cve=CVE-2026-43500 module=kafs
С -rebuild-initramfs
$ vcheck -fix -rebuild-initramfs -host host.example.com -identity ~/.ssh/id_ed25519
...
INF writing modprobe.d snippet path=/etc/modprobe.d/cve-2026-43284-disable.conf modules="[esp4 esp6 ipcomp4 ipcomp6 xfrm_user]"
INF writing modprobe.d snippet path=/etc/modprobe.d/cve-2026-43500-disable.conf modules="[rxrpc kafs]"
INF rebuilding initramfs for running kernel timeout=10m0s
INF initramfs rebuilt for running kernel tool=update-initramfs
INF re-scanning after fix snippets_written=2
...
Пересобирается только initramfs работающего ядра. Остальные установленные ядра сохраняют свой initramfs, поэтому более старая запись в меню загрузки остаётся работоспособным запасным вариантом, если новый initramfs вызовет проблемы. На хосте без update-initramfs и dracut vcheck записывает в журнал WRN no supported initramfs tool found ... и продолжает работу.
Первый запуск на хосте — -insecure
$ vcheck -insecure -host host.example.com -identity ~/.ssh/id_ed25519
WRN host key not in known_hosts; accepting due to -insecure host=host.example.com:22 remote=192.0.2.42:22 fingerprint=SHA256:AAAAEXAMPLEfingerPrint000000000000000000000
INF connected user=ops host=host.example.com port=22
INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail"
...
-insecure принимает хосты, которых ещё нет в known_hosts. Если хост уже записан и предоставляет другой ключ, соединение по-прежнему завершится ошибкой — этот флаг лишь разрешает «первый контакт», а не способ подавить предупреждения о человеке-посередине для известного хоста.
Детали обнаружения
- Загружен:
lsmodвыполняется один раз, а имена модулей сопоставляются с первой колонкой. - Встроен в ядро: проверяются
/lib/modules/$(uname -r)/modules.builtinи/sys/module, поскольку фрагменты modprobe не могут отключить код, скомпилированный в работающее ядро. - В чёрном списке: каждый файл в
/etc/modprobe.d/проверяется (grep -rE) на наличие директивыinstall <module> /bin/false— той же формы, которую vcheck записывает с-fix. Другие формы отключения (например,blacklist) не распознаются. - Прошлая активность: сначала используется
journalctl -k, с запасным вариантом на/var/log/kern.log; для каждого модуля сохраняются последние пять подходящих строк. Передайте-skip-logs, чтобы пропустить этот шаг. - Активные сокеты (только для
algif_aead):ss -p --af-algвыводит список открытых сокетовAF_ALG; любой вывод, кроме заголовка, считается активным использованием.
Все команды выполняются через sudo и ограничены тайм-аутом -command-timeout — привилегированный доступ требуется для чтения /var/log/kern.log, получения списка сокетов AF_ALG и записи в /etc/modprobe.d/. С -unload привилегированный доступ также требуется для выполнения modprobe -r. С -rebuild-initramfs vcheck выполняет update-initramfs -u -k $(uname -r) (Debian/Ubuntu) или dracut -f --kver $(uname -r) (RHEL/Fedora), которым также нужны права root.