Как именно работает Meltdown

    Уже третий день у всех на слуху слова Meltdown и Spectre, свеженькие уязвимости в процессорах. К сожалению, сходу найти что либо про то, как именно работают данные уязвимости (для начала я сосредоточился на Meldown, она попроще), у меня не удалось, пришлось изучать оригинальные публикации и статьи: оригинальная статья, блок Google Project Zero, статья аж из лета 2017. Несмотря на то, что на хабре уже есть перевод введения из оригинальной публикации, хочется поделиться тем, что мне удалось прочитать и понять.


    UPD: добавил псевдокода в описание атаки


    Как работает процессор


    Последние десятилетия, начиная с 1992 года, когда появился первый Pentium, Intel развивала суперскалярную архитектуру своих процессоров. Суть в том, что компании очень хотелось сделать процессоры быстрее, сохраняя при этом обратную совместимость. В итоге современные процессоры — это очень сложная конструкция. Просто представьте себе: компилятор изо всех сил трудится и упаковывает инструкции так, чтобы они исполнялись в один поток, а процессор внутри себя дербанит код на отдельные инструкции, и начинает исполнять их параллельно, если это возможно, при этом ещё и переупорядочивает их. А всё из-за того, что аппаратных блоков для исполнения команд в процессоре много, каждая же инструкция обычно задействует только один их них. Подливает масла в огонь и то, что тактовая частота процессоров росла сильно быстрее, чем скорость работы оперативной памяти, что привело к появлению кешей 1, 2 и 3 уровней. Сходить в оперативную память стоит больше 100 процессорных тактов, сходить в кэш 1 уровня — уже единицы, исполнить какую нибудь простую арифметическую операцию типа сложения — пара тактов.


    image
    В итоге, пока одна инструкция ждёт получения данных из памяти, освобождения блока работы с floating point, ну или ещё чего нибудь, процессор спекулятивно отрабатывает следующие. Современные процессоры могут таким образом параллельно обрабатывать порядка сотни инструкций (97 в Sky Lake, если быть точным). Каждая такая инструкция работает со своими копиями регистров (это происходит в reservation station), и они, в момент исполнения, друг на друга не влияют. После того, как инструкция выполнена, процессор пытается выстроить результат их выполнения в линию в блоке retirement, как если бы всей этой магии суперскалярности не было (компилятор то про неё ничего не знает и думает, что там последовательное исполнение команд — помните об этом?). Если по какой-то причине процессор решит, что инструкция выполнена неправильно, например, потому, что использовала значение регистра, которое на самом деле изменила предыдущая инструкция, то текущая инструкция будет просто выкинута. То же самое происходит и при изменении значения в памяти, или если предсказатель переходов ошибся.


    Кстати, тут должно стать понятно, как работает гипертрединг — добавляем второй Register allocation table, и второй блок Retirement register file — и вуаля, у нас уже как бы два ядра, практически бесплатно.


    Память в Linux


    В 64-битном режиме работы у каждого приложения есть свой выделенный кусочек доступной для чтения и записи памяти, который собственно и является userspace памятью. Однако, на самом деле память ядра тоже присутствует в адресном пространстве процесса (подозреваю, что сделано было с целью повышения производительности работы сисколов), но защищена от доступа из пользовательского кода. Если он попытается обратиться к этой памяти — получит ошибку, это работает на уровне процессора и его колец защиты.


    Side-channel атаки


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


    Соединяем эти знания вместе


    Собственно, суть атаки то очень проста и достаточно красива:


    1. Сбрасываем кэш процессора.
      char userspace_array[256*4096];
      for (i = 0; i < 256*4096; i++) {
      _mm_clflush(&userspace_array[i]);
      }
    2. Читаем интересную нам переменную из адресного пространства ядра, это вызовет исключение, но оно обработается не сразу.
      const char* kernel_space_ptr = 0xBAADF00D;
      char tmp = *kernel_space_ptr;
    3. Спекулятивно делаем чтение из массива, который располагается в нашем, пользовательском адресном пространстве, на основе значения переменной из пункта 2.
      char not_used = userspace_array[tmp * 4096];
    4. Последовательно читаем массив и аккуратно замеряем время доступа. Все элементы, кроме одного, будут читаться медленно, а вот элемент, который соответствует значению по недоступному нам адресу — быстро, потому что он уже попал в кэш.
      for (i = 0; i < 256; i++) {
      if (is_in_cache(userspace_array[i*4096])) {
          // Got it! *kernel_space_ptr == i
      }
      }

    Таким образом, объектом атаки является микроархитектура процессора, и саму атаку в софте не починить.


    Код атаки


    ; rcx = kernel address
    ; rbx = probe array
    retry:
    mov al, byte [rcx]
    shl rax, 0xc
    jz retry
    mov rbx, qword [rbx + rax]

    Теперь по шагам, как это работает.
    mov al, byte [rcx] — собственно чтение по интересующему атакующего адресу, заодно вызывает исключение. Важный момент заключается в том, что исключение обрабатывается не в момент чтения, а несколько позже.
    shl rax, 0xc — зачение умножается на 4096 для того, чтобы избежать сложностей с механизмом загрузки данных в кэш
    mov rbx, qword [rbx + rax] — "запоминание" прочитанного значения, этой строкой прогревается кэш
    retry и jz retry нужны из-за того, что обращение к началу массива даёт слишком много шума и, таким образом, извлечение нулевых байтов достаточно проблематично. Честно говоря, я не особо понял, зачем так делать — я бы просто к rax прибавил единичку сразу после чтения, да и всё. Важный момент заключается в том, что этот цикл, на самом деле, не бесконечный. Уже первое чтение вызывает исключение


    Как пофиксили в Linux


    Достаточно прямолинейно — стали выключать отображение страниц памяти ядра в адресное пространство процесса, патч называется Kernel page-table isolation. В результате на каждый вызов сискола переключение контекста стало дороже, отсюда и падение производительности до 1.5 раз.

    Поделиться публикацией
    Комментарии 334
      +1
      Отличное описание, единственное хотелось бы что-то подобного для spectre, ту уязвимость понять немного сложнее. Я к примеру так и не понял, как ее использовать для чтения данных другого процесса.
        0
        Механизм атаки spectre я сам ещё не на столько хорошо понял, чтобы статью писать.
        Точнее, про отравление предсказателя переходов понятно, а вот с его эксплуатацией для повышения привелегий — пока не до конца разобрался.
          +44
          Такой же механизм. Только не читают запрещенный адрес напрямую. (Или как там они его читают в той уязвимости, которую вы перевели.)

          Сначала много раз тренируют бренч предиктор, чтобы был заход внутрь if, потом внезапно подают туда адрес, из которого нужно красть значение, и при этом такой, чтобы мы не зашли внутрь if.
          Внтури if — чтение памяти.
          Бренч предиктор говорит: «скорей всего мы зайдем в if». Это предположение неверно, но пока это неизвестно — и поэтому cpu начинает исполнять то, что внутри if.
          В результате выполнения кода, значение из адреса, с которого нельзя читать, попадает к кэш. Вообще, это — исключение. Но потом оказывается, что бренч предиктор ошибся, а раз ошибся, то и исключения нет, и мы как бы и не читали этот адрес.
          Исключение отменяется — но остается побочный эффект: данные в кэше.

          Фактически, уже это — некорректная работа. Я так понимаю, что если мы прочитаем этот адрес, то получим какое-то значение, и это значение будет не из нашего процесса, что некорректно.

          Чтобы узнать, где подтянутое в кэш число, используется атака по времени. Читается все подряд — и замеряется время чтения. То, что было подтянуто в кэш, прочитается гораздо быстрей.

          Все остальные бубнопляски в коде — обход других предикторов и оптимизаторов.

          Мой AMD phenom x4 B40 уязвим на тесте. Но — тест читает свою же память. То есть, чистоты эксперимента — нет. Кернел спейс читать не пробовал(не знаю его адреса, надо разбираться как узнать, и как потом понять, что прочитал именно его). Может, завтра попробую вечером.

          Со второй разновидностью атаки spectre не разбирался, но суть там та же. Неким способом заставить выполниться код, который что-то подтянет в кэш.
            +1
            Эта часть понятна, потому что суть примерно такая же. А вот дальше, про гаджеты и т.д. — вот в той части не особо разобрался. А вы?
              +3
              Я испугался этого слова — гаджеты… И не читал ту главу.

              Там дальше глава 5, про косвенные переходы. Когда переход делается не по фиксированному адресу, а по адресу, который в регистре, или по адресу который лежит в какой-то ячейке памяти. Можно сделать финт ушами — и «спекулятивно» выполнить не тот код, который должен был бы выполниться. Насколько понимаю — переход по адресу, которого нет в icache занимает ВРЕМЯ и все это время выполняется то, что в этом кэше лежит, только потом это все отменяется, поэтому нам незаметно.
              Но этот код, хоть и отменяется, но что-то подягивает в кэш. И дальше как обычно.

              Суть одна — тем или иным способом заставляют cpu выполнить код пользователя спекулятивно, причем так, что потом он гарантирванно отменится. А в таком выполнении можно (было до того, как нашли уязвимость) безнаказанно «побегать в труселях по мечети»: все равно никто не узнает.
              +3
              понял на вашем уровне, но не понятно как происходит чтение не своей памяти.
                +3
                НЯМС:

                там два чтения — одно запрещенное — а другое разрешенное:

                temp = array2[array1[x]*512];

                х — адрес внутри запрещенной области array1, array2 — разрешенная область.

                Спеклятивно это выполняется. Значит, какая-то область array2 подтягивается в кэш.
                Дальше мы читаем из array2 подряд, измеряя время чтения. И по времени чтения пытаемся понять, была ли подтянута в кэш соответствующая область.

                почему 512 — мне не понятно. Размер кэш-лини — 64 байта, а не 512.
                  +1
                  механизм чтения я понял, но вроде как читать ядро нельзя с помощью spectre, а как читать другой процесс мне вообще не понятно. У нас же с ним разные линейные адреса.
                    0
                    Можно получить информацию о том, где в физической памяти находятся страницы чужого процесса, если он не выгружен. Если у ядра вся физическая память смаппирована, то эти страницы можно прочесть.
                      0
                      еще раз spectre не дает читать память ядра, это делает Meltdown только на intel.
                        0
                        Это где такое написано? На сайте лежит pdf, в ней приводится код, и там есть строчка, которую я привел выше.

                        Насколько понимаю, предполагается, что ядро лежит по адресу array1. Поэтому, array1[x] — чтение из области ядра.

                        Потом подтягиваются в кэш соответствущая область памяти из array2. Какая именно область подтянется — зависит от значения, которое лежит по array1[x].
                          0
                          возможно я не так понял. Думал что именно в случае spectre не происходит чтения, если не достаточно привилегий.
                            +1
                            А в чем бы тогда была его польза? С разрешенных страниц и так читать можно.
                              +1
                              тогда непонятно чем 1 баг от другого отличается, только использованием предсказаний переходов?
                                0
                                Во втором «баге», благодаря использованию предсказаний переходов, не происходит исключения при недопустимом доступе.

                                (Это всё же не баг, а намеренная часть архитектуры.)
                                  +2
                                  я просто думал, различий больше
                                  0
                                  del.
                            0

                            Некоторые имплантации aarch64 также подвержены.

                        0
                        Если рассуждать так, что 8 бит = 1 байт, то при «разархивировании» получаем => 512 / 8 = 64 байта, и если так идти до конца то получается такая зависимость, приводящая к 1 байт / 8 = 1 бит.
                        P.s. зависимость притянута за уши, но уж очень хотелось написать. Одна из мыслей, так возможно проще с памятью работать.
                      –1

                      Но это требует привилегий для управления кэшом (чтобы вытащить прочитанные данные). А имея такие привилегии и без того можно делов натворить (как минимум DoS). Поэтому уязвимость менее критична — в правильных окружениях она не выполнима.
                      Можно попытаться косвенно определить значение данных (через спекулятивное исполнение), но это получается долго и нужно, чтобы процесс не прерывался планировщиком.

                        0
                        чтобы вытащить прочитанные данные

                        Зачем?
                          +1
                          Не требует. В цепочку спекулятивных выполнений можно поставить операцию типа address = вытащенный байт * адрес массива. Далее — опредилить, какая строчка массива была вытащена в кэш, например чтением всех строк и измерением времени. Все, значение выдернутого спекулятивно байта известно.
                        +1
                        Не поможет?
                        Спасибо за статью.
                          +1
                          там демонстрируется чтение свой памяти, а вот как читать не свою память я к примеру так и не понял.
                          +1
                          Вот и мне непонятно принципиальное отличие Spectre от Meltdown. И там, и там читается значение по произвольному виртуальному адресу — принципиальной разницы между атаками нет. Вот только почему изоляция страниц спасает от Meltdown, а от Spectre — нет?
                            +1
                            Meltdown — это чтение защищённых страниц памяти, гонка между отработкой исключения и чтением памяти.
                            Spectre — отравление или обман предсказателя переходов. Чтение происходит из своего адресного пространства.

                            Side channel при этом одинаковый — кеш данных.
                              +2
                              Чтение происходит из своего адресного пространства.

                              Так… и ядро тоже в «своем» адресном пространстве, в этом суть проблемы же.
                                +3
                                а зачем читать из своего адресного пространства?
                                  0
                                  Чтобы вылести из js-песочницы в браузере и подампить память всего процесса. А там данные соседних вкладок, недавно введенные пароли, куки и т.п.

                                  Насколько я понял, принцип не отличается от meltdown, только дампить можно то, что и так доступно процессу с т.з. ОС.

                                  Мозилла уже залепила у себя www.mozilla.org/en-US/security/advisories/mfsa2018-01

                                  Хром вроде тоже обещает аналогично сделать (или уже сделал)
                                  0
                                  Чтение происходит из своего адресного пространства.

                                  К своему адресному пространства мы и так имеем доступ.


                                  И того, что я понял, в случае Spectre в документах идёт отсылка к Berkeley Packet Filter (BPF) — это виртуальная машина, позволяющая в режиме ядра выполнять пользовательский код. Meltdown здесь неприменим, т.к. исключение бросить просто невозможно. А вот выйти за границы массива с помощью Spectre вполне можно.


                                  Но при этом в Windows BPF, насколько я понимаю, нет, поэтому Windows не должна быть подвержена этой атаке.

                                    0
                                    Эм, нет — документация по Spectre — раздел 5.2 — собственно, Example Implementation on Windows
                                    0
                                    Spectre — отравление или обман предсказателя переходов. Чтение происходит из своего адресного пространства.

                                    Тут немного чисто языковой путаницы. Да, чтение происходит из своего адресного пространства, только оно «свое» для чужого процесса, а не для атакующего.
                                    +1
                                    Вот только почему изоляция страниц спасает от Meltdown, а от Spectre — нет?

                                    Получается, что через мелтдаун мы можем прочесть данные ядра, и оттуда, либо sensitive данные напрямую, либо уже косвенно — данные чужих процессов. Изоляция всех данных и кода ядра означает, что прочесть ничего не получится.

                                    Spectre же заставляет чужой нам процесс спекулятивно читать данные из своего адресного пространства, которые мы потом подхватим через тайминг атаку на кеш. И этот второй чужой процесс тоже не сможет читать ядро, но зато мы сможем из его памяти вытащить данные так, будто мы в его адресном пространстве и находимся.
                                      +1
                                      про spectre очень интересно, ни как не могу понять как это происходит.
                                        +2
                                        Прочтите оригинал spectreattack.com/spectre.pdf, потому что можно долго Рабиновичем перепевать, все одно для деталей придется читать статью. Да и сам я мог неверно понять.

                                        Кратко (если брать пример под NT из раздела 5.2) — берется код, который зашарен между процессами — dll, ntdll в случае примера. В своем, атакующего процесса, адресном пространстве кусок кода с ветвлением видоизменияется так, чтобы натренировать предсказатель переходов определенным образом. (в атакуемом процессе этот же кусок регулярно атакуемым процессом используется, т.к. это обычный библиотечный код). Предсказатель переходов сохраняет свои предсказания на уровне ЦП, а не процесса, поэтому в том, атакуемом процессе будет происходить то же. Плюс определенным образом сформированные входные параметры — в итоге происходит branch misprediction + чтение данных из пространства атакуемого процесса из-за спекулятивного выполнения, потому что мы натаскали бранч предиктор на заход «вовнутрь». Они потом будут сброшены, потому что переход не произойдет, но в кеше останутся. А из кеша эти данные извелкаются аналогично тому способу, что использован в Meltdown.
                                          +2
                                          Я не понимаю, как мы в другом процессе можем изменить входные параметры.
                                          В этой pdf написано, что мы контролируем используемые регистры в найденном авторами dll кодом — это вообще как?
                                          Да и откуда нам знать, что этот другой процесс вообще исполнит избранный код? В моем представлении для этого нужно изначально воспользоваться какими-нибудь уязвимостями для удаленного исполнения кода, а в этом случае нам spectre уже и не нужен вовсе.
                                            +1
                                            Да и откуда нам знать, что этот другой процесс вообще исполнит избранный код?

                                            Ну, например, запустить эту программу на своей домашней машинке и посмотреть, что там исполняется, а что нет. Учитывая, что они с ntdll игрались, шансов, что код исполнится — много.
                                            Они же использовали Sleep, тут вообще почти что с гарантией.
                                            0
                                            спасибо, стало понятней. Но для решение достаточно не шарить ntdll, а грузить каждому процессу свой экземпляр или нет? Да это небольшой перерасход оперативной памяти, но это мелочи.
                                              +1
                                              Сам понял, что не поможет. Нам не обязательно использовать библиотеку, можем использовать код чужого приложения.
                                                0
                                                Я бы не сказал, что это небольшой перерасход. К тому же, просто скопировать маппинг виртуальной памяти при загрузке процесса намного дешевле, чем читать и парсить библиотеку каждый раз. Эта часть — mapped file sections — есть в NT с первых версий, когда она еще не была Windows NT, на нее, кмк, много завязано.
                                                +1
                                                Spectre же заставляет чужой нам процесс спекулятивно читать данные из своего адресного пространства, которые мы потом подхватим через тайминг атаку на кеш.

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


                                                Да, за счёт шаринга DLL, мы можем обмануть branch prediction так, чтобы при определённом системном вызове спекулятивно выполнился кусок кода из адресного пространства процесса-жертвы.


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

                                                  +1
                                                  Да, скорее всего, этот метод не подойдет, чтобы атаковать любой произвольный процесс. Тут надо смотреть конкретно, что за кусок они использовали, можно только предположить, как именно регистры контроллируются. Допустим, это может быть удаленный вызов; обработка данных из сети.
                                              0
                                              «Чужим процессом» для Spectre может быть само ядро, а функция-читалка — eBFP. Но может быть и другая последовательность в ядре.
                                          +3
                                          olartamonov на гигтаймс разместил статью про spectre, вот ключевая часть второго типа атаки, наиболее интересная:

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

                                          Через некоторое время блок предсказания переходов абсолютно уверен, что все переходы такого вида ведут на адрес 123456, поэтому, когда атакуемая программа — с нашей подачи или по своей инициативе — доходит до аналогичного перехода, процессор радостно начинает спекулятивное исполнение инструкций с адреса 123456. Уже в адресном пространстве атакуемой программы.

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


                                          Под «нужной инструкцией» по адресу 123456 имеется в виду тот самый «гаджет» (кусок кода атакуемой программы, или из какой либо библиотеки, которую она использует), который оставит такие следы в кэше, которые легко отследить из атакующего процесса.
                                            0
                                            Меня удивляет другое. Один из механизмов атаки — модификация адреса перехода в разделяемой библиотеке. Одна и та же физическая память отображается и в процесс жертвы, и в процессе атакующего. Далее мы меняем адрес перехода в своём адресном пространстве, при этом происходит CoW — изменённый участок памяти маппится на другую область памяти. Но при этом это действие влияет на результат предсказателя переходов в процессе-жертве.
                                              0
                                              Насколько я понимаю, речь идёт о косвенном переходе, т.е. «модификация адреса перехода» — это не изменение инструкции в памяти, а выполнение её с изменённым значением операнда.
                                                0
                                                Точно, это я напутал: физически местоположение инструкции одинаково, различие только в адресе операнда, который ещё надо прочитать.
                                                +1
                                                А что удивительного? Предсказатель переходов же не процессо-специфичен. Он процессоро-специфичен. И работает с виртуальными адресами.
                                            0
                                            В итоге процессор оставляет данные в кэше которые читать было нельзя, фактически произведя чтение, а программа может по косвенным признакам (времени чтения) узнать, что в этом кэше находится. Мне кажется, так немного понятнее, нет?
                                              +7
                                              Нет, данных в кэше не будет. В кэше будет 1 строчка, которая соответствует байту по недоступному адресу. То есть, если по адресу 0xdeadbeef было записано 42, и мы его хотим узнать — то в результате этой атаки в кэше будет строка, которая соответствует индексу 42*4096 в массиве.
                                                +1
                                                Ага, значит ещё сложнее. Значит самих данных не будет, только косвенно будет видно, какое там число — по индексу. Процессор в зависимости от числа в запрещённой для доступа памяти прочитает строку из нашего массива в кэш и уже по строке(которая оказалась в кэше) мы узнаём число. Хитро однако.
                                                  +43

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


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

                                                  На основе вышеизложенного, мы можем реализовать следующую схему:


                                                  1. Делаем массив в нашей пользовательской доступной памяти размером char userspace[256 * 4096]. 256 — количество значений которые может принимать байт, 4096 — такое расстояние, на котором гарантировано происходит кэш-промах при последовательном чтении с таким шагом в памяти.
                                                  2. Для i = 0..255
                                                  3. Составляем несколько инструкций так, чтобы сначала была инструкция с чтением из памяти по запрещенному адресу restrictedspace[address], а потом, на основе этих данных, выборка из нашего пользовательского массива на основе значения считанного байта: userspace[restrictedspace[address] * 4096]
                                                  4. Так как нельзя считывать по запрещенному адресу, происходит исключение, но к этому моменту код, который идет далее уже успевает спекулятивно выполниться, и нужная часть нашего пользовательского массива будет загружена в кэш.
                                                  5. Ловим исключение и измеряем время доступа к элементу address[i * 4096], записывая в массив time[i]
                                                  6. Повторяем для всех i (goto 2)
                                                  7. Ищем значение в массиве time, которое сильно отличается в меньшую сторону.
                                                  8. Полученный индекс и будет искомым значением из запрещенной памяти
                                                    +1
                                                    В первый пункт забыл добавить про спекулятивное выполнение.
                                                      +6
                                                      В саму ветку, которая читает restrictedspace[address] мы тоже попадаем спекулятивно, поэтому никакого исключения генериться не будет.

                                                      В начале кода честно стоит проверка if (address < OUT_OF_BOUNDS), но OUT_OF_BOUNDS задано не константой, а в отдельной области памяти, которая предварительно специально вымывается из кеша.

                                                      Это не позволяет процессору мгновенно определить правильную ветку перехода, и в результате он спекулятивно выполняет код, который программа якобы и «не собиралась» исполнять.
                                                        +2
                                                        Да, я сначала пытался описать это, но по ходу рассуждения не понял, в какой момент происходит неверное предсказание переходов. Можете привести код на ассемблере с этим бранчингом?
                                                      –1
                                                      Поясните про перемещение транзисторов на кристалле.
                                                      от их позиции разве зависит логика работы CPU?
                                                        +3
                                                        я имею ввиду, что это скорее всего не баг из-за глупости разработчиков, а особенность дизайна. Я имею ввиду, нельзя просто так взять и изменить место проверки этого условия как в обычной программе, придется переносить какие-то блоки, переразводить транзисторы на чипе и так далее. Я понимаю, что сейчас никто уже руками этого не делает, как раз все пишут в виде программы на специальных языках «программирования», но я имею ввиду, что этот перенос может в худшую сторону сказаться на быстродействии процессора, или вообще потребует глубокой переработки архитектуры. Возможно, программный фикс обойдется даже дешевле с точки зрения производительности, или архитектурная переработка ОС может быть даже выгоднее в этом плане.
                                                        А Intel скорее всего просто будут сбрасывать кэш при отмене операции, хоть это и не совсем верно, зато безопасно.
                                                          +2

                                                          Вот я тоже подумал про «сбрасывать кэш при отмене», но не получится ли при этом тогда действовать от противного? Прочитать весь наш массив в кэш, и потом замерять, какая часть была сброшена? 256*4096 = 1 Мб, влезет куда угодно, ну в L3 точно.


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

                                                            0
                                                            Прочитать весь наш массив в кэш, и потом замерять, какая часть была сброшена?

                                                            Можете подробнее объяснить? Как мы сможем различить эти случаи?

                                                              0

                                                              Различить можно будет, если сбрасывать будут не весь кэш, а только изменённую линейку. Если весь, то да, атака не сработает, как уже ниже пояснили.

                                                              +1
                                                              Если сбрасывать весь кэш при отмене, а не только последнюю загруженную строку, — то, по-моему, уязвимость будет устранена.
                                                              При этом ущерб производительности не колоссально большой, потому что невалидные чтения в действительности выполняются нечасто.
                                                                +1
                                                                Процентов на 30 просядет производительность.
                                                                Меня бы больше устроило, если бы команды rdtsc, rdtscp перевели в разряд привелегированных, или совсем отключили, или повысили гранулярность. Для большинства пользователей это будет ок. Нет часов с хорошей гранулярностью — нет проблемы. Как быстры фикс это — ок.
                                                                И вообще, пускай юзают hpet.
                                                                  –1
                                                                  Таймер для эксплойта необязателен: один поток пусть в бесконечном цикле инкрементирует счётчик, другой поток пусть сравнивает значения счётчика до обращения к памяти и после.
                                                                    +1
                                                                    Как из одного потока в другой передать этот счетчик?
                                                                    И вообще, что такое «счетчик» и что такое «поток» если мы говорим о микроархитектуре?

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

                                                                    Если под понятием «поток» вы подразумевали нечто, что выполняется вторым ядром — то как передавать этот счетчик из второго ядра в первое ядро, еще и ненарушив кэш? Для таких вещей есть барьеры памяти, но они влияют на кэш. По сути передача данных между ядрами — через L3 (хотя это от архитектуры может зависеть) Думаю, там не померяешь так просто такой короткий интервал времени…
                                                                      –1
                                                                      Как из одного потока в другой передать этот счетчик?

                                                                      У потоков общая память.


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

                                                                      А зачем потоки переключать? Они одновременно же работают на разных ядрах.


                                                                      Если под понятием «поток» вы подразумевали нечто, что выполняется вторым ядром — то как передавать этот счетчик из второго ядра в первое ядро, еще и ненарушив кэш? Для таких вещей есть барьеры памяти, но они влияют на кэш. По сути передача данных между ядрами — через L3 (хотя это от архитектуры может зависеть) Думаю, там не померяешь так просто такой короткий интервал времени…

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


                                                                      Во-вторых, ничто не мешает N раз провести атаку на одну и ту же ячейку и замерить суммарное время атаки, если точность измерения времени одиночной атаки недостаточна.

                                                                        +1
                                                                        А разве после первого обхода остальные ячейки не попадут в кэш?
                                                                          0
                                                                          Ну так у нас в арсенале имеется команда очистки кэша.
                                                                            +1
                                                                            Очищать будем выборочно или все подряд? Если выборочно, то по какому критерию, если все подряд — то как нам помогут множественные итерации?
                                                                          0
                                                                          У потоков общая память.

                                                                          В том то и дело, что несовсем: мы же на микроархитектурном уровне. Несколько ядер на одну память? Как вы себе это представляете? L0, L1 у каждого ядра — свой. L2 — иногда общий, и то не всегда (Xeon Clovertown E5345). Можете lstopo попробовать (под линуксом). Можно в гугл вбить — и включить картинки, и посмотреть, как вообще бывает. Там иногда такое, что даже не представляю что это.

                                                                          А теперь представьте себе: из L0 одного ядра нужно число переправить в L0 другого ядра. Это сотни тактов, и этот эффект больше, чем то, что мы хотим измерять. И это надо сделать так, чтобы не повлиять на кэш, потому что момент, в который мы это все меряем — очень «нежный». Любая подтяжка в кэш сама по себе уже повлияет на результат.
                                                                          И это еще не все. Команды исполняются на конвеере. Там еще есть всякие буферы валидации и прочие оптимизации. То, что придет в соседний проц, если не использовать барьеры памяти, может весьма слабо отражать значение реального счетчика.

                                                                          Во-первых, один атомарный инкремент

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

                                                                          N раз провести атаку

                                                                          Это приходится делать даже с rdtscp. В том коде они это делают 999 раз — и то не всегда помогает. Другие процессы сильно влияют. Счетчик в другом потоке — гораздо более грубый источник времени, а его получение — гораздо более дорогое, чем тот эффект, который измеряется.
                                                                            0
                                                                            Атомарные операции выполняются с барьерами памяти

                                                                            В архитектуре x86, насколько я помню, нет необходимости в явном использовании барьеров. И мои эксперименты с атомарными инкрементами показывают, что пересылка занимает явно меньше сотни тактов.


                                                                            В том коде они это делают 999 раз

                                                                            В том коде на каждой итерации делается вызов rdtsc. Я бы попробовал переписать код так, чтобы измерялось суммарное время 999 попыток, а не каждой из попыток в отдельности.

                                                                              0
                                                                              Смотря для чего и что надо.
                                                                              У атомарных счетчиков — барьеры «под капотом».

                                                                              Где-то у Шипилева была статья про исследование поведения при помощи jcstress, и там было наглядно показано, что можно нарваться на баги. Эти баги неособо частые, но они есть. И я тогда крутил эти тесты на своем амд — эти баги были.

                                                                              Но тут с вами я согласен: поскольку мы говорим про взлом, то некоторое кол-во некорректных результатов нас устроит. Если 1 раз из 1000 происходит глюк — это не ок для «обычного» софта, для банковского — вообще смерть, а для задач взлома систем — нормально, даже если 1 раз из 1000 все сработает как хочется :).

                                                                              Так что, пожалуй, что да. Загрублять rdtsc — не способ.
                                                                              0
                                                                              > А теперь представьте себе: из L0 одного ядра нужно число переправить в L0 другого ядра. Это сотни тактов, и этот эффект больше, чем то, что мы хотим измерять

                                                                              Это не совсем верное рассуждение:

                                                                              1. Это по любому не сотни циклов.
                                                                              2. Применяют хитрости для сокращения времени.
                                                                              3. Загрузку всегда делают в pipeline к операции. Тут конечно большая наука намешана, чтобы соблюсти когерентность данных.

                                                                              Но когеретность времени тут не соблюдается. Просто доступ из локального кэша много короче следующего уровня, вот схема опроса счетчика и работает.
                                                                                0
                                                                                Нет доказательств. И я не соображу, как это поменять хотя бы примерно. Строго говоря, я тоже не привел доказательств.
                                                                                Сотни тактов — это я слышал, что из памяти. А если из соседнего L0 — то может и быстрей (там, где L3 общий)
                                                                      +2
                                                                      Так ведь промахи кеша случаются нечасто в том числе благодаря тому, что даже когда предсказатель ветвлений условно на каждом 25-ом* повороте выбирает не ту ветку, кеш остаётся нетронутым. Мне кажется вайп в таких случаях сведёт на нет все преимущества кеша.

                                                                      * perf stat -e L1-dcache-loads,L1-dcache-load-misses,branches,branch-misses /opt/phpstorm-171/bin/phpstorm.sh

                                                                      Performance counter stats for '/opt/phpstorm-171/bin/phpstorm.sh':

                                                                      73.192.922.309 L1-dcache-loads
                                                                      6.005.629.782 L1-dcache-load-misses # 8,21% of all L1-dcache hits
                                                                      44.366.574.238 branches
                                                                      1.757.550.166 branch-misses # 3,96% of all branches

                                                                      41,088747127 seconds time elapsed
                                                                        +1
                                                                        При этом ущерб производительности не колоссально большой, потому что невалидные чтения в действительности выполняются нечасто.
                                                                        Вот же ж, блин, теоретики. Скорость доступа в кэш и в оперативку отличается на два порядка (то есть в сто раз). То есть даже если даже предсказатель будет «промахиваться» в одном случае из сотни (а этого, поверьте, не так-то просто достичь) мы получим проседание производительности на 30-50%.
                                                                          0
                                                                          Речь шла не про предсказания переходов, а про невалидные чтения, приводящие к исключению.
                                                                          Их намного меньше, чем одно на сто обращений.
                                                                            0
                                                                            Каким образом определять «невалидность»? Пинать MMU при каждом обращении к кешу?
                                                                              0
                                                                              Так же, как она определяется сейчас.
                                                                                0
                                                                                По сути, ты предлагаешь каждый раз, когда встретится код вида
                                                                                if(ptr != nullptr) read(ptr);

                                                                                сбрасывать весь кеш при неверном предсказании перехода. Это расточительно. Наверняка разработчики процессоров найдут способ дешевле (а решать эту аппаратную проблему все равно придется разработчикам CPU, текущие патчи на ядро — это лишь временная заплатка).
                                                                          0
                                                                          По-хорошему, строки кэша должны иметь флаг «данные загружены во время спекулятивного исполнения», и, либо кэш для спекулятивного исполнения вообще должен быть отдельным, либо этот флаг должен сбрасываться при актуализации спекулятивно исполненных команд. Тогда «мир возможного» будет отграничен от реальности.
                                                                            +1
                                                                            Нету отдельного не-спекулятивного исполнения, оно всё спекулятивное. Посмотрите на схему. А вот флаг в кэш, теоретически, можно добавить, только он должен означать «первое использование», и при отмене операции надо выкидывать из кэша только те строки, которые были затронуты этой операцией и у которых есть этот флаг. Но и это, наверняка, не панацея.
                                                                              0
                                                                              Но и это, наверняка, не панацея.
                                                                              Не панацея — можно заметить как что-то пропало из кеша. Можно для «первого использования» завести отдельный кеш, но тогда можно будет играться с «двойным первым использованием» и т.д. и т.п.

                                                                              Кажется, что самое разумное решение — одновременно и самое тупое. Современные системы всё равно делят адресное пространство пополам и по старшему биту адреса можно понять — это данные ядра или нет. Ну так давайте сделаем это деление оффициальным и всё.

                                                                              И не нужно никаких спекуляций, проверка одного бита — это несколько транзисторов, её куда угодно можно засунуть.
                                                                                +1
                                                                                кажется, что флаг и проверка — несколько транзисторов, отдельные кэши намного страшнее и дороже. Говорят, кэши на кристалле занимают солидную площадь (больше половины).
                                                                                  0
                                                                                  Так это уже есть — собственно, именно так защищаются страницы нулевого кольца от третьего. Или вы предлагаете явно ставить барьер при обращении к ядерным страницам, который будет запрещать реордеринг?
                                                                                    +1
                                                                                    Это, собственно, не я предлагаю. Это в статье про Meltdown есть.

                                                                                    Просто все попытки обращения к адресам, у которых старший битик установлен отвергать «с порога» если мы не в режиме супервизора. И всё.

                                                                                    Сейчас же это делается через таблицы страниц. Что, в конечном, счёте, даёт тот же ответ — но требует обращения к большим и сложным структурам данным. А поскольку это медленно — то приходится делать это параллельно с другими вычислениями… со всеми вытекающими…
                                                                                      0
                                                                                      Это напоминает защиту памяти в старой БЭСМ-6 — один из битов 48 битного слова в памяти показывал, это слово данных или команда. DEP 60х.
                                                                                    0
                                                                                    А скажите, в 64-битных системах в адресном пространстве тоже только один процесс и ядро присутствует? Или там может быть несколько процессов?
                                                                                      0
                                                                                      Это как раз в 32-битах можно, теоретически, несколько процессов сегментами развести. В 64-битах ничего этого нет.
                                                                                        0
                                                                                        Для удобства в память процесса отображается и память ядра, чтобы при входе в ядро не переконфигурировать карту. Просто эта память была закрыта правами доступа.

                                                                                        Также, для удобства ядра, в какую-то область отображается вся физическая RAM, чтобы ядру видеть сразу все процессы и не заморачиваться с подключением нужной страницы, если надо записать в какой-то процесс.

                                                                                        Теперь придётся все эти «удобства» отключать )))
                                                                                      0
                                                                                      Ну так я, собственно, это и имел ввиду. Есть некая ветка команд, которые выполняются опираясь на предсказание условного перехода, для этих команд в кэш подгружаются затребованные ими данные. Впоследствии же оказывается, что условный переход был предсказан неверно, и действия этих команд аннулируются, а вот подгруженные для них данные остаются в кэше. Что и позволяет потом сделать вывод о том, какие именно данные были задействованы этими «прозрачными» командами. Почему решение с аннулированием соответствующих строк кэша не закрывает данную уязвимость — мне непонятно.
                                                                                        0
                                                                                        Почему решение с аннулированием соответствующих строк кэша не закрывает данную уязвимость — мне непонятно.
                                                                                        Потому что вам недостаточно просто убрать эту строку из кеша. Нужно ещё вернуть ту, которую вы убрали, чтобы эту положить. Иначе её исчезновение тоже можно заметить. А ещё — всю эту деятельность наблюдает другое ядро, не забывайте, так что наблюдать за всем этим процессом мы можем достаточно пристально.
                                                                                        0
                                                                                        Можно из параллельного потока атомарно писать в i-ю строку памяти. Если из нее будет даже спекулятивное чтение, то время записи, скорее всего, изменится (строка в кеше пишущего потока на короткое время станет неэксклюзивной). Так можно отследить, не из i-й ли строки массива array2 пытается читать первый поток. Тут чинить надо первопричину, а не ее проявление.

                                                                                        Мне тут подумалось, для memory mapped io бывает ли такое, чтобы при чтении из ячейки памяти происходили побочные эффекты (типа считали содержимое ячейки — получили значение счетчика и он сбросился в ноль). Ведь спекулятивная запись невозможна (при генерации исключения, процессор отбросит созданные данные), а вот спекулятивное чтение из адресного пространства ядра вполне можно сделать (возможно, даже и того, что занимается вводом/выводом на устройства).
                                                                                          0
                                                                                          Мне тут подумалось, для memory mapped io бывает ли такое, чтобы при чтении из ячейки памяти происходили побочные эффекты (типа считали содержимое ячейки — получили значение счетчика и он сбросился в ноль).
                                                                                          Бывает. В лёгкую. И это настолько плохо, что уже во времена Pentium Pro появились MTRR, отключающие спекулятивные чтения для определённых диапазонов памяти.

                                                                                          Так что для атаки это использовать нельзя.
                                                                                +2
                                                                                другими словами, от их позиции не зависит логика работы CPU, но вот изменение логики работы может потребовать их перемещения и перекомпоновку блоков. Чипы все еще 2d, так что это может потребовать серьезного изменения архитектуры или может сказаться на производительности
                                                                                +1

                                                                                Зачем goto 2? В самом начале сбрасываем кэш специальной командой. Массив userspace[256x4096] в кэше отсутствует. После обработки исключения один из блоков длиной 4096 в этом массиве должен быть загружен в кэш. Измеряем время доступа к элементам с номерами ix4096 для i от 0 до 255. Определяем, при каком i время доступа было минимальным. Найденное i будет равно значению из защищенной области памяти. Массив time для этого не нужен, достаточно помнить минимальное время и значение индекса, в котором оно было получено.

                                                                                  0
                                                                                  Массив time для этого не нужен

                                                                                  Естественно, просто так проще объясняется алгоритм.


                                                                                  Измеряем время доступа к элементам с номерами ix4096 для i от 0 до 255

                                                                                  А разве кэш-промах и вытаскивание новых данных не испортят нам состояние кэша?

                                                                                    0

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

                                                                                      0
                                                                                      Да, вроде не должен… Но наверное это все же уже оптимизация, в любом случае, нужно экспериментировать. Может зависеть от ОС, процессора и еще кучи факторов вроде запущенных в фоне приложений.
                                                                                  +3
                                                                                  Честно говоря не очень понятно
                                                                                  1) как атакующий может знать какой именно адрес памяти жертвы его интересует — большинство программ используют стековую архитектуру и многие переменные находятся на стеке и вершина стека перемещается с течением времени. Многие объекты так же имеют ограниченный срок жизни между new и delete и адреса создаваемых и удаляемых объектов зачастую почти случайны особенно в многопоточном приложении жертвы. Даже дизассемблирование прогреммы жертвы до атаки не дает реального знания об интересующих адресах в процессе жертвы.
                                                                                  2) атака подразумевает длительное исследование одной ячейки памяти и за это время ячейка просто может поменять свое значение в многопроцессорной системе.
                                                                                  То есть метод абсолютно не подходит, чтобы сделать снимок памяти процесса жертвы.

                                                                                  Иными словами, если с помощью атаки «прочитал» байт из памяти жертвы, то насколько атакующий может быть уверен, что это именно тот байт, что его интересует?

                                                                                  Мне кажется метод атаки имеет академический интерес, но вот попроси любого из нас провести реальную атаку даже в лабораторных условиях — и мы не сможем и я не смогу.
                                                                                    0
                                                                                    Мне кажется метод атаки имеет академический интерес, но вот попроси любого из нас провести реальную атаку даже в лабораторных условиях — и мы не сможем и я не смогу.
                                                                                    Вы не сможете, а авторы соотвествующих статей смогли. Пароли из менеджера паролей вороются на раз. Просто потому что они не могут жить на стеке (они ж глобальные и должны там храниться годами) и менять их каждые 5 секунд тоже вроде как незачем.

                                                                                    И главное, что атака — ничего не ломает! Не получилось сейчас, попробуем через час… У многих браузеры сутками не закрываются!
                                                                                      0
                                                                                      Пароли в нормальных менеджерах лежат в базе данных в
                                                                                      зашифрованном виде и в память они попадают временно в момент когда их запрашивают (GUI/API)
                                                                                      Вероятность вытащить такой атакой пароль от важного ресурса призрачно мала.
                                                                                      такому удачливому хакеру нужно срочно бежать покупать билет «русском лото» — джекпот гарантирован )

                                                                                        +3
                                                                                        это при условии, что вы каждый раз вводите пароль. А не храните сессию
                                                                                          0
                                                                                          Предлагаю провести эксперимент:
                                                                                          1. Откройте свой менеджер паролей.
                                                                                          2. Снимите дамп памяти процесса.
                                                                                          3. Найдите в дампе свои пароли.
                                                                                          4. Назовите этот менеджер и его версию.
                                                                                            0
                                                                                            3. Найдите в дампе свои пароли.
                                                                                            Кто вам сказал, что они там «открытым текстом» будут храниться? Там где-то будет мастер-пароль и зашифрованная база со всеми остальными.

                                                                                            Но если менеджер паролей может их расшифровать (а он может, раз не спрашивает мастер-пароль повтороно), то и мы сможем… если достаточно долго посидим в отладчике предварительно…
                                                                                          0
                                                                                          в память они попадают временно в момент когда их запрашивают (GUI/API)

                                                                                          А что мешает их каждый раз во время атаки запрашивать?
                                                                                            0
                                                                                            Пароли в нормальных менеджерах лежат в базе данных в
                                                                                            зашифрованном виде и в память они попадают временно в момент когда их запрашивают (GUI/API)
                                                                                            Если у вас менеджер спрашивает мастер-пароль каждый раз при необходимости показать какой-либо другой пароль — то да. Но большинство пользователей такого уровня параноидальности не выдерживают.

                                                                                            И «хранилище паролей» остаётся открытым когда минутами, а когда и часами. В каком-нибудь keepass'е по умолчанию сессия вообще закрывается только когда пользователь сам об этом попросит.
                                                                                          0
                                                                                          1) Брутфорс никто не отменял. В случае Meltdown мы можем просто сдампить большой кусок памяти, а затем искать в ней какие-нибудь интересные строчки.

                                                                                          2) Что-то поменяется, что-то нет. Здесь и не нужна 100% удача.

                                                                                          А вот Spectre действительно имеет больше академический интерес — слишком много условий должно выполниться, чтобы было возможно прочитать память чужого процесса.
                                                                                            +1
                                                                                            А вот это уже вопрос номер два. Я думаю, что специалисты по взлому, имея исходный код chromium смогут в два счета понять, что им нужно, чтобы считать именно нужную область памяти. А вообще, да, это задача творческая и нетривиальная, но сама по себе уязвимость — это возможность начать работу по изучению. Я думаю, что появление реальных программ, способных узнать ваши пароли и номер банковской карты — это вопрос времени.
                                                                                            0

                                                                                            А мне может кажется или ваш цикл на шаге 2 нужно поставить после 4-го пункта? Ведь смысл от цикла — измерить время доступа к данным массива, чтобы получить значение байта по "невалидному адресу", а измеряем время доступа мы только после того, как поймаем исключение. На шаге 2 нужен другой цикл, ИМХО. Цикл, который будет читать последовательно байты из памяти ядра, чтобы, собственно, и получить интересующий нас пароль к почте Клинтон.
                                                                                            P.S. А так за объяснение плюс. Стало намного понятнее все.

                                                                                              0

                                                                                              В пункте 5 у меня опечатка:


                                                                                              Ловим исключение и измеряем время доступа к элементу address userspace[i * 4096], записывая в массив time[i]

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

                                                                                      +1
                                                                                      Ну и как я понимаю, для экономии на переключении страниц памяти все системы так делают — проецируют память ядра в пользовательскую.
                                                                                        +1
                                                                                        Не все. У микроядерных — честный IPC.
                                                                                          +1
                                                                                          Нет у всех. Часть памяти ядра должна отображаться всегда и во все процессы. При возникновении прерываний, исключений, вызове sysenter (честный IPC) происходит переход на адрес который должен находится в памяти.
                                                                                            +4
                                                                                            происходит переход на адрес который должен находится в памяти.

                                                                                            Да, но это может быть микроскопический трамплин.
                                                                                              0
                                                                                              Да, патч для Linux — KAISER так и делает. Просто необходимость проецирования части памяти ядра определяется архитектурой не ОС, а процессора. Защищенный режим у intel предполагал невозможность чтения памяти ядра прикладным ПО и «трамплины» не делали. Это лишний, сложный и медленный код, дублирующий функции железа. А теперь выяснилось, что из-за излишних оптимизаций этот код необходим.
                                                                                              0
                                                                                              Сисколлы любой процесс может вызывать, к памяти и карте ее распределения это не имеет никакого отношения. Проецируют память только по одной причине — чтобы часть кода ядра попала в кэш и была там по возможности как можно дольше, а лучше — всегда, но все это на усмотрение процессора. В любом случае ОС проводит значительное время(1-10%) в режиме ядра и выполняет шаблонные действия, и вот выполнение этой части можно ускорить — держать горячие части кеше.
                                                                                              Меньше возни с таблицами страниц — это побочный эффект, главное — ядерный код работает быстрее.
                                                                                                0
                                                                                                Проецируют память только по одной причине — чтобы часть кода ядра попала в кэш и была там по возможности как можно дольше, а лучше — всегда, но все это на усмотрение процессора

                                                                                                При перегрузке CR3 сбрасывается TLB.
                                                                                                  0
                                                                                                  У каждой задачи своя таблица страниц, но если дописать в нее маппинг на страницы ядра, то процессор будет(очень вероятно) держать эти страницы в кеше.
                                                                                                    0
                                                                                                    Ну, это зависит от соотношения интенсивности работы с памятью ядра и прикладной задачи.
                                                                                                    Как это зависит от того, есть «дописывание» или нет?
                                                                                                      0
                                                                                                      Юзерспейс код работает в 95% времени, остальные 5% — ядро(цифры от балды, но суть — у юзерспейса огромный перевес). У ядра просто нет шансов попасть в кеш(мы не tlb, а обычный L1-L2-L3), а очень хочется, вот настойчивое «дописывание» и помогает процу понять, что эти страницы желательно держать в кеше.
                                                                                                        +1
                                                                                                        Ужас какой. Вы тут развели целую теорию вместо того, что вам уже сказали: при перегрузке CR3 сбрасывается TLB. А наличие одного и того же фиксированного маппинга во всех процессах позволяет CR3 при переходе в ядро и возврате не сбрасывать. Вот и всё.

                                                                                                        А что с этого можно ещё каких-нибудь «плюшек» получить — это мелочи…
                                                                                                          0
                                                                                                          CR3 сбрасывается каждый рад при переключении задачи, но сейчас есть возможности не сбрасывать весь TLB — и делается это не мэппингом страниц ядра.
                                                                                                          Этот огород городили не ради 4кб TLB. Мэппинг — стародавний и работающий на всех платформах способ пропихнуть страницы с кодом и данными ядра в кеш процессора. Таггинг изобретут сильно позже, а пока это работает.
                                                                                                            0
                                                                                                            CR3 сбрасывается каждый рад при переключении задачи

                                                                                                            Но не при прогулке в ядро и обратно в пределах одной задачи. Для чего и нужно маппирование в нынешнем виде, иначе CR3 придется переключать дважды, сбрасывая TLB при каждом syscall'е и при каждом возврате из него.
                                                                                                        0
                                                                                                        95-5, вот именно. При чем тут дописывание? Что, от дописывания страницы в кеш попадут что ли?
                                                                                                          0
                                                                                                          Все ядро — 1-2 мб, самые нужные структуры данных еще 10мб, еще 100мб буферов. В реальности это выглядит как минус 1-2гб памяти прямо со старта Винды(и любой другой ОСи), но само ядрышко и горячие данные компактны, локальны и кешфрендли, поэтому с легкостью залетают в кеш.
                                                                                                            0
                                                                                                            Вы не понимаете уточняющих вопросов и говорите совершенно отвлеченные вещи.
                                                                                            +2
                                                                                            Есть архитектуры, где проверка доступа происходит ДО запуска чтения. MIPS например (Байкал-T1). И в AMD похоже тоже.
                                                                                            +1
                                                                                            а почему исключение отрабатывает не сразу? Насколько понимаю, уже это — уязвимость.
                                                                                              +6
                                                                                              На сколько я понимаю, корректность доступа проверяется в самом конце, на стадии retirement. И это имеет смысл, если большая часть инструкций валидна — меньше будет тормозить пайплайн. Но это уже мои домыслы, насколько глубоко документацию на процессоры я не копал.
                                                                                                +2
                                                                                                Логично, что они оптимизируют лучший случай — в 99.9% случаев чтение будет валидным, а 0.01% чтений зловреда или просто некорректного кода можно пренебречь — там performance penalty неважны.
                                                                                              +1
                                                                                              .
                                                                                                +1
                                                                                                Сразу прошу прощения за нубские вопросы, т.к. я не силен в низкоуровневом программировании. Можно ли код, эксплуатирующий такие уязвимости, засечь еще на этапе загрузки? Должен же он иметь некие паттерны? Если да, то может отказывать такому коду в загрузке и исполнении будет дешевле, чем выключать отображение страниц памяти ядра в адресное пространство процесса?
                                                                                                  +5
                                                                                                  вон же код, прямо в статье. взять и запретить загружать такой код и всех делов
                                                                                                    0
                                                                                                    Код атаки — всего четыре инструкции. Уязвимых комбинаций инструкций очень много. Они очень часто встречаются в дикой природе (в разных вариациях).
                                                                                                      +2
                                                                                                      парсер порезал irony… оно конечно там было. :)
                                                                                                        0
                                                                                                        Верификатор загружаемого кода может проверять, что все обращения в память происходят либо к статически выделенной памяти, либо к стеку, либо к тому, что вернул new/malloc. А там, где есть сомнения, ставить breakpoint, который сломает конвейер (а лучше вообще не давать запускать).
                                                                                                          +1
                                                                                                          Поздравляю, вы изобрели JVM.
                                                                                                            0
                                                                                                            Верификатор загружаемого кода может проверять, что все обращения в память происходят либо к статически выделенной памяти, либо к стеку, либо к тому, что вернул new/malloc.
                                                                                                            πздец, извините за выражение. Выходят статьи, диссертации, разные инструменты и прочее, которые нужны для того, чтобы это свойство, с некоторой вероятностью, можно было обеспечить.

                                                                                                            А тут раз: щелчок пальцев — и верификатор у нас в кармане.

                                                                                                            А там, где есть сомнения, ставить breakpoint, который сломает конвейер (а лучше вообще не давать запускать).
                                                                                                            Нечто подобное, примерно, и предлагается. Но там приходится почти везде это делать, так как магического валидатора у нас нету…
                                                                                                              +1

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

                                                                                                                0
                                                                                                                Это не совсем правда. Мы не можем точно понять — обладает программа таким поведением или нет. Но можно «пограничные случаи» обьявить «подозрительными» и тоже выкинуть.

                                                                                                                Проблема в том, что теоретически, это даст нам безопасность, а практически — страшную головную боль и почти все библиотеки окажется невозможно использовать. Останутся разве что олдскульные программы типа TeX'а, которые память выделяют в самом начале работы, а освобождают — по завершении…
                                                                                                                +1
                                                                                                                Верификатор загружаемого кода может проверять, что все обращения в память происходят либо к статически выделенной памяти, либо к стеку, либо к тому, что вернул new/malloc
                                                                                                                Это не защищает от Spectre.

                                                                                                                Там же код
                                                                                                                if (index < array_size) { обращение к array[index]; }

                                                                                                                Проблема в спекулятивном выполнении, когда процессор зашёл внутрь if при слишком большом index, а не должен был. Верификатор тут посчитает, что такое чтение закрыто if-ом.

                                                                                                                Если же верификатор будет заходить во все false-ветки и пытаться выполнять код, который не должен выполняться, у него быстро крыша съедет от ложных срабатываний.
                                                                                                            +1
                                                                                                            Паттерны есть, но они «размыты», как бинарный боеприпас. Кусочек, которые «начищает предсказатель» там, «читатель тени» тут, какая-то логика, которая всё объединяет — ещё где-то.

                                                                                                            Каждый кусочек — вполне «бытовой», встречающийся в обычных программах. А как понять что в рантайме вон тот, тот и вот ещё этот участки соберутся и получится эксплоит — неясно совершенно.

                                                                                                            Потому и паника такая, что уязвимость, сама по себе, не особо кошмарная, но вот то, что проведённая через неё атака не оставляет никаких следов — это страшно…
                                                                                                              0

                                                                                                              Вот такой кусок кода даст примерно такой же ассемблерный код:


                                                                                                              struct foo {
                                                                                                                  char flags;
                                                                                                                  char padding[4095];
                                                                                                              };
                                                                                                              
                                                                                                              struct foo array[256];
                                                                                                              unsugned char* index_ptr;
                                                                                                              
                                                                                                              do {
                                                                                                                  char flags = array[*index_ptr];
                                                                                                              } while (flags == 0);

                                                                                                              И этот код вполне себе обычный.

                                                                                                              0
                                                                                                              Я правильно понимаю, что с этими уязвимостями ничего толком не запустить? Мы можем только попытаться угадать, что хотел предсказать процессор при запросе данных из определенного места памяти?
                                                                                                                +7

                                                                                                                Ну Интел сказал же, что это не RCE.
                                                                                                                Но запуск и не требуется — просто прочитать из памяти что-нибудь вкусненькое тоже хорошо.
                                                                                                                Меня вот лично очень пугают сообщения, что чуть ли не через JS можно будет содержимое оперативной памяти читать. Зашёл на сайт с нехорошим скриптом — и пароли из KeePass утекли. Вот где ужас-то.

                                                                                                                  +8
                                                                                                                  Вы пробовали снимать дамп памяти процесса KeePass — можете найти там свои пароли?
                                                                                                                    +2
                                                                                                                    Вот-вот. Плюс нам надо запуститься в системе как минимум от юзера. Вычислить адрес приложения. Рассчитать где у него хранятся пароли. С вероятностью в N процентов попытаться их вычитать, ведь в кеше может быть не только то, что нам нужно. И на каждый тик процессора нужно создать как минимум 256 своих тиков, что жутко подвесит систему. Ну так себе уязвимость. На сервере может и не заметит никто, но рабочую машину я патчить не собираюсь.
                                                                                                                      +2
                                                                                                                      Все что вы написали не верно.
                                                                                                                      1. Вероятность прочитать правильно 99.97% (0.9997 если говорить в ТВ)
                                                                                                                      2. То что мы читаем не обязано быть в кэше, кэш используется для извлечения данных, читать можем что угодно.
                                                                                                                      3. Читать можно файловый кэш к примеру. Вроде как для js убрали эти примочки, но к примеру запуск flash может быть очень неприятный
                                                                                                                        +1
                                                                                                                        читать можем что угодно.
                                                                                                                        3. Читать можно файловый кэш к примеру.

                                                                                                                        Вы могли-бы пояснить как файловый кеш относится ко внутреннему процессорному кешу предсказаний переходов? Я, как понимаю, чтобы его (файловый кеш) считать — нужно его запросить. Для этого нужно иметь доступ к системе. А для этого нужно уже быть вирусом в системе. Тогда ЭТА уязвимость ну не совсем нужна. Точнее совсем не нужна. Если мы в системе и может запросить на чтение файл с достаточными правами — мы можем и так его считать. Может я чего не понимаю — поясните.
                                                                                                                          +5
                                                                                                                          Мы можем читать любую память, включая память ядра. Файловый кэш хранится в памяти ядра. Собственно все. Естественно, если файла нету в кэше, то его не удастся прочитать.
                                                                                                                            0
                                                                                                                            Т.е. чтобы считать хранилище паролей windows или chrome мы должны торчать в системе. Тратить 256 тиков на каждый процессорный тик только на чтение. Нам еще нужно обработать весь этот поток данных, чтобы понять, что мы читаем. Собрать все данные в один массив, система-же многозадачная и данные там будут не только ядра. Расшифровать его. Это вообще реально?
                                                                                                                              +2
                                                                                                                              все реально, легко снимается полный дамп памяти. А дальше уже можно много вещей делать.
                                                                                                                                0
                                                                                                                                Как у вас получится снять консистентный дамп памяти и успешно разобрать что/где лежит в этих XX гигах?
                                                                                                                                Приложения работающие с секретными данными
                                                                                                                                явно знают и используют функции вроде
                                                                                                                                msdn.microsoft.com/en-us/library/aa366877(v=vs.85).aspx
                                                                                                                                и не хранят открытые ключи в памяти «вечно»

                                                                                                                                  +2
                                                                                                                                  И потом совершенно незаметно эти XX гигов куда-то сохраняются и отсылаются? Да это даже не троянский слон, это троянский танкер какой-то.
                                                                                                                                    +1
                                                                                                                                    Это даже не танкер — это ходячий замок хаула. Мне не понятно какая должна быть параноика у антивируса, чтобы не заметить такое.
                                                                                                                                      0
                                                                                                                                      у антивируса

                                                                                                                                      Не у всех он стоит.
                                                                                                                                        0
                                                                                                                                        Да вообще не у всех стоит, но есть-же встроенный WinDefender. Практически не отключаемый. Проще-же было обновить его, чем городить патчи с 30% просадкой мощности.
                                                                                                                                          0
                                                                                                                                          А это уязвимость можно закрыть на уровне антивируса?
                                                                                                                                            0
                                                                                                                                            Первая, вроде как закрывается виагрой, но сам не пробовал — советовать не буду. Если вы про ту, что обсуждается в статье, то ИМХО можно закрыть предпосылки к её эксплуатации. Т.е. не давать стороннему софту пролезть на комп вообще.
                                                                                                                                              0
                                                                                                                                              JS — это софт исполняемый на стороне клиента, к примеру. Как вы собираетесь валидные, с первое взгляда, инструкции запрещать?
                                                                                                                                                0
                                                                                                                                                Я не знаю точно, но сегодня приехало обновление Firefox Quantum, в патчноуте пишут о предотвращении обсуждаемой атаки. ЗЫ: отвечал willyd, возможно, промахнулся веткой с планшета.
                                                                                                                                                  0
                                                                                                                                                  Валидность можно проверять верификацией кода перед запуском, как это делает JVM с байткодом. Что-то валидное может проверку не пройти, но это не очень большая проблема.
                                                                                                                                                    0
                                                                                                                                                    Вопрос остается только в том на сколько нечто невалидное отличается от валидного… Ну то есть если процент ложных отбраковок будет в районе долей процента — это сойдет, а если это будут единицы процентов?
                                                                                                                                                      0
                                                                                                                                                      Да даже если вы сможете придумать валидацию, в чем я сомневаюсь.
                                                                                                                                                      Сейчас, если зайти на какой-нибудь развесистый сайт, то и на ноутбуке браузер начнет замирать. А представьте, что вы еще начнете делать описанную валидацию…
                                                                                                                                                        0
                                                                                                                                                        Будет замирать еще дольше )
                                                                                                                                              0
                                                                                                                                              Да вообще не у всех стоит, но есть-же встроенный WinDefender.

                                                                                                                                              У меня его и в проекте не было.
                                                                                                                                              +1
                                                                                                                                              Зато любой обратит внимание на чудовищного объема исходящий траффик и/или на активное использование диска. Естественно, говорю о домашних пользователях, с серверами посложнее.
                                                                                                                                                +1
                                                                                                                                                Отсутствие активности мышки — вполне себе повод считать что юзера рядом нет…
                                                                                                                                                Ну и именно отправка огромных массивов — не столь уж обязательна.
                                                                                                                                        +1
                                                                                                                                        А если скопировать с памяти ядра токен который даёт нужные права приложению? Критических и весьма ценных данных в системе может быть не так уж и много, если знать где их взять — времени у троянца может быть просто масса, и если даже он будет угадывать по одному байту на системный тик с довольно высокой вероятностью он может выудить все необходимые пароли. А если в системе есть какой-то ключик который предоставит полный доступ вредоносному коду… то выуживать таким образом гигабайты не нужно — считываем ключ, пользуемся им для доступа к нужным нам гигабайтам данных — пара милисекунд после вторжения и система скомпрометирована.
                                                                                                                                          0
                                                                                                                                          Ещё раз, чтобы это сделать вы должны быть в системе как минимум от юзера. на сервере может и прокатит. На личной машине патч по сути бесполезен. Атаку понимающему человеку будет видно сразу. У остальных и так логины сопрут через фейковые сайты.
                                                                                                                                  –3
                                                                                                                                  Простой пример: Представим что JS может спокойно читать память с этой уязвимостью
                                                                                                                                  Итак для облегчение у нас есть браузер с 1 процессом на всё
                                                                                                                                  Открыто 2 страницы 1 с JS другая с <паролями> всего-то нужно хацкеру узнать адрес в памяти для нужной страницы браузера и найти место где хранятся пароли – и очень хорошо если пароли хранятся в чистом виде

                                                                                                                                  Но в реальности на 1 страницу браузера 1 процесс — надо найди нужный процесс
                                                                                                                                  В нужном процессе — найти нужное место в памяти где хранятся пароли

                                                                                                                                  Ребята да вас развоят – легче сломать какой-то саб домен пентагона через открытый порт – чем вытянут пароль реального процесса с кеш памяти процессора

                                                                                                                                  Это умышленное устаревание техники – чтоб лучше покупали новые процы
                                                                                                                                  Такой же развод как и силиконовая лотерея
                                                                                                                                  (кто не знает реальный процент брака там меньше 1 %
                                                                                                                                  и даже если б он реально был больше, То топовыйх процов (без брака)
                                                                                                                                  было б больше чем бракованных – но по факту продаж в разы наоборот – странно правда.
                                                                                                                                  (они могут как блочить в самом проце – так и спецом под шумок браковать если будет масс расследование, это литография – новая схема как два пальца об асфальт — вы ничего не докажите XD)
                                                                                                                                  (прям как в Апл с батареёй – типо они тут ни причем и сделаи ради пользователей
                                                                                                                                  Еслиб делали ради них то былаб галочка в настройках, хотя даже так пользователям пох
                                                                                                                                  Ибо они бегают от зарядки к зарядке весь день – и телефона макс хватает на 24 часа, а часто и на 12,
                                                                                                                                  а так это временной триггер для включение устаревания после N дней работы)
                                                                                                                                  (p.s вполне возможно что уже совсем скоро тот же “временной триггер устаревания” бeдет и в процах, если ещё его нет в последних моделях)
                                                                                                                                    +5
                                                                                                                                    Хочется взять и подарить учебник по русскому языку
                                                                                                                                      –2
                                                                                                                                      Ну, спасибо хоть не назвали “больным на голову параноиком”,
                                                                                                                                      а только “неграмотным школьником” ;)

                                                                                                                                      К примеру была такая уязвимость как Row hammer, пару лет назад
                                                                                                                                      И большие компании скопом взяли и «положили» на неё,
                                                                                                                                      Типо будет новый hardware – там пофиксим, а делать апдеты нету смысла
                                                                                                                                      – типо она не опасна, а тут на тебе — прошло 3 года и она внезапно стала опасна В новой форме
                                                                                                                                      (и пофиксить её решили патчем всех ОС что уменьшает производительность)

                                                                                                                                      p.s А ничё что JS и так может натворить такое, что на голову не налазит – и без всяких ваших новомодных уязвимостей
                                                                                                                                      – и всем опять откровенно на это “положить”
                                                                                                                                        0
                                                                                                                                        Видели — что патч творит с серверами?
                                                                                                                                        www.epicgames.com/fortnite/forums/news/announcements/132642-epic-services-stability-update
                                                                                                                                        я прикидывал на 50% падение производительности (в 2 раза),
                                                                                                                                        а в реальности бывает и на 70% — в 3 раза (на графике видно как с 10 выросло до 27)
                                                                                                                                        в этом нет ничего необычного
                                                                                                                                        на сервер где 32 ядра может работать под 100+ виртуалок
                                                                                                                                        каждая с 50+ сервисами/процессами
                                                                                                                                        – и при каждом переключении между ними сбрасывается “CPU оптимизация ”

                                                                                                                                        p.s разочаровал Linux что также как и Microsoft бездумно все пропатчил,
                                                                                                                                        а то что люди верят во всякую ересь тут и удивляется нечему
                                                                                                                                        (Как в то — чтоб сделать процы быстрей надо уменьшить тех процесс,
                                                                                                                                        хотя в реале надо уменьшить TDP, а TDP напрямую зависит от кривого дизайна,
                                                                                                                                        когда 30 процов стоят в притык друг к другу и нереально греют друг друга,
                                                                                                                                        и чёт я сомневаюсь что это было сделано случайно – они ж не полный раки,
                                                                                                                                        и таких рачных мелочей намного больше)

                                                                                                                                        pp.s – к сожалению дальше больше, это один из первых таких патчей…
                                                                                                                                        (может такое было и раньше, но я не помню)
                                                                                                                                      –1
                                                                                                                                      Вы немножко не понимаете, чуть больше, чем совсем. Дело тут не в процессах. Нельзя просто взять и считать данные отдельного процесса. Можно попытаться отследить когда на конкретном ядре процессора выполняется код конкретного процесса и попытаться считать его данные кеша. С не 100% Вероятностью, и потом попробовать извлечь из этих данных что-то. На что потребуется, ИМХО, мощность на порядки больная, чем атакуемого ПК.
                                                                                                                                        0
                                                                                                                                        Нельзя просто взять и считать данные отдельного процесса.
                                                                                                                                        Почему нельзя-то? В структурах данных ядра написано — где чего хранится. У нас есть доступ ко всей памяти. Заходим и читаем.
                                                                                                                                          0

                                                                                                                                          Из кеша ничего не читается, но можно сделать полный дамп памяти ядра. А потом применить volatility.

                                                                                                                                  +3
                                                                                                                                  с javascript — не очень ясно, как обратиться из js к интересуемым адресам. Вроде бы, js такое не позволяет, это же безопасный язык.
                                                                                                                                    +1
                                                                                                                                    webassembly?
                                                                                                                                      –2
                                                                                                                                      Лишний повод не поддерживать эту технологию.
                                                                                                                                        0
                                                                                                                                        wa — не js
                                                                                                                                      0
                                                                                                                                      Уже не впервый раз встречаюстя с этим мнением.
                                                                                                                                      Нет, через JS нельзя читать память других процессов используя Spectre. Но можно прочитать память своего процесса, например, браузера. Что тоже неприятно, но не настолько фатально.
                                                                                                                                    0
                                                                                                                                    Честно говоря, я не особо понял, зачем так делать — я бы просто к rax прибавил единичку сразу после чтения, да и всё


                                                                                                                                    0x00 станет 0x01, а что будет с 0xFF? Такие байты станут нулями. Т.е. проблема не исчезнет, только может немножко ускорится чтение, если нулей больше, чем 0xff.
                                                                                                                                    Но зато похоже будет 2 операции, задействующие ALU и я не уверен что в этом случае все эти команды сможет спекулятивно выполнить prefetch. Надо проверять.
                                                                                                                                      0
                                                                                                                                      0xff станет 0x100, так что там всё хорошо. Прибавлять единичку я предлагают уже в rax, там 64-битное значение хранится.
                                                                                                                                        0
                                                                                                                                        Так делается потому, что если возвращается ноль — есть вероятность что успело отработать исключение и запретить доступ в память — поэтому попытка предпринимается еще раз
                                                                                                                                        0
                                                                                                                                        А вот интересное дело: в первоначально документе сказано, что хотя PoC не удалось заставить работать на AMD и ARM, скорее всего не получилось из-за плохой оптимизации самого PoC, т.к. ассемблерный код из статьи отработал и там с ожидаемым результатом.
                                                                                                                                          +7
                                                                                                                                          Пункт 2 плохо объяснён, хотя именно в нём и кроется разница между intel и amd.
                                                                                                                                          Читаем интересную нам переменную из адресного пространства ядра, это вызовет исключение, но оно обработается не сразу.


                                                                                                                                          На intel'ах проверка прав производится после чтения, а на amd — до. Таким образом, у intel'а получается спекулятивное чтение (прогревающее кеш), а у amd — спекулятивный segmentation fault.
                                                                                                                                            +1
                                                                                                                                            Осталось прикрутить термометр к регистру, хранящему Segmentation Fault, чтобы определить был ли он задействован.
                                                                                                                                              0
                                                                                                                                              Если это так, как написал amarao, этот регистр по-любому будет задействован… Неудачная шутка…
                                                                                                                                              С другой стороны, это может объяснить почему на разных семействах процессоров Intel уязвимость есть, а у AMD — нет. Независимо от физического расположения регистров — кэшей на кристалле. Логика отработки спекулятивного исполнения разная.
                                                                                                                                                –2
                                                                                                                                                Как это у амд нет?

                                                                                                                                                интел не устойчив к обеим типам
                                                                                                                                                амд не устойчив только к spectre

                                                                                                                                                Но почему-то народное внимание акцентировано на интелах и meltdown, а амд в головах людей «надежны». Думаю, не последнюю роль тут сыграли маркетологи амд.
                                                                                                                                                На самом деле, это означает, что уязвимость есть везде. Я еще не разбирался с meltdown, но навскидку уязвимости весьма похожи. По сути, это 1 тип уязвимости, просто мы meltdown-это вид в фас, а spectre — вид в профиль. И основная уязвимость — та, которой подвержены обе фирмы, то есть spectre.
                                                                                                                                                  0
                                                                                                                                                  Похоже, что уязвимость присутствует не только у процессоров Intel и AMD, но и у многих процессоров с архитектурой ARM.
                                                                                                                                                    +1
                                                                                                                                                    www.amd.com/en/corporate/speculative-execution

                                                                                                                                                    амд уже пофиксили без потери производительности
                                                                                                                                                      0
                                                                                                                                                      Без понятия. Возможно, то, что написано по ссылке, соответствует реальному положению дел. Но на моем phenom b40 уязвимость есть.

                                                                                                                                                      Да и то, что они написали — «Resolved by software / OS updates to be made available by system vendors and manufacturers» — это же отмазка! Хочется же, чтобы и баз был закрыт — и производительность не падала. А патчи существенно снижают производительность (уже есть статья про это), повышают энергопотребление и тепловыделение.
                                                                                                                                                      0
                                                                                                                                                      > Но почему-то народное внимание акцентировано на интелах и meltdown, а амд в головах людей «надежны».

                                                                                                                                                      Meltdown легко сделать, даже в JS. И он не работает на AMD.

                                                                                                                                                      Spectre значительно труднее сделать, по крайней мере Гуглу пришлось воспользоваться eBPF, который по умолчанию выключен.