Spectre depends on binaries being able to be studied and decompiled, to influence how they behave. Polymorphing for Linux fundamentally nullifies the entire premise. It’s not even a competition. You can’t influence what you don’t know. Attackers are left confused and baffled.
Spectre and Meltdown are unique because:
This is a highly generalized and simplified explanation of Spectre. A graphical overview of how instructions can be exploited through speculative side-effects is provided in my previous post on Meltdown.
The foundation of Meltdown and Spectre lies on having the ability to extract data using a side-channel. A side-channel is a measurable/observable side-effect that you can read.
A great example of a side-channel is the cooling fan in my laptop. When I’m reading news online and my fan spins up, it tells me my CPU is overheating. Even though I’m not running any compute-intensive applications. That means one of my browser tabs is probably mining bitcoins at my expense. Thus a simple side-channel can effectively tell me there’s high CPU usage.
The second part of Spectre relies on influencing the victim program to do your bidding, without touching the program itself. If this is done in such a way as to leave a persistent side-effect, it can be read by the attacker program without ever crossing security boundaries.
This relies on having access to the program’s binary, so that it can be studied, decompiled and well understood. How is this possible?
All the speed gains we are used to are built on decades of adaptive learning. Nearly everything around you is continually learning and adapting to be better, faster and more efficient. Your internet connection is adapting and remembering what you connect to, and adapting in real time. Your DNS provider is caching your frequently used domains. Many interpreted languages now feature a JITer (Just in Time) compiler — this compiler studies which code paths are most frequently used, and in what ways, so it can rewrite code while it is running, to be more optimal and efficient.
Anything that can learn can be trained.
This power to learn and adapt can also be used to train and influence. All an attacker need do is train your processor to favor one path above another, and your branch predictor will do the attacker’s bidding in YOUR program.
Even though programs and their data is isolated, the learning is shared.
The CPU is learning from both. The attack program isn’t doing anything malicious. Even an intelligent scanning tool wouldn’t catch it. Quite the opposite, in fact. It is, however, training the branch predictor that jumping to LP1 results in innocuous behavior! Guess what happens when that branch is predicted in the victim program?
LP1 in the victim program points to dangerous instructions that expose private data (passwords, encryption keys, etc.) to the side-channel. Now, techniques like Meltdown can be used to read memory, EVEN IF the Meltdown patch has been applied.
By telling the CPU repeatedly that LP1 is a safe, innocuous location to jump to, the attacker made the CPU use that learning on the victim program, where that no longer held true.
A lot of possible defenses and mitigations are discussed in the paper about Spectre. However the paper makes one big assumption — that all binaries are the same at all times. Compiler-based defenses are assumed to be applicable only once. Obfuscation is assumed to be only applicable on a singular binary — thus severely limiting them.
But here’s the problem — the attack fundamentally works because a binary can be studied and analyzed at leisure. That is where it must be defeated.
Meltdown is technically a “security bug” because the branch speculation works across security zones. Spectre however, is not. Spectre is neither a “bug” nor a “vulnerability.” Spectre fundamentally works because every machine behaves identically. Furthermore, it relies on making the machine behave identically.
There is no way to have deterministic identical machine layouts and avoid the natural side-effect — deterministic speculation.
Fundamentally, Spectre is not the cause of anything being “wrong.” This is why tools that look for “wrongness” aren’t working this time. You can’t detect what is correct. You can’t analyze what is correct. AI will only make the speculator learn branches even BETTER. You can’t remedy side-effects that someone might legitimately be relying on.
Spectre is not a vulnerability.
With polymorphism, adaptive learning continues to work; common learning is defeated.
When we first began investigating this problem of ROP attacks, chains, and memory-based attacks (attacks that rely on knowing the precise contents of programs, layouts and memory), we discussed all the options above, and more.
The reason we went with compile-time isomorphism is precisely to overcome all these limitations in the simplest manner possible.
This is what it looks like in practice:
The victim program is not obfuscated. It is an isomorphic equivalent of the original one. But look what happened — and the attacker had no idea! The attacker’s program is still based on the layout they spent time studying. Since our polymorphic program acts and works the same, the attacker has no idea their training is having no effect.
The CPU is still learning from both. It is correctly predicting branches better, giving both programs the performance wins promised. We haven’t stopped or avoided branch prediction. There is nothing wrong with it, it works great and it improves performance.
However, it is no longer learning from the attacker program, and applying those learnings to the victim program.
Polymorphism is a very simple idea, but very effective. This is why Polymorphing for Linux PROTECTS machines against Spectre, where other tools have failed. Learn more by reading our Technical Whitepaper.