On 14/12/2021 20:39, Daniel P. Berrangé wrote:
> On Tue, Dec 14, 2021 at 01:59:10PM +0000, Dov Murik wrote:
>> Add a section explaining how the Guest Owner should calculate the
>> expected guest launch measurement for SEV and SEV-ES.
>>
>> Also update the name and link to the SEV API Spec document.
>>
>> Signed-off-by: Dov Murik <dovmu...@linux.ibm.com>
>> Suggested-by: Daniel P. Berrangé <berra...@redhat.com>
>> ---
>> docs/amd-memory-encryption.txt | 50 +++++++++++++++++++++++++++++++---
>> 1 file changed, 46 insertions(+), 4 deletions(-)
>>
>> diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt
>> index ffca382b5f..f97727482f 100644
>> --- a/docs/amd-memory-encryption.txt
>> +++ b/docs/amd-memory-encryption.txt
>> @@ -43,7 +43,7 @@ The guest policy is passed as plaintext. A hypervisor may
>> choose to read it,
>> but should not modify it (any modification of the policy bits will result
>> in bad measurement). The guest policy is a 4-byte data structure containing
>> several flags that restricts what can be done on a running SEV guest.
>> -See KM Spec section 3 and 6.2 for more details.
>> +See SEV API Spec [1] section 3 and 6.2 for more details.
>>
>> The guest policy can be provided via the 'policy' property (see below)
>>
>> @@ -88,7 +88,7 @@ expects.
>> LAUNCH_FINISH finalizes the guest launch and destroys the cryptographic
>> context.
>>
>> -See SEV KM API Spec [1] 'Launching a guest' usage flow (Appendix A) for the
>> +See SEV API Spec [1] 'Launching a guest' usage flow (Appendix A) for the
>> complete flow chart.
>>
>> To launch a SEV guest
>> @@ -113,6 +113,45 @@ a SEV-ES guest:
>> - Requires in-kernel irqchip - the burden is placed on the hypervisor to
>> manage booting APs.
>>
>> +Calculating expected guest launch measurement
>> +---------------------------------------------
>> +In order to verify the guest launch measurement, The Guest Owner must
>> compute
>> +it in the exact same way as it is calculated by the AMD-SP. SEV API Spec
>> [1]
>> +section 6.5.1 describes the AMD-SP operations:
>> +
>> + GCTX.LD is finalized, producing the hash digest of all plaintext data
>> + imported into the guest.
>> +
>> + The launch measurement is calculated as:
>> +
>> + HMAC(0x04 || API_MAJOR || API_MINOR || BUILD || GCTX.POLICY || GCTX.LD
>> || MNONCE; GCTX.TIK)
>> +
>> + where "||" represents concatenation.
>> +
>> +The values of API_MAJOR, API_MINOR, BUILD, and GCTX.POLICY can be obtained
>> +from the 'query-sev' qmp command.
>> +
>> +The value of MNONCE is part of the response of 'query-sev-launch-measure':
>> it
>> +is the last 16 bytes of the base64-decoded data field (see SEV API Spec [1]
>> +section 6.5.2 Table 52: LAUNCH_MEASURE Measurement Buffer).
>> +
>> +The value of GCTX.LD is SHA256(firmware_blob || kernel_hashes_blob ||
>> vmsas_blob),
>> +where:
>> +
>> +* firmware_blob is the content of the entire firmware flash file (for
>> example,
>> + OVMF.fd).
>
> Lets add a caveat that the firmware flash should be built to be stateless
> ie that it is not secure to attempt to measure a guest where the firmware
> uses an NVRAM store.
>
* firmware_blob is the content of the entire firmware flash file (for
example, OVMF.fd). Note that you must build a stateless firmware file
which doesn't use an NVRAM store, because the NVRAM area is not
measured, and therefore it is not secure to use a firmware which uses
state from an NVRAM store.
>> +* if kernel is used, and kernel-hashes=on, then kernel_hashes_blob is the
>> + content of PaddedSevHashTable (including the zero padding), which itself
>> + includes the hashes of kernel, initrd, and cmdline that are passed to the
>> + guest. The PaddedSevHashTable struct is defined in target/i386/sev.c .
>> +* if SEV-ES is enabled (policy & 0x4 != 0), vmsas_blob is the concatenation
>> of
>> + all VMSAs of the guest vcpus. Each VMSA is 4096 bytes long; its content
>> is
>> + defined inside Linux kernel code as struct vmcb_save_area, or in AMD APM
>> + Volume 2 [2] Table B-2: VMCB Layout, State Save Area.
>
> Is there any practical guidance we can give apps on the way the VMSAs
> can be expected to be initialized ? eg can they assume essentially
> all fields in vmcb_save_area are 0 initialized except for certain
> ones ? Is initialization likely to vary at all across KVM or EDK2
> vesions or something ?
>From my own experience, the VMSA of vcpu0 doesn't change; it is basically what
>QEMU
sets up in x86_cpu_reset() (which is mostly zeros but not all). I don't know
if it
may change in newer QEMU (machine types?) or kvm. As for vcpu1+, in SEV-ES the
CS:EIP for the APs is taken from a GUIDed table at the end of the OVMF image,
and has
actually changed a few months ago when the memory layout changed to support
both TDX
and SEV.
Here are the VMSAs for my 2-vcpu SEV-ES VM:
$ hd vmsa/vmsa_cpu0.bin
00000000 00 00 93 00 ff ff 00 00 00 00 00 00 00 00 00 00 |................|
00000010 00 f0 9b 00 ff ff 00 00 00 00 ff ff 00 00 00 00 |................|
00000020 00 00 93 00 ff ff 00 00 00 00 00 00 00 00 00 00 |................|
*
00000060 00 00 00 00 ff ff 00 00 00 00 00 00 00 00 00 00 |................|
00000070 00 00 82 00 ff ff 00 00 00 00 00 00 00 00 00 00 |................|
00000080 00 00 00 00 ff ff 00 00 00 00 00 00 00 00 00 00 |................|
00000090 00 00 8b 00 ff ff 00 00 00 00 00 00 00 00 00 00 |................|
000000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000000d0 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000140 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 |........@.......|
00000150 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 |................|
00000160 00 04 00 00 00 00 00 00 f0 0f ff ff 00 00 00 00 |................|
00000170 02 00 00 00 00 00 00 00 f0 ff 00 00 00 00 00 00 |................|
00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000260 00 00 00 00 00 00 00 00 06 04 07 00 06 04 07 00 |................|
00000270 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000310 10 0f 83 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000320 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000003e0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
000003f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001000
$ hd vmsa/vmsa_cpu1.bin
00000000 00 00 93 00 ff ff 00 00 00 00 00 00 00 00 00 00 |................|
00000010 00 f0 9b 00 ff ff 00 00 00 00 80 00 00 00 00 00 |................|
00000020 00 00 93 00 ff ff 00 00 00 00 00 00 00 00 00 00 |................|
*
00000060 00 00 00 00 ff ff 00 00 00 00 00 00 00 00 00 00 |................|
00000070 00 00 82 00 ff ff 00 00 00 00 00 00 00 00 00 00 |................|
00000080 00 00 00 00 ff ff 00 00 00 00 00 00 00 00 00 00 |................|
00000090 00 00 8b 00 ff ff 00 00 00 00 00 00 00 00 00 00 |................|
000000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000000d0 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000140 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 |........@.......|
00000150 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 |................|
00000160 00 04 00 00 00 00 00 00 f0 0f ff ff 00 00 00 00 |................|
00000170 02 00 00 00 00 00 00 00 00 b0 00 00 00 00 00 00 |................|
00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000260 00 00 00 00 00 00 00 00 06 04 07 00 06 04 07 00 |................|
00000270 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000310 10 0f 83 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000320 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000003e0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
000003f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001000
-Dov