Linuxové noviny | Březen 1998 | |||||
| ||||||
Mnoho systémových programů v UNIXovém operačním systému - Linux nevyjímaje - potřebuje pro svůj běh zvláštní privilegia. Příkladem budiž program passwd, který musí být schopen zapisovat do souboru /etc/passwd resp. /etc/shadow, aniž by k tomu byl oprávněn sám uživatel (z pochopitelných důvodů). Nejčastěji používaným mechanismem, který toto umožňuje, je tzv. propůjčení identifikace. U programu, jehož spustitelný soubor má nastavený aspoň jeden z s-bitů, například takto:
-r-sr-xr-x 1 root bin 15796 /usr/bin/passwddojde po jeho spuštění systémovým voláním execve() k tomu, že efektivní vlastník, efektivní skupina, případně oboje - podle toho, zda je v přístupových právech nastaven setuid bit (04000), setgid bit (02000), nebo oba dva - jsou nastaveny na hodnoty určené uživatelem resp. skupinou vlastnící soubor. (Množina doplňkových skupin (supplemental groups) je vždy ponechána beze změny.) Program pak pracuje se stejnými oprávněními, jako kdyby byl spuštěn svým vlastníkem resp. uživatelem v dané skupině.
Privilegovaný proces musí pečlivě kontrolovat prostředí, ve kterém je spuštěn, a vstupy, které jsou mu uživatelem předkládány. Naneštěstí mnoho programů (či spíše jejich autorů) toto podceňuje a výsledkem jsou závažné bezpečnostní problémy, které jsou ještě umocněny tím, že velká část takových programů pracuje rovnou s nejvyššími možnými privilegii - s právy superuživatele. K nejčastějším chybám, které mají za následek bezpečnostní problémy (a které budou detailněji diskutovány níže) patří:
Pomocí vhodně sestrojených vstupních dat pak může zlý uživatel přepsat návratovou adresu na zásobníku nebo jiné důležité údaje a donutit program k vykonání prakticky libovolných akcí - např. ke spuštění privilegovaného shellu. Detailní popis přináší například http://www-miaif.ibp.fr/willy/security/. Příklad (xc/programs/Xserver/os/access.c) je na výpisu Nesprávné meze polí.
Výpis 3: Nesprávné meze polí Uživatel může při spuštění Xserveru specifikovat libovolný (i nesmyslný a hlavně libovolně dlouhý) název displaye pomocí parametru uvozeného dvojtečkou. Tato hodnota je předána do funkce ResetHosts(), která ji používá pro konstrukci jména souboru. Avšak příliš dlouhá hodnota způsobí přetečení mezí pole fname.
Příklad (xc/programs/Xserver/os/utils.c) je na výpisu Příklad nesprávného zacházení se souborem.
Výpis 4: Příklad nesprávného zacházení se souborem Funkce ExpandCommandLine() interpretuje parametr -config tak, že načte obsah specifikovaného souboru a přidá ho k parametrům zadaným na příkazové řádce. Nicméně vůbec nekontroluje, zda je daný soubor uživateli, který Xserver spustil, přístupný pro čtení. Například, pokud zlý uživatel zadá soubor /etc/shadow, dostane se mu chybového hlášení typu:
Unrecognized option: root:BFLMpsvzABCD:12345:::::a může začít luštit superuživatelovo heslo. Zvláštní kapitolu představují dočasné soubory vytvářené v oblastech přístupných uživateli - zvláště v adresáři /tmp, ale i v domovském adresáři uživatele, v aktuálním adresáři apod. Zlý uživatel může vytvořením (sym)linků nebo přejmenováváním souborů lehce přesvědčit naivně implementovaný program, aby pracoval s úplně jiným souborem, než zamýšlel. Bohužel tomu opět napomáhá standardní knihovna - konkrétně funkce mktemp() a tmpnam(). V případě Xserveru lze problém tohoto typu demonstrovat na práci s adresářem /tmp/.X11-unix, i když konkrétní povaha těchto rizik poněkud vybočuje ze zaměření tohoto článku.
Příklad (xc/programs/Xserver/xkb/ddxLoad.c) je na výpisu Neopatrné spouštění dalších programů.
Výpis 5: Neopatrné spouštění dalších programů Proměnná XkbBaseDirectory obsahuje buď implicitní hodnotu (/usr/lib/X11/xkb), nebo hodnotu specifikovanou pomocí parametru -xkbdir. (Z tohoto důvodu mi není zcela jasný význam testu na nulovou hodnotu, ale to ponechme stranou.) Uživatel má nyní dvě možnosti jak tento parametr zneužít: jednak může vytvořit libovolný program pod jménem xkbcomp a předat jméno adresáře, ve kterém se nachází, nebo může využít faktu, že funkce popen() způsobí spuštění shellu, a zadat hodnotu, která obsahuje znaky mající pro shell zvláštní význam (např. mezery, obrácené apostrofy aj.).
První pravidlo říká, že v programu nesmí být chyby, ale navržen musí být s ohledem na to, že tam chyby budou. To například znamená, že ty části programů, které zvláštní privilegia vyžadují, je vhodné separovat do malých samostatných programů s přesně definovaným rozhraním, jejichž správnou funkci bude možno ověřit - ideálně formálním důkazem. Druhé pravidlo pak doporučuje, aby každý program měl přidělena pouze ta privilegia, která ke své práci potřebuje a pokud možno žádná jiná. To bohužel často naráží na omezení operačního systému - zvláště v UNIXovém světě (Linux opět nevyjímaje), kde vládne silná dichotomie: vše (superuživatel) nebo nic (ostatní uživatelé). Není-li možno dostatečně jemně rozlišovat privilegia, dochází k tomu, že jsou přidělována širší oprávnění, než je zapotřebí, a otevírá se prostor pro jejich zneužití. Jediným skutečným řešením tohoto problému je upravit operační systém tak, aby programy nemusely mít větší oprávnění než je nutno. Komplexnější projekty jako LinuxPrivs http://www.kernel.org/pub/linux/libs/security/linux-privs/ (implementace privilegií podle POSIX.1e) jsou vykročení správným směrem, ale existují i částečná řešení, jako například patch http://www.phrack.com/52/P52-06, který mj. eliminuje dosti nesmyslnou (v dnešní době) potřebu superuživatelských práv pro některé síťové služby. Poněkud paradoxní je, že popisovaná opatření (pomineme-li obecné doporučení, že v programech nemají být chyby) nejsou příliš vhodná pro náš Xserver. Ten totiž ve skutečnosti žádná speciální privilegia nepotřebuje, pouze musí být schopen ovládat grafický hardware. Stačí, aby pro to byla v jádře dostatečná podpora - jako jí poskytuje například GGI http://www.ggi-project.org/.
|