Hlavní navigace

Vlákno názorů ke zprávičce Stack Clash - lokální zranitelnost v Linuxu, BSD a Solarisu od Ondřej Novák - Moc tomu nerozumím tak prosím o vysvětlení. Když se...

  • Aktualita je stará, nové názory již nelze přidávat.
  • 20. 6. 2017 16:15

    Ondřej Novák

    Moc tomu nerozumím tak prosím o vysvětlení.

    Když se alokuje prostor pro lokální proměnné, dělá se probe každé stránky, pokud je potřeba větší velikost než je velikost stránky.

    Funkce alloca také dělá probe.

    Chybu buffer overrun nepočítám, to je jiný druh chyby.

    Takže v čem je problém?

  • 20. 6. 2017 16:53

    Jenda (neregistrovaný)

    > Funkce alloca také dělá probe.

    Já to z toho reportu pochopil tak, že alloca, případně nějaké její varianty/custom implementace v jiných knihovních funkcích, tohle dělají jenom s -fstack-check.

  • 20. 6. 2017 17:56

    Martin Dráb

    Pokud jsem to pochopil správně, tak ve zmíněných operačních systémech se v případě, že "dojde" zásobník (což je detekováno tak, že dojde k výpadku stránky na adrese pod jeho dnem (stack start)), jádro jej prodlouží (alokováním stránky, která vypadla, popř. dalších).

    Pokud k výpadku stránky nedojde, jádro nedetekuje nic. Což je právě klíčové (stejně jako fakt, že zásobník může růst "donekonečna", což je rozdíl např. oproti Windows). Zásobník pak "přeteče" do něčeno jiného (obvykle haldy). Pak již tam jsou hlavně detaily o tom, jak daného chování docílit.

    Pochybuji, že se dělá explicitní probe při každé implicitní alokaci lokálních proměnných. Obvykle se pouze sníží hodnota ukazatele na vrchol zásobníku (ESP na ia32, RSP na amd64/x64). Neznám bohužel detaily z linuxového či BSD světa (jen něco z WIndows).

  • 20. 6. 2017 21:19

    Ondřej Novák

    Právěže Windows, tedy přesněji kompilátor VC++ dělá probe každé stránky, pokud se alokuje něco většího.

  • 20. 6. 2017 22:01

    Martin Dráb

    Ano, ale ve Windows se guard page používá trochu jinak – ohraničuje aktuálně alokovnou oblast zásobníku (dno). Když se na ní narazí, alokuje se další stránka/y a guard page se posouvá dále. Z čehož vyplývá, že guard page se používá ke stejnému účelu jako page fault v *NIXech/BSD. Pokud se tedy alokuje větší část na zásobníku, je nutné onu guard page nepřeskočit.

  • 20. 6. 2017 19:55

    . . (neregistrovaný)

    není to nic složitého, pokud jsi kernel a máš zabránit, aby data nepřetekla z stacku či třeba nepřepsala jeho část (jiné proměnné, návratovou adresu či jiný program), dáš na konec stacku (či před chráněný prostor) page, u které nastavíš právo pouze pro čtení, pokud nějaký program do téhle page zapíše, skončí na seg fault.

    Tuhle speciální readonly page najdeš často pod termínem guard page. Celá slabina, o které se tady píše je právě o tom, že program zapíše až za samotnou guard page, tj. přeskočí jí, proto jako řešení se nabízí právě zvětšení dané page, což je jak sám tušíš jen obezlička, nic lepšího ale zatím nemáme.

    Tahle chyba se samozřejmě ošetřuje v samotném kódu, jedná se o tzv. bounds checking. Úloha kernelu ale není v kontrole spouštěných programů, jestli mají všude bounds checking nebo jestli došlo k přetečení, kernel se pouze snaží, aby daný program neovlivnil někoho jiného a to přesně zajišťuje tahle guard page.

    Teď se přišlo na to, že jistá konstelace nalinkovaných knihoven může přetéct stack, řešením je přidat do programů přímou kontrolu a to právě zajišťuje ten přepínač u glibc pro kompilaci, jen má zatím pár nevýhod, proto není ve výchozím nastavení zapnutý, ale po objevení těhle chyb se na tom pracuje. Podrobnosti jsou poté napsané v odkazech v samotné zprávičce.