LINUXTALKS.CO

Блоги - Архив 2022, Июль

Набивка буфера стека возврата

Блоги — Переводы статей
Группа Переводы статей

Retbleed — это название класса уязвимостей спекулятивного исполнения, связанных с инструкциями возврата. Средства защиты от Retbleed попали в основное ядро, но на момент написания этой статьи некоторые остающиеся проблемы не позволили им попасть в стабильные выпуски обновлений. Защита от Retbleed может сильно снизить производительность, особенно на некоторых процессорах Intel. Томас Глейкснер (Thomas Gleixner) и Питер Зайлстра (Peter Zijlstra) считают, что они нашли лучший способ, который обходит существующие средства защиты и вводит в заблуждение механизмы спекулятивного выполнения процессора.

Для того чтобы процессор мог предсказать значение после инструкции возврата, он должен иметь некоторое представление о том, куда вернется код. В последних моделях процессоров Intel существует специальная скрытая структура данных, называемая «буфером стека возврата» (RSB), которая кэширует адреса возврата для спекуляций. RSB может содержать 16 записей, поэтому он должен отбрасывать самые старые записи, если цепочка вызовов идет глубже этого значения. При возврате глубокой цепочки вызовов RSB может переполниться. Можно было бы подумать, что спекуляция просто прекратится в этот момент, но вместо этого процессор прибегает к другим эвристикам, включая предсказание из буфера истории ветвлений. Увы, техники неправильного обучения буфера истории ветвей на данный момент хорошо изучены.

В результате длинные цепочки вызовов в ядре подвержены атакам спекулятивного выполнения. На процессорах Intel, начиная с поколения Skylake, единственным способом предотвратить такие атаки является включение «функции» процессора indirect branch restricted speculation (IBRS), которая была добавлена Intel в начале эры Spectre. IBRS работает, но у нее есть нежелательный побочный эффект - снижение производительности на целых 30%. По какой-то причине пользователи не испытывают энтузиазма по поводу этого решения.

Другой способ

Глейкснер и Зайлстра решили попробовать другой подход. Спекулятивным выполнением обратных вызовов на этих процессорах можно злоупотреблять только в том случае, если RSB недополнен. Таким образом, если недополнение RSB можно предотвратить, эта конкретная проблема исчезнет. А этого, похоже, можно добиться, «набивая» RSB всякий раз, когда есть риск, что в нем закончатся записи.

Это сразу же приводит к двум новым проблемам: узнать, когда RSB заканчивается, и найти способ наполнить его снова. Первая задача решается путем отслеживания текущей глубины цепочки вызовов приблизительным способом. Система сборки модифицирована для создания пары новых секций в исполняемом образе ядра, чтобы хранить thunk входа и выхода для функций ядра и отслеживать их. Если включена начинка RSB, то при входе в каждую функцию будет вызываться входной thunk, а выходной thunk будет выполняться на выходе.

Состояние RSB отслеживается с помощью 64-битного значения для каждого процессора, которое первоначально установлено в:

    0x8000 0000 0000 0000

Функция входа увеличивает этот счетчик, сдвигая его вправо на пять бит. Процессор увеличивает значение по знаку, поэтому после первого вызова счетчик будет выглядеть следующим образом:

    0xfc00 0000 0000 0000 0000

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

Этим «что-то» является быстрая серия вызовов функций (закодированных на ассемблере и приведенных в конце этого патча), которая добавляет 16 записей в стек вызовов, а значит, и в RSB. Каждый из этих вызовов, при возврате из него, немедленно выполнит инструкцию int3; это остановит спекуляцию, если эти возвратные вызовы когда-либо выполнялись спекулятивно. Конечно, реальное ядро не хочет выполнять эти инструкции (или все эти возвраты), поэтому код RSB-stuffing увеличивает реальный указатель стека на только что добавленные кадры вызовов.

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

Затраты

Довольно много работы было проделано для минимизации накладных расходов этого решения, особенно в системах, где оно не нужно. Ядро собирается с прямыми вызовами своих функций, как обычно; во время загрузки, если выбрана опция retbleed=stuff, все эти вызовы будут исправлены, чтобы проходить через учетные транзакторы. Сами блоки размещены в огромном страничном отображении, чтобы минимизировать накладные расходы на буфер lookaside трансляции. Несмотря на это, как отмечается в сопроводительном письме, существуют издержки: «Мы оба, что неудивительно, весьма ненавидим результат».

Эти издержки проявляются в нескольких формах. Требуется «впечатляющий» объем памяти для хранения банков и связанной с ними домашней работы. Раздувание ядра влияет на производительность, даже в системах, где не включена функция RSB stuffing. Дополнительные инструкции увеличивают нагрузку на кэш инструкций, замедляя выполнение. Последняя проблема может быть несколько смягчена, говорится в сопроводительном письме, если выделять thunks в начале каждой функции, а не в отдельном разделе. Глейкснер подготовил патч для GCC, чтобы сделать это возможным, и сообщает, что при его использовании некоторые потери производительности уменьшаются.

Сопроводительное письмо содержит длинный список эталонных результатов, сравнивающих производительность RSB stuffing с производительностью полного отключения защиты и использования IBRS. Цифры для RSB stuffing поражают воображение, включая 382% регресс производительности для одного микробенчмарка. Однако во всех случаях RSB stuffing работает лучше, чем IBRS.

Однако лучшая производительность по сравнению с IBRS интересна только в том случае, если достигнута главная цель – блокирование атак Retbleed. В сопроводительном письме говорится следующее:

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

Итак, похоже, что RSB stuffing работает – по крайней мере, пока. Это должно сделать его привлекательным в ситуациях, когда защита от атак Retbleed считается необходимой; хостинг-провайдеры с недоверенными пользователями – один из очевидных примеров. Но никто не будет доволен накладными расходами, даже если они лучше, чем у IBRS. Для многих пользователей RSB stuffing будет рассматриваться как умный хак, который, к счастью, им не придется использовать.

Оригинал статьи на LWN

 , , , ,

cocucka ()

Взаимодействие через Google Meet при сильно отличающихся разрешениях экрана

Блоги — How-to
Группа How-to

По работе пришлось провести серию удаленных встреч с коллегой из Швейцарии. Он должен был кое-что настроить на тестовом контуре под моим наблюдением, чтобы попрактиковаться в настройке и потом выполнять похожие задачи самостоятельно. Соответственно, созвонились через Google Meet, он показал свой экран, а мне надо объяснять, что, собственно, надо настраивать, и контролировать процесс.

Проблема: у меня ноутбук 13" с Full HD экраном (масштаб шрифтов 125%), у него десктоп с монитором более высокого разрешения, и буквы в его терминале и браузере для меня слишком мелкие. И еще Google Meet не умеет честный полноэкранный режим и отъедает часть разрешения на заголовок «Коллега is presenting» вверху и панель с кнопочками внизу. Собственно, приходится напрягать глаза, что нездорово.

DE у меня - Cinnamon, у него какой-то tiling WM. Каждый раз просить коллегу сделать шрифты покрупнее не хочется, поэтому я исследовал возможность внедрения какого-нибудь костыля локально, чтобы увеличить часть экрана.

В Cinnamon встроенная экранная лупа на самом деле есть. Ее можно включить через Control Center: Accessibility > Visual > Enable zoom. Тогда через Alt + прокрутку вверх можно увеличить часть экрана. Вот только это не помогло. Были буковки из горстки пикселей, стали буковки из горстки увеличенных пикселей. Оказывается, я не только напрягал глаза, но и мозги, чтобы додумывать, что это там написано. То есть, оказывается, уже на этапе отрисовки картинки с экрана коллеги на мой экран (а может, еще и при передаче картинки) происходит серьезная потеря информации.

Иными словами, чтобы экранная лупа стала полезной, Chromium должен отрисовывать Google Meet в буфер с разрешением, большим, чем разрешение моего экрана. Этого можно добиться через xrandr:

xrandr --output eDP-1 --scale-from 3840x2160

Сработало, но ценой мелких букв уже у меня.

А на самом деле эта функциональность встроена в Cinnamon, и команду xrandr вручную вводить не надо. Называется эта функциональность Fractional Scaling, и Cinnamon при ее использовании также заставляет графические тулкиты рисовать UI в большем масштабе. Логика такая: выбранный пользователем масштаб округляется вверх до ближайшего целого (125% -> 200%), GTK настраивается на отрисовку с целочисленным масштабированием в виртуальный буфер, который средствами xrandr затем уменьшается до настоящего размера экрана. С точки зрения приложений, разрешение экрана составляет 3072x1728, и буквы на экране коллеги уже отображаются как буквы, а не как горстка пикселей. Лупе есть, что увеличивать, а мне не приходится напрягать ни глаза, ни мозги.

Ну и напоследок, можно задать нестандартный масштаб экрана в ~/.config/cinnamon-monitors.xml в теге <scale> в секции <logicalmonitor>. Например, при значении 1.0000001 срабатывает округление вверх до 200%, а потом масштабирование вниз, по сути, на те же 200%. С точки зрения приложений, разрешение экрана составляет 3840x2160, и лупа берет такую детальную картинку в качестве исходной, а с точки зрения пользователя, изменений практически нет. Поэтому я эту настройку так и оставил. Единственный обнаруженный негативный момент - в mpv появляется тиринг.

P.S. Трюк со scale 1.0000001 в ~/.config/monitors.xml также работает в Gnome. Но экранная лупа там сделана менее удобно, чем в Cinnamon. Вызывается через Alt + Super + 8, и надо настроить следование за курсором мыши и половинный размер в параметрах доступности. Неудобно, что лупа бывает только в пол-экрана или во весь экран, но не в четверть экрана.

 , ,

AEP ()

Passwordless login with U2F security key

Блоги — Персональные блоги участников
Группа Персональные блоги участников

Настроить passwordless login с Yubikey проще парёной репы.

Надо:

  1. Установить libpam_u2f.so из их репы

  2. Зарегистрировать свой ключ pamu2fcfg > ~/.config/Yubico/u2f_keys

  3. Добавить в соответствующие конфиги pam (минимум для sudo и для login manager) строчку auth sufficient pam_u2f.so перед строкой @include common-auth

  4. Добавить правило udev ACTION=="remove", ATTRS{idVendor}=="1050", RUN+="/bin/loginctl lock-sessions"

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

Это репост моего мини-гайда с ЛОРа, раз уж там есть, то пусть и у нас будет.

 , , ,

cocucka ()