From be0d83e869430232ca56f439eabac9c99758221f Mon Sep 17 00:00:00 2001 From: Kameron Carr Date: Mon, 19 Oct 2026 16:09:49 -0700 Subject: 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 Reviewed-by: Michael Kelley Signed-off-by: Wei Liu --- include/linux/hyperv.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') 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); } -- cgit v1.2.3