runtime: Add support for PEF

Protected Execution Facility(PEF) is the confidential computing
technology on ppc64le. This PR adds the support for it in Kata.
Also re-vendor govmm for the latest changes.

Fixes: #1881

Signed-off-by: Amulyam24 <amulmek1@in.ibm.com>
This commit is contained in:
Amulyam24 2021-05-25 14:29:42 +00:00
parent cc4748fa64
commit 37a426b4c6
6 changed files with 147 additions and 23 deletions

View File

@ -31,7 +31,7 @@ require (
github.com/gogo/googleapis v1.4.0 // indirect
github.com/gogo/protobuf v1.3.1
github.com/hashicorp/go-multierror v1.0.0
github.com/kata-containers/govmm v0.0.0-20210428163604-f0e9a35308ee
github.com/kata-containers/govmm v0.0.0-20210520142420-eb57f004d89f
github.com/mdlayher/vsock v0.0.0-20191108225356-d9c65923cb8f
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/opencontainers/runc v1.0.0-rc9.0.20200102164712-2b52db75279c

View File

@ -274,12 +274,10 @@ github.com/juju/errors v0.0.0-20180806074554-22422dad46e1/go.mod h1:W54LbzXuIE0b
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/testing v0.0.0-20190613124551-e81189438503/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kata-containers/govmm v0.0.0-20210112013750-7d320e8f5dca h1:UdXFthwasAPnmv37gLJUEFsW9FaabYA+mM6FoSi8kzU=
github.com/kata-containers/govmm v0.0.0-20210112013750-7d320e8f5dca/go.mod h1:VmAHbsL5lLfzHW/MNL96NVLF840DNEV5i683kISgFKk=
github.com/kata-containers/govmm v0.0.0-20210329205824-7fbc685865d2 h1:oDJsQ5avmW8PFUkSJdsuaGL3SR4/YQRno51GNGl+IDU=
github.com/kata-containers/govmm v0.0.0-20210329205824-7fbc685865d2/go.mod h1:VmAHbsL5lLfzHW/MNL96NVLF840DNEV5i683kISgFKk=
github.com/kata-containers/govmm v0.0.0-20210428163604-f0e9a35308ee h1:M4N7AdSHgWz/ubV5AZQdeqmK+9Ztpea6oqeXgk8GCHk=
github.com/kata-containers/govmm v0.0.0-20210428163604-f0e9a35308ee/go.mod h1:VmAHbsL5lLfzHW/MNL96NVLF840DNEV5i683kISgFKk=
github.com/kata-containers/govmm v0.0.0-20210520142420-eb57f004d89f h1:jXMZY7GIz5kSv3/Rdiesg1WMvgXJKNOk3KxwxgNWAVk=
github.com/kata-containers/govmm v0.0.0-20210520142420-eb57f004d89f/go.mod h1:VmAHbsL5lLfzHW/MNL96NVLF840DNEV5i683kISgFKk=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=

View File

@ -134,6 +134,9 @@ const (
// Loader is the Loader device driver.
Loader DeviceDriver = "loader"
// SpaprTPMProxy is used for enabling guest to run in secure mode on ppc64le.
SpaprTPMProxy DeviceDriver = "spapr-tpm-proxy"
)
func isDimmSupported(config *Config) bool {
@ -230,6 +233,14 @@ const (
// TDXGuest represents a TDX object
TDXGuest ObjectType = "tdx-guest"
// SEVGuest represents an SEV guest object
SEVGuest ObjectType = "sev-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.
PEFGuest ObjectType = "pef-guest"
)
// Object is a qemu object representation.
@ -258,37 +269,42 @@ type Object struct {
// File is the device file
File string
// CBitPos is the location of the C-bit in a guest page table entry
// This is only relevant for sev-guest objects
CBitPos uint32
// ReducedPhysBits is the reduction in the guest physical address space
// This is only relevant for sev-guest objects
ReducedPhysBits uint32
}
// Valid returns true if the Object structure is valid and complete.
func (object Object) Valid() bool {
switch object.Type {
case MemoryBackendFile:
if object.ID == "" || object.MemPath == "" || object.Size == 0 {
return false
}
return object.ID != "" && object.MemPath != "" && object.Size != 0
case TDXGuest:
if object.ID == "" || object.File == "" || object.DeviceID == "" {
return false
}
return object.ID != "" && object.File != "" && object.DeviceID != ""
case SEVGuest:
return object.ID != "" && object.File != "" && object.CBitPos != 0 && object.ReducedPhysBits != 0
case SecExecGuest:
return object.ID != ""
case PEFGuest:
return object.ID != "" && object.File != ""
default:
return false
}
return true
}
// QemuParams returns the qemu parameters built out of this Object device.
func (object Object) QemuParams(config *Config) []string {
var objectParams []string
var deviceParams []string
var driveParams []string
var qemuParams []string
deviceParams = append(deviceParams, string(object.Driver))
deviceParams = append(deviceParams, fmt.Sprintf(",id=%s", object.DeviceID))
switch object.Type {
case MemoryBackendFile:
objectParams = append(objectParams, string(object.Type))
@ -296,6 +312,8 @@ func (object Object) QemuParams(config *Config) []string {
objectParams = append(objectParams, fmt.Sprintf(",mem-path=%s", object.MemPath))
objectParams = append(objectParams, fmt.Sprintf(",size=%d", object.Size))
deviceParams = append(deviceParams, string(object.Driver))
deviceParams = append(deviceParams, fmt.Sprintf(",id=%s", object.DeviceID))
deviceParams = append(deviceParams, fmt.Sprintf(",memdev=%s", object.ID))
case TDXGuest:
objectParams = append(objectParams, string(object.Type))
@ -303,14 +321,44 @@ func (object Object) QemuParams(config *Config) []string {
if object.Debug {
objectParams = append(objectParams, ",debug=on")
}
deviceParams = append(deviceParams, string(object.Driver))
deviceParams = append(deviceParams, fmt.Sprintf(",id=%s", object.DeviceID))
deviceParams = append(deviceParams, fmt.Sprintf(",file=%s", object.File))
case SEVGuest:
objectParams = append(objectParams, string(object.Type))
objectParams = append(objectParams, fmt.Sprintf(",id=%s", object.ID))
objectParams = append(objectParams, fmt.Sprintf(",cbitpos=%d", object.CBitPos))
objectParams = append(objectParams, fmt.Sprintf(",reduced-phys-bits=%d", object.ReducedPhysBits))
driveParams = append(driveParams, "if=pflash,format=raw,readonly=on")
driveParams = append(driveParams, fmt.Sprintf(",file=%s", object.File))
case SecExecGuest:
objectParams = append(objectParams, string(object.Type))
objectParams = append(objectParams, fmt.Sprintf(",id=%s", object.ID))
case PEFGuest:
objectParams = append(objectParams, string(object.Type))
objectParams = append(objectParams, fmt.Sprintf(",id=%s", object.ID))
deviceParams = append(deviceParams, string(object.Driver))
deviceParams = append(deviceParams, fmt.Sprintf(",id=%s", object.DeviceID))
deviceParams = append(deviceParams, fmt.Sprintf(",host-path=%s", object.File))
}
qemuParams = append(qemuParams, "-device")
qemuParams = append(qemuParams, strings.Join(deviceParams, ""))
if len(deviceParams) > 0 {
qemuParams = append(qemuParams, "-device")
qemuParams = append(qemuParams, strings.Join(deviceParams, ""))
}
qemuParams = append(qemuParams, "-object")
qemuParams = append(qemuParams, strings.Join(objectParams, ""))
if len(objectParams) > 0 {
qemuParams = append(qemuParams, "-object")
qemuParams = append(qemuParams, strings.Join(objectParams, ""))
}
if len(driveParams) > 0 {
qemuParams = append(qemuParams, "-drive")
qemuParams = append(qemuParams, strings.Join(driveParams, ""))
}
return qemuParams
}

View File

@ -222,7 +222,7 @@ github.com/hashicorp/errwrap
# github.com/hashicorp/go-multierror v1.0.0
## explicit
github.com/hashicorp/go-multierror
# github.com/kata-containers/govmm v0.0.0-20210428163604-f0e9a35308ee
# github.com/kata-containers/govmm v0.0.0-20210520142420-eb57f004d89f
## explicit
github.com/kata-containers/govmm/qemu
# github.com/konsorten/go-windows-terminal-sequences v1.0.1

View File

@ -0,0 +1,17 @@
// Copyright (c) 2021 IBM
//
// SPDX-License-Identifier: Apache-2.0
package virtcontainers
import "os"
//Returns pefProtection if the firmware directory exists
func availableGuestProtection() (guestProtection, error) {
if d, err := os.Stat(pefSysFirmwareDir); err == nil && d.IsDir() {
return pefProtection, err
}
return noneProtection, nil
}

View File

@ -27,6 +27,14 @@ const defaultQemuMachineOptions = "accel=kvm,usb=off"
const qmpMigrationWaitTimeout = 5 * time.Second
const pefSysFirmwareDir = "/sys/firmware/ultravisor/"
const pefID = "pef0"
const tpmID = "tpm0"
const tpmHostPath = "/dev/tpmrm0"
var kernelParams = []Param{
{"rcupdate.rcu_expedited", "1"},
{"reboot", "k"},
@ -43,7 +51,7 @@ var supportedQemuMachine = govmmQemu.Machine{
// Logger returns a logrus logger appropriate for logging qemu messages
func (q *qemuPPC64le) Logger() *logrus.Entry {
return virtLog.WithField("subsystem", "qemu")
return virtLog.WithField("subsystem", "qemuPPC64le")
}
// MaxQemuVCPUs returns the maximum number of vCPUs supported
@ -69,9 +77,16 @@ func newQemuArch(config HypervisorConfig) (qemuArch, error) {
kernelParamsNonDebug: kernelParamsNonDebug,
kernelParamsDebug: kernelParamsDebug,
kernelParams: kernelParams,
protection: noneProtection,
},
}
if config.ConfidentialGuest {
if err := q.enableProtection(); err != nil {
return nil, err
}
}
q.handleImagePath(config)
q.memoryOffset = config.MemOffset
@ -116,3 +131,49 @@ func (q *qemuPPC64le) appendBridges(devices []govmmQemu.Device) []govmmQemu.Devi
func (q *qemuPPC64le) appendIOMMU(devices []govmmQemu.Device) ([]govmmQemu.Device, error) {
return devices, fmt.Errorf("PPC64le does not support appending a vIOMMU")
}
// Enables guest protection
func (q *qemuPPC64le) enableProtection() error {
var err error
q.protection, err = availableGuestProtection()
if err != nil {
return err
}
switch q.protection {
case pefProtection:
if q.qemuMachine.Options != "" {
q.qemuMachine.Options += ","
}
q.qemuMachine.Options += fmt.Sprintf("confidential-guest-support=%s", pefID)
virtLog.WithFields(logrus.Fields{
"subsystem": "qemuPPC64le",
"machine": q.qemuMachine,
"kernel-params": q.kernelParams,
}).Info("Enabling PEF protection")
return nil
default:
return fmt.Errorf("This system doesn't support Confidential Computing (Guest Protection)")
}
}
// append protection device
func (q *qemuPPC64le) appendProtectionDevice(devices []govmmQemu.Device, firmware string) ([]govmmQemu.Device, string, error) {
switch q.protection {
case pefProtection:
return append(devices,
govmmQemu.Object{
Driver: govmmQemu.SpaprTPMProxy,
Type: govmmQemu.PEFGuest,
ID: pefID,
DeviceID: tpmID,
File: tpmHostPath,
}), firmware, nil
case noneProtection:
return devices, firmware, nil
default:
return devices, "", fmt.Errorf("Unsupported guest protection technology: %v", q.protection)
}
}