CVE: CVE-2026-93221
Продукт: Linux Kernel
Дата публикации: 24.09.2026
Критичность: HIGH
CVSS: 8.1 (3.1)
EPSS: 0,33%; процентиль 23,45%
CISA KEV: нет подтверждения в каталоге CISA KEV
Краткое описание
Уязвимость CVE-2026-93221 затрагивает модуль nfsd ядра Linux. В структуре struct nfsd_net поля типа bool изменяются из нескольких контекстов без сериализации.
Функция nfsd4_end_grace() проверяет grace_ended как обычное bool, что позволяет двум потокам одновременно пройти проверку и вызвать nfsd4_record_grace_done(). Это приводит к одновременному обходу reclaim_str_hashtbl и двойному освобождению объектов nfs4_client_reclaim.
Основные характеристики
Риск связан с гонкой данных в серверной части NFSv4, где два независимых контекста ядра одновременно изменяют состояние grace period. Оба вызывающих контекста находятся внутри ядра и активируются штатными механизмами nfsd.
- Тип ошибки: race condition с double free и повреждением списка.
- CVSS 3.1:
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H, оценка 8.1, severity HIGH.
- Сложность доступа: высокая из-за необходимости совпадения гонки во времени.
- Факт эксплуатации: в предоставленных источниках нет подтверждения реальных атак или массового использования.
- EPSS: 0,33%; процентиль 23,45%.
Какие продукты и версии затронуты
Затронут компонент nfsd ядра Linux. В предоставленных данных нет списка конкретных версий ядра или дистрибутивов, которые содержат уязвимый код.
- Компонент: Linux Kernel, подсистема nfsd (NFS Server Daemon).
- Файлы изменения в исправлении: fs/nfsd/netns.h, fs/nfsd/nfs4proc.c, fs/nfsd/nfs4recover.c, fs/nfsd/nfs4state.c, fs/nfsd/nfsctl.c, fs/nfsd/nfssvc.c.
- Структура: struct nfsd_net в файле fs/nfsd/netns.h.
- Функции: nfsd4_end_grace(), nfsd4_record_grace_done(), nfs4_release_reclaim(), nfs4_remove_reclaim_record(), nfsd4_find_reclaim_client().
Причина уязвимости
В структуре struct nfsd_net несколько boolean-полей изменяются из разных контекстов без сериализации. Ключевое поле grace_ended проверяется и устанавливается как обычное bool в функции nfsd4_end_grace().
Операция if (nn->grace_ended) и запись nn->grace_ended = true не атомарны относительно друг друга. Два контекста могут одновременно прочитать false, записать true и продолжить выполнение.
Оба вызывающих контекста находятся внутри ядра:
- laundromat path: laundry_wq kworker вызывает nfs4_laundromat(), которая вызывает nfsd4_end_grace().
- RECLAIM_COMPLETE path: nfsd compound kthread вызывает nfsd4_reclaim_complete(), затем inc_reclaim_complete(), затем nfsd4_end_grace().
После прохождения проверки оба потока вызывают nfsd4_record_grace_done(). Эта функция вызывает активный callback client_tracking_ops->grace_done.
Для legacy_tracking_ops вызывается nfsd4_recdir_purge_old, для cld v1+ вызывается nfsd4_cld_grace_done. Оба пути вызывают nfs4_release_reclaim(), который обходит все бакеты reclaim_str_hashtbl без блокировки и вызывает nfs4_remove_reclaim_record() на каждом элементе.
Функция nfs4_remove_reclaim_record() выполняет list_del и kfree. Два одновременных обхода одного списка приводят к повреждению указателей и двойному освобождению каждого объекта nfs4_client_reclaim.
Третий вызывающий контекст в nfs4_state_start_net() работает под nfsd_mutex до подключения клиентов и до запуска первого delayed work laundromat, поэтому он не участвует в гонке с двумя основными путями.
Как работает атака
Уязвимость реализуется через временную гонку внутри ядра. Внешний атакующий не управляет потоками напрямую, но может создать условия для активации nfsd и совпадения вызов.
Первый поток входит в nfsd4_end_grace() из laundromat workqueue или RECLAIM_COMPLETE path. Он читает grace_ended как false.
Второй поток одновременно входит в ту же функцию из другого контекста. Он тоже читает grace_ended как false.
Оба потока записывают true и проходят проверку. Оба вызывают nfsd4_record_grace_done().
Функция grace_done вызывает nfs4_release_reclaim(). Она обходит reclaim_str_hashtbl по всем бакетам без блокировки.
Каждый элемент списка обрабатывается через nfs4_remove_reclaim_record(), который удаляет элемент из списка и освобождает память с помощью kfree.
Если два потока одновременно обрабатывают один бакет, указатели в списке повреждаются. Один поток может освободить объект, а второй — использовать уже освобождённую память или повторное освобождение того же объекта.
Функция nfsd4_find_reclaim_client() может одновременно итерировать тот же бакет и читать через освобождённую память.
Условия успешной эксплуатации
Для реализации ошибки необходимы следующие условия:
- Активная подсистема nfsd в ядре Linux.
- Наличие клиентского отслеживания (client tracking) или legacy reclaim path, который использует reclaim_str_hashtbl.
- Возможность одновременного входа двух контекстов в nfsd4_end_grace(): laundromat kworker и RECLAIM_COMPLETE compound thread.
- Состояние grace_ended должно быть false в момент чтения обоими потоками.
- Отсутствие блокировки вокруг проверки и установки grace_ended до исправления.
В предоставленных источниках нет указания на конкретные сетевые настройки или параметры NFS, которые повышают вероятность гонки.
Возможный сценарий атаки
Сценарий описывает внутреннюю последовательность событий в ядре. Внешний атакующий может пытаться создать нагрузку для nfsd, чтобы увеличить шанс совпадения контекстов.
- Сервер NFS работает с включённым client tracking или legacy reclaim.
- Клиент завершает соединение или вызывает RECLAIM_COMPLETE.
- Laundromat workqueue запускает delayed work и вызывает nfsd4_end_grace().
- Одновременно compound thread обрабатывает RECLAIM_COMPLETE и вызывает inc_reclaim_complete(), затем nfsd4_end_grace().
- Оба потока читают grace_ended == false.
- Оба потока записывают grace_ended = true.
- Оба потока вызывают nfsd4_record_grace_done().
- Grace_done callback вызывает nfs4_release_reclaim().
- Два обхода reclaim_str_hashtbl одновременно удаляют и освобождают элементы списка.
- Повреждение списка или двойное kfree приводит к некорректному поведению ядра.
Есть ли публичный эксплойт
В предоставленных источниках нет отдельного PoC, эксплойта или подтверждения публичной эксплуатации CVE-2026-93221.
Исправление опубликовано в stable tree Linux Kernel:
Техническое описание ошибки доступно в описании CVE и в диффах коммитов. Отсутствие сведений об эксплойте не означает, что он невозможен: механика двойного освобождения памяти позволяет корректно воспроизвести гонку при совпадении контекстов.
Признаки эксплуатации
Специфичных IOC для CVE-2026-93221 в предоставленных источниках нет. Ниже приведены неспецифичные точки контроля, которые можно использовать как общие признаки нестабильности ядра.
- Падение или зависание процесса nfsd.
- Ошибки ядра в dmesg с упоминанием NFS, reclaim, grace, list corruption или memory corruption.
- Аномальные задержки при обработке RECLAIM_COMPLETE или shutdown grace period.
- Повторяющиеся ошибки в journalctl или syslog после операций с NFSv4 clients.
- Неожиданное завершение работы nfsd compound threads или laundromat workqueue.
Эти признаки не являются подтверждёнными IOC именно для CVE-2026-93221 и могут возникать по другим причинам.
Как обнаружить атаку
Для обнаружения потенциальной эксплуатации или нестабильности можно использовать журналы ядра и мониторинг состояния nfsd.
- Проверка dmesg на ошибки с ключевыми словами: NFS, reclaim, grace, list, memory, double free, use after free.
- Мониторинг journalctl -k за сообщениями от подсистемы nfsd.
- Наблюдение за состоянием процессов nfsd и kworker в laundromat queue.
- Проверка логов NFSv4 clients на ошибки RECLAIM_COMPLETE или grace period.
- Анализ crash dump при падении ядра на повреждение структур reclaim_str_hashtbl.
Конкретные сигнатуры для автоматического обнаружения CVE-2026-93221 в предоставленных источниках не определены.
Как проверить свою версию
Для проверки версии ядра Linux можно использовать следующие команды:
Bash:
uname -r
Bash:
uname -a
Bash:
cat /proc/version
Эти команды показывают текущую версию ядра. В предоставленных данных нет списка конкретных версий, которые содержат уязвимость или исправление.
Для проверки наличия исправления в stable tree можно сравнить локальный git-репозиторий с коммитами:
Bash:
git log --oneline | grep 11a5fe42e1811f793e04ef885b639ea7668f439d
Bash:
git log --oneline | grep df5922fe09a8131c793ffa86adf204999b0470f8
Если коммиты присутствуют в истории ядра, исправление применено. Если нет, версия может быть уязвимой.
Исправление
Исправление состоит из замены разрозненных boolean-полей в struct nfsd_net на единое unsigned long flags word с атомарными операциями.
- Поле grace_ended заменяется на бит NFSD_NET_GRACE_ENDED в flags.
- Проверка и установка выполняются через test_and_set_bit(), что гарантирует атомарность на всех архитектурах.
- Остальные поля (grace_end_forced, in_grace, somebody_reclaimed, track_reclaim_completes, nfsd_net_up, lockd_up) переводятся на test_bit/set_bit/clear_bit.
Исправление доступно в stable tree Linux Kernel:
Рекомендуется обновить ядро до версии, содержащей эти коммиты. В предоставленных источниках нет списка конкретных дистрибутивных пакетов или версий с исправлением.
Временные меры защиты
В предоставленных источниках нет временных мер защиты.
Общие защитные выводы:
- Ограничить нагрузку на nfsd, чтобы снизить вероятность совпадения контекстов laundromat и RECLAIM_COMPLETE.
- Отключить client tracking или legacy reclaim path, если это допустимо для конфигурации NFSv4.
- Перезапустить nfsd после изменения нагрузки, чтобы сбросить состояние grace period.
- Мониторинг dmesg на ошибки памяти во время работы nfsd.
Эти меры не устраняют уязвимость и могут повлиять на функциональность NFSv4.
Как проверить устранение уязвимости
После обновления ядра можно проверить наличие исправления.
- Проверить версию ядра через uname -r или cat /proc/version.
- Проверить git-логи локального репозитория ядра на наличие коммитов 11a5fe42e1811f793e04ef885b639ea7668f439d и df5922fe09a8131c793ffa86adf204999b0470f8.
- Проверить исходный код struct nfsd_net в файле fs/nfsd/netns.h: вместо bool grace_ended должно быть unsigned long flags и enum nfsd_net_flag.
- Проверить функцию nfsd4_end_grace(): вместо if (nn->grace_ended) должна быть if (test_and_set_bit(NFSD_NET_GRACE_ENDED, &nn->flags)).
- Провести функциональное тестирование NFSv4 с client tracking и legacy reclaim.
В предоставленных источниках нет автоматического инструмента проверки исправления.
Вывод
CVE-2026-93221 — это race condition в nfsd ядра Linux, который приводит к двойному освобождению памяти объектов nfs4_client_reclaim. Ошибка возникает из-за неатомарной работы с boolean-полем grace_ended в struct nfsd_net.
Исправление заменяет разрозненные boolean-поля на атомарные операции над unsigned long flags word. Обновление ядра до версии с коммитами 11a5fe42e1811f793e04ef885b639ea7668f439d и df5922fe09a8131c793ffa86adf204999b0470f8 устраняет проблему.
В предоставленных данных нет подтверждения публичной эксплуатации или конкретных версий дистрибутивов. Рекомендация — обновить ядро и проверить наличие исправления через git-логи или исходный код.
Официальные источники
- NVD — CVE-2026-93221
- FIRST EPSS — CVE-2026-93221
- nfsd: convert nfsd_net boolean flags to unsigned long flags word - kernel/git/stable/linux.git - Linux kernel stable tree
- nfsd: convert nfsd_net boolean flags to unsigned long flags word - kernel/git/stable/linux.git - Linux kernel stable tree
- CVEs — The Linux Kernel documentation
История обновлений статьи
- 26.09.2026 — Опубликована первая версия материала.
