Napadení kompilačního procesu
Nejde o teoretický problém. Dokumenty Edwarda Snowdena dokazují, že CIA se podařilo v roce 2012 úspěšně napadnout build systémy firmy Apple a zasáhnout do procesu sestavování (kompilace) aplikací pro operační systémy této společnosti pomocí software Xcode. V praxi tak tajná služba dostala do ruky neomezený nástroj k ovlivňování funkce libovolné aplikace.
Jistě víme, že byl objeven způsob, jak do výsledné aplikace propašovat vlastní kód a získávat tak na dálku data ze zařízení s iOS či OS X. Je tak možné otevírat backdoory, vyměnit vývojářské klíče v aplikacích, odesílat uživatelská data ven nebo vypínat bezpečnostní nastavení systému. Bum.
O teoretické možnosti podstrčení falešných binárních souborů se hovoří prakticky co je svět světem, ale zatím to bylo jen předmětem vášnivých debat v anarchistických kroužcích, případně jiných veskrze akademických debat. Nyní se ukazuje, že je to realita, která boří veškeré bezpečnostní zábrany. Kukaččí vejce si totiž přinesete už s aplikací, která může být zcela legitimní.
Jehla v seně
Většina debat se navíc točila okolo hypotetického zlého vývojáře, který na veřejnosti ukazuje čisté zdrojové kódy, ale binární balíčky jsou sestavovány z upravených (nebo úplně jiných) kódů, které mohou dělat prakticky cokoliv. Nyní se ale ukázalo, že i vývojář v tom celém může být naprosto nevinně a pes byl zakopán po cestě: během kompilace, kterou fakticky řídil někdo jiný.
Jak tedy můžeme věřit softwarovým balíčkům z našich distribucí? Jsou přeci digitálně podepsané! Ale co když vývojář bezděky podepsal něco, co mu bylo vlastně tajně podstrčeno. Všichni uživatelé si pak ve slepé důvěře balíček nainstalují a dílo je dokonáno.
Potíž je v tom, jak takovou věc dokázat nebo vyvrátit. Kompilace je komplikovaný proces, jehož přesný výsledek závisí na mnoha různých faktorech: verzích knihoven, verzi kompilátoru, použitých přepínačích a stovkách dalších drobností, které mohou výsledek fatálně ovlivnit. Neplatí tedy, že když si teď pokusně sestavíte binárku z libovolného balíčku a nevypadne vám navlas totéž, jste automaticky napadeni. Prostě jste něco během procesu udělali jinak. Dobrat se jednoduše výsledku je tedy téměř nemožné.
Debian se rozhodl pustit do velkého díla, jehož výsledkem by měl být důkaz o čistotě systému: reprodukovatelná kompilace.
Test si může provést každý
Projekt se snaží vytvořit podmínky, ve kterých si kdokoliv může ověřit pravost binárních balíčků. Tedy to, že byly sestaveny z dodávaných zdrojových kódů a nic do nich nebylo po cestě přidáno. Tato veřejná kontrola by pak měla být definitivním řešením tohoto problému – jakýkoliv neoprávněný zásah je takto možné odhalit.
Pokud není znovu vytvořená binárka na bit stejná s balíčkem dodávaným Debianem, máte v ruce důkaz o manipulaci. V opačném případě si můžete být docela dobře jisti, že sestavovací proces v Debianu nebyl napaden a zdrojový kód nebyl v jeho průběhu změněn.
Cílem je kompletní reprodukovatelnost, tedy aby všech více než 22 000 balíčků bylo možné znovu zkompilovat přesně tak, abyste dostali celý originální debianí strom. Úkol to není malý, ale v současné době už je většina balíčků připravena. Vždyť také projekt běží už dva roky.
Kompilátor kompiluje kompilátor
Že je to problém velmi zašmodrchaný, ukazuje problém samotného kompilátoru. Jak můžeme věřit něčemu tak komplexnímu, co je navíc kompilováno dalším kompilátorem. Pokud by se někomu podařilo kompromitovat některý z kompilátorů, dostávali by všichni uživatelé sice stejné výsledky, ale vzniklé během stejně chybného procesu.
Odpovědí na tento zdánlivě nerozetnutelný kruh je takzvaná Diverse Double-Compiling. Potřebujete k němu dva kompilátory, přičemž jeden z nich prohlásíme za důvěryhodný. Poté testovaný kompilátor dvakrát sestavíte, pomocí obou kompilátorů. Obě takto vytvořené verze pak použijete k překladu testovaného kompilátoru ještě jednou. Pokud se výstupy neliší, můžete si být jisti, že proces je v pořádku a nebyl napaden.
Jak na to?
Celý problém je možné rozdělit na několik samostatných problémů: vytvoření kompilačního prostředí, dokumentace celého postupu kompilace, přenos prostředí k jiným uživatelům, standardizace testovacího procesu. Tím vším se Debian v současné době zabývá a slouží jako jakýsi etalon v této oblasti pro další projekty se stejnými ambicemi.
Vypadá to poměrně jednoduše: zajistíme stejný vstup a stejné prostředí a výstup musí být stejný, to dá rozum. V praxi je v tom ale celá řada háčků, protože kompilační proces ovlivňuje ještě mnohem více proměnných než jste si doposud mysleli. Nezapomeňte, že potřebujete dostat naprosto totožný výstup, ne jen přibližný.
Například: Časové značky tu hrají velkou roli, čas kompilace je velmi často součástí výstupu. Změny pořadí souborů na disku mohou také vést k různým výsledkům. Často se během kompilace může používat náhodné číslo například pro označení jednotlivých buildů. Součástí kódu mohou být specifické části pro konkrétní řadu procesorů. Cesta k adresáři (!) se zdrojovým kódem může být součástí výstupu. Velkou roli může hrát také nastavení lokalizace systému nebo použitá časová zóna. Stačí? Je toho víc.
Při sestavování balíčku se například mohou stahovat některé části z internetu – typicky třeba aktuální dokumentace. Ovšem aktuální znamená vždy jiná, což vede k jinému balíčku. Proto není možné se například spolehnout na internetové zdroje a je lepší mít vše offline nebo mít alespoň archivované kontrolní součty.
Pokud se během práce vytváří komprimované archivy, také mohou být při každém sestavování jiné. Záleží totiž na pořadí souborů na disku a na tom, jak je za sebou kompresní utilita sbírá a komprimuje. Vývojáři tedy musí upravovat zdrojové kódy tak, aby se explicitně třídily komprimované soubory podle názvu. Ovšem tady zase vstupuje do hry lokalizace. V češtině se může například ch třídit jinak než v jiných jazycích.
Připočítejte k tomu různé divně napsané aplikace, které k inicializaci datových struktur používají náhodný kus paměti s náhodným obsahem a máte dost práce na několik let. Všechno to poměrně podrobně sepsal Jérémy ‚Lunar‘ Bobbio ve své přednášce [PDF] pro letošní Chaos Communication Camp.
Stejný pracovní stůl je základ
Pokud už se vám podaří vymýtit všechny tyto nešvary, které ovlivňují výsledek, zbývá nadefinovat a zakonzervovat prostředí, ve kterém jsou binárky sestavovány. Prostředím jsou myšleny především nástroje, kterými se provádí kompilace a všechny následující činnosti. Vše je třeba samozřejmě zdokumentovat včetně verzí, architektury, operačního systému, adresářových cest, času sestavení a podobně.
Pokud pak chce uživatel začít reprodukovat existující balíčky, má dvě možnosti: začít kompilovat dané verze nástrojů ze zdrojových kódů a vytvořit si správné prostředí (tak to dělá třeba OpenWRT nebo Tor Browser), nebo získat kompletní verzi operačního systému v potřebném stavu (tak to dělá Bitcoin). Další variantou je využít virtualizačního prostředí nebo vše zavřít v kontejneru, což ale přináší další řadu softwarových nástrojů, kterým je třeba věřit.
Debian se ale rozhodl na to jít jinak a definoval nový formát řídicího souboru .buildinfo
. Ten obsahuje mimo jiné seznam všech zdrojových souborů a balíčků, které byly v době kompilace v systému nainstalovány. Je tedy poměrně snadné zpětně sestavit stejné prostředí – jednoduše se nainstalují stejné verze balíčků ze seznamu.
V Debianu je to možné velmi snadno, protože se archivují všechny balíčky, které kdy projekt vyprodukoval. Starší verze balíčku je tedy vždy k dispozici, i když už byla mezi tím v repozitářích přepsána verzí novější. Uživatelé by měli mít k dispozici nástroj (skript), který řídicí soubor projde a připraví vše do správného stavu.
V současné době běží projekt reproducible.debian.net, který automaticky zkouší kompilovat průměrně 1300 balíků denně. Vše se přitom kompiluje dvakrát a mezi cykly dojde ke změně v nastavení prostředí. Změní se například časová zóna, locales, uživatel, hostname a podobně. Strojově jsou tak odhalovány chyby a výsledky se sypou do databáze, která je veřejně dostupná na webu projektu.
Na základě projektu vzniká velké množství patchů, které jsou postupně zařazovány do současných zdrojových balíků. Práce je to nelehká, protože porovnáním dvou komprimovaných balíčků nezjistíte, proč se liší. Je potřeba se ponořit dovnitř a hledat v binárních souborech rozdíly. Slouží k tomu například mocný nástroj diffoscope nebo strip-nondeterminism schopný odstranit z výstupu nedeterministická data.
Debian není jediný
Je potřeba si říci, že Debian není jediným projektem, který se o něco takového snaží. U něj je situace zajímavá proto, že jde o jeden z největších softwarových balíků na světě. Proto je to obrovský úkol, ale zjevně ne nezvládnutelný.
Ze známých projektů se do cíle dostal například Tor Project nebo Bitcoin. Mnoho dalších projektů na reprodukovatelnosti pracuje, patří mezi ně například FreeBSD, NetBSD nebo OpenWRT. Reprodukovatelná kompilace by se podle vývojářů Debianu měla stát standardem a měla by být uživateli vyžadována.