mshv_region_range_fault() unconditionally sets HMM_PFN_REQ_WRITE on
the hmm_range_fault() request.  When the region was created without
MSHV_SET_MEM_BIT_WRITABLE (so region->hv_map_flags has no
HV_MAP_GPA_WRITABLE), the request still asks HMM for writable pages.
On read-only mappings this causes hmm_range_fault() to break
copy-on-write — for example, the shared zero page or file-backed
pages — granting the guest a private writable copy of memory that
host policy intended to keep shared.

Gate HMM_PFN_REQ_WRITE on the region's HV_MAP_GPA_WRITABLE bit so
that read-only regions request read-only faults.

Note: this still asks for write on writable regions even if the
backing VMA is read-only.  A more thorough check would also consult
each VMA's vm_flags inside the fault loop; that requires iterating
VMAs and is left for a follow-up.

Fixes: b9a66cd5ccbb ("mshv: Add support for movable memory regions")
Signed-off-by: Stanislav Kinsburskii <[email protected]>
---
 drivers/hv/mshv_regions.c |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/hv/mshv_regions.c b/drivers/hv/mshv_regions.c
index 81e57f727be35..d9e1fbfefe714 100644
--- a/drivers/hv/mshv_regions.c
+++ b/drivers/hv/mshv_regions.c
@@ -441,7 +441,7 @@ static int mshv_region_range_fault(struct mshv_mem_region 
*region,
 {
        struct hmm_range range = {
                .notifier = &region->mreg_mni,
-               .default_flags = HMM_PFN_REQ_FAULT | HMM_PFN_REQ_WRITE,
+               .default_flags = HMM_PFN_REQ_FAULT,
        };
        unsigned long *pfns;
        int ret;
@@ -455,6 +455,15 @@ static int mshv_region_range_fault(struct mshv_mem_region 
*region,
        range.start = region->start_uaddr + page_offset * HV_HYP_PAGE_SIZE;
        range.end = range.start + page_count * HV_HYP_PAGE_SIZE;
 
+       /*
+        * Only request writable pages from HMM when the region itself
+        * permits writes.  Without this, hmm_range_fault() would
+        * trigger COW on read-only regions, breaking copy-on-write
+        * semantics on shared host pages.
+        */
+       if (region->hv_map_flags & HV_MAP_GPA_WRITABLE)
+               range.default_flags |= HMM_PFN_REQ_WRITE;
+
        do {
                ret = mshv_region_hmm_fault_and_lock(region, &range);
        } while (ret == -EBUSY);



Reply via email to