runtime: Support launching SEV-ES guests

The `sev_guest_policy` configuration field distinguishes between SEV and
SEV-ES guests (according to standard AMD SEV policy values).

Modify the kata runtime to detect SEV-ES guests and calculate calculate
the expected launch digest taking into account the number of VCPUs and
their CPU signature (model/family/stepping).

Fixes: #5471

Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
This commit is contained in:
Dov Murik 2022-11-15 14:38:16 +02:00 committed by Dov Murik
parent 769f91de8b
commit adec86cc40
3 changed files with 86 additions and 2 deletions

View File

@ -46,3 +46,31 @@ const (
// 'EPYC-Milan-v2': family=25, model=1, stepping=1 // 'EPYC-Milan-v2': family=25, model=1, stepping=1
SigEpycMilanV2 VCPUSig = 0xa00f11 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)
}

View File

@ -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")
}
}

View File

@ -9,6 +9,7 @@ package virtcontainers
import ( import (
"context" "context"
"crypto/sha256"
b64 "encoding/base64" b64 "encoding/base64"
"fmt" "fmt"
"log" "log"
@ -38,6 +39,8 @@ type qemuAmd64 struct {
devLoadersCount uint32 devLoadersCount uint32
sgxEPCSize int64 sgxEPCSize int64
numVCPUs uint32
} }
const ( const (
@ -58,6 +61,9 @@ const (
sevAttestationGodhName = "godh.b64" sevAttestationGodhName = "godh.b64"
sevAttestationSessionFileName = "session_file.b64" sevAttestationSessionFileName = "session_file.b64"
// For more info, see AMD SEV API document 55766
sevPolicyBitSevEs = 0x4
) )
var kernelParams = []Param{ var kernelParams = []Param{
@ -140,6 +146,7 @@ func newQemuArch(config HypervisorConfig) (qemuArch, error) {
}, },
vmFactory: factory, vmFactory: factory,
snpGuest: config.SevSnpGuest, snpGuest: config.SevSnpGuest,
numVCPUs: config.NumVCPUs,
} }
if config.ConfidentialGuest { if config.ConfidentialGuest {
@ -409,6 +416,34 @@ func (q *qemuAmd64) setupSEVGuestPreAttestation(ctx context.Context, config sev.
return attestationId, nil 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 // wait for prelaunch attestation to complete
func (q *qemuAmd64) sevGuestPreAttestation(ctx context.Context, func (q *qemuAmd64) sevGuestPreAttestation(ctx context.Context,
qmp *govmmQemu.QMP, config sev.GuestPreAttestationConfig) error { qmp *govmmQemu.QMP, config sev.GuestPreAttestationConfig) error {
@ -447,9 +482,9 @@ func (q *qemuAmd64) sevGuestPreAttestation(ctx context.Context,
secrets := []*pb.RequestDetails{&requestDetails} 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 { 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[:]) launchDigestBase64 := b64.StdEncoding.EncodeToString(launchDigest[:])