Уязвимость нашлась не в структуре, а в самой логике системных операций.
На фоне постоянного противостояния между разработчиками ядра Linux и создателями вредоносных модулей, каждая новая версия системы меняет расстановку сил. Свежий пример — руткит-модуль FlipSwitch, который использует необычный способ перехвата системных вызовов в условиях жёстких ограничений, введённых в ядре 6.9. Этот приём основан не на привычной подмене указателей в sys_call_table, а на точечном вмешательстве в машинный код самого ядра — и работает даже после того, как классическая техника стала бесполезной.
Долгое время руткиты вроде Diamorphine или PUMAKIT маскировались, переписывая указатели на системные вызовы в sys_call_table, отключив защиту от записи и подменяя, например, sys_kill на свою вредоносную функцию. Но начиная с версии 6.9 ядра для архитектуры x86‑64, системные вызовы больше не обрабатываются через эту таблицу — вместо неё теперь используется конструкция на основе switch, напрямую вызывающая соответствующие обработчики через жёстко зашитые инструкции. В результате любые изменения sys_call_table больше не влияют на поведение системы, лишая руткиты привычной точки входа.
Однако логика вызова нужных функций при этом никуда не исчезла — она просто была скрыта внутри x64_sys_call. На этом и построена методика FlipSwitch: сначала извлекается адрес оригинальной функции, например sys_kill, через kallsyms_lookup_name, который сам по себе обычно недоступен, но может быть найден косвенно с помощью механизма kprobe. Получив указатель на нужный символ, руткит анализирует байт-код функции x64_sys_call, пока не находит конкретную инструкцию call с сигнатурой 0xe8 и смещением, точно указывающим на нужную цель.
Обнаружив этот вызов, модуль временно отключает защиту памяти, манипулируя 16‑ым битом регистра CR0, что позволяет изменять защищённые участки кода. Затем подменяется всего четыре байта — и вызов переадресуется с оригинального sys_kill на вредоносный аналог, в точности имитирующий легитимную функцию, но с возможностью фильтрации или подмены результатов. При этом остальная часть обработчиков системных вызовов остаётся нетронутой, что делает вмешательство практически незаметным.
Главная особенность FlipSwitch — в его избирательности и аккуратности. Изменения обратимы: при выгрузке модуля всё возвращается в исходное состояние, следов не остаётся. Однако это также означает, что обнаружить такой руткит после его загрузки крайне сложно. Для поиска прототипа FlipSwitch команда Elastic подготовила сигнатуру YARA, способную выявить наличие характерных шаблонов в памяти или на диске.
FlipSwitch стал наглядным примером того, как эволюция системной архитектуры провоцирует разработчиков вредоносных модулей на новые изобретения. Даже отказ от прямого обращения к sys_call_table не смог полностью закрыть лазейки — достаточно точечного вмешательства в нужную инструкцию, чтобы вернуть себе контроль над ядром.