Рубрики
Технологии

Пока-пока, mitigations=off Давно работаю с Linux, но почти…

Пока-пока, mitigations=off

Давно работаю с Linux, но почти в то же время познакомился и с FreeBSD, где make buildworld и make buildkernel — едва ли не местный вариант «Hello, World!». Так что самостоятельная сборка ядра для меня никогда не была чем-то необычным.

Поначалу меня, конечно, больше интересовала производительность.

Но примерно за год до всего этого LLM-индуцированного CVE-безумия, когда я начал активно использовать self-hosted сервисы, мои приоритеты окончательно сместились от производительности к безопасности. Образно говоря, эпоха mitigations=off окончательно канула в Лету. Напротив, приоритетными стали механизмы защиты, уже предусмотренные самими разработчиками ядра, но далеко не всегда включённые по умолчанию.

Я попросил ChatGPT оценить, насколько полезным оказался мой набор настроек применительно к CVE-2026-98432.

Немного о самой уязвимости

В основе CVE лежит race condition при обработке TCP handshake. Ядро сохраняет IPv4 options из входящего SYN в отдельно выделенном участке памяти, на который ссылается ireq->ireq_opt.

При определённом порядке обработки пакетов разными CPU один поток исполнения может продолжать читать эти данные, пока другой уже освободил соответствующую память через kfree().

Получается классический use-after-free (UAF). Если освобождённый участок успел достаться другому объекту, содержимое памяти может оказаться совсем не тем, которое ожидает сетевой стек. Отсюда возможность утечки данных и дальнейшей эксплуатации повреждения памяти.

Закономерно, что мне стало интересно: а насколько мои настройки усложняют эксплуатацию этой ошибки ещё до установки исправления?

Что оказалось включено

CONFIG_RANDOM_KMALLOC_CACHES=y

Пожалуй, самое интересное в данном случае. Обычные kmalloc-выделения распределяются между 16 наборами кэшей. Выбор зависит от адреса вызывающего кода и случайного seed, заданного при загрузке.

Атакующему уже недостаточно подобрать выделение подходящего размера: нужно ещё добиться попадания в тот же slab-кэш, что и уязвимый объект.

Это осложняет heap spraying и целенаправленное повторное использование освобождённой памяти. Впрочем, изоляция не абсолютна: возможны коллизии, а выделения из одного и того же call site обычно попадают в один кэш.

CONFIG_SLAB_FREELIST_RANDOM=y

Рандомизирует порядок свободных объектов при создании новых slab-страниц. Это усложняет предсказание их размещения и последующего повторного использования.

Важно, что речь не о перемешивании при каждом kmalloc() или kfree(). Поэтому влияние на уже подготовленный heap ограничено.

CONFIG_SLAB_FREELIST_HARDENED=y

Добавляет защиту метаданных freelist, затрудняя атаки, в которых повреждение этих метаданных используется для управления последующими выделениями памяти.

Это не защита непосредственно от UAF, но дополнительное препятствие для некоторых вариантов развития атаки после повреждения heap.

slab_nomerge

Запрещает объединение совместимых slab-кэшей. В результате объекты разных специализированных кэшей сложнее разместить в одной области памяти для cross-cache exploitation.

Однако обычные kmalloc-выделения по-прежнему могут совместно использовать generic-кэши. Здесь как раз становится интересным сочетание с CONFIG_RANDOM_KMALLOC_CACHES.

И что в итоге?

Разумеется, ни одна из этих настроек не исправляет саму гонку. Уязвимый код остаётся достижимым, и use-after-free по-прежнему возможен.

Но между «вызвать UAF» и «превратить его в удалённое выполнение кода с правами root» лежит немалый путь. И некоторые из перечисленных механизмов способны существенно осложнить отдельные его этапы.

Насколько всё это помешало бы конкретному эксплойту Anthropic, неизвестно: его код и подробности heap exploitation не опубликованы. Но и считать подобный hardening бесполезным оснований нет. Я бы даже сказал, что при таких раскладах, нужно использовать всё, что можно.