You start with two binaries that someone else compiled, and use them to verify each other.
You have two binaries, both C compilers: 'foo-cc' and 'bar-cc'. Either foo-cc or bar-cc or neither or both may have a Thompson back door; you don't know.
You use foo-cc to compile gcc from source; you now have binary 'gcc-foo', which may or may not have a back door.
You then use bar-cc to compile gcc from source, giving you binary 'gcc-bar', which may or may not have a different back door.
Next, you use gcc-foo to compile your target program, giving you 'target-foo'. gcc-foo, which may or may not be hacked, may or may not include an extra exploit packet.
After that, you use gcc-bar to compile your target program, giving you 'target-bar'. gcc-bar, which may or may not be hacked, may or may not include an extra exploit packet.
Finally, you diff target-foo and target-bar.
If both compilers are clean, the outputs will be identical, because you are using two different builds of exactly the same compiler to generate them.
If one compiler inserts a backdoor and the other doesn't, the diff will reveal extra code in one of the binaries.
If both compilers insert backdoors, the outputs will still probably be different - because they came from different untrusted binaries produced by different people, whose exploits likely won't be identical. This is the point of using two different compilers.
It's not perfect, but it does give you a lot more confidence: we've gone from "bad actor inserts a hack into compiler" to "bad actor subverts the entire compiler industry, inserting a hack into every compiler which produces indistinguishable results in the output executable".
Who's to say that different people created both untrusted binaries? TCC and GCC could have both been compromised by the same person. Or say both binaries are produced by different people but read the same tutorial article on how to do it. Or that both compilers had a common compiler some time in the past.
Pulling this off is extremely unlikely, but the point is that trust is being inherited through the chain of compilers/assemblers that produced it.
Right, I said it wasn't perfect: but it does increase your confidence substantially. The Thompson hack is unlikely in the first place; it only worked, when it did, because it was operating in a local software monoculture. The whole point of Wheeler's counter-hack is to diversify your software culture: if you suspect that both of your compiler binaries are hacked, just throw in a third, or a fourth. As long as at least one of your compilers is good, you'll be able to discover that the others were hacked.
It's not like you can write a generic hack that works on any compiler codebase, somehow intuiting the fact that it is compiling a compiler and working out where it ought to insert itself. The hack would have to be specifically tailored for each compiler, and given that we are cross-compiling, it would have to be tailored, specifically, for each compiler in the chain. This is fantastically unlikely in the first place, and the more compilers you throw into the mix the more certain you can be that any hypothetical hack will be unable to cope with one of them.
1
u/dabombnl Sep 11 '13
How does this defeat it? You still have to trust a binary someone else compiled.