Pull to refresh

Comments 17

Это все, безусловно, интересно. Указанные выше особенности пишутся один раз, или берутся готовыми вместе с RTOS/библиотекой/компилятором.


Думаю, что разработчику интереснее куда более простые, но насущные вопросы, а именно:


  1. Количество тактов на арифметические операции (о ужас, деление в несколько раз медленнее умножения!)
  2. Наличие аппаратных функций вычисления квадратного корня (vsqrtf.32), причем компилятор может и не захотеть его нативно использовать, отдав предпочтение программной реализации
  3. Время/инструкции на перегонку значений между FPU и ALU
  4. Возможность работы FPU параллельно с CPU

Так-то VFPv3 вполне хороший сопроцессор.


Кстати по поводу NEON — если я не ошибаюсь, он заявлен как несовместимый с IEEE-754. Не потому, что у него float другой, а просто он не отрабатывает все эти пограничные значения с бесконечностями и NaN как этого требует IEEE-754-совместимый FPU.


И размеры векторных регистров у A8 и A9 разные, если не ошибаюсь. Потому что у меня в коде был только float32x2

Указанные выше особенности пишутся один раз, или берутся готовыми вместе с RTOS/библиотекой/компилятором.

Позволю себе процитировать себя же из начала статьи
что мы и делали для Embox, в котором до этого использовалась программная реализация операций с плавающей точкой


Количество тактов на арифметические операции (о ужас, деление в несколько раз медленнее умножения!)

не уверен, что разработчику более интересно знать количество тактов, а не то как объяснить компилятору правильно использовать сопроцессор. То есть, это безусловно важно, но это из общей части работы с плавающей точкой.

Наличие аппаратных функций вычисления квадратного корня (vsqrtf.32), причем компилятор может и не захотеть его нативно использовать, отдав предпочтение программной реализации

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

Время/инструкции на перегонку значений между FPU и ALU

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

Возможность работы FPU параллельно с CPU

думал что и так понятно, что они работают пораллельно, ведь это сопроцессор, ну да, можно еще объяснить, что декодер из конвеера передает команду в следующее исполняющее устройство, но опять же, выходит за рамки статьи.

Так-то VFPv3 вполне хороший сопроцессор.

Правильнее говорить, что это стандарт, а реализации могут быть разными
VFPv3 — An optional extension to the Arm, Thumb, and ThumbEE instruction sets in the Armv7-A and Armv7-R profiles. VFPv3 can be implemented with either 32 or 16 doubleword registers. VFPv3U is a variant of VFPv3 that supports the trapping of floating-point exceptions to support code.


Кстати по поводу NEON — если я не ошибаюсь, он заявлен как несовместимый с IEEE-754.
Вы совершенно правы!

И размеры векторных регистров у A8 и A9 разные

конкретно с cortex-a8 и cortex-a9 не сталкивался, но как написано выше, зависит от реализации. в статье тоже есть ссылки, где при одной версии vfp разные реализации по регистрам.

Дурацкий вопрос: а если мы не сохраняем флоат-регистры в софте, то там же предыдущие значения от другой программы? Т.е. одна программа может получить доступ к float-регистрам другой программы. Кажется, как раз недавно пролетала CVE'шка подобного типа…

У ARM Cortex MxF действительно есть возможность ленивого сохранения контекста FPU. Там это оправдано по нескольким причинам:


  • Обычно 100% софта на микроконтроллере — доверенный код. Он записан во FLASH и так просто не меняется. Более того, МК обычно слишком маленькие, чтобы делать полноценную изоляцию окружений
  • Сохранение каждого регистра на стек — это, как минимум, еще один такт процессора, потраченный на переключение контекста. Посчитайте количество регистров в VFP и заметьте, насколько дольше у вас сразу станет обработка прерываний. К слову, математику в прерываниях обычно не делают
  • При включении Lazy FPU Storage при попытке доступа к FPU будет сгенерировано прерывание, которое попросит программный код осуществить выгрузку контекста FPU

А так по умолчанию контекст FPU сохраняется автоматически вместе с остальным состоянием процессора. Альтернативой этому является подход в других МК, к примеру, TI C2000, где автоматически сохраняются только самые нужные (вроде SP, PC), а за всеми остальными должен следить разработчик. Полезно это там, где больше одного-двух регистров прерыванию не нужны, а вот время реакции нужно сократить всеми возможными способами (вплоть до выделения отдельного банка регистров для обработчиков прерываний)

Процессор один на всех, контекст у каждого процесса свой. При переключении надо сохранять/восстанавливать контекст. Теоретически можно гонять не весь контекст, а только то, что реально надо процессу, но с одной стороны это утечки данных между процессами, да, но с другой — производительность.
Вопрос вовсе не дурацкий! Вы совершенно правы, потенциально это возможно. Мы хотели рассказать и об этом, но решили, что очень уж раздувается статья и мы можем утонуть в деталях.
Dima_Sharihin в принципе ответил на этот вопрос:
  • Назначение технологии не полного сохранения/востановления регистров — улучшение производительности. Но при этом происходит ухудшение безопасности.
  • Так же написано, что софт на микроконтроллере — доверенный код. Так вот уточню, что для Embox это касается не только кода микроконтроллеров. Предполагается, что использовать Embox целесообразно, если у вас есть система с заранее известной функциональностью. А принципы сборки и запуска ПО, гарантируют отсуствие стороннего (вредоносного) кода или потенциально небезопасного.
Я понимаю, что это не нужно однопользовательским системам, где весь софт доверенный и нет пользователей. Но если у нас есть привилегированный режим, значит, есть разделение прав, а значит, это уязвимость.
Дело не в множестве пользователей и не в разделении на уровни доступа, а в том, что весь код (все приложения, службы, библиотеки, драйвера) могут появиться в системе только на момент ее проектирования. То есть, нет возможности запустить код, который воспользуется этой уязвимостью. Даже если используются внешние скрипты обработка которых запрещена по умолчанию, но код самого интерпретатора есть на момент сборки и следовательно может быть просмотрен и проанализирован на предмет уязвимостей подобного рода.
То есть, если нет возможности установить новое ПО и запустить его на исполнение, то уровень угрозы сильно снижается.

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

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

Другое дело, что сильно снизить уровень угрозы, причем достаточно простыми методами.

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

Некая программа (процесс) оставляет на регистрах работу с ключами и при переключении другая программа их может прочитать, частично или полностью. Но как я уже сказал, ваша считывающая программа должна компилироваться Вами, то есть Вы сознательно включили в конечный образ либо не проверенную программу либо программу с известной функциональностью для считывания регистров. Тут я могу только оперировать к принципу языка Си, программист всегда прав.

Если речь идет о том, что современные системы очень сложны по функциональности и невозможно просмотреть весь код, то я отвечу, что принцип переиспользования кода, позволяет существенно снизить эту проблему. Если добавить к этому принцип ограничения функциональности, то есть, не добавлять всю потенциально требующуюся функциональность, а только минимально необходимую, то это еще уменьшит количество нужной для анализа информации, а следовательно и понизит уровень угрозы.
Обычная уязвимость в ПО, и вроде бы непривилегированный процесс от nobody уже читает регистры криптобиблиотеки соседнего приложения.
Процесс это слишком громко сказано для микроконтроллера)
В лучшем случае поток, для процессов уже требуется вирутализация памяти.
Но что бы этот поток создать, вам надо залезть в саму прошивку. Но с другой стороны если вы уже там то зачем такие выкрутасы?
Все таки уточню, что Embox с успехом может запускаться и на более мощьных платформах, в том числе и с виртуальной памятью. Но подход, когда делается единая прошивка, и нельзя обновить или установить одно приложение, сохраняется.
Это востребованно, например, берем роутер, или какое нибудь другое устройство с четко описанной функциональностью. В нем вам не нужно ставить приложения, но нужна довольно мощьная функциональность, которую микроконтроллер может не потянуть.
не важно, что он от nobody! Как процесс попал в систему? По нашей модели, его мог только разработчик добавить. То есть, это либо закладка, либо ошибка разработчика. Уровень угрозы определяет насколько тщательно выгребаются эти ошибки. Плюс, приложение которое используется в системе и содержит подобного рода ошибку, скорее всего заимствовано. Но тогда оно (приложение) должно знать в каком окружении его будут использовать, ну например, что передача управления поризошла от интерисующего процесса. А у нас это не возможно, у нас на этапе конфигурации определяются даже системные вызовы, все отстальные параметры также могут меняться.

Гм, кто считает криптографию на FPU? Вы же понимаете, что для просто перегонки данных из-в-FPU есть отдельные ассемблерные команды и вся целочисленная арифметика считается на других регистрах, сохранение контекста которых — обязательно на уровне архитектуры?


А если вы говорите про аппаратную изоляцию "секурных" и "несекурных" процессов, то за этим идите к ARM Cortex M23/M33, все, что было "до" предполагает, что все есть доверенное.
Ну или сконфигурируйте MPU на запрет записи конфигурации FPU для обычных процессов, запретите ленивую выгрузку контекста и проблема исчезнет сама собой.

Ну по идее для криптографии может использоваться SIMD, то есть тот же NEON, а он использует те же регистры.

Справедливо, да. В моем понимании FPU — это в первую очередь VFP, про NEON я забыл (потому что работаю чаще с М-серией, а не А-).

Sign up to leave a comment.