diff --git a/src/runtime/pkg/sev/vcpu_sigs.go b/src/runtime/pkg/sev/vcpu_sigs.go index b28460b0fd..9cee59e2b1 100644 --- a/src/runtime/pkg/sev/vcpu_sigs.go +++ b/src/runtime/pkg/sev/vcpu_sigs.go @@ -46,3 +46,31 @@ const ( // 'EPYC-Milan-v2': family=25, model=1, stepping=1 SigEpycMilanV2 VCPUSig = 0xa00f11 ) + +// NewVCPUSig computes the CPU signature (32-bit value) from the given family, +// model, and stepping. +// +// This computation is described in AMD's CPUID Specification, publication #25481 +// https://www.amd.com/system/files/TechDocs/25481.pdf +// See section: CPUID Fn0000_0001_EAX Family, Model, Stepping Identifiers +func NewVCPUSig(family, model, stepping uint32) VCPUSig { + var family_low, family_high uint32 + if family > 0xf { + family_low = 0xf + family_high = (family - 0x0f) & 0xff + } else { + family_low = family + family_high = 0 + } + + model_low := model & 0xf + model_high := (model >> 4) & 0xf + + stepping_low := stepping & 0xf + + return VCPUSig((family_high << 20) | + (model_high << 16) | + (family_low << 8) | + (model_low << 4) | + stepping_low) +} diff --git a/src/runtime/pkg/sev/vcpu_sigs_test.go b/src/runtime/pkg/sev/vcpu_sigs_test.go new file mode 100644 index 0000000000..70f8487509 --- /dev/null +++ b/src/runtime/pkg/sev/vcpu_sigs_test.go @@ -0,0 +1,21 @@ +// Copyright contributors to AMD SEV/-ES in Go +// +// SPDX-License-Identifier: Apache-2.0 + +package sev + +import ( + "testing" +) + +func TestNewVCPUSig(t *testing.T) { + if NewVCPUSig(23, 1, 2) != SigEpyc { + t.Errorf("wrong EPYC CPU signature") + } + if NewVCPUSig(23, 49, 0) != SigEpycRome { + t.Errorf("wrong EPYC-Rome CPU signature") + } + if NewVCPUSig(25, 1, 1) != SigEpycMilan { + t.Errorf("wrong EPYC-Milan CPU signature") + } +} diff --git a/src/runtime/virtcontainers/qemu_amd64.go b/src/runtime/virtcontainers/qemu_amd64.go index 4c7e026a94..586aa40ad7 100644 --- a/src/runtime/virtcontainers/qemu_amd64.go +++ b/src/runtime/virtcontainers/qemu_amd64.go @@ -9,6 +9,7 @@ package virtcontainers import ( "context" + "crypto/sha256" b64 "encoding/base64" "fmt" "log" @@ -38,6 +39,8 @@ type qemuAmd64 struct { devLoadersCount uint32 sgxEPCSize int64 + + numVCPUs uint32 } const ( @@ -58,6 +61,9 @@ const ( sevAttestationGodhName = "godh.b64" sevAttestationSessionFileName = "session_file.b64" + + // For more info, see AMD SEV API document 55766 + sevPolicyBitSevEs = 0x4 ) var kernelParams = []Param{ @@ -140,6 +146,7 @@ func newQemuArch(config HypervisorConfig) (qemuArch, error) { }, vmFactory: factory, snpGuest: config.SevSnpGuest, + numVCPUs: config.NumVCPUs, } if config.ConfidentialGuest { @@ -409,6 +416,34 @@ func (q *qemuAmd64) setupSEVGuestPreAttestation(ctx context.Context, config sev. return attestationId, nil } +func getCPUSig(cpuModel string) sev.VCPUSig { + // This is for the special case for SNP (see cpuModel()). + if cpuModel == "EPYC-v4" { + return sev.SigEpycV4 + } + return sev.NewVCPUSig(cpuid.DisplayFamily, cpuid.DisplayModel, cpuid.SteppingId) +} + +func calculateGuestLaunchDigest(config sev.GuestPreAttestationConfig, numVCPUs int, cpuModel string) ([sha256.Size]byte, error) { + if config.Policy&sevPolicyBitSevEs != 0 { + // SEV-ES guest + return sev.CalculateSEVESLaunchDigest( + numVCPUs, + getCPUSig(cpuModel), + config.FwPath, + config.KernelPath, + config.InitrdPath, + config.KernelParameters) + } + + // SEV guest + return sev.CalculateLaunchDigest( + config.FwPath, + config.KernelPath, + config.InitrdPath, + config.KernelParameters) +} + // wait for prelaunch attestation to complete func (q *qemuAmd64) sevGuestPreAttestation(ctx context.Context, qmp *govmmQemu.QMP, config sev.GuestPreAttestationConfig) error { @@ -447,9 +482,9 @@ func (q *qemuAmd64) sevGuestPreAttestation(ctx context.Context, secrets := []*pb.RequestDetails{&requestDetails} - launchDigest, err := sev.CalculateLaunchDigest(config.FwPath, config.KernelPath, config.InitrdPath, config.KernelParameters) + launchDigest, err := calculateGuestLaunchDigest(config, int(q.numVCPUs), q.cpuModel()) if err != nil { - return fmt.Errorf("Could not calculate SEV launch digest: %v", err) + return fmt.Errorf("Could not calculate SEV/SEV-ES launch digest: %v", err) } launchDigestBase64 := b64.StdEncoding.EncodeToString(launchDigest[:])