Re: [PATCH 23/35] x86/speculation: Add basic speculation control code

From: Andy Lutomirski
Date: Thu Jan 18 2018 - 23:15:53 EST


On Thu, Jan 18, 2018 at 5:41 PM, Andrea Arcangeli <aarcange@xxxxxxxxxx> wrote:
> Hello,
>
> On Thu, Jan 18, 2018 at 03:25:25PM -0800, Andy Lutomirski wrote:
>> I read the whitepaper that documented the new MSRs a couple days ago
>> and I'm now completely unable to find it. If anyone could send the
>> link, that would be great.
>
> I see Andrew posted a link.
>
>> From memory, however, the docs were quite clear that setting leaving
>> IBRS set when entering user mode or guest mode does not guarantee any
>> particular protection unless an additional CPUID bit (the name of
>> which I forget) is set, and that current CPUs will *not* get that bit
>
> My current understanding is that with SPEC_CTRL alone set in cpuid,
> IBRS is meaningful, other bits don't matter.
>
>> set by microcode update. IOW the protection given is that, if you set
>> IBRS bit zero after entry to kernel mode, you are protected until you
>> re-enter user mode. When you're in user mode, you're not protected.
>
> If you leave IBRS set while in user mode, userland is protected as
> strong as kernel mode.

The link that Andrew posted says:

If software sets IA32_SPEC_CTRL.IBRS to 1 after a transition to a more
privileged predictor mode, predicted targets of indirect branches
executed in that predictor mode with IA32_SPEC_CTRL.IBRS = 1 cannot be
controlled by software that was executed in a less privileged
predictor mode or on another logical processor.

...

Enabling IBRS does not prevent software from controlling the predicted
targets of indirect branches of unrelated software executed later at
the same predictor mode (for example, between two different user
applications, or two different virtual machines). Such isolation can
be ensured through use of the IBPB command, described in Section
2.5.3, âIndirect Branch Predictor Barrier (IBPB)â.

So maybe it's poorly written, but I see nothing in that language that
suggests that IBRS=1 (on a CPU without enhanced IBRS) provides any
guarantees at all about who can or cannot control speculation of
indirect branches in user mode.

>
> When you return to kernel mode you've to call IBRS again even if it
> was left set, because there's a higher-privilege mode change. That's
> equivalent to calling only IBPB and leaving STIBP set (only way to
> understand the locations where IBRS has to be set is to imagine IBRS
> as a strict "STIBP; IBPB").

Then Intel should improve their spec to say so.

> IBRS Q/A:
>
> 1) When to write IBRS in SPEC_CTRL? -> imagine it as "STIBP; IBPB"
>
> 2) When to leave IBRS set or when to call IBPB -> imagine the previous
> setting of IBRS as temporarily disabling indirect branch prediction
> without an IBPB implicit in IBRS
>
> If you think it only like 1) you risk missing some places where you've
> to write IBRS even if it was already set.
>
> If you think it only like 2) you risk clearing it too early or you
> risk missing a necessary IBPB.
>
> It has to be thought simultaneously in both ways.

>From your description, it sounds like what's actually happening is:

When IBRS is enabled, indirect branch speculation targets cannot be
controlled by code that executed on a different logical processor on
by code that executed prior to the most recent time that IBRS was set
to 1. Additionally, if the CPU supports enhanced IBRS, then indirect
branch speculation targets cannot be controlled by code that executed
at a less privileged predictor mode.

Is that actually correct? If so, could Intel please *say* so?
Because writing voodoo magic security code seriously sucks.

>
> The sure thing I get from the specs is IBRS always implies STIBP (even
> when STIBP is a noop), specs are pretty explicit about that.

Ah, it says:

As noted in Section 2.5.1, âIndirect Branch Restricted Speculation
(IBRS)â, enabling IBRS prevents software operating on one logical
processor from controlling the predicted targets of indirect branches
executed on another logical processor. For that reason, it is not
necessary to enable STIBP when IBRS is enabled.

So I guess we can write 1 when we enter the kernel, but we probably
want to write 2 instead of 0 when we exit.