Killswitch позволяет мгновенно блокировать уязвимые функции ядра
Администраторам крупных Linux-парков предлагают дать аварийный выключатель для уязвимых участков ядра. Разработчик ядра Саша Левин отправил в список рассылки патч Killswitch, который позволяет временно заставить выбранную функцию ядра сразу возвращать заданное значение и не выполнять собственный код. Идея рассчитана на промежуток между публикацией уязвимости и моментом, когда исправленное ядро уже собрано, доставлено на серверы и запущено после перезагрузки.
Механика выглядит грубо, но понятна. Привилегированный администратор записывает команду в /sys/kernel/security/killswitch/control, например для af_alg_sendmsg. После включения Killswitch функция начинает возвращать -EPERM на каждый вызов, а тело функции больше не выполняется. Митигирующая мера вступает в силу сразу и исчезает после перезагрузки, к которой уже желательно поставить нормальный патч ядра.
Левин объясняет замысел практической болью больших инфраструктур. Уязвимость в ядре может стать публичной за часы, а обновление всего парка серверов часто занимает больше времени. При этом многие свежие проблемы появляются в подсистемах, которые нужны не всем установкам, например AF_ALG, ksmbd, nf_tables, vsock или ax25. Для большинства пользователей временная потеря отдельного семейства сокетов или подсистемы может быть менее болезненной, чем работа на заведомо уязвимом ядре.
Killswitch не заменяет livepatch и не подсовывает исправленную реализацию функции. Патч просто ставит перехват через kprobe, записывает нужное возвращаемое значение в регистр и пропускает тело функции. В документации прямо указано, что механизм не проверяет тип возвращаемого значения и не держит список разрешенных функций: если слой kprobe принимает символ, Killswitch пытается включить перехват. Ошибка в выборе функции или возвращаемого значения ляжет на администратора.
Разработчики отдельно прописали главный риск. Нельзя отключать первую попавшуюся функцию только потому, что уязвимость находится где-то рядом. Если функция успевает подготовить данные, взять ссылку, заполнить список страниц или выполнить другой побочный шаг, пропуск тела может сломать вызывающий код сильнее исходной уязвимости. В качестве правильного подхода документация предлагает выбирать высокоуровневую точку входа, похожую на обработчик системного вызова, где ошибка уже означает «операция не выполнена» и нормально возвращается в пользовательское пространство.
Патч также добавляет диагностические следы. После первого успешного включения Killswitch ядро получает новый флаг taint с буквой H, чтобы разработчики при разборе сбоев видели, что работающий образ ядра уже отличался от исходного кода. Для каждой отключенной функции появляются счетчики вызовов, а включение и выключение попадают в журнал ядра вместе с данными оператора. Если модуль с перехваченной функцией выгружается, Killswitch снимает перехват и пишет предупреждение.
Первую версию патча Левин опубликовал 7 мая, а 8 мая отправил вторую редакцию. В v2 разработчик добавил режим LOCKDOWN_KILLSWITCH, изменил работу со счетчиком ссылок и задокументировал причину использования atomic_long_t для возвращаемого значения. Размер изменения вырос до 21 файла и 1513 добавленных строк, так что речь идет не о мелкой правке, а о новой административной возможности ядра.
Пока Killswitch остается предложением для обсуждения, а не готовой функцией Linux. Если идея пройдет ревью, администраторы получат инструмент последнего рубежа: не чинить уязвимый код на лету, а временно отрезать опасный путь выполнения до нормального обновления ядра. Цена такого подхода понятна заранее: часть функциональности может перестать работать, а неверный выбор точки перехвата способен превратить временную защиту в новый источник сбоев.