Секреты одной UEFI-опции AMD CBS

Знакомясь с настройками UEFI BIOS ма­те­рин­ской пла­ты ASUS Prime TRX40-Pro, как плат­фор­мы для ра­бо­чих стан­ций на ба­зе про­цес­со­ра AMD Thread­ripper 3970X, труд­но бы­ло прой­ти ми­мо од­ной за­га­доч­ной оп­ции. В об­щем пу­ле на­ст­ро­ек раз­де­ла AMD CBS (что рас­шиф­ро­вы­ва­ет­ся как Com­mon BIOS Spe­ci­fi­ca­tions, хо­тя по­нят­нее бы­ло бы Cus­tom BIOS Set­tings) при­та­ил­ся пункт ме­ню Re­di­rect­For­Re­turn­Dis, на­з­ва­ние ко­то­ро­го ни о чем не го­во­рит. По­пы­та­ем­ся ис­сле­до­вать роль и мес­то этой оп­ции в эко­сис­те­ме но­во­го по­ко­ле­ния про­цес­со­ров, по­ст­ро­ен­ных на ба­зе ар­хи­тек­ту­ры Zen 2.

RedirectForReturnDis — this item from a workaround for GCC/C000005 issue for XV Core on CZ A0, setting MSRC001_1029 Decode Configuration (DE_CFG) bit 14 [DecfgNoRdrctForReturns] to 1

RedirectForReturnDis — this item from a workaround for GCC/C000005 issue for XV Core on CZ A0, setting MSRC001_1029 Decode Configuration (DE_CFG) bit 14 [DecfgNoRdrctForReturns] to 1

Дословно, в контексте комментария к опции RedirectForReturnDis можно предположить, что речь о про­яв­ле­нии ошибки, до­пу­щен­ной разработчиками процессора, в результате которой, при определенном не­бла­го­при­ят­ном стечении об­сто­я­тельств, дан­ные, воз­вра­ща­е­мые ин­ст­рук­ци­ей чтения, будут искажены. Скорее все­го, речь идет о том, что ис­ка­же­ние в пер­вую оче­редь кос­ну­лось данных, чи­та­е­мых из стека в качестве ад­ре­са возврата при выполнении ин­ст­рук­ций воз­в­ра­та RET (или IRET — возврат из пре­ры­ва­ния). В любом слу­чае ситуация возникает как результат неверной син­хро­ни­за­ции спекулятивных механизмов. Для ис­клю­че­ния этого опасного сце­на­рия требуется пе­ре­на­ст­ро­ить мо­де­ле­за­ви­си­мый регистр цен­т­раль­но­го про­цес­со­ра MSR C001_0029h.

Как можно понять из обсуждения в интернете, озна­чен­ное ис­ка­же­ние влияет на устойчивость работы ком­пи­ля­то­ра GCC. В ситуации, когда обновление UEFI недоступно, ре­ко­мен­ду­ет­ся ус­та­нав­ли­вать в коде ядра Linux без­о­пас­ное зна­че­ние регистра MSRC001_1029:

Workaround for GCC/C000005 issue for XV Core on CZ A0, setting MSRC001_1029 Decode Configuration (DE_CFG) bit 14 [DecfgNoRdrctForReturns] to 1. C000005 is STATUS_ACCESS_VIOLATION (Segfault). Linux kernel can set MSRC001_1029 without UEFI update (wrmsr).

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

MSRC001_1029 частично документирован в описаниях процессоров AMD .Официальную информацию о его би­тах 13 и 14, представляющих интерес в рассматриваемом контексте, найти не удалось. По логике и кон­тек­с­ту, ини­ци­а­ли­за­ция данного мо­де­ле­за­ви­си­мого регистра входит в обязанности UEFI. Одно из не­мно­гих офи­ци­аль­ных упоминаний о MSRC001_1029h есть в документе Managing Speculation on AMD Pro­ces­sors, но там описывается функциональность другого бита [1], управляющего уровнем строгости син­хро­ни­за­ции, ко­то­рую обеспечивает инструкция LFENCE (Load Fence).

Документ Revision Guide for AMD Family 17h Processors на странице 31 также ссылается на мо­де­ле­за­ви­си­мый регистр цен­т­раль­но­го про­цес­со­ра MSRC001_0029h, вернее, на его 13-й бит, в то время, когда UEFI кам­нем преткновения счи­та­ет 14-й бит. Весьма вероятно, что оба бита используются для отключения не­ко­то­рых спе­ку­ля­тив­ных механизмов, из­ме­ня­ю­щих по­сле­до­ва­тель­но­с­ти операций чтения и записи. Это оз­на­ча­ет, что их ус­та­нов­ка в единичное состояние при­ве­дет к более стабильной работе процессора, ценой сни­же­ния про­из­во­ди­тель­но­с­ти.

Все упоминания связывает общий контекст, в котором можно выделить такие проблемы:

  • вероятность искажения данных;
  • вероятность намеренной реализации вредоносных сценариев.

Детализируем сказанное

  1. Логика синхронизации требует поддерживать консистентность при чтении и записи данных, не­смо­т­ря на на­ли­чие спекулятивных механизмов. Точнее, нарушения синхронизации, в ре­зуль­та­те которых поток уви­дел соб­ст­вен­ное не­кон­сис­тен­т­ное состояние не до­пус­ка­ют­ся и кор­рек­ти­ру­ют­ся процессором аппаратно, а нарушения синхронизации, в результате которых один по­ток увидел не­кон­сис­тен­т­ное состояние другого потока, до­пус­ка­ют­ся, не кор­рек­ти­ру­ют­ся ап­па­рат­но и требуют внимания со стороны программиста или разработчика ком­пи­ля­то­ра. Для их кор­рек­ции ис­поль­зу­ют­ся инструкции семейства MFENCE/SFENCE/LFENCE (Memory Fence, Store Fen­ce, Load Fence), создающие так называемый «барьер» для спекулятивных операций доступа к па­мя­ти. Смысл такого механизма в том, что инструкции обращения к памяти, расположенные до «барь­е­ра» должны быть полностью выполнены до начала обработки инструкций, расположенных по­сле «барье­ра». Полное выполнение здесь оз­на­ча­ет наступление последствий операций об­ра­ще­ния к па­мя­ти, программно-видимых все­ми про­цес­со­ра­ми муль­ти­про­цес­сор­ной плат­фор­мы. Если раз­ра­бот­чики процессора допустили ошибки в синхронизации, то, воз­мож­но, на­ру­ше­ние этих пра­вил приведет к тому, что поток, например, может «потерять» операцию записи и ин­ст­рук­ция чте­ния получит устаревшие данные, имевшие место до записи. Если такой баг об­на­ру­жен в в про­цес­со­рах, уже выпущенных и поставленных потребителю, то спасти ситуацию мо­жет раз­ра­бот­чик (кас­то­ми­за­тор) UEFI, хотя и ценой некоторого снижения про­из­во­ди­тель­но­с­ти. Для это­го спекулятивные операции, в логике синхронизации которых до­пу­ще­ны ошибки, запрещаются. Этим и управляет MSR #C001_1029h.
  2. Для авторов вредоносных сценариев важно то, что используя нарушения синхронизации можно про­чи­тать дан­ные, доступ к которым запрещен согласно законной логике программы. Уп­ро­щен­ный пример: вредоносный код может прочитать пароль из области памяти, уже после то­го, как ОС обнулила эту область, так как есть ве­ро­ят­ность запаздывания наступления про­г­рам­мно-ви­ди­мых последствий операции записи относительно операции чтения. В этом уп­ро­щен­ном примере, по ло­ги­ке программы, обнуление области памяти должно произойти до по­пыт­ки ее чтения, но в си­лу спекулятивных механизмов может наступить позже, в результате ра­нее хранившиеся там дан­ные (например, пароль) будут прочитаны.