Portál AbcLinuxu, 16. května 2024 08:36

Jaderné noviny - 26. 11. 2008

9. 1. 2009 | Jirka Bourek
Články - Jaderné noviny - 26. 11. 2008  

Aktuální verze jádra: 2.6.28-rc6. Citáty týdne: Steven Rostedt, Robert Love, Andrew Morton. Ksplice a kreplace. Znaková zařízení v uživatelském prostoru. API ovladačů: spící poll(), exkluzivní I/O paměť a ladění DMA API.

Obsah

Aktuální verze jádra: 2.6.28-rc6

link

Současné vývojové jádro je 2.6.28-rc6 vydané Linusem 20. listopadu těsně předtím, než prchl z města na přístrojové potápění. (Aspoň předpokládejme, že prchl z města; v Portlandu není zrovna to nejlepší období pro vodní sporty.) Jádro obsahuje mnoho oprav, včetně jedné pro významnou regresi ve vmalloc(). Kompletní changelog obsahuje detaily.

Současné stabilní jádro 2.6 je 2.6.27.7 také vydané 20. listopadu. Obsahuje slušné množství oprav včetně jedné s přiřazeným CVE číslem.

Citáty týdne: Steven Rostedt, Robert Love, Andrew Morton

link

+/*
+ * "Define 'is'", Bill Clinton
+ * "Define 'if'", Steven Rostedt
+ */
+#define if(cond) if (__builtin_constant_p((cond)) ? !!(cond) :		\
+	({								\
+		int ______r;						\
+		static struct ftrace_branch_data			\
+			__attribute__((__aligned__(4)))			\
+			__attribute__((section("_ftrace_branch")))	\
+			______f = {					\
+				.func = __func__,			\
+				.file = __FILE__,			\
+				.line = __LINE__,			\
+			};						\
+		______r = !!(cond);					\
+		if (______r)						\
+			______f.hit++;					\
+		else							\
+			______f.miss++;					\
+		______r;						\
+	}))

-- Steven Rostedt představuje nové "if"

Při práci v lkml se často zdá, že všichni křičí NE a zaměřují svou energii pouze na zastavení věcí. Občas je to tak, ale většinou mají na mysli to, že je prostě potřeba věnovat dané věci nějaký čas a udělat ji správně. Připouštím, že to znamená hodně iterací, ale Linux je vznešený cíl.

-- Robert Love

Podívejme se ale na problém, který se snažíme řešit. Vývojář A si přeje napsat nějaký kód pro sledování/ovládání jádra, takže je nucen nacpat ho na svou webovou stránku, připomínat lidem, že mají stahovat aktualizace, chovat se jako nezávislý cíl patchů od jiných lidí, atd., atd. To je všechno nepříjemné a ošklivé, takže se vývojář A vzdá a implementuje svůj kód pro uživatelský prostor v jádře. Ve výsledku je to technicky horší, pouze anglicky, ale aspoň se to tam dostalo.

-- Andrew Morton

Ksplice a kreplace

link

Rebootovat systém kvůli aplikování bezpečnostní aktualizace je nepříjemnost. V některých případech je to dokonce horší než nepříjemnost; z různých důvodů nelze mnoho systémů vůbec vypnout bez narušení práce, kterou mají dělat. V dubnu se Jaderné noviny dívaly na Ksplice, mechanismus, který umožňuje instalaci jaderných aktualizací bez potřeby rebootovat systém. Od té doby práce na Ksplice pokračovala, byla zaslána nová verze a projekt se začíná pohybovat směrem k začlenění do jádra. Je tedy na místě další pohled.

Hlavním myšlenka Ksplice zůstává stejná: když je mu dán strom zdrojových kódů a patch, přeloží jádro jak s, tak bez patche a hledá rozdíly. Za tímto účelem je postup při překladu modifikován tak, aby každá funkce a datová struktura byly ve své vlastní spustitelné sekci. To je pro překladač a linker poněkud obtížnější, ale vývojáři jsou na potíže, které těmto nástrojům způsobí, výrazně necitliví. Když jsou věci takto rozděleny, je relativně jednoduché identifikovat minimální sadu změn v binárním obrazu jádra, kterou patch způsobí. S trochou opatrnosti potom Ksplice může patchovat nový kód do běžícího jádra. Když je to dokončeno, staré jádro používá nový kód bez nutnosti rebootu.

Tato technika dobře funguje pro změny v kódu, ale změny v datových strukturách s sebou nesou problémy navíc. V dubnu Ksplice takovou změnu nezvládalo; i tak vývojáři tvrdili, že pomocí ksplice jsou schopni aplikovat většinu bezpečnostních aktualizací. Od té doby tímto směrem věnovali nějaké úsilí a po přidání několika nových technik - které vyžadují určitou snahu na straně toho, kdo připravuje patch pro Ksplice - je nyní možné aplikovat 100 % z 65 ne-DOS bezpečnostních patchů, které byly pro jádro vydány od roku 2005.

V některých případech bude jaderný patch jednoduše vyžadovat, aby se datové struktury inicializovaly jinak. Způsob, jakým tuto změnu zvládnout v aktualizaci pomocí Ksplice, je modifikovat relevantní datové struktury za běhu. Za účelem takové změny lze patch modifikovat tak, aby zahrnul přibližně takovýto kód:

#include <ksplice-patch.h>

ksplice_apply(void (*funkce)());

Zatímco Ksplice aplikuje změny - zbytek systému je stále zastaven - je zavolána daná funkce. Ta potom může prohrabat jaderné datové struktury a změnit je podle potřeby. Například CVE-2008-0007 byla důsledkem toho, že některé ovladače nenastavily příznak VM_DONTEXPAND v některých strukturách vm_area_struct. Ksplice je schopné opravit ovladače bez problémů, ale to samo neopraví chybně inicializované VMA (virtual memory area, oblast virtuální paměti) přítomné na běžícím systému. Modifikovaný patch tedy přidává nějaké funkce, které nastavují VM_DONTEXPAND na existujících VMA, a pak použije ksplice_apply(), aby byly tyto funkce vykonány. Výsledkem je zcela opravený systém.

Změny definic datových struktur jsou obtížnější. Jestliže je pole ze struktury odstraněno, verze patche pro Ksplice ho může nechat na místě. Přidání nového pole nicméně vyžaduje komplikovanější prostředky. Jednoduché nahrazení alokovaných struktur za běhu se zdá být nepraktické; nalezení a opravení všech ukazatelů na tyto struktury by bylo přinejmenším obtížné. Je potřeba něco jiného.

U Ksplice je to něco jiného "stínový" mechanismus, který pro ukládání nových polí alokuje oddělenou strukturu. Použití stínových struktur znamená slušné množství dodatečné práce; původní patch je potřeba změnit na mnoha místech. Kód, který alokuje dotčenou strukturu, musí být modifikován tak, aby alokoval i stín. Stejně tak kód, který strukturu uvolňuje, je potřeba změnit podobným způsobem. Jakýkoliv odkaz na nové pole musí místo toho prohledávat stínovou strukturu a použít tuto verzi pole. Ve shrnutí to vypadá jako únavný postup, u kterého je velká šance, že zavede nové chyby. Také je zde potenciál pro výkonnostní problémy způsobené prohledáváním lineárního spojového seznamu. Dobrá zpráva je, že je taková modifikace patche nutná jenom ve výjimečných případech.

Nezdá se, že by vývojáři Ksplice byli s prací hotovi; ze zaslání nejnovějšího patche:

V současnosti pracujeme na tom, aby bylo možné aplikovat pomocí Ksplice celý stable strom. I když se původní záměr Ksplice soustředil na patche pro CVE, chápeme názor, že "bezpečnostní chyby jsou prostě 'obyčejné chyby'" (tj. sledovat bezpečnostní chyby odděleně od normálních chyb může být obtížné a nemusí to být žádoucí). Naším konečným cílem je poskytnout všem dlouhodobě běžícím strojům všechny čerstvé opravy chyb, které se dostanou do odpovídajícího stabilního stromu.

To je ambiciózní cíl; jedna stabilní řada může nasbírat stovky změn, některé z nich mohou být poměrně velké. Bude zajímavé sledovat, kolik uživatelů skutečně zajímá tento druh aktualizací; místa, kde běží kritické systémy, mívají starší "podniková" jádra, pro která se již nevydávají aktualizace stabilního stromu. Na druhou stranu, pokud bude Ksplice dostatečně flexibilní, aby zvládlo proud aktualizací pro stabilní strom, mělo by také být užitečné pro distributory, kteří budou chtít poskytnout bezrebootovací patche svým zákazníkům.

Mezitím Nikanth Karthikesan zaslal nástroj nazvaný kreplace. Při zběžném pohledu je podobný Ksplice, ale cíl je trochu odlišný: jeho účelem je umožnit vývojáři rychle vyzkoušet změnu na běžícím jádře. Kreplace funguje jednoduše vypatchováním a nahrazením funkce nebo funkcí v jádře. Může mít svou hodnotu, ale první reakce nebyla příliš nadšená. Mezi jinými věcmi bylo poukázáno na to, že i Ksplice má nástroje pro rychlé experimentování se změnami - i když rychlé bude pouze v případě, že vývojář již nastavil běžící jádro tak, aby používalo Ksplice.

Poslední obavou u obou těchto řešení je to, že z praktického pohledu používají techniky rootkitů. Mechanismus, který distributoři mohou užít k patchování běžících systémů, může (zne)užít i někdo jiný. Výrobci pouze binárních modulů mohou například použít Ksplice či kreplace k tomu, aby obešli pouze-GPL exporty a jiné nehodící se vlastnosti současných jader. Stejně tak by tyto nástroje samozřejmě mohli použít crackeři, ale ti již mají své vlastní nástroje pro rootkity a z oficiálně podporovaného patchovacího mechanismu tak nebudou mít žádný prospěch. Jestli je tento aspekt Ksplice něco, čím se bude komunita vývojářů zabývat, se uvidí v příštích měsících, jak se bude kód blížit k začlenění do hlavní řady.

Znaková zařízení v uživatelském prostoru

link

Je mnoho funkcí - věci jako ovladače zařízení či souborové systémy - které se obvykle považují za záležitost jádra, ale postupem času jim bylo umožněno přesunout se do uživatelského prostoru. Framework UIO pro ovladače v uživatelském prostoru se připojil ve 2.6.23, zatímco souborové systémy v uživatelském prostoru (FUSE) už jsou zde od 2.6.14. Tejun Heo by byl rád, aby se tento nápad rozšířil ještě více pomocí patche znakových zařízení v uživatelském prostoru (CUSE).

Na první pohled není zjevné, jaké využití by znaková zařízení v uživatelském prostoru mohla mít. Trochu podrobnější pohled nicméně ukáže, že mnoho programů - jak otevřených, tak uzavřených - potřebuje staré znakové ovladače. Tyto ovladače jsou nyní v jádře, ale nemusely by být, kdyby je bylo možné implementovat v uživatelském prostoru. Starší, zavržená rozhraní, jako je například Open Sound System (OSS), mohou být lépe podporována bez neustálého rýpání se v jaderné emulaci.

Poskytnutí lepší podpory OSS je jednou z hlavních motivací CUSE, jak Tejun oznámil v mailu v linux-kernel, kde představoval OSS proxy. Proxy využívá CUSE, aby implementovalo zařízení /dev/dsp, /dev/adsp a /dev/mixer, která programy používající OSS očekávají. Adrian Bunk to nepovažuje za dobrou věc:

Omlouvám se za pesimismus, ale 6 let poté, co se ALSA dostala do jádra, se pomalu dostáváme do bodu, kdy ji všechny programy podporují.

Program, který jmenuješ na své webové stránce, je podpora zvuku UML hostitele. Zajímalo by mě, proč ji neopravíš místo práce na lepší emulaci OSS.

Tejun nicméně považuje současný stav OSS emulace za komplikovaný chaos, který tak jako tak potřebuje pročistit:

Nyní máme v jádře OSS emulaci, kterou nelze mixovat s ostatními proudy, aoss [ALSA OSS emulace], která má své vlastní seznamy podporovaných a nefunkčních věcí a také ji lze směrovat přes PA [PulseAudio] správnou konfigurací ALSA, a také padsp [PA OSS emulation], která má také své vlastní seznamy podporovaných a nefunkčních věcí a nic nefunguje dostatečně dobře. Takže kdybychom měli jednu věc, která bude prostě fungovat, ty ostatní bychom mohli nechat spát.

Jsou zde ale i další možná využití CUSE. Greg Kroah-Hartman poznamenal, že starý software pro komunikaci s Palm Pilot, který je většinou pouze binární, chce komunikovat se sériovým portem /dev/pilot. Jádro k tomu má ovladač, ale přenos všech dat do USB zařízení by místo toho mohl zařídit uživatelský program založený na libusb. CUSE by tedy mohlo být použito k odstranění dalšího zastaralého ovladače při zachování kompatibility se starým kódem v uživatelském prostoru.

CUSE je implementováno nad FUSE, protože se v mnohém překrývají. Znaková zařízení a souborové systémy implementují mnoho stejných souborových operací - věci jako open(), close(), read() a write() - což z nich dělá dobrý pár. Tejun má oddělený patch pro FUSE, který implementuje další operace pro souborové systémy, z nichž některé použije CUSE.

Tyto přídavné FUSE operace zahrnují implementaci ioctl(), která je nutně poněkud ošklivé. Protože implementace ioctl() může přistupovat k paměti nepředvídatelnými způsoby - a tyto struktury mohou být libovolně hluboké - je potřeba mechanismus pro CUSE zařízení v uživatelském prostoru, který by jim umožnil číst a zapisovat do této paměti. CUSE server nemá přímý přístup do paměti volajícího, takže musí být implementováno vícekrokové ioctl() s opakovanými pokusy. Tato konkrétní ošklivost je povolena pouze pro použití v jádře, takže CUSE (a další jemu podobné věci) mohou umožnit "neomezené" implementace ioctl(). Všechny souborové systémy FUSE nadále potřebují mít "omezená" ioctl(), kde může jádro určit směr a množství dat, která se přenesou. Do FUSE byla také přidána podpora pro poll(), která následně vyžaduje oddělený patch, jenž umožní zpětným voláním [callback] poll() spát (popsáno v článku níže).

Jakmile jsou změny ve FUSE na místě, implementace CUSE je relativně malá, váží okolo 1000 řádek plus nějaký úklid přejmenovávající a exportující symboly FUSE. Ve svém jádře CUSE vezme přes FUSE připojený souborový systém, který se připojí k zařízení implementovanému v uživatelském prostoru a jádrem exportovanému znakovému zařízení, čímž tyto dva spojí dohromady. FUSE zajišťuje interakci s kódem v uživatelském prostoru stejným způsobem, jakým to dělá u souborového systému.

CUSE vytváří zařízení pro příkazy /dev/cuse, které otevírá program vytvářející konkrétní znakové zařízení. CUSE se otevírajícího dotáže, které zařízení implementuje, a podle toho vytvoří příslušný uzel zařízení. Většinu operací CUSE prostě přehazuje na FUSE, ale u open() místo toho otevírá soubor z připojeného souborového systému FUSE a manipulátor ukládá pro pozdější použití.

V mnoha směrech je CUSE určitým druhem vrstvy impedančního přizpůsobení, která vytváří něco, co se chová jako znakové zařízení, ale pod sebou nemá přímo žádný hardware. To CUSE umožňuje ignorovat věci jako přerušení od hardwaru; ta musí obsloužena někde jinde, typicky v ovladači na nižší úrovni - v případě OSS proxy v ovladači zvukové karty. To je jeden z velkých rozdílů mezi UIO a CUSE. UIO je mnohem více podobné obvyklému jadernému ovladači zařízení, který potřebuje řešit přerušení v jádře. Ovladače využívající CUSE mohou být na druhou stranu vytvořeny úplně bez kontaktu s jaderným prostorem.

Jedinou námitkou se zdá být Adrianova stížnost o podpoře OSS, které bylo už tak dávno označeno za zastaralé. Jak ale Tejun upozornil, je stále mnoho aplikací, které podporují jenom OSS. Navíc veškerý zaslaný kód je mnohem menší než OSS emulace v ALSA v jádře, kterou je nyní poněkud nepříjemné používat, říká Tejun. Vzhledem k tomu, že jsou zde další potenciální uživatelé CUSE, ne jenom OSS proxy, zdá se, že v nepřítomnosti dalších významnějších námitek se CUSE dostane do 2.6.29.

API ovladačů: spící poll(), exkluzivní I/O paměť a ladění DMA API

link

V současnosti je na stole mnoho navrhovaných změn API ovladačů, o kterých se v konferencích diskutuje. Žádné z nich nejsou významné, ale stojí za to mít je v povědomí.

poll()

link

Většina funkcí ve struktuře file_operations se zabývá I/O. Není tedy překvapující, že je těmto funkcím povoleno spát. Až na jednu výjimku - poll() spát nemůže. Žádná vlastnost systémových volání poll() a select nepotřebuje, aby bylo zpětné volání [callback] poll() ovladače neblokující; tento požadavek vychází z implementace. Zjednodušeně vypadá jádro poll() nějak takto:

for (;;)
    set_current_state(TASK_INTERRUPTIBLE)
    pro každý popisovač v poll
        zeptej se ovladače, jestli lze provést I/O
        přidej současný proces do fronty ovladače
    jestliže je jeden nebo více popisovačů připraveno
        break
    schedule_timeout_range(...)

Problém je relativně přímočarý: pokud by se specifický ovladač rozhodl spát ve svém zpětném volání poll(), současný stav úlohy by se změnil zpět na TASK_RUNNING a schedule_timeout_range() by se vrátila hned. Spící ovladač tedy mění hlavní smyčku v aktivní čekání.

Řešení, které vyvinul Tejun Heo, je také přímočaré. Jeho patch způsobí, že sys_poll() definuje uživatelskou probouzející funkci, která nastaví nový příznak triggered, když je zavolána. To eliminuje potřebu přepnout proces na TASK_INTERRUPTIBLE po dobu trvání hlavní smyčky; to lze místo toho udělat těsně před skutečným uspáním.

Většina autorů ovladačů si této změny, která bude s velkou pravděpodobností začleněna do 2.6.29, nemusí všímat. Pro ty, kdo ho potřebují, to ale znamená další stupeň volnosti při implementaci zpětných volání poll().

Exkluzivní I/O paměť

link

Po nějakou dobu si vývojáři zapojení do honu na chybu poškozující e1000e mysleli, že by problém mohl být v X serveru. Ukázalo se, že chyba je ve skutečnosti někde jinde, ale podezření vržené na X vedlo k vývoji nového API, které má programům v uživatelském prostoru ztížit narušení fungování ovladače v jádře.

Konkrétně se zdálo, že má smysl zabránit uživatelskému prostoru manipulovat s I/O pamětí, která byla alokována ovladači zařízení. Toho lze dosáhnout tak, že se volání mmap() na /dev/mem zakáže mapovat oblasti již přidělené ovladačům. Jestliže je nastavena konfigurační volba STRICT_DEVMEM, jádro bude chránit svou vlastní paměť před mapováním z uživatelského prostoru; ochrana I/O paměti je ve skutečnosti pouhým rozšířením tohoto mechanismu.

Arjan van de Ven implementoval tuto vlastnost ve svém patchi ekluzivity MMIO. Rozhodl se nicméně, že tato ochrana nebude ve výchozím stavu zapnutá. Ovladač, který bude chtít exkluzivní přístup k oblasti I/O paměti, by měl zavolat jednu z těchto nových funkcí:

int pci_request_region_exclusive(struct pci_dev *pdev, int bar, 
                                 const char *res_name);
int pci_request_regions_exclusive(struct pci_dev *pdev, 
                                  const char *res_name);
int pci_request_selected_regions_exclusive(struct pci_dev *pdev,
                                           int bars, 
                                           const char *res_name);

Také je zde nové, nízkoúrovňové alokační makro:

request_mem_region_exclusive(start, n, name);

Ve všech případech jsou tyto funkce ekvivalentní svým neexkluzivním protějškům s výjimkou změny jména a exkluzivity výsledné alokace.

Mohou se objevit případy, kde bude chtít vývojář mapovat oblast z uživatelskému prostoru na vývojovém systému bez ohledu na to, jaký je názor ovladače. Pro takové situace je zde nový bootovací parametr iomem=relaxed. Když je nastaven, exkluzivní alokace nejsou vynucovány. To zjevně není volba, kterou by chtěl někdo využít na produkčním systému, ale v prostředí vývoje může být užitečná.

Ladění DMA API

link

Toto poslední téma ve skutečnosti není změna API, ale stojí za to se na něj podívat taktéž. Jádro poskytuje hezké API pro nastavení DMA operací. V mnoha případech s ním spojené funkce dělají málo nebo žádnou práci; systém, na kterém běží, nevyžaduje žádné další úsilí. Výsledkem může být, že mnoho "testovaného" kódu ovladačů může ve skutečnosti obsahovat vážné chyby ve svém použití DMA API. Když jsou tyto ovladače spuštěny na jiném systému - konkrétně na nějakém s jednotkou správy I/O paměti (IOMMU), mohou tyto chyby vést k hromadě nepříjemného chování.

Jaderní vývojáři mají rádi, když se jim podaří odhalit chyby před tím, než je jimi pokousán uživatel vzdáleného systému. Aby tomu pomohl u API DMA, Joerg Roedel zaslal nové ladící prostředky DMA API. Tato vlastnost, když je zabudována do jádra, by měla umožnit najít mnoho dříve skrytých chyb v ovladačích zařízení. Ve skutečnosti již ukázala na pár problémů v ovladačích ve stromě, většinou v síťovém subsystému.

Použití této funkce vyžaduje jednoduché povolení konfigurační volby; API samo se nemění. Jakmile je povolen, kód hledá mnoho problémů, včetně uvolňování DMA bufferů s jinou velikostí, než byla zadána v době alokace, uvolňování bufferů, které nebyly vůbec alokovány, míchání koherentních a nekoherentních funkcí na stejném bufferu, zmatení u směru I/O a další. Každý z těchto problémů může na testovacím systému vývojáře uniknout jeho pozornosti, ale tam, kde se používá IOMMU, by mohl napáchat zmatek. Když je problém nalezen, zaloguje se varování a výpis zásobníku.

Reakce na toto API byla kladná. Největší stížnost se zdá být ta, že je toto API implementováno jako vlastnost specifická pro x86. Před začleněním ji tedy bude potřeba zobecnit - koneckonců, vývojáři ostatních platforem také umí zavádět s DMA spojené chyby. Jakmile bude začleněna, měla by být tato vlastnost pravděpodobně povolena na každém systému, který se používá k vývoji ovladačů.

Související články

Jaderné noviny - 12. 11. 2008
Jaderné noviny - 5. 11. 2008
Jaderné noviny - 29. 10. 2008

Odkazy a zdroje

Kernel coverage at LWN.net: November 26, 2008

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.