David Chisnall считает, что самая сложная задача изоляции программного обеспечения заключается не в полном разделении двух нагрузок, а в изоляции компонентов, которым необходимо взаимодействовать и совместно использовать данные. В докладе, опубликованном через InfoQ, Chisnall объясняет, как архитектура CHERI объединяет концепции защищённых возможностей и расширенных указателей, обеспечивая аппаратную защиту указателей, безопасность памяти и точную изоляцию в пределах одного адресного пространства.
Chisnall является соучредителем и директором по системной инженерии в SCI Semiconductor, а также приглашённым исследователем Кембриджского университета. Доклад опирается на исследовательские работы по CHERI и их программные и аппаратные реализации — от CheriBSD и расширений ARM Morello до CHERIoT, предназначенной для микроконтроллеров, — а также на набор инструкций RISC-V под названием RVY, стандартизация которого, по его словам, находилась на завершающих этапах.
Указатель становится аппаратно защищённой сущностью
CHERI не представляет собой отдельный набор инструкций в традиционном смысле, а объединяет идеи, которые можно адаптировать к различным архитектурам, подобно тому как концепции SIMD реализуются в нескольких расширениях. Согласно этой концепции, указатель перестаёт быть просто числом, представляющим адрес в памяти, и становится возможностью, содержащей адрес, границы объекта и набор разрешений, а также аппаратный тег, определяющий, является ли значение действительным указателем.
Эти возможности обладают однонаправленными свойствами: границы можно сузить или разрешения можно удалить, но расширить их или восстановить из самого указателя нельзя. Аппаратное обеспечение также проверяет, что указатель действителен и имеет тег, прежде чем использовать его в операциях загрузки, сохранения или перехода. Если программа пытается использовать значение, с которым обращались как с данными или которое изменили для получения адреса, операция завершается ошибкой, вместо того чтобы автоматически преобразовать его в пригодный для использования указатель.
Такая конструкция, согласно докладу, обеспечивает прямую защиту от ряда распространённых этапов атак на память, например от перезаписи указателя значением, контролируемым злоумышленником. Она также позволяет выполнять универсальные операции, такие как memcpy, без предварительного знания расположения указателей, поскольку тег указателя перемещается вместе со значением или удаляется при перезаписи части пространства возможностей.
Границы и разрешения, которые можно сокращать
Возможности CHERI включают разрешения на чтение и запись, а также отдельные разрешения на работу с указателями, содержащимися внутри данных. Chisnall объясняет, что такая точность позволяет, например, предоставить программе разрешение на чтение данных внутри сложной структуры, не предоставляя ей возможности сохранять в ней новые указатели. Таким образом можно обеспечить представление только для чтения, распространяющееся на всё дерево данных, вместо поверхностной защиты одного объекта.
Механизм sealing также позволяет создавать безопасные непрозрачные указатели, подобные дескрипторам или файловым описателям, но без обязательной необходимости в таблице преобразований, управляемой ядром. Возможность запечатывается с использованием кода типа, поэтому во время запечатывания её нельзя изменить, разыменовать или использовать для перехода, загрузки и сохранения. При возврате владельцу возможность можно распечатать только в том случае, если код типа совпадает.
Пространственная и временная безопасность памяти
При ошибках выхода за границы CHERI может преобразовать неопределённое поведение в языке C в детерминированную аппаратную остановку. Chisnall приводит пример массива из 14 элементов, при обращении к элементу 14 которого в традиционной системе существует вероятность перезаписи адреса возврата, тогда как в системе CHERI операция перехватывается, поскольку указатель ограничен границами массива.
Предложение не ограничивается пространственной безопасностью. В CHERIoT используются теги указателей и теневая память, содержащая по одному биту на единицу выделения, благодаря чему можно аннулировать указатели, связанные с освобождённой памятью. При загрузке возможности в регистр фильтр загрузки может проверить состояние блока и стереть тег, если память освобождена. Аппаратный периодический механизм также проверяет память и удаляет теги указателей, ссылающихся на объекты, которые больше не являются живыми, что позволяет повторно использовать память после завершения цикла аннулирования.
От безопасности памяти к точной изоляции
Первоначальная цель проекта CHERI, по словам Chisnall, заключалась в создании точной изоляции, выходящей за пределы традиционной изоляции процессов. Изоляция каждого компонента в отдельном процессе требует затрат, связанных с таблицами страниц, механизмами RPC, сериализацией и копированием данных. Это может быть приемлемо для десятков изолированных доменов, но становится менее подходящим, когда браузерам, например, требуется запускать тысячи или десятки тысяч песочниц для таких компонентов, как декодирование изображений и звука или выполнение JavaScript JIT.
Модель CHERI позволяет рассматривать набор памяти, доступной из возможностей, находящихся в регистрах выполнения, как домен защиты. Два домена в одном адресном пространстве могут совместно использовать некоторые данные, сохраняя изоляцию остальных частей, поскольку совместное использование начинается с определённых возможностей и может распространяться на сложные структуры данных и всё, что доступно через них.
В более крупных системах доклад объясняет поэтапный путь через вызов coexecve, который создаёт новый процесс без создания нового адресного пространства, а затем устанавливает набор корневых возможностей, определяющих, к чему новый процесс может получить доступ. CHERIoT, напротив, использует строгое разделение разрешений в рамках операционной системы реального времени, с компонентом переключения, отвечающим за переключение контекста и вызовы между изолированными доменами; согласно докладу, его размер составляет около 350 инструкций.
Вывод Chisnall заключается в том, что защита памяти и изоляция не должны зависеть от полной переработки правил кода или от помещения каждого компонента в отдельный процесс. Сохранение привычной модели C при аппаратно понятных и контролируемых указателях и разрешениях доступа может обеспечить постепенный путь к сокращению количества ошибок памяти и построению более проверяемого совместного использования. Детали реализации при этом различаются между крупными системами и микроконтроллерами, а доклад отражает точку зрения его автора и его непосредственный опыт работы с CHERI, а не общий стандарт, автоматически гарантирующий устранение всех проблем безопасности.