Come compilare il compilatore C da zero, quindi compilare Unix / Linux da zero


64

Diciamo che lavoro per una grande organizzazione di servizi al di fuori degli Stati Uniti / Regno Unito. Utilizziamo ampiamente i server UNIX e Linux.

Leggendo questo articolo si afferma che sarebbe facile inserire una backdoor in un compilatore C, quindi qualsiasi codice compilato con quel compilatore conterrebbe anche una backdoor. Ora, viste le recenti perdite relative al mandato dell'NSA / GCHQ di mettere backdoor / punti deboli in tutti i metodi di crittografia, hardware e software, il compilatore è ora un punto critico di fallimento. Potenzialmente tutte le distribuzioni standard UNIX / Linix potrebbero essere compromesse. Non possiamo permetterci che i nostri sistemi, i dati e i dati dei nostri clienti vengano compromessi da governi canaglia.

Date queste informazioni, vorrei creare un compilatore affidabile da zero, quindi ho una base sicura su cui basarmi in modo da poter costruire il sistema operativo e le applicazioni dal codice sorgente utilizzando quel compilatore.

Domanda

Qual è il modo corretto (e sicuro) per compilare un compilatore dal codice sorgente (uno scenario apparentemente a forma di uovo di gallina), quindi compilare una distribuzione Unix / Linux affidabile da zero?

Puoi presumere che io o altri abbiamo la capacità di leggere e comprendere il codice sorgente per i difetti di sicurezza, quindi il codice sorgente verrà verificato prima di compilare. Quello che sto davvero cercando è una guida di lavoro per produrre questo compilatore da zero in modo sicuro e può essere utilizzato per compilare il kernel, altre parti del sistema operativo e le applicazioni.

Lo stack di sicurezza deve iniziare a livello di base se vogliamo avere fiducia nel sistema operativo o nelle applicazioni in esecuzione su quello stack. Sì, capisco che potrebbero esserci backdoor hardware che potrebbero inserire un microcodice nel compilatore mentre viene creato. Al momento non possiamo fare molto al riguardo, tranne forse usare chip non progettati negli Stati Uniti. Prendiamo questo livello ordinato per cominciare e supponiamo che potrei costruirlo su un vecchio computer potenzialmente prima di inserire eventuali backdoor.

Come dice Bruce Schneier: "Agli ingegneri, dico questo: abbiamo costruito Internet e alcuni di noi hanno contribuito a sovvertirlo. Ora, chi ama la libertà deve ripararlo".

Link extra:


7
Dannazione, questa è una domanda molto interessante e non voglio migrarla ma non credo proprio che sia in tema qui. È più adatto a stackoverflow.com poiché la tua domanda di base è su come compilare un compilatore da zero che è praticamente indipendente dal sistema operativo e molto una domanda di programmazione. Se non ricevi una risposta qui dopo un po ', considera di utilizzare il link "flag" sotto i tag della tua domanda e di chiedere a un moderatore di spostarlo su SO.
Terdon

2
@terdon Potrebbe effettivamente adattarsi meglio a Programmers.SE poiché si tratta più di problemi di programmazione generale che di un problema di sviluppo specifico. In effetti, potrebbe essere un duplicato lì .
un CVn

2
GCC è open source, come verrebbe inserita una backdoor?
Michael Pankov,

2
Tenere presente che l'exploit Thompson stabile richiede un codice in grado di riconoscere quando viene compilato il programma di accesso o il compilatore. Se è possibile trasformare manualmente l'origine in un modulo che non è riconoscibile dal compilatore come uno di quei programmi, la backdoor non verrà propagata.
Russell Borogove,

2
@Constantius: leggi l'articolo Thompson collegato nella prima riga. Chi compila il compilatore?
Russell Borogove,

Risposte:


30

AFAIK l'unico modo per essere completamente sicuri della sicurezza sarebbe scrivere un compilatore in linguaggio assembly (o modificare il disco direttamente da soli ). Solo allora puoi assicurarti che il tuo compilatore non stia inserendo una backdoor - questo funziona perché stai effettivamente eliminando completamente il compilatore.

Da lì, è possibile utilizzare il compilatore da zero per l'avvio, ad esempio la toolchain GNU. Quindi potresti usare la tua toolchain personalizzata per compilare un sistema Linux From Scratch .

Nota che per semplificarti le cose, potresti avere un secondo compilatore intermedio, scritto in C (o qualunque altra lingua). Quindi dovresti scrivere il compilatore A in assembly, quindi riscrivere quel compilatore in C / C ++ / Python / Brainfuck / qualunque cosa per ottenere il compilatore B, che compileresti usando il compilatore A. Quindi useresti il ​​compilatore B per compilare gcc e amici.


13
Anche così, questo protegge solo contro un compilatore dannoso. Devi ancora fidarti del sistema su cui il compilatore esegue. Nessun software esiste in isolamento.
un CVn

3
Qualunque cosa autonoma è intrinsecamente pericolosa. Stai effettivamente proponendo un compilatore di toolchain (anche se strano), il che significa che probabilmente può essere modificato esattamente nel modo in cui stai cercando di evitare. Ancora meglio, potrebbe essere modificato in transito tramite MitM.
Strugee,

1
Ragazzi, dovete rendervi conto che questa risposta arriva da un quindicenne. Continua strugee!
mtahmed,

3
Non bisogna dimenticare di scrivere anche un editor di codice da zero - chissà se il tuo <code> vim </code> precompilato o il <code> vim </code> compili con il tuo buon compilatore dalla fonte che hai controllato solo usando infetti <code> vim </code> è affidabile?
Hagen von Eitzen,

1
Non dimenticare mai che, a meno che tu non abbia scritto personalmente quel primo codice macchina (non assembly. Codice macchina effettivo), e tu sei un esperto nel riconoscere falle di sicurezza subdole e leggere e controllare ogni singola riga di codice che stai compilando ... o almeno conosci la persona che ha fatto personalmente , e fidarsi di lui per fare questo .... nulla di tutto ciò aiuterà affatto. Ecco perché provare a Kickstarter questo, sta rovinando il punto. Che è: alta affidabilità.
Evi1M4chine,

22

Un modo possibile, anche se in pratica richiederebbe molto tempo, sarebbe quello di tornare alle origini. Lo sviluppo di GNU iniziò nel 1984, e la versione originale di Minix (che fu usata durante lo sviluppo iniziale di Linux per scopi di bootstrap) fu rilasciata nel 1987.

L'intera risposta si basa sulla tua premessa che "[tu] o altri hanno la capacità di leggere e comprendere il codice sorgente per i difetti di sicurezza, quindi il codice sorgente verrà controllato prima della compilazione" e che ci si può fidare del risultato di tale analisi . Senza questo, questa risposta è probabilmente peggio che inutile, in quanto trascorrerai un sacco di tempo senza assolutamente alcun beneficio.

Se riesci a trovare una copia del libro Minix originale con il codice sorgente, puoi digitarlo dal libro. Compilarlo e quindi utilizzare un decompilatore diverso su un sistema diverso per verificare che il compilatore generi l'output binario del linguaggio macchina previsto. (Il codice ha solo 12.000 righe, presumibilmente C, quindi farlo richiede molto tempo ma è ancora ragionevole se si prende sul serio un progetto del genere.) Si potrebbe persino scrivere il proprio disassemblatore; non dovrebbe essere molto difficile.

Prendi le versioni più vecchie delle utility GNU sulle quali puoi eventualmente mettere le mani (dato che presumibilmente hanno meno codice e meno dipendenze da librerie esterne), vai attraverso il codice, costruiscilo per Minix (questo potrebbe richiedere del lavoro, però; assolutamente da evitare è apportare modifiche al codice sorgente, poiché ciò renderà l'aggiunta di patch in seguito molto soggetta a errori) e passerà attraverso un ciclo di verifica disassemblaggio simile per gli strumenti GNU. A quel punto ti fidi del sistema operativo e della toolchain, quindi devi solo passare attraverso il codice sorgente nel patchset (tutto ciò che non è nel patchset è già attendibile), ma gli strumenti saranno ancora molto primitivi e rozzi rispetto a ciò che sei usato ad oggi. Ad esempio, non aspettarti altro che le funzionalità di base degli strumenti di sistema.Leggi un sacco di XKCD.

Ad un certo punto, avrai un sistema in grado di compilare e avviare una versione iniziale del kernel Linux, proprio come è stato fatto nei primi anni '90 quando Linux ha iniziato a guadagnare terreno tra gli hacker. Suggerirei di migrare su Linux a quel punto (ricostruire le librerie di sistema e la toolchain contro Linux, costruire il kernel Linux, avviare Linux e possibilmente ricostruire il kernel Linux e la toolchain GNU all'interno di Linux; l'ultimo dimostra che il sistema ora è auto- hosting), ma dipende in gran parte da te. Continua a verificare patch, patch del kernel, librerie e strumenti GNU di base e ricostruzione fino ad arrivare alle versioni moderne.

Questo è quando hai un sistema operativo e un compilatore di base affidabili che possono essere utilizzati per creare software moderno. A quel punto, puoi seguire, ad esempio, le guide di Linux From Scratch per creare un sistema in grado di svolgere attività utili .

In nessun caso il sistema "compilatore" potrà mai essere collegato a una rete in alcun modo (incluso come VM su un host in rete); rischieresti di penetrare attraverso qualsiasi componente abilitato alla rete incluso il kernel. Se sei preoccupato per un attacco del compilatore Thompson , dovresti aspettarti che anche qualsiasi host di macchine virtuali possa essere compromesso. Usa sneakernet per ottenere codice sorgente e binari dall'host fisico su cui stai compilando le cose. Aspettatevi problemi nell'ottenere e spegnere i file dal sistema almeno prima di arrivare al punto in cui è stato implementato il supporto di archiviazione di massa USB. Se siete veramente paranoico, listati di codice sorgente di stampa e digitare a mano (e la speranza che il driver di stampa e la stampante non hanno un codice simile a loro) o leggi il codice sul monitor di un computer e digitalo in un altro computer fisicamente accanto ma non collegato ad esso.

Sì, ci vorrà molto tempo. Ma il vantaggio di questo approccio è che ogni passaggio è incrementale, il che significa che sarebbe molto più difficile far passare qualsiasi cosa maliziosa a meno che non venga introdotta molto gradualmente in un periodo di molte versioni; questo perché l'insieme delle modifiche ad ogni passaggio è relativamente piccolo e quindi molto più facile da guardare. Confronta il patchset con il log delle modifiche e assicurati di poter determinare esattamente quale voce del log delle modifiche corrisponde a ogni modifica del codice sorgente. Ancora una volta, ciò presuppone che tu abbia la possibilità (possibilmente attraverso qualcuno di cui ti fidi) di verificare che tali modifiche non siano state introdotte di nascosto nella base di codice, ma dovrebbe avvicinarti a un sistema fidato come un software, tranne- l'approccio del firmware può.


Il metodo di verifica del disassemblaggio è molto imperfetto, poiché fa ancora l'enorme presupposto che la macchina di verifica sia pienamente affidabile. A meno che tu non abbia costruito quella macchina e il suo software da zero, o conosci la persona che l'ha fatto personalmente e si fida di lei, questo non accadrà. Quindi questo è ancora insicuro. Scusate. …… Inoltre, in queste faccende “il più vicino a…” significa ancora “insicuro”, in quanto richiede solo un singolo punto inaffidabile per rovinare l'intero punto.
Evi1M4chine,

9

Se hai bisogno di un compilatore di fiducia, potresti dare un'occhiata al lavoro accademico, come il progetto Compcert . È un compilatore creato dall'INRIA (un laboratorio pubblico IT francese) progettato per essere "certificato", cioè per produrre un eseguibile semanticamente perfettamente equivalente al codice (e, naturalmente, è stato matematicamente provato).


1
Tutti hanno bisogno di un compilatore di fiducia. Come funzionano i calcoli che possono produrre un compilatore "attendibile"?
David J,

@DavidJ Bootstrapping, molto probabilmente. Costruisci alcuni piccoli pezzi che puoi verificare e dimostrare completamente, quindi usali come base per costruire compilatori più complessi.
un CVn

1
"" "Ciò che distingue CompCert C da qualsiasi altro compilatore di produzione, è che è verificato formalmente, utilizzando prove matematiche assistite da macchina, per essere esente da problemi di compilazione errata." "" Compcert.inria.fr/compcert-C.html Compilazione non è più empirico come una volta.
lgeorget,

1
@ MichaelKjörling che probabilmente non tiene conto del fatto che il kernel potrebbe essere compromesso per includere una backdoor nella fonte del compilatore quando viene letto da un compilatore
maniaco del cricco

1
Ho anche trovato questo link che potrebbe funzionare anche.
David J,

2

Mentre creare manualmente il proprio compilatore come punto di partenza sarebbe il più sicuro, un'altra opzione è quella di installare un sistema da un CD di installazione di 5 (o 10) anni di cui si crede sia stato creato prima che esistessero questi exploit. Quindi utilizzalo come base per compilare la nuova fonte controllata da.


5
L'attacco è noto pubblicamente dal 1984. Presumibilmente Thompson non è stato il primo a pensare alla possibilità. Tornare così lontano significa che la maggior parte delle cose che diamo per scontate oggi non c'erano; considera quali computer sono stati in grado di fare 20 anni fa e confrontali con il loro stato attuale. Persino il sistema di bootstrap originale Minix di Linux non fu rilasciato fino all'87 , e lo sviluppo di GNU iniziò nell'84. Quindi, mentre in teoria questo può rispondere alla domanda, in pratica è in gran parte inutile come risposta.
un CVn

2
Il primo computer su cui potrei potenzialmente mettere le mani sarebbe un 286. Dovrò vedere se i miei nonni ce l'hanno ancora.
David J,

1
Punti bonus per aver effettivamente considerato che :-). @DavidJ
11684

@ MichaelKjörling: non proprio; poiché allunga solo la catena del bootstrap. Ma forse non fino a quando scrivi il tuo compilatore da zero nel linguaggio macchina.
Evi1M4chine,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.