diff --git a/src/runtime/Makefile b/src/runtime/Makefile index 0e565bd4e0..3b6f792001 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)\"] @@ -706,6 +707,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 58d050e39b..7859f7d444 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,