Portál AbcLinuxu, 26. května 2024 21:55

Jaderné noviny – 8. 9. 2010: Starý bezpečnostní problém

27. 9. 2010 | Jirka Bourek
Články - Jaderné noviny – 8. 9. 2010: Starý bezpečnostní problém  

Aktuální verze jádra: 2.6.36-rc3. Stabilní jádro 2.4.37.10. Citáty týdne: Valerie Aurora, Andrew Morton, Ted Ts'o. Přednačítání je považováno za škodlivé. Příliš mnoho Cc. Práce na pracovních frontách. Další starý bezpečnostní problém.

Obsah

Aktuální verze jádra: 2.6.36-rc3

link

Současné vývojové jádro je stále 2.6.36-rc3; během minulého týdne nevyšly žádné nové předverze. Linus se vrátil ze svého výletu do Brazílie a začal zase začleňovat patche, takže 2.6.36-rc4 lze pravděpodobně očekávat v blízké budoucnosti.

Stabilní aktualizace: Během uplynulého týdne žádné nevyšly.

Stabilní jádro 2.4.37.10

link

Jádro 2.4 žije! Teda přinejmenším o trochu déle. Willy Tarreau právě vydal aktualizaci 2.4.37.10 s malou sadou důležitých oprav. Pokud se neobjeví žádná další významná chyba, mohla by to být poslední aktualizace této série. Jestli se před zářím 2011 nic nastane, je možné, že žádné 2.4.37.11 nebude. Tou dobou bude jádro 2.6 existovat již 8 let, což by mělo být dost času na to, aby se na něj podívali všichni. Uživatelé mají rok na migraci nebo na to, aby nahlásili kritické chyby. Myslím si, že to je férová nabídka. Kompletní popis jeho plánované politiky vizte v oznámení.

Citáty týdne: Valerie Aurora, Andrew Morton, Ted Ts'o

link

Mnoho z mých rozhovorů s Alem [Viro] o sjednocených připojeních probíhá takto:

Al: „Přepiš to takhle.“
Val: „Ale jak se pak dostaneme k nameidata?“
Al: „Arrrrrrrrrrrrrggggh.“

-- Valerie Aurora

Zatraceně dobrá detektivní práce. Zajímalo by mě, kolik těch ošklivých hlášení o náhodných chybách se špatným stavem stránky jsme právě opravili. Pasuji tě na záříjového „Hrdinu linuxového jádra“.

-- Andrew Morton (Jiřímu Slabému)

Jaderní vývojáři jsou placeni za práci na vlastnostech, to ano. Nejsou placeni za opravování chyb náhodných kolemjdoucích, kteří by chtěli používat nejnovější stabilní jádro.

-- Ted Ts'o

Přednačítání je považováno za škodlivé

link

napsal Jonathan Corbet, 8. září 2010

Každý, kdo četl Co by každý programátor měl vědět o paměti, ví, že výkonnost je na současných systémech výrazně ovlivňována chováním cache. Jediný případ, kdy potřebná data nejsou v cache, může způsobit, že se procesor na několik set cyklů zastaví. Jádro používá spoustu triků a technik, kterými optimalizuje chování cache, ale jak se často stává u nízkoúrovňových optimalizací, ukazuje se, že některé z těchto triků nejsou tak užitečné, jak se myslelo.

Jaderná makra pro spojové seznamy obsahují několik operací pro průchod celým seznamem. Na začátku smyčky procházející seznam makro zadá operaci pro přednačtení dalšího záznamu na seznamu. Doufá se, že když je záznam zpracován, CPU už bude mít následující načtený v cache, takže se zabrání zpoždění na začátku dalšího průchodu smyčkou. Vypadá to jako ten druh mikrooptimalizace, která může jenom pomoci, ale na tyto operace se nikdo dlouhou dobu nepodíval – až doteď. Andi Kleen právě poslal patch, který většinu přednačítání odstraňuje.

Andi tvrdí, že na současných procesorech operace přednačítání věci naopak zhoršují. Procesory již nyní přednačítají všechno, na co přijdou, takže explicitní vyjmenovávání dalších věcí těžko pomůže. A i když přednačtení začne cyklus práce s pamětí o něco dříve, smyčky zpracovávající seznamy obvykle bývají krátké, takže paralelizace není o mnoho lepší. Přednačítání přitom zvětšuje obraz jádra, více využívá registry a způsobuje, že překladač generuje horší kód. Proto bude lepší se ho zbavit.

S odstraněním přednačítacích operací se obraz Andiho jádra zmenšil o 10 kB. Také se v hlavní řadě neobjevily žádné výkonnostní regrese, takže pokud někdo nezjistí jiné výsledky, vypadá to, že je začlenění patche do hlavní řady ospravedlněné.

Příliš mnoho Cc

link

napsal Jonathan Corbet, 8. září 2010

Co se týče e-mailové komunikace, obecně se chybuje spíš tak, že se kopie pošlou příliš mnoha příjemcům, než příliš málo. Objemy dat v e-mailových konferencí jsou takové, že nikdy nelze předpokládat, že tam relevantní lidé najdou specifickou zprávu, takže je zvykem vyjmenovávat je explicitně. V nedávné době si však mnoho jaderných vývojářů začalo stěžovat, že dostávají kopie patchů, které je nezajímají. A výběr příjemců často vypadá naprosto náhodně.

Na vině je skript get_maintainer.pl, který se dodává se zdrojovými kódy jádra. Skript je poměrně užitečný nástroj – podívá se do souboru MAINTAINERS a najde lidi, které by daný patch mohl zajímat. Méně užitečné ale může být to, že se povrtá v historii repozitáře a hledá další vývojáře, kteří měnili soubory modifikované daným patchem. Takže každý, kdo v nedávné minulosti ladil nějaký soubor – i když dělal jenom triviální změny – bude v seznamu lidí, kterým poslat kopii dalších patchů pro daný soubor.

Podívat se do historie revizí může být užitečný způsob, jak vypátrat „skutečné“ správce; informace v souboru MAINTAINERS mohou být naopak zastaralé nebo nekompletní. Zjevně je ale potřeba podívat se, co vývojář v dané oblasti dělal; úprava souboru kvůli opravě API neznamená, že vývojář na daném kódu aktivně pracuje. Mnoho lidí ale tuto kontrolu vynechá a místo toho prostě pošlou e-mail každému, koho skript vypsal.

Úroveň rozladěnosti způsobená často rozesílanými patchi podle všeho roste. Vývojáři, kteří nechtějí na své e-maily obdržet naštvané reakce, by si měli dávat trochu pozor nebo alespoň použít get_maintainer.pl s volbou --nogit.

Práce na pracovních frontách

link

napsal Jonathan Corbet, 7. září 2010

Jedna z největších interních změn v 2.6.36 bude přijetí souběžností řízených pracovních front. Krátkodobým cílem této práce je omezit počet jaderných vláken, která běží v systému, a přitom zvýšit souběžnost úloh předaných pracovním frontám. Za tímto účelem jaderná vlákna specifická pro pracovní frontu mizí a nahrazuje je sada vláken se jmény jako [kworker/0:0]; úlohy jsou následně rozdělovány mezi vlákna algoritmem, který se snaží zajistit, aby na každém CPU pořád běžela právě jedna úloha. Výsledkem by mělo být lepší využívání CPU úlohami v pracovní frontě a méně paměti spojené s mašinérií pracovních front.

To je samo o sobě výsledek, který stojí za snahu, ale je to pouze začátek. Patche v 2.6.36 byly úmyslně navrženy tak, aby minimalizovaly dopad na zbytek jádra, takže zachovávají současné API pracovních front. Nový kód ale má dělat více než nahradit pracovní fronty chytřejší implementací; ve skutečnosti má být obecným systémem pro správu úloh v jádře. Plné využívání jeho schopností bude vyžadovat změny na straně volajícího – a na straně kódu, který pracovní fronty zatím vůbec nevyužívá.

V jádrech před 2.6.36 se pracovní fronty vytvářejí pomocí create_workqueue() a pár dalších variant. Tato funkce mezi jinými spustí jedno nebo více jaderných vláken, která zpracují úlohy předané dané frontě. V 2.6.36 je toto rozhraní zachováno, ale pracovní fronta, která je takto vytvořena, se liší: Nemá žádná dedikovaná vlákna a ve skutečnosti slouží jenom jako kontext pro předávání úloh. API se považuje za zastaralé; správný způsob, jak vytvořit pracovní frontu, je nyní:

int alloc_workqueue(char *name, unsigned int flags, int max_active);

Parametr name (jméno) frontu pojmenovává, ale na rozdíl od staré implementace nevytváří vlákna podle tohoto jména. Parametr flags (příznaky) vybírá z mnoha relativně složitých možností to, jak se má provést práce předaná frontě; mezi hodnoty může patřit:

Kombinace příznaků WQ_HIGHPRIWQ_CPU_INTENSIVE zcela vyjímá danou frontu z řízení souběžností. Jakákoliv úloha předaná takové pracovní frontě bude spuštěna, jakmile je k dispozici CPU.

Poslední argument alloc_workqueue() je max_active. Tento parametr omezuje počet úloh, které lze z dané pracovní fronty spustit na jakémkoliv CPU. Výchozí hodnota (používá se, když se max_active předá nula) je 256, ale skutečné maximum pravděpodobně bude mnohem nižší, protože kód pracovních front bude chtít, aby na jednom CPU běžela jenom jedna úloha. Kód, který vyžaduje, aby se úlohy v pracovní frontě spouštěly v pořadí, v jakém jsou zadávány, mohou použít frontu s WQ_UNBOUNDmax_active nastaveným na jedna.

(Shodou okolností byla většina z toho, co je popsáno výše, opsána z rozpracovaného dokumentu Tejuna Heo o používání pracovních front.)

Zdá se, že v dlouhodobém plánu je konvertovat všechny uživatele create_workqueue() na vhodné volání alloc_workqueue(); nakonec bude create_workqueue() odstraněna. To bude ale asi chvíli trvat; rychlý grep ukazuje téměř 300 volání.

Ještě dlouhodobější plán je začlenit mnoho dalších jaderných vláken do nového mechanismu pracovních front. Například bloková vrstva spravuje sadu vláken, která se jmenují jako flush-8:0bdi-default; ta zajišťují zápis dat na bloková zařízení. Tejun nedávno zaslal patch, který tato vlákna nahrazuje pracovními frontami. Tento patch však několik vývojářů znervóznil – problémy se zpětným zápisem mohou způsobit nekončící potíže, když je systém pod tlakem způsobeným nedostatkem paměti. Možná se tedy do hlavní řady nedostane rychle, ale pravděpodobně nakonec ano, pokud se neobjeví regrese.

Poté je zde nekončící seznam jaderných vláken pro zvláštní účely. Ne všechna bude možné upravit tak, aby je bylo možné konvertovat na pracovní frontu, ale u mnoha z nich to je vhodné. Postupem času by toto všechno mělo vyústit v menší využívání zdrojů, čistší výstup z „ps“ a lépe běžící systém.

Další starý bezpečnostní problém

link

napsal Jonathan Corbet, 8. září 2010

V srpnu byla uzavřena dlouho existující bezpečnostní chyba spojená s přeplněním zásobníku. Ukazuje se ale, že v dané oblasti jsou další chyby, přinejmenším jedna je známa již od konce minulého roku. Na opravě se pracuje, ale je těžké nezabývat se tím, jestli bezpečnostní záležitosti řešíme tak dobře, jak bychom měli.

Problém opět nahlásil Brad Spengler, který zaslal krátký program demonstrující, jak snadno lze zajistit, aby se věci pokazily. Program alokuje jediné pole o velikosti 128 kB, které je zaplněno jako dlouhý C řetězec. Pak je alokováno pole o délce více něž 24 000 ukazatelů na char *, každý záznam přitom ukazuje na ten dlouhý řetězec. Poslední krok volá execv() a pole použije jako seznam argumentů pro program, který má být spuštěn. Jinými slovy exploit říká jádru, aby spustilo program s tolika obrovskými argumenty, kolik jde.

Bylo nebylo, jádro mělo limit na to, kolik stránek lze použít pro argumenty programu. Tento limit by zabránil všem problémům spojeným se zneužitím, které ukazuje Bradův program, ale v 2.6.23 byl odstraněn; zdá se, že dělal problémy Googlu. Na jeho místo byla vložena nová kontrola, která vypadá nějak takto (z fs/exec.c):

/*
 * Limit to 1/4-th the stack size for the argv+env strings.
 * This ensures that:
 *  – the remaining binfmt code will not run out of stack space,
 *  – the program will have a reasonable amount of stack left
 *    to work from.
 */
rlim = current->signal->rlim;
if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) {
    put_page(page);
    return NULL;
}

Myšlenka za tímto kódem je jasná: Jestliže argumenty nemohou překročit čtvrtinu povolené velikosti zásobníku procesu, nemohou se úplně vymknout kontrole. Ukazuje se ale, že tato myšlenka má jednu zásadní chybu: Velikost zásobníku nemusí být vůbec omezena. V takovém případě bude hodnota limitu -1 (jinými slovy samé jedničky) a kontrola podle velikosti zásobníku bude bezpředmětná. Konečným výsledkem je, že v některých situacích nebude nijak omezena velikost prostoru na zásobníku, kterou mohou spotřebovat argumenty exec(). A bohužel důsledky nejsou omezeny pouze na škodící proces.

Přinejmenším je Bradův exploit schopen vyvolat oops systému, když se zásobník pokouší expandovat příliš. Zmínil možnost, že se zásobník rozšíří až na adresu 0 – a tak znovu otevře hrozbu zneužití nullového ukazatele – ale nepřišel na to, jak to udělat. Kopírování všech argumentů samozřejmě spotřebuje velký kus paměti; kvůli další chybce tato paměť není řádně započítána, takže když se spustí zabiják při nedostatku paměti (out-of-memory killer), aby věci napravil, nezamíří na proces, který ve skutečnosti způsobuje problém. A aby toho nebylo málo, počítání a kopírování řetězců argumentů nelze přerušit preempcí ani zabít; vzhledem k tomu, že může běžet velmi dlouho, může nepříjemně ovlivnit výkonnost zbytku systému.

Brad říká, že tento problém poprvé hlásil v prosinci 2009, ale neobdržel žádnou odpověď. Nedávno poslal poznámku Keesovi Cookovi, který reagoval zasláním částečné opravy. Tato oprava měla nějaké technické problémy a nebyla aplikována, ale Roland McGrath zaslal novou sadu oprav, která je na tom lépe. Roland použil minimalistický přístup, protože nechtěl omezit velikosti argumentů víc, než je absolutně nutné. Jeho patch tedy zajišťuje, že zásobník nepřeroste pod minimální adresu paměti v uživatelském prostoru (mmap_min_addr). Tato kontrola, společně s ochrannou stránkou zásobníku přidanou v srpnové opravě, by měla zabránit tomu, aby zásobník přerostl do škodlivé oblasti. Roland také přidal bod pro preempci do kódu, který kopíruje argumenty, aby zlepšil interaktivitu zbytku systému, a kontrolu na signály, která umožní v případě potřeby proces zabít. Neřešil záležitost s OOM zabijákem, tu bude nutné opravit samostatně.

Rolandův patch podle všeho řeší nejhorší problémy, ale někteří komentátoři tvrdí, že nezachází dost daleko. Dá se předpokládat, že patche v blízké budoucnosti zamíří do distribučních jader, ale tato epizoda ukázala několik nepříjemných věcí:

Problém může naznačovat klíčový nedostatek v tom, jak je podporován vývoj linuxového jádra. Jsou zde tisíce vývojářů, kteří jsou placeni za to, že stráví alespoň část svého času prací na jádře. Někteří z nich jsou placeni za práci v oblastech spojených s bezpečností, jako je SELinux nebo AppArmor. Není ale jasné, jestli je někdo placen jednoduše za to, aby kontroloval, jestli je základní kód jádra bezpečný. To může zjednodušovat pronikání bezpečnostních problémů do jádra a zpomalovat reakci, když někdo poukáže na problémy v kódu. Je zde silný (a zvyšující se) ekonomický zájem na zneužití bezpečnostních problémů v Linuxu; možná potřebujeme najít způsob, jak zvýšit zájem o prevenci těchto záležitostí.

Související články

Jaderné noviny – 1. 9. 2010: Zamyšlení nad stabilními jádry
Jaderné noviny – 25. 8. 2010: Přístup k jaderné kryptografii z uživatelského prostoru
Jaderné noviny – 18. 8. 2010: Miliarda souborů v Linuxu
Jaderné noviny – 11. 8. 2010: Co dalšího v jádře 2.6.36
Jaderné noviny – 4. 8. 2010: Co bude v jádru 2.6.36
Jaderné noviny – 28. 7. 2010: Potřebuje Linux znát čas vytvoření souboru?

Odkazy a zdroje

Kernel coverage at LWN.net: September 8, 2010

Další články z této rubriky

Jaderné noviny – přehled za duben 2024
Jaderné noviny – přehled za březen 2024
Jaderné noviny – přehled za únor 2024
Jaderné noviny – přehled za leden 2024
Jaderné noviny – přehled za prosinec 2023

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.