Dezinfikujte adresní prostor

Mám ještě spoustu poznámek z devconfu. Byl jsem na přednášce o Kernel Address sanitizeru a konečně se dozvěděl něco málo o tom jak to funguje. Přemýšlel jsem jak by se to asi přeložilo do češtiny..

Když se přistoupí k platné paměti, tak je všechno v pohodě. Když se ale přistoupí k nealokované paměti, tak je složité zjistit co se stalo. V případě jádra se mohl stát třeba o špatný hardware, konkrétně třeba špatný DMA přístup do paměti, apod.

Na straně software to bývá obvykle programátorská chyba. Jedná se o práci s neinicializovanou pamětí, přístup mimo inicializovanou paměť (out of bounds), například přetečení bufferu. Použití proměnné po free, což je často způsobenou špatnou prací s více vlákny. Nebo použití ukazatele na strukturu špatného typu (random reference error).

Jak se tyhle věci hledají? No přece špatně (-;

Hlavně kvůli tomu že to nastává jenom někdy. Systematicky můžeme postupovat metodou půlení, kdy se buď vracíme k funkční verzi (git bisect) nebo prostě odstraňujeme části zdrojáku. Když máme dojem, že víme kde je problém, tak to může vyřešit třeba tím, že se podíváme do kódu (code review).

Můžeme si pomoct třeba valgrindem, který má ale obrovskou režii. Druhý pomocník je address sanitizer. V případě kernelu je to kernel address sanitizer KASAN.

– KASAN umí: out-of-bound, use-after-free, stack-use-after-scope
– KASAN neumí: přístup k neinicializované paměti, random reference corruption

Jak to funguje?

Do paměťového prostoru se mezi proměnné vloží prázdné bloky paměti. Tzv. červené zóny (red zones). Pokud program zapíše mimo alokováný prostor (typicky třeba overflow a underflow chyby), tak by to mělo být dobře vidět

object [rz] object [rz] object [rz] object [rz]

Nebo ve stack trace:

Memory state around the buggy address:
 ffff8800693bc300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff8800693bc380: fc fc 00 00 00 00 00 00 00 00 00 00 00 00 00 fc
 ffff8800693bc400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff8800693bc480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff8800693bc500: fc fc fc fc fc fc fc fc fc fc fc 00 00 00 00 00
>ffff8800693bc580: 00 00 00 00 00 00 00 00 00 00 03 fc fc fc fc fc
                                                  ^

Dalším principem je použítí shadow memory. Kde pro celý paměťový prostor máme označené části, které mají být dostupné v dané místě programu.

Aby to celé fungovalo, tak se musí na správné místa přidat pár instrukcí (code instrumentation). Jedná se zejména o load a store.

V případě linuxového jádra a KASANu jsou paměťové nároky přibližně dvojnásobné a zpomalení taky přibližně dvojnásobné.

Ostatně si můžete poslechnout přednášku Jerome Marchanda přímo na youtube:

Jak použít KASAN jenom na určitý modul jádra a jak to s tím přeložit v samotné přednášce zaznělo taky.

Použití address sanitizeru v userspace je mi bližší a princip fungování bude  podobný.

Do CFLAGS nebo CPPFLAGS se přidá -fsanitize=address, do LDFLAGS se přidá -lasan. Přeloží se, sestaví se, a při spuštění to do standardního chybového výstupu nalezené chyby.

Myslím si, že každý kdo to s C a C++ myslí aspoň trošku vážně by měl vědět, že jeho programy správně pracují s pamětí.

Facebooktwittergoogle_plusredditpinterestlinkedin