Предисловие
Информации в данной статье не стоит стопроцентно и безоговорочно доверять. Я и мой товарищ, который помогал мне со сбором информации, только изучаем тему микроэлектроники не являемся экспертами в отрасли процессорных архитектур, в особенности RISC-V, отчего в данной статье могут быть ошибки, в виду не полного понимания темы. Всю информацию мы брали из открытых источников, документаций и статей с нашего любимого Хабра, Гит-хаба и подобных, поэтому для погруженных в тему людей данная статья, скорее всего, ничего нового и полезного не даст. Однако, я был бы рад получить конструктивную критику от знающих людей, чтобы разобраться в этой теме лучше.
P.S. Огромное спасибо за помощь в сборе информации моему товарищу Елфимову Артёму Андреевичу
Введение
В настоящее время цифровая инфраструктура очень быстро растет и развивается, вместе с ней должна развиваться и защита информации, используемая в той или иной технологии. Чаще всего основное внимание уделяют защите программных уязвимостей, тогда как аппаратный уровень остается в тени, хотя именно через него проходят все данные. Классические программные методы защиты — антивирусы, фаерволы, изоляция процессов, не всегда могут предотвратить утечку информации, ведь если в аппаратном уровне допущены механизмы, которые позволяют добраться до защищенной памяти, то никакие программные методы не помогут избежать утечек данных. Именно поэтому производители и разработчики всё чаще закладывают элементы безопасности непосредственно в архитектуру микропроцессора.
Разработка аппаратной безопасности включает в себя множество различных механизмов, такие как: разграничение уровней доступа, изоляция памяти, контроль выполнения привилегированных команд, использование доверенных сред исполнения. Важно понимать, что безопасность в процессорах — это не просто возможность дополнительной защиты, а необходимость, которая обхватывает не только микроархитектуру, но и программную инфраструктуру, взаимодействующую с ней. При правильном проектировании аппаратная безопасность позволяет предотвращать атаки.
Исторически считалось, что закрытые архитектуры, такие как x86 (Intel, AMD) и ARM, обладают встроенной безопасностью, благодаря контролю производителя над всеми составляющими в процессоре. Однако, с ростом сложности микропроцессоров, оказалось, что даже они не являются безопасными.
Яркий пример — атаки Spectre и Meltdown, позволившие извлекать данные из защищённой памяти [1]. Эти атаки затронули почти все современные процессоры, включая Intel, AMD и ARM.
В этом контексте особое внимание вызывает RISC-V — открытая архитектура команд, предоставляющая гибкость и прозрачность во всех своих аспектах. Но возникает вопрос: если даже закрытые архитектуры уязвимы, как обеспечивается безопасность в открытой архитектуре RISC-V? Но для начала, нам нужна небольшая историческая справочка в истории архитектур
1 Эволюция архитектур: от CISC к RISC
1.1 CISC-процессоры
В 1970-1980-ых годах на рынке микроэлектроники доминировали CISC-процессоры (Complex Instruction Set Computer - компьютер с полным набором команд), архитектуры x86. Главная особенность подобных процессоров была в том, что сложные операции выполнялись одной инструкцией длиной от 1 до 15 байт. Инструкция – это закодированная команда, определяющая операцию, которую должен выполнить процессор. Данный подход хоть и был неплохим, но имел в себе много недостатков:
Так как инструкции могли быть очень длинными, они требовали больше транзисторов, что повышало энергопотребление процессора, что было большой проблемой для отрасли 3д-моделирования и рендеринга того времени;
Для декодирования и выполнения нескольких сложных операций процессору требовалось много памяти, которая на тот момент стоила очень дорого (к примеру, один мегабайт оперативной памяти стоил около 5000 долларов). Также при обращении декодера к памяти скорость обработки инструкций становилась меньше;
Большинство возможностей CISC (например, строковые операции) редко использовались, но усложняли декодер.
1.2 Возникновение архитектуры RISC
В середине 1980-ых стали появляться процессоры на новом архитектурном подходе RISC (reduced instruction set computer - вычислитель с сокращённым набором команд). Его отличием от CISC было:
Фиксированная длина инструкции - всего 4 байта, что снизило энергопотребление.
Минимально необходимый набор команд, без лишней нагрузки на декодер.
Большое количество регистров, куда часть необходимых команд могли сохраняться, не прибегая к использованию памяти.
Но главным преимуществом RISC стала конвейеризация процессора - выполнение несколько инструкций одновременно. К примеру, для исполнения инструкции, она проходит 5 этапов:
Fetch (чтение инструкции).
Decode (декодирование).
Execute (выполнение).
Memory Access (работа с памятью).
Writeback (запись в регистр).
Каждый из этих этапов выполняется в один такт. В CISC процессорах пока одна инструкция проходит эти 5 этапов, вторая ждёт полного исполнения инструкции, чтобы начинать первый этап, когда как в RISC вторая инструкция может приступать первому этапу сразу, как первая инструкция перешла на второй. Если в CISC первая инструкция выполняется за 5 тактов, то вторая уже за 10, а третья за 15, в то время как в RISC все три выполнялись за 5 тактов. Архитектура оказалась успешной и производительной: любой процессор на базе RISC был в разы эффективнее в работе, чем его аналог на CISC[2].
1.3 Распространение RISC-архитектур
В дальнейшем началось сильно развитие архитектур на основе подхода RISC: в последнее время популярная архитектура ARM, процессоры которой стоят в каждом смартфоне и современных ноутбуках, и персональных компьютерах от Apple, нынче почившая MIPS, на базе которой делали процессор для PlayStation 1 и 2, а также появившаяся в 2010 году открытая архитектура RISC -V.
Основной особенностью RISC-V является её открытость и персонализированность в настройках. Если процессоры на архитектуре ARM хоть и являются производительными и современными, их нужно лицензировать, когда как RISC -V, несмотря на то, что подобен процессорам RISC 80-х и 90-х годов и во многом сильно проигрывает ARM, является открытой, и имеет возможность добавить собственные инструкции и декодер, настроить опциональные расширения для команд и также инструменты для информационной защиты процессора [3].
2 PMP: Защита памяти в RISC-V
2.1 Зачем нужна защита памяти
В современных вычислительных системах защита памяти является критически важным аспектом информационной безопасности. Процессорная память содержит ключи шифрования, учетные записи пользователей, код операционной системы и другие чувствительные элементы, и нарушение целостности или конфиденциальности этой информации может привести к серьезным последствиям. Для предотвращения подобного в различных архитектурах реализованы специализированные механизмы защиты.
2.2 Защита памяти в архитектуре RISC-V
В архитектуре RISC-V есть такой механизм защиты памяти, как PMP (Physical Memory Protection). С помощью него можно задать участки физической памяти, записав его в один из регистров, доступ к которым будет запрещен. Например, можно сделать запрет на чтение, запись или выполнение программ. Это полезно, если программа в пользовательском режиме, то она не сможет прочитать или изменить память, доступ к которой запрещён в настройках PMP. Его главным отличие от аналогов в x86 и ARM является использование физической памяти, а не виртуальной, благодаря чему PMP в выбранной области памяти будет осуществлять защиту лучше, чем методы, использующие виртуальную память. Но из-за небольшого количества регистров (от 8 до 16), метод не подходит для сложных ОС (например, Linux), так как не сможет защитить все области системы, поэтому PMP более эффективен для встраиваемых систем и устройств без полноценной операционной системы.
Основной принцип работы PMP поделен на два типа регистров:
Регистры pmpaddr0–pmpaddrN: Определяют границы защищаемых областей памяти. Количество регистров зависит от конкретной реализации (обычно от 8 до 16). Формат адреса зависит от режима адресации (TOR, NAPOT).
-
Регистры pmpcfg0–pmpcfgN: Задают права доступа для соответствующих областей. Каждый регистр pmpcfg содержит 8 бит, которые определяют:
Разрешение на чтение (R), запись (W) и выполнение (X);
Режим блокировки (L), предотвращающий изменение правил до перезагрузки системы.
Данные регистры важно настроить правильно, ведь при неверных ограничениях областей памяти может произойти утечка данных [4].


2.3 Защита памяти в архитектуре x86
В архитектуре x86 механизм защиты памяти устроен иначе, через метод страничной организации (paging), который использует виртуальную память. Механизм так и называет - Paging Protection. Он позволяет:
Изолировать процессы друг от друга;
Контролировать доступ к памяти на уровне страниц (обычно 4 КБ);
Реализовывать разграничения по уровню привилегий Ring levels (0–3) для разных участков памяти.
Данный механизм отлично подойдёт для сложный систем, ведь имеет многоуровневую структуру регистров (PML4 - Page Map Level 4, PDP - Page Directory Pointer, PD - Page Directory, PT - Page Table), благодаря чему охватывает всю ОС, но из-за сложности настройки не подойдёт для простых устройств [5].
2.4 Защита памяти в архитектуре ARM
Архитектура ARM использует комбинацию MMU (Memory Management Unit) и бита PXN (Privileged Execute Never):
MMU: Управляет трансляцией виртуальных адресов в физические;
PXN: Запрещает выполнение кода в пользовательском режиме для определенных страниц.
Данный механизм больше нацелен на энергоэффективность, поэтому имеет меньше регистров и более прост в настройке, чем Paging, но также пригоден для работы со сложными ОС [6]. Для корректной работы механизма потребуется настроенный TrustZone, о котором мы расскажем далее.
Критерий |
RISC-V (PMP) |
x86 (Paging) |
ARM (MMU+PXN) |
Работа без ОС |
Да |
Нет |
Нет |
Гранулярность |
8–16 регистров |
4 КБ–1 ГБ |
4 КБ–1 ГБ |
Сложность настройки |
Простая (регистры) |
Сложные таблицы страниц |
Для настройки требуется TrustZone |
3. Доверенная среда исполнения в RISC-V
3.1 Что такое TEE (Trusted Execution Environment)
Методы безопасности нужны не только памяти процессора, но и код и его корректное исполнения. Для такого типа информации есть TEE (Trusted Execution Environment - доверенная среда исполнения) – это среда внутри процессора, предназначенная для безопасного исполнения кода и хранения чувствительных данных. Данная среда обеспечивает изоляцию от основной операционной системы и приложений. Даже если хост-система скомпрометирована, код внутри TEE остаётся защищённым [7].
3.2 Подход к TEE в архитектуре RISC-V
В RISC-V нет встроенного TEE на уровне архитектуры, но есть множество внешних решений, которые пользователь по предпочтению может поставить сам: Keystone Enclave, OpenTitan, Hex-Five MultiZone Security, Bao Hypervisor, Silicon Labs Secure Vault и другие. Из них всех возьмём лишь самый популярный - Keystone Enclave [8].
Keystone — это платформа открытого исходного кода (open-source), предназначенная для реализации TEE (Trusted Execution Environment) на базе архитектуры RISC-V.
Концепция Keystone базируется на технологиях Intel SGX, то есть доверенная среда реализуется через анклав - защищённую область памяти, которая позволяет выполнять код и хранить данные так, что даже операционная система или привилегированный пользователь не могут получить к ним доступ без соответствующих прав, и данная защищённая область в Keystone выделяется с помощью PMP. Но несмотря на заимствования идей у Intel и ARM, построена данная TEE с учётом всех их слабостей. Сам Keystone, подобно RISC-V, также открыт и гибок в настройках, его можно проанализировать на уязвимости, улучшить или адаптировать под себя, чего нельзя сказать про SGX и TrustZone. Так же и сама доверенная среда построена модульно, и разработчик может самостоятельно настроить, какие компоненты попадут в доверенную базу, а какие останутся за пределами защищённой области. Но для данного метода нужна точная и правильная настройка, ведь при неверных параметрах может произойти утечка данных и потеря конфиденциальной информации[9]. Keystone — это гибкий, программный и открытый аналог, реализующий TEE поверх минимального набора аппаратных расширений.

3.3 Сравнение Keystone Enclave с аналогами других архитектур
Intel SGX — это набор инструкций на x86 от Intel, позволяющий создавать анклавы внутри адресного пространства процесса. В отличии от Keystone, анклав в SGX находится в пределах одного процесса, но область памяти анклава шифруется и аппаратно защищена от остальной ОС. Работает SGX на уровне пользовательского режима (Ring 3), в качестве самого анклава реализует защищённую область DRAM, и данный TEE широко используется в облачных решениях, таких как Azure Confidential Computing. Из недостатков выделяют сложность программирования и отладки SGX, а так наличие серьёзных уязвимостей, которые невозможно проанализировать из-за проприетарности метода [10].

TrustZone – аппаратная технология от ARM, которая делит систему на два "мира":
Secure World — по сути является той самой доверенной средой.
Normal World — основная операционная система и приложения.
Между этими “мирами” переключение осуществляется через инструкции SMC (Secure Monitor Call). Secure World имеет доступ к ресурсам Normal World, но не наоборот. Обычно эта технология используется в Android для реализации Trusty OS, а также в чипах с DRM (Технические средства защиты авторских прав). Минусом у TrustZone является его закрытая реализация, и разработчики не могут свободно адаптировать TEE под необходимые задачи [11].

Параметр |
Keystone (RISC-V) |
Intel SGX (x86) |
TrustZone (ARM) |
Открытость |
Полностью открытый код и спецификации |
Закрытая реализация |
Закрытая реализация |
Изоляция |
На основе PMP и привилегий |
Аппаратная изоляция в CPU |
Аппаратный делитель мира |
Гибкость |
Пользователь может адаптировать архитектуру под нужды |
Жёстко привязан к Intel чипам |
Жёстко привязан к ARM Cortex |
Применение |
IoT, edge-серверы, исследовательская среда |
Облачные сервисы, DRM |
Мобильные устройства, криптооперации |
4. Контроль привилегий в процессорах
4.1 Зачем нужен контроль привилегий
В каждом современном процессоре существует контроль привилегий - это разделение на уровни доступа, какие участки кода и какие программы могут выполнять определенные команды и обращаться к различным ресурсам. Это нужно для того, чтобы нежелательные программы не могли вмешиваться в работу процессора на аппаратном уровне.
4.2 Механизм привилегий в архитектуре RISC-V и ее аналогах
В RISC-V существует три уровня привилегий:
Machine mode (M-mode) — самый высокий, доступ ко всей памяти, как виртуальной, так и физической;
Supervisor mode (S-mode) — для операционной системы, может управлять виртуальной памятью и процессами;
User mode (U-mode) — для обычных приложений.
Для каждого режима разрешен только определенный набор действий [12].
Если сравнивать с архитектурой x86, то там контроль привилегий действует иначе, есть кольца (Ring 0 — Ring 3), где Ring 0 - это самый высокий уровень, а Ring 3 - это обычные приложения [13].

У ARM тоже своя система и в старых версиях она была схожа с RISC-V, но в более новых появился механизм TrustZone, который делит систему на обычную и защищённую, что позволяет выполнять важные задачи отдельно от основной операционной системы.

5. Защита от спекулятивных атак в процессорах
5.1 Что такое спекулятивное выполнение
Процессоры на современных архитектурах активно используют спекулятивное исполнение инструкций — технику, при которой процессор выполняет задачу, до её фактического получения, чтобы не простаивать в ожидании результата сравнения.
Однако в 2018 году опубликовали исследования, показавшие, что через спекулятивные инструкции можно прочитать данные, к которым у приложения нет доступа. Как это работает:
Атакующий многократно вызывает код с корректным индексом x, чтобы процессор «привык» выполнять эту ветку.
-
Теперь он передаёт нужный ему индекс, выходящий за границы массива и указывающий на защищённые данные (к примеру, пароли и ключи шифрования). Тем временем процессор:
Спекулятивно загружает array[x] (например, секретный ключ);
Проверяет условие и понимает, что доступ запрещён;
Отменяет операцию, но следы остаются в кэше;
-
Атакующий измеряет время доступа к ячейкам памяти:
Если данные были в кэше (значит, они спекулятивно загружались) — доступ быстрый;
Если не были — доступ медленный.
Таким образом атакующий получает доступ к защищённой информации. Подобных уязвимостей много, самые популярные из них:
Spectre — манипулирование ветвлениями, обход изоляции между процессами.
Meltdown — доступ к защищённой памяти через спекулятивное выполнение.
Эти уязвимости затронули почти все современные процессоры на x86 и ARM, и возникла необходимость в их архитектурных изменениях [14].


5.2 Реализация защиты в RISC-V и других архитектурах
RISC-V, в отличие от x86 и Arm, не требует спекулятивного выполнения для высокой производительности. Однако некоторые ядра поддерживают эту оптимизацию, что делает их потенциально уязвимыми. К примеру, 64-битное ядро CVA6 поддерживает спекулятивное выполнение, и несмотря на то, что это ускоряет доступ к памяти, повышая эффективность ядер, появляется потенциальная уязвимость Spectre-атаки. Для защиты ядра была создана fence инструкция - принудительный барьер, который сбрасывает спекулятивные операции при смене контекста. И всё равно, если от атак Spectre-V2 fence защищает, то Spectre-V1 все ещё возможен, если ядро спекулятивно выполнит инструкции после условного перехода. Но ядро Ariane не имеет поддержки спекулятивного выполнения, что хоть и понижает их производительность, по сравнению с CVA6, но делает его абсолютно неуязвимым к любым спекулятивным атакам [15].
Intel и AMD выпускают обновления для своих x86 процессоров, которые добавляют новые механизмы защиты:
IBRS (Indirect Branch Restricted Speculation) – ограничивает спекулятивное выполнение косвенных переходов;
STIBP (Single Thread Indirect Branch Predictors) – защищает от атак между потоками (например, в облаке).
Данные механизмы запрещают использование истории предсказаний ветвлений инструкций, что защищает от Spectre-атак, но уязвима к Meltdown и понижает производительность процессора на 5–15%. В качестве альтернативы этим механизмам есть LFENCE-барьер, который принудительно останавливает спекулятивное выполнение последующих команд. Данный метод помимо неуязвимости к Spectre даёт частичную защиту к Meltdown, и понижает производительно всего на 5%.
Процессорные ядра у ARM более уязвимые к Spectre, чем x86[16], поэтому был создан аналог LFENCE в ARM - инструкция CSDB. Принципиально, они ничем друг от друга не отличаются, и CSDB, так же как LFENCE, блокируют большинство Spectre-атак, но в отличии от x86, армовский аналог понижает производительность до 10%. Также, из аппаратных методов у ARM есть SSBS (Speculative Store Bypass Safe)[17], который отключает спекулятивный обход проверок памяти, защищает от большинства Spectre-атак и понижает производительность на 5-10%. Но данный метод включается через регистр SCTLR_ELx.SSBS, по умолчанию включён только CSDB[18].
6. Экспериментальная часть, с целью проверки методов безопасности процессоров RISC-V на практике
К сожалению, у меня нет системы с процессором на архитектуре RISC-V, поэтому эксперименты были проведены в программе для эмуляции аппаратного обеспечения различных платформ QEMU, так как он поддерживает эмуляцию процессоров на архитектуре RISC-V, на виртуальной операционной системе Ubuntu. В программировании на ассемблере я чайник, поэтому в помощь мне приходили некоторые форумы и нейронный товарищ в лице ChatGPT. Прошу сильно не сердиться)
6.1 Эксперимент 1: Настройка PMP
Цель эксперимента: проверить, как механизм PMP настраивается и ограничивает доступ программ к определённым физическим адресам, особенно при переходе из режима привилегий M-mode (Machine) в U-mode (User).
Для начала попробуем корректную настройку PMP.
Структура проекта:
main.c - основной код (настройка PMP + тест записи).
-
start.S - ассемблерный код, который выполняется самым первым после загрузки программы. Его задачи:
инициализировать стек (sp);
подготовить окружение для запуска main() (например, очистить .bss);
переключиться в нужный режим.
-
linker.ld - конфигурационный файл, который указывает компоновщику:
где в памяти размещать код (text), данные (data, bss) и другие секции;
как выравнивать секции;
какие симоволы (например, _start) считать точками входа.
Корректная настройка PMP:

configure_pmp() настраивает pmpaddr0 на область 4К от 0x80000000.
Устанавливается pmpcfg0 на RWX (команда для изменения прав доступа).
Данные регистров pmpaddr0 и pmpcfg0 записываются в allowed.
Запись регистров в forbidden — выходит за пределы и вызывает trap (в QEMU просто "виснет").

Файл linker.ld размещает код по адресу 0x80000000, так как PMP настраивается на этот же адрес.

Минимальный стартовый код:
устанавливает стек (sp);
Вызывает main;
Бесконечный цикл после выхода из main.
Ожидаемое поведение:
если QEMU с поддержкой PMP — trap при второй записи;
если PMP не эмулируется — запись произойдёт (плохой результат);
если всё настроено верно — QEMU зависнет или покажет trap (в зависимости от настроек).
Запуск:
Компиляция start.S и main.c в нужные форматы

Запуск QEMU с файлом формата .elf

Видим, что QEMU – завис. Чтобы в этом удостовериться используем команду «ps aux | grep qemu», если увидим, что сеанс программы не завершён – QEMU зависла. QEMU действительно зависла, следовательно, произошёл вызов «trap», PMP заблокировал доступ к выделенной области, и эксперимент прошёл успешно.

Некорректная настройка PMP:
Дальше попробуем намеренно настроить PMP неправильно. Изменим файл main.c


PMP настроен на 0x80200000, но ошибочно: разрешены все доступы. Происходит переход в U-mode. U-код обращается по адресу 0x80200000, и это срабатывает. Выводится «[U-MODE] Write succeeded! PMP failed!»

Добавляет секцию .rodata для смены уровня привилегий, а также исключает лишнее. Файл start.S остаётся без изменений.
Программа должна вывести:
«[M-MODE] PMP incorrectly configured. Should block, but doesn't.
[U-MODE] Attempting to write to protected memory...
[U-MODE] Write succeeded! PMP failed!»
Запуск. Компилируем файлы и запускаем QEMU

Программа зависла – следовательно PMP сработал или произошла проблема при переходе в другой уровень привилегий. Попробуем добавить в код настройку mstatus перед mret, для корректного перехода по уровням привилегий.
Добавление настройки mstatus

Запуск эмулятора через интерфейс OpenSBI


Эмулятор снова завис, вероятнее всего это связано с ошибкой во время смены уровня привилегии из-за некорректной эмуляции PMP на виртуальных эмуляторах, и мой низкий навык владения ассемблером. Эксперимент неудачный.
6.2 Эксперимент 2: Моделирование Spectre-подобной атаки в RISC-V
Цель эксперимента: Смоделировать условия для Spectre-атаки в эмуляторе RISC-V. В RISC-V QEMU обычно нет поддержки спекуляции, но мы имитируем её поведение: покажем, как потенциально могла бы произойти утечка через побочный канал, даже если реально спекуляции нет.
Суть нашей Spectre-атаки:
есть секретный массив, который мы должны достать: secret[];
есть проверка границы доступа к array[index], которая должна ограничить доступ;
но при спекуляции CPU может временно проигнорировать проверку границы и начать выполнять следующую команду (например, доступ к secret);
даже если потом выполнение отменяется, побочные эффекты (например, кэш) остаются — их можно "заметить";
именно этой уязвимостью мы и воспользуемся.
Структура проекта:
main.c - основной код — имитация Spectre;
start.S - инициализация и запуск main;
linker.ld - разметка памяти.


Пояснение кода: есть массив unused_array — безопасный буфер. Есть секретный байт secret, расположенный сразу за unused_array. Функция victim_function получает индекс, проверяет, что он внутри unused_array и читает значение из этого массива, а затем обращается к probe_array по индексу, зависящему от прочитанного байта. В норме выход за пределы массива невозможен, но в спекулятивном исполнении процессор мог бы "спекулятивно" выполнить код с неправильным индексом, косвенно раскрывая значение secret. Функция spectre_attack пытается вызвать victim_function с индексом, указывающим на секретный байт, и затем анализирует изменения в probe_array, чтобы "угадать" секрет. В выводе показывается угаданное значение секретного байта (в данном случае — D0 в шестнадцатеричном виде).


Почему это не реальная спекулятивна атака:
нет спекуляции в QEMU;
нет реального кэша, а значит и времени доступа;
это учебная симуляция: мы "предполагаем", что доступ по неверному индексу всё же произошёл и повлиял на поведение.
Программа должна вывести:
«[SPECTRE] Starting simulation...
Guessed secret: D0»
Запуск. Компилируем start.S и main.c в нужные для работы форматы

Запуск QEMU с файлом формата .elf

В выводе мы видим секретный байт, следовательно, Spectre атака прошла успешно – эксперимент удачный.
6.3 Эксперимент 3: Демонстрация Keystone Enclave в QEMU
Цель эксперимента: Запустить защищённое исполняемое окружение (TEE) с помощью Keystone и продемонстрировать его работу на RISC-V через эмулятор QEMU. Несмотря на то, что вариантов механизма TEE в архитектуре RISC-V достаточно, мы решили так же взять Keystone, так как он позволяет:
создавать и запускать энклавы — приложения в изолированной защищённой среде;
использовать SDK для их написания;
запускать всё это в QEMU, даже без физического RISC-V железа.
Запуск. Установка зависимостей

Так как Keystone — это внешняя open-source система, её нужно клонировать вручную с GitHub [20].

Далее идет сборка собственного RISC-V компилятора, настроенного для работы с Keystone

Переходим в директорию папки sdk. Запускаем скрипт init.sh. Скрипт init.sh подготовит окружение и необходимые зависимости


Далее производим сборку тестовой энклавы (HelloWorld)

После сборки появились два бинарных файла:
host_helloworld — программа на стороне хоста;
eapp_helloworld — исполняемый код в энклаве.
Производим запуск через QEMU. Переходим в директорию scripts – ближе к «сердцу» Keystone и запускаем скрипты


На консоль выводится запуск системы и выполнение защищённого кода. Энклава демонстрирует базовую функциональность TEE: код исполняется в изолированном пространстве, доступ к нему ограничен со стороны основной ОС.

Данный вывод означает что:
хост-приложение запустило энклаву;
код внутри энклавы выполнен изолированно;
доверительная среда (TEE) работает.
Таким образом, можем сделать вывод, что эксперимент прошёл успешно, все ключевые компоненты отработали корректно.
7. Заключение
Архитектура RISC-V, несмотря на свою относительную молодость и моральную устарелость, демонстрирует высокую степень возможности глубокой настройки систем безопасности. В отличие от закрытых архитектур x86 и ARM, она предлагает разработчикам возможность гибко настраивать уровни доступа, расширять набор инструкций и интегрировать механизмы защиты по своему вкусу. Такие технологии, как PMP, Keystone и трёхуровневая модель привилегий, позволяют реализовать надёжную защиту данных и изоляцию процессов на уровне встраиваемых систем.
Однако RISC‑V имеет и определённые ограничения. Архитектура не имеет полноценной защиты от спекулятивных атак в общедоступных ядрах, а PMP ограничен по количеству регионов и подходит в первую очередь для встраиваемых решений, а не для полноценных операционных систем. Архитектуры x86 и ARM имеют более зрелые аппаратные защиты, но их сложность и закрытость осложняют аудит, доверие и анализ уязвимостей.
RISC‑V обеспечивает удобную площадку для создания систем с расширяемой и проверяемой моделью защиты, что особенно важно для критических сфер и встраиваемых систем.
Сравнение с архитектурами x86 и ARM показывает, что закрытость не является гарантией защищённости. Примеры атак Spectre и Meltdown затронули многие устройства, преимущественно на закрытых архитектурах.
Открытость RISC‑V даёт возможность независимым исследователям и организациям самостоятельно изучать и расширять защитные механизмы, и главное — доверять тому, что их процессор действительно делает. Примеры Keystone Enclave показывают, что открытые TEE‑решения могут быть не менее сильными, чем закрытые TrustZone и SGX.
Таким образом, открытые архитектуры, при грамотной настройке и сообществе разработчиков, способны обеспечивать более надёжную и контролируемую защиту, чем проприетарные.
Список использованных источников
Статья об атаках Spectre и Meltdown на сайте Касперского URL: https://www.kaspersky.ru/blog/spectre-meltdown-in-practice/32334/
«Ретроспективный взгляд на развитие микропроцессоров CISC, RISC, MIPS, ARM» URL: https://habr.com/ru/companies/first/articles/798635/
«Гениальность микропроцессоров RISC-V» URL: https://habr.com/ru/companies/vdsina/articles/534542/
Официальная документация про PMP на сайте проекта «RISC-V» URL: https://riscv.org/blog/2024/03/adding-physical-memory-protection-to-the-veer-el2-risc-v-core-2/
Страница на OSDev Wiki про механизм защиты Paging URL: https://wiki.osdev.org/Paging
Страница на DeepWiki про меры безопасности архитектуры ARM URL: https://deepwiki.com/nccgroup/exploit_mitigations/4.1-arm-architecture-security-mitigations
Статья про Trusted Execution Environment на сайте Microsoft URL: https://learn.microsoft.com/ru-ru/azure/confidential-computing/trusted-execution-environment
Статья про особенности TEE Xuantie на сайте проекта «RISC-V» URL: https://riscv.org/blog/2023/01/xuantie-risc-v-tee-solution-for-mcu/
«Проект Keystone: доверенная среда для запуска приложений на базе RISC-V» URL: https://habr.com/ru/companies/mws/articles/423777/
«Trusted Execution Environment на примере Intel SGX. Основные принципы простыми словами. «Hello World!»» URL: https://habr.com/ru/articles/518004/
«TrustZone: доверенная ОС и ее приложения» URL: https://www.aladdin-rd.ru/company/pressroom/articles/trustzone-doverennaa-os-i-ee-prilozenia/
Руководство по набору инструкций RISC-V, Том II: Привилегированная архитектура URL: https://www.five-embeddev.com/riscv-priv-isa-manual/latest-latex/priv-intro.html
«Кольца, уровни привилегий и защита в x86» URL: https://habr.com/ru/companies/smart_soft/articles/184174/
«Новая техника атак на основе Meltdown. Использование спекулятивных инструкций для детектирования виртуализации» URL: https://habr.com/ru/companies/bizone/articles/359110/
«Программное обеспечение для защиты от атак Spectre в RISC-V» URL: https://link.springer.com/chapter/10.1007/978-3-031-52947-4_5
Статья «Новая атака обходит аппаратную защиту от уязвимостей Spectre в процессорах Intel и ARM» URL: https://www.csoonline.com/article/572191/new-attack-bypasses-hardware-defenses-for-spectre-flaw-in-intel-and-arm-cpus.html
SSBS, Speculative Store Bypass Safe Documentation URL: https://developer.arm.com/documentation/ddi0601/2025-03/AArch64-Registers/SSBS--Speculative-Store-Bypass-Safe
CSDB, Consumption of Speculative Data Barrier Documentation URL: https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/CSDB--Consumption-of-Speculative-Data-Barrier-
QEMU User space emulator URL: https://www.qemu.org/docs/master/user/main.html
Keystone Enclave (QEMU + HiFive Unleashed) URL: https://github.com/keystone-enclave/keystone
Комментарии (25)
anoldman25
04.08.2025 18:12Яркий пример — атаки Spectre и Meltdown, позволившие извлекать данные из защищённой памяти [1]. Эти атаки затронули почти все современные процессоры, включая Intel, AMD и ARM.
Вот еще одна ошибка в первых pentium - FDIV:
SIISII
04.08.2025 18:12Ну, это именно ошибка в чистом виде, а не "фишка" (особенность микроархитектуры), которая превращается в уязвимость.
SIISII
04.08.2025 18:12Так как инструкции могли быть очень длинными, они требовали больше транзисторов, что повышало энергопотребление процессора, что было большой проблемой для отрасли 3д-моделирования и рендеринга того времени;
Для декодирования и выполнения нескольких сложных операций процессору требовалось много памяти, которая на тот момент стоила очень дорого (к примеру, один мегабайт оперативной памяти стоил около 5000 долларов). Также при обращении декодера к памяти скорость обработки инструкций становилась меньше;
Большинство возможностей CISC (например, строковые операции) редко использовались, но усложняли декодер.
Строго говоря, неверны все три пункта.
Количество потребных транзисторов со сложностью системы команд связано отнюдь не линейным образом. В частности, сложность исполнительных блоков (условно говоря, АЛУ) для выполнения одних и тех же операций вообще никак не зависит от кодирования команд как такового; нет никакой разницы и в конструкциях кэшей, TLB, регистровых файлов и т.д. и т.п.
С декодированием тоже далеко не всё однозначно. Когда автор статьи пишет про длину команды от 1 до 15 байт, он, несомненно, имеет в виду IA-32 aka x86. Эта кодировка не самая длинная (у VAX-11, если память не изменяет, длина команды могла достигать вообще 36 байт), но одна из самых бредовых и сложных для декодирования -- в первую очередь, из-за наличия префиксов, ни количество, ни порядок которых никак архитектурой не ограничены. Однако CISC отнюдь не обязан быть столь безумным. Скажем, такой классический CISC, как IBM System/360 (и все её потомки, включая современную z/Architecture), имеет длину команды 2, 4 или 6 байт, причём длина однозначно устанавливается анализом двух старших битов первого байта -- т.е. даже проще, чем, скажем, для команд набора Thumb-2 архитектуры ARM (там всего две длины -- 2 или 4 байта, -- но анализ длины сложнее).
Насчёт памяти написана вообще полная ерунда -- CISC как раз требует меньше памяти, поскольку в одной команде может закодировать куда более сложную операцию. Сколько места займёт подпрограмма шифрования AES на ARM или RISC-V? Ну а на мэйнфреймах z/Architecture это делается одной командой. А если необходима десятичная арифметика? (а она необходима для финансового сектора -- недаром соответствующие вещи есть, например, в Жабе) На большинстве архитектур, включая IA-32, будут пляски с бубном, чтобы добиться того же результата, используя целочисленную двоичную арифметику, ну а мэйнфреймы ещё с Системы 360 имеют и команды десятичной арифметики. Да, и операция пересылки строк на них тоже используется весьма и весьма часто -- пересылать ведь не только строки в узком смысле приходится, а произвольные блоки данных.
(Замечу, что есть по крайней мере одно типа исследование, которое "доказывает", что плотность кода CISC ниже, чем RISC: но, во-первых, сами авторы там между строк замечают, что, фактически, их сравнение неправомерно, поскольку сравнивают современные 64-разрядные архитектуры ARMv8 и RISC-V с древними CISCами, где 64-разрядные расширения были добавлены много позже -- а соответственно, все короткие коды операций уже попросту были заняты; а во-вторых, они начисто игнорируют случаи, когда сложные операции выполняются на CISCах одной-двумя командами, а на RISCах требуют подпрограмм значительного размера -- т.е., попросту говоря, подбирают тесты под требуемые результаты)
Усложнение декодера -- тоже далеко не факт. В частности, декодер для системы команд Thumb-2 будет сложней, чем даже для современных мэйнфреймов z/Architecture, не говоря о классической Системе 360
Усложнение управляющей логики, о чём автор почему-то не говорит, -- чуть ли не единственный пункт, где можно было бы согласиться, но и здесь не всё просто. Многие CISCи (а с 1970-х годов -- пожалуй, все или почти все) используют не чисто схемное, а микропрограммное или смешанное микропрограммно-аппаратное управление, что многократно упрощает конструкцию управляющей части процессора (память микропрограмм многократно проще и дешевле, чем управляющая логика). Впервые микропрограммы были использованы на младших и средних моделях Системы 360; старшие модели делались со схемным управлением (и были конвейерными) -- разработчики опасались, что микропрограммное управление будет медленнее. Но, как оказалось, оно может быть столь же быстрым: это зависит от особенностей микроархитектуры; поэтому, набив руку, его стали использовать и в топовых моделях. Скажем, в младших моделях (IBM System360/30 и наша ЕС-1020) АЛУ было 8-разрядным, а соответственно, простейшая 32-разрядная операция требовала для своего выполнения четыре микрокоманды только для собственно вычислений -- не говоря о всяких других потребных действиях; понятно, что это было очень медленно -- но требовало очень мало аппаратуры, почему, собственно, и использовалось. Однако, если не экономить оборудование для выборки команд и для собственно выполнения операций, разницы в скорости с машиной с чисто схемным управлением не будет, а разница в объёме аппаратуры окажется весьма значительной. Скажем, наша ЕС-1130 при заполненном конвейере выполняла простые команды регистр-регистр и регистр-память (!) за один такт, но была микропрограммной, просто вся микропрограмма для этих простых команд состояла из единственной микрокоманды (а вот выборка команды, декодирование, вычисление адресов операндов и их подготовка в ней были сделаны чисто аппаратно; микропрограмма управляла лишь ходом выполнения собственно обработки данных -- была, как я уже сказал, элементарнейшей для простейших операций, но сложной для сложных). Примерно ту же идею, только в значительно более сложном исполнении (в первую очередь, из-за суперскалярности и внеочередного исполнения) используют и современные CISC-процессоры (что у интеловских процессоров есть микрокод, наверное, все знают).
В 1980-х RISC-микропроцессоры (подчёркиваю микро) показывали более высокую производительность над CISC-микропроцессорами за счёт того, что благодаря очень малому числу команд (первый из них насчитывал, насколько помню, всего 31 команду) и другим упрощениям его можно было сделать конвейерным, но всё равно впихнуть на один кристалл; для CISC-процессора на тот момент это было невозможно, поэтому приходилось выбирать: либо медленная микропрограммная реализация на одном кристалле, либо быстрая, но на куче микросхем (в IA-32 первым конвейерным стал 80486; в мэйнфреймах конвейерными давно уже были все модели, а некоторые -- и суперскалярными, но они достаточно долго оставались многокристальными). Однако, если рассматривать все процессоры, а не только микро, RISC по скорости первыми отнюдь не были -- но далеко не каждый может позволить себе поставить мэйнфрейм или, тем более, какой-нибудь Cray с охлаждением жидким азотом (и хорошо, если азотом). Но в 1990-х, когда количество транзисторов на кристалле значительно выросло, конвейерные CISC тоже стали однокристальными -- и догнали (а нередко и перегнали) по скорости RISC. Да и сами современные RISC, прямо скажем, зачастую мало чем отличаются от CISC: имеют сотни, а то и тысячи команд, включают ряд достаточно сложных операций и т.д. Изначальная идея RISC (напомню, у первого из них была 31 команда, и среди них не было даже умножения и деления -- они сложные) оказалась несовместима с высокой производительностью, поэтому от неё отошли; фактически единственное, что осталось -- это отсутствие команд обработки данных вида "регистр-память" или "память-память" -- вся обработка выполняется исключительно в регистрах.
Fin_Debov Автор
04.08.2025 18:12Большое спасибо, за пояснение и разбор моих ошибок. При чтении статей про историю CISC я, видимо, не совсем корректно понял информацию по кризису CISC 80-ых, перепутал момент по поводу использования памяти, не до конца раскрыл другие пункты, и не упомянул некоторые краеугольные проблемы CISC 80-ых годов,которые и стали причиной кризиса. Буду изучать этот вопрос подробнее, чтобы в дальнейшем избежать таких ошибок и неточностей.
unreal_undead2
04.08.2025 18:12Сколько места займёт подпрограмма шифрования AES на ARM или RISC-V? Ну а на мэйнфреймах z/Architecture это делается одной командой.
Эти команды и на RISC процессорах есть. RISC на самом деле - не про простоту или небольшое количество инструкций (хотя название намекает), а про минимальную прослойку между ISA и железом процессора - изначально речь шла про борьбу с микрокодом, то есть о выкидывании инструкций, реализация которых требует по сути отдельных подпрограмм внутри процессора. Если в процессор добавляется специальный юнит для крипто операций, расширение ISA для работы с ним идее RISC не противречит.
SIISII
04.08.2025 18:12Про RISC-V не знал -- по большому счёту, я с ним не знаком, хотя всё собираюсь заняться. В известных же мне типа RISCах подобные операции (шифрование, например) выполняются железными блоками, которые расположены отдельно от процессора и, по сути, выступают в роли внешних устройств, т.е. частью соответствующей архитектуры не являются. Таковы, например, многие микроконтроллеры ARM: сама система команд никаких тебе шифраций или, скажем, преобразования UTF-8 в UTF-32 или обратно не содержит.
Ну и опять повторюсь, что от изначальной идеи RISC (а она -- именно что небольшое количество простых команд) отказались, считай, полностью -- она оказалась неконкурентоспособной с CISCами, как только совершенствование технологий дало возможность конвейерный (а позже и суперскалярный) CISC впихнуть на один кристалл. Так что лично для меня сейчас RISC -- это архитектура, не имеющая команд обработки данных прямо в памяти, ибо это, по сути, единственное, что нынешние RISCи отличает от нынешних CISCов, хотя и это различие, похоже, постепенно уходит (ведь, полагаю, RISC-V шифрует данные в памяти? Регистров у него не так уж много, и большой объём в них не впихнуть. Надо как-нибудь изучить сей вопрос...)
unreal_undead2
04.08.2025 18:12подобные операции (шифрование, например) выполняются железными блоками, которые расположены отдельно от процессора
Да, для микроконтроллеров это логично, но в серверных чипах вполне можно выделить транзисторы на самом процессоре.
от изначальной идеи RISC (а она -- именно что небольшое количество простых команд)
Всё таки изначально Паттерсон в статье выступал в основном против микрокода. И да, в те времена - когда даже FPU на чипе встречалось нечасто - ISA, отображающая только то, что реализовано в железе, получалась весьма компактной. Но если в микроархитектуру добавляются векторные регистры, специализированные блоки в ALU и т.д. - странно не предоставлять к этому архитектурный доступ на уровне ISA.
ведь, полагаю, RISC-V шифрует данные в памяти? Регистров у него не так уж много
Инструкции работают со скалярными или векторными регистрами, если надо обработать большой массив, нужен цикл. И да, сейчас видимые отличие CISC/RISC скорее в наличии/отстутствии аргументов в памяти в арифметических инструкциях. Хотя сейчас в ARM есть, скажем, CISC-style атомики, инкрементирующие значение в памяти одной инструкцией, в спецификации (в железе пока не видел) есть и инструкции копирования памяти по типу REP MOVS в x86.
SIISII
04.08.2025 18:12Инструкции работают со скалярными или векторными регистрами, если надо обработать большой массив, нужен цикл. И да, сейчас видимые отличие CISC/RISC скорее в наличии/отсутствии аргументов в памяти в арифметических инструкциях. Хотя сейчас в ARM есть, скажем, CISC-style атомики, инкрементирующие значение в памяти одной инструкцией, в спецификации (в железе пока не видел) есть и инструкции копирования памяти по типу REP MOVS в x86.
Кстати говоря, для реализации атомарных операций вроде И, ИЛИ шина AXI имеет соответствующие навороты, чтобы операции эти фактически выполнялись контроллером памяти, а не процессором. Откопал, когда смотрел сию шину (использую в своих мегапроектах на ПЛИС, поскольку она используется для подключения контроллера памяти).
В общем, похоже, от изначальных RISCов теперь не осталось ничего. Ну а микрокод высокой производительности ни разу не противоречит, как и я говорил, и всякие там Интелы на практике доказывали. Как по мне, бороться с ним не надо -- он даёт гибкость (медленная, но компактная реализация тоже может быть ценной -- а использование микропрограммного управления даёт возможность легко подстраиваться под потребности). В общем, исходить, смотря по задаче.
unreal_undead2
04.08.2025 18:12микрокод высокой производительности ни разу не противоречит
Изначальный посыл RISC был в том, что реализованные в микрокоде инструкции со сложной семантикой удобны скорее человеку - компиляторы их не генерируют, а большая часть ПО пишется на языках высокого уровня - соответственно, все эти навороты с микрокодом только зря расходуют транзисторы, которые можно использовать более продуктивно.
unreal_undead2
04.08.2025 18:12RISC-V, в отличие от x86 и Arm, не требует спекулятивного выполнения для высокой производительности
И что он предлагает взамен (и как тут вообще влияет ISA)? Вроде пока ничего лучше для ускорения обычного однопоточного кода не придумано.
SIISII
04.08.2025 18:12Мне кажется, автор просто что-то там недопонял. Недостаточное понимание видно, например, из "описания" MMU -- ведь принципиально и на ARM, и на IA-32, и почти в любых других архитектурах MMU работают одинаково -- точно так же, как ещё в Системе 370 (несколько уровней таблиц переадресации в памяти, базовый адрес таблицы верхнего уровня -- в некоем специальном регистре, а для ускорения преобразования -- TLB).
Fin_Debov Автор
04.08.2025 18:12Тут вы правы, я в этой теме только начинаю вариться и не сильно "прошарен")
Этот проект - по сути, моя курсовая, которую я опубликовал на хабр, больше не с целью того, чтобы не знающие люди почерпнули для себя что-то новое в теме процессорных архитектур(хотя и не без этого),а получения критики от более матёрых в этой теме людей, чтобы более основательно погрузится в изучение вопросов архитектур и их безопасности.unreal_undead2
04.08.2025 18:12Стоит тогда на Эльбрус посмотреть - там, например, разделены стеки возрата и данных. А если копнуть в историю - то ещё и на старый советский Эльбрус с аппаратным контролем типизации (подобное было и в iAPX 432).
Fin_Debov Автор
04.08.2025 18:12Тут я не совсем корректно выразился. Я имел в виду, что в основе у RISC-V есть ядра, которые не поддерживают спекулятивное выполнение, что понижает производительность этих самых ядер, но делает их менее уязвимыми к Spectre-атакам, когда как у x86 и ARM все ядра имеют поддержку спекулятивного выполнения. Я здесь больше говорю не про производительность, а про уязвимость к Spectre и Meltdown.
unreal_undead2
04.08.2025 18:12когда как у x86 и ARM все ядра имеют поддержку спекулятивного выполнения
По крайней мере ARM ядра c in order микроархитектурой ещё живы; насчёт x86 не уверен, но они достаточно долго были таковыми (спекулятивное выполнение появилось только в Pentium Pro) и никто не мешает сделать новое x86 in order ядро - вопрос только в рыночной востребованности, сама по себе ISA не требует какой то конкретной микроархитектуры. При этом если RISC V таки дойдёт до HPC и энтерпрайза, спекулятивное выполнение в таких чипах скорее всего будет - например, у Syntacore в ядрах начиная с SCR6 спекулятивное выполнение есть.
Fin_Debov Автор
04.08.2025 18:12При рассмотрении методов безопасности, в том числе про спекулятивные атаки, я брал для сравнения современные x86 и ARM, но про in order я не знал. Спасибо за дополнение, будет, что дополнительно изучить.
SIISII
04.08.2025 18:12Ну, во-первых, ядра с внеочередным выполнением команд -- это вообще только для максимальной производительности любой ценой, что не везде нужно.
Во-вторых, и x86, и ARM -- понятия очень сильно растяжимые. У последнего, в частности, выпускаются процессоры с ядрами, где даже простой суперскалярности нет, не говоря уже о внеочередном выполнении, а среди микроконтроллеров таких явно больше половины -- а ведь они тоже ARM.
Ну а в-третьих, указанные уязвимости прямо не связаны с суперскалярностью и внеочередным исполнением: там очень большую роль играет стратегия использования кэша. Скажем, у мэйнфреймов любое прерывание вызывает т.н. сериализацию ("временную отмену совмещений", как её переводили в советской литературе), в результате чего, по сути, кэш очищается (все изменения, внесённые программой, выполнявшейся до прерывания, записываются в память, а все ранее выбранные данные аннулируются, заставляя в дальнейшем сначала выбирать их из памяти). Соответственно, любые данные, попавшие в кэш в результате спекулятивного выполнения, в случае прерывания будут благополучно "забыты" -- а, если мне память не изменяет, Spectre был основан именно на таком сценарии (обращение к запрещённой области с последующим прерыванием и возобновлением работы -- но чужие данные уже в кэше). Хотя, возможно, с чем-то путаю, смотрел очень давно...
Kerman
Нет, в CISC вполне себе конвеер c i486 и какие-то команды могут исполняться в один и тот же такт на разных блоках (с пентиума про). Вот старая статья про них.
SIISII
Более того, и конвейер, и суперскалярность появились ещё на машинах 1960-х годов. У нас первой конвейерной машиной была БЭСМ-6 (1967 год), у американцев всё это появилось ещё раньше.
Fin_Debov Автор
Это да, но i486 является гибридом RISC и CISC, а в статье я говорил именно про момент появления RISC, когда у CISC ещё не было конвейеризации. Понятно, что позже, в погоне за RISC, CISC-подобные архитектуры начали задумываться о добавлении конвейеризации, и в последствии появился i486. Но спасибо за дополнение
SIISII
Если говорить про архитектуры (в первом приближении -- про системы команд), то никаким гибридом i486 не является -- самый натуральный (и плохой) CISC.
Если же говорить про внутреннее устройство, то, как я уже написал, конвейеризация появилась задолго до появления RISC, и одно с другим не связано от слова "совсем".
Kerman
Гибридом RISC и CISC был Cyrix 6x86 (M1) намного позже. У него было рисковое ядро и транслятор x86 в команды ядра. Вот статья.