summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorKameron Carr <kameroncarr@linux.microsoft.com>2026-10-19 16:09:49 -0700
committerWei Liu <wei.liu@kernel.org>2026-10-21 00:00:29 -0700
commitbe0d83e869430232ca56f439eabac9c99758221f (patch)
treeb58d56ee7f4ec417a2e99b1b551b17632b5e68ef /include/linux
parenta8e60890cb86a181d8216ac7e60873ba9d7d2ff9 (diff)
Drivers: hv: vmbus: Keep the ring byte counts sane for a bad index
The remaining users of the shared indices can't cause a bad memory access with the channels a CoCo VM accepts today, but an out-of-range index gives them a nonsense byte count. Give them defined behavior instead. hv_pkt_iter_first() bounds its memcpy() by hv_pkt_iter_avail(), which is derived from write_index, and by pkt_buffer_size, which comes from max_pkt_size and can exceed ring_datasize. A bad write index can then make it read past the end of the ring. Only KVP has such a max_pkt_size (16K on a 12K ring with 4K pages), and vmbus_is_valid_offer() rejects it in isolated VMs, so this is latent. hv_pkt_iter_avail() now reports an empty ring for a bad write index and logs it, rate-limited like hv_ringbuffer_write(). It takes the channel instead of the ring so the message can include the relid. hv_get_bytes_to_read() and hv_get_bytes_to_write() now return 0 for a bad index, so callers see nothing to read and no room to write. This also stops hv_end_read() from reporting data that hv_pkt_iter_first() won't return, which would keep a channel rescheduling its callback. hv_pkt_iter_close() only uses the indices to decide whether to signal the host, so skip the signal if either is out of range. Signed-off-by: Kameron Carr <kameroncarr@linux.microsoft.com> Reviewed-by: Michael Kelley <mhklinux@outlook.com> Signed-off-by: Wei Liu <wei.liu@kernel.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/hyperv.h4
1 files changed, 4 insertions, 0 deletions
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 09f25ade88b0..216c0b9e9be5 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -250,6 +250,8 @@ static inline u32 hv_get_bytes_to_read(const struct hv_ring_buffer_info *rbi)
read_loc = READ_ONCE(rbi->ring_buffer->read_index);
write_loc = READ_ONCE(rbi->ring_buffer->write_index);
+ if (unlikely(hv_ringbuffer_indices_invalid(rbi, read_loc, write_loc)))
+ return 0;
return hv_ringbuffer_avail_read(rbi, read_loc, write_loc);
}
@@ -260,6 +262,8 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi)
read_loc = READ_ONCE(rbi->ring_buffer->read_index);
write_loc = READ_ONCE(rbi->ring_buffer->write_index);
+ if (unlikely(hv_ringbuffer_indices_invalid(rbi, read_loc, write_loc)))
+ return 0;
return hv_ringbuffer_avail_write(rbi, read_loc, write_loc);
}