Cómo compilar el compilador de C desde cero, luego compilar Unix / Linux desde cero

64

Digamos que trabajo para una gran organización de servicios fuera de los Estados Unidos / Reino Unido. Usamos servidores UNIX y Linux ampliamente.

Al leer este artículo , menciona que sería fácil insertar una puerta trasera en un compilador de C, entonces cualquier código compilado con ese compilador también contendría una puerta trasera. Dadas las filtraciones recientes sobre el mandato de la NSA / GCHQ de poner puertas traseras / debilidades en todos los métodos de cifrado, hardware y software, el compilador ahora es un punto crítico de falla. Potencialmente, todas las distribuciones estándar de UNIX / Linix podrían verse comprometidas. No podemos permitir que nuestros sistemas, datos y datos de nuestros clientes se vean comprometidos por gobiernos corruptos.

Dada esta información, me gustaría construir un compilador confiable desde cero, luego tengo una base segura sobre la cual construir para poder construir el Sistema Operativo y las aplicaciones desde el código fuente usando ese compilador.

Pregunta

¿Cuál es la forma correcta (y segura) de compilar un compilador a partir del código fuente (un escenario aparentemente de huevo de gallina) y luego compilar una distribución confiable de Unix / Linux desde cero?

Puede suponer que yo u otros tenemos la capacidad de leer y comprender el código fuente para detectar fallas de seguridad, por lo que el código fuente se examinará primero antes de compilar. Lo que realmente busco es una guía de trabajo para producir este compilador desde cero de forma segura y se puede utilizar para compilar el núcleo, otras partes del sistema operativo y las aplicaciones.

La pila de seguridad debe comenzar en el nivel base si queremos tener alguna confianza en el sistema operativo o las aplicaciones que se ejecutan en esa pila. Sí, entiendo que puede haber puertas traseras de hardware que pueden insertar algún microcódigo en el compilador a medida que se está construyendo. No podemos hacer mucho al respecto por el momento, excepto que tal vez usemos chips no diseñados en los EE. UU. Vamos a ordenar esta capa para empezar y asumir que podría construirla en una computadora vieja potencialmente antes de que se insertaran las puertas traseras.

Como dice Bruce Schneier: "A los ingenieros les digo esto: construimos Internet, y algunos de nosotros hemos ayudado a subvertirlo. Ahora, aquellos de nosotros que amamos la libertad tenemos que arreglarla".

Enlaces extra:

David J
fuente
77
Maldición, esta es una pregunta muy interesante y no quiero migrarla, pero realmente no creo que sea un tema aquí. Es más adecuado para stackoverflow.com, ya que su pregunta básica es sobre cómo compilar un compilador desde cero, que es bastante independiente del sistema operativo y es una pregunta de programación. Si no recibe una respuesta aquí después de un tiempo, considere usar el enlace "flag" debajo de las etiquetas de su pregunta y pedirle a un moderador que mueva esto a SO.
terdon
2
@terdon En realidad, podría ser una mejor opción para los Programadores.SE ya que se trata más de problemas de programación generales que de un problema de desarrollo específico. De hecho, podría ser un duplicado allí .
un CVn
2
GCC es de código abierto, ¿cómo se insertaría cualquier puerta trasera?
Michael Pankov
2
Tenga en cuenta que el exploit estable de Thompson requiere un código que pueda reconocer cuándo se está compilando el programa de inicio de sesión o el compilador. Si puede transformar manualmente la fuente en un formulario que el compilador no pueda reconocer como uno de esos programas, la puerta trasera no se propagará.
Russell Borogove
2
@Constantius: lea el artículo de Thompson vinculado en la primera línea. ¿Quién compila el compilador?
Russell Borogove el

Respuestas:

30

AFAIK, la única forma de estar completamente seguro de la seguridad sería escribir un compilador en lenguaje ensamblador (o modificar el disco directamente usted mismo ). Solo entonces puede asegurarse de que su compilador no esté insertando una puerta trasera; esto funciona porque en realidad está eliminando el compilador por completo.

A partir de ahí, puede usar su compilador desde cero para arrancar, por ejemplo, la cadena de herramientas GNU. Luego, podría usar su cadena de herramientas personalizada para compilar un sistema Linux From Scratch .

Tenga en cuenta que para facilitarle las cosas a usted mismo, podría tener un segundo compilador intermediario, escrito en C (o cualquier otro lenguaje). Por lo tanto, escribiría el compilador A en el ensamblaje, luego volvería a escribir ese compilador en C / C ++ / Python / Brainfuck / lo que sea para obtener el compilador B, que compilaría usando el compilador A. Luego usaría el compilador B para compilar gcc y amigos.

Strugee
fuente
13
Aun así, esto solo protege contra un compilador malicioso. Aún necesita confiar en el sistema en el que se ejecuta el compilador. No existe software de forma aislada.
un CVn
3
Cualquier cosa autónoma es inherentemente peligrosa. Está proponiendo efectivamente un compilador de cadena de herramientas (aunque sea extraño), lo que significa que probablemente pueda modificarse exactamente de la manera que está tratando de evitarlo. Aún mejor, podría modificarse en tránsito a través de MitM.
Strugee
1
Ustedes deben darse cuenta de que esta respuesta proviene de un joven de 15 años. ¡Sigue adelante Strugee!
mtahmed
3
No se debe olvidar también escribir un editor de código desde cero, quién sabe si su <code> vim </code> precompilado o el <code> vim </code> que compila con su buen compilador desde la fuente que ha auditado solo usando infectados ¿<code> vim </code> es confiable?
Hagen von Eitzen
1
Nunca olvide que, a menos que haya escrito personalmente ese primer código de máquina (no ensamblado. Código de máquina real), y que sea un experto en reconocer agujeros de seguridad poco claros, y lea y verifique cada línea de código que está compilando ... o al menos sepa la persona que hizo eso personalmente , y confía en él para hacer esto ... nada de esto ayudará en absoluto. Es por eso que intentar Kickstarter esto está arruinando todo el punto. Cuál es: Alta confiabilidad.
Evi1M4chine
22

Una forma posible, aunque llevaría mucho tiempo en la práctica, sería volver a las raíces. El desarrollo de GNU comenzó en 1984, y la versión original de Minix (que se utilizó durante el desarrollo inicial de Linux con fines de arranque) se lanzó en 1987.

Toda esta respuesta se basa en su premisa de que "[usted] u otros tienen la capacidad de leer y comprender el código fuente por fallas de seguridad, por lo que el código fuente será examinado primero antes de compilar", y que puede confiar en el resultado de dicho análisis . Sin eso, esta respuesta es probablemente peor que inútil, ya que pasarás una gran cantidad de tiempo sin ningún beneficio.

Si puede encontrar una copia del libro original de Minix con el código fuente, puede escribirlo desde el libro. Compílelo y luego use un descompilador diferente en un sistema diferente para verificar que el compilador genere la salida binaria esperada en lenguaje máquina. (El código es de solo 12,000 líneas, presumiblemente C, por lo que hacerlo lleva mucho tiempo pero es razonable si se toma en serio este proyecto). Incluso podría escribir su propio desensamblador; eso no debería ser muy difícil.

Tome las versiones más antiguas de las utilidades de GNU que posiblemente pueda tener en sus manos (ya que presumiblemente tienen menos código y menos dependencias de bibliotecas externas), revise el código, compílelo para Minix (sin embargo, esto podría requerir algo de trabajo; absolutamente lo que quiero evitar es hacer ajustes al código fuente, porque eso hará que agregar parches más tarde sea muy propenso a errores) y pasar por un ciclo similar de desmontaje-verificación para las herramientas GNU. En ese momento, confía en el sistema operativo y la cadena de herramientas, por lo que solo necesita revisar el código fuente en el conjunto de parches (cualquier cosa que no esté en el conjunto de parches ya es confiable), pero las herramientas seguirán siendo muy primitivas y crudas en comparación con lo que se usa hasta hoy. Por ejemplo, no espere nada más que la funcionalidad más básica de las herramientas del sistema.Lee muchos XKCD.

En algún momento, tendrá un sistema que puede compilar y arrancar una versión inicial del kernel de Linux, al igual que se hizo a principios de la década de 1990 cuando Linux comenzó a ganar tracción entre los piratas informáticos. Sugeriría migrar a Linux en ese punto (reconstruir las bibliotecas del sistema y la cadena de herramientas contra Linux, construir el kernel de Linux, arrancar en Linux y posiblemente reconstruir el kernel de Linux y la cadena de herramientas GNU dentro de Linux; lo último prueba que el sistema ahora es auto- hosting), pero eso depende en gran medida de usted. Continúe verificando parches, parcheando el kernel, las bibliotecas y las herramientas básicas de GNU, y reconstruya hasta llegar a las versiones modernas.

Es entonces cuando tiene un sistema operativo y un compilador básicos confiables que se pueden utilizar para crear software moderno. Para entonces, puede seguir, por ejemplo, las guías de Linux From Scratch para crear un sistema capaz de realizar tareas útiles .

En ningún momento se puede conectar el sistema "compilador" a una red de ninguna manera (incluso como VM en un host en red); correría el riesgo de penetración a través de cualquier componente con capacidad de red, incluido el kernel. Si le preocupa un ataque del compilador Thompson , debe esperar que cualquier host VM también se vea comprometido. Use sneakernet para obtener el código fuente y los binarios del host físico en el que está compilando. Espere problemas para que los archivos entren y salgan del sistema al menos antes de llegar al punto donde se implementó el soporte de almacenamiento masivo USB. Si usted es realmente paranoico, listados de código fuente de impresión y las escribe en la mano (y la esperanza de que el controlador de la impresora y la impresora no tienen un código similar en ellas), o lea el código en un monitor de computadora y escríbalo físicamente en otra computadora que esté al lado, pero que no esté conectado a él.

Sí, esto llevará mucho tiempo. Pero la ventaja de este enfoque es que cada paso es incremental, lo que significa que sería mucho más difícil que se deslice cualquier cosa maliciosa a menos que se introduzca gradualmente durante un período de muchas versiones; Esto se debe a que el conjunto de cambios en cada paso es relativamente pequeño y, por lo tanto, mucho más fácil de revisar. Compare el conjunto de parches con el registro de cambios y asegúrese de poder determinar exactamente qué entrada del registro de cambios corresponde a cada cambio en el código fuente. Una vez más, esto supone que tiene la capacidad (posiblemente a través de alguien en quien confía) para verificar que dichos cambios no se hayan infiltrado en la base de código, pero debería acercarlo a un sistema confiable como un software solo, excepto- enfoque de firmware puede.

un CVn
fuente
El método de verificación de desensamblaje es muy defectuoso, ya que todavía supone que la máquina de verificación es totalmente confiable. A menos que construya esa máquina y su software desde cero, o conozca a la persona que lo hizo personalmente y confíe en ella, esto no va a suceder. Entonces esto todavía es inseguro. Lo siento. ...... Además, en estos asuntos "lo más cercano a ..." todavía significa "inseguro", ya que solo requiere un solo lugar no confiable para arruinar todo el punto.
Evi1M4chine
9

Si necesita un compilador de confianza, puede echar un vistazo al trabajo académico, como el proyecto compcert . Es un compilador creado por el INRIA (un laboratorio público francés de TI) diseñado para ser '' certificado '', es decir, para producir un ejecutable semánticamente equivalente al código (y, por supuesto, ha sido probado matemáticamente).

lgeorget
fuente
1
Todos necesitan un compilador de confianza. ¿Cómo funcionan las matemáticas para poder producir un compilador "confiable"?
David J
@DavidJ Bootstrapping, muy probablemente. Construya una pieza pequeña que pueda verificar completamente y demuestre que es correcta, luego úsela como base para construir compiladores más complejos.
un CVn
1
"" "Lo que diferencia a CompCert C de cualquier otro compilador de producción es que se verifica formalmente, utilizando pruebas matemáticas asistidas por máquina, para estar exento de problemas de compilación incorrecta." "" Compcert.inria.fr/compcert-C.html Compilación no es tan empírico como solía ser.
lgeorget
1
@ MichaelKjörling que probablemente no tenga en cuenta que el kernel puede verse comprometido a incluir una puerta trasera en la fuente del compilador cuando lo lee un compilador
monstruo de trinquete el
1
También encontré este enlace que también podría funcionar.
David J
2

Si bien la creación manual de su propio compilador como punto de partida sería la más segura, otra opción es instalar un sistema de un CD de instalación de 5 (o 10) años de antigüedad en el que confía que se creó antes de que existieran estas vulnerabilidades. Luego, utilícelo como base para compilar la nueva fuente auditada.

sambler
fuente
55
El ataque se conoce públicamente desde 1984. Presumiblemente, Thompson no fue el primero en pensar en la posibilidad. Retroceder tan lejos significa que la mayoría de las cosas que damos por sentado hoy no existían; considere lo que las computadoras eran capaces de hacer hace 20 años y compárelo con su estado actual. Incluso el sistema de arranque original de Linux Minix no se lanzó hasta el '87 , y el desarrollo de GNU comenzó en el '84. Entonces, aunque en teoría esto puede responder la pregunta, en la práctica es en gran medida inútil como respuesta.
un CVn
2
La primera computadora que podría tener en mis manos sería una 286. Tendré que ver si mis abuelos todavía la tienen.
David J
1
Puntos de bonificación por considerar eso :-). @DavidJ
11684
@ MichaelKjörling: No realmente; ya que solo alarga tu cadena de arranque. Pero tal vez no sea tan largo como escribir su propio compilador desde cero en lenguaje máquina.
Evi1M4chine