Merge pull request #4931 from jpecholt/snp-support

Added SNP-Support for Kata-Containers
This commit is contained in:
Peng Tao
2022-09-27 14:17:54 +08:00
committed by GitHub
23 changed files with 458 additions and 135 deletions

View File

@@ -56,6 +56,7 @@ BINLIBEXECLIST :=
BIN_PREFIX = $(PROJECT_TYPE)
PROJECT_DIR = $(PROJECT_TAG)
IMAGENAME = $(PROJECT_TAG).img
INITRDNAME = $(PROJECT_TAG)-initrd.img
TARGET = $(BIN_PREFIX)-runtime
RUNTIME_OUTPUT = $(CURDIR)/$(TARGET)
@@ -110,6 +111,7 @@ PKGLIBEXECDIR := $(LIBEXECDIR)/$(PROJECT_DIR)
KERNELDIR := $(PKGDATADIR)
IMAGEPATH := $(PKGDATADIR)/$(IMAGENAME)
INITRDPATH := $(PKGDATADIR)/$(INITRDNAME)
FIRMWAREPATH :=
FIRMWAREVOLUMEPATH :=
@@ -401,6 +403,8 @@ USER_VARS += FCVALIDJAILERPATHS
USER_VARS += SYSCONFIG
USER_VARS += IMAGENAME
USER_VARS += IMAGEPATH
USER_VARS += INITRDNAME
USER_VARS += INITRDPATH
USER_VARS += MACHINETYPE
USER_VARS += KERNELDIR
USER_VARS += KERNELTYPE

View File

@@ -15,6 +15,7 @@
path = "@QEMUPATH@"
kernel = "@KERNELPATH@"
image = "@IMAGEPATH@"
# initrd = "@INITRDPATH@"
machine_type = "@MACHINETYPE@"
# Enable confidential guest support.
@@ -33,6 +34,12 @@ machine_type = "@MACHINETYPE@"
# Default false
# confidential_guest = true
# Choose AMD SEV-SNP confidential guests
# In case of using confidential guests on AMD hardware that supports both SEV
# and SEV-SNP, the following enables SEV-SNP guests. SEV guests are default.
# Default false
# sev_snp_guest = true
# Enable running QEMU VMM as a non-root user.
# By default QEMU VMM run as root. When this is set to true, QEMU VMM process runs as
# a non-root random user. See documentation for the limitations of this mode.

View File

@@ -231,6 +231,9 @@ const (
// SEVGuest represents an SEV guest object
SEVGuest ObjectType = "sev-guest"
// SNPGuest represents an SNP guest object
SNPGuest ObjectType = "sev-snp-guest"
// SecExecGuest represents an s390x Secure Execution (Protected Virtualization in QEMU) object
SecExecGuest ObjectType = "s390-pv-guest"
// PEFGuest represent ppc64le PEF(Protected Execution Facility) object.
@@ -295,6 +298,8 @@ func (object Object) Valid() bool {
case TDXGuest:
return object.ID != "" && object.File != "" && object.DeviceID != ""
case SEVGuest:
fallthrough
case SNPGuest:
return object.ID != "" && object.File != "" && object.CBitPos != 0 && object.ReducedPhysBits != 0
case SecExecGuest:
return object.ID != ""
@@ -349,6 +354,8 @@ func (object Object) QemuParams(config *Config) []string {
deviceParams = append(deviceParams, fmt.Sprintf("config-firmware-volume=%s", object.FirmwareVolume))
}
case SEVGuest:
fallthrough
case SNPGuest:
objectParams = append(objectParams, string(object.Type))
objectParams = append(objectParams, fmt.Sprintf("id=%s", object.ID))
objectParams = append(objectParams, fmt.Sprintf("cbitpos=%d", object.CBitPos))

View File

@@ -86,6 +86,7 @@ const defaultVhostUserStorePath string = "/var/run/kata-containers/vhost-user/"
const defaultRxRateLimiterMaxRate = uint64(0)
const defaultTxRateLimiterMaxRate = uint64(0)
const defaultConfidentialGuest = false
const defaultSevSnpGuest = false
const defaultGuestSwap = false
const defaultRootlessHypervisor = false
const defaultDisableSeccomp = false

View File

@@ -149,6 +149,7 @@ type hypervisor struct {
DisableVhostNet bool `toml:"disable_vhost_net"`
GuestMemoryDumpPaging bool `toml:"guest_memory_dump_paging"`
ConfidentialGuest bool `toml:"confidential_guest"`
SevSnpGuest bool `toml:"sev_snp_guest"`
GuestSwap bool `toml:"enable_guest_swap"`
Rootless bool `toml:"rootless"`
DisableSeccomp bool `toml:"disable_seccomp"`
@@ -827,6 +828,7 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
GuestMemoryDumpPath: h.GuestMemoryDumpPath,
GuestMemoryDumpPaging: h.GuestMemoryDumpPaging,
ConfidentialGuest: h.ConfidentialGuest,
SevSnpGuest: h.SevSnpGuest,
GuestSwap: h.GuestSwap,
Rootless: h.Rootless,
LegacySerial: h.LegacySerial,
@@ -1221,6 +1223,7 @@ func GetDefaultHypervisorConfig() vc.HypervisorConfig {
TxRateLimiterMaxRate: defaultTxRateLimiterMaxRate,
SGXEPCSize: defaultSGXEPCSize,
ConfidentialGuest: defaultConfidentialGuest,
SevSnpGuest: defaultSevSnpGuest,
GuestSwap: defaultGuestSwap,
Rootless: defaultRootlessHypervisor,
DisableSeccomp: defaultDisableSeccomp,

View File

@@ -422,6 +422,8 @@ func (clh *cloudHypervisor) enableProtection() error {
case sevProtection:
return errors.New("SEV protection is not supported by Cloud Hypervisor")
case snpProtection:
return errors.New("SEV-SNP protection is not supported by Cloud Hypervisor")
default:
return errors.New("This system doesn't support Confidentian Computing (Guest Protection)")

View File

@@ -348,6 +348,10 @@ type HypervisorConfig struct {
// Enable or disable different hardware features, ranging
// from memory encryption to both memory and CPU-state encryption and integrity.
ConfidentialGuest bool
// Enables SEV-SNP guests in case both AMD SEV and SNP are supported.
// SEV is default.
SevSnpGuest bool
}
```

View File

@@ -530,6 +530,9 @@ type HypervisorConfig struct {
// from memory encryption to both memory and CPU-state encryption and integrity.
ConfidentialGuest bool
// Enable SEV-SNP guests on AMD machines capable of both
SevSnpGuest bool
// BootToBeTemplate used to indicate if the VM is created to be a template VM
BootToBeTemplate bool
@@ -873,6 +876,11 @@ const (
// Exclude from lint checking for it won't be used on arm64 code
sevProtection
// AMD Secure Encrypted Virtualization - Secure Nested Paging (SEV-SNP)
// https://developer.amd.com/sev/
// Exclude from lint checking for it won't be used on arm64 code
snpProtection
// IBM POWER 9 Protected Execution Facility
// https://www.kernel.org/doc/html/latest/powerpc/ultravisor.html
// Exclude from lint checking for it won't be used on arm64 code
@@ -889,6 +897,7 @@ var guestProtectionStr = [...]string{
pefProtection: "pef",
seProtection: "se",
sevProtection: "sev",
snpProtection: "snp",
tdxProtection: "tdx",
}

View File

@@ -13,6 +13,8 @@ const (
tdxCPUFlag = "tdx"
sevKvmParameterPath = "/sys/module/kvm_amd/parameters/sev"
snpKvmParameterPath = "/sys/module/kvm_amd/parameters/sev_snp"
)
// Implementation of this function is architecture specific
@@ -26,6 +28,13 @@ func availableGuestProtection() (guestProtection, error) {
if d, err := os.Stat(tdxSysFirmwareDir); (err == nil && d.IsDir()) || flags[tdxCPUFlag] {
return tdxProtection, nil
}
// SEV-SNP is supported and enabled when the kvm module `sev_snp` parameter is set to `Y`
// SEV-SNP support infers SEV (-ES) support
if _, err := os.Stat(snpKvmParameterPath); err == nil {
if c, err := os.ReadFile(snpKvmParameterPath); err == nil && len(c) > 0 && (c[0] == 'Y') {
return snpProtection, nil
}
}
// SEV is supported and enabled when the kvm module `sev` parameter is set to `1` (or `Y` for linux >= 5.12)
if _, err := os.Stat(sevKvmParameterPath); err == nil {
if c, err := os.ReadFile(sevKvmParameterPath); err == nil && len(c) > 0 && (c[0] == '1' || c[0] == 'Y') {

View File

@@ -24,6 +24,8 @@ type qemuAmd64 struct {
// inherit from qemuArchBase, overwrite methods if needed
qemuArchBase
snpGuest bool
vmFactory bool
devLoadersCount uint32
@@ -122,6 +124,7 @@ func newQemuArch(config HypervisorConfig) (qemuArch, error) {
legacySerial: config.LegacySerial,
},
vmFactory: factory,
snpGuest: config.SevSnpGuest,
}
if config.ConfidentialGuest {
@@ -169,6 +172,21 @@ func (q *qemuAmd64) bridges(number uint32) {
q.Bridges = genericBridges(number, q.qemuMachine.Type)
}
func (q *qemuAmd64) cpuModel() string {
var err error
cpuModel := defaultCPUModel
// Temporary until QEMU cpu model 'host' supports AMD SEV-SNP
protection, err := availableGuestProtection()
if err == nil {
if protection == snpProtection && q.snpGuest {
cpuModel = "EPYC-v4"
}
}
return cpuModel
}
func (q *qemuAmd64) memoryTopology(memoryMb, hostMemoryMb uint64, slots uint8) govmmQemu.Memory {
return genericMemoryTopology(memoryMb, hostMemoryMb, slots, q.memoryOffset)
}
@@ -197,6 +215,11 @@ func (q *qemuAmd64) enableProtection() error {
if err != nil {
return err
}
// Configure SNP only if specified in config
if q.protection == snpProtection && !q.snpGuest {
q.protection = sevProtection
}
logger := hvLogger.WithFields(logrus.Fields{
"subsystem": "qemuAmd64",
"machine": q.qemuMachine,
@@ -219,6 +242,13 @@ func (q *qemuAmd64) enableProtection() error {
q.qemuMachine.Options += "confidential-guest-support=sev"
logger.Info("Enabling SEV guest protection")
return nil
case snpProtection:
if q.qemuMachine.Options != "" {
q.qemuMachine.Options += ","
}
q.qemuMachine.Options += "confidential-guest-support=snp"
logger.Info("Enabling SNP guest protection")
return nil
// TODO: Add support for other x86_64 technologies
@@ -263,6 +293,16 @@ func (q *qemuAmd64) appendProtectionDevice(devices []govmmQemu.Device, firmware,
CBitPos: cpuid.AMDMemEncrypt.CBitPosition,
ReducedPhysBits: cpuid.AMDMemEncrypt.PhysAddrReduction,
}), "", nil
case snpProtection:
return append(devices,
govmmQemu.Object{
Type: govmmQemu.SNPGuest,
ID: "snp",
Debug: false,
File: firmware,
CBitPos: cpuid.AMDMemEncrypt.CBitPosition,
ReducedPhysBits: 1,
}), "", nil
case noneProtection:
return devices, firmware, nil

View File

@@ -293,6 +293,26 @@ func TestQemuAmd64AppendProtectionDevice(t *testing.T) {
assert.Equal(expectedOut, devices)
// snp protection
amd64.(*qemuAmd64).protection = snpProtection
devices, bios, err = amd64.appendProtectionDevice(devices, firmware, "")
assert.NoError(err)
assert.Empty(bios)
expectedOut = append(expectedOut,
govmmQemu.Object{
Type: govmmQemu.SNPGuest,
ID: "snp",
Debug: false,
File: firmware,
CBitPos: cpuid.AMDMemEncrypt.CBitPosition,
ReducedPhysBits: 1,
},
)
assert.Equal(expectedOut, devices)
// tdxProtection
amd64.(*qemuAmd64).protection = tdxProtection

View File

@@ -209,6 +209,13 @@ func TestQemuArm64AppendProtectionDevice(t *testing.T) {
assert.Empty(bios)
assert.NoError(err)
// SNP protection
arm64.(*qemuArm64).protection = snpProtection
devices, bios, err = arm64.appendProtectionDevice(devices, firmware, "")
assert.Empty(devices)
assert.Empty(bios)
assert.NoError(err)
// TDX protection
arm64.(*qemuArm64).protection = tdxProtection
devices, bios, err = arm64.appendProtectionDevice(devices, firmware, "")

View File

@@ -79,6 +79,12 @@ func TestQemuPPC64leAppendProtectionDevice(t *testing.T) {
assert.Error(err)
assert.Empty(bios)
//SNP protection
ppc64le.(*qemuPPC64le).protection = snpProtection
devices, bios, err = ppc64le.appendProtectionDevice(devices, firmware, "")
assert.Error(err)
assert.Empty(bios)
//TDX protection
ppc64le.(*qemuPPC64le).protection = tdxProtection
devices, bios, err = ppc64le.appendProtectionDevice(devices, firmware, "")

View File

@@ -136,6 +136,12 @@ func TestQemuS390xAppendProtectionDevice(t *testing.T) {
assert.Error(err)
assert.Empty(bios)
// SNP protection
s390x.(*qemuS390x).protection = snpProtection
devices, bios, err = s390x.appendProtectionDevice(devices, firmware, "")
assert.Error(err)
assert.Empty(bios)
// Secure Execution protection
s390x.(*qemuS390x).protection = seProtection