Комбинаторный ядерный взрыв: что грозит системе инвентаризации уязвимостей CVE в 2024 году
Если вы занимаетесь программированием или, скажем, системным администрированием уже не первый год, то вы наверняка видели аббревиатуру «CVE» в статьях или новостях об информационной безопасности.
База CVE (Common Vulnerabilities and Exposures) — это самая известная и популярная в мире база данных общеизвестных уязвимостей безопасности в ПО. Её поддержкой занимается некоммерческая организация Mitre (обычно её пишут как «MITRE», думая, что это аббревиатура).
Логотип CVE с 2020 года
Номера CVE имеют вид «CVE-2024–1234», где первое число — текущий год, второе — порядковый номер уязвимости. Например, CVE-2024–0225 — довольно серьёзная дырка в браузере Chrome.
Когда я только начинал работать в индустрии в 2006 году, второе число всегда имело четыре знака (номера с недостаточным числом цифр дополнялись слева нулями). Примерно с 2016 года к декабрю регулярно начали появляться дыры с пятизначными номерами. Прошлый год завершился на номере 52431, а в этом году уже имеем уязвимость с номером 25977, хотя всего лишь середина февраля.
Последние дни настают: команда разработчиков ядра Linux позавчера получила статус CVE Number Authority, в результате чего будет назначать номера для уязвимостей ядра самостоятельно.
Начав перечислять, что с этим не так, сложно остановиться. Разработчики ядра в лице, например, Грега Кроа-Хартмана неоднократно публично заявляли, что система CVE им надоела вредит и её нужно упразднить. У них на то были свои объективные причины:
Непонятно, какие баги в контексте ядра считать уязвимостями.
Любое неаккуратное обращение с памятью в ядре потенциально может приводить к какой-нибудь проблеме безопасности в user space-программах. Наличие готового эксплоита не является обязательным для назначения номера CVE.
Как абсолютно закономерно следует из п. 1, систему CVE в отношении ядра Linux активно фармили не очень добросовестные программисты с целью повышения суровости своих резюме.
Сценарий примерно следующий (рассказываю только потому, что теперь это не сработает):
Берёте произвольный патч ядра, исправляющий что-нибудь там с памятью, в идеале use-after-free;
Находите оригинальный коммит, в котором появился этот баг;
Пишете письмо в Mitre с описанием бага, датой его появления, перечислением affected kernel versions, ну и каким-нибудь описанием (пострашнее), как через этот use-after-free могли залутать всю систему (локального повышения привилегий вполне достаточно), ждёте три недели;
PROFIT: теперь вы сертифицированный хакер международного уровня и автор CVE.
В качестве побочного эффекта мы получаем звон во все колокола в различных системах мониторинга уязвимостей, сотни тысяч людей по всему миру срочно обновляют ядра до последней версии, на сайте theregister.com выходят три статьи с анализом печального состояния безопасности в ядре, в общем, красота.
Система CVE очень плохо подходит для трекинга долгосрочных проблем с безопасностью, которые на уровне ядра периодически случаются.
Самый наглядный пример здесь — печально известная CVE-2017–5753 (чтение оперативной памяти через спекулятивное выполнение), также имеющая имя собственное — «Spectre»: её один раз вроде запатчили, второй раз вроде запатчили, потом выяснилось, что надо патчить ещё и ещё. Модель CVE для этого не подходит, в её рамках под каждую новую проблему нужно новый номер открывать.
По факту, публичная система Mitre CVE активно эксплуатировалась отдельными разработчиками ядра Linux для проталкивания своих патчей в их собственные внутренние системы.
Как? А вот так:
Дело тут вот в чём: как мы выяснили в п. 1, примерно любые баги в контексте ядра можно, определённым образом приукрасив, подать как проблемы безопасности. Теперь представьте, что вы разрабатываете модули ядра, числясь в штате какой-нибудь коммерческой компании. Как правило, ваша работа состоит в добавлении поддержки нового оборудования в довольно допотопные стабильные версии ядра.
Как правило, это означает, что вам нужно взять существующий драйвер, но для версии ядра 5.10.34, и запихать его аж в 2.6.32. Между этими двумя версиями (как читатель, вероятно, догадывается) в ядре поменялось много что, и много чего добавилось. К отсутствию какого-нибудь алгоритма A драйвер можно адаптировать за день, к отсутствию модуля B — за две недели, а к отсутствию подсистемы C — и месяца не хватит, а таких драйверов у вас в бэклоге ещё двадцать штук.
Вам бы очень пригодилось, если бы подсистему C из 5.10.34 бэкпортировали в 2.6.32 за вас ваши корпоративные мейнтейнеры ядра в целом. Но вот беда — любой такой бэкпорт они воспринимают в штыки, потому что делаются эти бэкпорты всегда «на живую нитку», регулярно ломают обратную совместимость, ну и вообще — на то ж у нас и стабильная версия, чтобы её кардинально не менять.
Что в этой ситуации делает разработчик? Он находит в нужной ему окрестности ядра какую-нибудь относительно безобидную проблему, далее по вышеописанной схеме получает от Mitre на эту проблему номер CVE, и всё — бэкпорт подсистемы C автоматически получает высокий приоритет у менеджмента, портирование драйверочка тем самым ускоряется в восемь раз.
В качестве побочного эффекта мы получаем звон во все колокола… ну вы поняли.
В конечном счёте, позиция команды разработки ядра по данному вопросу сформировалась следующая:
CVE неудобны;
CVE не нужны!
Уязвимости можно трекать просто хэшами соответствующих коммитов в Git.
Для удобства — брать коммиты исправляющих патчей, потому что идентифицировать исходную проблему одним коммитом бывает не всегда возможно (уязвимость иногда складывается постепенно из каскада разномастных коммитов, а вот чинится всегда одним).
Однако избавиться от Mitre разработчикам ядра никак не удавалось, потому что за долгие годы своего существования система CVE попала в слишком большое количество compliance-документации, и заказчики часто требуют от поставщиков Linux-систем оперативного реагирования на новые номера CVE.
Что ж, с 13 февраля у Кроа-Хартмана сотоварищи появляется реальная возможность подорвать систему не снаружи, а изнутри.
В LKML (Linux kernel mailing list) уже опубликованы принципы, согласно которым будет работать CNA-команда Linux Kernel:
CVE в отношении ядра назначаются только тогда, когда для уязвимости уже есть патч.
Это несколько, мягко говоря, противоречит исходной философии CVE, потому что получается, что если уязвимости уже три года, но по ней всё равно нет патча, то она как бы и не уязвимость всё ещё. В принципе, назначение номеров CVE в прошлом неоднократно успешно использовалось для того, чтобы надавить на вендоров ПО и заставить их выкатить патчи пораньше. С Linux Kernel теперь такой фокус не прокатит.
В принципе, CVE в отношении ядра назначаются только через согласование с самой командой ядра. Не захотят, не назначат.
Где-то в недрах Microsoft, Adobe и Cisco сейчас сидят совершенно ошалевшие менеджеры и дурным голосом орут «а что, так можно было?!»
Но если вы (вдруг) переживаете, что номеров CVE теперь станет меньше, чем раньше, то спешу вас успокоить. CNA-команда издевательски сообщает в своей документации, что будет чрезмерно осторожной («overly cautious») и будет выдавать номера CVE вообще всем багфиксам, которые сочтёт хотя бы теоретически небезопасными.
Багфиксу-то чего ж CVE не назначить! Он же багфикс, кушать не просит.
Нам ещё предстоит увидеть, как будет работать эта система. В пессимистичном сценарии можно ожидать номеров типа CVE-2024–100500 уже к лету, и полноценный патч-менеджмент (по крайней мере, в области ядра Linux) с опорой на CVE перестанет быть возможным. В принципе, вероятно, в этом и цель данного процесса — по факту в принципе избавить ядро от груза в виде CVE.
Система CVE никогда не была идеальной, но, согласитесь, было бы полезно сначала изобрести что-нибудь новое хорошее, и только потом уже убивать старое плохое. Есть серьёзные опасения, что в данном случае процесс пойдёт в строго обратном порядке.