Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mshv: Fix infinite fault loop on permission-denied GPA intercepts

Prevent infinite fault loops when guests access memory regions without
proper permissions. Currently, mshv_handle_gpa_intercept() attempts to
remap pages for all faults on movable memory regions, regardless of
whether the access type is permitted. When a guest writes to a read-only
region, the remap succeeds but the region remains read-only, causing
immediate re-fault and spinning the vCPU indefinitely.

Validate intercept access type against region permissions before
attempting remaps. Reject writes to non-writable regions and executes to
non-executable regions early, returning false to let the VMM handle the
intercept appropriately.

This also closes a potential DoS vector where malicious guests could
intentionally trigger these fault loops to consume host resources.

Fixes: b9a66cd5ccbb ("mshv: Add support for movable memory regions")
Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
Reviewed-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>

authored by

Stanislav Kinsburskii and committed by
Wei Liu
16cbec24 b6422dff

+20 -5
+12 -3
drivers/hv/mshv_root_main.c
··· 630 630 { 631 631 struct mshv_partition *p = vp->vp_partition; 632 632 struct mshv_mem_region *region; 633 - bool ret; 633 + bool ret = false; 634 634 u64 gfn; 635 635 #if defined(CONFIG_X86_64) 636 636 struct hv_x64_memory_intercept_message *msg = ··· 641 641 (struct hv_arm64_memory_intercept_message *) 642 642 vp->vp_intercept_msg_page->u.payload; 643 643 #endif 644 + enum hv_intercept_access_type access_type = 645 + msg->header.intercept_access_type; 644 646 645 647 gfn = HVPFN_DOWN(msg->guest_physical_address); 646 648 ··· 650 648 if (!region) 651 649 return false; 652 650 651 + if (access_type == HV_INTERCEPT_ACCESS_WRITE && 652 + !(region->hv_map_flags & HV_MAP_GPA_WRITABLE)) 653 + goto put_region; 654 + 655 + if (access_type == HV_INTERCEPT_ACCESS_EXECUTE && 656 + !(region->hv_map_flags & HV_MAP_GPA_EXECUTABLE)) 657 + goto put_region; 658 + 653 659 /* Only movable memory ranges are supported for GPA intercepts */ 654 660 if (region->mreg_type == MSHV_REGION_TYPE_MEM_MOVABLE) 655 661 ret = mshv_region_handle_gfn_fault(region, gfn); 656 - else 657 - ret = false; 658 662 663 + put_region: 659 664 mshv_region_put(region); 660 665 661 666 return ret;
+6
include/hyperv/hvgdk_mini.h
··· 1533 1533 u8 data[HV_HYPERCALL_MMIO_MAX_DATA_LENGTH]; 1534 1534 } __packed; 1535 1535 1536 + enum hv_intercept_access_type { 1537 + HV_INTERCEPT_ACCESS_READ = 0, 1538 + HV_INTERCEPT_ACCESS_WRITE = 1, 1539 + HV_INTERCEPT_ACCESS_EXECUTE = 2 1540 + }; 1541 + 1536 1542 #endif /* _HV_HVGDK_MINI_H */
+2 -2
include/hyperv/hvhdk.h
··· 779 779 u32 vp_index; 780 780 u8 instruction_length:4; 781 781 u8 cr8:4; /* Only set for exo partitions */ 782 - u8 intercept_access_type; 782 + u8 intercept_access_type; /* enum hv_intercept_access_type */ 783 783 union hv_x64_vp_execution_state execution_state; 784 784 struct hv_x64_segment_register cs_segment; 785 785 u64 rip; ··· 825 825 struct hv_arm64_intercept_message_header { 826 826 u32 vp_index; 827 827 u8 instruction_length; 828 - u8 intercept_access_type; 828 + u8 intercept_access_type; /* enum hv_intercept_access_type */ 829 829 union hv_arm64_vp_execution_state execution_state; 830 830 u64 pc; 831 831 u64 cpsr;