2 ноября 2021 г.

SiliFuzz: Fuzzing CPUs by proxy

Недавно писал про статью инженеров гугла об аппаратных дефектах микропроцессоров (Cores that don't count) Там констатировалось, что такие дефекты есть, и их не так уж мало – но что с этим делать обсуждалось только гипотетически.

SiliFuzz: Fuzzing CPUs by proxy1 – продолжение этой темы. Авторы задались целью создать механизм непрерывного тестирования парка серверов на аппаратные ошибки. Поскольку заранее неизвестно, какие именно аппаратные ошибки искать, то авторы решили положиться на фаззинг.

Они генерировали сотни тысяч тестов – полу-случайных наборов инструкций. Эти наборы прогонялись на разных процессорах, чтобы получить "правильный" результат их выполнения – таким образом "набор инструкций" превращался в "тест"2, с известным ожидаемым результатом. Дальше с какой-то периодичностью подмножество этих тестов прогоняется на каждом ядре процессора каждой машины из парка серверов. Машины, давшие подозрительные результаты – выводятся на карантин, для дальнейшего разбирательства.

Статья довольно короткая, не буду ее пересказывать. Мне показались интересными 2 вещи: как они генерируют тестовые последовательности инструкций, и что широкое применение таких тестов начинает выглядеть неожиданно вполне реальным и близким.

Как генерируются тесты: black & graybox fuzzing

В основном, тесты генерируются случайно (blackbox fuzzing). Генерируют случайные последовательности инструкций, проверяют их на корректность, и выполняют их многократно, на разных экземплярах всех архитектур процессоров, доступных в Google – чтобы понять, какой должен получиться "правильный" результат.

Результат не всегда однозначен – он может меняться от запуска к запуску, или от модели процессора – но сейчас, для простоты, они не пытаются работать со множественными правильными результатами, а просто отбрасывают последовательности инструкций, которые дают такие неоднозначные результаты.

Но гораздо интереснее, что авторы пытались так же организовать graybox fuzzing: использовать информацию о покрытии (coverage), достигаемом текущими тестами, чтобы направлять генерацию новых тестов – генерировать больше тестов там, где покрытие мало, и меньше там, где покрытие уже хорошее.

Оптимизировать тестовое покрытие выглядит как актуальная задача для фаззинга CPU: процессор штука сложная, умеет делать очень много всего разного. Если генерировать тесты совсем вслепую – легко может оказаться, что большая доля сгенерированных тестов задействует (проверяет) лишь небольшое подмножество блоков процессора – а остальные блоки, и их комбинации, почти не покрыты. При этом тестов много, их исполнение занимает много времени, и создает ложное ощущение надежности.

Как собрать информацию о покрытии электронных схем процессора в ходе выполнения теста? Я не знаю, и авторы тоже не знают, поэтому они использовали трюк, который и дал название статье (fuzzing CPUs by proxy): они нашли программный эмулятор одного из блоков процессора, и предположили, что покрытие эмулятора в ходе "выполнения" теста будет коррелировать с покрытием электронной схемы этого блока при выполнении теста на реальном процессоре.

Подходящий эмулятор-прокси нашелся (пока?) только для блока декодера инструкций3 – а это далеко не весь процессор. Тем не менее, даже это дало эффект: по подсчетам авторов, примерно 40% обнаруженных багов проявили себя только на тестах, сгенерированных с учетом покрытия (graybox fuzzing) – а остальные 60% багов выявляются и на тестах, сгенерированых случайно (blackbox fuzzing).

Авторы считают, что 40% это хороший результат, который демонстрирует перспективность подхода. Если честно – я не очень понял, почему они так считают. Ведь долю багов, выявляемых чисто случайными тестами, можно увеличить – просто сгенерировать больше таких тестов. Почему это менее перспективно?

Да, тесты, которые генерируются на основе анализа покрытия – теоретически более перспективны. Но чтобы эту перспективу реализовать, нужна хорошая информация о покрытии – то есть, в подходе авторов, нужно больше хороших прокси, эмуляторов разных функций/блоков процессора. Насколько вероятно найти такие эмуляторы?

XED, который они используют сейчас, поддерживается Intel – поэтому в хорошем состоянии. Существует ли вообще что-то еще подобного качества и актуальности для других блоков процессора – для арифметики, например? Ведь если таких эмуляторов нет готовых, то создание и доведение их до ума может занять годы. А без таких, "более хороших" прокси их подход останется ограниченным.

Корпус тестов как антивирусная база

Интересно, что генерация и поддержание корпуса тестов естественным образом отвязываются от тестирования парка серверов на этом наборе тестов.

Даже по краткому описанию выше понятно, что создание корпуса тестов с хорошим покрытием – задача довольно сложная, исследовательская. Она требует как инженеров с высокой квалификацией, так и доступа к парку серверов масштаба если не гугла, то хотя бы яндекса – аппаратные ошибки все-таки редки, и нужно много серверов, чтобы убедиться, что корпус тестов вообще способен что-то ловить.

А вот если у вас уже есть корпус тестов, отлаженный ведущими собаководами, то прогонять его периодически на своем парке серверов – задача существенно менее сложная.

Так, авторы уделяют немного места обсуждению инфраструктуры тестирования:

  • весь корпус тестов довольно большой, и его неудобно прогонять в один проход – а значит, нужен планировщик, который будет нарезать корпус на сэмплы, помнить, когда, какие ядра, на какой машине уже прогоняли какие сэмплы, и планировать выполнение очередных сэмплов
  • сами сгенерированные тесты нужно где-то хранить, версионировать, отслеживать их происхождение и КПД

…но это все довольно обычные задачи, знакомые многим разработчикам и инженерам по развертыванию и инфраструктуре во многих компаниях.

Вообще, наиболее близкая аналогия из существующих, которая приходит мне в голову – регулярный запуск антивируса.

Я могу себе представить, что такие корпуса тестов могут стать аналогом нынешних антивирусных баз: их генерацией, оптимизацией, и обновлением занимаются специализированные компании, в тесном сотрудничестве с вендорами железа – а остальные просто ставят себе какой-нибудь Google SiliFuzz (tm), и периодически скачивают обновленные "базы тестирования процессоров" по подписке за (не-)разумные деньги.

В таком виде проверка надежности железа имеет шанс стать мейнстримом довольно быстро: основная сложность-то именно с генерацией тестов, а регулярно прогонять какие-то проверки на своих серверах – это сейчас делает почти каждый, у кого есть хоть сколько-либо приличный парк серверов.

Вот сейчас авторы статьи нагенерировали ~500 000 тестов, которые уже регулярно выявляют сбои в парке серверов гугла. Неизвестно, сколько места занимают эти полмиллиона тестов, но даже если речь идет о десятках гигабайт, то скачать их раз в месяц – совершенно не проблема.

А ведь можно сэкономить еще больше: если из ~500 000 тестов только несколько десятков (сотен) что-то обнаружили на парке машин гугла – значит, именно эти ошибки наиболее вероятно встречаются в процессорах вообще. Значит для какого-нибудь среднего бизнеса более чем достаточно скачать и прогнать на своих машинах только эти несколько десятков/сотен тестов – вообще плевая задача.

Еще весной, когда вышла Cores that don't count, мне казалось, что проверка корректности железа войдет в практику лет, может, через 5-10 – сейчас я уже настроен оптимистично.

Ссылки и примечания

  1. https://arxiv.org/pdf/2110.11519.pdf. В списке авторов только одно общее имя с "Cores that don't count", так что не очень понятно: другая ли это команда, или просто другие люди в рамках той же команды, возглавляемой Peter Hochschild-ом?↩︎

  2. В терминологии авторов такой тест называется "снапшотом".↩︎

  3. Они используют Intel XED – декодер-энкодер инструкций x86 от Интела.↩︎

Комментариев нет:

Отправить комментарий