On Mon, Jan 31, 2022 at 03:38:47PM +0200, Dov Murik wrote: > > > On 31/01/2022 13:44, Daniel P. Berrangé wrote: > > On Mon, Jan 31, 2022 at 11:15:39AM +0000, Dov Murik wrote: > >> Currently the responses of QMP commands query-sev-launch-measure and > >> query-sev-attestation-report return just the signed measurement. In > >> order to validate it, the Guest Owner must know the exact guest launch > >> digest, besides other host and guest properties which are included in > >> the measurement. > >> > >> The other host and guest details (SEV API major, SEV API minor, SEV > >> build, and guest policy) are all available via query-sev QMP command. > >> However, the launch digest is not available. This makes checking the > >> measurement harder for the Guest Owner, as it has to iterate through all > >> allowed launch digests and compute the expected measurement. > > > > So more specifically to validate the measurement, the guest owner is > > currently calculating: > > > > expected_measurement = HMAC(0x04 || API_MAJOR || API_MINOR || BUILD || > > GCTX.POLICY || GCTX.LD || MNONCE; GCTX.TIK) > > > > where GCTX.LD is > > > > SHA256(FIRMWARE-CODE || KERNEL-HASHES-TABLE || VMSA-FOREACH-VCPU) > > > > and comparing expected_measurement to the actual measurement from > > query-sev-launch-measure. > > > >> Add a new field debug-launch-digest to the response of > >> query-sev-launch-measure and query-sev-attestation-report which includes > >> the guest launch digest, which is the SHA256 of all initial memory added > >> to the guest via sev_launch_update_data(). > > > > So this new 'debug-launch-digest' field is returning GCTX.LD value > > above. > > > > Yes. Maybe rename it to gctx-ld ? > > hmmm, except at the moment it doesn't include the VMSAs, because I don't > know an easy way to do it within QEMU :-( . So the content of > debug-launch-digest is currently incorrect for SEV-ES guests.
Yes, that comes back to the problem we've discussed previously about how to determine the correct expected VMSA content which has no easy answer. > The scenario we are encountering is that there's not one allowed > assignment to the parameters, but rather a more relaxed policy along the > lines of: > > API_MAJOR.API_MINOR should be >= 12.34 > BUILD should be >= 66 > GCTX.POLICY should be 0x0 or 0x2 > GCTX.LD can be one of these allowed OVMFs: {hash-a, hash-b, hash-c} > > > Having the values of API*, BUILD, POLICY from query-sev is very > comfortable for verifying they are in the allowed ranges. But since the > Guest Owner doesn't have GCTX.LD, they have to compute the measurement > for each of the allowed OVMF images. Once the values are known and > "allowed", then the HMAC must be computed to see that the signed > measurement does indeed match. Ok, so the usage scenario is that the platform owner is deciding which OVMF build in use, not the guest owner. That guest owner just knows that it is an OVMF build from a set of builds published by the platform owner. Good enough if you trust the cloud owner in general, but want confidence that their compute host isn't compromised. Would need an independantly reproducible build, if you don't trust the cloud owner at all. Assuming we've got 5 possible OVMF builds, currently we would need to calculate 5 HMACs over the inpuot data. With this extra piece of info, we only need to calculate 1 HMAC. So this is enabling a performance optimization, that could indeed be used in a production deployment. The HMAC ops are not exactly performance intensive though until we get to the point of choosing between a huge number of possible OVMFs. If we can't get the VMSA info included, then the guest owner still needs a local copy of every possible OVMF binary that is valid. IOW this digest is essentially no more than a filename to identify which OVMF binary to calc the HMAC over. > Note: I guess that adding the hashes of kernel/initrd/cmdline here might > help too (for direct boot with kernel-hashes=on), and maybe the hash of > OVMF itself (on its own). IOW, I think there's only two scenarios that make sense 1. The combined launch digest over firmware, kernel hashes and VMSA state. 2. Individual hashes for each of firmware, kernel hashes table and VMSA state I think we should assume that anyone who has access to SEV-ES hardware is likely to run in SEV-ES policy, not SEV policy. So without VMSA state I think that (1) is of quite limited usefulness. (2) would be nicer to allow optimization of picking which OVMF blob to use, as you wouldn't need to figure out the cross-product of very valid OVMF and every valid kernel hashes table - the latter probably isn't even a finite bounded set. > More generally: within space/network constraints, give the Guest Owner > all the information it needs to compute the launch measurement. There's > a problem with OVMF there (we don't want to send the whole 4 MB over the > QMP response, but given its hash we can't "extend" it to include the > kernel-hashes struct). Yeah its a shame we aren't just measuring the digest of each piece of information in GCTX.LD, instead of measuring the raw information directly. I wonder if we're thinking of this at the wrong level though. Does it actually need to be QEMU providing this info to the guest owner ? Guest owners aren't going to be interacting with QEMU / QMP directly, nor are they likely to be interacting with libvirt directly. Their way into the public cloud will be via some high level API. eg the OpenStack Nova REST API, or the IBM Cloud API (whatever that may be). This high level mgmt infra is likely what is deciding which of the 'N' possible OVMF builds to pick for a given VM launch. It could easily just expose the full OVMF data to the user via its own API regardless of what query-sev does. Similarly if the cloud is choosing which kernel, out of N possible kernels to boot with, they could expose the raw kernel data somewhere in their API - we don't neccessarily need to expose that from QEMU. If we don't find a way to extract the VMSA data blob on the fly, then the cloud owner will need to public VMSA data somewhere out of band regardless. > > Is that really compelling enough to justify adding this extra > > info to the QAPI commands ? IME of writing code to verify the SEV > > measurement, there were many little ways I screwed up at first > > and having this field would not have made a significant difference > > to my debugging efforts. > > I think that adding the extra field is not that bad, even if it's useful > just for some cases. > > I'll be glad to get rid of the launch_memory buffer in my implementation > and replace it with a SHA256-context variable (but found none in QEMU). > Other than that I don't think the suggested addition is too bad (in > fact, I would add some more info like kernel hashes.). Given we can't actually emit a valid GCTX.LD for SEV, my preference would be to just report the hashes of each piece of data that is a input to the GCTX.LD. eg report 'firmware-digest', 'kernel-digest', 'initrd-digest', 'cmdline-digest'. They can use firmware-digest as a identifier to locate the raw firmware data blob. They can use kernel-digest, initrd-digest, and cmdline-digest to compare against their list of expected kernel/initrd binaries, if the cloud owner controls them, and also to then build the kernl hashes table. They still have to figure out the VMSAs separately somehow, or the cloud mgmt layer can use all of this info to expose the raw data in their own higher level API. 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 :|