В середине марта исследователи из нескольких университетов в США опубликовали научную работу, в которой продемонстрировали аппаратную уязвимость в процессорах Apple серии M. Apple M — собственная разработка компании на базе архитектуры ARM, используемая в большинстве ноутбуков и настольных ПК, а также в некоторых планшетах iPad. Проблема может быть эксплуатирована для взлома алгоритмов шифрования. Атаку, построенную на базе этой уязвимости, назвали GoFetch.
Сочетание интересной темы с именем известного производителя привело к тому, что совершенно техническая работа была процитирована большим количеством специализированных и не очень изданий, зачастую с алармистскими заголовками типа «не доверяйте ноутбукам Apple свои приватные данные». На самом деле все не так плохо, но чтобы по-настоящему разобраться в сути новой проблемы, нам придется слегка углубиться в теорию работы процессоров, в частности поговорить про три концепции: предварительную выборку данных из оперативной памяти, программирование с постоянным временем и атаку по сторонним каналам. Как обычно, мы постараемся объяснить все максимально простыми словами.
Предварительная выборка данных
Центральный процессор компьютера или ноутбука выполняет программу, которая представлена в виде машинных кодов. Грубо говоря, это набор чисел, часть из которых представляет собой команды, а все остальное — данные для вычислений. На этом самом базовом уровне речь идет о самых простых командах: загрузить из памяти такие-то данные, произвести над ними какие-то вычисления, записать результат обратно в память.
Программу по идее нужно выполнять последовательно. Приведем самый простой пример: пользователь ввел пароль для доступа к криптокошельку. Нужно считать этот пароль из оперативной памяти, произвести над ним определенные вычисления, убедиться, что пароль правильный, и только тогда открыть доступ к секретным данным. Но если бы современные процессоры так выполняли весь код, наши компьютеры работали бы крайне медленно. Как удается ускорить выполнение программ? С помощью большого числа оптимизаций, в числе которых и предварительная загрузка данных.
Концепция предварительной загрузки данных заключается в следующем: если в коде программы будет обнаружена команда на загрузку определенных данных, почему бы во имя ускорения не загрузить их еще до того, как они понадобятся? Если данные в ходе дальнейших вычислений пригодятся — мы выполним программу чуть быстрее. Не пригодятся — не беда, сотрем их из кэш-памяти процессора и загрузим что-то еще.
Так работают самые базовые технологии предварительной выборки данных. В процессорах Apple используется довольно новый метод, известный как «контекстно зависимая предварительная выборка данных» или «data memory-dependent prefetcher» (DMP). Если коротко, DMP работает более агрессивно. Не всегда команды на загрузку данных из памяти доступны явным образом. Указатели на определенную область памяти могут быть результатом вычислений, которые еще нужно произвести. Либо они могут храниться в массиве информации, с которым программа будет работать позднее. DMP пытается угадать, что из данных программы является указателем на область памяти. Логика такая же: если что-то похоже на указатель, пытаемся загрузить информацию по соответствующему адресу. Процесс угадывания использует историю недавних операций, причем они могут относиться к совсем другой программе.
В 2022 году предыдущее исследование показало, что технология DMP достаточно часто путает указатели и какие-то другие данные, с которыми работает программа. Само по себе это проблемой не является: ну загрузили в кэш-память процессора что-то не то, ну бывает. Проблемы появляются, когда речь идет о работе алгоритмов шифрования. DMP может при некоторых условиях сломать концепцию программирования с постоянным временем. Давайте теперь поговорим про нее.
Программирование с постоянным временем
Есть простое правило: время обработки данных не должно зависеть от характера этих данных. В криптографии это один из базовых принципов защиты алгоритма шифрования от атак. Довольно часто потенциальный злоумышленник может взаимодействовать с алгоритмом шифрования. Он подает на вход алгоритма какие-то данные и видит, какой получился результат в зашифрованном виде. Но ему не известен приватный ключ, которым эти данные зашифрованы. Если атакующий узнает этот ключ, он может расшифровать и другую информацию. Например, сохраненные в системе пароли или сетевой трафик.
Если используется достаточно плохой алгоритм шифрования, какие-то данные он будет обрабатывать быстрее, какие-то — медленнее. Это даст злоумышленнику мощный инструмент для взлома: просто наблюдая за временем работы алгоритма, он может реконструировать приватный ключ.
Большинство алгоритмов шифрования защищены от такой атаки: они написаны так, чтобы время вычислений было одинаковым всегда, при любых входящих данных. Проверка надежности алгоритма всегда включает в себя попытки сломать этот принцип. Так произошло, например, в случае атаки Hertzbleed. Но чтобы само похищение стало возможным, необходимо применить атаку по сторонним каналам.
Атака по сторонним каналам
Если механизм предварительной выборки данных DMP иногда принимает обычные данные приложения за указатель на определенную область памяти, означает ли это, что он может принять за указатель кусок приватного ключа? Оказывается, да. Исследователи показали это на практике, используя сразу две популярных библиотеки для шифрования данных. Это Go Crypto, стандартная библиотека для разработчиков ПО на языке Go, и OpenSSL, используемая для шифрования сетевого трафика и многих других задач. Были исследованы разные алгоритмы шифрования, включая повсеместно используемые RSA, Diffie-Hellman, но также и устойчивые к квантовым вычислениям Kyber-512 и Dilithium-2. Пытаясь загрузить что-то по ложному указателю, который на самом деле является куском приватного ключа, технология DMP как бы «выдает» этот ключ злоумышленнику.
Есть одна проблема: кэш-память для нашей теоретической вредоносной программы, необходимой для проведения этой атаки, недоступна. Мы не знаем, что туда загрузил механизм DMP и по какому адресу он обращался к оперативной памяти. Но если атака «в лоб» невозможна, остается возможность вытащить информацию по стороннему каналу. Этот канал утечки обеспечивается простой особенностью любого компьютера: данные, загруженные в кэш-память процессора, обрабатываются быстрее, чем те, что находятся в обычной оперативной памяти.
Собираем атаку в единое целое. У нас есть вредоносная программа, которая может подавать на вход алгоритма шифрования произвольные данные. В процессе работы алгоритма в кэш-память загружаются разные данные, включая секретный ключ шифрования. Алгоритм DMP иногда по ошибке загружает данные по определенному адресу, который на самом деле является куском этого ключа. Атакующий может узнать, что предварительная выборка данных по определенному адресу состоялась, неявным образом, измеряя время доступа к определенным данным. Если данные сохранены в кэш-памяти, обращение к ним произойдет немного быстрее, чем в иных случаях. Именно так исследователи сломали принцип программирования с постоянным временем: мы можем подавать на вход алгоритма произвольный текст и наблюдать, как меняется время выполнения.
Так данные под угрозой или нет?
На практике, чтобы извлечь ключ шифрования, нужно провести десятки и сотни тысяч вычислений, подавая на вход алгоритма данные и наблюдая за состоянием кэш-памяти неявным образом. Это надежная, но очень ресурсозатратная атака: в лучшем случае кража ключа занимает час, в худшем — более десяти часов. Все это время устройство будет практически полностью загружено вычислениями. На сайте проекта GoFetch есть видео с демонстрацией атаки, когда приватный ключ вытаскивается буквально по одному биту.
Но не это делает атаку непрактичной. Мы несколько раз упомянули, что на компьютер потенциальной жертвы должна быть установлена вредоносная программа. Как вы понимаете, если такое случилось, данные уже по определению под угрозой. Добраться до данных наверняка можно куда более простыми методами. Из-за этого разработчики библиотеки OpenSSL даже не стали рассматривать сообщение авторов исследования: подобные атаки не входят в их модель безопасности.
Все подобные исследования можно сравнить с наукой о строительстве зданий. Чтобы конструкция получилась надежной, нужно изучать особенности используемых материалов, характер почвы, предусмотреть опасность землетрясений и многое другое. В большинстве случаев даже плохой, не по науке построенный дом без проблем простоит десятки лет. Но редкое стечение обстоятельств может привести к катастрофе. Чтобы избежать катастрофы с последующей массовой утечкой секретов пользователей, и разрабатываются модели атак, подобные GoFetch.
Исследователи будут продолжать изучать этот довольно новый механизм предварительной выборки данных. Он, кстати, также используется в процессорах Intel, начиная с 13-го поколения, хотя конкретно предложенная в данном исследовании атака на них не работает. Важный момент заключается в том, что исправить эту уязвимость нельзя: в процессорах Apple M1 и M2 она останется на весь срок службы соответствующих устройств. Исключить возможность атаки можно только путем модификации алгоритмов шифрования. Например, можно использовать для расчетов только кластер экономичных процессорных ядер, так как технология DMP работает только на «производительных». Можно обфусцировать ключи шифрования перед загрузкой в оперативную память. Эти методы приведут к падению производительности, но для пользователя оно вряд ли будет заметным. А в процессорах Apple M3 появился специальный флаг, который может отключать оптимизацию DMP для особо конфиденциальных вычислений.
Подведем итог. Прямо сейчас угрозы для данных, хранящихся на устройствах Apple, нет — вряд ли они будут украдены таким сложным способом. Работа американских исследователей тем не менее полезна, так как раскрывает ранее неизвестные особенности работы новейших процессоров. Их усилия направлены на то, чтобы исключить проблемы в будущем, которые могут возникнуть, если будет найден более простой способ эксплуатации подобной уязвимости.