RE: Linux guest kernel threat model for Confidential Computing

From: Reshetova, Elena
Date: Thu Feb 02 2023 - 06:32:42 EST



> On 2023-01-31 at 10:06 UTC, "Reshetova, Elena" <elena.reshetova@xxxxxxxxx>
> wrote...
> > Hi Dinechin,
>
> Nit: My first name is actually Christophe ;-)

I am sorry, my automation of extracting names from emails failed here ((

>
> [snip]
>
> >> "The implementation of the #VE handler is simple and does not require an
> >> in-depth security audit or fuzzing since it is not the actual consumer of
> >> the host/VMM supplied untrusted data": The assumption there seems to be
> that
> >> the host will never be able to supply data (e.g. through a bounce buffer)
> >> that it can trick the guest into executing. If that is indeed the
> >> assumption, it is worth mentioning explicitly. I suspect it is a bit weak,
> >> since many earlier attacks were based on executing the wrong code. Notably,
> >> it is worth pointing out that I/O buffers are _not_ encrypted with the CPU
> >> key (as opposed to any device key e.g. for PCI encryption) in either
> >> TDX or SEV. Is there for example anything that precludes TDX or SEV from
> >> executing code in the bounce buffers?
> >
> > This was already replied by Kirill, any code execution out of shared memory
> generates
> > a #GP.
>
> Apologies for my wording. Everyone interpreted "executing" as "executing
> directly on the bounce buffer page", when what I meant is "consuming data
> fetched from the bounce buffers as code" (not necessarily directly).

I guess in theory it is possible, but we have not seen such usages in guest kernel code
in practice during our audit. This would be pretty ugly thing to do imo even if
you forget about confidential computing.


>
> For example, in the diagram in your document, the guest kernel is a
> monolithic piece. In reality, there are dynamically loaded components. In
> the original SEV implementation, with pre-attestation, the measurement could
> only apply before loading any DLKM (I believe, not really sure). As another
> example, SEVerity (CVE-2020-12967 [1]) worked by injecting a payload
> directly into the guest kernel using virtio-based network I/O. That is what
> I referred to when I wrote "many earlier attacks were based on executing the
> wrong code".

The above attack was only possible because an attacker was able to directly
modify the code execution pointer to an arbitrary guest memory address
(in that case guest NMI handler was substituted pointing to attacker payload).
This is an obvious hole in the integrity protection of the guest private memory
and its page table mappings. This is not possible with TDX and I believe with
new versions of AMD SEV also.

>
> The fact that I/O buffers are not encrypted matters here, because it gives
> the host ample latitude to observe or even corrupt all I/Os, as many others
> have pointed out. Notably, disk crypto may not be designed to resist to a
> host that can see and possibly change the I/Os.
>
> So let me rephrase my vague question as a few more precise ones:
>
> 1) What are the effects of semi-random kernel code injection?
>
> If the host knows that a given bounce buffer happens to be used later to
> execute some kernel code, it can start flipping bits in it to try and
> trigger arbitrary code paths in the guest. My understanding is that
> crypto alone (i.e. without additional layers like dm-integrity) will
> happily decrypt that into a code stream with pseudo-random instructions
> in it, not vehemently error out.
>
> So, while TDX precludes the host from writing into guest memory directly,
> since the bounce buffers are shared, TDX will not prevent the host from
> flipping bits there. It's then just a matter of guessing where the bits
> will go, and hoping that some bits execute at guest PL0. Of course, this
> can be mitigated by either only using static configs, or using
> dm-verity/dm-integrity, or maybe some other mechanisms.
>
> Shouldn't that be part of your document? To be clear: you mention under
> "Storage protection" that you use dm-crypt and dm-integrity, so I believe
> *you* know, but your readers may not figure out why dm-integrity is
> integral to the process, notably after you write "Users could use other
> encryption schemes".

Sure, I can elaborate in the storage protection section about the importance
of disk integrity protection.

>
> 2) What are the effects of random user code injection?
>
> It's the same as above, except that now you can target a much wider range
> of input data, including shell scripts, etc. So the attack surface is
> much larger.
>
> 3) What is the effect of data poisoning?
>
> You don't necessarily need to corrupt code. Being able to corrupt a
> system configuration file for example can be largely sufficient.
>
> 4) Are there I/O-based replay attacks that would work pre-attestation?
>
> My current mental model is that you load a "base" software stack into the
> TCB and then measure a relevant part of it. What you measure is somewhat
> implementation-dependent, but in the end, if the system is attested, you
> respond to a cryptographic challenge based on what was measured, and you
> then get relevant secrets, e.g. a disk decryption key, that let you make
> forward progress. However, what happens if every time you boot, the host
> feeds you bogus disk data just to try to steer the boot sequence along
> some specific path?

What you ideally want is a full disk encryption with additional integrity protection,
like aes-gcm authenticated encryption mode. Then there are no questions on the
disk integrity and many attacks are mitigated.

>
> I believe that the short answer is: the guest either:
>
> a) reaches attestation, but with bad in-memory data, so it fails the
> crypto exchange, and secrets are not leaked.
>
> b) does not reach attestation, so never gets the secrets, and therefore
> still fulfils the CC promise of not leaking secrets.
>
> So I personally feel this is OK, but it's worth writing up in your doc.
>

Yes, I will expand the storage section more on this.

>
> Back to the #VE handler, if I can find a way to inject malicious code into
> my guest, what you wrote in that paragraph as a justification for no
> in-depth security still seems like "not exactly defense in depth". I would
> just remove the sentence, audit and fuzz that code with the same energy as
> for anything else that could face bad input.

In fact most of our fuzzing hooks are inside #VE itself if you take a look on the
implementation. They just don’t cover things like the #VE info decoding (information
is provided by a trusted party - TDX module).

Best Regards,
Elena.