Согласованность памяти требует, чтобы load uop получил значение, которое было недавно сохранено в целевой памяти. Следовательно, буфер порядка памяти (MOB) должен определять, перекрывает ли загрузка какие-либо ранние запоминающие операции в программном порядке. И буфер загрузки, и буфер хранилища имеют круглую форму, и каждая загрузка помечается идентификатором самого младшего хранилища, которое предшествует загрузке в программном порядке (распределитель знает идентификатор последнего хранилища, которое он выделил во время распределения нагрузки ). Это позволяет MOB правильно определить, какие хранилища предшествуют каким загрузкам.
Начиная с микроархитектуры Intel Core и микроархитектуры Goldmont, планировщик включает в себя логику спекулятивного устранения неоднозначности памяти (SMD), которая использует IP-адрес нагрузки, чтобы решить, следует ли разрешать распределение нагрузки вне очереди по отношению к STA Uops всех более ранних магазинов. Это похоже на то, как прогнозирование ветвлений использует IP текущего 16-байтового фрагмента, выбираемого для прогнозирования потока управления, за исключением того, что в этом случае IP используется для устранения неоднозначности памяти. Если в RS нет ожидающих STA или если все STA могут быть отправлены в том же цикле, что и загрузка, результат SMD игнорируется, а нагрузка отправляется. В противном случае, если SMD решит заблокировать нагрузку, планировщик отправляет нагрузку только тогда, когда все предыдущие STA были отправлены или будут отправлены в том же цикле, что и нагрузка. При некоторых загрузках SMD всегда блокирует загрузку в RS.
Когда диспетчер загрузки отправляется на один из портов AGU загрузки, эффективный адрес, то есть линейный адрес нагрузки, вычисляется с использованием заданной базы сегмента, операнда базового регистра, операнда регистра индекса, масштаба и смещения. В то же время в буфере хранилища могут быть хранилища. Линейный адрес загрузки сравнивается с линейными адресами всех более ранних хранилищ, чьи STA-операции были выполнены (т.е. доступен линейный адрес хранилища). Может также потребоваться сравнить также физические адреса, но физический адрес нагрузки на данный момент все еще недоступен (эта ситуация называется недействительным физическим адресом в патенте). Чтобы минимизировать наблюдаемую задержку загрузки, MOB выполняет быстрое сравнение, используя только 12 младших разрядов линейных адресов нагрузки и каждое более раннее хранилище. Для получения дополнительной информации об этом сравнении см. Пропускная способность памяти L1: снижение эффективности на 50% при использовании адресов, которые отличаются на 4096 + 64 байта (но маскированные мопы там не обсуждаются). Эта логика называется свободной сетью, и она составляет другую часть спекулятивного механизма устранения неоднозначности памяти. Свободная сеть поддерживается во всех микроархитектурах Intel начиная с Pentium Pro (включая Bonnell), но точная реализация изменилась из-за того, что увеличился размер данных, с которыми может работать одна загрузка или хранилище, и из-за введения замаскированные памяти мопс начиная с Pentium II. Параллельно с работой в свободной сети линейный адрес загрузки отправляется в TLB для получения соответствующего физического адреса и выполнения необходимых проверок атрибутов страницы, а также проверки сегментов.
Если загрузка не перекрывается с каким-либо более ранним хранилищем, адрес которого был известен во время отправки нагрузки в соответствии с результатом свободной сети, запрос на загрузку отправляется на L1D. Из уязвимостей RIDL мы уже знаем, что некоторые данные могут быть перенаправлены в MOB, даже не имея действительного физического адреса из TLB, но только в том случае, если загрузка вызывает ошибку или помощь. При пропуске TLB первого уровня загрузка блокируется в буфере загрузки, так что она пока не продолжает доступ к L1D. Позже, когда запрошенная запись страницы достигает TLB первого уровня, MOB информируется об адресе этой виртуальной страницы, которая, в свою очередь, проверяет все загрузки и хранилища, которые заблокированы на этой странице, и разблокирует их, воспроизводя мопы согласно наличие портов TLB.
Я думаю, что свободная сеть занимает всего один цикл, чтобы сравнить адрес данной загрузки с любым количеством хранилищ в буфере хранилища и определить самое младшее перекрывающееся хранилище, которое старше загрузки, если таковое найдено. Процесс поиска TLB первого уровня и предоставления физического адреса L1D при попадании должен занимать только один цикл. Вот как может быть достигнута максимальная задержка загрузки для использования в 4 цикла (что также требует (1) правильного определения адреса физической страницы, (2) режима адресации base + disp без индекса или с нулем индекс и (3) нулевой базовый адрес сегмента, в противном случае существует штраф как минимум за один цикл). Подробнее об этом см. Обсуждение в комментариях.
Обратите внимание, что если упущение нагрузки пропущено в свободной сети, можно сделать вывод, что нагрузка не перекрывает какое-либо предыдущее хранилище, но только в том случае, если STA всех более ранних выполнений уже выполнялись во время отправки нагрузочного задания. Это невозможно для двух линейных адресов, чьи младшие 12 бит отличаются друг от друга.
Если результат свободной сети показывает, что загрузка перекрывается с более ранним хранилищем, MOB выполняет две вещи параллельно. Одним из них является то, что процесс устранения неоднозначности в памяти продолжается с использованием точной сети (то есть полное сравнение линейных адресов). Если в тонкой сети пропущена нагрузка, физические адреса сравниваются при их наличии. В противном случае, если груз попадет в тонкую сетку, груз и магазин перекрываются. Обратите внимание, что ISA x86 требует использования полностью сериализованной инструкции после внесения изменений в структуру подкачки. Таким образом, нет необходимости сравнивать физические адреса в случае точного попадания в сеть. В дополнение ко всему этому, всякий раз, когда отправляется новый STA-моп, весь этот процесс повторяется, но на этот раз со всеми загрузками в буфере загрузки. Результаты всех этих сравнений объединяются, и когда нагрузка проверяется по всем более ранним хранилищам, конечный результат определяет, как правильно выполнить загрузку.
Параллельно MOB предполагает, что хранилище, попавшее в свободную сеть с грузом, имеет значение, которое должно быть перенаправлено в груз. Если загрузка и сохранение находятся на одной и той же виртуальной странице, тогда предположение верно. Если загрузка и сохранение выполняются на разных виртуальных страницах, но виртуальные страницы отображаются на одну и ту же физическую страницу, предположение также верно. В противном случае, если загрузка и сохранение выполняются на разных физических страницах, MOB испортился, что привело к ситуации, называемой псевдонимом 4K. Но подождите, давайте немного откатимся.
Может быть невозможно переслать данные хранилища в загрузку.Например, если загрузка не полностью содержится в хранилище, тогда он должен ждать, пока хранилище будет зафиксировано, а затем загрузке будет разрешено продолжить и получить данные из кэша.Кроме того, что, если STD моп магазина еще не выполнен (например, это зависит от мент с длительным временем ожидания)?Обычно данные передаются из буфера хранилища только тогда, когда выполнены требования для пересылки хранилища.Однако уязвимость MSBDS показывает, что это не всегда так.В частности, когда загрузка вызывает ошибку или помощь, буфер хранилища может пересылать данные в загрузку без выполнения каких-либо проверок пересылки хранилища.Из статьи Intel о MDS:
Возможно, что хранилище не перезаписывает все поле данных в буфере хранилища из-за того, что хранилище имеет меньший размер, чем ширина буфера хранилища, или нетвсе же выполнив часть данных магазина.Эти случаи могут привести к пересылке данных, которые содержат данные из более старых хранилищ.
Очевидно, что данные могут быть пересланы, даже если операция STD еще не была выполнена.Но откуда будут поступать данные?Что ж, поле данных записи буфера хранилища не очищается при освобождении.Размер поля данных равен ширине хранения данных, который можно определить путем измерения количества операций хранения, которое требуется для выполнения самой широкой доступной команды хранения (например, из регистра XMM, YMM или ZMM).Похоже, это 32 байта на Haswell и 64 байта на Skyake-SP.Каждое поле данных в записи буфера хранилища настолько велико.Поскольку он никогда не очищается, он может содержать некоторую случайную комбинацию данных из хранилищ, которые случайно были выделены в этой записи буфера хранилища.Когда нагрузка попадает в свободную сеть и вызывает сбой / помощь, данные ширины, заданные нагрузкой, будут перенаправлены на загрузку из буфера хранилища, даже не проверяя выполнение STD или ширину хранилища.Таким образом, нагрузка может получать данные из одного или нескольких хранилищ, которые, возможно, даже были переданы миллиардом инструкций назад.Подобно MLBDS, некоторые части данных или целые данные, которые передаются, могут быть устаревшими (то есть не принадлежать хранилищу, занимающему запись).
Эти данные фактически были предоставлены только Intel,не бумага Fallout.В статье авторы проводят эксперимент (раздел 4) на системах с отключенным KPTI (я объясню почему), но они не используют уязвимость Meltdown.Вот как работает эксперимент:
- Атакующий выполняет последовательность хранилищ, все из которых отсутствуют в иерархии кэша.Количество хранилищ, по крайней мере, равно количеству записей буфера хранилища.
- Вызывается модуль ядра, который выполняет последовательность хранилищ, каждое из которых имеет различное смещение на другой странице ядра.Сохраненные значения известны.Количество хранилищ варьируется от 1 до 50, как показано на рисунке 5. После этого модуль ядра возвращается злоумышленнику.
- Злоумышленник выполняет последовательность загрузок пользовательских страниц (отличается от страниц ядра).к таким же смещениям.Каждая пользовательская страница размещается только в виртуальном адресном пространстве и аннулирует разрешение на доступ (путем вызова
mprotect(...,PROT_NONE)
, помечая ее как Пользователь и Не присутствует).Таблица 1 показывает, что страница Supervisor, которой нет, не работает.Количество загрузок совпадает с количеством хранилищ, выполняемых модулем ядра.Загруженные значения затем просочились с помощью традиционной атаки FLUSH + RELOAD.
На первом шаге делается попытка сохранить буфер хранилища максимально занятым, чтобы отложить фиксацию хранилищ из модуля ядра. Помните, что переадресация ложного хранилища работает только для записей буфера в занятом хранилище Первый шаг работает, потому что магазины должны совершать заказы по порядку. На третьем шаге все, что имеет значение, это получить свободные попадания в сеть. Обратите внимание, что в этом эксперименте авторы не думали об утечке устаревших данных, они просто хотели получить данные из хранилищ ядра, которые, как мы надеемся, все еще находятся в буфере хранилища. При изменении текущего уровня привилегий все инструкции удаляются перед выполнением каких-либо инструкций на новом уровне привилегий. Хранилища могут быстро удалиться, даже до того, как запрос RFO завершится, но им все еще нужно ждать в буфере хранилища, чтобы зафиксировать их по порядку. Считалось, что таким образом наличие хранилищ с различными уровнями привилегий в буфере хранилища не является проблемой. Однако, когда злоумышленники начинают выполнять нагрузки, если хранилище с тем же смещением, что и загружаемая в данный момент нагрузка, все еще находится в буфере хранилища, происходит случайное попадание в сеть, когда данные (не устарели) спекулятивно пересылаются. Ты знаешь все остальное.
Когда KPTI включен, большинство страниц ядра живут в виртуальном адресном пространстве, отличном от пользовательских страниц. Таким образом, при возврате из модуля ядра ядро должно переключать адресные пространства, записывая значение в регистр CR3
. Но это операция сериализации, которая означает, что она остановит конвейер, пока не будут зафиксированы все хранилища (ядра). Вот почему авторам нужно было отключить KPTI, чтобы их эксперимент работал (т. Е. Буфер хранилища был бы пуст). К сожалению, поскольку у Coffee Lake R есть аппаратное смягчение для Meltdown, ядро Linux по умолчанию отключает KPTI на этом процессоре. Вот почему авторы говорят, что смягчение аппаратного обеспечения сделало процессор более уязвимым.
То, что описано в статье Intel (но не в статье), показывает, что MSBDS гораздо более опасен, чем это: сбой / вспомогательная нагрузка может привести к утечке и устаревших данных из буфера хранилища. В статье Intel также показано, что MSBDS работает через одноуровневые логические ядра: когда логическое ядро переходит в состояние сна, его записи буфера хранения, которые были статически выделены для него, могут стать доступными для другого логического ядра. Позже, если логическое ядро снова становится активным, буфер хранилища статически разбивается, что может позволить этому ядру вытекать устаревшие данные из его записей, записанных другим ядром.
Все это показывает, что включения KPTI недостаточно для смягчения MSBDS. Кроме того, смягчения, рекомендованного в статье в разделе 6 (очистка буфера хранилища с использованием MFENCE
при пересечении границы безопасности), также недостаточно. Надлежащее смягчение MDS обсуждается здесь .
Я не знаю, как авторы в разделе 3.2 могут сделать вывод из следующей цитаты из патента Intel:
если в операции 302 есть попадание [частичное совпадение с использованием смещений страницы]
и физический адрес загрузки или операции магазина не
действительный, проверка физического адреса на операции 310 [полный физический
совпадение адресов] можно считать хитом
следующее:
То есть, если преобразование адреса загрузки μOP завершится неудачно, а минимальное - 12
значащие биты адреса загрузки совпадают с битами предыдущего хранилища,
процессор предполагает, что физические адреса нагрузки и
сохранить совпадение и переслать ранее сохраненное значение в загрузку μOP.
Весь патент не упоминает сравнение 12 битов и не говорит о том, что нагрузка должна быть неисправной, чтобы произошла ложная пересылка хранилища. Кроме того, сам вывод неверен, потому что 12 младших разрядов не должны точно совпадать, а нагрузка не должна давать сбои (но атака срабатывает только в случае сбоя).
MSBDS отличается от Meltdown тем, что злоумышленник пропускает данные со страниц ядра, которые находятся в отдельном виртуальном адресном пространстве.MSBDS отличается от SSB тем, что злоумышленник неправильно управляет SMD, так что он распределяет нагрузку до того, как будут отправлены все STA, предшествующие загрузке.Таким образом, существует меньшая вероятность того, что загрузка не попадет в свободную сеть, что заставляет MOB передать нагрузку в кэш L1D и получить потенциально значение, которое не является самым последним значением в соответствии с порядком программы.SMD можно отключить, установив для IA32_SPEC_CTRL[2]
значение 1. Когда SMD отключен, планировщик обрабатывает загрузочные мопы, как в Pentium Pro.
Стоит вкратце отметить, что есть загрузочные и сохраненные мопы, которые работают иначе, чемчто я описал выше.Примеры включают в себя мопы памяти из MFENCE
, SFENCE
и CLFLUSH
.Но они здесь не актуальны.