Hi All,
(sorry for the long message)
CPUs from AMD EPYC family supports Secure Encrypted Virtualization (SEV)
feature - the feature allows running encrypted VMs. To enable the feature,
I have been submitting patches to Linux kernel [1], Qemu [2] and OVMF [3].
We have been making some good progress in getting patches accepted upstream
in Linux and OVMF trees. SEV builds upon SME (Secure Memory Encryption)
feature -- SME support just got pulled into 4.14 merge window. The base
SEV patches are accepted in OVMF tree -- now we have SEV aware guest BIOS.
I am getting ready to take off "RFC" tag from remaining patches to get them
reviewed and accepted.
The boot flow for launching an SEV guest is a bit different from a typical
guest launch. In order to launch SEV guest from virt-manager or other
high-level VM management tools, we need to design and implement new
interface between libvirt and qemu, and probably add new APIs in libvirt
to be used by VM management tools. I am new to the libvirt and need some
expert advice while designing this interface. A pictorial representation
for a SEV guest launch flow is available in SEV Spec Appendix A [4].
A typical flow looks like this:
1. Guest owner (GO) asks the cloud provider to launch SEV guest.
2. VM tool asks libvirt to provide its Platform Diffie-Hellman (PDH) key.
3. libvirt opens /dev/sev device to get its PDH and return the blob to the
caller.
4. VM tool gives its PDH to GO.
5. GO provides its DH key, session-info and guest policy.
6. VM tool somehow communicates the GO provided information to libvirt.
7. libvirt adds "sev-guest" object in its xml file with all the information
obtained from #5
(currently my xml file looks like this)
<qemu:arg value='-object'>
<qemu:arg
value='sev-guest,id=sev0,policy=<GO_policy>,dh-key-file=<filename>,session-file=<filename>/>
<qemu:arg value='-machine'/>
<qemu:arg value='memory-encryption=sev0'/>
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
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.
Questions:
a) Do we need to add a new set of APIs in libvirt to return the PDH from
libvirt and VM tool ? Or can we use some pre-existing APIs to pass the
opaque blobs ? (this is mainly for step 3 and 6)
b) do we need to define a new xml tag to for memory-encryption ? or just
use the qemu:args tag ? (step 6)
c) what existing communicate interface can be used between libvirt and qemu
to get the measurement ? can we add a new qemu monitor command
'get_sev_measurement' to get the measurement ? (step 10)
d) how to pass the secret blob from libvirt to qemu ? should we consider
adding a new object (sev-guest-secret) -- libvirt can add the object through
qemu monitor.
[1]
https://marc.info/?l=kvm&m=150092661105069&w=2
[2]
https://marc.info/?l=qemu-devel&m=148901186615642&w=2
[3]
https://lists.01.org/pipermail/edk2-devel/2017-July/012220.html
[4]
http://support.amd.com/TechDocs/55766_SEV-KM%20API_Specification.pdf
Thanks
Brijesh