Intel'овский аппаратный clusterfuck
2018-01-02 10:02 pmВ Linux (4.15+) и в Windows (10 build 17035+) недавно закоммитили патчи, которые изменяют таблицы страниц таким способом, чтобы все страницы выше середины адресного пространства не были отображены в userspace-контексте.
Таким образом, регистр CR3 и все TLB стали сбрасываться при каждом пересечении границы ядро/юзерспейс. Это происходит дважды на каждом системном вызове и дважды при обработке каждого аппаратного прерывания, а также для page fault (рост стека, своппинг и обращения к отображённым в память файлам). В результате, утилиты типа du стали работать на 50% медленнее. Про десятую винду я уже молчу, после недавнего большого апдейта FCU она и так едва шевелилась.
На подходе публикация информации о какой-то серьёзной аппаратной уязвимости, предположительно — о возможности читать ядерную память из юзерспейса на интеловских процессорах. Причём это будет уязвимость, не исправимая на уровне микрокода, и затрагивающая широкий ассортимент процессоров, выпущенных в разные годы (у Intel нет финансовой возможности отозвать/заменить их все).
С точки зрения нормально работающего процессора всё это не нужно: чтению ядерных страниц из юзерспейса препятствуют лимиты сегментных дескрипторов и флаги защиты страниц. Но, по всей видимости, там всё не так уж и герметично: уже раньше были свидетельства о том, что исполнение инструкций в процессоре опережает проверку привилегий, а результаты выполнения таких инструкций хоть и отменяются на аппаратном уровне, но меняют состояние процессорного кэша: https://cyber.wtf/2017/07/28/negative-result-reading-kernel-memory-from-user-mode/
Любой студент-айтишник, изучавший в институте проектирование процессоров, знает, что в процессорах с поддержкой MMU (виртуальной памяти) преобразование виртуальных адресов в физические адреса посредством TLB происходит физически одновременно с работой кэшей первого/второго/третьего уровней. Именно благодаря этой хитрости, накладные расходы на MMU условно равны нулю, и именно поэтому кэширование данных осуществляется с привязкой к виртуальным адресам, а не к физическим, невзирая на все недостатки такого подхода (например некогерентность обновлений при множественных отображениях). Двойная инвалидация всех TLB на каждом системном вызове, на каждом аппаратном прерывании, и на каждом page fault на корню убивает все преимущества по производительности, даваемые этой хитрой схемой. Раньше TLB инвалидировались только при переключении процессов планировщиком задач, и за один таймслот (10 мс на Windows) потенциально можно было выполнить сотни тысяч вызовов ядра (каждый вызов занимает порядка нескольких сотен машинных циклов). Именно поэтому оценочная цифра потери производительности в два раза выглядит черезчур оптимистичной для меня.
UPD (2018-01-04 00:00 UTC). Google Project Zero нарушил эмбарго и досрочно опубликовал все технические подробности этой атаки: https://meltdownattack.com/meltdown.pdf
Таким образом, регистр CR3 и все TLB стали сбрасываться при каждом пересечении границы ядро/юзерспейс. Это происходит дважды на каждом системном вызове и дважды при обработке каждого аппаратного прерывания, а также для page fault (рост стека, своппинг и обращения к отображённым в память файлам). В результате, утилиты типа du стали работать на 50% медленнее. Про десятую винду я уже молчу, после недавнего большого апдейта FCU она и так едва шевелилась.
На подходе публикация информации о какой-то серьёзной аппаратной уязвимости, предположительно — о возможности читать ядерную память из юзерспейса на интеловских процессорах. Причём это будет уязвимость, не исправимая на уровне микрокода, и затрагивающая широкий ассортимент процессоров, выпущенных в разные годы (у Intel нет финансовой возможности отозвать/заменить их все).
С точки зрения нормально работающего процессора всё это не нужно: чтению ядерных страниц из юзерспейса препятствуют лимиты сегментных дескрипторов и флаги защиты страниц. Но, по всей видимости, там всё не так уж и герметично: уже раньше были свидетельства о том, что исполнение инструкций в процессоре опережает проверку привилегий, а результаты выполнения таких инструкций хоть и отменяются на аппаратном уровне, но меняют состояние процессорного кэша: https://cyber.wtf/2017/07/28/negative-result-reading-kernel-memory-from-user-mode/
Любой студент-айтишник, изучавший в институте проектирование процессоров, знает, что в процессорах с поддержкой MMU (виртуальной памяти) преобразование виртуальных адресов в физические адреса посредством TLB происходит физически одновременно с работой кэшей первого/второго/третьего уровней. Именно благодаря этой хитрости, накладные расходы на MMU условно равны нулю, и именно поэтому кэширование данных осуществляется с привязкой к виртуальным адресам, а не к физическим, невзирая на все недостатки такого подхода (например некогерентность обновлений при множественных отображениях). Двойная инвалидация всех TLB на каждом системном вызове, на каждом аппаратном прерывании, и на каждом page fault на корню убивает все преимущества по производительности, даваемые этой хитрой схемой. Раньше TLB инвалидировались только при переключении процессов планировщиком задач, и за один таймслот (10 мс на Windows) потенциально можно было выполнить сотни тысяч вызовов ядра (каждый вызов занимает порядка нескольких сотен машинных циклов). Именно поэтому оценочная цифра потери производительности в два раза выглядит черезчур оптимистичной для меня.
UPD (2018-01-04 00:00 UTC). Google Project Zero нарушил эмбарго и досрочно опубликовал все технические подробности этой атаки: https://meltdownattack.com/meltdown.pdf