runtime: Enable connection to Quote Generation Service (QGS)

For the TD attestation to work the connection to QGS on the host is needed.
By default QGS runs on vsock port 4050, but can be modified by the host owner.
Format of the qemu object follows the SocketAddress structure, so it needs to be provided in the JSON format, as in the example below:
-object '{"qom-type":"tdx-guest","id":"tdx","quote-generation-socket":{"type":"vsock","cid":"2","port":"4050"}}'

Fixes: #9497
Signed-off-by: Jakub Ledworowski <jakub.ledworowski@intel.com>
This commit is contained in:
Jakub Ledworowski 2024-05-16 12:37:23 +02:00
parent 0331859740
commit fc680139e5
8 changed files with 80 additions and 6 deletions

View File

@ -179,6 +179,7 @@ QEMUVALIDHYPERVISORPATHS := [\"$(QEMUPATH)\"]
#QEMUTDXPATH := $(QEMUBINDIR)/$(QEMUTDXCMD)
QEMUTDXPATH := PLACEHOLDER_FOR_DISTRO_QEMU_WITH_TDX_SUPPORT
QEMUTDXVALIDHYPERVISORPATHS := [\"$(QEMUTDXPATH)\"]
QEMUTDXQUOTEGENERATIONSERVICESOCKETPORT := 4050
QEMUSNPPATH := $(QEMUBINDIR)/$(QEMUSNPCMD)
QEMUSNPVALIDHYPERVISORPATHS := [\"$(QEMUSNPPATH)\"]
@ -705,6 +706,7 @@ USER_VARS += QEMUTDXCMD
USER_VARS += QEMUSNPCMD
USER_VARS += QEMUPATH
USER_VARS += QEMUTDXPATH
USER_VARS += QEMUTDXQUOTEGENERATIONSERVICESOCKETPORT
USER_VARS += QEMUSNPPATH
USER_VARS += QEMUVALIDHYPERVISORPATHS
USER_VARS += QEMUTDXVALIDHYPERVISORPATHS

View File

@ -17,6 +17,7 @@ kernel = "@KERNELCONFIDENTIALPATH@"
image = "@IMAGECONFIDENTIALPATH@"
# initrd = "@INITRDPATH@"
machine_type = "@MACHINETYPE@"
tdx_quote_generation_service_socket_port = @QEMUTDXQUOTEGENERATIONSERVICESOCKETPORT@
# rootfs filesystem type:
# - ext4 (default)

View File

@ -15,6 +15,7 @@ package qemu
import (
"context"
"encoding/json"
"fmt"
"io"
"log"
@ -44,6 +45,12 @@ const (
MachineTypeMicrovm string = "microvm"
)
const (
// Well known vsock CID for host system.
// https://man7.org/linux/man-pages/man7/vsock.7.html
VsockHostCid uint64 = 2
)
// Device is the qemu device interface.
type Device interface {
Valid() bool
@ -306,6 +313,9 @@ type Object struct {
// Prealloc enables memory preallocation
Prealloc bool
// QgsPort defines Intel Quote Generation Service port exposed from the host
QgsPort uint32
}
// Valid returns true if the Object structure is valid and complete.
@ -316,7 +326,7 @@ func (object Object) Valid() bool {
case MemoryBackendEPC:
return object.ID != "" && object.Size != 0
case TDXGuest:
return object.ID != "" && object.File != "" && object.DeviceID != ""
return object.ID != "" && object.File != "" && object.DeviceID != "" && object.QgsPort != 0
case SEVGuest:
fallthrough
case SNPGuest:
@ -362,11 +372,7 @@ func (object Object) QemuParams(config *Config) []string {
}
case TDXGuest:
objectParams = append(objectParams, string(object.Type))
objectParams = append(objectParams, fmt.Sprintf("id=%s", object.ID))
if object.Debug {
objectParams = append(objectParams, "debug=on")
}
objectParams = append(objectParams, prepareObjectWithTdxQgs(object))
config.Bios = object.File
case SEVGuest:
fallthrough
@ -408,6 +414,52 @@ func (object Object) QemuParams(config *Config) []string {
return qemuParams
}
type SocketAddress struct {
Type string `json:"type"`
Cid string `json:"cid"`
Port string `json:"port"`
}
type TdxQomObject struct {
QomType string `json:"qom-type"`
Id string `json:"id"`
QuoteGenerationSocket SocketAddress `json:"quote-generation-socket"`
Debug *bool `json:"debug,omitempty"`
}
func (this *SocketAddress) String() string {
b, err := json.Marshal(*this)
if err != nil {
log.Fatalf("Unable to marshal SocketAddress object: %s", err.Error())
return ""
}
return string(b)
}
func (this *TdxQomObject) String() string {
b, err := json.Marshal(*this)
if err != nil {
log.Fatalf("Unable to marshal TDX QOM object: %s", err.Error())
return ""
}
return string(b)
}
func prepareObjectWithTdxQgs(object Object) string {
qgsSocket := SocketAddress{"vsock", fmt.Sprint(VsockHostCid), fmt.Sprint(object.QgsPort)}
tdxObject := TdxQomObject{string(object.Type), object.ID, qgsSocket, nil}
if object.Debug {
*tdxObject.Debug = true
}
return tdxObject.String()
}
// Virtio9PMultidev filesystem behaviour to deal
// with multiple devices being shared with a 9p export.
type Virtio9PMultidev string

View File

@ -58,6 +58,7 @@ var systemdUnitName = "kata-containers.target"
const defaultKernelParams = ""
const defaultMachineType = "q35"
const defaultQgsPort = 4050
const defaultVCPUCount uint32 = 1
const defaultMaxVCPUCount uint32 = 0

View File

@ -89,6 +89,7 @@ type hypervisor struct {
CPUFeatures string `toml:"cpu_features"`
KernelParams string `toml:"kernel_params"`
MachineType string `toml:"machine_type"`
QgsPort uint32 `toml:"tdx_quote_generation_service_socket_port"`
BlockDeviceDriver string `toml:"block_device_driver"`
EntropySource string `toml:"entropy_source"`
SharedFS string `toml:"shared_fs"`
@ -373,6 +374,14 @@ func (h hypervisor) machineType() string {
return h.MachineType
}
func (h hypervisor) qgsPort() uint32 {
if h.QgsPort == 0 {
return defaultQgsPort
}
return h.QgsPort
}
func (h hypervisor) GetEntropySource() string {
if h.EntropySource == "" {
return defaultEntropySource
@ -890,6 +899,7 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
CPUFeatures: cpuFeatures,
KernelParams: vc.DeserializeParams(vc.KernelParamFields(kernelParams)),
HypervisorMachineType: machineType,
QgsPort: h.qgsPort(),
NumVCPUsF: h.defaultVCPUs(),
DefaultMaxVCPUs: h.defaultMaxVCPUs(),
MemorySize: h.defaultMemSz(),

View File

@ -182,6 +182,7 @@ func createAllRuntimeConfigFiles(dir, hypervisor string) (testConfig testRuntime
VirtioFSCache: defaultVirtioFSCacheMode,
PFlash: []string{},
SGXEPCSize: epcSize,
QgsPort: defaultQgsPort,
}
if goruntime.GOARCH == "arm64" && len(hypervisorConfig.PFlash) == 0 && hypervisorConfig.FirmwarePath == "" {

View File

@ -671,6 +671,9 @@ type HypervisorConfig struct {
// ExtraMonitorSocket allows to add an extra HMP or QMP socket when the VMM is Qemu
ExtraMonitorSocket govmmQemu.MonitorProtocol
// QgsPort defines Intel Quote Generation Service port exposed from the host
QgsPort uint32
}
// vcpu mapping from vcpu number to thread number

View File

@ -31,6 +31,8 @@ type qemuAmd64 struct {
devLoadersCount uint32
sgxEPCSize int64
qgsPort uint32
}
const (
@ -125,6 +127,7 @@ func newQemuArch(config HypervisorConfig) (qemuArch, error) {
},
vmFactory: factory,
snpGuest: config.SevSnpGuest,
qgsPort: config.QgsPort,
}
if config.ConfidentialGuest {
@ -282,6 +285,7 @@ func (q *qemuAmd64) appendProtectionDevice(devices []govmmQemu.Device, firmware,
govmmQemu.Object{
Driver: govmmQemu.Loader,
Type: govmmQemu.TDXGuest,
QgsPort: q.qgsPort,
ID: "tdx",
DeviceID: fmt.Sprintf("fd%d", id),
Debug: false,