[PATCH 13/13] virtio_balloon: enforce ACCESS_PLATFORM in CoCo
From: Kevin Loughlin
Date: Mon Oct 26 2026 - 23:03:50 EST
In confidential computing environments (CC_ATTR_GUEST_MEM_ENCRYPT),
virtio devices require VIRTIO_F_ACCESS_PLATFORM to negotiate restricted
memory access and DMA bounce buffering for virtqueue rings and
metadata buffers.
Currently, virtballoon_validate() unconditionally clears
VIRTIO_F_ACCESS_PLATFORM, causing virtio_features_ok() to reject probing
the balloon device (-ENODEV) when restricted memory access is active.
Preserve VIRTIO_F_ACCESS_PLATFORM in virtballoon_validate() when
CC_ATTR_GUEST_MEM_ENCRYPT is active, clear VIRTIO_BALLOON_F_FREE_PAGE_HINT
in CoCo since free_page_vq maps MAX_PAGE_ORDER blocks through standard DMA
ops without unaccepting them. Reject probing (-ENODEV) on CoCo
platforms where balloon page state transitions are unsupported.
Signed-off-by: Kevin Loughlin <kevinloughlin@xxxxxxxxxx>
---
drivers/virtio/virtio_balloon.c | 36 ++++++++++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 217431e75751..ae011636c07f 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -1311,6 +1311,14 @@ static int virtballoon_restore(struct virtio_device *vdev)
}
#endif
+static bool virtballoon_cc_supported(void)
+{
+ if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
+ return has_unaccepted_memory();
+
+ return cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT);
+}
+
static int virtballoon_validate(struct virtio_device *vdev)
{
/*
@@ -1318,7 +1326,17 @@ static int virtballoon_validate(struct virtio_device *vdev)
* initialized. If we cannot do that then we should disable
* page reporting as it could potentially change the contents
* of our free pages.
+ *
+ * In encrypted guests without unaccepted memory (e.g. SEV-ES), the
+ * hypervisor cannot populate discarded pages with guest-encrypted
+ * poison/zero values and the guest does not re-initialize reported
+ * pages on return. Clear VIRTIO_BALLOON_F_PAGE_POISON so reporting
+ * is disabled when init_on_free or page_poison is active.
*/
+ if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) &&
+ !has_unaccepted_memory())
+ __virtio_clear_bit(vdev, VIRTIO_BALLOON_F_PAGE_POISON);
+
if (!want_init_on_free() && !page_poisoning_enabled_static())
__virtio_clear_bit(vdev, VIRTIO_BALLOON_F_PAGE_POISON);
else if (!virtio_has_feature(vdev, VIRTIO_BALLOON_F_PAGE_POISON))
@@ -1329,7 +1347,23 @@ static int virtballoon_validate(struct virtio_device *vdev)
* virtqueue_add during page reporting.
*/
__virtio_clear_bit(vdev, VIRTIO_RING_F_INDIRECT_DESC);
- __virtio_clear_bit(vdev, VIRTIO_F_ACCESS_PLATFORM);
+
+ /*
+ * The balloon bypasses the DMA API for page addresses and cannot
+ * support a physical or virtual IOMMU on non-CoCo guests. In CoCo
+ * guests, VIRTIO_F_ACCESS_PLATFORM is required for bounce-buffering
+ * virtqueue rings and metadata. Disable free page hinting in CoCo
+ * guests as free_page_vq maps MAX_PAGE_ORDER blocks through standard
+ * DMA ops, and reject probing on CoCo platforms where balloon page
+ * state transitions are not supported.
+ */
+ if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {
+ __virtio_clear_bit(vdev, VIRTIO_F_ACCESS_PLATFORM);
+ } else {
+ if (!virtballoon_cc_supported())
+ return -ENODEV;
+ __virtio_clear_bit(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT);
+ }
return 0;
}
--
2.56.0.307.g5fe7bd680c-goog