Форум программистов, компьютерный форум, киберфорум
Процессоры
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 5.00/13: Рейтинг темы: голосов - 13, средняя оценка - 5.00
из племени тумба-юбма
 Аватар для мама Стифлера
2523 / 1819 / 419
Регистрация: 29.11.2015
Сообщений: 8,857
Записей в блоге: 15

О новом хайпе про уязвимость процессоров Intel

06.01.2018, 02:23. Показов 3584. Ответов 49
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Посмотрел давеча несколько роликов на Ютубе, про новую-"старую" уязвимость процессоров Intel и AMD. И не совсем до конца понял про похищение данных из кеша процессоров. А точнее, совсем не понял при каких моих действиях эти данные могут быть похищены. Понял только, что процессоры работают по особому алгоритму угадывания, загружая наперед данные в свою кеш память. И если вдруг эти данные оказались не востребованы на текущий момент, то они могут быть легко похищены злоумышленником.
Ну я как и большинство обычных людей пользуюсь онлайн-банком, поэтому заинтересован в своей безопасности. Вот и спрашиваю, как можно защитить свои важные данные от похищения, если антивирусы даже тут бессильны?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
06.01.2018, 02:23
Ответы с готовыми решениями:

Хочу обсудить недавно "обнаруженную" "уязвимость" процессоров Intel и не только
Наверное, эту тему уже много где обсуждали. Возможно, я ошибся разделом - но, посмотрел тут на форуме - нигде нету похожей тематики. Тут уж...

Есть ли аппаратное различие процессоров INTEL с Hyper-threading и процессоров без него?
Всем привет, меня интересует такой вопрос. Есть ли аппаратное различие процессоров INTEL с Hyper-threading и процессоров без него?

Типы процессоров Intel
Подскажите, чем отличаются современные Atom, Celeron и Pentium. Просто всегда использовал процессоры семейств i3-i7, а тут нужно для...

49
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
09.01.2018, 23:56
Студворк — интернет-сервис помощи студентам
Как выбираются данные, я понял. Процессор до прерывания успевает считать "чужой" байт и использовать его значение как смещение для обращения к "своему" массиву. Массив частично кэшируется. Дальше его просматривают поэлементно, измеряя время обращения, и индекс с минимальным временем и будет тем самым байтом.

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

И даже если ядро ОС отображено в адресное пространство процесса, почему доступны все прочие процессы? Там же должна быть таблица страниц. Она, что, общая для всей системы?
0
 Аватар для Shargo
180 / 172 / 27
Регистрация: 22.12.2015
Сообщений: 1,176
Записей в блоге: 1
10.01.2018, 00:17
Цитата Сообщение от FizMat73 Посмотреть сообщение
Мне пофигу у меня linux old stable. Я специально обновляться не буду.
Добавлено через 11 минут
А вам я искренне сочувствую. Либо Win 7 ставить без обнов и рубаться в игры. Либо приобретать планшеты/смартфоны от нормальных ментейнеров. LG, samsung.

Ох уж эти линуксоиды...

Планшеты... виндовс 7.. как у вас всё плохо
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
10.01.2018, 09:25
Цитата Сообщение от nmcf Посмотреть сообщение
Evg, а как Meltdown обходит виртуализацию? В 32-битных системах образ приложения по одному и тому же внутреннему адресу загружается, как в таком случае предлагается читать чужую память, если значения налагаются?
Правильно работающий процессор должен запретить обращаться по "неправильным" адресам в память. Обращение по такому адресу должно вызывать слом. Проблема растёт из-за того, что внутри процессора есть спекулятивные операции. Таких операций в системе команд нет, но они есть во внутренней микрокодной начинке процессора, которая реализует "внешнюю" систему команд

Что есть спекулятивная операция? Поясню на простом примере на пальцах. Допустим, есть код

C
int x;
int *ptr;
if (длинное выражение)
  x = *ptr;
В "обычном" процессоре такой код отрабатывает простым способом. Сначала посчитается длинное выражение, после того, как станет ясно, true оно или false, далее уже либо выполнится либо не выполнится чтение из памяти. В итоге получится, что сначала будет 100 тактов вычисляться условие перехода, а затем ещё 100 тактов будет делаться чтение из памяти. Но это неэффективно. Чтение из памяти можно было бы сделать одновременно с тем, как считается условие перехода (т.е. можно сэкономить 100 тактов). Если условие окажется true, то результат подхватится, если false, то проигнорируется. Т.е. процессор переупорядочит и немного изменит порядок вычислений таким образом, что в реальности в машине будет выполняться вот такой код:

Code
1. load *ptr -> tmp_register (speculative mode)
2. вычисление длинного выражения -> predicat
3. if (predicat == true) x = tmp_register
Пункты 1 и 2 будут выполняться одновременно. При этом пункт 1 мы выполняем заранее, не зная того, должен ли он вообще выполняться. Если в ptr записан кривой адрес, то обращение по нему должно сломаться. Но если значение выражения есть false, то при "нормальном" исполнении чтения памяти не было бы, а потому кривой указатель не привёл бы к поломке программы. Чтобы расплетать подобные проблемы, в процессор вводится спекулятивный режим исполнения операций. В этом режиме исполняются все операции, которые выполняются заранее, когда ещё не известно, должна ли операция выполняться. Спекулятивно исполняемые операции НЕ ломаются в момент исполнения. Если они вдруг должны были сломаться (типа обращения по некорректному адресу или деление на ноль), то этот факт отмечается в регистре tmp_register, он помечается специальным маркером, который говорит, что регистр содержит дефектное значение, выработанное операцией, которая должна была сломаться. Далее при исполнении пункта 3 если условие оказалось true, то произойдёт слом при чтении регистра с дефектностью, но если условие окажется false, то ничего не произойдёт

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

Добавлено через 4 минуты
Цитата Сообщение от nmcf Посмотреть сообщение
И даже если ядро ОС отображено в адресное пространство процесса, почему доступны все прочие процессы?
Потому что ошибка в процессоре. При определённых условиях защита адресного пространства не отрабатывает. Т.е. на уровне исполнения кода защита есть, но при этом осталась дыра в виде попадания данных в кэш
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
10.01.2018, 09:45
Я понял про защиту. Но адреса в программе виртуальные. В Windows 32bit образ почти любого приложения начинается с 0x00400000, адреса области данных и стека тоже совпадают. Как в таком случае адресовать из одного процесса другой?
Цитата Сообщение от Evg Посмотреть сообщение
При определённых условиях защита адресного пространства не отрабатывает.
Защита не отрабатывает, но чтобы получить данные, нужно преобразовать виртуальный адрес в физический, а для этого нужно, чтобы в таблице страниц была запись для соответствующего участка. Я почему-то думал, что у каждого приложения своя таблица страниц, и те участки, которые через неё не отображены, в принципе не доступны из-за невозможности вычислить адрес.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
10.01.2018, 10:07
Цитата Сообщение от nmcf Посмотреть сообщение
Я понял про защиту. Но адреса в программе виртуальные. В Windows 32bit образ почти любого приложения начинается с 0x00400000, адреса области данных и стека тоже совпадают. Как в таком случае адресовать из одного процесса другой?
Через таблицу виртуальных адресов. Но кэш работает по физическим адресам

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

Т.е. логически процессор отрабатывает корректно на уровне системы команд. Но кэш по смыслу к системе команд не относится и является особенностью внутренней реализации процессора. С точки зрения системы команд операция чтения по чужому адресу НЕ отработала, но с точки зрения внутренней реализации процессора она всё-таки отработала, оставив след в кэше. Видимо, потом этот след как-то извлекают

Добавлено через 31 секунду
Это не 100%, я просто общий смысл вижу примерно так
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
10.01.2018, 10:36
Это работало бы, если бы все адреса были разные, но доступ к чужим был бы закрыт. А здесь каждый процесс пользуется одним и тем же набором адресов. Может, Meltdown не работает в 32-битных системах?

Не по теме:

Эх, жаль, нет Убеждённого. Он-то должен знать.

0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
10.01.2018, 12:35
Цитата Сообщение от nmcf Посмотреть сообщение
А здесь каждый процесс пользуется одним и тем же набором адресов
А что от этого меняется?

Допустим, процесс1 и процесс2 работают в диапазоне виртуальных адресов 0 - 999 (с абстрактными 10-чными числами проще воспринимать). Допустим, процесс1 лежит в памяти по физическим адресам 500000 - 500999, а процесс2 - по адресам 501000 - 501999. Т.е. виртуальная адресация в обоих процессах одинаковая, но физическая разная

Теперь в 1-м процессе делают обращение по адресу 1000. Такую операцию процессор отлупит, потому что она вываливается за диапазон виртуальных адресов (0-999). Но со спекулятивной операцией до того, как случился отлуп, судя по всему, происходит реальное обращение по физическому адресу, которое вычисляется через таблицу (очень грубо в виде "начальный физический адрес + виртуальнай адрес"), т.е. по адресу 500000 + 1000 = 501000, что попадает в диапазон физических адресов 2-го процесса. Т.е. внутри процесса1 обращение по такому адресу не сломается (т.к. оно спекулятивное), возможно значение в регистре и не совпадёт с тем, что реально находилось по этому адресу, но в кэше значение по этому адресу застрянет и его как-то оттуда можно извлечь, находясь в процессе1

Если я правильно понял
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
10.01.2018, 13:08
Цитата Сообщение от Evg Посмотреть сообщение
которое вычисляется через таблицу
Т. е. таблица едина для всей системы? Как тогда происходит трансляция одного и того же 0x00400000 в разные физические адреса?
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
10.01.2018, 13:32
Вот тут какие-то исходники выложили https://github.com/paboldin/meltdown-exploit

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

В программе в функции readbyte находится основной цикл. Функция clflush_target выполняет чистку кэша. Функция speculate что-то делает, точно не могу сказать что, ибо интеловскую систему команд почти не знаю. Там делаются два чтения из памяти, одно из адреса, подсунутого параметром (т.е. запретного), другое - из собственного массива target_array. По логике при обращении к запретному адресу программа должна словить сигнал SIGSEGV, далее он ловится в обработчике (функция sigsegv), а там подменяется адрес возврата из обработчика сигнала на метку stopspeculate. Таким образом, после обращения по некорректному адресу завершается исполнение функции speculate. В функции check делаются обращения к массиву target_array и проверяется, чтение случилось из кэша, или из памяти. Информацию о результатах записывает в массив hist

Дальше я не совсем понял, как они извлекают информацию. Я этого в исходнике как-то не вижу. Проверка делается в цикле внутри main. Но как-то не коррелирует возвращаемое значение функции readbyte и искомая строка в переменной expected. Т.е. тут хотелось бы запустить вживую, но у меня нет root'овых правов, чтобы выудить нужный адрес. А методом тыка я просто общий принцип работы прикинул, но точной рыбалки так не получится

В итоге это программа демонстрирует наличие проблемы в процессоре. Но сам процесс рыбалки подразумевает, что заранее знают, по каким адресам искать, а главное - заведомо знают, что должны найти. Т.е. очень-очень-очень упрощённая модель. Чтобы из неё сделать что-то, что может воровать, нужно приложить титанические усилия. К тому же тут воруются только данные из ядра, т.е. данные считываются именно из собственного виртуального пространства. Эта программа НЕ демонстрирует, как украсть данные из чужого процесса

Добавлено через 1 минуту
Цитата Сообщение от nmcf Посмотреть сообщение
Т. е. таблица едина для всей системы?
Внутри одного процессорного ядра таблица едина (как и регистры). Таблица заполняется при переключении на каждый пользовательский процесс. Т.е. процесс1 работает с одним содержимым таблицы, а процесс2 - с другим. Т.е. этот момент ничем не отличается от работы с обычными регистрами
0
 Аватар для nuworo
517 / 410 / 66
Регистрация: 03.08.2016
Сообщений: 1,623
10.01.2018, 20:01
Microsoft выпустила обновление Windows и убила компьютеры
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
10.01.2018, 21:57
Цитата Сообщение от Someone007 Посмотреть сообщение
Spectre example code
Смысл данного кода, судя по всему, не в том, что он демонстрирует процесс воровства, а в том, что это принципиально возможно. В функции victim_function воткнут код, который работает с массивом array2. При некоторых значениях переменной x должен случиться выход за границу массива. В коде всё это накрыто проверкой допустимости значения x, но в реальности аппаратура обращение в память будет исполнять спекулятивно до того, как выполнится реальная проверка на корректность, т.е. всё-таки делать реальные обращения в "чужой" адрес. В цикле, идущем после цикла с вызовом victim_function, делается подсчёт того, сколько элементов массива оказались в кэше. Далее идёт какая-то хитрая математика над подсчитанными значениями и каким-то образом на основании количества cache hit'ов они вычисляют, какие реальные значения находились по адресам, находящимся вне "законного" диапазона. Т.е. какие значения были считаны спекулятивными операциями, которые процессор должен был отлупить (или реально отлупил) на основании того, что результат спекулятивного чтения содержит дефектность

Другими словами, хитро..ыми анализами наличия тех или иных данных в кэше, вычисляется значение в памяти, в которую не было прямых обращений. Т.е. вычисляется значения считанных данных в функции victim_function в тех случаях, когда x >= array1_size. Т.е. значения тех обращений в память, которые по логике программы не должны исполняться (т.к. накрыты проверкой условия), но которые аппаратура реально исполняет, но в спекулятивном режиме

Добавлено через 39 минут

Мне тут подкинули инфу

https://spectreattack.com/spectre.pdf
+ блог google project zero

Spectre attacks involve inducing a victim to speculatively perform operations that would not occur during correct program execution and which leak the victim's confidential information via a side channel to the adversary. This paper describes practical attacks that combine methodology from side channel attacks, fault attacks, and return-oriented programming that can read arbitrary memory from the victim's process. More broadly, the paper shows that speculative execution implementations violate the security assumptions underpinning numerous software security mechanisms, including operating system process separation, static analysis, containerization, just-in-time (JIT) compilation, and countermeasures to cache timing/side-channel attacks. These attacks represent a serious threat to actual systems, since vulnerable speculative execution capabilities are found in micropro-
cessors from Intel, AMD, and ARM that are used in billions of devices.

Код из поста #16 демонстрирует, что можно прочитать данные, НЕ обращаясь к ним непосредственно. Т.е. браузер, который предоставляет песочницу для всяких внешних кодов, логически всё делает правильно. Но из-за особенности реализации процессора, код, логически правильный с точки зрения песочницы (т.е. не имеющий реальных обращений куда нельзя), в реальности может прочитать данные внутри виртуальной памяти браузера, который внешнему коду читать не положено. Т.е. не прочитать, а вычислить, пользуясь магией с проверкой наличия данных в кэше, как это сделано в коде из поста #16. Например, это может быть пароль, находящийся в соседней вкладке браузера

Конкретно в браузерах проблему можно решить загрублением таймера

Добавлено через 1 час 13 минут
Для полноты картины ещё и это https://meltdownattack.com/meltdown.pdf

Конкретно со spectre, судя по всему, реальная опасность есть в местах, где исполняется внешний код в песочнице (типа браузеров). Т.е. в одной вкладке браузера работать с онлайн-банком, а во второй вкладке лазить по сомнительным сайтам. И это никак не зависит от операционной системы (виндовс или линукс)
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
11.01.2018, 13:56
Цитата Сообщение от Evg Посмотреть сообщение
Таблица заполняется при переключении на каждый пользовательский процесс.
Как тогда возможен доступ к памяти других процессов? Виртуальные адреса основных областей у процессов совпадают и всегда будет происходить чтение собственных данных. А если у каждого процесса в таблице есть области остальных процессов по другим адресам, то зачем так сделано?

Добавлено через 5 минут
Я к тому, что, может, проблема в архитектуре ОС, а не только в процессоре?
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
11.01.2018, 15:06
Цитата Сообщение от nmcf Посмотреть сообщение
Как тогда возможен доступ к памяти других процессов?
По ходу, я немного ошибся (об этом напишу ниже), но просто поясню логику своих размышлений

В посте #23 я написал, как работают спекулятивные load'ы. Т.е. выполняется load по некорректному адресу, и при этом аппаратура его не запрещает исполнять. Т.е. допустим у нас виртуальное пространство представляет собой единственную страницу с диапазоном 0-999 и она отмапирована на физические адреса 500000 - 500999. Т.е. в таблице страниц у нас написано, что виртуальная страница, начинающаяся на адрес 0 и имеющая размер 1000 отображена на физическую страницу 500000

Допустим, мы хотим выполнить load из виртуального адреса x. Что делает аппаратура (в нашем примитивном случае):
1. Выясняет, в который из диапазонов виртуальных адресов попадает x. В нашем случае это единственный диапазон, начинающийся с адреса 0
2. Проверяет, что значение x влезает в диапазон виртуальных адресов 0-999. Т.е. x должен быть меньше 1000, если это не так, то нужно выдать ошибку
3. Проверяет, что данная страница памяти доступна для чтения, если это не так, то нужно выдать ошибку
4. Вычисляет физический адрес 500000 + x и делает к нему обращение

Суть ошибки процессора в том, что для спекулятивных load'ов он выполняет пункт 4 до того, как выполнит пункты 2 или 3, т.к. спекулятивный load не должен выдавать ошибку. Такой подход позволяет ускорить работу. Т.е. сначала отправить запрос на чтение данных, а пока данные читаются, заниматься выяснением того, правомерно ли обращение к данным. Если правомерно, то всё хорошо, у нас уже операция чтения выполняется. Если неправомерно, то результат чтения надо отменить. Как это реализовано технически, не принципиально, я писал о том, что регистр помечается дефектным значением (чтобы операции потребители знали об этом и смогли сделать отложенную ошибку). Возможно, делаются ещё какие-то телодвижения. Но при этом корень проблемы остаётся - аппартура load всё-таки выполнила и данные в кэш попали. Да, результат чтения отменяется, прочитанное значение будет недоступно, но кэш в этом месте НЕ вытравливается. Т.е. прочитанные данные в кэше всё-таки застряли, хотя напрямую и не доступны

Моя ошибка заключалась в том, что я исходил из того, что п.4 выполняется раньше или одновременно с п.2 и с п.3. По ходу в реальности дело обстоит так, что п.4. выполняется раньше или одновременно только с п.3, но п.2 выполняется до того, как уйдёт запрос в память. Т.е. в память чужого процесса залезть всё-таки нельзя, но в память ядра залезть можно, потому что ядро находится в том же виртуальном пространстве, что и пользовательский процесс. Эту возможность демонстрирует исходник, ссылка на который приведена в посте #29

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

Добавлено через 5 минут
Цитата Сообщение от nmcf Посмотреть сообщение
Я к тому, что, может, проблема в архитектуре ОС, а не только в процессоре?
Проблема именно в процессоре. Архитектура ОС (да и здравый смысл) предполагает, что чтение по запрещённому адресу будет проходить в определённом порядке: процессор сначала проверит, что такое обращение допустимо и только потом его исполнит. Т.е. это логический порядок выполнения. Реальный порядок отличается от логического (сначала выполняется обращение, а потом проверяется его законность), но внешне создаётся видимость того, что логический порядок был сохранён. Последствием отличия между логическим и реальным порядком действий является только то, что изменяется состояние кэша. Т.е. если бы действия выполнялись согласно логическому порядку, то состояние кэша было бы одно. Но реально действия выполняются в другом порядке, а потому состояние кэша другое. А на уровне системы команд видимость логического порядка остаётся: программа ловит прерывание, там где нужно, значение в регистре такое, какое нужно и т.п.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
13.01.2018, 23:26
Попробую пояснить базовый принцип уязвимости на простом примере. Для простоты я буду полагать, что кэш работает с точностью до одного байта, в то время как в реальности кэш работает с точностью до cache line (это величина 32, 64, 128 байт или что-то типа того)

Проблема тут по сути трёхуровневая

--------

1 уровень (не знаю, как эта уязвимость называется)

Рассмотрим простой код

C
char secret_key[16]; /* закрытые данные */
char user_data[256]; /* доступные снаружи данные */
 
/* "хорошая" функция */
char foo (size_t param)
{
  char index = secret_key[param & 0xf]; /* "param & 0xf" заведомо попадает в диапазон 0-15 */
  char res = user_data[(size_t)index];
  return res;
}
То, что здесь делается, представляет по своей сути двухэтажное обращение в память. Т.е. сначала делается обращение к массиву secret_key с индексом param, а затем прочитанное значение используется в качестве индекса для обращения в массив user_data

Полагаем, что функция foo - "хорошая", т.е. является законным куском некоей софтины. Массив secret_key является секретными данными, которые не положено видеть снаружи (например, пароль для шифровальщика). Массив user_data является куском данных, доступным для обращения снаружи этого кода, в том числе и из "плохой" функции, которая пытается провести атаку. В реальной жизни массив user_data скорее всего будет выглядеть как указатель на буфер, который передан в функцию foo в качестве параметра, и в который функция foo записывает результирующие (зашифрованные) данные. Предполагается, что пароль, записанный в массиве secret_key, снаружи от "хорошей" функции не доступен. Задача "плохого" кода состоит в том, чтобы, вызывая функцию foo и работая с массивом user_data, украсть данные, записанные в массиве secret_key

Метод атаки на эту функцию выглядит следующим образом

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

Следующим этапом вызывается вызов функции foo с параметром, например 12. После выполнения оператора "index = secret_key[param & 0xf]" в переменной index будет записан 12-й элемент массива secret_key, т.е. 12-й байт секретного пароля, который требуется украсть. Допустим, в secret_key[12] было записано значение 135. Далее при выполнении оператора "res = user_data[index];" в кэш попадёт элемент массива с индексом, соответствующий значению 12-го байта секретного пароля. Т.е. элемент user_data[135] окажется в кэше. После чего функция foo завершится

Далее "плохая" функция по очереди прочитает все элементы массива user_data и измерит время чтения. Все элементы, кроме user_data[135] в кэше будут отсутствовать, а потому время чтения будет долгим (условные 100 тактов). А вот элемент user_data[135] будет присутствовать в кэше, а потому прочтётся за 3 такта. Таким образом, "плохая" функция выясняет, что secret_key[12] равно 135. Выясняется это без прямого обращения к массиву secret_key, а только на основании коссвеного следа в кэше, который оставляет функция foo при своей работе

Так выглядит базовая часть уязвимости. Эта проблема по сути дела появилась вместе с появлением кэша, т.е. очень и очень давно. Точно так же она известна давно. Но эта проблема по большому счёту никому не мешала, т.к. у неё есть очень много "если". Атакуемая функция должна содержать двухэтажные обращения в память. В качестве первого этажа обязательно должны быть секретные данные, которые интересно украсть. В нашем примере мы исходили из того, что кэш работает с точностью до одного байта, в реальности кэш работает с точностью до cache line'а. Т.е. второй этаж обращения в память должен выглядеть что-то типа "res = user_data[index * 256]", чтобы можно было отличить следы в кэше, оставленные разными значениями index. На уровне того, как реально пишется софт, такому шаблону отвечает практически единственные алгоритмы - алгоритмы шифрования, причём далеко не все, и даже возможно, только какие-то отдельно взятые. При этом реальные функции выглядят намного сложнее, чем наша примитивная функция foo. В нашем примере мы воровали данные из собственного адресного пространства. В реальности если бы "плохая" функция могла бы напрямую вызывать "хорошую" функцию, то ей было бы проще украсть данные напрямую, вычислив адрес в памяти массива secret_key. Такие варианты не рассматриваются вообще, т.к. это по сути дефект проектирования софта, а не аппаратная проблема, т.е. к обсуждаемому вопросу не относятся. Т.е. область реального применения аппаратной уязвимости сужается ещё больше. Это может быть по сути дела только код, запускаемый в некоей песочнице типа того, как браузер запускает всякие сторонние java-script'ы и прочий активный контент web-страницы

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

--------

2 уровень. Соответствует уязвимости Spectre

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

Но в какой-то момент появился следующий уровень опасности, связанный с тем, что в процессорах, работающих с out-of-order исполнением коде в совокупности с предсказателями переходов, появились некоторые неприятные побочные эффекты

C
char open_key[16]; /* теперь тут уже нет секретных данных */
char user_data[256]; /* доступные снаружи данные */
char secret_data[1024]; /* а где-то тут лежат интересующие нас данные, которые вообще в функции foo не используются */
 
/* "хорошая" функция */
char foo (size_t param)
{
  char index, res;
  if (param >= 0 && param < 16)
  {
    char index = open_key[param]; /* тут мы уже проверили, что param попадает в диапазон 0-15 */
    char res = user_data[(size_t)index];
    return res;
  } else
  {
    return -1;
  }
}
Тут интерес представляет проверка значения param с последующим двухэтажным обращением в память. Я уже об этом писал в посте #23, но вкратце повторюсь, чтобы вся информация была в одном месте

В современных процессорах есть возможность out-of-order исполнения операций. Чтобы этот механизм проскакивал через операции условного перехода, в процессорах есть ещё предсказатель переходов. Предсказатель можно натренировать так, что он будет предполагать, что вероятнее всего значение param окажется в нужном диапазоне. Тогда механизм out-of-order в выполнит операции внутри альтернативы then нашего кода (т.е. двухэтажное чтение) ДО того, как реально будет вычислено значение условия "param >= 0 && param < 16". Если выяснится, что условие "истина", то всё хорошо, к этому моменту операции чтения либо уже отработают, либо уже находятся в процессе исполнения, что экономит время. Если же выяснится, что условие "ложь", то ненужные операции, которые поставил на исполнение out-of-order, попросту отменятся

Метод атаки выглядит практически таким же образом, как и в "1 уровень". Для начала функция foo вызывается с "хорошим" значением параметра, при котором условие перехода будет "истина" (например, со значением 0). Когда код несколько раз подряд в одном и том же переходе прошёлся по одной и той же альтернативе, то предсказатель переходов при последующем исполнении этого же места будет делать предположение, что скорее всего условие перехода будет таким же, а потому скорее всего исполнение пройдёт по этим же самым веткам кода

Затем функция foo вызывается с "плохим" параметром, т.е. со значением, выходящим за размерность массива open_key. Можно подсунуть значение, например, 16+256+12. Что при этом произойдёт? Процессор поставит на исполнение вычисление условия "param >= 0 && param < 16". Предсказатель переходов скажет, что скорее всего условие будет "истина". Не дожидаясь, пока вычислится условие, механизм out-of-order, опираясь на предсказатель переходов, поставит на исполнение операции "index = open_key[param]" и "res = user_data[(size_t)index]". Операция "index = open_key[param]" для значения param равного 16+256+12 прочитает данные со смещением 16+256+12 от начала массива open_key, таким образом, прочитав значение secret_data[12], которое, например, равно 135. Далее операция "res = user_data[(size_t)index]" подкачает в кэш элемент массива user_data[135]. Ну а в конечном итоге вычислится условие перехода, оно окажется ложным, результаты работы операций чтения отменятся, но подгруженный в кэш элемент user_data[135] так и останется сидеть в кэше. Ну а дальше аналогичным образом проверяется время доступа ко всем элементам массива user_data, выяснится, что secret_data[12] равно 135. Т.е. "плохой" код смог вычислить значение данных, вообще никак в этом фрагменте кода не присутствующих

Таким образом, мы здесь имеем по большому счёту то же самое, что и в "1 уровень", но с одним очень важным отличием. В "1 уровень" мы могли таким образом выяснить только значение конкретного массива secret_key. Здесь же мы можем выяснить значение из любого адреса внутри текущего адресного пространства. Т.е. прочитать абсолютно любые данные, доступные текущему процессу

Уязвимость Spectre, как и "1 уровень", по своей сути не излечима. Её можно было бы излечить, удалив out-of-order исполнение операций чтения из памяти. Но это точно так же вернёт человечество в каменный век. Потому что именно out-of-order исполнение операций чтения из памяти даёт очень большой прирост к скорости исполнения. Вряд ли человечество согласится на такие жертвы. Системным образом эта проблема не исправляется. Аналогично решению из "1 уровень", пока всё идёт к тому, что исправляться будет пользовательский софт. Однако здесь область применение гораздо более широкая, потому как целью атак являются не только двухэтажные чтения, работающие с секретными данными на первом уровне, но гораздо более широкий спектр кодов c двухэтажными обращениями в память. Разработчикам песочниц придётся предпринимать какие-то усилия, чтобы сделать невозможным атаку изнутри исполняемого чужого кода. Одно из решений в лоб - сделать невозможным анализ времени исполнения операции чтения из памяти, чтобы невозможно было проверить, есть данные в кэше или нет. Другой вариант - построить двухэтажные обращения как-то по другому, чтобы они не оставляли в кэше откровенных следов, легко используемых для анализа

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

--------

3 уровень. Соответствует уязвимости Meltdown

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

Проблема растёт из того, что современные операционные системы для экономии памяти и ускорения работы помещают коды операционной системы в то же виртуальное пространство адресов, где находится код пользовательской задачи. При этом адреса, соответствующие кодам и данным операционной системы, закрываются для доступа из пользовательской задачи. Т.е. пользовательская задача не может залезть в данные операционной системы, несмотря на то, что они находятся в том же адресном пространстве. Однако в процессорах Intel есть ошибка. Те операции чтения из памяти, которые механизм out-of-order поставил на исполнение до вычисления условия перехода, не ломаются на исполнении, если они попадают в адреса, запрещённые для обращения. Другими словами, в вызов функции foo из "2 уровень" вместо параметра 16+256+12 можно подсунуть такое значение, которое попадает в адреса операционной системы и украсть оттуда какие-нибудь данные. Например, содержимое буфера ввода данных другого процесса, который содержит пароль. В отличие от "1 уровень" и "2 уровень", где проблему вызывал только код, запущенный из песочницы, здесь проблему вызывает в том числе и любой код, напрямую запущенный на машине

Эта проблема излечима. Несомненно, в будущих версиях процессора её исправят. В уже выпущенных процессорах проблема, судя по всему, НЕ чинится стандартными методами обновления микрокодной прошивки процессора через биос. Конкретно в моём понимании проблема находится на одном уровне с проблемами уязвимости в системном софте или операционной системе. Т.е. обычная дыра в безопасности. Её можно исправить через операционную систему - попросту не включать данные операционной системы в адресное пространство пользовательских задач, или включать только те данные, воровство которых не представляет интереса. Т.е. проблема лечится системными методами, просто нужно вовремя сделать обновления операционной системы
0
365 / 124 / 22
Регистрация: 08.01.2015
Сообщений: 1,418
Записей в блоге: 2
14.01.2018, 22:59
Цитата Сообщение от Evg Посмотреть сообщение
браузеров, которые позволяют исполнять на машине сторонний код
Однако, этот сторонний код не будет иметь доступа к файловой системе (за исключением localStorage, куки и выбора файла для отправки). В последнем случае требуется явное разрешение пользователя. В первых двух - данные считаются только для открытой в окне страницы. Чужие данные считаны не будут.
Ну, или java-апплеты, которые должны быть. опять же, явно разрешены пользователем.

Добавлено через 10 минут
Цитата Сообщение от Evg Посмотреть сообщение
Эта проблема по сути дела появилась вместе с появлением кэша, т.е. очень и очень давно
Именно.
Цитата Сообщение от Evg Посмотреть сообщение
здесь проблему вызывает в том числе и любой код, напрямую запущенный на машине
Вы, по сути, ведете речь об обычном переполнении, которое известно еще, пожалуй, с IBM 286 или даже раньше.
Однако, все-таки на машине в подобном случае (уже лет 20 как с лишним) возникает ошибка сегментации. Стало быть, нет никакой СОВРЕМЕННОЙ проблемы, озвученной для Intel. Это то - что было давно известно и раньше. Если программа сделана так, что не допускает переполнения, данная "уязвимость" не страшна.

Добавлено через 6 минут
Цитата Сообщение от мама Стифлера Посмотреть сообщение
новую-"старую"
Ключевое тут - второе слово. Правда, я так и не понял - зачем шумиху-то подняли. То, что программа может брать данные из области памяти другой программы - так это (переполнение) давно известно и использовалось хакерами при взломе некорректно написанных программ.
0
дивананалитикаиксперд
 Аватар для K2K
15985 / 10990 / 914
Регистрация: 08.01.2013
Сообщений: 39,480
14.01.2018, 23:06
Еще какую-то дыру в AMT нашли. Но все опять ссылается к тому, что необходим физический доступ к устройству. Так собсна любое можно поломать и это лишь вопрос времени.
Вообще, все это отчасти напоминает старую страшилку про заражение биос вирусней, когда все боялись, но никто так и смог заразить. Ну, не считая там пары товарищей, которым опять же потребовался физический доступ к устройству.
0
157 / 300 / 47
Регистрация: 14.08.2012
Сообщений: 2,578
14.01.2018, 23:18
Evg, В общем итоге получается, что уязвимость существует, уязвимость можно использовать, но при условие, что знаешь что и где искать. А при условие случайности данных, а так же случайности адресов в условиях постоянного перемешивания памяти ядром системы - мы получаем полноё отсутствие смысла в использование такой уязвимости при удалённой атаке для получения конкретных данных. Это что получается, я прав и вся шумиха впустую? Информацию можно достать, но она будет скорее случайной, чем конкретной.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
14.01.2018, 23:52
Цитата Сообщение от саша40 Посмотреть сообщение
уязвимость можно использовать, но при условие, что знаешь что и где искать
Да, так и есть. Однако в мире много исходников с открытым кодом. А потому где и что искать - это уже известно. В частности, глядя на исходники браузера можно понять, по каким адресам будет лежать буфер с введённым паролем. Основная масса пользователей скачивают браузеры в бинарном виде, а не сами из исходников собирают. Т.е. информация о том, в какой версии браузера в каких адресах нужно рыбачить - это статическая заранее известная информация, в соответствии с тем, как распространяется браузер в виде готовых сборок

Цитата Сообщение от саша40 Посмотреть сообщение
Это что получается, я прав и вся шумиха впустую?
Как сказать... уязвимость вполне реальная. А шумиха, думается, вызвана вовсе не тем, что нашли очередную уязвимость (коих каждый год находят десятками и сотнями), а тем, что уязвимость не в софте, а в железе. И хуже того, уязвимость неизлечима. И это означает, что разработчики софта постоянно должны держать в голове и помнить про подобные дыры в железе. Если бы spectre можно было починить в железе или в операционке, то исправление по сути находилось бы в руках одной компании. А тут получается так, что ответственность за программных обход проблемы возлагается на разработчиков софта, размазанных по всему миру, а потому надёжность исправления потенциально снижается. Фиг знает, может быть возможно такие вещи надёжно отловить из антивирусов. С одной стороны проблему создаёт то, что атакующий код не выполняет никаких действий, которые формально бы выглядели как вредоносные. С другой стороны вредоносный код должен замерять времена обращения в память, а 99.99% софта подобных кодов не содержит. Т.е. антивирусы скорее всего без проблем должны распознавать такие атаки

Цитата Сообщение от K2K Посмотреть сообщение
Но все опять ссылается к тому, что необходим физический доступ к устройству
Хрень типа javascript'ов, массово растущая из браузеров, в общем-то и предоставляет доступ к устройству. Т.е. браузер скачивает чужой код и запускает на машине. Правда код исполняется в песочнице, а потому разработчики браузера должны уметь его прикрыть. Но есть опасность, что рано или поздно за чем-нибудь не углядят

Несколько особняком находится Meltdown. Это откровенная дыра в процессоре. Я не специалист по проектированию процессоров, но меня очень сильно удивляет, как можно было допустить такой косяк, а потом в течение нескольких лет его не замечать. Проблема, которую я описал как "1 уровень", известна очень давно, инженеры-железячники должны были об этом знать. Вариант целенаправленно оставленной дыры мог бы всё объяснить. Причём вполне возможно, что изначально это была обычная ошибка проектирования, которую довольно быстро обнаружили, но по понятным причинам порешили, что надо бы сделать вид, что её пока ещё не нашли

Добавлено через 4 минуты
Цитата Сообщение от саша40 Посмотреть сообщение
А при условие случайности данных, а так же случайности адресов в условиях постоянного перемешивания памяти ядром системы - мы получаем полноё отсутствие смысла в использование такой уязвимости при удалённой атаке для получения конкретных данных
Не совсем так. Когда программа распространяется в виде бинарника, то известно, что из себя представляют данные. Пусть данные и будут располагаться по рандомному адресу, но когда заранее известно, что где-то в памяти должна лежать определённая последовательность байтов, то просканировав память можно эту последовательность найти, а это уже позволит узнать, каким было рандомное значение адреса. Т.е. эта техника просто усложняет жизнь атакующему коду, но усложняет количествено, а не принципиально. Атакующему коду может понадобиться несколько минут на то, чтобы выяснить, в каких адресах надо рыбачить, а этого времени может оказаться достаточным для того, чтобы пароля в памяти уже и не оказалось. Но это не есть полноценный метод решения
0
дивананалитикаиксперд
 Аватар для K2K
15985 / 10990 / 914
Регистрация: 08.01.2013
Сообщений: 39,480
15.01.2018, 01:00
Цитата Сообщение от Evg Посмотреть сообщение
а потом в течение нескольких лет его не замечать.
Может, просто скрывать. Нам ведь дают только ту инфу, которую считают нужной для масс и дают когда нужно. Очень удобно манипулировать прикрываясь, что сами только узнали, а вы теперь жди и покупайте новые, не дырявые процы для мельдония, но в них найдется что нить другое и так по кругу.
Сама винда - одна большая дыра которую постоянно латают. Я сто лет как забил на все обновления. Ставлю только крайнюю версиею винды, если таки вынуждают на нее переходить.
0
365 / 124 / 22
Регистрация: 08.01.2015
Сообщений: 1,418
Записей в блоге: 2
15.01.2018, 09:25
Цитата Сообщение от Evg Посмотреть сообщение
типа javascript'ов, массово растущая из браузеров, в общем-то и предоставляет доступ к устройству.
Вы лжете даже не оглядываясь. JS по определению неспособен осуществлять доступ к устройству (про исключения см. выше). Я выше уже писал об этом. В ветку javascript загляните здесь на форуме, что ли.
Собственно, теперь мне становится понятнее, ОТКУДА пошли разговоры про "уязвимость".

Добавлено через 9 минут
И дело тут, повторюсь, вовсе не в разработчиках браузеров. А в том, что в JS отсутствуют функции доступа к файловой системе, за исключением (см. выше). Но, последнее находится под контролем пользователя или ограничено в месторасположении.

Добавлено через 3 минуты
Цитата Сообщение от Evg Посмотреть сообщение
Атакующему коду может понадобиться несколько минут на то, чтобы выяснить, в каких адресах надо рыбачить
))За это время содержимое памяти существенно изменится. Оно за секунды-то меняется хотя бы немного, не говоря уже о НЕСКОЛЬКИХ минутах. Пресловутому "атакующему коду" придется сканировать память постоянно.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
15.01.2018, 09:25

Тестирование процессоров AMD VS Intel
Чисто пользовательские тесты, многую синтетику будем выбрасывать сразу! особенно однопоточные, заточененые и старые Добавлено через 2...

Архитектура процессоров AMD и Intel
Подскажите ресурс в котором можно найти информацию об архитектуре процессоров от AMD и Intel начиная с самых первых моделей. Нужна...

Буквы в названиях процессоров Intel
Я знаю, что помимо стандартных процессоров есть ещё процессоры с различными буквенными коэффициентами P, S, K, M, T. К - разблокированный...

Производительность процессоров AMD и Intel
Здравствуйте, столкнулся с проблемой выбора процессора для домашней системы. Начал смотреть процессоры различных производителей. И заметил...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
Запись в регистр сведений независимо от заполненности табличной части
Maks 25.08.2026
Реализация из решения ниже выполнена на нетиповом документе с несколькими табличными частями, разработанного в КА2. Задача: Обеспечить запись документа в регистр сведений независимо от. . .
Ноутбук Альфария
kumehtar 24.08.2026
Встретился тут в сети ноутбук Альфария, примарха Альфа-Легиона. Хотя возможно, это ноутбук Омегона, разумеется. Ну как вам?
Мастера простых решений
DevAlt 23.08.2026
В сишарп стэках winforms, да и wpf существует сложная система связывания источниках данных и элементов формы(текстовые поля и метки), опирается все это на технологию событий и мета. . .
Цена ошибки
DevAlt 23.08.2026
Человек я беспокойный и потому заинтересовался OCaml, в чате форсили функторы модулей как суперфичу. Пытаясь отдуплить концепт, наткнулся на тутор с простым примером. А главный принцип обучения от. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru