20 часов назад
Dirty Frag: как работает свежий Linux LPE

Универсальный LPE на актуальных ядрах Linux: один бинарь поднимает root на Ubuntu 24.04, RHEL 10.1, AlmaLinux 10, Fedora 44, openSUSE Tumbleweed. CVE пока нет, PoC лежит в открытом репозитории. Разбираем механику, объясняем, почему это не «ещё один Dirty Pipe», и даём чеклист действий для системных администраторов.
Контекст
7 мая 2026 года Hyunwoo Kim (@v4bel) опубликовал цельный write-up и рабочий PoC уязвимости, которую он назвал Dirty Frag. Это локальное повышение привилегий (LPE) до root, которое работает на всех мажорных дистрибутивах с актуальными ядрами – от 6.12 до 7.0.
29 апреля – автор отправляет отчёт по RxRPC-варианту в
security@kernel.orgи патч в netdev.30 апреля – туда же уходит ESP-вариант. Данные по обеим уязвимостям появляется в публичных рассылках kernel-сообщества.
7 мая – Kim отправляет детали и эксплойт в
linux-distros@vs.openwall.orgс эмбарго на 5 дней. Условие стандартное: если кто-то третий публикует PoC до окончания эмбарго – автор сразу выкатывает свою версию.7 мая (через некоторое количество часов) – неизвестная сторона публикует эксплойт ESP-варианта. По обсуждению в LWN и Hacker News видно, что параллельно некоторое количество человек самостоятельно разработали PoC по уже опубликованному в netdev патчу – формально эмбарго не нарушали, но результат тот же.
7 мая (вечером) – по согласованию с мейнтейнерами дистрибутивов автор публикует цельный документ с PoC на GitHub.
Что мы имеем на руках:
CVE не назначено ни одной из двух уязвимостей цепочки.
Патч ESP-варианта уже в netdev (смержен 7 мая), патч RxRPC – пока только в LKML.
В дистрибутивах патчи в работе: AlmaLinux уже выкатил тестовые ядра, CloudLinux готовит KernelCare livepatch. Остальные – в режиме «ждём бэкпорта».
Жизненный цикл бага: ESP-вариант существует с коммита
cac2661c53f3(январь 2017), RxRPC – с2dc334f1a63a(июнь 2023). Приблизительно 9 лет на ESP-стороне.
Механика уязвимости
Dirty Frag – это не одна, а две независимые уязвимости одного класса, объединённые в совокупный exploit chain. Класс – тот же, что у Dirty Pipe и Copy Fail: запись в page cache файлов, к которым у атакующего есть только read-доступ. Только Dirty Pipe «грязнил» struct pipe_buffer, а Dirty Frag «грязнит» frag в struct sk_buff.
Общая идея
Атакующий через splice(file -> pipe -> socket) с MSG_SPLICE_PAGES подсаживает в frag отправляющего skb прямую ссылку на страницу page cache, в частности, страницу /usr/bin/su или /etc/passwd. Этот же skb проходит через loopback и попадает в receiving-путь ядра, где криптокод выполняет in-place crypto прямо поверх этой страницы. AEAD-проверка падает с ошибкой, но 4–8 байт в page cache уже изменены – и сохраняются до перезагрузки или drop_caches.
Вариант 1: xfrm-ESP Page-Cache Write
Точка входа – esp_input() в net/ipv4/esp4.c и net/ipv6/esp6.c. Перед in-place AEAD-расшифровкой нелинейного skb код должен позвать skb_cow_data() и скопировать информация frag в закрытый буфер. Но в исходном коде есть ветка, которая пропускает COW:
cif (!skb_cloned(skb)) { if (!skb_is_nonlinear(skb)) { nfrags = 1; goto skip_cow; } else if (!skb_has_frag_list(skb)) { nfrags = skb_shinfo(skb)->nr_frags; nfrags++; goto skip_cow; // вот сюда улетает skb с подставленной страницей } }
if (!skb_cloned(skb)) { if (!skb_is_nonlinear(skb)) { nfrags = 1; goto skip_cow; } else if (!skb_has_frag_list(skb)) { nfrags = skb_shinfo(skb)->nr_frags; nfrags++; goto skip_cow; // вот сюда улетает skb с подставленной страницей } }
Дальше при комбинации ESP + ESN + authencesn(hmac(sha256), cbc(aes)) функция crypto_authenc_esn_decrypt() в контексте перестановки байт seqno делает 4-байтный STORE по адресу assoclen + cryptlen в dst SGL:
cscatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
Атакующий контролирует и адрес, и значение этих 4 байт:
Адрес – через выбор длины payload (точно подгоняется так, чтобы попасть в необходимый file offset страницы P).
Значение – это
seq_hiизXFRMA_REPLAY_ESN_VAL, который пользователь сам выставляет при регистрации SA через netlink.
То есть это arbitrary 4-byte STORE primitive в page cache. AEAD-проверка после STORE возвращает -EBADMSG, но модификация уже сделано.
Цена входа: для регистрации XFRM SA нужен CAP_NET_ADMIN, следовательно эксплойт делает unshare(CLONE_NEWUSER | CLONE_NEWNET). На дистрибутивах, где разрешено разработка непривилегированных user namespace, всё работает.
Вариант 2: RxRPC Page-Cache Write
Точка входа – rxkad_verify_packet_1() в net/rxrpc/rxkad.c. На уровне RXRPC_SECURITY_AUTH ядро делает in-place pcbc(fcrypt) decrypt первых 8 байт payload skb:
cret = skb_to_sgvec(skb, sg, sp->offset, 8); memset(&iv, 0, sizeof(iv)); skcipher_request_set_crypt(req, sg, sg, 8, iv.x); // src == dst, in-place ret = crypto_skcipher_decrypt(req);
ret = skb_to_sgvec(skb, sg, sp->offset, 8); memset(&iv, 0, sizeof(iv)); skcipher_request_set_crypt(req, sg, sg, 8, iv.x); // src == dst, in-place ret = crypto_skcipher_decrypt(req);
Проверка перед этим – только skb_cloned(skb), но не skb->data_len, следовательно нелинейный skb с подсаженной страницей в frag проскакивает.
Тут есть нюанс: STORE-значение – это не произвольные байты, а результат fcrypt_decrypt(C, K), где C – уже лежащий по этому смещению ciphertext, а K – сессионный ключ из RxRPC v1 token (его атакующий сам кладёт через add_key("rxrpc", ...), без каких-либо привилегий).
fcrypt – это AFS-cipher с 56-битным ключом и блоком 8 байт. Детерминированная опция, легко портируется в user-space. Эксплойт перебирает K локально (~18 M ключей/сек) до тех пор, пока fcrypt_decrypt(C, K) не выдаст нужный паттерн plaintext. Полные 8 байт перебрать нереально (~2⁵⁶), но если фиксировать только 2–3 ключевых байта – подбор укладывается в миллисекунды.
Цель – не перезаписать всё /etc/passwd, а превратить первую строку в:
textroot::0:0:GGGGGG:/root:/bin/bash
root::0:0:GGGGGG:/root:/bin/bash
Пустое поле пароля + pam_unix.so nullok в PAM common-auth = su - без запроса пароля. Дальше – setresuid(0,0,0) и /bin/bash от root.
Главное: никаких namespace, никакого CAP_*. Только add_key(), socket(AF_RXRPC), splice(), recvmsg() – всё доступно обычному непривилегированному пользователю.
Почему это не Dirty Pipe-2
Dirty Pipe был race-condition-free, но опирался на специфическое состояние struct pipe_buffer – нужно было «протолкнуть» нужные флаги через splice. Dirty Frag устроен ещё прямолинейнее: in-place crypto по определению пишет в dst, а dst – это страница page cache, на которую у атакующего read-only доступ.
Не нужен timing window. Между splice и crypto-STORE нет конкурентного события, которое надо успеть.
Не нужен race. Логика детерминированная: подсадили страницу – она прошла до sink – STORE гарантирован.
Ядро не паникует при неудаче. AEAD/HMAC возвращает ошибку, skb просто дропается, никаких BUG/oops.
Высокий success rate. На тестовых стендах – фактически 100%.
Чем это отличается от Dirty Pipe и Copy Fail
Параметр | Dirty Pipe (CVE-2022-0847) | Copy Fail (CVE-2026-31431) | Dirty Frag (CVE pending) |
|---|---|---|---|
Объект записи |
| TX SGL поверх page cache |
|
Sink |
|
|
|
Triggering subsystem | pipe + splice | AF_ALG ( | xfrm/IPsec ESP + RxRPC |
Race condition | Нет | Нет | Нет |
Размер примитива | произвольная запись | 4 байта | 4 байта (ESP) / 8 байт (RxRPC) |
Привилегии | непривилегированный user | непривилегированный user (если algif_aead доступен) |
|
Workaround | патч ядра | blacklist | blacklist |
Mitigation Copy Fail помогает? | – | – | Нет, обходится |
Affected ядра | 5.8+ | актуальные | ESP: с 4.10 (2017), RxRPC: с 6.5 (2023) |
CVE | назначено | назначено | не назначено |
Основной вывод из таблицы – публично известный workaround Copy Fail (algif_aead blacklist) не защищает от Dirty Frag. Это уже отдельный sink, через иной crypto-путь.
Кого это реально касается
К счастью не все среды одинаково уязвимы.
Высокий риск
Shared hosting и VPS-провайдеры. Любой заказчик с обычной shell-сессией поднимается до root на хост-ноде, если применима cgroup-политика без user namespace lockdown. Для CloudLinux уже отдельный пост с готовым livepatch.
Kubernetes worker nodes. Контейнер с
hostPID: falseи стандартным seccomp всё равно даёт доступ кadd_key(),socket(AF_RXRPC),splice(). RxRPC-вариант здесь работает «из коробки» на Ubuntu-нодах, где компонент грузится по умолчанию. ESP-вариант – на нодах сkernel.unprivileged_userns_clone=1.CI/CD runners (GitLab Runner, GitHub Actions self-hosted, Jenkins agents). Любой PR от внешнего контрибьютора в публичном репозитории = выполнение произвольного кода в runner-окружении. Если runner общий между проектами – компрометация одного проекта = компрометация всех.
Multi-tenant sandbox-окружения: code playgrounds, ML-тренажёры, песочницы для статей и обучения.
Средний риск
Серверы с локальными непривилегированными пользователями. Корпоративные jump-hosts, dev-боксы, build-серверы. Если у пользователя есть SSH – у него есть root.
Контейнерные среды без user namespace lockdown. Docker без
userns-remap, podman в rootfull-режиме на Ubuntu.
Пониженный риск
Десктопы с одним пользователем. Без локального доступа постороннего эксплойт не запустить.
Single-purpose серверы и сетевые аплайансы. Об этом подробнее ниже.
Наш продукт Ideco NGFW
Уязвим ли Ideco NGFW?
Технически ядро Linux, на котором работает Ideco NGFW, относится к классу затронутых. Но реальный attack surface для Dirty Frag на NGFW принципиально другой:
На Ideco NGFW нет shell-сессий обычных пользователей. Управление – через web-консоль и SSH под выделенными аккаунтами администраторов, без
splice/add_key-сценариев.Нет CI/CD-нагрузок, нет компиляции произвольного кода, нет multi-tenant изоляции внутри аплайанса.
Trigger-вектор Dirty Frag требует локального исполнения произвольного бинаря под непривилегированным пользователем. На правильно сконфигурированном NGFW такой возможности у внешнего атакующего просто нет – нужен сначала RCE из сети, а это уже другая категория угрозы.
То есть для Dirty Frag на NGFW справедлив принцип «не первая дверь, которую можно сломать». Тем не менее, мы готовим обновление с патчем netdev сразу, как только апстрим стабилизируется и пройдёт регрессионное тестирование.
Что создавать прямо сейчас
Минимальный чеклист для системного администратора Linux. Порядок шагов важен.
1. Проверить, загружены ли уязвимые модули
bashlsmod | grep -E '^(esp4|esp6|rxrpc) '
lsmod | grep -E '^(esp4|esp6|rxrpc) '
Если ничего не выводится – модули не загружены, риск минимальный (но не нулевой: модули могут подгружаться автоматически по запросу через MODULE_ALIAS_NETPROTO).
2. Оценить, нужны ли модули в проде
esp4/esp6нужны, если есть IPsec (strongSwan, libreswan, racoon, FRR с IPsec-туннелями, любые kernel-mode VPN).rxrpcнужен только при использовании AFS (Andrew File System) – на 99% серверов не используется, особенно на Ubuntu, где он грузится по умолчанию «на всякий случай».WireGuard, OpenVPN, Tailscale, Nebula, GRE – не используют ни esp4/esp6, ни rxrpc. На них не повлияет blacklist модулей esp.
3. Применить workaround там, где это безопасно
Для серверов без IPsec:
bashsudo sh -c "printf 'install esp4 /bin/false\ninstall esp6 /bin/false\ninstall rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag.conf; rmmod esp4 esp6 rxrpc 2>/dev/null; true" sudo sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
sudo sh -c "printf 'install esp4 /bin/false\ninstall esp6 /bin/false\ninstall rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag.conf; rmmod esp4 esp6 rxrpc 2>/dev/null; true" sudo sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
Для серверов с IPsec – blacklist'ить только rxrpc:
bashsudo sh -c "printf 'install rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag-rxrpc.conf; rmmod rxrpc 2>/dev/null; true"
sudo sh -c "printf 'install rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag-rxrpc.conf; rmmod rxrpc 2>/dev/null; true"
Это закрывает один из двух векторов цепочки на Ubuntu (где rxrpc загружается по умолчанию даже без AFS). ESP-вариант остаётся открытым до выхода патча от вендора, но требует возможности создания user namespace.
4. Закрыть user namespace там, где они не нужны
На Ubuntu/Debian:
bashsudo sysctl -w kernel.unprivileged_userns_clone=0 echo 'kernel.unprivileged_userns_clone = 0' | sudo tee /etc/sysctl.d/99-no-userns.conf
sudo sysctl -w kernel.unprivileged_userns_clone=0 echo 'kernel.unprivileged_userns_clone = 0' | sudo tee /etc/sysctl.d/99-no-userns.conf
На RHEL/Alma/Rocky/Fedora:
bashsudo sysctl -w user.max_user_namespaces=0 echo 'user.max_user_namespaces = 0' | sudo tee /etc/sysctl.d/99-no-userns.conf
sudo sysctl -w user.max_user_namespaces=0 echo 'user.max_user_namespaces = 0' | sudo tee /etc/sysctl.d/99-no-userns.conf
Учтите, что это сломает rootless Docker/Podman, Firefox sandbox в некоторых конфигурациях, и часть инструментов вроде bwrap/flatpak. Применять там, где это допустимо.
5. Подписаться на security-уведомления и обновиться, как только выйдет патч
Ubuntu – USN-канал, пока тикета нет, но он появится.
Debian – DSA.
RHEL/Alma/Rocky – AlmaLinux уже выкатил тестовые ядра.
CloudLinux – KernelCare livepatch в работе.
SUSE/openSUSE – тикет в работе, апдейт ожидается на этой неделе.
После накатки патча проверить отсутствие SKBFL_SHARED_FRAG-обхода:
bashzgrep -E 'SKBFL_SHARED_FRAG|skb_has_shared_frag' /proc/config.gz 2>/dev/null # или, если /proc/config.gz нет: modinfo esp4 | grep -i version
zgrep -E 'SKBFL_SHARED_FRAG|skb_has_shared_frag' /proc/config.gz 2>/dev/null # или, если /proc/config.gz нет: modinfo esp4 | grep -i version
И отдельно – проверка следов компрометации. Если на сервере уже запускался PoC, в page cache могут оставаться модифицированные копии /usr/bin/su и /etc/passwd. Грубая проверка:
bash# Сравнить хеш файла на диске и через cat (page cache) sha256sum /usr/bin/su cat /usr/bin/su | sha256sum diff <(getent passwd root) <(grep '^root:' /etc/passwd)
# Сравнить хеш файла на диске и через cat (page cache) sha256sum /usr/bin/su cat /usr/bin/su | sha256sum diff <(getent passwd root) <(grep '^root:' /etc/passwd)
При расхождении – echo 3 > /proc/sys/vm/drop_caches и обязательная перезагрузка с проверкой целостности через rpm -V / dpkg --verify / debsums. Если расхождение остаётся после этого – исходим из факта компрометации хоста.
Итог
Dirty Frag – пример того, что класс «in-place crypto over splice'd page» оказался шире, чем казалось после Copy Fail. Локальное повышение привилегий до root на всех мажорных дистрибутивах через детерминированный баг без race condition, без CVE, с публичным PoC и без готовых патчей в большинстве дистрибутивов – это серьезная задача безопасности.
Мы в Ideco следим за этой историей с момента появления первой публикации в netdev 30 апреля. Мы уже включили в план ближайших минорных релизов выпуска патчей для поддерживаемых версий – как только апстрим стабилизирует фикс.
Похоже, что ближайшие месяцы принесут ещё некоторое количество уязвимостей этого класса – в других подсистемах, где тоже есть splice → in-place transform → STORE.
Читают сейчас

2 минуты назад
Выпуск менеджера файлов Total Commander 11.57
7 мая 2026 года состоялся релиз менеджера файлов Total Commander 11.57 со встроенным FTP‑клиентом с FXP, анализатором дискового пространства, синхронизатором файлов, поддержкой работы с архивами (ZIP,

6 часов назад
DeepSeek V4 силен только в «своих» бенчмарках. На независимых — отстает на 8 месяцев
После анонса DeepSeek V4 Pro, в котором компания заявила об отставании от фронтира США всего на 3–6 месяцев, NIST — американский институт стандартов при Министерстве торговли — провел собственные заме

10 часов назад
От сервиса к партнерству: как пересобрать архитектуру продуктовой аналитики
Часто системная проблема продуктовой аналитики кроется не в слабых хард-скилах команды, а в сломанной архитектуре самой роли и границах ответственности. Когда аналитики работают в режиме внутреннего h

10 часов назад
Starlink достиг медианной скорости загрузки в 100 Мбит/с в 49 штатах из 50, кроме Аляски — Ookla Speedtest
Starlink достиг медианной скорости загрузки более чем 100 Мбит/с в 49 из 50 штатов — кроме Аляски, где показатель составил 87,6 Мбит/с, говорится в отчёте Ookla Speedtest за второе полугодие 2025 года

11 часов назад
Европейские регуляторы оштрафовали «дочку» «Яндекса» — оператора Yango — на €100 млн за утечку данных в Россию
Нидерландский регулятор по защите данных оштрафовал местную «дочку» «Яндекса» MLU B.V. — оператора приложения Yango — на €100 млн. По оценке ведомства, данные клиентов и водителей Yango хранились в Ро