Мэтью Гаррет (Matthew Garrett), известный разработчик ядра Linux, в своё время получивший от Фонда СПО премию за вклад в развитие свободного ПО, рассказал о сути механизма SBAT (Secure Boot Advanced Targeting), созданного для блокирования уязвимостей в загрузчике без отзыва цифровой подписи, а также о его роли в недавнем инциденте с обновлением для Windows, которое привело к прекращению загрузки Linux, установленных параллельно с Windows на системах с включённым UEFI Secure Boot. Ниже перевод заметки Гаррета:
Когда велась разработка спецификации UEFI Secure Boot, все её участники были, скажем, немного наивны. Основная модель безопасности Secure Boot заключается в том, что весь код, который запускается в привилегированной среде на уровне ядра, должен быть проверен перед выполнением – прошивка проверяет загрузчик, загрузчик проверяет ядро, ядро проверяет любой дополнительный загруженный во время выполнения код ядра, и теперь у нас есть доверенная среда для навязывания любой другой политики безопасности, которую мы хотим. Очевидно, что люди могут оплошать, но в спецификации был предусмотрен способ отзыва подписанных компонентов, которые оказались неблагонадежными: просто добавьте хэш недостоверного кода в переменную, а затем откажитесь загружать что-либо с этим хэшем, даже если оно подписано доверенным ключом.
К сожалению, как выяснилось, проблема в масштабе. Каждый дистрибутив Linux, работающий в экосистеме Secure Boot, генерирует собственные двоичные файлы загрузчика, и у каждого из них свой хэш. Если в исходном коде такого загрузчика обнаружена уязвимость, то необходимо отозвать большое количество различных двоичных файлов. А объем памяти для хранения переменной, содержащей все эти хэши, ограничен. Просто не хватит места, чтобы добавлять новый набор хэшей каждый раз, когда оказывается, что GRUB (загрузчик, изначально написанный во времена, когда не практиковалась защита загрузки, и имеющий несколько отдельных парсеров img-образов, а также парсер шрифтов) имеет ещё один механизм для атакующего, чтобы заставить его выполнить произвольный код, поэтому потребовалось другое решение.
Этим решением стал SBAT. Общая концепция SBAT довольно проста. Каждый важный компонент в цепочке загрузки объявляет поколение безопасности, которое включается в подписанный двоичный файл. Когда уязвимость обнаружена и устранена, это поколение увеличивается. Затем можно выпустить обновление, определяющее минимальное поколение – компоненты загрузки будут смотреть на следующий элемент в цепочке, сравнивать его имя и номер поколения с теми, что хранятся в переменной прошивки, и решать, выполнять его или нет, исходя из этого. Вместо того чтобы отзывать большое количество отдельных хэшей, можно выпустить одно обновление, которое просто говорит: «Любая версия GRUB с поколением безопасности ниже этого номера считается недоверенной».
Почему же это вдруг стало актуальным? SBAT был разработан совместно сообществом Linux и Microsoft, и Microsoft решила выпустить обновление для Windows, которое говорило системам не доверять версиям GRUB с поколением безопасности ниже определённого уровня. Это было сделано потому, что эти версии GRUB имели реальные уязвимости в безопасности, которые позволяли злоумышленникам нарушить цепочку безопасной загрузки Windows, и мы видели реальные примеры вредоносного ПО, которое хотело сделать это (Black Lotus использовал уязвимость в загрузчике Windows, но уязвимость в GRUB была настолько же эффективной). Если смотреть на это чисто с точки зрения безопасности, это вполне законное желание.
Теперь что касается сообщения «Что-то совсем пошло не так» и невозможности загрузки в результате этого обновления. Его выводит shim, а не от какой-то код от Microsoft. Shim учитывает обновления SBAT, и, чтобы не нарушать принципы безопасности, принятые другими загрузчиками в системе, и, хотя и Microsoft выпустила обновление SBAT, именно загрузчик Linux в результате отказывается запускать старые версии GRUB. Все работает так, как и должно.
Проблема, с которой люди столкнулись, заключается в том, что несколько дистрибутивов Linux не выпустили версии GRUB с более новым поколением безопасности, и поэтому эти версии GRUB считаются небезопасными (стоит отметить, что GRUB подписывается самими дистрибутивами, а не Microsoft, поэтому здесь нет никакого привнесённого извне отставания). По замыслу Microsoft, обновление Windows Update должно было применять обновление SBAT только к системам, работающим только с Windows, а любые установки с двойной загрузкой оставались бы уязвимыми для атак до тех пор, пока установленный дистрибутив не обновит GRUB и не обновит поколение SBAT. К сожалению, как теперь очевидно, это не сработало так, как было задумано, и, по крайней мере, некоторые системы с двойной загрузкой применили обновление, а Shim этого дистрибутива отказался загружать GRUB этого дистрибутива.
В чем итог? Microsoft (по понятным причинам) не хотела, чтобы Windows можно было атаковать с помощью уязвимой версии GRUB, которую можно было бы обманом заставить выполнить произвольный код, а затем внедрить буткит в ядро Windows во время загрузки. Microsoft сделала это, выпустив обновление Windows, которое обновило переменную SBAT, указав, что уязвимые версии GRUB не должны загружаться на этих системах. Предоставленный дистрибутивом Shim загрузчик первого этапа считывал эту переменную, считывал раздел SBAT из установленной копии GRUB, понимал, что они конфликтуют, и отказывался загружать grub с сообщением «Что-то совсем пошло не так». Это обновление не должно было применяться к системам с двойной загрузкой, но все равно применялось.
В общем:
1) Microsoft применила обновление к системам, к которым оно не должно было применяться
2) Некоторые дистрибутивы Linux не обновили загрузчик GRUB и поколение безопасности SBAT, когда в GRUB были обнаружены уязвимости.
В результате некоторые люди не могут загрузить свои системы. Я думаю, что здесь есть много виноватых. Microsoft следовало бы провести больше тестов, чтобы убедиться, что установки с двойной загрузкой могут быть точно определены. Но и дистрибутивы, поставляющие подписанные загрузчики, должны убедиться, что они обновляют их и обновляют поколение безопасности, чтобы соответствовать, потому что в противном случае они предоставляют вектор атаки, который может быть использован для взлома других операционных систем, и это своего рода нарушение общественного договора вокруг всего этого.
К сожалению, жертвами здесь становятся в основном конечные пользователи, столкнувшиеся с тем, что система внезапно отказывается загружать ту ОС, которую они хотят загрузить. Этого никогда не должно произойти. Я не думаю, что опрос конечных пользователей касаемо того, хотят ли они обновлений системы безопасной загрузки, приведёт к хорошему результату, и хотя я смутно склоняюсь к тому, что безопасная загрузка UEFI не является чем-то, что приносит пользу большинству конечных пользователей, это также вещь, которую вы не хотите обнаружить после подобных происшествий, поэтому я симпатизирую тому, что она включена по умолчанию, поэтому я поддерживаю включение её по умолчанию, и разделяю выбор Microsoft, за исключением неудачной попытки избежать обновления на системах с двойной загрузкой.
В любом случае, я был сильно вовлечён в реализацию этого механизма для Linux в 2012 году и написал первый прототип Shim (который сейчас является значительно лучшим загрузчиком, поддерживаемым более широким кругом людей, и к которому я не прикасался уже несколько лет), так что если вы хотите обвинить кого-то одного, пожалуйста, не стесняйтесь обвинять меня. Это то, чего не должно было случиться, и если вы не Microsoft или дистрибутив Linux, то это не ваша вина. Прошу прощения.