
Инструмент обнаружения и устранения уязвимостей для ошибок 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 плюс интерфейса конфигурации netlink `xfrm_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):** ```bash brew install --cask krisiasty/tap/vcheck ``` **Готовые бинарные файлы** для Linux, macOS и Windows публикуются на [странице релизов](https://github.com/krisiasty/vcheck/releases). **Из исходников** (требуется Go 1.26+): ```bash go install github.com/krisiasty/vcheck@latest ``` ## Использование ```text 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` | Внутренняя ошибка / ошибка проверки | ## Пример вывода ### Полностью защищённый хост ```console $ 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 ``` ### Незащищённый и частично загруженный хост — обычная проверка ```console $ 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` — первый запуск ```console $ 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 всё ещё загружен ```console $ 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` ```console $ 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` ```console $ 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` ```console $ 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.