qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] libvirt/QEMU/SEV interaction


From: Richard Relph
Subject: Re: [Qemu-devel] libvirt/QEMU/SEV interaction
Date: Wed, 27 Sep 2017 14:06:10 -0500
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.0) Gecko/20100101 Thunderbird/52.3.0

Forgive the top post... some of the conversation has been trimmed, but I need to go back to first principles of SEV in order to make sure we all have a clear understanding of what the goal is.

The goal - for BOTH guest owner and cloud provider - is to get to a VM where ONLY the guest owner (GO) has access to the GO "secrets". Legitimate cloud providers (ie, those that wish to not retain a back door in to their customer's VMs) want this every bit as much as GOs want it. It is this privacy concern that some believe holds back broader adoption of public cloud for sensitive applications.

To provide this additional privacy will require some changes to the "untrustable" model that seems to be in place now. There is value for everyone in creating a "trustable" model.

Given that, the root of the problem for the GO is trust. How can the GO know that every instruction in their VM is "theirs"? AMD Epyc CPUs decrypt every instruction fetch (and guest page table walk) in an SEV guest VM with that VM's random memory encryption key. (Data can either be encrypted or not, at the guest's choosing.) Only the SEV FW and the guest itself can encrypt memory with that key. The SEV FW measures every byte it encrypts for the guest and provides that measurement to the GO. The GO is free to ignore the value and run the guest "as-is". But recommended practice will be to inspect the measurement, verify it, and only then provide the guest VM with "secrets" necessary to decrypt disks, connect to privileged network resources, etc.

As has been observed, the BIOS has a great deal of power. It is impossible to maintain the GO's privacy in a VM where the BIOS (or any other code, for that matter) is "unknown". It simply is a violation of the trust model both the GO and the CP want to have to allow unknown code from the CP to enter the GO's VM. (Yes, there are LOTS of other ways for untrusted code to get in and secrets to get out... we're only trying to close this door between the CP and the guest VM at this time. ;-)

I anticipate that legitimate cloud providers will be happy (or at least willing) to share with customers the source for their BIOS. The GO can inspect the source, build the binary from that source, and generate the required hash. Or they may just trust that someone else has done that work and accept the hash the CP posts on their BIOS image. (Note that when the hash is returned by the SEV FW, it is in HMAC form, with a nonce that the GO can compute, and a key the GO provided at launch time.)

Whether the "BIOS" is a "static shim" as Michael suggests, or a full BIOS, or even a BIOS+kernel+initrd is really not too significant. What is significant is that the GO has a basis for trusting all code that is imported in to their VM by the CP. And that NONE of the code provided by the CP is "unknown" and unauditable by the GO. If the CP has a way to inject code unknown to the GO in to the guest VM, the trust model is broken and both GO and CP suffer the consequences.

When the CP needs to update the BIOS image, they will have to inform the GO and allow the GO to establish trust in the CP's new BIOS image somehow.

I hope that helps outline what we're doing, and why.

Richard


On 9/27/17 11:12 AM, Michael S. Tsirkin wrote:
On Wed, Sep 27, 2017 at 08:39:24AM -0500, Brijesh Singh wrote:
Hi Michael,


On 09/26/2017 09:36 AM, Michael S. Tsirkin wrote:

...

8. libvirt launches the guest with "-S"
9. While creating the SEV guest qemu does the following
   i) create encryption context using GO's DH, session-info and guest policy
      (LAUNCH_START)
   ii) encrypts the guest bios (LAUNCH_UPDATE_DATA)
   iii) calls LAUNCH_MEASUREMENT to get the encrypted bios measurement

This part troubles me. This seems to mean that the guest being launched
must know what the measurement of the bios is going to be.  This means
that the cloud provider can not update the bios without breaking guests.
Also, while in practice you typically can run an old bios image on a new
qemu instance, this is not really tested so would be very hard to
support properly in QEMU.




The guest itself does not need to know the measurement of the bios --
the SEV launch flow empowers the GO to validate the bootstrap code (bios)
before GO can provide a confidential information to the guest. Please note
that the validating of the measurement flow is optional. GO can ask cloud
provider to ignore the measurement all together and boot the SEV guest.

As the OS runs on top of the bios, it does not seem prudent to boot the
SEV guest without a way to verify that the bios is safe to use.
Linux generally trusts the firmware it runs on. Are you looking for
examples of how a malicious firmware can leak info out of the guest?

The measurement flow can be useful when GO decides to provide a custom
bios and want to know that his bios is used for booting the guest. In this
case, since the guest owner knows the initial contents of the guest at boot,
he can request the measurement from the cloud provider and compare it with
what the guest owner expects.

I agree the measurement works for this, but If that's the only case, I'd
say it's not all that interesting since most people will use a standard
bios.

I do think something needs to vaidate the bios though, and I do not
think naively measuring the hash of the full bios is a way to do this
that we can support well long term.



And this looks like a fundamental problem with the hash based
measurement that's in hardware. So below I suggest that we layer
some software on top to rely on the hash as little as possible.



10. By some interface we must propagate the measurement all the way to GO
    before libvirt starts the guest.
11. GO verifies the measurement and if measurement matches then it may
   give a secret blob -- which must be injected into the guest before
   libvirt starts the VM. If verification failed, GO will request cloud
   provider to destroy the VM.
12. After secret blob is injected into guest, we call LAUNCH_FINISH
    to destory the encryption context.
13. libvirt issues "continue" command to resume the guest boot.

Please note that the measurement value is protected with transport
encryption key (TIK) and it changes on each run. Similarly the secret blob
provided by GO does not need to be protected using libvirt/qemu APIs. The
secret is protected by TIK. From qemu and libvirt point of view these are
blobs and must be passed as-is to the SEV FW.

So here's an alternative idea for starting guests:

How about building a minimal shim firmware that
runs on a single CPU and uses no hardware at all,
it just contains the secret blob.

That firmware just immediately stops and signals
hypervisor that it is ready to be run in the cloud.

Have user generate and start this shim firmware as a guest in a private
setup, then export it out using SEND_* commands.

Then instead of asking to launch guest, you ask provider
to load it with RECEIVE_* commands.

Unlike bios the shim firmware
can hopefully be static so supporting it across qemu
versions should be easy.

The shim firmware then loads bios from qemu, verifies
it in any way it sees fit (e.g. it could check a signature, version, etc:
it is not limited to a hardware hash anymore).
It then jumps to the bios.


While not exactly the same, there is some similarity
here with how people solved the issues around secureboot -
by using a shim.





reply via email to

[Prev in Thread] Current Thread [Next in Thread]