In confidential computing guests with dynamic unaccepted memory
transitions, configure the free page reporting order to
unaccepted_memory_order(). Invoke mark_memory_unaccepted() on each
scatterlist range in virtballoon_free_page_report() before adding the
scatterlist to reporting_vq and kicking the host.

Unaccepting the pages prior to virtqueue_add_inbuf() and virtqueue_kick()
guarantees that the guest finishes PVALIDATE(validate=false) before the
host VMM can observe the reporting request in the virtqueue ring and
punch a hole in guest_memfd, eliminating any race where the guest
re-allocates and re-accepts a page before a deferred host hole-punch
executes.

Signed-off-by: Kevin Loughlin <[email protected]>
---
 drivers/virtio/virtio_balloon.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index d162c162b496..e10bd792ef7c 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -213,7 +213,26 @@ static int virtballoon_free_page_report(struct 
page_reporting_dev_info *pr_dev_i
        struct virtio_balloon *vb =
                container_of(pr_dev_info, struct virtio_balloon, pr_dev_info);
        struct virtqueue *vq = vb->reporting_vq;
-       unsigned int unused, err;
+       unsigned int unused;
+       int err;
+
+       if (virtballoon_cc_needs_state_transition()) {
+               unsigned long unit_size = PAGE_SIZE << 
unaccepted_memory_order();
+               struct scatterlist *sgl;
+               unsigned int i;
+
+               for_each_sg(sg, sgl, nents, i) {
+                       if (WARN_ON_ONCE(!IS_ALIGNED(sg_phys(sgl), unit_size) ||
+                                        !IS_ALIGNED(sgl->length, unit_size)))
+                               return -EINVAL;
+               }
+               for_each_sg(sg, sgl, nents, i) {
+                       err = mark_memory_unaccepted(sg_phys(sgl), sgl->length);
+                       if (err)
+                               return err;
+                       cond_resched();
+               }
+       }
 
        /* We should always be able to add these buffers to an empty queue. */
        err = virtqueue_add_inbuf(vq, sg, nents, vb, GFP_NOWAIT);
@@ -1142,8 +1161,11 @@ static int virtballoon_probe(struct virtio_device *vdev)
                 * host's base page size. However, it needs more work to report
                 * that value. The hard-coded order would be fine currently.
                 */
+               if (virtballoon_cc_needs_state_transition())
+                       vb->pr_dev_info.order = unaccepted_memory_order();
 #if defined(CONFIG_ARM64) && defined(CONFIG_ARM64_64K_PAGES)
-               vb->pr_dev_info.order = 5;
+               else
+                       vb->pr_dev_info.order = 5;
 #endif
 
                vb->pr_dev_info.capacity = capacity;
-- 
2.56.0.307.g5fe7bd680c-goog


Reply via email to