mshv_vp_create() publishes a VP pointer to pt_vp_array with a plain
store. The ISR reads this array locklessly from interrupt context on
other CPUs. Without memory ordering, a reader may observe the non-NULL
pointer before all VP fields (e.g. vp_register_page, run.vp_suspend_queue)
are fully initialized, leading to use of uninitialized data.
Fix by using smp_store_release() when publishing the VP pointer and
smp_load_acquire() on all lockless ISR read sites. This guarantees that
all VP initialization is visible to readers before the pointer itself.
Fixes: 621191d709b1 ("Drivers: hv: Introduce mshv_root module to expose
/dev/mshv to VMMs")
Signed-off-by: Stanislav Kinsburskii <[email protected]>
---
drivers/hv/mshv_eventfd.c | 2 +-
drivers/hv/mshv_root_main.c | 3 ++-
drivers/hv/mshv_synic.c | 6 +++---
3 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/hv/mshv_eventfd.c b/drivers/hv/mshv_eventfd.c
index c99ca5770d3d0..780f0ea43f2c6 100644
--- a/drivers/hv/mshv_eventfd.c
+++ b/drivers/hv/mshv_eventfd.c
@@ -180,7 +180,7 @@ static int mshv_try_assert_irq_fast(struct mshv_irqfd
*irqfd,
if (irq->lapic_apic_id >= MSHV_MAX_VPS)
return -EINVAL;
- vp = partition->pt_vp_array[irq->lapic_apic_id];
+ vp = smp_load_acquire(&partition->pt_vp_array[irq->lapic_apic_id]);
if (!vp)
return -EINVAL;
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 0e9b696853fcb..4d58e0b005183 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -1224,7 +1224,8 @@ mshv_partition_ioctl_create_vp(struct mshv_partition
*partition,
/* already exclusive with the partition mutex for all ioctls */
partition->pt_vp_count++;
- partition->pt_vp_array[args.vp_index] = vp;
+ /* Ensure VP is fully initialized before visible to lockless ISR
readers */
+ smp_store_release(&partition->pt_vp_array[args.vp_index], vp);
goto out;
diff --git a/drivers/hv/mshv_synic.c b/drivers/hv/mshv_synic.c
index 39c6b22e1e11e..a916a39888aad 100644
--- a/drivers/hv/mshv_synic.c
+++ b/drivers/hv/mshv_synic.c
@@ -245,7 +245,7 @@ handle_bitset_message(const struct
hv_vp_signal_bitset_scheduler_message *msg)
goto unlock_out;
}
- vp = partition->pt_vp_array[vp_index];
+ vp =
smp_load_acquire(&partition->pt_vp_array[vp_index]);
if (unlikely(!vp)) {
pr_debug("failed to find VP %u\n", vp_index);
goto unlock_out;
@@ -294,7 +294,7 @@ handle_pair_message(const struct
hv_vp_signal_pair_scheduler_message *msg)
break;
}
- vp = partition->pt_vp_array[vp_index];
+ vp = smp_load_acquire(&partition->pt_vp_array[vp_index]);
if (!vp) {
pr_debug("failed to find VP %u\n", vp_index);
break;
@@ -390,7 +390,7 @@ mshv_intercept_isr(struct hv_message *msg)
goto unlock_out;
}
vp_index = array_index_nospec(vp_index, MSHV_MAX_VPS);
- vp = partition->pt_vp_array[vp_index];
+ vp = smp_load_acquire(&partition->pt_vp_array[vp_index]);
if (unlikely(!vp)) {
pr_debug("failed to find VP %u\n", vp_index);
goto unlock_out;