Christopher Celio wrote:
> Spectre is more complex, but it appears that both disclosed variants
> ("bounds check bypass" and "branch target injection") rely on two
> components to work: 1) a way for an attacker thread to force a victim
> thread to speculatively execute an existing "gadget", and 2) a covert
> channel to gain information from the gadget.
>
> In other words, Spectre relies on a malicious thread injecting
> information into a shared BTB/BPD structure. BOOM is currently
> susceptible to this, but a number of relatively simple, low-impact
> changes to the BTB/BPD structure (such as flushing or tagging) can
> guard against Spectre.
Project Zero also demonstrated (on Haswell) a closely-related attack
that used the BTB to leak the (partial) addresses of previously executed
instructions. This was used to defeat KASLR in a KVM hypervisor. This
did not work on the AMD or ARM processors tested, and I believe (based
on information in the old AMD K8 software optimization guide) that this
cannot work on AMD microarchitectures, because AMD stores the BTB in the
L1 I-cache. (The optimization guide states that only three branches in
a 16-byte fetch window can be predicted and recommends no more than one
per aligned 16-byte window.)
For RISC-V, we obviously do not care where an implementation stores its
BTB (or whether it even *has* a BTB), but we can require that branch
prediction never use information learned in one hardware "domain" in
another hardware "domain". The lack of this invariant on Intel's
Haswell made Project Zero's KVM hypervisor attacks possible.
> However, there is one form of Spectre that is confounding --- when the
> attacker thread and the victim thread are one and the same. In this
> scenario, there is no way to flush the BTB/BPD between the attacker
> setting up the misdirection and the victim speculatively executing it.
>
> I contend in this scenario that we have a software bug --- the
> software is attempting to enforce its own domain protections and not
> leveraging the existing protection mechanisms provided by the hardware
> (think of a sandboxed JIT that is running untrusted code with
> supervisor permissions). In this scenario, any act of speculative (not
> just speculative cache allocations) leaks information.
That is why I have suggested that this should be an issue for RVJ to
address -- JITs often include software sandboxes and the security of
those sandboxes is becoming increasingly important.
> So far, I have seen a few ideas that have been proposed:
> * allow SW to flush the BTB/BPD --- I'm not sure this will work as
> even a flushed BPD makes predictions, and a "not-taken" prediction is
> all that is required to force the leak.
On RISC-V, we have an answer to this: (user ISA spec, section 2.5
"Control Transfer Instructions" subheading "Conditional Branches")
"Software should be optimized such that the sequential code path is the
most common path, with less-frequently taken code paths placed out of
line. Software should also assume that backward branches will be
predicted taken and forward branches as not taken, at least the first
time they are encountered. Dynamic predictors should quickly learn any
predictable branch behavior."
A flushed dynamic branch predictor will make the ISA-required static
predictions, which for a bounds check will be that it will pass...
oops. So, we are back to closing the side channels that leak speculated
execution, then. :-)
> * allow SW to insert speculation fences --- I'm concerned this is only
> a temporary patch, as it only protects known gadgets from attacks.
Agreed.
> * force SW to move protected information to a protected hw domain ---
> I'm not sure how tenable this is, particularly in the short-term.
Short-term? Impossible. Long-term? I would like to see some kind of
U-mode intraprocess protection as part of RVJ, but I do not know what
form that should take.
-- Jacob