Сервис развивается: тестируем формат, собираем идеи, улучшаем сервис. Есть идеи? Написать
Войти
Дайджесты новостей
Узлы кластера Kubernetes с линиями разделяемого кэша страниц ядра Linux и панелью фильтрации системных вызовов seccomp в пиксель-арт стиле

Уязвимость Copy Fail в Kubernetes: почему PSS Restricted и RuntimeDefault не защищают кэш ядра Linux

Уязвимость CVE-2026-31431 в криптосокетах ядра Linux меняет границы изоляции: тесты на Talos и AWS EKS показали, как непривилегированный контейнер под профилем PSS Restricted искажает данные в общем кэше страниц других подов на том же узле, пока стандартный seccomp RuntimeDefault пропускает вызов.

Уязвимость Copy Fail в Kubernetes: почему PSS Restricted и RuntimeDefault не защищают кэш ядра Linux

Контейнерная архитектура современных кластеров Kubernetes строится на предположении, что многопользовательская изоляция надежно обеспечивается комбинацией пространств имен, контрольных групп cgroups и стандартов безопасности Pod Security Standards (PSS). Инфраструктурные команды привыкли считать: если pod запущен без root-привилегий, с полным сбросом linux capabilities, флагом allowPrivilegeEscalation: false и стандартным профилем seccomp RuntimeDefault, его процессы изолированы от соседних нагрузок. Однако исследование уязвимости CVE-2026-31431 (Copy Fail) выявило фундаментальное ограничение этой модели: контейнеры делят между собой единый экземпляр ядра Linux и общее дисковое кэширование в оперативной памяти — page cache.

Парадокс контейнерной изоляции и разделяемый page cache

В отличие от аппаратных виртуальных машин с независимой памятью гостевых ОС, контейнеры в Kubernetes исполняются на одном общем ядре хоста. Для оптимизации файлового ввода-вывода операционная система использует page cache — буфер страниц оперативной памяти, в котором удерживаются данные недавно прочитанных или записанных файлов. Этот механизм работает на уровне системных объектов ядра, а не пространств имен контейнеров.

Если на одном узле запущены несколько подов, использующих общий базовый образ (например, Alpine или Debian), их неизменяемые слои OCI физически обслуживаются одними и теми же страницами в page cache. Несмотря на раздельные пространства имен монтирования (mount namespaces), операции чтения бинарных файлов и библиотек из общего слоя адресуются к идентичным физическим страницам оперативной памяти.

Анатомия CVE-2026-31431: сбой в сокетах AF_ALG

Уязвимость Copy Fail обнаружена в интерфейсе криптографических сокетов ядра Linux algif_aead, относящемся к адресному семейству AF_ALG (числовой код — 38). Интерфейс позволяет процессам в пользовательском пространстве обращаться к криптоалгоритмам ядра через стандартный сокетный API.

Дефект проявляется при комбинации операций аутентифицированного шифрования AEAD и системного вызова splice(), перемещающего данные между дескрипторами без копирования в пространство пользователя. Непривилегированный процесс способен через этот интерфейс записать данные непосредственно в страницы кэша памяти файла, открытого исключительно для чтения.

Ключевая особенность: ядро не помечает модифицированные страницы как «грязные» (dirty pages). Файловая система не инициирует сброс измененных байтов на диск, поэтому искажения существуют только в оперативной памяти ядра.

Расхождение памяти и диска: почему слепнут сканеры FIM

Механизм Copy Fail создает расхождение между состоянием накопителя и данными, считываемыми запущенными сервисами:

  • Буферизованное чтение из кэша: Обычные процессы, вызывающие read() или mmap(), получают данные из page cache. Если страница искажена сокетом, процесс читает подмененные байты.
  • Прямой ввод-вывод с диска: При использовании флага O_DIRECT запрос направляется напрямую к блочному устройству в обход кэша, возвращая оригинальное содержимое.
  • Контрольные суммы: Средства мониторинга целостности файлов (FIM) и дисковые сканеры видят исходный хэш SHA-256 и не фиксируют признаков компрометации.

В результате сервис выполняет искаженный код из кэша памяти, тогда как аудиторские утилиты рапортуют о полной неизменности файлов на диске.

Практическое воспроизведение: тесты на Talos и AWS EKS

Воспроизводимость атаки была подтверждена исследователями Juliet Security в двух кластерных окружениях:

  1. Sidero Talos v1.12.2: Иммутабельная ОС с ядром 6.18.5-talos и средой containerd 2.1.6.
  2. AWS EKS на базе Amazon Linux 2023.11: Платформа с ядром 6.12.79-101.147.amzn2023.x86_64 и containerd 2.2.1.

В обоих тестах непривилегированный pod без capabilities под профилями PSS Restricted и RuntimeDefault seccomp успешно создал сокет AF_ALG и привязал алгоритм AEAD. В межконтейнерных тестах pod A изменил байты в файле разделяемого слоя образа, после чего pod B в отдельном пространстве имен на том же узле сразу увидел измененные данные. Монтирование каталогов хоста (hostPath) для атаки не требовалось.

Границы уязвимости: что останавливает PSS Restricted

Уязвимости присвоен рейтинг CVSS 3.1: 7.8 High с вектором AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, что указывает на ее строго локальный характер: атака требует выполнения кода на узле и не может быть проведена удаленно по сети.

В тестах с подменой бинарников с setuid-битом проявились границы защитных механизмов:

  • В подах с флагом allowPrivilegeEscalation: true модификация файла позволила процессу получить права root внутри контейнера.
  • В подах под контролем PSS Restricted параметр allowPrivilegeEscalation: false активирует системный флаг no_new_privs. Ядро заблокировало передачу повышенных привилегий при запуске измененного бинарника.

PSS Restricted успешно предотвращает повышение привилегий внутри пода, однако сам факт повреждения страниц в общем кэше памяти предотвратить не может.

Почему RuntimeDefault seccomp пропускает сокет

Стандартный профиль seccomp RuntimeDefault среды исполнения (containerd, Docker) фильтрует вызовы выборочно. Например, системный вызов socket(AF_VSOCK, ...) (семейство 40) в нем явно заблокирован, но вызов socket(AF_ALG, ...) (семейство 38) разрешен по умолчанию. Проверка наличия RuntimeDefault в конфигурации пода не гарантирует защиту от манипуляций с криптосокетами ядра.

Сравнение уровней защиты в Kubernetes

Уровень изоляцииРеализуемые ограниченияЗащита от CVE-2026-31431
PSS BaselineЗапрещает явные привилегированные флаги и опасные томаУязвим; сокет AF_ALG открывается свободно
PSS RestrictedТребует non-root, no_new_privs и сброс capabilitiesБлокирует root-эскалацию, но пропускает порчу кэша
RuntimeDefault seccompФильтрует опасные системные вызовы среды исполненияПропускает socket(AF_ALG, ...) с кодом семейства 38
Кастомный seccomp (Localhost)Запрещает вызов socket с первым аргументом 38Полностью блокирует создание криптосокета (EPERM)
Обновление ядра LinuxИсправляет логику в подсистеме algif_aeadУстраняет первопричину уязвимости на узле

Компенсирующий контроль: профиль seccomp Localhost

До установки исправлений ядра надежным барьером служит локальный профиль seccomp, возвращающий ошибку EPERM для вызова socket, если его первый аргумент равен 38:

  1. Доставка на узлы: Правила seccomp нельзя встроить в манифест пода. JSON-файл профиля должен быть размещен на каждом узле в каталоге kubelet (/var/lib/kubelet/seccomp/).
  2. Спецификация пода: В блоке безопасности пода задается securityContext.seccompProfile.type: Localhost с путем localhostProfile: profiles/deny-af-alg.json.
  3. Аудит приложений: Сервисы, законно использующие алгоритмы ядра через AF_ALG, потребуют предварительного согласования исключений.

Статус исправлений ядра и дистрибутивы ОС

Окончательное устранение дефекта требует обновления ядра Linux. В upstream-ветках исправление возвращает криптоподсистему к безопасной обработке буферов памяти («Revert to operating out-of-place»).

В дистрибутивах семейства RHEL криптодрайверы ядра могут компилироваться монолитно, поэтому правила blacklist algif_aead в /etc/modprobe.d/ не исключают вектор атаки. Для систем Debian, Ubuntu, SUSE и Amazon Linux требуется установка вендорных пакетов безопасности и последующая перезагрузка узлов.

Чек-лист для платформенных инженеров и SRE

  1. Инвентаризация узлов: Составьте реестр версий ядер и рантаймов. Отделите узлы с внешними или недоверенными сервисами.
  2. Аудит seccomp: Проверьте реальную активность профилей seccomp на хостах и протестируйте поведение вызова AF_ALG на staging.
  3. Плановый rollout нод: Сверьтесь с бюллетенями дистрибутива, подготовьте свежие образы хостов и проведите перезагрузку нод с проверкой версии ядра.
  4. Внедрение seccomp Localhost: На узлах, ожидающих обновления ядра, примените профиль с блокировкой AF_ALG через admission-контроллеры.
  5. Изоляция нагрузок: Разнесите недоверенные контейнеры и критические сервисы по разным группам узлов (node pools) через taints и nodeSelector.
  6. Процедуры расследования: При анализе инцидентов сопоставляйте данные буферизованного чтения с прямым чтением через флаг O_DIRECT.