Spectre (уязвимость): различия между версиями

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
[отпатрулированная версия][непроверенная версия]
Содержимое удалено Содержимое добавлено
Нет описания правки
(не показаны 2 промежуточные версии этого же участника)
Строка 7: Строка 7:
== Значение ==
== Значение ==
Ошибка Spectre позволяет злонамеренным пользовательским приложениям, работающим на данном компьютере, получить доступ на чтение к произвольным местам {{не переведено3|Computer memory|компьютерной памяти|en}}, в том числе к памяти, используемой другими приложениями (то есть нарушить изоляцию памяти между программами). Атаке Spectre подвержены большинство компьютерных систем, использующих высокопроизводительные микропроцессоры, в том числе персональные компьютеры, сервера, ноутбуки и ряд мобильных устройств<ref>https://developer.arm.com/support/security-update</ref>. В частности, атака Spectre была продемонстрирована на процессорах производства корпораций [[Intel]], [[Advanced Micro Devices|AMD]] и [[ARM (компания)|ARM]].
Ошибка Spectre позволяет злонамеренным пользовательским приложениям, работающим на данном компьютере, получить доступ на чтение к произвольным местам {{не переведено3|Computer memory|компьютерной памяти|en}}, в том числе к памяти, используемой другими приложениями (то есть нарушить изоляцию памяти между программами). Атаке Spectre подвержены большинство компьютерных систем, использующих высокопроизводительные микропроцессоры, в том числе персональные компьютеры, сервера, ноутбуки и ряд мобильных устройств<ref>https://developer.arm.com/support/security-update</ref>. В частности, атака Spectre была продемонстрирована на процессорах производства корпораций [[Intel]], [[Advanced Micro Devices|AMD]] и [[ARM (компания)|ARM]].

== Описание реализации с использованием неверного предсказания условных переходов ==

Предположим, что фрагмент кода
<syntaxhighlight lang="c">
if (x < array1_size)
y = array2[ array1[ x ] * 256 ];
</syntaxhighlight>
является частью функции, получающей беззнаковое целое <tt>x</tt> из ненадежного источника, а процесс, выполняющий этот код, имеет доступ к массиву беззнаковых 8-битных целых <tt>array1</tt> размером <tt>array1_size</tt>,
и ко второму массиву беззнаковых 8-битных целых <tt>array2</tt> размером <tt>64кб</tt>.

Данный фрагмент начинается с проверки того, что значение <tt>x</tt> является допустимым. И эта проверка является существенной с точки зрения безопасности. В частности, она предотвращает чтение информации за пределами границ массива <tt>array1</tt>. В случае ее отсутствия, недопустимые значения <tt>x</tt> могут привести или к возникновению исключения, при попытке чтения данных за пределами доступной процессу памяти, или к чтению доступной процессу конфиденциальной информации путем задания <tt>x = &lt;адрес_секретного_байта&gt; - &lt;адрес_массива_array1&gt;</tt>.

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

Например, приведенный выше фрагмент кода может быть выполнен в следующих условиях:
* значение <tt>x</tt> выбрано выходящим за пределы границ массива <tt>array1</tt>, а значение <tt>array1[x]</tt> указывает на байт <tt>k</tt> секретных данных в памяти процесса-жертвы,
* значения <tt>array1_size</tt> и <tt>array2</tt> отсутствуют в кэше процессора, а секретный байт <tt>k</tt> находится в кэше,
* предыдущие обращения к данному фрагменту кода выполнялись с допустимыми значениями <tt>x</tt> (т.е. выполнялось условие <tt>x &lt; array1_size</tt>).
Такие условия могут возникать спонтанно, однако, могут быть и сформированы целенаправленно, например, путем чтения большого объема посторонних данных, с целью заполнения этими данными кэша процессора и, соответственно, выбивания <tt>array1_size</tt> и <tt>array2</tt> из кэша, а затем вызова функции ядра, задействующей секретный байт <tt>k</tt>, с целью помещения его в кэш.
Впрочем, если структура кэша известна, или же процессор добровольно предоставляет инструкцию обнуления кэша (например, инструкция <tt>cflush</tt> процессоров семейства [[X86|x86]]), то задача по созданию необходимых условий для выполнения фрагмента кода существенно упрощается.

Выполнение фрагмента кода начинается со сравнения значения <tt>x</tt> со значением <tt>array1_size</tt>. Чтение значения <tt>array1_size</tt> в описанных выше условиях приводит к промаху кэша, что в свою очередь приведёт к ожиданию, когда значение <tt>array1_size</tt> будет получено из оперативной памяти. Из-за наличия в процессоре механизма спекулятивного исполнения команд, в течение времени ожидания процессор не будет простаивать, а попытается выполнить одну из ветвей программного кода, следующего за инструкцией ветвления.

Т.к. предыдущие обращения к фрагменту выполнялись с допустимыми значениями <tt>x</tt>, то предсказатель ветвлений предположит, что и в этот раз предикат <tt>(x &lt; array1_size)</tt> окажется истинным, и процессор попытается выполнить соответствующую последовательность инструкций. А именно, он прочитает байт по адресу <tt>&lt;адрес_массива_array1&gt;+x</tt>, т.е. секретный байт <tt>k</tt>, который, благодаря сформированным специально условиям, уже находится в кэше. Затем, процессор использует полученное значение для вычисления выражения <tt>k * 256</tt> и чтения элемента массива <tt>array2[ k * 256 ]</tt>, которое приведет ко второму промаху кэша, и ожиданию получения значения <tt>array2[ k * 256 ]</tt> из оперативной памяти. В это время из оперативной памяти будет получено значение <tt>array1_size</tt>, процессор распознает ошибку предсказателя ветвлений, и восстановит свое состояние до выполнения неверной ветви программного кода.

Однако, на реальных процессорах спекулятивное чтение <tt>array2[ k * 256 ]</tt> повлияет на состояние кэша процессора, и это состояние будет зависеть от <tt>k</tt>. Для завершения атаки требуется лишь выявить это изменение, и основываясь на нем вычислить секретный байт <tt>k</tt>. Это легко осуществить, т.к. чтения элементов массива <tt>array2[ n * 256 ]</tt> будут выполняться быстро для <tt>n = k</tt>, и медленно для остальных значений.

== Использование неверного предсказания косвенных переходов ==

[[Косвенный_переход|Косвенный переход]] может использовать для ветвления больше, чем два адреса.
Например, инструкции процессоров семейства [[X86|x86]] могут выполнять переход, используя значение адреса в регистре (<tt>jmp eax</tt>), в памяти (<tt>jmp [eax]</tt>, или <tt>jmp dword ptr [0xdeadc0de]</tt>), или в стеке (<tt>ret</tt>). Инструкции косвенных переходов имеются также в процессорах [[ARM_(архитектура)|ARM]] (<tt>mov pc, r14</tt>), [[MIPS_(архитектура)|MIPS]] (<tt>jr $ra</tt>), [[SPARC|SPARC]] (<tt>jmpl %o7</tt>), [[RISC-V|RISC-V]] (<tt>jarl x0,x1,0</tt>), и многих других.

Если определение адреса косвенного перехода откладывается из-за промаха кэша, и [[Предсказатель_переходов#Предсказание_косвенных_переходов|предсказатель косвенных переходов]] &quot;натренирован&quot; с использованием специально подобранных адресов, может произойти спекулятивное исполнение команд по адресу, заданному злоумышленником. Команд, которые иначе никогда бы не были выполнены. Если такое исполнение оставляет измеримые [[Побочный_эффект_(программирование)|побочные эффекты]], то его использование становится мощным инструментом в руках атакующего.


== Патчи ==
== Патчи ==

Версия от 12:41, 5 января 2018

Логотип уязвимости

Spectre — аппаратная уязвимость в некоторых реализациях устройства предсказания ветвлений; утечка данных (чтение) через побочный канал. Затрагивает ряд современных микропроцессоров, реализующих Шаблон:Не переведено3,[1] в частности, архитектур х86/x86_64 и ARM. Ошибка позволяет локальным приложениям (локальному атакующему) потенциально получить доступ к содержимому виртуальной памяти других программ[2][3][4]. Угрозе присвоены два CVE-идентификатора: CVE-2017-5753 и CVE-2017-5715.

История

Spectre была обнаружена независимо исследователями североамериканской корпорации Google (проект Zero) и группой, сотрудничающий с Paul Kocher. Атака была обнародована 4 января 2018 года, одновременно с другой уязвимостью «Meltdown».

Значение

Ошибка Spectre позволяет злонамеренным пользовательским приложениям, работающим на данном компьютере, получить доступ на чтение к произвольным местам Шаблон:Не переведено3, в том числе к памяти, используемой другими приложениями (то есть нарушить изоляцию памяти между программами). Атаке Spectre подвержены большинство компьютерных систем, использующих высокопроизводительные микропроцессоры, в том числе персональные компьютеры, сервера, ноутбуки и ряд мобильных устройств[5]. В частности, атака Spectre была продемонстрирована на процессорах производства корпораций Intel, AMD и ARM.

Описание реализации с использованием неверного предсказания условных переходов

Предположим, что фрагмент кода

  if (x < array1_size)
    y = array2[ array1[ x ] * 256 ];

является частью функции, получающей беззнаковое целое x из ненадежного источника, а процесс, выполняющий этот код, имеет доступ к массиву беззнаковых 8-битных целых array1 размером array1_size, и ко второму массиву беззнаковых 8-битных целых array2 размером 64кб.

Данный фрагмент начинается с проверки того, что значение x является допустимым. И эта проверка является существенной с точки зрения безопасности. В частности, она предотвращает чтение информации за пределами границ массива array1. В случае ее отсутствия, недопустимые значения x могут привести или к возникновению исключения, при попытке чтения данных за пределами доступной процессу памяти, или к чтению доступной процессу конфиденциальной информации путем задания x = <адрес_секретного_байта> - <адрес_массива_array1>.

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

Например, приведенный выше фрагмент кода может быть выполнен в следующих условиях:

  • значение x выбрано выходящим за пределы границ массива array1, а значение array1[x] указывает на байт k секретных данных в памяти процесса-жертвы,
  • значения array1_size и array2 отсутствуют в кэше процессора, а секретный байт k находится в кэше,
  • предыдущие обращения к данному фрагменту кода выполнялись с допустимыми значениями x (т.е. выполнялось условие x < array1_size).

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

Выполнение фрагмента кода начинается со сравнения значения x со значением array1_size. Чтение значения array1_size в описанных выше условиях приводит к промаху кэша, что в свою очередь приведёт к ожиданию, когда значение array1_size будет получено из оперативной памяти. Из-за наличия в процессоре механизма спекулятивного исполнения команд, в течение времени ожидания процессор не будет простаивать, а попытается выполнить одну из ветвей программного кода, следующего за инструкцией ветвления.

Т.к. предыдущие обращения к фрагменту выполнялись с допустимыми значениями x, то предсказатель ветвлений предположит, что и в этот раз предикат (x < array1_size) окажется истинным, и процессор попытается выполнить соответствующую последовательность инструкций. А именно, он прочитает байт по адресу <адрес_массива_array1>+x, т.е. секретный байт k, который, благодаря сформированным специально условиям, уже находится в кэше. Затем, процессор использует полученное значение для вычисления выражения k * 256 и чтения элемента массива array2[ k * 256 ], которое приведет ко второму промаху кэша, и ожиданию получения значения array2[ k * 256 ] из оперативной памяти. В это время из оперативной памяти будет получено значение array1_size, процессор распознает ошибку предсказателя ветвлений, и восстановит свое состояние до выполнения неверной ветви программного кода.

Однако, на реальных процессорах спекулятивное чтение array2[ k * 256 ] повлияет на состояние кэша процессора, и это состояние будет зависеть от k. Для завершения атаки требуется лишь выявить это изменение, и основываясь на нем вычислить секретный байт k. Это легко осуществить, т.к. чтения элементов массива array2[ n * 256 ] будут выполняться быстро для n = k, и медленно для остальных значений.

Использование неверного предсказания косвенных переходов

Косвенный переход может использовать для ветвления больше, чем два адреса. Например, инструкции процессоров семейства x86 могут выполнять переход, используя значение адреса в регистре (jmp eax), в памяти (jmp [eax], или jmp dword ptr [0xdeadc0de]), или в стеке (ret). Инструкции косвенных переходов имеются также в процессорах ARM (mov pc, r14), MIPS (jr $ra), SPARC (jmpl %o7), RISC-V (jarl x0,x1,0), и многих других.

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

Патчи

В настоящее время не существует готовых программных технологий защиты от атаки Spectre, хотя ведется определенная работа. По данным веб-сайта, посвященному продвижению атаки, «Это не так легко исправить и она (ошибка) будет преследовать нас в течение длительного времени.»

См. также

Примечания

  1. Greenberg, Andy A Critical Intel Flaw Breaks Basic Security for Most Computers. Wired (magazine) (3 января 2018). Дата обращения: 3 января 2018.
  2. Staff. Meltdown and Spectre. Graz University of Technology (2018). Дата обращения: 3 января 2018.
  3. Metz, Cade; Perlroth, Nicole (January 3, 2018). "Researchers Discover Two Major Flaws in the World's Computers". The New York Times (англ.). ISSN 0362-4331. Дата обращения: 3 января 2018.
  4. Warren, Tom (January 3, 2018). "Intel's processors have a security bug and the fix could slow down PCs". The Verge. Дата обращения: 3 января 2018.
  5. https://developer.arm.com/support/security-update

Ссылки