Comment by isaacimagine

5 years ago

That's what I was thinking while reading this article, +1!

In short, the premise of the talk is: if you add a self replicating change to any self-hosted compiler:

- You can 'teach' the compiler to do things that are never explicitly stated in their source code, like, in this article, making the compiler modify programs that meet specific predicates.

- You can not trust that your compiler hasn't been modified without bootstrapping it yourself. You can't trust a program without trusting its compiler; and since compilers are programs, well it's turtles all the way down.

To build a trusted compiler, you have to bootstrap one yourself from some trusted manner, usually from hand-written assembly. In C, this would be akin to writing a small C compiler in assembly, using that to compile tcc, using that to compile a slightly larger C compiler, and that to compile clang or gcc.

But in other more complex languages, such as Rust, bootstrapping is not as clear cut. There's the Reproducible Builds project, but afaict there exists no minimal small Rust compiler you can bootstrap the latest one from: You have to go back the the original OCaml one and compile up from there, or just trust that the publicly available build is secure (which it most likely is).

I guess the lesson is that it's possible to inject hidden self-replicating behavior into any significantly complex system.

An assembler can also do this same attack. You have to hand-assemble your basic assembler to machine code. In theory a sophisticated-enough hex editor could also be subverted, silently adding in code when it's used to edit executable-looking files. The system dynamic linker can be compromised to subvert any executable. Etc.

If a machine is compromised, it can't be recovered without access to a known-good machine.

I get the theory here, but never having written a compiler myself, I’m curious how easy/difficult it would be to come up with those predicates in practice?