Починка мелкой уязвимости в важной библиотеке Linux вызвала к жизни жуткую «дыру». Под ударом все дистрибутивы

Безопасность Техника Открытое ПО
, Текст: Дмитрий Степанов
Закрытие бреши в одной из важнейших системных библиотек Linux glibc привело к возникновению гораздо более серьезной уязвимости. Она позволяет «уронить» почти любую программу и вызвать ошибку типа «отказ в обслуживании». Повышенный уровень привилегий для этого не нужен.

Опасная уязвимость

Опасная уязвимость была выявлена в важной библиотеке GNU C (glibc), которая присутствует во всех дистрибутивах Linux. С ее помощью можно остановить выполнение практически любой программы. Примечательно, что данная уязвимость появилась в glibc в результате попытки исправить другую, значительно менее серьезную ошибку.

Новая уязвимость, получившая идентификатор CVE-2021-38604, может использована для провоцирования ошибки сегментации (Segmentation fault) в произвольной программе и ее последующего аварийного завершения. На практике это означает, что сервер, работающий под управлением Linux, можно сравнительно легко вывести из строя и лишить клиентов доступа к сервисам. Причем для этого злоумышленнику не понадобится добиваться получения привилегий root (администратора).

CVE-2021-38604 (7,5 баллов из 10 по шкале опасности) была обнаружена специалистом американской компании Cloudlinux Никитой Поповым в ходе анализа бреши CVE-2021-3357 – тоже опасной, однако требующей от злоумышленника значительно больших усилий для ее эксплуатации. Последняя присутствовала в glibc версий 2.32 и 2.33, а к версии 2.34 была исправлена, породив позднее обнаруженную Поповым «дыру».

Glibc – это свободная реализация стандартной библиотеки языка программирования C. Она создана при поддержке Фонда свободного ПО (Free Software Foundation) и содержит ключевые функции, используемые ПО, написанным на языках C и C++. Glibc так или иначе используется большинством программ, предназначенных для запуска в ОС семейства Linux, в том числе различных компиляторов и интерпретаторов других языков. Glibc можно назвать вторым по важности компонентом любой ОС семейства Linux после ядра.

Cloudlinux развивает собственную коммерческую операционную систему Cloudlinux OS для хостинг-провайдеров, а с января 2021 г. – Almalinux, позиционируемую как замену CentOS.

Корни проблемы

Обе упомянутые ошибки фигурируют в файле sysdeps/unix/sysv/linux/mq_notify.c, в котором реализована системная функция mq_notify(), являющаяся частью программного интерфейса (API) для работы с очередью сообщений POSIX в glibc.

Механизм очереди сообщений обеспечивает обмен данными между различными процессами (программами или потоками) в реальном времени в операционных системах, отвечающих стандарту POSIX, в том числе и в ОС семейства Linux.

Функция mq_notify() позволяет зарегистрироваться для получения асинхронных уведомлений о появлении в очереди новых сообщений. Ошибки, которые привели к образованию уязвимостей связаны с некорректным управлением динамической памятью внутри данной функции.

Проблемный патч, содержащий исправления, которые только усугубили ситуацию

Так, более ранняя из них в теории позволяет злоумышленнику добиться обращения к участку памяти после его освобождения, что может приводить к непредсказуемым последствиям, но, чаще всего – к «падению» программы. Однако на практике, по мнению главного инженера-программиста Red Hat Сиддхеша Поярекара (Siddhesh Poyarekar), это едва ли возможно – ни в одном из известных дистрибутивов Linux просто нет программ, которые подходили бы для эксплуатации данной уязвимости.

Тем не менее, это не означает, что проблему не нужно было решать. Для этого в код была добавлена по сути одна строка, которая включает обращение к функции удаления дескриптора потока (pthread_attr_destroy). Она принимает единственный аргумент – указатель на объект атрибутов потока, который определяет поведение создаваемого потока.

Если в качестве аргумента передать нулевой указатель (NULL), то есть не связанный с каким-либо объектом в памяти, это приводит к ошибке разыменовывания нулевого указателя, которая, в свою, очередь ведет к неопределенному поведению процесса – в большинстве случаев к его краху. Таким образом, чтобы «уронить» программу, использующую glibc 2.34, достаточно добиться передачи NULL в качестве аргумента pthread_attr_destroy().

Как выяснил Никита Попов, такой аргумент данная функция в реализации mq_notify() получит, если приложение попытается породить поток с атрибутами по умолчанию средствами библиотеки. То есть совершить атаку с использованием более «свежей» уязвимости значительно проще.

Исправление уже доступно

К счастью, для большинства администраторов ошибка, найденная Поповым, не успела добраться до популярных дистрибутивов, так как релиз glibc 2.34 состоялся сравнительно недавно – 1 августа 2021 г.

Исправление, состоящее из дополнительной проверки аргумента на соответствие нулевому указателю, уже включено в основную ветку glibc.

Ранее Киc Кук (Kees Cook), сотрудник Google и разработчик ядра Linux, заявил, что нужно срочно увеличить количество программистов, которые будут трудиться над улучшением безопасности ядра. Сил нынешнего штата не хватает, они не успевают обрабатывать все исправления, и в результате пока одна уязвимость устраняется сразу, другая может оставаться в коде годами. Также он предложил отказаться от языка С, назвав его небезопасным, и переписать ядро на Rust.