Исследователи из команды V12 (подразделение компании по анализу кода) обнародовали информацию о новой уязвимости в ядре Linux, которая получила кодовое имя PinTheft. Это уже шестая по счёту проблема, позволяющая локальному непривилегированному пользователю получить права root. Атака осуществляется путём перезаписи данных в страничном кэше (page cache) - области оперативной памяти, где ядро хранит содержимое файлов для ускорения доступа к диску.
Детали уязвимости
Главные факты таковы. Уязвимость присутствует в реализации сетевого протокола RDS (Reliable Datagram Sockets - протокол надёжных дейтаграмм для высокоскоростного обмена сообщениями между узлами в кластере). Ошибка кроется в функции "rds_message_zcopy_from_user()", которая отвечает за копирование данных из пользовательского пространства с так называемым нулевым копированием (zerocopy) - механизмом, позволяющим избежать лишнего копирования данных между буферами. При сбое в этой функции не очищается счётчик "rm->data.op_nents", что приводит к двойному освобождению буфера (double-free). Эксплуатируя это состояние, злоумышленник может перезаписать содержимое страничного кэша, а затем заставить ядро выполнить подменённый исполняемый файл, имеющий флаг SUID-root (то есть запускающийся с привилегиями владельца - root).
CVE-идентификатор пока не присвоен, но разработчики уже опубликовали патч: первый вариант появился 5 мая, а 11 мая исправление было принято в ветку "netdev" сетевых драйверов. Тем не менее оно пока не включено в корректирующие выпуски ядра, поэтому подавляющее большинство систем остаётся уязвимым, если в них загружен соответствующий модуль.
Для успешной атаки необходимо выполнение нескольких условий. Во-первых, ядро должно быть собрано с опциями "CONFIG_RDS", "CONFIG_RDS_TCP" и "CONFIG_IO_URING". Во-вторых, в системе не должна быть отключена подсистема "io_uring" (параметр "io_uring_disabled=0"). В-третьих, требуется наличие доступного на чтение исполняемого файла с флагом SUID-root, например "su", "mount", "passwd", "chsh", "newgrp", "umount" или "pkexec". При этом сам протокол RDS используется редко - из распространённых дистрибутивов модуль "rds" по умолчанию включён только в Arch Linux. Для других систем эксплуатация возможна, только если администратор вручную загрузил соответствующий модуль или разрешил его автоматическую загрузку.
Прототип эксплоита (PoC) опубликован в открытом доступе. Он написан для архитектуры x86_64, но, как утверждают авторы, техника атаки не зависит от платформы - достаточно лишь сменить встроенную полезную нагрузку в формате ELF. Сценарий работы включает несколько этапов. Эксплоит сначала находит подходящий SUID-файл и делает его резервную копию. Затем он регистрирует анонимную страницу в качестве фиксированного буфера через интерфейс "io_uring" (асинхронный ввод-вывод, позволяющий эффективно работать с памятью). После этого с помощью серии неудачных отправок данных через RDS злоумышленник похищает ссылки на эту страницу (так называемые FOLL_PIN - закреплённые ссылки в адресном пространстве ядра), освобождает страницу и захватывает её снова, но уже как страничный кэш для выбранного SUID-файла. Когда фиксированный буфер "io_uring" по-прежнему указывает на эту страницу, атакующий записывает туда свой ELF-код через операцию "IORING_OP_READ_FIXED". Файл на диске не изменяется, но при последующем запуске SUID-программы ядро загружает из страничного кэша подменённый код - и вместо утилиты выполняется команда "/usr/bin/sh" с правами root.
С точки зрения экспертизы, эта атака объединяет две известные техники: использование двойного освобождения буфера в сетевом стеке и манипуляцию с фиксированными буферами "io_uring". Ранее аналогичные уязвимости в других компонентах ядра (например, Dirty Pipe) также позволяли перезаписывать страничный кэш, но PinTheft примечателен тем, что атакующему не требуется физический доступ к системе или специальные привилегии - достаточно возможности выполнять локальные команды.
Последствия для бизнеса и пользователей серьёзны, хотя и ограничены кругом потенциально уязвимых конфигураций. Если в организации используются кластеры с RDS (такие как Oracle RAC или некоторые системы высокопроизводительных вычислений), либо администраторы по какой-то причине вручную загрузили модули "rds" и "rds_tcp", локальный злоумышленник может мгновенно получить полный контроль над сервером. В облачных средах и типовых серверных сборках, где эти модули не загружены, риск невелик. Тем не менее, поскольку прототип эксплоита опубликован, уже в ближайшее время могут появиться его адаптации для более широкого круга систем.
Временная защита до обновления ядра заключается в принудительном отключении модулей RDS. Для этого нужно выполнить в терминале команду удаления модулей "rmmod rds_tcp rds" и затем добавить правило блокировки автозагрузки: с помощью команды "printf 'install rds /bin/false\ninstall rds_tcp /bin/false\n' > /etc/modprobe.d/pintheft.conf". После перезагрузки или повторной загрузки модули не будут загружаться, что полностью устраняет вектор атаки. Если же протокол RDS необходим для работы, остаётся ждать выпуска стабильного обновления ядра и оперативно его установить.
Важно отметить, что эта уязвимость не является единственной в своей серии. Ранее были выявлены как минимум пять аналогичных проблем, связанных с перезаписью страничного кэша через различные подсистемы ядра. Разработчики Linux регулярно закрывают подобные дыры, но каждая новая демонстрирует, насколько сложно полностью обезопасить взаимодействие сетевых протоколов, механизмов нулевого копирования и модулей управления памятью.
Ссылки