Skip to content
KitploitKITPLOIT
ИнструментыЭксплойтыБлог
Log in
Отправить
ИнструментыЭксплойтыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

ЛентыКонтактыКонфиденциальность© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-31429-POC — POC для CVE-2026-31429 (Linux Kernel >= 6.3 < 6.12.82 Slab Cross-Cache Confusion) - уязвимость обнаружена Antonius - w1sdom - bluedragonsec.com | Kitploit
Инструменты/GitHubGitHub/bluedragonsecurity/cve-2026-31429-poc
Анализ уязвимостейЭксплуатацияОбучение и ОбразованиеЭксплуатация Бинарных Файлов
GitHubbluedragonsecurity/cve-2026-31429-poc

CVE-2026-31429-POC

POC для CVE-2026-31429 (Linux Kernel >= 6.3 < 6.12.82 Slab Cross-Cache Confusion) - уязвимость обнаружена Antonius - w1sdom - bluedragonsec.com

Репозиторий
175 месяцев назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2026-31429 — Linux Kernel: Cross-Cache Free of KFENCE-Allocated SKB Head via bpf_prog_test_run_skb

Severity: Medium (CWE-763: Release of Invalid Pointer or Reference)
Published: 2026-04-20
Affected subsystem: net/core/skbuff.c — skb_kfree_head()
Researcher: Antonius / w1sdom — Blue Dragon Security
Contact: [email protected]
Lore thread: https://lore.kernel.org/netdev/CAK8a0jxC5L5N7hq-DT2_NhUyjBxrPocoiDazzsBk4TGgT1r4-A@mail.gmail.com/


Возможные последствия для безопасности

  • обход механизмов смягчения (mitigation bypass)
  • отключение LSM
  • внедрение руткитов в ядро
  • побег из контейнера
  • отказ в обслуживании

Обзор

Этот репозиторий содержит proof-of-concept для CVE-2026-31429 (не рабочий эксплойт, а только POC) — ошибки cross-cache путаницы slab-кэшей в сетевом стеке ядра Linux. Ошибка срабатывает, когда включён KFENCE и вызывающий код (в частности, bpf_test_init в net/bpf/test_run.c) выделяет SKB head-буфер через kzalloc() с размером, который совпадает с SKB_SMALL_HEAD_CACHE_SIZE. Из-за семантики точного размера, возвращаемого KFENCE, функция ядра skb_kfree_head() некорректно освобождает объект обратно в skb_small_head_cache вместо исходного кэша kmalloc-1k, повреждая метаданные slab.


Затронутые версии

СтатусДиапазон
ЗатронутоLinux >= 6.3 (введено коммитом bf9f1baa279f)
Не затронуто< 6.3
Исправлено>= 6.12.82
Исправлено>= 6.18.23
Исправлено>= 6.19.13
Исправлено>= 7.0 (mainline, коммит 0f42e3f4fe2a)

Уязвимость была введена коммитом bf9f1baa279f ("net: add dedicated kmem_cache for typical/small skb->head"), который добавил skb_small_head_cache и условную логику освобождения в skb_kfree_head().


Анализ первопричины

Предыстория: назначение skb_small_head_cache

SKB_SMALL_HEAD_CACHE_SIZE намеренно установлен в не степень двойки (например, 704 байта на x86_64), чтобы избежать коллизий с типовыми размерами kmalloc-бакетов (всегда степени двойки: 512, 1024, ...). Эвристика в skb_kfree_head() использует эту уникальность для маршрутизации освобождений только по skb_end_offset:

// net/core/skbuff.c (УЯЗВИМО — до исправления)
static void skb_kfree_head(void *head, unsigned int end_offset)
{
    if (end_offset == SKB_SMALL_HEAD_HEADROOM)
        kmem_cache_free(net_hotdata.skb_small_head_cache, head);
    else
        kfree(head);
}
  • end_offset == SKB_SMALL_HEAD_HEADROOM → предполагается из skb_small_head_cache → kmem_cache_free()
  • в противном случае → обычный kfree()

Эта эвристика корректна только при обычной семантике slab, когда ksize() возвращает размер бакета (1024 для запроса в 704 байта), который никогда не равен SKB_SMALL_HEAD_CACHE_SIZE.

Исключение KFENCE

KFENCE (Kernel Electric-Fence) перехватывает часть выделений памяти ядра и обслуживает их из памяти с guard-страницами. Его ключевое поведенческое отличие: kfence_ksize() возвращает точный запрошенный размер, а не размер slab-бакета.

Уязвимая цепочка вызовов

BPF_PROG_TEST_RUN  (syscall 321, cmd BPF_PROG_TEST_RUN=10)
  └─> __sys_bpf()
        └─> bpf_prog_test_run_skb()
              └─> bpf_test_init()
                    └─> kzalloc(size, GFP_USER)
                    │       size == SKB_SMALL_HEAD_CACHE_SIZE (704 на x86_64)
                    │       KFENCE перехватывает → объект обслуживается из области kmalloc-1k
                    │
                    └─> slab_build_skb(data, NULL, size)
                          └─> ksize(data)
                                └─> kfence_ksize()   ← возвращает 704 (точно!)
                          └─> skb_end_offset
                                = ksize(data) - sizeof(skb_shared_info)
                                = 704 - 320
                                = 384
                                = SKB_SMALL_HEAD_HEADROOM  ← ложное совпадение!

  [На пути освобождения SKB:]
  └─> sk_skb_reason_drop()
        └─> skb_release_data()
              └─> skb_free_head()
                    └─> skb_kfree_head(head, skb->end)
                          └─> (end_offset == SKB_SMALL_HEAD_HEADROOM) == TRUE
                                └─> kmem_cache_free(skb_small_head_cache, head)
                                      ↑ ОШИБКА: head из kmalloc-1k, а не из skb_small_head_cache!
                                      → warn_free_bad_obj() → повреждение SLUB

Почему skb_end_offset = 384?

На x86_64:

SKB_SMALL_HEAD_CACHE_SIZE  = 704 байта
sizeof(skb_shared_info)    = 320 байт
SKB_SMALL_HEAD_HEADROOM    = 704 - 320 = 384

Когда KFENCE перехватывает kzalloc() на 704 байта, kfence_ksize() возвращает ровно 704. Арифметика даёт skb_end_offset = 384 = SKB_SMALL_HEAD_HEADROOM, удовлетворяя условию в skb_kfree_head() — срабатывает неверный путь освобождения.

Исправление

Апстрим-исправление от Jiayuan Chen (рецензировано Eric Dumazet, влито Jakub Kicinski) полностью устраняет эвристику:

// net/core/skbuff.c (ИСПРАВЛЕНО)
static void skb_kfree_head(void *head, unsigned int end_offset)
{
    kfree(head);   // всегда обычный; работает для обоих случаев
}

kfree() безопасен как для памяти, выделенной через kmalloc, так и через skb_small_head_cache, поскольку kmem_cache_free() на skb_small_head_cache больше не требуется — обычный kfree() сам определяет нужный кэш через указатель kmem_cache на slab-странице.


Вывод dmesg (доказательство воспроизведения)

Репродуктор (repro_bpf.c) был запущен на Linux 7.0.0-rc5 в окружении QEMU (i440FX, BIOS 1.17.0-debian). Наблюдался следующий каскад предупреждений ядра:

[ 3065.322973] ------------[ cut here ]------------
[ 3065.322990] kmem_cache_free(skbuff_small_head, ffff888186d6e000): object belongs to different cache kmalloc-1k
[ 3065.323005] WARNING: mm/slub.c:6258 at warn_free_bad_obj+0x91/0xc0, CPU#0: repro_bpf/2167
[ 3065.323061] CPU: 0 UID: 0 PID: 2167 Comm: repro_bpf Not tainted 7.0.0-rc5 #1 PREEMPT(lazy)
[ 3065.323098] RIP: 0010:warn_free_bad_obj+0x98/0xc0
...
[ 3065.323231] Call Trace:
[ 3065.323247]  skb_free_head+0x1ec/0x290
[ 3065.323267]  skb_release_data+0x7a6/0x9d0
[ 3065.323308]  bpf_prog_test_run_skb+0x14f8/0x3410
[ 3065.323510]  __sys_bpf+0x769/0x4b60
[ 3065.323763]  __x64_sys_bpf+0x78/0xc0
[ 3065.323794]  do_syscall_64+0x111/0x690
[ 3065.323813]  entry_SYSCALL_64_after_hwframe+0x77/0x7f

Каскад предупреждений даёт 4 отдельных splat-сообщения на каждое срабатывание:

  1. warn_free_bad_obj — первичное обнаружение cross-cache освобождения (mm/slub.c:6258)
  2. depot_fetch_stack — индекс пула stack depot вне границ (lib/stackdepot.c:506) при отслеживании Allocated
  3. stack_depot_print — обнаружен повреждённый handle (lib/stackdepot.c:780)
  4. depot_fetch_stack + stack_depot_print — та же пара повторяется для отслеживания Freed

Этот каскад указывает на то, что метаданные отслеживания SLUB объекта (alloc_track / free_track) ссылаются на handle stack depot, который повреждается после освобождения в неверный кэш.


Репродуктор

Предварительные требования

Kernel:  Linux >= 6.3, скомпилирован с:
           CONFIG_KFENCE=y
           CONFIG_BPF_SYSCALL=y
           CONFIG_NET_SCH_INGRESS=y  (или любой драйвер с поддержкой SCHED_CLS)
           CONFIG_SLUB_DEBUG=y       (для видимости warn_free_bad_obj)
           CONFIG_STACKDEPOT=y       (для полного каскада)

Привилегии: root (uid=0) — требуется для BPF_PROG_LOAD

Сборка

Скачать инструмент