Ho sempre detto che i programmi a sorgente aperto (open source) sono trasparenti perché non nascondono nessuna delle sue funzioni. Chiunque comprenda il codice con cui sono stati scritti può ispezionarli alla ricerca di eventuali funzioni malevole e anche se noi non siamo in grado di comprendere il codice possiamo stare certi che, se un programma è molto diffuso, moltissimi sviluppatori avranno dato, almeno una volta, un'occhiata al codice sorgente. Il problema è che veramente una piccolissima porzione di utenti scarica il codice e perde tempo a compilarlo per creare il programma finito da utilizzare; quando disponibile, la stragrande maggioranza si limita a scaricare l'archivio o il pacchetto contenente il programma già compilato. È qui che entrano in gioco le "reproducible builds"...

Cosa sono "reproducible builds"?

Con reproducible builds (letteralmente "costruzioni riproducibili"), dette anche "deterministic compilation" (compilazione deterministica), si intende una serie di pratiche per lo sviluppo dei programmi che, se seguite, sono in grado di generare sempre lo stesso risultato partendo dallo stesso codice sorgente. Queste pratiche e regole sono raccolte e catalogate dal progetto Reproducible Builds.

Ad alcuni potrà sembrare strano ma, normalmente, compilando uno stesso codice sorgente su computer diversi si può ottenere un programma che funziona allo stesso modo ma che tuttavia non è identico sui due computer. Di più: compilando lo stesso codice sorgente sullo stesso computer, in momenti diversi, può generare risultati differenti. Com'è possibile? La compilazione è un processo così casuale?

Cosa sono "reproducible builds"?

No, la compilazione è un processo molto preciso, il problema sta nelle istruzioni del codice sorgente che possono includere alcune variabili (come il timestamp) che, facendo riferimento al sistema in uso, possono determinare variazioni nel prodotto finale della compilazione. Queste variazioni potrebbero non influire assolutamente sul funzionamento del programma e la diversità si potrà trovare anche solo nell'ordine di alcuni bit dell'eseguibile. Questo però ci potrebbe far venire un dubbio: come essere sicuri che il programma compilato non sia stato manomesso (ad esempio, per inserire una backdoor)?

Nello schema sotto possiamo vedere quali sono le variabili che possono influire, identificate da Reproducible Builds:

Cosa sono "reproducible builds"?

Con la compilazione deterministica si punta ad ottenere, da una precisa versione di un dato codice sorgente, sempre lo stesso artefatto, uguale bit per bit, indipendentemente da quando o dove questo venga compilato e quindi verificabile da chiunque, offrendo garanzia che ad un codice sorgente corrisponde sempre lo stesso eseguibile. Per raggiungere questo risultato occorre quindi rispettare regole precise (si parla persino di "comandamenti"), valide per quasi ogni linguaggio di programmazione, che, senza entrare troppo in dettagli tecnici utili solo agli sviluppatori, devono garantire l'assoluta indipendenza del codice sorgente dal sistema in uso. Ideale, ma non strettamente necessario, sarebbe avere anche il sistema dove avviene la compilazione completamente riproducibile.

Quali sono i vantaggi?

I vantaggi nell'adottare questa pratica sono molti, il più evidente è quello che abbiamo finora sottinteso, cioè la possibilità di provare con sicurezza che il software non è stato manomesso.

Un altro vantaggio meno evidente è la possibilità di evidenziare problemi hardware sui server utilizzati per la compilazione (ad esempio, in caso di settori danneggiati della RAM): se sappiamo che dobbiamo aspettarci un certo risultato, che non corrisponde a quello ottenuto, è chiaro come possiamo individuare subito un problema. In caso di distro Linux, ad esempio, se rilevata un'incongruenza è possibile fermare la distribuzione del software, a tutto vantaggio della affidabilità dei rilasci. Ancora la facilità nel fare il debug delle applicazioni; quando il risultato della compilazione deve essere il medesimo è più facile vedere le differenze date da una correzione del codice sorgente.

Un altro vantaggio è scongiurare l'utilizzo di un programma compilatore che installa malware nel programma da produrre, durante la fase di compilazione; anche se questo può essere un attacco molto difficile da perseguire, in passato è già successo.

Cosa sono "reproducible builds"?

Ultimo ma non ultimo, la compilazione deterministica è un'assicurazione per gli sviluppatori di software che, in questo modo, non possono essere "spinti" (con minacce o pressioni di vario tipo) ad installare backdoor (o malware in generale) nel prodotto compilato (ma non presente nel codice sorgente) perché sarebbero facilmente scoperti.

Chi lo utilizza?

GNU è stata tra le prime a capire l'importanza di avere compilazioni deterministiche e attua regole per garantire questo risultato per tutti i suoi strumenti già dai primi anni '90, quando ancora non esisteva il progetto Reproducible Builds.

Anche Debian e Bitcoin (con la creazione di Gitian) si sono mossi in questa direzione già dai primi anni 2000 seguite, dopo il caso Snowden, da Tor.

» Leggi: La Grande Guida a Tor: navigazione anonima gratuita, senza censura o VPN

» Leggi: Guida Bitcoin e criptovalute: tutto quello che devi sapere per iniziare

Oggi sono molti di più i progetti che cercano di raggiungere la completa riproducibilità dei software che forniscono, con risultati diversi fra loro, tra cui si evidenziano alcune eccellenze come, ad esempio, Debian ed ArchLinux.

» Leggi: ArchLinux: una distro solo per utenti esperti?

Cosa sono "reproducible builds"?

Perché non è una pratica adottata da tutti?

Ci sono sviluppatori che pensano che i benefici dati dalla compilazione deterministica siano minimi se non nulli a fronte della complicazione richiesta per raggiungerla [1] [2], sostenendo che l'unico modo per essere sicuri che il prodotto di una compilazione derivi esattamente da un codice sorgente, sia compilare in autonomia il programma. Anche se le argomentazioni presentate possono essere valide soprattutto in alcuni settori che riguardano la sicurezza, personalmente, ritengo questa tesi un po' estrema (lo stesso potrebbe essere detto dei programmi open source: l'unico modo per essere sicuri è controllare il codice da noi stessi); per l'utente medio la possibilità di verificare facilmente che una programma è esattamente quello che ci si aspetta può essere un ausilio più che sufficiente, ad esempio, per capire se il sistema è stato compromesso oppure no.

I motivi per cui questa pratica non è adottata da tutti sono vari ma i principali sono il continuo controllo del lavoro svolto (che costa tempo e risorse) e l'effettiva necessità di un sistema di verifica. Per capire meglio quest'ultimo punto, possiamo analizzare il modo in cui viene compilato e distribuito il software dalle eccellenze evidenziate sopra tra coloro che hanno adottato questa pratica: sia Debian che ArchLinux consentono ai manutentori dei pacchetti che distribuiscono dai loro repository, di compilare in maniera autonoma i programmi dai sorgenti. Questo significa che ogni sviluppatore che fa parte di quel progetto può essere "un punto debole" per la distribuzione di malware o programmi contenenti backdoor (non perché non siano persone degne di fiducia ma perché, come detto, potrebbero essere "spinti" in tale direzione...) ed ecco perché si rende necessario un sistema che consenta di verificare che, ad un dato sorgente corrisponde un preciso file compilato. Caso diverso è, ad esempio, quello di Fedora o OpenSUSE, che compilano i programmi in un sistema centralizzato e strettamente controllato, molto più difficile da compromettere; ciò nonostante entrambe le realtà appena citate hanno deciso di aderire al progetto Reproducible Builds.

» Leggi: Fedora la distro per tutti sponsorizzata da RedHat

» Leggi: OpenSUSE Tumbleweed: buon divertimento con la migliore distro!

Vale solo per il mondo Unix (Linux/BSD)?

Finora abbiamo parlato per la maggior parte di Linux ma si può ottenere compilazioni deterministiche anche su piattaforme proprietarie come Windows e MacOS che di solito richiedono compilatori anch'essi proprietari? Sistemi proprietari come questi sono difficili da controllare e c'è sempre la possibilità che possano modificare la compilazione in qualche modo. Sicuramente sono da evitare i compilatori proprietari che aggiungono ulteriori ombre al processo di compilazione.

Fortunatamente è possibile utilizzare compilatori trasversali, come Mingw-W64 o Crosstool-ng, che consentono ad esempio di compilare software rispettivamente per Windows e MacOS direttamente da Linux. Pionieri nella tecnica di compilazione trasversale sono ancora una volta i già citati Bitcoin e Tor.