From 9891b111d1268663e13c4531f096ec6d39adab80 Mon Sep 17 00:00:00 2001 From: rafsalrahim Date: Thu, 14 Aug 2025 17:05:58 +0530 Subject: [PATCH 1/2] runtime: Add initdata support to s390x - Added support for initdata device on s390x. - Generalized devno generation for QEMU CCW devices. Signed-off-by: rafsalrahim --- src/runtime/virtcontainers/qemu.go | 19 +-------- src/runtime/virtcontainers/qemu_arch_base.go | 21 ++++++++++ src/runtime/virtcontainers/qemu_arm64.go | 5 +++ src/runtime/virtcontainers/qemu_ppc64le.go | 6 +++ src/runtime/virtcontainers/qemu_s390x.go | 41 ++++++++++++++++++- src/runtime/virtcontainers/qemu_s390x_test.go | 7 ++-- 6 files changed, 76 insertions(+), 23 deletions(-) diff --git a/src/runtime/virtcontainers/qemu.go b/src/runtime/virtcontainers/qemu.go index 0de579c870..e7d00f7ea3 100644 --- a/src/runtime/virtcontainers/qemu.go +++ b/src/runtime/virtcontainers/qemu.go @@ -397,23 +397,6 @@ func (q *qemu) createQmpSocket() ([]govmmQemu.QMPSocket, error) { return sockets, nil } -func (q *qemu) buildInitdataDevice(devices []govmmQemu.Device, InitdataImage string) []govmmQemu.Device { - device := govmmQemu.BlockDevice{ - Driver: govmmQemu.VirtioBlock, - Transport: govmmQemu.TransportPCI, - ID: "initdata", - File: InitdataImage, - SCSI: false, - WCE: false, - AIO: govmmQemu.Threads, - Interface: "none", - Format: "raw", - } - - devices = append(devices, device) - return devices -} - func (q *qemu) buildDevices(ctx context.Context, kernelPath string) ([]govmmQemu.Device, *govmmQemu.IOThread, *govmmQemu.Kernel, error) { var devices []govmmQemu.Device @@ -763,7 +746,7 @@ func (q *qemu) CreateVM(ctx context.Context, id string, network Network, hypervi } if len(hypervisorConfig.Initdata) > 0 { - devices = q.buildInitdataDevice(devices, hypervisorConfig.InitdataImage) + devices = q.arch.buildInitdataDevice(ctx, devices, hypervisorConfig.InitdataImage) } // some devices configuration may also change kernel params, make sure this is called afterwards diff --git a/src/runtime/virtcontainers/qemu_arch_base.go b/src/runtime/virtcontainers/qemu_arch_base.go index aa41445916..18c193628c 100644 --- a/src/runtime/virtcontainers/qemu_arch_base.go +++ b/src/runtime/virtcontainers/qemu_arch_base.go @@ -176,6 +176,9 @@ type qemuArch interface { // Query QMP to find the PCI slot of a device, given its QOM path or ID qomGetSlot(qomPath string, qmpCh *qmpChannel) (types.PciSlot, error) + + // buildInitdataDevice creates an initdata device for the given architecture. + buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device } type qemuArchBase struct { @@ -949,6 +952,24 @@ func (q *qemuArchBase) qomGetSlot(qomPath string, qmpCh *qmpChannel) (types.PciS return types.PciSlotFromInt(slotNum) } +// build initdata device +func (q *qemuArchBase) buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device { + device := govmmQemu.BlockDevice{ + Driver: govmmQemu.VirtioBlock, + Transport: govmmQemu.TransportPCI, + ID: "initdata", + File: initdataImage, + SCSI: false, + WCE: false, + AIO: govmmQemu.Threads, + Interface: "none", + Format: "raw", + } + + devices = append(devices, device) + return devices +} + // Query QMP to find a device's PCI path given its QOM path or ID func (q *qemuArchBase) qomGetPciPath(qemuID string, qmpCh *qmpChannel) (types.PciPath, error) { diff --git a/src/runtime/virtcontainers/qemu_arm64.go b/src/runtime/virtcontainers/qemu_arm64.go index bfe6e2d405..2f3885835d 100644 --- a/src/runtime/virtcontainers/qemu_arm64.go +++ b/src/runtime/virtcontainers/qemu_arm64.go @@ -154,6 +154,11 @@ func (q *qemuArm64) enableProtection() error { return nil } +func (q *qemuArm64) buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device { + hvLogger.Warnf("buildInitdataDevice not implemented for arm64; ignoring initdata image: %s", initdataImage) + return devices +} + func (q *qemuArm64) appendProtectionDevice(devices []govmmQemu.Device, firmware, firmwareVolume string, initdataDigest []byte) ([]govmmQemu.Device, string, error) { err := q.enableProtection() if err != nil { diff --git a/src/runtime/virtcontainers/qemu_ppc64le.go b/src/runtime/virtcontainers/qemu_ppc64le.go index 87c2139b2b..51b014010b 100644 --- a/src/runtime/virtcontainers/qemu_ppc64le.go +++ b/src/runtime/virtcontainers/qemu_ppc64le.go @@ -8,6 +8,7 @@ package virtcontainers import ( + "context" "fmt" "time" @@ -156,6 +157,11 @@ func (q *qemuPPC64le) enableProtection() error { } } +func (q *qemuPPC64le) buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device { + hvLogger.Warnf("buildInitdataDevice not implemented for PPC64le; ignoring initdata image: %s", initdataImage) + return devices +} + // append protection device func (q *qemuPPC64le) appendProtectionDevice(devices []govmmQemu.Device, firmware, firmwareVolume string, initdataDigest []byte) ([]govmmQemu.Device, string, error) { switch q.protection { diff --git a/src/runtime/virtcontainers/qemu_s390x.go b/src/runtime/virtcontainers/qemu_s390x.go index 5f00e9ea76..9a10510d13 100644 --- a/src/runtime/virtcontainers/qemu_s390x.go +++ b/src/runtime/virtcontainers/qemu_s390x.go @@ -349,8 +349,9 @@ func (q *qemuS390x) appendProtectionDevice(devices []govmmQemu.Device, firmware, case seProtection: return append(devices, govmmQemu.Object{ - Type: govmmQemu.SecExecGuest, - ID: secExecID, + Type: govmmQemu.SecExecGuest, + ID: secExecID, + InitdataDigest: initdataDigest, }), firmware, nil case noneProtection: return devices, firmware, nil @@ -382,6 +383,42 @@ func (q *qemuS390x) appendVFIODevice(devices []govmmQemu.Device, vfioDev config. return devices } +func (q *qemuS390x) buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device { + + var transport govmmQemu.VirtioTransport + var devNo string + + transport = govmmQemu.TransportCCW + id := "initdata" + addr, bridge, err := q.addDeviceToBridge(ctx, id, types.CCW) + if err != nil { + hvLogger.WithError(err).Error("Failed to allocate CCW address for initdata") + return nil + } + devNo, err = bridge.AddressFormatCCW(addr) + if err != nil { + hvLogger.WithError(err).Error("Failed to format CCW address for initdata") + return nil + } + hvLogger.WithField("devno", devNo).Info("Using dynamic CCW DevNo for initdata") + + device := govmmQemu.BlockDevice{ + Driver: govmmQemu.VirtioBlock, + Transport: transport, + ID: id, + File: initdataImage, + SCSI: false, + WCE: false, + AIO: govmmQemu.Threads, + Interface: "none", + Format: "raw", + DevNo: devNo, + } + + devices = append(devices, device) + return devices +} + // Query QMP to find a device's PCI path given its QOM path or ID func (q *qemuS390x) qomGetPciPath(qemuID string, qmpCh *qmpChannel) (types.PciPath, error) { hvLogger.Warnf("qomGetPciPath not implemented for s390x") diff --git a/src/runtime/virtcontainers/qemu_s390x_test.go b/src/runtime/virtcontainers/qemu_s390x_test.go index db88b4690f..f04c8cbf40 100644 --- a/src/runtime/virtcontainers/qemu_s390x_test.go +++ b/src/runtime/virtcontainers/qemu_s390x_test.go @@ -144,14 +144,15 @@ func TestQemuS390xAppendProtectionDevice(t *testing.T) { // Secure Execution protection s390x.(*qemuS390x).protection = seProtection - devices, bios, err = s390x.appendProtectionDevice(devices, firmware, "", []byte(nil)) + devices, bios, err = s390x.appendProtectionDevice(devices, firmware, "", []byte("")) assert.NoError(err) assert.Empty(bios) expectedOut := []govmmQemu.Device{ govmmQemu.Object{ - Type: govmmQemu.SecExecGuest, - ID: secExecID, + Type: govmmQemu.SecExecGuest, + ID: secExecID, + InitdataDigest: []byte(""), }, } assert.Equal(expectedOut, devices) From 43cdde4c5dd75b61cec1278cca33376ac0448b5a Mon Sep 17 00:00:00 2001 From: stevenhorsman Date: Thu, 31 Jul 2025 10:02:34 +0100 Subject: [PATCH 2/2] test/k8s: Extend initdata tests to run on s390x Enable testing of initdata on the qemu-coco-dev and qemu-se runtime classes, so we can validate the function on s390x Signed-off-by: stevenhorsman --- .../integration/kubernetes/k8s-initdata.bats | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/integration/kubernetes/k8s-initdata.bats b/tests/integration/kubernetes/k8s-initdata.bats index 1dd801dca8..15bcc4993c 100644 --- a/tests/integration/kubernetes/k8s-initdata.bats +++ b/tests/integration/kubernetes/k8s-initdata.bats @@ -10,7 +10,7 @@ # 3. Pull an image from a banned registry # 4. Check if the pulling fails with log `image security validation failed`, # the initdata works. -# +# # Note that if initdata does not work, the pod still fails to launch (hang at # CreatingContainer status). The error information is # `[CDH] [ERROR]: Get Resource failed` which internally means that the KBS URL @@ -35,7 +35,7 @@ setup() { setup_common || die "setup_common failed" FAIL_TEST_IMAGE="quay.io/prometheus/busybox:latest" - + SECURITY_POLICY_KBS_URI="kbs:///default/security-policy/test" } @@ -45,13 +45,16 @@ function setup_kbs_image_policy_for_initdata() { fi export CURRENT_ARCH=$(uname -m) - if [ "${CURRENT_ARCH}" != "x86_64" ]; then - skip "Test skipped as only x86-64 supports, while current platform is ${CURRENT_ARCH}" - fi + case "${CURRENT_ARCH}" in + "x86_64"|"s390x") + ;; + *) + skip "Test skipped as only x86-64 & s390x is supported, while current platform is ${CURRENT_ARCH}" + ;; + esac - # TODO: Enable for more archs case "$KATA_HYPERVISOR" in - "qemu-tdx"|"qemu-coco-dev"|"qemu-snp") + "qemu-tdx"|"qemu-coco-dev"|"qemu-snp"|"qemu-se") ;; *) skip "Test not supported for ${KATA_HYPERVISOR}." @@ -88,7 +91,7 @@ EOF @test "Test that creating a container from an rejected image configured by initdata, fails according to policy reject" { setup_kbs_image_policy_for_initdata - + CC_KBS_ADDRESS=$(kbs_k8s_svc_http_addr) kernel_parameter="agent.image_policy_file=${SECURITY_POLICY_KBS_URI} agent.enable_signature_verification=true"