Как именно работят Meltdown и Spectre
На 4 януари 2018 година излезе информация за огромна хардуерна накърнимост в процесорите на Intel, която дава опция на непривилегирована стратегия да получи достъп до данните в ядрото на компютърната система. Тази накърнимост бе наречена Meltdown . По-късно бе открит метод за потребление на сходна накърнимост в съвсем всички процесори, който получи името Spectre .
С какво стартира всичко
Началото на тази история напълно не е 4-ти януари. Още в далечната 2008 година, съветският експерт по компютърна сигурност Крис Касперски разкри сериозна накърнимост в процесорите на Intel, която дава опция за отдалечено хакване на компютърната система посредством JavaScript или непосредствено посредством TCP/IP, без значение от операционната система. Крис възнамеряваше да показа работещ код за Windows и Linux, само че след това всичко затихна за цели 10 години. Сега няма по какъв начин да намерим цялата информация, тъй като Крис почина при скок с парашут.
За повторно тази накърнимост бе разкрита от няколко самостоятелни групи от специалисти и по-точно, от Гугъл Project Zero, Cyberus Technology и други. Всичко бе защитавано в загадка, с цел да могат разработчиците да основат и пуснат пачове за отбрана от Meltdown И Spectre. През цялото това време водещите Windows и Linux програмисти взаимно работиха върху върху решението на казуса. Плановете бяха данните за Meltdown и Spectre да бъдат оповестени на 9 януари 2018 година, само че информацията изтече по-рано – The Register някак разбра за тези уязвимости и разгласява всичко.
Уязвимостта Meltdown
Да разгледаме насъбраната до момента информация за Meltdown, и да се опитаме да разберем, дали в действителност всичко е толкоз ужасно. Първоначално в резюме да разгледаме по какъв начин работи процесора.
През последните десетилетия, започвайки от 1992 година, когато се появи първият Pentium, Intel непрестанно развиваше своята суперскаларна архитектура на своите процесори. Идеята е да се основат бързи процесори, запазвайки противоположната съгласуемост. Получава се една комплицирана конструкция, в която компилаторът подрежда и опакова инструкциите по подобен метод, че да се извършват в един поток, а процесорът вътре в себе си разделя кода на обособени команди и стартира да ги извършва редом, стига да е допустимо, и даже разменя тяхната поредност. Причината за тези дейности е, че хардуерните блокове за изпълняването на командите в процесора са доста и всяка директива нормално задейства единствено един от тях. И още, тактовата периодичност на процесорите с излизането на нови модели, нараства доста по-бързо, в сравнение с скоростта на оперативната памет. Това докара до появяването на кешове от 1, 2 и 3 равнище. Да се прочете или запише информация от и в оперативната памет са нужни повече от 100 процесорни такта, а достъпът до кеш паметта от 1 равнище става единствено за единици тактове – изпълняването на интервенция от вида на аритметично събиране на операнди да вземем за пример, става единствено за два такта.
Като резултат от всичко това, до момента в който една директива чака приемането на данни от паметта или освобождението на floating point блока, или още нещо, процесорът спекулативно обработва идващите указания. Съвременните процесори по този метод могат редом да обработват към 100 указания (97 в Sky Lake, в случай че би трябвало да бъдем точни). Всяка сходна директива работи със свое копие на регистрите (това става в reservation station) и по време на осъществяването, те по този метод не си въздействат един на различен. След като въпросната директива е изпълнена, процесорът се пробва да подреди резултатите от осъществяването на тези указания в блока retirement, като че ли тази суперскаларност я е нямало (компилаторът не знае за това и смята, че това си е поредно осъществяване на кода). Ако по някаква причина процесорът реши, че някоя от тези указания е изпълнена погрешно – да вземем за пример, пробва се да употребява смисъла на регистъра, променено от предходна директива, то настоящата директива ще бъде изхвърлена. Същото става и при измененията в клетките на паметта, в случай че предсказването на прехода се е оказало неверно.
Паметта в операционната система
В 64-битов режим всяко приложение разполага със личен блок памет, само че в действителност паметта на ядрото също участва в адресното пространство на процеса за повишение продуктивността на систематичните извиквания, само че е предпазена от достъп от страна на потребителския код. Ако директива от потребителския код се опита да получи достъп към предпазената памет, то се генерира неточност на равнище защитните механизми на процесора и неговите защитни пръстени Ring 0, Ring 1, Ring 2 и така нататък
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. Извършваме спекулативно четене от масива, който се намира в нашето адресно пространство, като използваме смисъла на променливата от втората точка
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] – „запомняне“ на прочетеното значение и работа с кеша. Информацията на специалистите на Гугъл Project Zero стопира дотук, с цел да няма злоупотреби. Но концепцията е ясна.
Защитените данни могат да се прочетат даже с JavaScript код, с който са препълнени актуалните уеб-страници. А това прави казуса световен.
Ясно е, че с цел да се запуши тази накърнимост в операционните системи, може просто да се раздели виртуалното адресно пространство на паметта и на Оценка за съвместимост ядрото. Но това съществено ще забави операционната система, тъй като систематичните извиквания ще лишават доста повече време. Точно това се случва в компютърните системи с към този момент конфигурирани пачове.
Meltdown получи показател CVE-2017-5754 и визира:
Всички процесори на Intel от семействата Core, Xeon, Celeron и Pentium с Core ядраARM процесорите с най-новите ядра Cortex-A75Всички iOS устройства с ARM основани процесори
Ето един забавен образец за потреблението на Meltdown:
Какво е Spectre
Meltdown получи показател CVE-2017-5754 и визира всички процесори на Intel от последните 10 и даже 15 години. На втората накърнимост Spectre, открита освен в процесорите на Intel, само че и в ARM чиповете, бяха присвоени два идентификатора: CVE-2017-5753 (секретен байт) и CVE-2017-5715 (еднакви поредни инструкции), като последният важи и за някои процесори на AMD.
Spectre не може да прониква в паметта на ядрото, само че дава достъп до паметта на другите приложения.
Тази технология може да принуди всеки развой независимо да покаже съдържимото на своята памет. Използва се поредност повтарящи се указания, с които се тренира блока за предсказание на преходите, а по-късно му се подава напълно друга, особено подбрана директива. По този метод границите сред изолираните приложения в тези сериозни случаи се размиват и става допустимо прочитането на предпазените данни на друго приложение, само че не и от ядрото.
Няма универсална отбрана от Spectre: разкритият механизъм може да употребява цялостен набор от разновидности, което усложнява стартирането на повсеместен пач. Налага се приложението единствено да пази своята памет или непрестанно да чисти кеша. Това значи прекомпилиране на всички приложения и съществено намаление на продуктивността. А и надали програмистите ще се заемат просто по този начин да прекомпилират приложенията си.
Spectre визира следните процесори:
Всички процесори на IntelВсичко нови ядра на ARM, поддържащи спекулативно осъществяване на кодаНякои процесори на AMD
Но през днешния ден AMD публично заяви, че за потреблението на тази накърнимост в нейните процесори, е нужен физически достъп до компютърното устройство, само че за това ще стане дума в друга публикация.
Безспорно, Meltdown и Spectre са съществени неточности и ще би трябвало по-внимателно да следим за сигурността на нашите устройства. Но всеки самичък взема решение за себе си. Вече започнаха да излизат указания, по какъв начин да се ревизира, дали системата е уязвима към Meltdown и Spectre и по какъв начин да се изключат фиксовете за тях в другите операционни системи. Това също е тематика за различен материал.
С какво стартира всичко
Началото на тази история напълно не е 4-ти януари. Още в далечната 2008 година, съветският експерт по компютърна сигурност Крис Касперски разкри сериозна накърнимост в процесорите на Intel, която дава опция за отдалечено хакване на компютърната система посредством JavaScript или непосредствено посредством TCP/IP, без значение от операционната система. Крис възнамеряваше да показа работещ код за Windows и Linux, само че след това всичко затихна за цели 10 години. Сега няма по какъв начин да намерим цялата информация, тъй като Крис почина при скок с парашут.
За повторно тази накърнимост бе разкрита от няколко самостоятелни групи от специалисти и по-точно, от Гугъл Project Zero, Cyberus Technology и други. Всичко бе защитавано в загадка, с цел да могат разработчиците да основат и пуснат пачове за отбрана от Meltdown И Spectre. През цялото това време водещите Windows и Linux програмисти взаимно работиха върху върху решението на казуса. Плановете бяха данните за Meltdown и Spectre да бъдат оповестени на 9 януари 2018 година, само че информацията изтече по-рано – The Register някак разбра за тези уязвимости и разгласява всичко.
Уязвимостта Meltdown
Да разгледаме насъбраната до момента информация за Meltdown, и да се опитаме да разберем, дали в действителност всичко е толкоз ужасно. Първоначално в резюме да разгледаме по какъв начин работи процесора.
През последните десетилетия, започвайки от 1992 година, когато се появи първият Pentium, Intel непрестанно развиваше своята суперскаларна архитектура на своите процесори. Идеята е да се основат бързи процесори, запазвайки противоположната съгласуемост. Получава се една комплицирана конструкция, в която компилаторът подрежда и опакова инструкциите по подобен метод, че да се извършват в един поток, а процесорът вътре в себе си разделя кода на обособени команди и стартира да ги извършва редом, стига да е допустимо, и даже разменя тяхната поредност. Причината за тези дейности е, че хардуерните блокове за изпълняването на командите в процесора са доста и всяка директива нормално задейства единствено един от тях. И още, тактовата периодичност на процесорите с излизането на нови модели, нараства доста по-бързо, в сравнение с скоростта на оперативната памет. Това докара до появяването на кешове от 1, 2 и 3 равнище. Да се прочете или запише информация от и в оперативната памет са нужни повече от 100 процесорни такта, а достъпът до кеш паметта от 1 равнище става единствено за единици тактове – изпълняването на интервенция от вида на аритметично събиране на операнди да вземем за пример, става единствено за два такта.
Като резултат от всичко това, до момента в който една директива чака приемането на данни от паметта или освобождението на floating point блока, или още нещо, процесорът спекулативно обработва идващите указания. Съвременните процесори по този метод могат редом да обработват към 100 указания (97 в Sky Lake, в случай че би трябвало да бъдем точни). Всяка сходна директива работи със свое копие на регистрите (това става в reservation station) и по време на осъществяването, те по този метод не си въздействат един на различен. След като въпросната директива е изпълнена, процесорът се пробва да подреди резултатите от осъществяването на тези указания в блока retirement, като че ли тази суперскаларност я е нямало (компилаторът не знае за това и смята, че това си е поредно осъществяване на кода). Ако по някаква причина процесорът реши, че някоя от тези указания е изпълнена погрешно – да вземем за пример, пробва се да употребява смисъла на регистъра, променено от предходна директива, то настоящата директива ще бъде изхвърлена. Същото става и при измененията в клетките на паметта, в случай че предсказването на прехода се е оказало неверно.
Паметта в операционната система
В 64-битов режим всяко приложение разполага със личен блок памет, само че в действителност паметта на ядрото също участва в адресното пространство на процеса за повишение продуктивността на систематичните извиквания, само че е предпазена от достъп от страна на потребителския код. Ако директива от потребителския код се опита да получи достъп към предпазената памет, то се генерира неточност на равнище защитните механизми на процесора и неговите защитни пръстени Ring 0, Ring 1, Ring 2 и така нататък
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. Извършваме спекулативно четене от масива, който се намира в нашето адресно пространство, като използваме смисъла на променливата от втората точка
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] – „запомняне“ на прочетеното значение и работа с кеша. Информацията на специалистите на Гугъл Project Zero стопира дотук, с цел да няма злоупотреби. Но концепцията е ясна.
Защитените данни могат да се прочетат даже с JavaScript код, с който са препълнени актуалните уеб-страници. А това прави казуса световен.
Ясно е, че с цел да се запуши тази накърнимост в операционните системи, може просто да се раздели виртуалното адресно пространство на паметта и на Оценка за съвместимост ядрото. Но това съществено ще забави операционната система, тъй като систематичните извиквания ще лишават доста повече време. Точно това се случва в компютърните системи с към този момент конфигурирани пачове.
Meltdown получи показател CVE-2017-5754 и визира:
Всички процесори на Intel от семействата Core, Xeon, Celeron и Pentium с Core ядраARM процесорите с най-новите ядра Cortex-A75Всички iOS устройства с ARM основани процесори
Ето един забавен образец за потреблението на Meltdown:
Какво е Spectre
Meltdown получи показател CVE-2017-5754 и визира всички процесори на Intel от последните 10 и даже 15 години. На втората накърнимост Spectre, открита освен в процесорите на Intel, само че и в ARM чиповете, бяха присвоени два идентификатора: CVE-2017-5753 (секретен байт) и CVE-2017-5715 (еднакви поредни инструкции), като последният важи и за някои процесори на AMD.
Spectre не може да прониква в паметта на ядрото, само че дава достъп до паметта на другите приложения.
Тази технология може да принуди всеки развой независимо да покаже съдържимото на своята памет. Използва се поредност повтарящи се указания, с които се тренира блока за предсказание на преходите, а по-късно му се подава напълно друга, особено подбрана директива. По този метод границите сред изолираните приложения в тези сериозни случаи се размиват и става допустимо прочитането на предпазените данни на друго приложение, само че не и от ядрото.
Няма универсална отбрана от Spectre: разкритият механизъм може да употребява цялостен набор от разновидности, което усложнява стартирането на повсеместен пач. Налага се приложението единствено да пази своята памет или непрестанно да чисти кеша. Това значи прекомпилиране на всички приложения и съществено намаление на продуктивността. А и надали програмистите ще се заемат просто по този начин да прекомпилират приложенията си.
Spectre визира следните процесори:
Всички процесори на IntelВсичко нови ядра на ARM, поддържащи спекулативно осъществяване на кодаНякои процесори на AMD
Но през днешния ден AMD публично заяви, че за потреблението на тази накърнимост в нейните процесори, е нужен физически достъп до компютърното устройство, само че за това ще стане дума в друга публикация.
Безспорно, Meltdown и Spectre са съществени неточности и ще би трябвало по-внимателно да следим за сигурността на нашите устройства. Но всеки самичък взема решение за себе си. Вече започнаха да излизат указания, по какъв начин да се ревизира, дали системата е уязвима към Meltdown и Spectre и по какъв начин да се изключат фиксовете за тях в другите операционни системи. Това също е тематика за различен материал.
Източник: kaldata.com
КОМЕНТАРИ




