From fc680139e54b86e3d9a300c95f3227118b1116dd Mon Sep 17 00:00:00 2001 From: Jakub Ledworowski Date: Thu, 16 May 2024 12:37:23 +0200 Subject: [PATCH] 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 --- src/runtime/Makefile | 2 + .../config/configuration-qemu-tdx.toml.in | 1 + src/runtime/pkg/govmm/qemu/qemu.go | 64 +++++++++++++++++-- .../pkg/katautils/config-settings.go.in | 1 + src/runtime/pkg/katautils/config.go | 10 +++ src/runtime/pkg/katautils/config_test.go | 1 + src/runtime/virtcontainers/hypervisor.go | 3 + src/runtime/virtcontainers/qemu_amd64.go | 4 ++ 8 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/runtime/Makefile b/src/runtime/Makefile index d7f058c3e1..d8cfa582c5 100644 --- a/src/runtime/Makefile +++ b/src/runtime/Makefile @@ -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 diff --git a/src/runtime/config/configuration-qemu-tdx.toml.in b/src/runtime/config/configuration-qemu-tdx.toml.in index 34b34eb55d..a18bdb4392 100644 --- a/src/runtime/config/configuration-qemu-tdx.toml.in +++ b/src/runtime/config/configuration-qemu-tdx.toml.in @@ -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) diff --git a/src/runtime/pkg/govmm/qemu/qemu.go b/src/runtime/pkg/govmm/qemu/qemu.go index b48baff8f6..092c0b8ca2 100644 --- a/src/runtime/pkg/govmm/qemu/qemu.go +++ b/src/runtime/pkg/govmm/qemu/qemu.go @@ -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 diff --git a/src/runtime/pkg/katautils/config-settings.go.in b/src/runtime/pkg/katautils/config-settings.go.in index a6d2ece25a..ea7ad487fe 100644 --- a/src/runtime/pkg/katautils/config-settings.go.in +++ b/src/runtime/pkg/katautils/config-settings.go.in @@ -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 diff --git a/src/runtime/pkg/katautils/config.go b/src/runtime/pkg/katautils/config.go index a786bb2da1..91d048e657 100644 --- a/src/runtime/pkg/katautils/config.go +++ b/src/runtime/pkg/katautils/config.go @@ -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(), diff --git a/src/runtime/pkg/katautils/config_test.go b/src/runtime/pkg/katautils/config_test.go index f29cb288c4..640afb2578 100644 --- a/src/runtime/pkg/katautils/config_test.go +++ b/src/runtime/pkg/katautils/config_test.go @@ -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 == "" { diff --git a/src/runtime/virtcontainers/hypervisor.go b/src/runtime/virtcontainers/hypervisor.go index fa307bbbb8..41ab4495eb 100644 --- a/src/runtime/virtcontainers/hypervisor.go +++ b/src/runtime/virtcontainers/hypervisor.go @@ -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 diff --git a/src/runtime/virtcontainers/qemu_amd64.go b/src/runtime/virtcontainers/qemu_amd64.go index 3e48fce7fd..ade7356eb6 100644 --- a/src/runtime/virtcontainers/qemu_amd64.go +++ b/src/runtime/virtcontainers/qemu_amd64.go @@ -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,