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: b9a66cd5cc ("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>
master
parent
b6422dff0e
commit
16cbec2489
|
|
@ -630,7 +630,7 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp)
|
||||||
{
|
{
|
||||||
struct mshv_partition *p = vp->vp_partition;
|
struct mshv_partition *p = vp->vp_partition;
|
||||||
struct mshv_mem_region *region;
|
struct mshv_mem_region *region;
|
||||||
bool ret;
|
bool ret = false;
|
||||||
u64 gfn;
|
u64 gfn;
|
||||||
#if defined(CONFIG_X86_64)
|
#if defined(CONFIG_X86_64)
|
||||||
struct hv_x64_memory_intercept_message *msg =
|
struct hv_x64_memory_intercept_message *msg =
|
||||||
|
|
@ -641,6 +641,8 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp)
|
||||||
(struct hv_arm64_memory_intercept_message *)
|
(struct hv_arm64_memory_intercept_message *)
|
||||||
vp->vp_intercept_msg_page->u.payload;
|
vp->vp_intercept_msg_page->u.payload;
|
||||||
#endif
|
#endif
|
||||||
|
enum hv_intercept_access_type access_type =
|
||||||
|
msg->header.intercept_access_type;
|
||||||
|
|
||||||
gfn = HVPFN_DOWN(msg->guest_physical_address);
|
gfn = HVPFN_DOWN(msg->guest_physical_address);
|
||||||
|
|
||||||
|
|
@ -648,12 +650,19 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp)
|
||||||
if (!region)
|
if (!region)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (access_type == HV_INTERCEPT_ACCESS_WRITE &&
|
||||||
|
!(region->hv_map_flags & HV_MAP_GPA_WRITABLE))
|
||||||
|
goto put_region;
|
||||||
|
|
||||||
|
if (access_type == HV_INTERCEPT_ACCESS_EXECUTE &&
|
||||||
|
!(region->hv_map_flags & HV_MAP_GPA_EXECUTABLE))
|
||||||
|
goto put_region;
|
||||||
|
|
||||||
/* Only movable memory ranges are supported for GPA intercepts */
|
/* Only movable memory ranges are supported for GPA intercepts */
|
||||||
if (region->mreg_type == MSHV_REGION_TYPE_MEM_MOVABLE)
|
if (region->mreg_type == MSHV_REGION_TYPE_MEM_MOVABLE)
|
||||||
ret = mshv_region_handle_gfn_fault(region, gfn);
|
ret = mshv_region_handle_gfn_fault(region, gfn);
|
||||||
else
|
|
||||||
ret = false;
|
|
||||||
|
|
||||||
|
put_region:
|
||||||
mshv_region_put(region);
|
mshv_region_put(region);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
|
|
@ -1533,4 +1533,10 @@ struct hv_mmio_write_input {
|
||||||
u8 data[HV_HYPERCALL_MMIO_MAX_DATA_LENGTH];
|
u8 data[HV_HYPERCALL_MMIO_MAX_DATA_LENGTH];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
enum hv_intercept_access_type {
|
||||||
|
HV_INTERCEPT_ACCESS_READ = 0,
|
||||||
|
HV_INTERCEPT_ACCESS_WRITE = 1,
|
||||||
|
HV_INTERCEPT_ACCESS_EXECUTE = 2
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _HV_HVGDK_MINI_H */
|
#endif /* _HV_HVGDK_MINI_H */
|
||||||
|
|
|
||||||
|
|
@ -779,7 +779,7 @@ struct hv_x64_intercept_message_header {
|
||||||
u32 vp_index;
|
u32 vp_index;
|
||||||
u8 instruction_length:4;
|
u8 instruction_length:4;
|
||||||
u8 cr8:4; /* Only set for exo partitions */
|
u8 cr8:4; /* Only set for exo partitions */
|
||||||
u8 intercept_access_type;
|
u8 intercept_access_type; /* enum hv_intercept_access_type */
|
||||||
union hv_x64_vp_execution_state execution_state;
|
union hv_x64_vp_execution_state execution_state;
|
||||||
struct hv_x64_segment_register cs_segment;
|
struct hv_x64_segment_register cs_segment;
|
||||||
u64 rip;
|
u64 rip;
|
||||||
|
|
@ -825,7 +825,7 @@ union hv_arm64_vp_execution_state {
|
||||||
struct hv_arm64_intercept_message_header {
|
struct hv_arm64_intercept_message_header {
|
||||||
u32 vp_index;
|
u32 vp_index;
|
||||||
u8 instruction_length;
|
u8 instruction_length;
|
||||||
u8 intercept_access_type;
|
u8 intercept_access_type; /* enum hv_intercept_access_type */
|
||||||
union hv_arm64_vp_execution_state execution_state;
|
union hv_arm64_vp_execution_state execution_state;
|
||||||
u64 pc;
|
u64 pc;
|
||||||
u64 cpsr;
|
u64 cpsr;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue