Re: [PATCH] x86: enable Data Operand Independent Timing Mode

From: Dave Hansen
Date: Thu Jan 26 2023 - 18:59:12 EST


On 1/26/23 14:37, Eric Biggers wrote:
> The end result is that on older CPUs, Intel explicitly guarantees that the
> instructions in
> https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/resources/data-operand-independent-timing-instructions.html
> have data operand independent timing. But on newer CPUs, Intel has explicitly
> removed that guarantee, and enabling DOITM is needed to get it back.

Yep.

> By the way, surely the importance of using DOITM on a particular CPU correlates
> strongly with its performance overhead? So I'm not sure that benchmarks of
> DOITM would even be very interesting, as we couldn't necessarily decide on
> something like "don't use DOITM if the overhead is more than X percent", since
> that would exclude exactly the CPUs where it's the most important to use...

We've looked at how bad the cure is compared to the disease for *every*
one of these issues. As far as I know, either the disease has always
gotten better over time or the cure gets cheaper (think IBRS/retpoline
-> EIBRS or RDCL_NO for Meltdown).

DOITM doesn't follow that pattern. It appears that it's fairly cheap
now, but Intel is reserving the right to make it worse over time. I
don't know how we can come up with a kernel policy which will be sane
going forward when things get worse over time.

> I think the real takeaway here is that the optimizations that Intel is
> apparently trying to introduce are a bad idea and not safe at all. To the
> extent that they exist at all, they should be an opt-in thing, not out-opt. The
> CPU gets that wrong, but Linux can flip that and do it right.

Let's try to break this down a _bit_.

The code most sensitive to the DOITM behavior is code written to be
resistant to timing side-channels today. DOITM=0 behavior is obviously
unsafe there. This code is, unfortunately, out in the wild and
completely unannotated and completely unaware of DOITM. The only way to
mitigate it is to set DOITM=1 whenever it _might_ be running, which is
when userspace runs. If the kernel can't be bothered to switch DOITM on
kernel entry/exit, then it's game over and DOITM=1 is the only choice.
For this code, it's arguable that even mitigations=off shouldn't set
DOITM=0.

The other extreme is code that's known to be vulnerable to timing
side-channels no matter the value of DOITM. KSM is an example here.
Setting DOITM=1 isn't going to make KSM's side channels go away.

Then, there's the middle ground. There is surely some code that does
not have timing side-channels with DOITM=0, but some appear with
DOITM=1. I _think_ my colleagues at Intel consider this code to be in
the same bucket as "known vulnerable". Basically, "if it's not designed
to be timing side-channel resistant then it surely is vulnerable to one,
regardless of DOITM."

That middle ground matters a *lot* because it's probably 99.9% of all
software, including essentially the whole kernel.

I think what I'm hearing from folks in this thread is that if going from
DOITM=1->0 _makes_ any code vulnerable in practice, then they view that
as a bug -- a real-world security bug. It doesn't matter whether the
code was designed to be side-channel resistant or not. A regression is
a regression.

I'm also hearing that the old (pre-Ice Lake), universal, DOITM=1
behavior is basically architecture because software depends on it. It
can't be changed except with an explicit software opt-in. Even if DOITM
were the right basic interface for this opt-in, the default polarity is
wrong for an opt-in.