
Эксплойт proof-of-concept для локального повышения привилегий в Linux, эксплуатирующий состояние гонки в таблице скоростей qdisc и использующий групминг кучи BPF и утечку через pipe для получения прав root.

Этот репозиторий содержит proof-of-concept эксплойт для локального повышения привилегий через CVE-2026-68138 — гонку в коде rate-table подсистемы управления трафиком Linux. В протестированном окружении QEMU PoC повышает привилегии от обычного процесса с внешним UID 1000 до шелла с UID 0 в исходном пользовательском пространстве имён.
Предупреждение
Этот код намеренно повреждает состояние кучи ядра. Используйте его только в изолированной одноразовой ВМ, которая принадлежит вам. Пропущенная гонка или преждевременная очистка могут вызвать панику гостевой системы. Не запускайте его на рабочей станции, сервере или в чужой системе.
qdisc_get_rtab() и qdisc_put_rtab() управляют глобальным для процесса односвязным списком qdisc_rtab_list и обычным неатомарным int refcnt. Исторически вызывающий код удерживал мьютекс RTNL, который сериализовал доступ к списку и счётчику ссылок.
Классификатор flower устанавливает TCF_PROTO_OPS_DOIT_UNLOCKED. В результате запрос RTM_NEWTFILTER для правила flower может достичь police-действия и вызвать вспомогательные функции rate-table qdisc без RTNL:
tc_new_tfilter()
-> fl_change()
-> tcf_exts_validate_ex()
-> tcf_action_init()
-> tcf_police_init()
-> qdisc_get_rtab()/qdisc_put_rtab()
Одновременные запросы, использующие одну и ту же rate-table, могут конкурировать за глобальный список и его счётчик ссылок. Результат — use-after-free или double-free объекта struct qdisc_rate_table, 1056-байтовой структуры, выделяемой из kmalloc-2k на протестированном ядре x86-64.
Поскольку список глобальный, а не на каждое сетевое пространство имён, запросы из разных сетевых пространств имён всё равно конкурируют за один и тот же объект.
Запись Linux CNA определяет коммит, вносящий уязвимость: 470502de5bdb, выпущенный в Linux 5.1.
| Ветка | Статус | Коммит/версия |
|---|---|---|
| Linux до 5.1 | Не затронута | Вносящий изменение коммит отсутствует |
| Linux с 5.1 по 7.1.5 | Затронута, если нет вендорного бэкпорта | 470502de5bdb до коммита перед стабильным исправлением |
| Linux 7.1.y | Исправлена | 7.1.6, fb29e1b41052 |
| Серия разработки Linux 7.2 | Затронута до rc5 | rc1 – rc4 |
| Mainline | Исправлена | 7.2-rc5, f43ee0c0730d |
Дистрибутивные ядра часто бэкпортируют исправления, не меняя версию на указанную выше upstream. Проверьте, присутствует ли в точном исходном коде ядра, используемого системой, один из исправляющих коммитов — или эквивалентное изменение со spinlock в rate-table qdisc.
Эксплойт разработан и проверен против уязвимого коммита 92d3817649df2b0b6a008a686c8275c88d7ef594, непосредственного родителя исправления в mainline. В качестве контроля на исправленном ядре использовался f43ee0c0730d6191629b5ee1ceae27b1ebfdc047.
По состоянию на 2026-08-12 поиск по CVE-трекеру Ubuntu не вернул запись об этой CVE. Поэтому таблица ниже — результат непосредственного анализа исходного кода, а не определение статуса безопасности от Canonical. Каждый связанный тег Ubuntu по-прежнему содержит незаблокированный qdisc_rtab_list и не содержит исправляющий qdisc_rtab_lock.
| Линейка Ubuntu | Проверенный пакет/тег | Результат анализа исходного кода |
|---|---|---|
| Ubuntu 22.04 GA | 5.15.0-187.197 | Уязвимый код присутствует; полный эксплойт воспроизведён в QEMU |
| Ubuntu 22.04 HWE | 6.8.0-136.136~22.04.1 | Уязвимый код присутствует; цепочка эксплойта не тестировалась |
| Ubuntu 24.04 HWE | 7.0.0-28.28~24.04.1 | Уязвимый код присутствует; эта цепочка эксплойта несовместима с его усилением аллокатора |
| Ubuntu 26.04 | 7.0.0-28.28 | Уязвимый код присутствует; эта цепочка эксплойта несовместима с его усилением аллокатора |
На дату проверки исправленных пакетов Ubuntu не выявлено. Будущие пакеты Ubuntu следует проверять на наличие бэкпорта, эквивалентного указанным исправлениям upstream, а не оценивать только по номеру версии.
Специфичный для сборки Ubuntu 22.04 эксплойт, лаборатория QEMU, точная контрольная сумма образа и условия описаны в ubuntu/README.md. Он проверен на официальном ядре 5.15.0-187-generic #197-Ubuntu с включённым учётом памяти cgroup.
Лежащая в основе ошибка и эта конкретная цепочка эксплойта имеют разные требования. PoC проверен при следующих условиях:
CONFIG_USER_NS=y и CONFIG_NET_NS=y;CONFIG_NET_CLS=y, CONFIG_NET_CLS_FLOWER=y,
CONFIG_NET_CLS_ACT=y и CONFIG_NET_ACT_POLICE=y;CONFIG_TMPFS_XATTR=y для heap-spray через simple_xattr;CONFIG_MODULES=y и рабочий /sbin/modprobe для финального root-хелпера;CONFIG_MEMCG=n, чтобы размещения qdisc/BPF/pipe/xattr, используемые этой
цепочкой, попадали в ожидаемый кэш kmalloc-2k;CONFIG_SLAB_BUCKETS=y, рандомизация freelist и усиление freelist были включены в успешно протестированном ядре. KASLR не обходится сам по себе с помощью жёстко заданного адреса: PoC получает необходимые указатели на страницу и операции из pipe-утечки. Поставляемая лаборатория использовала nokaslr для упрощения отладки.
Ядра с включённым учётом памяти cgroup или иной компоновкой аллокатора/кэшей требуют другой стратегии переиспользования памяти. PoC намеренно не претендует на переносимость между произвольными конфигурациями дистрибутивов.
Отдельный вариант для Ubuntu реализует эту другую стратегию переиспользования; его требования намеренно уже и перечислены в ubuntu/README.md.
Четыре рабочих потока входят в отдельные сетевые пространства имён и создают flower-фильтры с police-действиями. Три потока идут по пути успешного действия; один передаёт намеренно недопустимый estimator после получения обеих ссылок на rate-table, заставляя выполниться путь очистки. Такая комбинация делает воспроизводимыми одновременные операции со счётчиком ссылок и списком без совместного использования состояния flower-классификатора между потоками.
qdisc_rate_table с помощью классического BPFПосле каждого netlink-запроса тот же самый CPU немедленно прикрепляет классический BPF-фильтр из 133 инструкций. Его массив инструкций размером 1064 байта выделяется из kmalloc-2k и сформирован так, что байты, перекрывающие qdisc_rate_table.next и qdisc_rate_table.refcnt, изначально остаются корректными.