Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On 10/18/17 8:35 PM, Michael S. Tsirkin wrote: On Wed, Oct 18, 2017 at 08:18:48PM +0100, Dr. David Alan Gilbert wrote: * Michael S. Tsirkin (m...@redhat.com) wrote: On Fri, Sep 08, 2017 at 10:48:10AM -0500, Brijesh Singh wrote: > 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. I realised I'm missing something here: how does GO limit the secret to the specific VM? For example, what prevents hypervisor from launching two VMs with the same GO's DH, getting measurement from 1st one but injecting the secret into the second one? Isn't that the 'trusted channel nonce currently associated with the guest' in the guest context? Dave Let me try to clarify the question. I understand that sometimes a key is shared between VMs. If this is allowed, it seems that a hypervisor can run any number of VMs with the same key. An unauthorised VM will not get a measurement that guest owner authorizes, but can the hypervisor get secret intended for an authorized VM and then inject it into an unauthorized one sharing the same key? Michael, Yes, that's possible. This is why we recommend against a guest owner authorizing key sharing. There's no way for the guest owner to control what other guests the HV might install using the same key and mapping the same memory to. So a security-conscious customer, especially in a cloud environment, should never enable key sharing. Richard Thanks, -- MST -- Dr. David Alan Gilbert / dgilb...@redhat.com / Manchester, UK -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Wed, Oct 18, 2017 at 08:18:48PM +0100, Dr. David Alan Gilbert wrote: > * Michael S. Tsirkin (m...@redhat.com) wrote: > > On Fri, Sep 08, 2017 at 10:48:10AM -0500, Brijesh Singh wrote: > > > > > > 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. > > > > I realised I'm missing something here: how does GO limit the > > secret to the specific VM? For example, what prevents hypervisor > > from launching two VMs with the same GO's DH, getting measurement > > from 1st one but injecting the secret into the second one? > > Isn't that the 'trusted channel nonce currently associated with the > guest' in the guest context? > > Dave Let me try to clarify the question. I understand that sometimes a key is shared between VMs. If this is allowed, it seems that a hypervisor can run any number of VMs with the same key. An unauthorised VM will not get a measurement that guest owner authorizes, but can the hypervisor get secret intended for an authorized VM and then inject it into an unauthorized one sharing the same key? > > Thanks, > > > > -- > > MST > > > -- > Dr. David Alan Gilbert / dgilb...@redhat.com / Manchester, UK -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
* Michael S. Tsirkin (m...@redhat.com) wrote: > On Fri, Sep 08, 2017 at 10:48:10AM -0500, Brijesh Singh wrote: > > > > > 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. > > I realised I'm missing something here: how does GO limit the > secret to the specific VM? For example, what prevents hypervisor > from launching two VMs with the same GO's DH, getting measurement > from 1st one but injecting the secret into the second one? Isn't that the 'trusted channel nonce currently associated with the guest' in the guest context? Dave > Thanks, > > -- > MST > -- Dr. David Alan Gilbert / dgilb...@redhat.com / Manchester, UK -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Fri, Sep 08, 2017 at 10:48:10AM -0500, Brijesh Singh wrote: > > > > 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. I realised I'm missing something here: how does GO limit the secret to the specific VM? For example, what prevents hypervisor from launching two VMs with the same GO's DH, getting measurement from 1st one but injecting the secret into the second one? Thanks, -- MST -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
Hi Laszlo, On 10/01/2017 04:56 AM, Laszlo Ersek wrote: On 10/01/17 11:17, Laszlo Ersek wrote: (3) Implement SEV encryption for pflash. A pflash chip can be in one of two modes: (a) it reads and executes as ROM, or (b) it behaves like a programmable (r/w) device with MMIO registers. Switching between both modes is explicit (see "OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c"); perhaps some SEV controls could be hooked in there. Hmmm wait a second, we *already* execute code from pflash (namely SEC code from OVMF_CODE.fd), and instruction fetch always entails decryption. Furthermore, in SEC, we decompress PEI and DXE FVs from pflash (OVMF_CODE.fd) to RAM -- the decompression code runs in long mode, plus you modified the OVMF/X64 reset vector to set the C-bit in all PTEs, covering the low 4GB of guest RAM. This tells me that at least read and execute from pflash work with SEV decryption already. Is this expected? Yes, this is expected. During the machine_init, qemu creates two pflash units. The pflash unit#0 contains OVMF_CODE.fd and unit #1 points to OVMF_VARS.fd. As part of machine creation, we encrypt the unit#0 using KVM_SEV_LAUNCH_UPDATE command. The unit#0 is mapped at the x86 reset vector. On vm_start, guest fetches the code from the unit#0. Since the code was already encrypted hence guest was able to read and execute the initial bootstrap code just fine. When OVMF is build with OvmfPkgX64.dsc, SetCr3ForPageTables64 builds the initial page table. When SEV is active, we add the C-bit pte mask [1] -- it will ensures that when decompression happen then data get written as encrypted in the guest RAM. [1] https://github.com/tianocore/edk2/commit/e60af8a1ebb15bfcbf2ecc4afb6cf35084c847aa When OVMF is build with OvmfPkgIa32X64.dsc, the SEC phase runs in 32-bit mode hence SEV hardware forces the C-bit to 1. This will ensure that decompression routines writes the data as encrypted. However, in PlatformPei, we don't report the varstore pflash range via any resource descriptor HOB (the varstore chip is at [0xffc0, 0xFFC84000) in the 4MB build). Consequently, AmdSevDxe clears the C-bit under the "NonExistent" branch: AmdSevDxe:SetMemoryEncDec: Cr3Base=0x0 Physical=0xFEF0 Length=0x110 Mode=Decrypt CacheFlush=0 Subsequently, "OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c" adds the pflash range as EFI_MEMORY_UC | EFI_MEMORY_RUNTIME. The C-bit remains clear, AIUI. OK, I'm totally confused now. Looks like SEV decryption already works for pflash (from SEC's example), and transparently at that (???), but we fail to use it in QemuFlashFvbServicesRuntimeDxe? AmdSevDxe clears the C-bit of pflash range in PlatformPei because QemuFlashFvbServicesRuntimeDxe switches the pflash out from ROMD mode; i.e it become MMIO. The MMIO regions must be mapped as unencrypted. SEV hardware engine uses a random encryption key on each run. Since OVMF_VAR.fd is used for storing the UEFI persistent variable hence we will not be able to store the data encrypted using the SEV engine. Any persistent storage should be protected using a disk encryption technologies (like luks, dm-crypt etc). Regarding optionROM comments, I will propose something on edk-devel list. I am thinking at least we should start by adding some kind of bug_on or warning when a SEV guest BIOS is attempting to copy the option ROM. I am hoping that once we have secure boot working then we should be able to handle the signed option ROM, grub.efi or kernel.efi etc. -Brijesh -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Sat, Sep 30, 2017 at 12:16:55AM +0300, Michael S. Tsirkin wrote: > On Fri, Sep 29, 2017 at 02:48:45PM -0500, Richard Relph wrote: > > On 9/29/17 2:34 PM, Michael S. Tsirkin wrote: > > > On Wed, Sep 27, 2017 at 02:06:10PM -0500, Richard Relph wrote: > > > > 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. > > > > > > Absolutely. > > > > > > > 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. > > > > > > This GO update on every BIOS change is imho is not a workable model. You > > > want something like checking the BIOS signature instead. And since > > > hardware is all hash based, you need the shim to do it in software. > > > > A BIOS "signed" by the CP doesn't meet the security requirement. It is code > > that is "unknown" to the GO. > > There is a misunderstanding here. > > BIOS would not be signed by a CP. It would be signed by a trusted > software vendor e.g. by Red Hat. > > > The (legitimate) CP does NOT want to be in that position of trust. If they > > are, then some government somewhere is going to insist that they sign a BIOS > > that allows the government to spy on the GO's VMs, and steal secrets from > > it. Or some hacker admin will do it "for fun". > > > > How often do large public CPs really change their BIOSes? My sense is that > > large public CPs prefer stability over "latest and greatest". > > CPs just do dnf update. Software vendors change BIOSes. No they really don't do that. Cloud providers will stick on a golden image of RHEL. If and when they need to do an upgrade, they won't usually do a 'dnf update' because that imposes risk of breaking VMs on that node with no fallback path. Instead they would usually deploy brand new nodes with the new software version, and then live migrate VMs off the old hosts. > And we do change them. Look at number of revisions for seabios in e.g. > Fedora. More importantly we might need to change them quickly e.g. > because of a security issue. Adding the need to coordinate with all GOs > is not going to work. Neither can QEMU support booting old BIOS > versions on new machine types indefinitely. I don't think Fedora is a good fit for SEV - a long term supported distro like RHEL is the more apt target, and there you are looking at 6 months lifetime, except in rare cases of having a BIOS security flaw to pyush out. > > > And, perhaps more importantly, if a CP are able to sell a "more secure" VM, > > one that justifies a higher price per vCPU hour, wouldn't that warrant some > > changes in the "insecure" model being used today? > > > > Richard > > Absolutely. CPs have no business signing images. But it is just not > really feasible for software vendors to distribute hashes. Why can't software vendors distribute hashes - they are best placed to, particularly when a single vendor is supplying the whole stack of base OS, virt and OpenStack as a single coordinated product. Regards, Daniel -- |: https://berrange.com -o-https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o-https://fstop138.berrange.com :| |: https://entangle-photo.org-o-https://www.instagram.com/dberrange :| -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Fri, Sep 29, 2017 at 02:48:45PM -0500, Richard Relph wrote: > On 9/29/17 2:34 PM, Michael S. Tsirkin wrote: > > On Wed, Sep 27, 2017 at 02:06:10PM -0500, Richard Relph wrote: > > > 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. > > > > Absolutely. > > > > > 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. > > > > This GO update on every BIOS change is imho is not a workable model. You > > want something like checking the BIOS signature instead. And since > > hardware is all hash based, you need the shim to do it in software. > > A BIOS "signed" by the CP doesn't meet the security requirement. It is code > that is "unknown" to the GO. > > The (legitimate) CP does NOT want to be in that position of trust. If they > are, then some government somewhere is going to insist that they sign a BIOS > that allows the government to spy on the GO's VMs, and steal secrets from > it. Or some hacker admin will do it "for fun". > > How often do large public CPs really change their BIOSes? My sense is that > large public CPs prefer stability over "latest and greatest". It is hard to generalize, but from a RHEL POV, we typically do major updates of the virt stack every ~6 months, and these will include BIOS updates. So if a cloud vendor is following the RHEL update stream actively that's the kind of cadence you'd expect. The gotcha would come if there were out-of-band security updates for BIOS which caused it to be updated before the 6 month window. Fortunately I've not see these happen often, so I don't think its a fatal problem. IOW, I tend to agree with you that this is not really a blocking problem to the use of SEV in cloud. > And, perhaps more importantly, if a CP are able to sell a "more secure" VM, > one that justifies a higher price per vCPU hour, wouldn't that warrant some > changes in the "insecure" model being used today? Yes. Regards, Daniel -- |: https://berrange.com -o-https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o-https://fstop138.berrange.com :| |: https://entangle-photo.org-o-https://www.instagram.com/dberrange :| -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On 10/01/17 11:17, Laszlo Ersek wrote: > (3) Implement SEV encryption for pflash. A pflash chip can be in one of > two modes: (a) it reads and executes as ROM, or (b) it behaves like a > programmable (r/w) device with MMIO registers. Switching between both > modes is explicit (see > "OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c"); perhaps some SEV > controls could be hooked in there. Hmmm wait a second, we *already* execute code from pflash (namely SEC code from OVMF_CODE.fd), and instruction fetch always entails decryption. Furthermore, in SEC, we decompress PEI and DXE FVs from pflash (OVMF_CODE.fd) to RAM -- the decompression code runs in long mode, plus you modified the OVMF/X64 reset vector to set the C-bit in all PTEs, covering the low 4GB of guest RAM. This tells me that at least read and execute from pflash work with SEV decryption already. Is this expected? However, in PlatformPei, we don't report the varstore pflash range via any resource descriptor HOB (the varstore chip is at [0xffc0, 0xFFC84000) in the 4MB build). Consequently, AmdSevDxe clears the C-bit under the "NonExistent" branch: AmdSevDxe:SetMemoryEncDec: Cr3Base=0x0 Physical=0xFEF0 Length=0x110 Mode=Decrypt CacheFlush=0 Subsequently, "OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c" adds the pflash range as EFI_MEMORY_UC | EFI_MEMORY_RUNTIME. The C-bit remains clear, AIUI. OK, I'm totally confused now. Looks like SEV decryption already works for pflash (from SEC's example), and transparently at that (???), but we fail to use it in QemuFlashFvbServicesRuntimeDxe? Laszlo -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On 10/01/17 02:09, Brijesh Singh wrote: > > > On 9/29/17 4:58 PM, Laszlo Ersek wrote: > ... >> The expansion ROMs (containing UEFI drivers) of emulated PCI devices, >> and the same of assigned physical PCI devices, constitute another >> channel through which code enters the guest from the outside (i.e., from >> the Cloud Provider). The ROM BARs from which the guest firmware reads >> the UEFI binaries are not guest RAM, they are MMIO. (For execution, the >> drivers are copied into encrypted guest RAM.) >> >> If the guest has Secure Boot enabled, then the oproms are verified[*] >> (and not launched if verification fails), but this is slightly different >> from what I understand under audit-by-GO. It means the GO wouldn't get a >> measurement of the oproms for one-by-one clearing, when about to >> green-light a guest startup. Instead the GO would ensure that Secure >> Boot be enabled with the right certificates (and/or executable hashes) >> enrolled off the bat, and then implicitly trust all oprom drivers >> accepted by those certs / hashes. It's another layer of indirection. >> >> This is likely nothing new qualitatively, but "the devil is in the >> details", so I thought it was worth raising. >> >> [*] For edk2 / OvmfPkg specifics, I'll mention >> >> gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy >> >> The SecurityPkg default is 0x04 ("Deny execution when there is security >> violation"). However, OVMF sets it to 0x00 ("Always trust the image"). >> Please see the following commit for the reasons: >> >> https://github.com/tianocore/edk2/commit/1fea9ddb4e3fd >> >> Brijesh, for SEV guests, we likely want to flip this PCD to 0x04, in the >> AmdSevInitialize() function, in "OvmfPkg/PlatformPei/AmdSev.c". For that >> we'll also have to change the PCD from fixed-at-build to dynamic, but >> that in turn will require a change to "SecurityPkg.dec" itself >> (currently it only allows fixed-at-build or patchable, not dynamic). Do >> you want me to file a BZ in the TianoCore tracker for this, and assign >> it to you? If you don't have time for writing the patch, I'm glad to do >> it too, but then the review could be slower; both other OvmfPkg >> co-maintainers are busy with other things.) > > Very good point Laszlo. Please submit the BZ and assign it me - thank > you. we will take a look at implementing the required support. I've filed: https://bugzilla.tianocore.org/show_bug.cgi?id=728 Another thought: once we delegate part of the protection that SEV provides to the Secure Boot implementation in the guest, the pflash chip that stores the UEFI variables (i.e., certificates for SB as well) becomes a target of attacks not just from within the guest, but also from the host. This is a big problem because the pflash chip is MMIO, nor RAM. So it is not encrypted, and the Cloud Provider can tamper with it at will -- even if the variable store file that backs the pflash chip (with the certificates pre-enrolled) comes from the Guest Owner initially, and/or passes the GO's measurement check. Put differently, even if we set PcdOptionRomImageVerificationPolicy to 0x04, it doesn't help if the CP can poke any UEFI executable hash or self-signed certificate into the varstore, which in turn will "verify" the CP's malicious oprom driver. The varstore pflash chip has never been considered to be under attack from the *host* side; all the guest-SMM work was focused on protecting pflash (and guest firmware in general) from the *guest* OS (and 3rd party *guest* UEFI apps). Theoretically, I see three ways to mitigate this: (1) Eliminate pflash from OVMF altogether. This would be a huge project, affecting OVMF, QEMU and libvirt. It would also throw the current in-guest protections provided by SB out the window. (2) Keep pflash as-is, but do not off-load any SEV protections to guest-side Secure Boot. This means that the guest firmware must be comprehensively restricted to load binaries only from media that the GO measured and the CP cannot tamper with. No option ROMs, no PXE boot, no plaintext ISOs, no plaintext hard disk images. (And booting from encrypted ISOs / hard disk images would require a LUKS driver for OVMF.) (3) Implement SEV encryption for pflash. A pflash chip can be in one of two modes: (a) it reads and executes as ROM, or (b) it behaves like a programmable (r/w) device with MMIO registers. Switching between both modes is explicit (see "OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c"); perhaps some SEV controls could be hooked in there. Thanks Laszlo -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Fri, Sep 29, 2017 at 03:07:40PM -0500, Richard Relph wrote: > Depending on your level of paranoia, > that may require advance notice of BIOS changes, or even allowing the GO to > provide the BIOS themselves, written to a spec supported by the CP's HV, > and/or based on BIOS code provided by the CP. BTW this last most secure option is easy to implement with the shim because the shim is using very little in terms of the HV interface. User can then easily build it from source. -- MST -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Fri, Sep 29, 2017 at 03:07:40PM -0500, Richard Relph wrote: > It's a business decision and I think SEV can support both. I think what has been missed in the noise is the fact that with VM launch, key distribution is a huge problem. With the shim the key distribution problem can go completely away, as you just start it in the private cloud and include the key with the shim, then use the send/recv machinery to migrate to the public one. -- MST -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On 9/29/17 4:58 PM, Laszlo Ersek wrote: ... > The expansion ROMs (containing UEFI drivers) of emulated PCI devices, > and the same of assigned physical PCI devices, constitute another > channel through which code enters the guest from the outside (i.e., from > the Cloud Provider). The ROM BARs from which the guest firmware reads > the UEFI binaries are not guest RAM, they are MMIO. (For execution, the > drivers are copied into encrypted guest RAM.) > > If the guest has Secure Boot enabled, then the oproms are verified[*] > (and not launched if verification fails), but this is slightly different > from what I understand under audit-by-GO. It means the GO wouldn't get a > measurement of the oproms for one-by-one clearing, when about to > green-light a guest startup. Instead the GO would ensure that Secure > Boot be enabled with the right certificates (and/or executable hashes) > enrolled off the bat, and then implicitly trust all oprom drivers > accepted by those certs / hashes. It's another layer of indirection. > > This is likely nothing new qualitatively, but "the devil is in the > details", so I thought it was worth raising. > > [*] For edk2 / OvmfPkg specifics, I'll mention > > gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy > > The SecurityPkg default is 0x04 ("Deny execution when there is security > violation"). However, OVMF sets it to 0x00 ("Always trust the image"). > Please see the following commit for the reasons: > > https://github.com/tianocore/edk2/commit/1fea9ddb4e3fd > > Brijesh, for SEV guests, we likely want to flip this PCD to 0x04, in the > AmdSevInitialize() function, in "OvmfPkg/PlatformPei/AmdSev.c". For that > we'll also have to change the PCD from fixed-at-build to dynamic, but > that in turn will require a change to "SecurityPkg.dec" itself > (currently it only allows fixed-at-build or patchable, not dynamic). Do > you want me to file a BZ in the TianoCore tracker for this, and assign > it to you? If you don't have time for writing the patch, I'm glad to do > it too, but then the review could be slower; both other OvmfPkg > co-maintainers are busy with other things.) Very good point Laszlo. Please submit the BZ and assign it me - thank you. we will take a look at implementing the required support. -Brijesh -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On 09/29/17 23:16, Michael S. Tsirkin wrote: > On Fri, Sep 29, 2017 at 02:48:45PM -0500, Richard Relph wrote: >> On 9/29/17 2:34 PM, Michael S. Tsirkin wrote: >>> On Wed, Sep 27, 2017 at 02:06:10PM -0500, Richard Relph wrote: 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. >>> >>> Absolutely. >>> 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. >>> >>> This GO update on every BIOS change is imho is not a workable model. You >>> want something like checking the BIOS signature instead. And since >>> hardware is all hash based, you need the shim to do it in software. >> >> A BIOS "signed" by the CP doesn't meet the security requirement. It is code >> that is "unknown" to the GO. > > There is a misunderstanding here. > > BIOS would not be signed by a CP. It would be signed by a trusted > software vendor e.g. by Red Hat. > >> The (legitimate) CP does NOT want to be in that position of trust. If they >> are, then some government somewhere is going to insist that they sign a BIOS >> that allows the government to spy on the GO's VMs, and steal secrets from >> it. Or some hacker admin will do it "for fun". >> >> How often do large public CPs really change their BIOSes? My sense is that >> large public CPs prefer stability over "latest and greatest". > > CPs just do dnf update. Software vendors change BIOSes. > > And we do change them. Look at number of revisions for seabios in e.g. > Fedora. More importantly we might need to change them quickly e.g. > because of a security issue. Adding the need to coordinate with all GOs > is not going to work. Neither can QEMU support booting old BIOS > versions on new machine types indefinitely. > >> And, perhaps more importantly, if a CP are able to sell a "more secure" VM, >> one that justifies a higher price per vCPU hour, wouldn't that warrant some >> changes in the "insecure" model being used today? >> >> Richard > > Absolutely. CPs have no business signing images. But it is just not > really feasible for software vendors to distribute hashes. Can this be helped by "reproducible builds"? Like, - guest firmware vendor publishes the source package, - GO asynchronously audits the source package (most likely incrementally, reviewing the new, broken-out patches in the source package), - GO builds the binary package, - GO verifies that it bit-wise matches the guest fw vendor's binary package, - GO adds the fw binary's hash to their own whitelist. By virtue of releasing the source package of the guest firmware (and by announcing it via another erratum), the guest fw vendor implicitly notifies all GOs. It is then up to the individual GOs to evaluate the changes on their own time, and to switch to the new fw binary. It would even be OK if the GO built their own fw binary from the source package, and submitted that to the CP, as part of the guest payload. The guest firmware vendor would still be able to support this build, since it would match the vendor's own binary 100%. Thanks Laszlo -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
Side topic; sorry if it has been mentioned elsewhere: On 09/27/17 21:06, Richard Relph wrote: > 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. The expansion ROMs (containing UEFI drivers) of emulated PCI devices, and the same of assigned physical PCI devices, constitute another channel through which code enters the guest from the outside (i.e., from the Cloud Provider). The ROM BARs from which the guest firmware reads the UEFI binaries are not guest RAM, they are MMIO. (For execution, the drivers are copied into encrypted guest RAM.) If the guest has Secure Boot enabled, then the oproms are verified[*] (and not launched if verification fails), but this is slightly different from what I understand under audit-by-GO. It means the GO wouldn't get a measurement of the oproms for one-by-one clearing, when about to green-light a guest startup. Instead the GO would ensure that Secure Boot be enabled with the right certificates (and/or executable hashes) enrolled off the bat, and then implicitly trust all oprom drivers accepted by those certs / hashes. It's another layer of indirection. This is likely nothing new qualitatively, but "the devil is in the details", so I thought it was worth raising. [*] For edk2 / OvmfPkg specifics, I'll mention gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy The SecurityPkg default is 0x04 ("Deny execution when there is security violation"). However, OVMF sets it to 0x00 ("Always trust the image"). Please see the following commit for the reasons: https://github.com/tianocore/edk2/commit/1fea9ddb4e3fd Brijesh, for SEV guests, we likely want to flip this PCD to 0x04, in the AmdSevInitialize() function, in "OvmfPkg/PlatformPei/AmdSev.c". For that we'll also have to change the PCD from fixed-at-build to dynamic, but that in turn will require a change to "SecurityPkg.dec" itself (currently it only allows fixed-at-build or patchable, not dynamic). Do you want me to file a BZ in the TianoCore tracker for this, and assign it to you? If you don't have time for writing the patch, I'm glad to do it too, but then the review could be slower; both other OvmfPkg co-maintainers are busy with other things.) Thanks! Laszlo -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Fri, Sep 29, 2017 at 02:48:45PM -0500, Richard Relph wrote: > On 9/29/17 2:34 PM, Michael S. Tsirkin wrote: > > On Wed, Sep 27, 2017 at 02:06:10PM -0500, Richard Relph wrote: > > > 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. > > > > Absolutely. > > > > > 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. > > > > This GO update on every BIOS change is imho is not a workable model. You > > want something like checking the BIOS signature instead. And since > > hardware is all hash based, you need the shim to do it in software. > > A BIOS "signed" by the CP doesn't meet the security requirement. It is code > that is "unknown" to the GO. There is a misunderstanding here. BIOS would not be signed by a CP. It would be signed by a trusted software vendor e.g. by Red Hat. > The (legitimate) CP does NOT want to be in that position of trust. If they > are, then some government somewhere is going to insist that they sign a BIOS > that allows the government to spy on the GO's VMs, and steal secrets from > it. Or some hacker admin will do it "for fun". > > How often do large public CPs really change their BIOSes? My sense is that > large public CPs prefer stability over "latest and greatest". CPs just do dnf update. Software vendors change BIOSes. And we do change them. Look at number of revisions for seabios in e.g. Fedora. More importantly we might need to change them quickly e.g. because of a security issue. Adding the need to coordinate with all GOs is not going to work. Neither can QEMU support booting old BIOS versions on new machine types indefinitely. > And, perhaps more importantly, if a CP are able to sell a "more secure" VM, > one that justifies a higher price per vCPU hour, wouldn't that warrant some > changes in the "insecure" model being used today? > > Richard Absolutely. CPs have no business signing images. But it is just not really feasible for software vendors to distribute hashes. -- MST -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Fri, Sep 29, 2017 at 03:07:40PM -0500, Richard Relph wrote: > On 9/29/17 2:48 PM, Richard Relph wrote: > > On 9/29/17 2:34 PM, Michael S. Tsirkin wrote: > > > On Wed, Sep 27, 2017 at 02:06:10PM -0500, Richard Relph wrote: > > > > 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. > > > > > > Absolutely. > > > > > > > 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. > > > > > > This GO update on every BIOS change is imho is not a workable model. You > > > want something like checking the BIOS signature instead. And since > > > hardware is all hash based, you need the shim to do it in software. > > > > A BIOS "signed" by the CP doesn't meet the security requirement. It is > > code that is "unknown" to the GO. > > > > The (legitimate) CP does NOT want to be in that position of trust. If > > they are, then some government somewhere is going to insist that they > > sign a BIOS that allows the government to spy on the GO's VMs, and steal > > secrets from it. Or some hacker admin will do it "for fun". > > > > How often do large public CPs really change their BIOSes? My sense is > > that large public CPs prefer stability over "latest and greatest". > > > > And, perhaps more importantly, if a CP are able to sell a "more secure" > > VM, one that justifies a higher price per vCPU hour, wouldn't that > > warrant some changes in the "insecure" model being used today? > > Ultimately, I think both approaches are "doable". It will be a CP and GO > decision. If the GO trusts the CP, the shim+signed BIOS will work fine. I think there's a misunderstanding. A trusted software vendor would sign the BIOS. GO would verify it. Trusting the CP is not required. > If > GO requires a more secure VM and the CP wants to offer it, the CP will > figure out a way to satisfy the GO's "trust issue" that the BIOS can't be > used to circumvent SEV's protections. Depending on your level of paranoia, > that may require advance notice of BIOS changes, or even allowing the GO to > provide the BIOS themselves, written to a spec supported by the CP's HV, > and/or based on BIOS code provided by the CP. We are discussing this on a qemu mailing list, aren't we? And from QEMU point of view, I think it won't be able to support a requirement to boot ancient bios versions on new machine types indefinitely with good performance and also fix security issues in them in a timely manner somehow. > > It's a business decision and I think SEV can support both. That said, AMD > currently has no plans to write a shim that can verify the signature on a > CP-provided BIOS image. > > Richard Someone else will have to work on a supportable solution for QEMU then. > > > > Richard -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On 9/29/17 2:34 PM, Michael S. Tsirkin wrote: On Wed, Sep 27, 2017 at 02:06:10PM -0500, Richard Relph wrote: 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. Absolutely. 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. This GO update on every BIOS change is imho is not a workable model. You want something like checking the BIOS signature instead. And since hardware is all hash based, you need the shim to do it in software. A BIOS "signed" by the CP doesn't meet the security requirement. It is code that is "unknown" to the GO. The (legitimate) CP does NOT want to be in that position of trust. If they are, then some government somewhere is going to insist that they sign a BIOS that allows the government to spy on the GO's VMs, and steal secrets from it. Or some hacker admin will do it "for fun". How often do large public CPs really change their BIOSes? My sense is that large public CPs prefer stability over "latest and greatest". And, perhaps more importantly, if a CP are able to sell a "more secure" VM, one that justifies a higher price per vCPU hour, wouldn't that warrant some changes in the "insecure" model being used today? Richard -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On 9/29/17 2:48 PM, Richard Relph wrote: On 9/29/17 2:34 PM, Michael S. Tsirkin wrote: On Wed, Sep 27, 2017 at 02:06:10PM -0500, Richard Relph wrote: 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. Absolutely. 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. This GO update on every BIOS change is imho is not a workable model. You want something like checking the BIOS signature instead. And since hardware is all hash based, you need the shim to do it in software. A BIOS "signed" by the CP doesn't meet the security requirement. It is code that is "unknown" to the GO. The (legitimate) CP does NOT want to be in that position of trust. If they are, then some government somewhere is going to insist that they sign a BIOS that allows the government to spy on the GO's VMs, and steal secrets from it. Or some hacker admin will do it "for fun". How often do large public CPs really change their BIOSes? My sense is that large public CPs prefer stability over "latest and greatest". And, perhaps more importantly, if a CP are able to sell a "more secure" VM, one that justifies a higher price per vCPU hour, wouldn't that warrant some changes in the "insecure" model being used today? Ultimately, I think both approaches are "doable". It will be a CP and GO decision. If the GO trusts the CP, the shim+signed BIOS will work fine. If GO requires a more secure VM and the CP wants to offer it, the CP will figure out a way to satisfy the GO's "trust issue" that the BIOS can't be used to circumvent SEV's protections. Depending on your level of paranoia, that may require advance notice of BIOS changes, or even allowing the GO to provide the BIOS themselves, written to a spec supported by the CP's HV, and/or based on BIOS code provided by the CP. It's a business decision and I think SEV can support both. That said, AMD currently has no plans to write a shim that can verify the signature on a CP-provided BIOS image. Richard Richard -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Wed, Sep 27, 2017 at 02:06:10PM -0500, Richard Relph wrote: > 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. Absolutely. > 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. This GO update on every BIOS change is imho is not a workable model. You want something like checking the BIOS signature instead. And since hardware is all hash based, you need the shim to do it in software. -- MST -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
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 a
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
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. > > -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
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. 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. 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. -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
* Michael S. Tsirkin (m...@redhat.com) wrote: > On Fri, Sep 08, 2017 at 06:57:30AM -0500, Brijesh Singh wrote: > > Hi All, > > Sorry if below comment doesn't make sense, I might be misunderstanding > something basic about SEV. Also sorry about the delay, I've been on > vacation. > > > > (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) > > > > > > > value='sev-guest,id=sev0,policy=,dh-key-file=,session-file=/> > > > > > > > > 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. > > > 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. I think the normal way to solve this is that the Distro would provide a list of the signatures, and the GO would check the bios measurement against that list. The GO needs to keep that list up to date; either directly downloading it from the Distro or a copy signed by the Distro. Dave > > > 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 > v
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Fri, Sep 08, 2017 at 06:57:30AM -0500, Brijesh Singh wrote: > Hi All, Sorry if below comment doesn't make sense, I might be misunderstanding something basic about SEV. Also sorry about the delay, I've been on vacation. > (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) > > > value='sev-guest,id=sev0,policy=,dh-key-file=,session-file=/> > > > > 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. 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. Thanks! > 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 > opaq
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Mon, Sep 18, 2017 at 07:41:09AM -0500, Richard Relph wrote: > > > On 9/18/17 4:47 AM, Daniel P. Berrange wrote: > > On Mon, Sep 18, 2017 at 11:43:57AM +0200, Erik Skultety wrote: > > > [...] > > > > > > > > > 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) > > > > > > > > > > Yes, QMP commands seeem most likely. > > > > > > > > > > > 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. > > > > > > > > > > Yeah, that looks like a viable option too. > > > > So I could see a flow like the following: > > > > > > > > > > > >1. mgmt tool calls virConnectGetCapabilities. This returns an XML > > > > document that includes the following > > > > > > > > > > > > ...other bits... > > > > > > > > ...hex encoded PDH key... > > > > > > > > > > > > > > > >2. mgmt tool requests to start a guest calling virCreateXML(), > > > > passing VIR_DOMAIN_START_PAUSED. The XML would include > > > > > > > > > > > > ...hex encode DH key... > > > > ..hex encode info... > > > > ...int32 value.. > > > > > > > > > > > > > > > > if is provided and VIR_DOMAIN_START_PAUSED is missing, > > > > libvirt would report an error and refuse to start the guest > For ease of use, I would not add this conditional to libvirt. If is > provided and VIR_DOMAIN_START_PAUSED is missing, I’d just send the "GO" I also feel that the presence of the element might determine the usage of the VIR_DOMAIN_START_PAUSED flag implicitly. > command as it would naturally occur. > Unless that would confuse things inside libvirt or QEMU in relation to the > measurement and secret… > Many of our existing tests focus on other aspects of SEV functionality and > so they skip the MEASURE/SECRET phase of launch and just go immediately from > LAUNCH_UPDATE_DATA (or VMSA) to LAUNCH_FINISH. > I guess the key question will be how will QEMU know when to get the > MEASUREMENT and wait for a LAUNCH_SECRET before doing a LAUNCH_FINISH when > connected to libvirt. > Brijesh, this is your area. It feels to me like QEMU will have to wait to do > the LAUNCH_FINISH until it gets the first “go” from libvirt. If that’s > right, and assuming the same “go” comes from libvirt with or without > VIR_DOMAIN_START_PAUSED, then I’d simply exclude the conditional check. QEMU > would get the measurement when it is done sending the data. > Though in “real world” uses, I think the conditional is perfectly OK. > > > > > > > >3. Libvirt generates the QEMU cli arg to enable SEV using > > > > the XML data and starts QEMU, leaving CPUs paused > > > > > > > >4. QEMU emits a SEV_MEASURE event containing the measurement > > > > blob > > > Speaking of which, I expect QEMU to have a QMP command to retrieve the > > > measurement, in which case I think libvirt has to provide an API for the > > > user > > > to retrieve the measurement in case libvirtd crashes somewhere between > > > setting > > > up QEMU and waiting for the measurement event from QEMU, or simply > > > because the > > > GO missed the event for some unspecified reason. > > Yeah, that's a good point - we also ought to have a pause-reason that > > reflects that it is paused due to waiting for SEV secrets. > > > > > >5. Libvirt catches the QEMU event and emits its own > > > > VIR_CONNECT_DOMAIN_EVENT_SEV_MEASURE event containing > > > > the measurement blob > > > > > > > >6. GO does its validation of the measurement > > > > > > > >7a If validation failed, then virDomainDestroy() to stop QEMU > > > > > > > >7b If validation succeeed > > > > > > > > Optionally call > > > > > > > > virDomainSetSEVSecret() > > > Given the fact that we're likely introducing a new element to the > > > XML > > > config, I'm more inclined to utilizing the existing virSecret interfaces > > > (as > > > was originally suggested) instead of creating a vendor-specific API. You > > > could > > > have an optional secret sub-element within the element and libvirt > > > would > > > simply check if that secret has a value set, once the GO issues > > > virDomainResume(). Any particular reason for having a specific API for > > > this that > > > I'm missing? > > Initially I was intending to suggest extensive use of virSecret, but it > > turns out that despite being called a "secret", none of the SEV data we are > > passing around needs protection. Either it is safe to be public, or it is > > already encrypted. So essentially we just have some data blobs we need to > > pass into QEMU. I didn't feel we ought to be
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On 9/18/17 4:47 AM, Daniel P. Berrange wrote: On Mon, Sep 18, 2017 at 11:43:57AM +0200, Erik Skultety wrote: [...] > 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) Yes, QMP commands seeem most likely. > 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. Yeah, that looks like a viable option too. So I could see a flow like the following: 1. mgmt tool calls virConnectGetCapabilities. This returns an XML document that includes the following ...other bits... ...hex encoded PDH key... 2. mgmt tool requests to start a guest calling virCreateXML(), passing VIR_DOMAIN_START_PAUSED. The XML would include ...hex encode DH key... ..hex encode info... ...int32 value.. if is provided and VIR_DOMAIN_START_PAUSED is missing, libvirt would report an error and refuse to start the guest For ease of use, I would not add this conditional to libvirt. If is provided and VIR_DOMAIN_START_PAUSED is missing, I’d just send the "GO" command as it would naturally occur. Unless that would confuse things inside libvirt or QEMU in relation to the measurement and secret… Many of our existing tests focus on other aspects of SEV functionality and so they skip the MEASURE/SECRET phase of launch and just go immediately from LAUNCH_UPDATE_DATA (or VMSA) to LAUNCH_FINISH. I guess the key question will be how will QEMU know when to get the MEASUREMENT and wait for a LAUNCH_SECRET before doing a LAUNCH_FINISH when connected to libvirt. Brijesh, this is your area. It feels to me like QEMU will have to wait to do the LAUNCH_FINISH until it gets the first “go” from libvirt. If that’s right, and assuming the same “go” comes from libvirt with or without VIR_DOMAIN_START_PAUSED, then I’d simply exclude the conditional check. QEMU would get the measurement when it is done sending the data. Though in “real world” uses, I think the conditional is perfectly OK. 3. Libvirt generates the QEMU cli arg to enable SEV using the XML data and starts QEMU, leaving CPUs paused 4. QEMU emits a SEV_MEASURE event containing the measurement blob Speaking of which, I expect QEMU to have a QMP command to retrieve the measurement, in which case I think libvirt has to provide an API for the user to retrieve the measurement in case libvirtd crashes somewhere between setting up QEMU and waiting for the measurement event from QEMU, or simply because the GO missed the event for some unspecified reason. Yeah, that's a good point - we also ought to have a pause-reason that reflects that it is paused due to waiting for SEV secrets. 5. Libvirt catches the QEMU event and emits its own VIR_CONNECT_DOMAIN_EVENT_SEV_MEASURE event containing the measurement blob 6. GO does its validation of the measurement 7a If validation failed, then virDomainDestroy() to stop QEMU 7b If validation succeeed Optionally call virDomainSetSEVSecret() Given the fact that we're likely introducing a new element to the XML config, I'm more inclined to utilizing the existing virSecret interfaces (as was originally suggested) instead of creating a vendor-specific API. You could have an optional secret sub-element within the element and libvirt would simply check if that secret has a value set, once the GO issues virDomainResume(). Any particular reason for having a specific API for this that I'm missing? Initially I was intending to suggest extensive use of virSecret, but it turns out that despite being called a "secret", none of the SEV data we are passing around needs protection. Either it is safe to be public, or it is already encrypted. So essentially we just have some data blobs we need to pass into QEMU. I didn't feel we ought to be abusing virSecret as a general purpose mechanism for passing in opaque data blobs which do not need any kind of protection. All of the above looks really good to me. While I agree with Daniel’s analysis of the need for “secret”, I do like using virSecret to convey the notion of secrecy. But it isn’t necessary. The end points are the SEV FW and the guest owner and all secrets they share are already encrypted. Embedding it in the “GO” command feels equally OK to me. Note that sending a secret with a “GO” other than the first one is an error… I don’t think libvirt needs to catch that, though. The SEV FW will. Regards, Daniel Thanks, Richard -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Mon, Sep 18, 2017 at 11:43:57AM +0200, Erik Skultety wrote: > [...] > > > > > > > > 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) > > > > > > Yes, QMP commands seeem most likely. > > > > > > > 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. > > > > > > Yeah, that looks like a viable option too. > > > > So I could see a flow like the following: > > > > > > 1. mgmt tool calls virConnectGetCapabilities. This returns an XML > > document that includes the following > > > > > > ...other bits... > > > > ...hex encoded PDH key... > > > > > > > > 2. mgmt tool requests to start a guest calling virCreateXML(), > > passing VIR_DOMAIN_START_PAUSED. The XML would include > > > > > > ...hex encode DH key... > > ..hex encode info... > > ...int32 value.. > > > > > > > > if is provided and VIR_DOMAIN_START_PAUSED is missing, > > libvirt would report an error and refuse to start the guest > > > > 3. Libvirt generates the QEMU cli arg to enable SEV using > > the XML data and starts QEMU, leaving CPUs paused > > > > 4. QEMU emits a SEV_MEASURE event containing the measurement > > blob > > Speaking of which, I expect QEMU to have a QMP command to retrieve the > measurement, in which case I think libvirt has to provide an API for the user > to retrieve the measurement in case libvirtd crashes somewhere between setting > up QEMU and waiting for the measurement event from QEMU, or simply because the > GO missed the event for some unspecified reason. Yeah, that's a good point - we also ought to have a pause-reason that reflects that it is paused due to waiting for SEV secrets. > > > > > 5. Libvirt catches the QEMU event and emits its own > > VIR_CONNECT_DOMAIN_EVENT_SEV_MEASURE event containing > > the measurement blob > > > > 6. GO does its validation of the measurement > > > > 7a If validation failed, then virDomainDestroy() to stop QEMU > > > > 7b If validation succeeed > > > > Optionally call > > > > virDomainSetSEVSecret() > > Given the fact that we're likely introducing a new element to the XML > config, I'm more inclined to utilizing the existing virSecret interfaces (as > was originally suggested) instead of creating a vendor-specific API. You could > have an optional secret sub-element within the element and libvirt would > simply check if that secret has a value set, once the GO issues > virDomainResume(). Any particular reason for having a specific API for this > that > I'm missing? Initially I was intending to suggest extensive use of virSecret, but it turns out that despite being called a "secret", none of the SEV data we are passing around needs protection. Either it is safe to be public, or it is already encrypted. So essentially we just have some data blobs we need to pass into QEMU. I didn't feel we ought to be abusing virSecret as a general purpose mechanism for passing in opaque data blobs which do not need any kind of protection. Regards, Daniel -- |: https://berrange.com -o-https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o-https://fstop138.berrange.com :| |: https://entangle-photo.org-o-https://www.instagram.com/dberrange :| -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
[...] > > > > > 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) > > > > Yes, QMP commands seeem most likely. > > > > > 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. > > > > Yeah, that looks like a viable option too. > > So I could see a flow like the following: > > > 1. mgmt tool calls virConnectGetCapabilities. This returns an XML > document that includes the following > > > ...other bits... > > ...hex encoded PDH key... > > > > 2. mgmt tool requests to start a guest calling virCreateXML(), > passing VIR_DOMAIN_START_PAUSED. The XML would include > > > ...hex encode DH key... > ..hex encode info... > ...int32 value.. > > > > if is provided and VIR_DOMAIN_START_PAUSED is missing, > libvirt would report an error and refuse to start the guest > > 3. Libvirt generates the QEMU cli arg to enable SEV using > the XML data and starts QEMU, leaving CPUs paused > > 4. QEMU emits a SEV_MEASURE event containing the measurement > blob Speaking of which, I expect QEMU to have a QMP command to retrieve the measurement, in which case I think libvirt has to provide an API for the user to retrieve the measurement in case libvirtd crashes somewhere between setting up QEMU and waiting for the measurement event from QEMU, or simply because the GO missed the event for some unspecified reason. > > 5. Libvirt catches the QEMU event and emits its own > VIR_CONNECT_DOMAIN_EVENT_SEV_MEASURE event containing > the measurement blob > > 6. GO does its validation of the measurement > > 7a If validation failed, then virDomainDestroy() to stop QEMU > > 7b If validation succeeed > > Optionally call > > virDomainSetSEVSecret() Given the fact that we're likely introducing a new element to the XML config, I'm more inclined to utilizing the existing virSecret interfaces (as was originally suggested) instead of creating a vendor-specific API. You could have an optional secret sub-element within the element and libvirt would simply check if that secret has a value set, once the GO issues virDomainResume(). Any particular reason for having a specific API for this that I'm missing? Other than that I like the initial proposal for the design. Erik -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On 09/08/2017 10:51 AM, Daniel P. Berrange wrote: On Fri, Sep 08, 2017 at 10:48:10AM -0500, Brijesh Singh wrote: So I could see a flow like the following: The flow looks good 1. mgmt tool calls virConnectGetCapabilities. This returns an XML document that includes the following ...other bits... ...hex encoded PDH key... 2. mgmt tool requests to start a guest calling virCreateXML(), passing VIR_DOMAIN_START_PAUSED. The XML would include ...hex encode DH key... ..hex encode info... ...int32 value.. if is provided and VIR_DOMAIN_START_PAUSED is missing, libvirt would report an error and refuse to start the guest One thing which is not clear to me is, how do we know that we are asked to launch SEV guest? Are you thinking that tag in the XML will hint libvirt that GO has asked to launch a SEV guest? Yes, the existance of the tag is the indicator that informs libvirt that SEV *must* be used for the guest. Thanks for confirming. 3. Libvirt generates the QEMU cli arg to enable SEV using the XML data and starts QEMU, leaving CPUs paused I am looking at [1] to get the feel for how do we model it in the XML. As you can see I am using ad-hoc to create the sev-guest object. Currently, sev-guest object accepts the following properties: dh-cert-file: session-info-file: policy: I believe the new XML model will influence the property input type, Any recommendation on how do model this part ? thank you so much. That looks ok to me - even if QEMU wants the data provided in files on disk, libvirt can just create the files on the fly from the data it has in the element in the XML file. Since they're only needed during startup, libvirt can then easily delete the files the moment QEMU has completed its startup. Perfect! works well with me. -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On 09/08/17 17:51, Daniel P. Berrange wrote: > On Fri, Sep 08, 2017 at 10:48:10AM -0500, Brijesh Singh wrote: >> I am looking at [1] to get the feel for how do we model it in the XML. >> As you can see I am using ad-hoc to create the sev-guest >> object. Currently, sev-guest object accepts the following properties: >> >> dh-cert-file: >> session-info-file: >> policy: >> >> I believe the new XML model will influence the property input type, >> Any recommendation on how do model this part ? thank you so much. > > That looks ok to me - even if QEMU wants the data provided in > files on disk, libvirt can just create the files on the fly > from the data it has in the element in the XML file. > Since they're only needed during startup, libvirt can then > easily delete the files the moment QEMU has completed its > startup. /dev/fd/N filenames could be used for poor man's fd passing, I think. (/dev/fd is a symlink to the /proc/self/fd directory) proc(5) has documentation on this. Thanks, Laszlo -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
Hi Daniel, On 09/08/2017 09:52 AM, Daniel P. Berrange wrote: On Fri, Sep 08, 2017 at 01:45:06PM +, Relph, Richard wrote: A few answers in line… On 9/8/17, 8:16 AM, "Daniel P. Berrange" wrote: On Fri, Sep 08, 2017 at 06:57:30AM -0500, Brijesh Singh wrote: > 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. What sort of size are we talking about for the PDH ? The PDH blob is described in reference 4. It’s 0x824 bytes long… a bit over 2K bytes. PDH is “Platform Diffie-Hellman” key, public portion. There's a few ways libvirt could report it 1. As an XML element in the host capabilities XML 2. As an XML element in the emulator capabilities XML 3. Via a newly added host API > 4. VM tool gives its PDH to GO. > 5. GO provides its DH key, session-info and guest policy. Are steps 4 & 5 strictly required to be in this order, or is it possible Steps 4 and 5 must occur in that order. The data sent by the GO in the “session info” is encrypted and integrity protected with keys that the GO derives from the GO private Diffie-Hellman key and the PDH public Diffie-Hellman key. What are the security requirements around the DH key, session info and guest policy ? Are any of them sensitive data which needs to be kept private from untrustworthy users. Also are all three of these items different for every guest launched, or are some of them likely to be the same for every guest ? The PDH is not sensitive. It is relatively static for the platform. (It only changes when the platform owner chooses to change the apparent identity of the platform that will actually run the virtual machine.) The 128-byte session info data is encrypted and integrity protected by the GO. It need not be additionally encrypted or integrity protected. It should vary for EVERY guest launch. The 4-byte guest policy must be sent in the clear as some components may want to observe the policy bits. It may change from guest to guest, but there will likely only be a few common values. Given this, and the pretty small data sizes, I think this info could in fact all be provided inline in the XML config - either hex or base64 encoded for the binary blobs. > 8. libvirt launches the guest with "-S" All libvirt guests get launched with -S, to give libvirt chance to do some setup before starting vCPUs. Normally vCPUs are started by default, but the VIR_DOMAIN_START_PAUSED flag allows the mgmt app to tell libvirt to leave vCPUS paused. Alternatively, if libvirt sees presencese of 'sev' config for the guest, it could automatically leave it in PAUSED state regardless of the VIR_DOMAIN_START_PAUSED flag. While using the LAUNCH_MEASURE and LAUNCH_SECRET operations is expected to be the common case, they are optional. I would recommend requiring the upstream software to explicitly set the VIR_DOMAIN_START_PAUSED flag, if only to minimize the dependencies… Ok. > 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 > b
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Fri, Sep 08, 2017 at 10:48:10AM -0500, Brijesh Singh wrote: > > So I could see a flow like the following: > > > The flow looks good > > > > > > >1. mgmt tool calls virConnectGetCapabilities. This returns an XML > > document that includes the following > > > > > > ...other bits... > > > > ...hex encoded PDH key... > > > > > > > >2. mgmt tool requests to start a guest calling virCreateXML(), > > passing VIR_DOMAIN_START_PAUSED. The XML would include > > > > > > ...hex encode DH key... > > ..hex encode info... > > ...int32 value.. > > > > > > > > if is provided and VIR_DOMAIN_START_PAUSED is missing, > > libvirt would report an error and refuse to start the guest > > > > > One thing which is not clear to me is, how do we know that we are asked > to launch SEV guest? Are you thinking that tag in the XML will > hint libvirt that GO has asked to launch a SEV guest? Yes, the existance of the tag is the indicator that informs libvirt that SEV *must* be used for the guest. > >3. Libvirt generates the QEMU cli arg to enable SEV using > > the XML data and starts QEMU, leaving CPUs paused > > > > > I am looking at [1] to get the feel for how do we model it in the XML. > As you can see I am using ad-hoc to create the sev-guest > object. Currently, sev-guest object accepts the following properties: > > dh-cert-file: > session-info-file: > policy: > > I believe the new XML model will influence the property input type, > Any recommendation on how do model this part ? thank you so much. That looks ok to me - even if QEMU wants the data provided in files on disk, libvirt can just create the files on the fly from the data it has in the element in the XML file. Since they're only needed during startup, libvirt can then easily delete the files the moment QEMU has completed its startup. > > [1] https://libvirt.org/formatdomain.html#elementsCPU > > > >4. QEMU emits a SEV_MEASURE event containing the measurement > > blob > > > >5. Libvirt catches the QEMU event and emits its own > > VIR_CONNECT_DOMAIN_EVENT_SEV_MEASURE event containing > > the measurement blob > > > >6. GO does its validation of the measurement > > > >7a If validation failed, then virDomainDestroy() to stop QEMU > > > >7b If validation succeeed > > > > Optionally call > > > > virDomainSetSEVSecret() > > > > providing the optional secret, then > > > > virDomainResume() > > > > to let QEMU continue > > > > > > > > > > Regards, > > Daniel > > Regards, Daniel -- |: https://berrange.com -o-https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o-https://fstop138.berrange.com :| |: https://entangle-photo.org-o-https://www.instagram.com/dberrange :| -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Fri, Sep 08, 2017 at 01:45:06PM +, Relph, Richard wrote: > A few answers in line… > > On 9/8/17, 8:16 AM, "Daniel P. Berrange" wrote: > > On Fri, Sep 08, 2017 at 06:57:30AM -0500, Brijesh Singh wrote: > > 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. > > What sort of size are we talking about for the PDH ? > > The PDH blob is described in reference 4. It’s 0x824 bytes long… a bit over > 2K bytes. > PDH is “Platform Diffie-Hellman” key, public portion. > > There's a few ways libvirt could report it > > 1. As an XML element in the host capabilities XML > 2. As an XML element in the emulator capabilities XML > 3. Via a newly added host API > > > 4. VM tool gives its PDH to GO. > > 5. GO provides its DH key, session-info and guest policy. > > Are steps 4 & 5 strictly required to be in this order, or is it > possible > > Steps 4 and 5 must occur in that order. The data sent by the GO in the > “session info” is encrypted and integrity protected with keys that the > GO derives from the GO private Diffie-Hellman key and the PDH public > Diffie-Hellman key. > > What are the security requirements around the DH key, session info > and guest policy ? Are any of them sensitive data which needs to be > kept private from untrustworthy users. Also are all three of these > items different for every guest launched, or are some of them > likely to be the same for every guest ? > > The PDH is not sensitive. It is relatively static for the platform. > (It only changes when the platform owner chooses to change the apparent > identity of the platform that will actually run the virtual machine.) > The 128-byte session info data is encrypted and integrity protected by > the GO. It need not be additionally encrypted or integrity protected. > It should vary for EVERY guest launch. > The 4-byte guest policy must be sent in the clear as some components > may want to observe the policy bits. It may change from guest to guest, > but there will likely only be a few common values. Given this, and the pretty small data sizes, I think this info could in fact all be provided inline in the XML config - either hex or base64 encoded for the binary blobs. > > 8. libvirt launches the guest with "-S" > > All libvirt guests get launched with -S, to give libvirt chance to do some > setup before starting vCPUs. Normally vCPUs are started by default, but > the VIR_DOMAIN_START_PAUSED flag allows the mgmt app to tell libvirt to > leave vCPUS paused. > > Alternatively, if libvirt sees presencese of 'sev' config for the guest, > it could automatically leave it in PAUSED state regardless of the > VIR_DOMAIN_START_PAUSED flag. > > While using the LAUNCH_MEASURE and LAUNCH_SECRET operations is expected > to be the common case, they are optional. I would recommend requiring > the upstream software to explicitly set the VIR_DOMAIN_START_PAUSED flag, > if only to minimize the dependencies… Ok. > > 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 inte
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
A few answers in line… On 9/8/17, 8:16 AM, "Daniel P. Berrange" wrote: On Fri, Sep 08, 2017 at 06:57:30AM -0500, Brijesh Singh wrote: > 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. What sort of size are we talking about for the PDH ? The PDH blob is described in reference 4. It’s 0x824 bytes long… a bit over 2K bytes. PDH is “Platform Diffie-Hellman” key, public portion. There's a few ways libvirt could report it 1. As an XML element in the host capabilities XML 2. As an XML element in the emulator capabilities XML 3. Via a newly added host API > 4. VM tool gives its PDH to GO. > 5. GO provides its DH key, session-info and guest policy. Are steps 4 & 5 strictly required to be in this order, or is it possible Steps 4 and 5 must occur in that order. The data sent by the GO in the “session info” is encrypted and integrity protected with keys that the GO derives from the GO private Diffie-Hellman key and the PDH public Diffie-Hellman key. What are the security requirements around the DH key, session info and guest policy ? Are any of them sensitive data which needs to be kept private from untrustworthy users. Also are all three of these items different for every guest launched, or are some of them likely to be the same for every guest ? The PDH is not sensitive. It is relatively static for the platform. (It only changes when the platform owner chooses to change the apparent identity of the platform that will actually run the virtual machine.) The 128-byte session info data is encrypted and integrity protected by the GO. It need not be additionally encrypted or integrity protected. It should vary for EVERY guest launch. The 4-byte guest policy must be sent in the clear as some components may want to observe the policy bits. It may change from guest to guest, but there will likely only be a few common values. eg, would the same guest policy blob be used for every guest, with only session info changing ? Also what sort of size are we talking about for each of these data items, KBs, 10's of KB, 100's of KBs or larger ? The security and data size can influence our design approach from the libvirt POV. > 6. VM tool somehow communicates the GO provided information to libvirt. Essentially we have two choices 1. inline in the guest XML config description passed to libvirt when defining the guest XML 2. out of band, ahead of time, via some other API prior to defining the guest XML, which is then referenced in guest XML. THis could be done using the virSecret APIs, where we create 3 secrets, one each for DH key, session-info and guets policy. The UUID of the secret could be specified in the guest XML. This has flexibility of allowing the same secrets ot be used for many guests (if this is valid for SEV) > 7. libvirt adds "sev-guest" object in its xml file with all the information >obtained from #5 > >(currently my xml file looks like this) > > > value='sev-guest,id=sev0,policy=,dh-key-file=,session-file=/> > > > > 8. libvirt launches the guest with "-S" All libvirt guests get launched with -S, to give libvirt chance to do some setup before starting vCPUs. Normally vCPUs are started by def
Re: [libvirt] [Qemu-devel] libvirt/QEMU/SEV interaction
On Fri, Sep 08, 2017 at 06:57:30AM -0500, Brijesh Singh wrote: > 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. What sort of size are we talking about for the PDH ? There's a few ways libvirt could report it 1. As an XML element in the host capabilities XML 2. As an XML element in the emulator capabilities XML 3. Via a newly added host API > 4. VM tool gives its PDH to GO. > 5. GO provides its DH key, session-info and guest policy. Are steps 4 & 5 strictly required to be in this order, or is it possible What are the security requirements around the DH key, session info and guest policy ? Are any of them sensitive data which needs to be kept private from untrustworthy users. Also are all three of these items different for every guest launched, or are some of them likely to be the same for every guest ? eg, would the same guest policy blob be used for every guest, with only session info changing ? Also what sort of size are we talking about for each of these data items, KBs, 10's of KB, 100's of KBs or larger ? The security and data size can influence our design approach from the libvirt POV. > 6. VM tool somehow communicates the GO provided information to libvirt. Essentially we have two choices 1. inline in the guest XML config description passed to libvirt when defining the guest XML 2. out of band, ahead of time, via some other API prior to defining the guest XML, which is then referenced in guest XML. THis could be done using the virSecret APIs, where we create 3 secrets, one each for DH key, session-info and guets policy. The UUID of the secret could be specified in the guest XML. This has flexibility of allowing the same secrets ot be used for many guests (if this is valid for SEV) > 7. libvirt adds "sev-guest" object in its xml file with all the information > obtained from #5 > > (currently my xml file looks like this) > > > value='sev-guest,id=sev0,policy=,dh-key-file=,session-file=/> > > > > 8. libvirt launches the guest with "-S" All libvirt guests get launched with -S, to give libvirt chance to do some setup before starting vCPUs. Normally vCPUs are started by default, but the VIR_DOMAIN_START_PAUSED flag allows the mgmt app to tell libvirt to leave vCPUS paused. Alternatively, if libvirt sees presencese of 'sev' config for the guest, it could automatically leave it in PAUSED state regardless of the VIR_DOMAIN_START_PAUSED flag. > 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. Again, what kind of size data are we talking about for athe "measurement" blob ? a KB, 10's of KB, or more ? My first gut instinct would be for QEMU to emit a QMP event when it has the measurement available. The event could include the actual data blob, or we can could add an explicit QMP command to fetch the data blob. Libvirt could listen for this QEMU event, and in turn emit an event from libvirt with the same data, which the mgmt tool can finally give to the GO. > 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. So w